NIHVIVO-1510 Collation of properties using default list view. NIHVIVO-1569 Fixed a bug in BaseObjectPropertyDataPostProcessor.removeDuplicates()
This commit is contained in:
parent
587e83f6b1
commit
25a818efa9
6 changed files with 90 additions and 70 deletions
|
@ -2,6 +2,7 @@
|
||||||
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
|
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -58,11 +59,14 @@ public abstract class BaseObjectPropertyDataPostProcessor implements
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<String> foundObjects = new ArrayList<String>();
|
List<String> foundObjects = new ArrayList<String>();
|
||||||
for (Map<String, String> map : data) {
|
log.debug("Processing property: " + objectPropertyTemplateModel.getUri());
|
||||||
|
Iterator<Map<String, String>> dataIterator = data.iterator();
|
||||||
|
while (dataIterator.hasNext()) {
|
||||||
|
Map<String, String> map = dataIterator.next();
|
||||||
String objectValue = map.get(objectVariableName);
|
String objectValue = map.get(objectVariableName);
|
||||||
// We arbitrarily remove all but the first. Not sure what selection criteria could be brought to bear on this.
|
// We arbitrarily remove all but the first. Not sure what selection criteria could be brought to bear on this.
|
||||||
if (foundObjects.contains(objectValue)) {
|
if (foundObjects.contains(objectValue)) {
|
||||||
data.remove(map);
|
dataIterator.remove();
|
||||||
} else {
|
} else {
|
||||||
foundObjects.add(objectValue);
|
foundObjects.add(objectValue);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,36 +26,27 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||||
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.getLog(CollatedObjectPropertyTemplateModel.class);
|
||||||
|
private static final String DEFAULT_CONFIG_FILE = "listViewConfig-default-collated.xml";
|
||||||
|
|
||||||
private SortedMap<String, List<ObjectPropertyStatementTemplateModel>> subclasses;
|
private SortedMap<String, List<ObjectPropertyStatementTemplateModel>> subclasses;
|
||||||
|
|
||||||
CollatedObjectPropertyTemplateModel(ObjectProperty op, Individual subject, VitroRequest vreq) throws Exception {
|
CollatedObjectPropertyTemplateModel(ObjectProperty op, Individual subject, VitroRequest vreq) throws Exception {
|
||||||
super(op, subject, vreq);
|
super(op, subject, vreq);
|
||||||
|
|
||||||
// RY Temporarily throw an error because collation hasn't been implemented yet.
|
/* Get the data */
|
||||||
// boolean error = true;
|
|
||||||
// if (error) {
|
|
||||||
// throw new Exception("Collated object property not implemented yet");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* Change the approach to collation:
|
|
||||||
* Custom views can get the subclasses in the query. Must use a term ?subclass - throw error if not.
|
|
||||||
* Default view: we may be able to figure out the class to get subclasses of by inspecting the property.
|
|
||||||
* If not, use getDirectClasses etc of the object term.
|
|
||||||
* We need a subclassed and nonsubclassed default query for the default view: collated-query and uncollated-query.
|
|
||||||
* We can also use these for custom views. Throw error if property is collated but there's no subclass term
|
|
||||||
* in the query. (The reverse is okay - uncollated property with a subclass term in the query.
|
|
||||||
*/
|
|
||||||
|
|
||||||
WebappDaoFactory wdf = vreq.getWebappDaoFactory();
|
WebappDaoFactory wdf = vreq.getWebappDaoFactory();
|
||||||
ObjectPropertyStatementDao opDao = wdf.getObjectPropertyStatementDao();
|
ObjectPropertyStatementDao opDao = wdf.getObjectPropertyStatementDao();
|
||||||
String subjectUri = subject.getURI();
|
String subjectUri = subject.getURI();
|
||||||
String propertyUri = op.getURI();
|
String propertyUri = op.getURI();
|
||||||
List<Map<String, String>> statementData = opDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, getQueryString());
|
List<Map<String, String>> statementData =
|
||||||
|
opDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, getQueryString());
|
||||||
|
|
||||||
Map<String, List<ObjectPropertyStatementTemplateModel>> unsortedSubclasses = hasDefaultListView() ?
|
/* Apply postprocessing */
|
||||||
collateDefaultListView(subjectUri, propertyUri, statementData, vreq) :
|
postprocess(statementData, wdf);
|
||||||
collateCustomListView(subjectUri, propertyUri, statementData, vreq);
|
|
||||||
|
/* Collate the data */
|
||||||
|
Map<String, List<ObjectPropertyStatementTemplateModel>> unsortedSubclasses =
|
||||||
|
collate(subjectUri, propertyUri, statementData, vreq);
|
||||||
|
|
||||||
/* Sort by subclass name */
|
/* Sort by subclass name */
|
||||||
Comparator<String> comparer = new Comparator<String>() {
|
Comparator<String> comparer = new Comparator<String>() {
|
||||||
|
@ -67,10 +58,10 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
|
||||||
subclasses.putAll(unsortedSubclasses);
|
subclasses.putAll(unsortedSubclasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, List<ObjectPropertyStatementTemplateModel>> collateCustomListView(String subjectUri,
|
private Map<String, List<ObjectPropertyStatementTemplateModel>> collate(String subjectUri,
|
||||||
String propertyUri, List<Map<String, String>> statementData, VitroRequest vreq) {
|
String propertyUri, List<Map<String, String>> statementData, VitroRequest vreq) {
|
||||||
|
|
||||||
Map<String, List<ObjectPropertyStatementTemplateModel>> unsortedSubclasses =
|
Map<String, List<ObjectPropertyStatementTemplateModel>> subclassMap =
|
||||||
new HashMap<String, List<ObjectPropertyStatementTemplateModel>>();
|
new HashMap<String, List<ObjectPropertyStatementTemplateModel>>();
|
||||||
String currentSubclassUri = null;
|
String currentSubclassUri = null;
|
||||||
List<ObjectPropertyStatementTemplateModel> currentList = null;
|
List<ObjectPropertyStatementTemplateModel> currentList = null;
|
||||||
|
@ -80,19 +71,11 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
|
||||||
currentSubclassUri = subclassUri;
|
currentSubclassUri = subclassUri;
|
||||||
currentList = new ArrayList<ObjectPropertyStatementTemplateModel>();
|
currentList = new ArrayList<ObjectPropertyStatementTemplateModel>();
|
||||||
String subclassName = getSubclassName(subclassUri, vreq);
|
String subclassName = getSubclassName(subclassUri, vreq);
|
||||||
unsortedSubclasses.put(subclassName, currentList);
|
subclassMap.put(subclassName, currentList);
|
||||||
}
|
}
|
||||||
currentList.add(new ObjectPropertyStatementTemplateModel(subjectUri, propertyUri, map));
|
currentList.add(new ObjectPropertyStatementTemplateModel(subjectUri, propertyUri, map));
|
||||||
}
|
}
|
||||||
return unsortedSubclasses;
|
return subclassMap;
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, List<ObjectPropertyStatementTemplateModel>> collateDefaultListView(String subjectUri,
|
|
||||||
String propertyUri, List<Map<String, String>> statementData, VitroRequest vreq) {
|
|
||||||
|
|
||||||
Map<String, List<ObjectPropertyStatementTemplateModel>> unsortedSubclasses =
|
|
||||||
new HashMap<String, List<ObjectPropertyStatementTemplateModel>>();
|
|
||||||
return unsortedSubclasses;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getSubclassName(String subclassUri, VitroRequest vreq) {
|
private String getSubclassName(String subclassUri, VitroRequest vreq) {
|
||||||
|
@ -101,27 +84,9 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
|
||||||
return vclass.getName();
|
return vclass.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCollationTargetError() {
|
@Override
|
||||||
String errorMessage = null;
|
protected String getDefaultConfigFileName() {
|
||||||
String collationTarget = getCollationTarget();
|
return DEFAULT_CONFIG_FILE;
|
||||||
// Make sure the collation target is not null or empty.
|
|
||||||
if (collationTarget == null || collationTarget.trim().isEmpty()) {
|
|
||||||
errorMessage = "No collation target specified.";
|
|
||||||
} else {
|
|
||||||
// Make sure the collation target is one of the select terms in the query.
|
|
||||||
String queryString = getQueryString();
|
|
||||||
String selectClause = queryString.substring(0, queryString.indexOf("{"));
|
|
||||||
Pattern collationTargetPattern = Pattern.compile("\\b\\\\?" + collationTarget + "\\b");
|
|
||||||
Matcher matcher = collationTargetPattern.matcher(selectClause);
|
|
||||||
if (! matcher.find()) {
|
|
||||||
errorMessage = "Invalid collation target.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<VClass> getDirectVClasses(String key, List<Map<String, Object>> data) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Access methods for templates */
|
/* Access methods for templates */
|
||||||
|
|
|
@ -56,10 +56,6 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
|
||||||
return config.queryString;
|
return config.queryString;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getCollationTarget() {
|
|
||||||
return config.collationTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean hasDefaultListView() {
|
protected boolean hasDefaultListView() {
|
||||||
return config.isDefaultConfig;
|
return config.isDefaultConfig;
|
||||||
}
|
}
|
||||||
|
@ -95,19 +91,18 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract String getDefaultConfigFileName();
|
||||||
|
|
||||||
private class PropertyListConfig {
|
private class PropertyListConfig {
|
||||||
|
|
||||||
private static final String DEFAULT_CONFIG_FILE = "listViewConfig-default.xml";
|
|
||||||
private static final String CONFIG_FILE_PATH = "/config/";
|
private static final String CONFIG_FILE_PATH = "/config/";
|
||||||
private static final String NODE_NAME_QUERY = "query";
|
private static final String NODE_NAME_QUERY = "query";
|
||||||
private static final String NODE_NAME_TEMPLATE = "template";
|
private static final String NODE_NAME_TEMPLATE = "template";
|
||||||
private static final String NODE_NAME_COLLATION_TARGET = "collation-target";
|
|
||||||
private static final String NODE_NAME_POSTPROCESSOR = "postprocessor";
|
private static final String NODE_NAME_POSTPROCESSOR = "postprocessor";
|
||||||
|
|
||||||
private boolean isDefaultConfig;
|
private boolean isDefaultConfig;
|
||||||
private String queryString;
|
private String queryString;
|
||||||
private String templateName;
|
private String templateName;
|
||||||
private String collationTarget;
|
|
||||||
private String postprocessor;
|
private String postprocessor;
|
||||||
|
|
||||||
PropertyListConfig(ObjectProperty op, VitroRequest vreq) throws Exception {
|
PropertyListConfig(ObjectProperty op, VitroRequest vreq) throws Exception {
|
||||||
|
@ -117,7 +112,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
|
||||||
ObjectPropertyDao opDao = wdf.getObjectPropertyDao();
|
ObjectPropertyDao opDao = wdf.getObjectPropertyDao();
|
||||||
String configFileName = opDao.getCustomListConfigFileName(op);
|
String configFileName = opDao.getCustomListConfigFileName(op);
|
||||||
if (configFileName == null) { // no custom config; use default config
|
if (configFileName == null) { // no custom config; use default config
|
||||||
configFileName = DEFAULT_CONFIG_FILE;
|
configFileName = getDefaultConfigFileName();
|
||||||
}
|
}
|
||||||
log.debug("Using list view config file " + configFileName + " for object property " + op.getURI());
|
log.debug("Using list view config file " + configFileName + " for object property " + op.getURI());
|
||||||
|
|
||||||
|
@ -127,7 +122,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
|
||||||
if ( ! isDefaultConfig(configFileName) && ! config.exists() ) {
|
if ( ! isDefaultConfig(configFileName) && ! config.exists() ) {
|
||||||
log.warn("Can't find config file " + configFilePath + " for object property " + op.getURI() + "\n" +
|
log.warn("Can't find config file " + configFilePath + " for object property " + op.getURI() + "\n" +
|
||||||
". Using default config file instead.");
|
". Using default config file instead.");
|
||||||
configFilePath = getConfigFilePath(DEFAULT_CONFIG_FILE);
|
configFilePath = getConfigFilePath(getDefaultConfigFileName());
|
||||||
// Should we test for the existence of the default, and throw an error if it doesn't exist?
|
// Should we test for the existence of the default, and throw an error if it doesn't exist?
|
||||||
}
|
}
|
||||||
setValuesFromConfigFile(configFilePath);
|
setValuesFromConfigFile(configFilePath);
|
||||||
|
@ -143,7 +138,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
|
||||||
log.warn("Invalid list view config for object property " + op.getURI() +
|
log.warn("Invalid list view config for object property " + op.getURI() +
|
||||||
" in " + configFilePath + ":\n" +
|
" in " + configFilePath + ":\n" +
|
||||||
invalidConfigMessage + " Using default config instead.");
|
invalidConfigMessage + " Using default config instead.");
|
||||||
configFilePath = getConfigFilePath(DEFAULT_CONFIG_FILE);
|
configFilePath = getConfigFilePath(getDefaultConfigFileName());
|
||||||
setValuesFromConfigFile(configFilePath);
|
setValuesFromConfigFile(configFilePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +147,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDefaultConfig(String configFileName) {
|
private boolean isDefaultConfig(String configFileName) {
|
||||||
return configFileName.equals(DEFAULT_CONFIG_FILE);
|
return configFileName.equals(getDefaultConfigFileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String checkForInvalidConfig(VitroRequest vreq) {
|
private String checkForInvalidConfig(VitroRequest vreq) {
|
||||||
|
@ -189,7 +184,6 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
|
||||||
templateName = getConfigValue(doc, NODE_NAME_TEMPLATE);
|
templateName = getConfigValue(doc, NODE_NAME_TEMPLATE);
|
||||||
|
|
||||||
// Optional values
|
// Optional values
|
||||||
collationTarget = getConfigValue(doc, NODE_NAME_COLLATION_TARGET);
|
|
||||||
postprocessor = getConfigValue(doc, NODE_NAME_POSTPROCESSOR);
|
postprocessor = getConfigValue(doc, NODE_NAME_POSTPROCESSOR);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error processing config file " + configFilePath, e);
|
log.error("Error processing config file " + configFilePath, e);
|
||||||
|
|
|
@ -18,23 +18,35 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||||
public class UncollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateModel {
|
public class UncollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateModel {
|
||||||
|
|
||||||
private static final Log log = LogFactory.getLog(UncollatedObjectPropertyTemplateModel.class);
|
private static final Log log = LogFactory.getLog(UncollatedObjectPropertyTemplateModel.class);
|
||||||
|
private static final String DEFAULT_CONFIG_FILE = "listViewConfig-default-uncollated.xml";
|
||||||
|
|
||||||
private List<ObjectPropertyStatementTemplateModel> statements;
|
private List<ObjectPropertyStatementTemplateModel> statements;
|
||||||
|
|
||||||
UncollatedObjectPropertyTemplateModel(ObjectProperty op, Individual subject, VitroRequest vreq) {
|
UncollatedObjectPropertyTemplateModel(ObjectProperty op, Individual subject, VitroRequest vreq) {
|
||||||
super(op, subject, vreq);
|
super(op, subject, vreq);
|
||||||
|
|
||||||
|
/* Get the data */
|
||||||
WebappDaoFactory wdf = vreq.getWebappDaoFactory();
|
WebappDaoFactory wdf = vreq.getWebappDaoFactory();
|
||||||
ObjectPropertyStatementDao opDao = wdf.getObjectPropertyStatementDao();
|
ObjectPropertyStatementDao opDao = wdf.getObjectPropertyStatementDao();
|
||||||
String subjectUri = subject.getURI();
|
String subjectUri = subject.getURI();
|
||||||
String propertyUri = op.getURI();
|
String propertyUri = op.getURI();
|
||||||
List<Map<String, String>> statementData = opDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, getQueryString());
|
List<Map<String, String>> statementData = opDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, getQueryString());
|
||||||
|
|
||||||
|
/* Apply postprocessing */
|
||||||
postprocess(statementData, wdf);
|
postprocess(statementData, wdf);
|
||||||
|
|
||||||
|
/* Put into data structure to send to template */
|
||||||
statements = new ArrayList<ObjectPropertyStatementTemplateModel>(statementData.size());
|
statements = new ArrayList<ObjectPropertyStatementTemplateModel>(statementData.size());
|
||||||
for (Map<String, String> map : statementData) {
|
for (Map<String, String> map : statementData) {
|
||||||
statements.add(new ObjectPropertyStatementTemplateModel(subjectUri, propertyUri, map));
|
statements.add(new ObjectPropertyStatementTemplateModel(subjectUri, propertyUri, map));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultConfigFileName() {
|
||||||
|
return DEFAULT_CONFIG_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Access methods for templates */
|
/* Access methods for templates */
|
||||||
|
|
||||||
public List<ObjectPropertyStatementTemplateModel> getStatements() {
|
public List<ObjectPropertyStatementTemplateModel> getStatements() {
|
||||||
|
|
43
webapp/web/config/listViewConfig-default-collated.xml
Normal file
43
webapp/web/config/listViewConfig-default-collated.xml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Default list view config file for collated object properties
|
||||||
|
|
||||||
|
Required elements:
|
||||||
|
- query: the sparql query used to retrieve the data
|
||||||
|
- template: the name of the template used to display a single property statement
|
||||||
|
|
||||||
|
Optional elements:
|
||||||
|
- postprocessor: a Java class that postprocesses the data retrieved from the query before
|
||||||
|
sending it to the template
|
||||||
|
|
||||||
|
Query requirements:
|
||||||
|
- WHERE clause must contain a statement ?subject ?property ?object, with the variables
|
||||||
|
?subject and ?property named as such. The object can be given any name, but it must be
|
||||||
|
included in the SELECT terms retrieved by the query. This is the statement that will be edited
|
||||||
|
from the edit links.
|
||||||
|
- Each assertion or set of optional assertions must reference a different graph variable, so that
|
||||||
|
we do not impose a requirement about which assertions are in the same graph.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<list-view-config>
|
||||||
|
<query>
|
||||||
|
PREFIX vitro: <http://vitro.mannlib.cornell.edu/ns/vitro/0.7#>
|
||||||
|
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||||
|
|
||||||
|
SELECT ?subclass ?object ?name ?moniker {
|
||||||
|
GRAPH ?g1 { ?subject ?property ?object }
|
||||||
|
OPTIONAL { GRAPH ?g2 { ?object rdfs:label ?name } }
|
||||||
|
OPTIONAL { GRAPH ?g3 { ?object vitro:moniker ?moniker } }
|
||||||
|
OPTIONAL { GRAPH ?g4 { ?object a ?subclass }
|
||||||
|
FILTER (?g4 != <http://vitro.mannlib.cornell.edu/default/inferred-tbox> &&
|
||||||
|
?g4 != <http://vitro.mannlib.cornell.edu/default/vitro-kb-inf> )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</query>
|
||||||
|
|
||||||
|
<postprocessor>edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DefaultListViewDataPostProcessor</postprocessor>
|
||||||
|
|
||||||
|
<template>propStatement-default.ftl</template>
|
||||||
|
</list-view-config>
|
|
@ -2,6 +2,8 @@
|
||||||
<!-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
<!-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
Default list view config file for uncollated object properties
|
||||||
|
|
||||||
Required elements:
|
Required elements:
|
||||||
- query: the sparql query used to retrieve the data
|
- query: the sparql query used to retrieve the data
|
||||||
- template: the name of the template used to display a single property statement
|
- template: the name of the template used to display a single property statement
|
Loading…
Add table
Add a link
Reference in a new issue