NIHVIVO-1625 For custom list views that order by end datetime descending, reorder (within a collation, if property is collated) to put nulls at beginning rather than end.
This commit is contained in:
parent
7db0ea8938
commit
6b7415f5a0
5 changed files with 94 additions and 12 deletions
|
@ -573,7 +573,11 @@ public class EntityMergedPropertyListController extends VitroHttpServlet {
|
|||
|
||||
for (ObjectPropertyStatement statement : statements) {
|
||||
Individual object = statement.getObject();
|
||||
relatedStatements.add(object.getObjectPropertyStatements(op).get(0));
|
||||
List<ObjectPropertyStatement> statementsForObject = object.getObjectPropertyStatements(op);
|
||||
// Could be empty for statements with no linked individual.
|
||||
if ( ! statementsForObject.isEmpty() ) {
|
||||
relatedStatements.add(statementsForObject.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
return relatedStatements;
|
||||
|
|
|
@ -22,7 +22,9 @@ public abstract class BaseObjectPropertyDataPostProcessor implements
|
|||
private static String KEY_SUBJECT = "subject";
|
||||
private static final String KEY_PROPERTY = "property";
|
||||
private static final String DEFAULT_LIST_VIEW_QUERY_OBJECT_VARIABLE_NAME = "object";
|
||||
private static final Pattern QUERY_PATTERN = Pattern.compile("\\?" + KEY_SUBJECT + "\\s+\\?" + KEY_PROPERTY + "\\s+\\?(\\w+)");
|
||||
private static final Pattern SUBJECT_PROPERTY_OBJECT_PATTERN =
|
||||
// ?subject ?property ?\w+
|
||||
Pattern.compile("\\?" + KEY_SUBJECT + "\\s+\\?" + KEY_PROPERTY + "\\s+\\?(\\w+)");
|
||||
|
||||
protected ObjectPropertyTemplateModel objectPropertyTemplateModel;
|
||||
protected WebappDaoFactory wdf;
|
||||
|
@ -41,6 +43,7 @@ public abstract class BaseObjectPropertyDataPostProcessor implements
|
|||
}
|
||||
|
||||
removeDuplicates(data);
|
||||
|
||||
for (Map<String, String> map : data) {
|
||||
process(map);
|
||||
}
|
||||
|
@ -89,7 +92,7 @@ public abstract class BaseObjectPropertyDataPostProcessor implements
|
|||
", so query object = '" + object + "'");
|
||||
} else {
|
||||
String queryString = objectPropertyTemplateModel.getQueryString();
|
||||
Matcher m = QUERY_PATTERN.matcher(queryString);
|
||||
Matcher m = SUBJECT_PROPERTY_OBJECT_PATTERN.matcher(queryString);
|
||||
if (m.find()) {
|
||||
object = m.group(1);
|
||||
log.debug("Query object for property " + objectPropertyTemplateModel.getUri() + " = '" + object + "'");
|
||||
|
@ -99,7 +102,7 @@ public abstract class BaseObjectPropertyDataPostProcessor implements
|
|||
return object;
|
||||
}
|
||||
|
||||
/* Postprocessor helper methods callable from any postprocessor */
|
||||
/* Postprocessor methods callable from any postprocessor */
|
||||
|
||||
protected void addName(Map<String, String> map, String nameKey, String objectKey) {
|
||||
String name = map.get(nameKey);
|
||||
|
@ -124,4 +127,8 @@ public abstract class BaseObjectPropertyDataPostProcessor implements
|
|||
protected Individual getIndividual(String uri) {
|
||||
return wdf.getIndividualDao().getIndividualByURI(uri);
|
||||
}
|
||||
|
||||
protected static void moveNullEndDateTimesToTop(List<ObjectPropertyStatementTemplateModel> list) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,13 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
|
|||
|
||||
private static final Log log = LogFactory.getLog(CollatedObjectPropertyTemplateModel.class);
|
||||
private static final String DEFAULT_CONFIG_FILE = "listViewConfig-default-collated.xml";
|
||||
private static final Pattern SELECT_QUERY_PATTERN = Pattern.compile("SELECT[^{]*\\?subclass\\b", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern ORDER_BY_QUERY_PATTERN = Pattern.compile("ORDER\\s+BY\\s+(DESC\\s*\\(\\s*)?\\?subclass", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern SELECT_SUBCLASS_PATTERN =
|
||||
// SELECT ?subclass
|
||||
Pattern.compile("SELECT[^{]*\\?subclass\\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", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private SortedMap<String, List<ObjectPropertyStatementTemplateModel>> subclasses;
|
||||
|
||||
|
@ -65,7 +70,11 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
|
|||
return o1.compareTo(o2);
|
||||
}};
|
||||
subclasses = new TreeMap<String, List<ObjectPropertyStatementTemplateModel>>(comparer);
|
||||
subclasses.putAll(unsortedSubclasses);
|
||||
subclasses.putAll(unsortedSubclasses);
|
||||
|
||||
for (List<ObjectPropertyStatementTemplateModel> list : subclasses.values()) {
|
||||
postprocessStatementList(list);
|
||||
}
|
||||
}
|
||||
|
||||
private String checkConfiguration() {
|
||||
|
@ -73,12 +82,12 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
|
|||
String queryString = getQueryString();
|
||||
Matcher m;
|
||||
|
||||
m = SELECT_QUERY_PATTERN.matcher(queryString);
|
||||
m = SELECT_SUBCLASS_PATTERN.matcher(queryString);
|
||||
if ( ! m.find() ) {
|
||||
return("Query does not select a subclass variable.");
|
||||
}
|
||||
|
||||
m = ORDER_BY_QUERY_PATTERN.matcher(queryString);
|
||||
m = ORDER_BY_SUBCLASS_PATTERN.matcher(queryString);
|
||||
if ( ! m.find() ) {
|
||||
return("Query does not sort first by subclass variable.");
|
||||
}
|
||||
|
|
|
@ -5,8 +5,12 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
@ -31,13 +35,21 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
|
|||
private static final Log log = LogFactory.getLog(ObjectPropertyTemplateModel.class);
|
||||
private static final String TYPE = "object";
|
||||
|
||||
/* NB The default postprocessor is not the same as the postprocessor for the default view. The latter
|
||||
* actually defines its own postprocessor, whereas the default postprocessor is used for custom views
|
||||
* that don't define a postprocessor, to ensure that the standard postprocessing applies.
|
||||
/* NB The default post-processor is not the same as the post-processor for the default view. The latter
|
||||
* actually defines its own post-processor, whereas the default post-processor is used for custom views
|
||||
* that don't define a post-processor, to ensure that the standard post-processing applies.
|
||||
*/
|
||||
private static final String DEFAULT_POSTPROCESSOR =
|
||||
"edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DefaultObjectPropertyDataPostProcessor";
|
||||
|
||||
private static final String END_DATE_TIME_VARIABLE = "dateTimeEnd";
|
||||
private static final Pattern ORDER_BY_END_DATE_TIME_PATTERN =
|
||||
/* ORDER BY DESC(?dateTimeEnd)
|
||||
* ORDER BY ?subclass ?dateTimeEnd
|
||||
* ORDER BY DESC(?subclass) DESC(?dateTimeEnd)
|
||||
*/
|
||||
Pattern.compile("ORDER\\s+BY\\s+((DESC\\()?\\?subclass\\)?\\s+)?DESC\\s*\\(\\s*\\?" + END_DATE_TIME_VARIABLE + "\\)", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private PropertyListConfig config;
|
||||
|
||||
ObjectPropertyTemplateModel(ObjectProperty op, Individual subject, VitroRequest vreq) {
|
||||
|
@ -91,6 +103,54 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
|
|||
}
|
||||
}
|
||||
|
||||
/* Post-processing that must occur after collation, because it does reordering on collated subclass
|
||||
* lists rather than on the entire list. This should ideally be configurable in the config file
|
||||
* like the pre-collation post-processing, but for now due to time constraints it applies to all views.
|
||||
*/
|
||||
protected void postprocessStatementList(List<ObjectPropertyStatementTemplateModel> statements) {
|
||||
moveEndDateTimesToTop(statements);
|
||||
}
|
||||
|
||||
/* SPARQL ORDER BY gives null values the lowest value, so null datetimes occur at the end
|
||||
* of a list in descending sort order. Generally we assume that a null end datetime means the
|
||||
* activity is ongoing in the present, so we want to display those at the top of the list.
|
||||
* Application of this method should be configurable in the config file, but for now due to
|
||||
* time constraints it applies to all views that sort by DESC(?dateTimeEnd), and the variable
|
||||
* name is hard-coded here. (Note, therefore, that using a different variable name
|
||||
* effectively turns off this post-processing.)
|
||||
*/
|
||||
protected void moveEndDateTimesToTop(List<ObjectPropertyStatementTemplateModel> statements) {
|
||||
String queryString = getQueryString();
|
||||
Matcher m = ORDER_BY_END_DATE_TIME_PATTERN.matcher(queryString);
|
||||
if ( ! m.find() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the statements with null end datetimes in a temporary list, remove them from the original list,
|
||||
// and move them back to the top of the original list.
|
||||
List<ObjectPropertyStatementTemplateModel> tempList = new ArrayList<ObjectPropertyStatementTemplateModel>();
|
||||
Iterator<ObjectPropertyStatementTemplateModel> iterator = statements.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
ObjectPropertyStatementTemplateModel stmt = (ObjectPropertyStatementTemplateModel)iterator.next();
|
||||
String dateTimeEnd = (String) stmt.get(END_DATE_TIME_VARIABLE);
|
||||
if (dateTimeEnd == null) {
|
||||
// If the first statement has a null end datetime, all subsequent statements in the list also do,
|
||||
// so there is nothing to reorder.
|
||||
// NB This assumption is FALSE if the query orders by subclass but the property is not collated.
|
||||
// This happens because all the queries are written with a subclass variable to support
|
||||
// collation if switched on in the back end.
|
||||
//if (statements.indexOf(stmt) == 0) {
|
||||
// break;
|
||||
//}
|
||||
tempList.add(stmt);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
// Put all the statements with null end datetimes at the top of the list, preserving their original order.
|
||||
statements.addAll(0, tempList);
|
||||
|
||||
}
|
||||
|
||||
protected abstract String getDefaultConfigFileName();
|
||||
|
||||
private class PropertyListConfig {
|
||||
|
|
|
@ -40,6 +40,8 @@ public class UncollatedObjectPropertyTemplateModel extends ObjectPropertyTemplat
|
|||
for (Map<String, String> map : statementData) {
|
||||
statements.add(new ObjectPropertyStatementTemplateModel(subjectUri, propertyUri, map));
|
||||
}
|
||||
|
||||
postprocessStatementList(statements);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Reference in a new issue