VIVO-957 error, updating subclass sorting method for object, using superclasses of classes instead of just comparing whether classes are subclasses of each other

This commit is contained in:
hudajkhan 2015-02-03 15:25:18 -05:00
parent a829de7923
commit 8e97ff3678

View file

@ -24,277 +24,313 @@ import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; import edu.cornell.mannlib.vitro.webapp.dao.VClassDao;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException;
public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateModel { public class CollatedObjectPropertyTemplateModel extends
ObjectPropertyTemplateModel {
private static final Log log = LogFactory.getLog(CollatedObjectPropertyTemplateModel.class); private static final Log log = LogFactory
private static final String SUBCLASS_VARIABLE_NAME = "subclass"; .getLog(CollatedObjectPropertyTemplateModel.class);
private static final String SUBCLASS_VARIABLE_NAME = "subclass";
private static final Pattern SELECT_SUBCLASS_PATTERN =
// SELECT ?subclass
Pattern.compile("SELECT[^{]*\\?" + SUBCLASS_VARIABLE_NAME + "\\b", Pattern.CASE_INSENSITIVE);
// ORDER BY ?subclass
// ORDER BY DESC(?subclass)
private static final Pattern ORDER_BY_SUBCLASS_PATTERN =
Pattern.compile("ORDER\\s+BY\\s+(DESC\\s*\\(\\s*)?\\?" + SUBCLASS_VARIABLE_NAME, Pattern.CASE_INSENSITIVE);
private final List<SubclassTemplateModel> subclasses;
private final VClassDao vclassDao;
CollatedObjectPropertyTemplateModel(ObjectProperty op, Individual subject,
VitroRequest vreq, boolean editing,
List<ObjectProperty> populatedObjectPropertyList)
throws InvalidConfigurationException {
super(op, subject, vreq, editing);
vclassDao = vreq.getWebappDaoFactory().getVClassDao(); private static final Pattern SELECT_SUBCLASS_PATTERN =
// SELECT ?subclass
if (populatedObjectPropertyList.contains(op)) { Pattern.compile("SELECT[^{]*\\?" + SUBCLASS_VARIABLE_NAME + "\\b",
log.debug("Getting data for populated object property " + op.getURI()); Pattern.CASE_INSENSITIVE);
// ORDER BY ?subclass
/* Get the data */ // ORDER BY DESC(?subclass)
List<Map<String, String>> statementData = getStatementData(); private static final Pattern ORDER_BY_SUBCLASS_PATTERN = Pattern.compile(
"ORDER\\s+BY\\s+(DESC\\s*\\(\\s*)?\\?" + SUBCLASS_VARIABLE_NAME,
/* Apply post-processing */ Pattern.CASE_INSENSITIVE);
postprocess(statementData);
/* Collate the data */
subclasses = collate(subjectUri, op, statementData, editing);
for (SubclassTemplateModel subclass : subclasses) {
List<ObjectPropertyStatementTemplateModel> list = subclass.getStatements();
postprocessStatementList(list);
}
Collections.sort(subclasses); private final List<SubclassTemplateModel> subclasses;
private final VClassDao vclassDao;
} else {
log.debug("Object property " + getUri() + " is unpopulated.");
subclasses = new ArrayList<SubclassTemplateModel>();
}
}
@Override
protected boolean isEmpty() {
return subclasses.isEmpty();
}
public ConfigError checkQuery(String queryString) {
if (StringUtils.isBlank(queryString)) {
return ConfigError.NO_SELECT_QUERY;
}
Matcher m;
m = SELECT_SUBCLASS_PATTERN.matcher(queryString);
if ( ! m.find() ) {
return ConfigError.NO_SUBCLASS_SELECT;
}
m = ORDER_BY_SUBCLASS_PATTERN.matcher(queryString);
if ( ! m.find() ) {
return ConfigError.NO_SUBCLASS_ORDER_BY;
}
return null;
}
@Override
protected void removeDuplicates(List<Map<String, String>> data) {
filterSubclasses(data);
super.removeDuplicates(data);
}
/*
* The query returns subclasses of a specific superclass that the object belongs to; for example,
* in the case of authorInAuthorship, subclasses of core:InformationResource. Here we remove all but
* the most specific subclass for the object.
*/
private void filterSubclasses(List<Map<String, String>> statementData) {
String objectVariableName = getObjectKey();
if (objectVariableName == null) {
log.error("Cannot remove duplicate statements for property " + getUri() + " because no object found to dedupe.");
return;
}
if (log.isDebugEnabled()) {
log.debug("Data before subclass filtering");
logData(statementData);
}
// Compile a list of the statements with most specific subclasses; others will be removed
List<Map<String, String>> filteredList = new ArrayList<Map<String, String>>();
Set<String> processedObjects = new HashSet<String>();
for (Map<String, String> outerMap : statementData) {
String objectUri = outerMap.get(objectVariableName);
if (processedObjects.contains(objectUri)) {
continue;
}
processedObjects.add(objectUri);
List<Map<String, String>> dataForThisObject = new ArrayList<Map<String, String>>();
for (Map<String, String> innerMap : statementData) {
if ( innerMap.get(objectVariableName) == objectUri ) {
dataForThisObject.add(innerMap);
}
}
// Sort the data for this object from most to least specific subclass, with nulls at end
Collections.sort(dataForThisObject, new DataComparatorBySubclass());
filteredList.add(dataForThisObject.get(0));
}
statementData.retainAll(filteredList); CollatedObjectPropertyTemplateModel(ObjectProperty op, Individual subject,
VitroRequest vreq, boolean editing,
if (log.isDebugEnabled()) { List<ObjectProperty> populatedObjectPropertyList)
log.debug("Data after subclass filtering"); throws InvalidConfigurationException {
logData(statementData);
}
}
private class DataComparatorBySubclass implements Comparator<Map<String, String>> {
@Override super(op, subject, vreq, editing);
public int compare(Map<String, String> map1, Map<String, String> map2) {
String subclass1 = map1.get(SUBCLASS_VARIABLE_NAME);
String subclass2 = map2.get(SUBCLASS_VARIABLE_NAME);
if (subclass1 == null) {
if (subclass2 == null) {
return 0;
} else {
return 1; // nulls rank highest
}
}
if (subclass2 == null) {
return -1; // nulls rank highest
}
if (subclass1.equals(subclass2)) {
return 0;
}
List<String> superclasses = vclassDao.getAllSuperClassURIs(subclass1);
if (superclasses.contains(subclass2)) {
return -1;
}
superclasses = vclassDao.getAllSuperClassURIs(subclass2);
if (superclasses.contains(subclass1)) {
return 1;
}
return 0;
}
}
// Collate the statements by subclass.
private List<SubclassTemplateModel> collate(String subjectUri, ObjectProperty property,
List<Map<String, String>> statementData, boolean editing) {
String objectKey = getObjectKey();
List<SubclassTemplateModel> subclasses = new ArrayList<SubclassTemplateModel>();
for (Map<String, String> map : statementData) {
String subclassUri = map.get(SUBCLASS_VARIABLE_NAME);
VClass vclass = vclassDao.getVClassByURI(subclassUri); vclassDao = vreq.getWebappDaoFactory().getVClassDao();
List<ObjectPropertyStatementTemplateModel> listForThisSubclass = null;
for (SubclassTemplateModel subclass : subclasses) { if (populatedObjectPropertyList.contains(op)) {
VClass subclassVClass = subclass.getVClass(); log.debug("Getting data for populated object property "
if ( ( vclass == null && subclassVClass == null ) || + op.getURI());
( vclass != null && vclass.equals(subclassVClass) ) ) {
listForThisSubclass = subclass.getStatements();
break;
}
}
if (listForThisSubclass == null) { /* Get the data */
listForThisSubclass = new ArrayList<ObjectPropertyStatementTemplateModel>(); List<Map<String, String>> statementData = getStatementData();
subclasses.add(new SubclassTemplateModel(vclass, listForThisSubclass));
}
listForThisSubclass.add(new ObjectPropertyStatementTemplateModel(subjectUri, /* Apply post-processing */
property, objectKey, map, getTemplateName(), vreq)); postprocess(statementData);
} /* Collate the data */log.debug("Collate:collating subclasses for "
+ subjectUri + " - predicate= " + op.getURI());
return subclasses; subclasses = collate(subjectUri, op, statementData, editing);
}
for (SubclassTemplateModel subclass : subclasses) {
// class SubclassComparatorByDisplayRank implements Comparator<String> { List<ObjectPropertyStatementTemplateModel> list = subclass
// .getStatements();
// private List<VClass> vclasses; postprocessStatementList(list);
// }
// SubclassComparatorByDisplayRank(List<VClass> vclasses) {
// this.vclasses = vclasses; Collections.sort(subclasses);
// }
// } else {
// @Override log.debug("Object property " + getUri() + " is unpopulated.");
// public int compare(String nameLeft, String nameRight) { subclasses = new ArrayList<SubclassTemplateModel>();
// }
// if (StringUtils.isBlank(uriLeft)) { }
// return StringUtils.isBlank(uriRight) ? 0 : 1;
// } @Override
// protected boolean isEmpty() {
// VClass vclassLeft = vclassDao.getVClassByURI(uriLeft); return subclasses.isEmpty();
// VClass vclassRight = vclassDao.getVClassByURI(uriRight); }
//
// if (vclassLeft == null) { public ConfigError checkQuery(String queryString) {
// return vclassRight == null ? 0 : 1;
// } if (StringUtils.isBlank(queryString)) {
// return ConfigError.NO_SELECT_QUERY;
// int rankLeft = vclassLeft.getDisplayRank(); }
// int rankRight = vclassRight.getDisplayRank();
// Matcher m;
// int intCompare = 0; m = SELECT_SUBCLASS_PATTERN.matcher(queryString);
// if (!m.find()) {
// // Values < 1 are undefined and go at end, not beginning return ConfigError.NO_SUBCLASS_SELECT;
// if (rankLeft < 1) { }
// intCompare = rankRight < 1 ? 0 : 1;
// } else if (rankRight < 1) { m = ORDER_BY_SUBCLASS_PATTERN.matcher(queryString);
// intCompare = -1; if (!m.find()) {
// } else { return ConfigError.NO_SUBCLASS_ORDER_BY;
// intCompare = ((Integer)rankLeft).compareTo(rankRight); }
// }
// return null;
// if (intCompare != 0) { }
// return intCompare;
// } @Override
// protected void removeDuplicates(List<Map<String, String>> data) {
// // If display ranks are equal, sort by name filterSubclasses(data);
// if (nameLeft == null) { super.removeDuplicates(data);
// return nameRight == null ? 0 : 1; }
// }
// if (nameRight == null) { /*
// return -1; * The query returns subclasses of a specific superclass that the object
// } * belongs to; for example, in the case of authorInAuthorship, subclasses of
// return nameLeft.compareToIgnoreCase(nameRight); * core:InformationResource. Here we remove all but the most specific
// * subclass for the object.
// } */
// } private void filterSubclasses(List<Map<String, String>> statementData) {
String objectVariableName = getObjectKey();
// private String getSubclassName(String subclassUri) { if (objectVariableName == null) {
// if (subclassUri.isEmpty()) { log.error("Cannot remove duplicate statements for property "
// return ""; + getUri() + " because no object found to dedupe.");
// } return;
// VClass vclass = vclassDao.getVClassByURI(subclassUri); }
// return vclass != null ? vclass.getName() : "";
// } if (log.isDebugEnabled()) {
log.debug("Data before subclass filtering");
logData(statementData);
/* Template properties */ }
public List<SubclassTemplateModel> getSubclasses() { // Compile a list of the statements with most specific subclasses;
return subclasses; // others will be removed
} List<Map<String, String>> filteredList = new ArrayList<Map<String, String>>();
Set<String> processedObjects = new HashSet<String>();
@Override for (Map<String, String> outerMap : statementData) {
public boolean isCollatedBySubclass() {
return true; String objectUri = outerMap.get(objectVariableName);
} if (processedObjects.contains(objectUri)) {
continue;
}
processedObjects.add(objectUri);
List<Map<String, String>> dataForThisObject = new ArrayList<Map<String, String>>();
for (Map<String, String> innerMap : statementData) {
if (innerMap.get(objectVariableName) == objectUri) {
dataForThisObject.add(innerMap);
}
}
// Sort the data for this object from most to least specific
// subclass, with nulls at end
Collections.sort(dataForThisObject, new DataComparatorBySubclass());
filteredList.add(dataForThisObject.get(0));
}
statementData.retainAll(filteredList);
if (log.isDebugEnabled()) {
log.debug("Data after subclass filtering");
logData(statementData);
}
}
private class DataComparatorBySubclass implements
Comparator<Map<String, String>> {
@Override
public int compare(Map<String, String> map1, Map<String, String> map2) {
String subclass1 = map1.get(SUBCLASS_VARIABLE_NAME);
String subclass2 = map2.get(SUBCLASS_VARIABLE_NAME);
if (subclass1 == null) {
if (subclass2 == null) {
return 0;
} else {
return 1; // nulls rank highest
}
}
if (subclass2 == null) {
return -1; // nulls rank highest
}
// if subclasses are equal, return 0
if (subclass1.equals(subclass2))
return 0;
String subclass1Superclasses = this
.getSuperclassesAsString(subclass1);
String subclass2Superclasses = this
.getSuperclassesAsString(subclass2);
int s1SuperclassesLength = subclass1Superclasses.length();
int s2SuperclassesLength = subclass2Superclasses.length();
if (s1SuperclassesLength == s2SuperclassesLength) {
// If the length is the same, then compare the strings
// alphabetically
return subclass1Superclasses.compareTo(subclass2Superclasses);
} else {
// if the length is different, the longer string is the more
// specific type
return (s1SuperclassesLength > s2SuperclassesLength ? -1 : 1);
}
}
// Given a particular class URI, generate a string representing the
// superclasses and types of the class
// The types are first sorted alphabetically and then concatenated to
// form the string representation
private String getSuperclassesAsString(String classURI) {
List<String> superclasses = vclassDao
.getAllSuperClassURIs(classURI);
if (superclasses == null || superclasses.size() == 0)
return "";
Collections.sort(superclasses);
return StringUtils.join(superclasses, " | ");
}
}
// Collate the statements by subclass.
private List<SubclassTemplateModel> collate(String subjectUri,
ObjectProperty property, List<Map<String, String>> statementData,
boolean editing) {
String objectKey = getObjectKey();
List<SubclassTemplateModel> subclasses = new ArrayList<SubclassTemplateModel>();
for (Map<String, String> map : statementData) {
String subclassUri = map.get(SUBCLASS_VARIABLE_NAME);
VClass vclass = vclassDao.getVClassByURI(subclassUri);
List<ObjectPropertyStatementTemplateModel> listForThisSubclass = null;
for (SubclassTemplateModel subclass : subclasses) {
VClass subclassVClass = subclass.getVClass();
if ((vclass == null && subclassVClass == null)
|| (vclass != null && vclass.equals(subclassVClass))) {
listForThisSubclass = subclass.getStatements();
break;
}
}
if (listForThisSubclass == null) {
listForThisSubclass = new ArrayList<ObjectPropertyStatementTemplateModel>();
subclasses.add(new SubclassTemplateModel(vclass,
listForThisSubclass));
}
listForThisSubclass.add(new ObjectPropertyStatementTemplateModel(
subjectUri, property, objectKey, map, getTemplateName(),
vreq));
}
return subclasses;
}
// class SubclassComparatorByDisplayRank implements Comparator<String> {
//
// private List<VClass> vclasses;
//
// SubclassComparatorByDisplayRank(List<VClass> vclasses) {
// this.vclasses = vclasses;
// }
//
// @Override
// public int compare(String nameLeft, String nameRight) {
//
// if (StringUtils.isBlank(uriLeft)) {
// return StringUtils.isBlank(uriRight) ? 0 : 1;
// }
//
// VClass vclassLeft = vclassDao.getVClassByURI(uriLeft);
// VClass vclassRight = vclassDao.getVClassByURI(uriRight);
//
// if (vclassLeft == null) {
// return vclassRight == null ? 0 : 1;
// }
//
// int rankLeft = vclassLeft.getDisplayRank();
// int rankRight = vclassRight.getDisplayRank();
//
// int intCompare = 0;
//
// // Values < 1 are undefined and go at end, not beginning
// if (rankLeft < 1) {
// intCompare = rankRight < 1 ? 0 : 1;
// } else if (rankRight < 1) {
// intCompare = -1;
// } else {
// intCompare = ((Integer)rankLeft).compareTo(rankRight);
// }
//
// if (intCompare != 0) {
// return intCompare;
// }
//
// // If display ranks are equal, sort by name
// if (nameLeft == null) {
// return nameRight == null ? 0 : 1;
// }
// if (nameRight == null) {
// return -1;
// }
// return nameLeft.compareToIgnoreCase(nameRight);
//
// }
// }
// private String getSubclassName(String subclassUri) {
// if (subclassUri.isEmpty()) {
// return "";
// }
// VClass vclass = vclassDao.getVClassByURI(subclassUri);
// return vclass != null ? vclass.getName() : "";
// }
/* Template properties */
public List<SubclassTemplateModel> getSubclasses() {
return subclasses;
}
@Override
public boolean isCollatedBySubclass() {
return true;
}
} }