diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseObjectPropertyDataPostProcessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseObjectPropertyDataPostProcessor.java new file mode 100644 index 000000000..f7f8eec08 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseObjectPropertyDataPostProcessor.java @@ -0,0 +1,114 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; + +public abstract class BaseObjectPropertyDataPostProcessor implements + ObjectPropertyDataPostProcessor { + + private static final Log log = LogFactory.getLog(BaseObjectPropertyDataPostProcessor.class); + + private static String KEY_SUBJECT = "subject"; + private static final String KEY_PROPERTY = "property"; + private static final String DEFAULT_KEY_OBJECT = "object"; + private static final Pattern QUERY_PATTERN = Pattern.compile("\\?" + KEY_SUBJECT + "\\s+\\?" + KEY_PROPERTY + "\\s+\\?(\\w+)"); + + protected ObjectPropertyTemplateModel objectPropertyTemplateModel; + protected WebappDaoFactory wdf; + + public BaseObjectPropertyDataPostProcessor(ObjectPropertyTemplateModel optm, WebappDaoFactory wdf) { + this.objectPropertyTemplateModel = optm; + this.wdf = wdf; + } + + @Override + public void process(List> data) { + removeDuplicates(data); + for (Map map : data) { + process(map); + } + } + + protected abstract void process(Map map); + + /** The SPARQL query results may contain duplicate rows for a single object, if there are multiple assertions for some of the + * other query variables. Remove duplicates here by arbitrarily selecting only the first row returned. + * @param List> data + */ + protected void removeDuplicates(List> data) { + String objectVariableName = getQueryObjectVariableName(); + if (objectVariableName == null) { + log.error("Cannot remove duplicate statements for property " + objectPropertyTemplateModel.getName() + " because no object found to dedupe."); + return; + } + List foundObjects = new ArrayList(); + for (Map map : data) { + String objectValue = map.get(objectVariableName); + // We arbitrarily remove all but the first. Not sure what selection criteria could be brought to bear on this. + if (foundObjects.contains(objectValue)) { + data.remove(map); + } else { + foundObjects.add(objectValue); + } + } + } + + /** Return the name of the primary object variable of the query by inspecting the query string. + * The primary object is the X in the assertion "?subject ?property ?X". + */ + private String getQueryObjectVariableName() { + + String object = null; + + if (objectPropertyTemplateModel.hasDefaultListView()) { + object = DEFAULT_KEY_OBJECT; + log.debug("Using default list view for property " + objectPropertyTemplateModel.getUri() + + ", so query object = '" + DEFAULT_KEY_OBJECT + "'"); + } else { + String queryString = objectPropertyTemplateModel.getQueryString(); + Matcher m = QUERY_PATTERN.matcher(queryString); + if (m.find()) { + object = m.group(1); + log.debug("Query object for property " + objectPropertyTemplateModel.getUri() + " = '" + object + "'"); + } + } + + return object; + } + + /* Postprocessor helper methods callable from any postprocessor */ + + protected void addName(Map map, String nameKey, String objectKey) { + String name = map.get(nameKey); + if (name == null) { + map.put(nameKey, getIndividual(map.get(objectKey)).getName()); + } + } + + /* This is a temporary measure to handle the fact that the current Individual.getMoniker() + * method returns the individual's VClass if moniker is null. We want to replicate that + * behavior here, but in future the moniker property (along with other Vitro namespace + * properties) will be removed. In addition, this type of logic (display x if it exists, otherwise y) + * will be moved into the display modules (Editing and Display Configuration Improvements). + */ + protected void addMoniker(Map map, String monikerKey, String objectKey) { + String moniker = map.get(monikerKey); + if (moniker == null) { + map.put(monikerKey, getIndividual(map.get(objectKey)).getMoniker()); + } + } + + protected Individual getIndividual(String uri) { + return wdf.getIndividualDao().getIndividualByURI(uri); + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseObjectPropertyDataPostprocessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseObjectPropertyDataPostprocessor.java deleted file mode 100644 index c37edb6b6..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseObjectPropertyDataPostprocessor.java +++ /dev/null @@ -1,56 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ -package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; - -import java.util.List; -import java.util.Map; - -import edu.cornell.mannlib.vitro.webapp.beans.Individual; -import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; - -public abstract class BaseObjectPropertyDataPostprocessor implements - ObjectPropertyDataPostprocessor { - - protected ObjectPropertyTemplateModel objectPropertyTemplateModel; - protected WebappDaoFactory wdf; - - public BaseObjectPropertyDataPostprocessor(ObjectPropertyTemplateModel optm, WebappDaoFactory wdf) { - this.objectPropertyTemplateModel = optm; - this.wdf = wdf; - } - - @Override - public void process(List> data) { - for (Map map : data) { - process(map); - } - } - - protected abstract void process(Map map); - - - /* Postprocessor helper methods callable from any postprocessor */ - - protected void addName(Map map, String nameKey, String objectKey) { - String name = map.get(nameKey); - if (name == null) { - map.put(nameKey, getIndividual(map.get(objectKey)).getName()); - } - } - - /* This is a temporary measure to handle the fact that the current Individual.getMoniker() - * method returns the individual's VClass if moniker is null. We want to replicate that - * behavior here, but in future the moniker property (along with other Vitro namespace - * properties) will be removed. In addition, this type of logic (display x if it exists, otherwise y) - * will be moved into the display modules (Editing and Display Configuration Improvements). - */ - protected void addMoniker(Map map, String monikerKey, String objectKey) { - String moniker = map.get(monikerKey); - if (moniker == null) { - map.put(monikerKey, getIndividual(map.get(objectKey)).getMoniker()); - } - } - - protected Individual getIndividual(String uri) { - return wdf.getIndividualDao().getIndividualByURI(uri); - } -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java index 1505e4d43..88635337d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java @@ -53,9 +53,9 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM String propertyUri = op.getURI(); List> statementData = opDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, getQueryString()); - Map> unsortedSubclasses = hasCustomListView() ? - collateCustomListView(subjectUri, propertyUri, statementData, vreq) : - collateDefaultListView(subjectUri, propertyUri, statementData, vreq); + Map> unsortedSubclasses = hasDefaultListView() ? + collateDefaultListView(subjectUri, propertyUri, statementData, vreq) : + collateCustomListView(subjectUri, propertyUri, statementData, vreq); /* Sort by subclass name */ Comparator comparer = new Comparator() { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DefaultListViewDataPostProcessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DefaultListViewDataPostProcessor.java new file mode 100644 index 000000000..1b4016676 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DefaultListViewDataPostProcessor.java @@ -0,0 +1,33 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; + +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; + +/** Data postprocessor for default object property list view **/ +public class DefaultListViewDataPostProcessor extends + BaseObjectPropertyDataPostProcessor { + + private static final Log log = LogFactory.getLog(DefaultListViewDataPostProcessor.class); + + private static final String KEY_NAME = "name"; + private static final String KEY_MONIKER = "moniker"; + private static final String KEY_OBJECT = "object"; + + public DefaultListViewDataPostProcessor(ObjectPropertyTemplateModel optm, WebappDaoFactory wdf) { + super(optm, wdf); + } + + @Override + /* Apply processing specific to this postprocessor */ + protected void process(Map map) { + addName(map, KEY_NAME, KEY_OBJECT); + addMoniker(map, KEY_MONIKER, KEY_OBJECT); + } + +} \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DefaultObjectPropertyDataPostProcessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DefaultObjectPropertyDataPostProcessor.java new file mode 100644 index 000000000..cd77db81d --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DefaultObjectPropertyDataPostProcessor.java @@ -0,0 +1,27 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; + +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; + +/** The object property data postprocessor that is used if the view does not specify another postprocessor */ +public class DefaultObjectPropertyDataPostProcessor extends BaseObjectPropertyDataPostProcessor { + + private static final Log log = LogFactory.getLog(DefaultObjectPropertyDataPostProcessor.class); + + public DefaultObjectPropertyDataPostProcessor(ObjectPropertyTemplateModel optm, + WebappDaoFactory wdf) { + super(optm, wdf); + } + + @Override + protected void process(Map map) { + // no default data postprocessing defined yet + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DefaultObjectPropertyDataPostprocessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DefaultObjectPropertyDataPostprocessor.java deleted file mode 100644 index a991e6e26..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DefaultObjectPropertyDataPostprocessor.java +++ /dev/null @@ -1,29 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; - -import java.util.Map; - -import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; - -public class DefaultObjectPropertyDataPostprocessor extends - BaseObjectPropertyDataPostprocessor { - - protected String KEY_NAME = "name"; - protected String KEY_MONIKER = "moniker"; - protected String KEY_OBJECT = "object"; - - public DefaultObjectPropertyDataPostprocessor(ObjectPropertyTemplateModel optm, WebappDaoFactory wdf) { - super(optm, wdf); - } - - @Override - /* Apply processing specific to this postprocessor */ - protected void process(Map map) { - addName(map, KEY_NAME, KEY_OBJECT); - addMoniker(map, KEY_MONIKER, KEY_OBJECT); - } - - - -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyDataPostprocessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyDataPostProcessor.java similarity index 68% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyDataPostprocessor.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyDataPostProcessor.java index 8880ac3ab..fe9807c6d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyDataPostprocessor.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyDataPostProcessor.java @@ -6,14 +6,14 @@ import java.util.List; import java.util.Map; /** - * These postprocessors take a list of object property statement data derived from a - * SPARQL query (or other source) and prepare it for insertion into the template data model. + * These postprocessors take a list of object property statement data returned from a + * SPARQL query and prepare it for insertion into the template data model. * * @author rjy7 * */ -public interface ObjectPropertyDataPostprocessor { +public interface ObjectPropertyDataPostProcessor { public void process(List> data); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java index 0ab5f77b1..a90d9e264 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java @@ -30,7 +30,14 @@ 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. + */ + private static final String DEFAULT_POSTPROCESSOR = + "edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DefaultObjectPropertyDataPostProcessor"; + private PropertyListConfig config; ObjectPropertyTemplateModel(ObjectProperty op, Individual subject, VitroRequest vreq) { @@ -53,8 +60,8 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel return config.collationTarget; } - protected boolean hasCustomListView() { - return !config.isDefaultConfig; + protected boolean hasDefaultListView() { + return config.isDefaultConfig; } protected static ObjectPropertyTemplateModel getObjectPropertyTemplateModel(ObjectProperty op, Individual subject, VitroRequest vreq) { @@ -74,13 +81,14 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel protected void postprocess(List> data, WebappDaoFactory wdf) { String postprocessorName = config.postprocessor; if (postprocessorName == null) { - return; + //return; + postprocessorName = DEFAULT_POSTPROCESSOR; } try { Class postprocessorClass = Class.forName(postprocessorName); Constructor constructor = postprocessorClass.getConstructor(ObjectPropertyTemplateModel.class, WebappDaoFactory.class); - ObjectPropertyDataPostprocessor postprocessor = (ObjectPropertyDataPostprocessor) constructor.newInstance(this, wdf); + ObjectPropertyDataPostProcessor postprocessor = (ObjectPropertyDataPostProcessor) constructor.newInstance(this, wdf); postprocessor.process(data); } catch (Exception e) { log.error(e, e); diff --git a/webapp/web/config/listViewConfig-default.xml b/webapp/web/config/listViewConfig-default.xml index 6f2d5c720..bd3b30c25 100644 --- a/webapp/web/config/listViewConfig-default.xml +++ b/webapp/web/config/listViewConfig-default.xml @@ -31,7 +31,7 @@ } - edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DefaultObjectPropertyDataPostprocessor + edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DefaultListViewDataPostProcessor