NIHVIVO-1510 Collation of properties using default list view. NIHVIVO-1569 Fixed a bug in BaseObjectPropertyDataPostProcessor.removeDuplicates()

This commit is contained in:
rjy7 2011-01-05 19:48:50 +00:00
parent 587e83f6b1
commit 25a818efa9
6 changed files with 90 additions and 70 deletions

View file

@ -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);
} }

View file

@ -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 */

View file

@ -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);

View file

@ -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() {

View 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: &lt;http://vitro.mannlib.cornell.edu/ns/vitro/0.7#&gt;
PREFIX rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#&gt;
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 != &lt;http://vitro.mannlib.cornell.edu/default/inferred-tbox&gt; &amp;&amp;
?g4 != &lt;http://vitro.mannlib.cornell.edu/default/vitro-kb-inf&gt; )
}
}
</query>
<postprocessor>edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DefaultListViewDataPostProcessor</postprocessor>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -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