diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyDao.java index 5c3a4281f..ae1bef568 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyDao.java @@ -1,5 +1,5 @@ -/* $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$ */ + package edu.cornell.mannlib.vitro.webapp.dao; import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; @@ -34,9 +34,11 @@ public interface DataPropertyDao extends PropertyDao { List getRootDataProperties(); - boolean annotateDataPropertyAsExternalIdentifier(String dataPropertyURI); - - public List getDataPropertyList(Individual subject); - + boolean annotateDataPropertyAsExternalIdentifier(String dataPropertyURI); + + public List getDataPropertyList(Individual subject); + public List getDataPropertyList(String subjectUri); + + public String getCustomListViewConfigFileName(DataProperty dataProperty); } \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyStatementDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyStatementDao.java index ff795fa83..3801f9a67 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyStatementDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyStatementDao.java @@ -4,6 +4,7 @@ package edu.cornell.mannlib.vitro.webapp.dao; import java.util.Collection; import java.util.List; +import java.util.Set; import com.hp.hpl.jena.rdf.model.Literal; @@ -44,5 +45,9 @@ public interface DataPropertyStatementDao { List getDataPropertyValuesForIndividualByProperty(String subjectUri, String propertyUri); + List getDataPropertyValuesForIndividualByProperty(Individual subject, DataProperty property, String queryString, Set constructQueryStrings); + + List getDataPropertyValuesForIndividualByProperty(String subjectUri, String propertyUri, String queryString, Set constructQueryStrings); + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyDaoFiltering.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyDaoFiltering.java index f2f569b62..819f84f65 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyDaoFiltering.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyDaoFiltering.java @@ -213,4 +213,9 @@ class DataPropertyDaoFiltering extends BaseFiltering implements DataPropertyDao{ return innerDataPropertyDao.getDataPropertyList(subjectUri); } + @Override + public String getCustomListViewConfigFileName(DataProperty dataProperty) { + return innerDataPropertyDao.getCustomListViewConfigFileName(dataProperty); + } + } \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyStatementDaoFiltering.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyStatementDaoFiltering.java index a7f9868dd..d0936e2fd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyStatementDaoFiltering.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyStatementDaoFiltering.java @@ -7,6 +7,7 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import com.hp.hpl.jena.rdf.model.Literal; @@ -18,6 +19,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters; class DataPropertyStatementDaoFiltering extends BaseFiltering implements DataPropertyStatementDao{ + final DataPropertyStatementDao innerDataPropertyStatementDao; final VitroFilters filters; @@ -141,4 +143,48 @@ class DataPropertyStatementDaoFiltering extends BaseFiltering implements DataPro } + @Override + public List getDataPropertyValuesForIndividualByProperty(Individual subject, DataProperty property, String queryString, Set constructQueryStrings) { + return getDataPropertyValuesForIndividualByProperty(subject.getURI(), property.getURI(), queryString, constructQueryStrings); + } + + @Override + public List getDataPropertyValuesForIndividualByProperty(String subjectUri, String propertyUri, String queryString, Set constructQueryStrings) { + List literals = innerDataPropertyStatementDao.getDataPropertyValuesForIndividualByProperty(subjectUri, propertyUri, queryString, constructQueryStrings); + /* Filter the data + * + * Filtering is applied to a list of DataPropertyStatement. Create these statements, mapped + * to the literal that they are built from, apply filtering to the statements, then get + * the associated literals out of the original list. Use a LinkedHashMap to preserve the ordering. + */ + Map stmtsToLiterals = + new LinkedHashMap(literals.size()); + + for (Literal literal : literals) { + String value = literal.getLexicalForm(); + DataPropertyStatement statement = new DataPropertyStatementImpl(subjectUri, propertyUri, value); + statement.setDatatypeURI(literal.getDatatypeURI()); + statement.setLanguage(literal.getLanguage()); + stmtsToLiterals.put(statement, literal); + } + + List stmtList = new ArrayList(stmtsToLiterals.keySet()); + + // Apply the filters to the list of statements + List filteredStatements = filter(stmtList, filters.getDataPropertyStatementFilter()); + + // Get the literals associated with the filtered statements out of the original list + List filteredLiterals = new ArrayList(filteredStatements.size()); + for (DataPropertyStatement dps : filteredStatements) { + if (dps instanceof DataPropertyStatementFiltering) { + dps = ((DataPropertyStatementFiltering)dps).innerStmt; + } + filteredLiterals.add(stmtsToLiterals.get(dps)); + } + + // Return the filtered list of literals + return filteredLiterals; + + } + } \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java index f0d6f4c3e..fbbb291f7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java @@ -11,6 +11,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -25,6 +26,8 @@ import com.hp.hpl.jena.ontology.ProfileException; import com.hp.hpl.jena.ontology.Restriction; import com.hp.hpl.jena.ontology.SomeValuesFromRestriction; import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.QueryExecution; +import com.hp.hpl.jena.query.QueryExecutionFactory; import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.query.QuerySolution; import com.hp.hpl.jena.query.ResultSet; @@ -729,5 +732,52 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements } return properties; } + protected static final String LIST_VIEW_CONFIG_FILE_QUERY_STRING = + "PREFIX display: " + + "SELECT ?property ?filename WHERE { \n" + + " ?property display:listViewConfigFile ?filename . \n" + + "}"; + + protected static Query listViewConfigFileQuery = null; + static { + try { + listViewConfigFileQuery = QueryFactory.create(LIST_VIEW_CONFIG_FILE_QUERY_STRING); + } catch(Throwable th){ + log.error("could not create SPARQL query for LIST_VIEW_CONFIG_FILE_QUERY_STRING " + th.getMessage()); + log.error(LIST_VIEW_CONFIG_FILE_QUERY_STRING); + } + } + + Map customListViewConfigFileMap = null; + + @Override + public String getCustomListViewConfigFileName(DataProperty dp) { + if (customListViewConfigFileMap == null) { + customListViewConfigFileMap = new HashMap(); + OntModel displayModel = getOntModelSelector().getDisplayModel(); + //Get all property to list view config file mappings in the system + QueryExecution qexec = QueryExecutionFactory.create(listViewConfigFileQuery, displayModel); + ResultSet results = qexec.execSelect(); + //Iterate through mappings looking for the current property and setting up a hashmap for subsequent retrieval + while (results.hasNext()) { + QuerySolution soln = results.next(); + String propertyUri = soln.getResource("property").getURI(); + DataProperty prop = getDataPropertyByURI(propertyUri); + if (prop == null) { + //This is a warning only if this property is the one for which we're searching + if(dp.getURI().equals(propertyUri)){ + log.warn("Can't find property for uri " + propertyUri); + } else { + log.debug("Can't find property for uri " + propertyUri); + } + } else { + String filename = soln.getLiteral("filename").getLexicalForm(); + customListViewConfigFileMap.put(prop, filename); + } + } + qexec.close(); + } + return customListViewConfigFileMap.get(dp); + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyStatementDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyStatementDaoJena.java index 06504e8ca..600d0fa4d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyStatementDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyStatementDaoJena.java @@ -8,6 +8,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import com.hp.hpl.jena.datatypes.TypeMapper; import com.hp.hpl.jena.ontology.OntModel; @@ -18,10 +19,15 @@ import com.hp.hpl.jena.query.QueryExecution; import com.hp.hpl.jena.query.QueryExecutionFactory; import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.query.QuerySolution; +import com.hp.hpl.jena.query.QuerySolutionMap; import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.AnonId; import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.rdf.model.Statement; @@ -38,6 +44,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.edit.ReorderController; import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualUpdateEvent; +import edu.cornell.mannlib.vitro.webapp.dao.jena.ObjectPropertyStatementDaoJena; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -190,6 +197,7 @@ public class DataPropertyStatementDaoJena extends JenaBaseDao implements DataPro Resource res = ResourceFactory.createResource(entity.getURI()); if (!VitroVocabulary.PSEUDO_BNODE_NS.equals(entity.getNamespace())) { for (Literal lit : this.getDataPropertyValuesForIndividualByProperty(res.getURI(), datapropURI)) { + log.debug("Literal lit = " + lit); DataPropertyStatement ed = new DataPropertyStatementImpl(); fillDataPropertyStatementWithJenaLiteral(ed, lit); ed.setIndividualURI(entity.getURI()); @@ -390,4 +398,126 @@ public class DataPropertyStatementDaoJena extends JenaBaseDao implements DataPro } } + + @Override + public List getDataPropertyValuesForIndividualByProperty( + Individual subject, + DataProperty property, + String queryString, Set constructQueryStrings ) { + return getDataPropertyValuesForIndividualByProperty(subject.getURI(), property.getURI(), queryString, constructQueryStrings ); + } + + @Override + public List getDataPropertyValuesForIndividualByProperty( + String subjectUri, + String propertyUri, + String queryString, Set constructQueryStrings ) { + + Model constructedModel = constructModelForSelectQueries( + subjectUri, propertyUri, constructQueryStrings); + + log.debug("Query string for data property " + propertyUri + ": " + queryString); + + Query query = null; + try { + query = QueryFactory.create(queryString, Syntax.syntaxARQ); + } catch(Throwable th){ + log.error("Could not create SPARQL query for query string. " + th.getMessage()); + log.error(queryString); + return Collections.emptyList(); + } + + QuerySolutionMap initialBindings = new QuerySolutionMap(); + initialBindings.add("subject", ResourceFactory.createResource(subjectUri)); + initialBindings.add("property", ResourceFactory.createResource(propertyUri)); + + // Run the SPARQL query to get the properties + List values = new ArrayList(); + DatasetWrapper w = dwf.getDatasetWrapper(); + Dataset dataset = w.getDataset(); + dataset.getLock().enterCriticalSection(Lock.READ); + QueryExecution qexec = null; + try { + + qexec = (constructedModel == null) + ? QueryExecutionFactory.create( + query, dataset, initialBindings) + : QueryExecutionFactory.create( + query, constructedModel, initialBindings); + + ResultSet results = qexec.execSelect(); + + while (results.hasNext()) { + QuerySolution sol = results.next(); + Literal value = sol.getLiteral("value"); + values.add(value); + } + log.debug("values = " + values); + return values; + + } catch (Exception e) { + log.error("Error getting data property values for subject " + subjectUri + " and property " + propertyUri); + return Collections.emptyList(); + } finally { + dataset.getLock().leaveCriticalSection(); + w.close(); + if (qexec != null) { + qexec.close(); + } + } + + } + private Model constructModelForSelectQueries(String subjectUri, + String propertyUri, + Set constructQueries) { + + if (constructQueries == null) { + return null; + } + + Model constructedModel = ModelFactory.createDefaultModel(); + + for (String queryString : constructQueries) { + + log.debug("CONSTRUCT query string for object property " + + propertyUri + ": " + queryString); + + Query query = null; + try { + query = QueryFactory.create(queryString, Syntax.syntaxARQ); + } catch(Throwable th){ + log.error("Could not create CONSTRUCT SPARQL query for query " + + "string. " + th.getMessage()); + log.error(queryString); + return constructedModel; + } + + QuerySolutionMap initialBindings = new QuerySolutionMap(); + initialBindings.add( + "subject", ResourceFactory.createResource(subjectUri)); + initialBindings.add( + "property", ResourceFactory.createResource(propertyUri)); + + DatasetWrapper w = dwf.getDatasetWrapper(); + Dataset dataset = w.getDataset(); + dataset.getLock().enterCriticalSection(Lock.READ); + QueryExecution qe = null; + try { + qe = QueryExecutionFactory.create( + query, dataset, initialBindings); + qe.execConstruct(constructedModel); + } catch (Exception e) { + log.error("Error getting constructed model for subject " + subjectUri + " and property " + propertyUri); + } finally { + if (qe != null) { + qe.close(); + } + dataset.getLock().leaveCriticalSection(); + w.close(); + } + } + + return constructedModel; + + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/DataPropertyListConfig.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/DataPropertyListConfig.java new file mode 100644 index 000000000..b88b9ab38 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/DataPropertyListConfig.java @@ -0,0 +1,159 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DataPropertyTemplateModel; +import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DataPropertyTemplateModel.ConfigError; +import freemarker.cache.TemplateLoader; +import freemarker.template.Configuration; + +public class DataPropertyListConfig { + private static final Log log = LogFactory.getLog(DataPropertyListConfig.class); + + + private static final String CONFIG_FILE_PATH = "/config/"; + private static final String DEFAULT_CONFIG_FILE_NAME = "listViewConfig-dataDefault.xml"; + + /* 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. + * + * edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DefaultObjectPropertyDataPostProcessor + */ + + // TODO Lump these together into the PropertyListConfigContext + private final DataPropertyTemplateModel dptm; + private final VitroRequest vreq; + private final TemplateLoader templateLoader; + + private boolean isDefaultConfig; + private Set constructQueries; + private String selectQuery; + private String templateName; + + public DataPropertyListConfig(DataPropertyTemplateModel dptm, TemplateLoader templateLoader, VitroRequest vreq, + DataProperty dp, boolean editing) + throws InvalidConfigurationException { + + this.dptm = dptm; + this.vreq = vreq; + WebappDaoFactory wadf = vreq.getWebappDaoFactory(); + this.templateLoader = templateLoader; + + // Get the custom config filename + String configFileName = wadf.getDataPropertyDao().getCustomListViewConfigFileName(dp); + if (configFileName == null) { // no custom config; use default config + configFileName = DEFAULT_CONFIG_FILE_NAME; + } + log.debug("Using list view config file " + configFileName + " for data property " + dp.getURI()); + + String configFilePath = getConfigFilePath(configFileName); + + try { + File config = new File(configFilePath); + if ( ! isDefaultConfig(configFileName) && ! config.exists() ) { + log.warn("Can't find config file " + configFilePath + " for data property " + dp.getURI() + "\n" + + ". Using default config file instead."); + configFilePath = getConfigFilePath(DEFAULT_CONFIG_FILE_NAME); + // Should we test for the existence of the default, and throw an error if it doesn't exist? + } + setValuesFromConfigFile(configFilePath, wadf, editing); + + } catch (Exception e) { + log.error("Error processing config file " + configFilePath + " for data property " + dp.getURI(), e); + // What should we do here? + } + + if ( ! isDefaultConfig(configFileName) ) { + ConfigError configError = checkConfiguration(); + if ( configError != null ) { // the configuration contains an error + log.warn("Invalid list view config for data property " + dp.getURI() + + " in " + configFilePath + ":\n" + + configError + " Using default config instead."); + configFilePath = getConfigFilePath(DEFAULT_CONFIG_FILE_NAME); + setValuesFromConfigFile(configFilePath, wadf, editing); + } + } + + isDefaultConfig = isDefaultConfig(configFileName); + } + + private boolean isDefaultConfig(String configFileName) { + return configFileName.equals(DEFAULT_CONFIG_FILE_NAME); + } + + private ConfigError checkConfiguration() { + + ConfigError error = dptm.checkQuery(selectQuery); + if (error != null) { + return error; + } + + if (StringUtils.isBlank(selectQuery)) { + return ConfigError.NO_SELECT_QUERY; + } + + if ( StringUtils.isBlank(templateName)) { + return ConfigError.NO_TEMPLATE; + } + + try { + if ( templateLoader.findTemplateSource(templateName) == null ) { + return ConfigError.TEMPLATE_NOT_FOUND; + } + } catch (IOException e) { + log.error("Error finding template " + templateName, e); + } + + return null; + } + + private void setValuesFromConfigFile(String configFilePath, WebappDaoFactory wdf, + boolean editing) { + try { + FileReader reader = new FileReader(configFilePath); + CustomListViewConfigFile configFileContents = new CustomListViewConfigFile(reader); + + selectQuery = configFileContents.getSelectQuery(false, editing); + templateName = configFileContents.getTemplateName(); + constructQueries = configFileContents.getConstructQueries(); + + } catch (Exception e) { + log.error("Error processing config file " + configFilePath, e); + } + } + + private String getConfigFilePath(String filename) { + return vreq.getSession().getServletContext().getRealPath(CONFIG_FILE_PATH + filename); + } + + public String getSelectQuery() { + return this.selectQuery; + } + + public Set getConstructQueries() { + return this.constructQueries; + } + + public String getTemplateName() { + return this.templateName; + } + + public boolean isDefaultListView() { + return this.isDefaultConfig; + } + +} \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyStatementTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyStatementTemplateModel.java index f9fa1bf1a..47b7bfbac 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyStatementTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyStatementTemplateModel.java @@ -25,13 +25,15 @@ public class DataPropertyStatementTemplateModel extends PropertyStatementTemplat private final Literal literalValue; private final String deleteUrl; private final String editUrl; - + private final String templateName; + //Extended to include vitro request to check for special parameters - public DataPropertyStatementTemplateModel(String subjectUri, String propertyUri, - Literal literal, VitroRequest vreq) { + public DataPropertyStatementTemplateModel(String subjectUri, String propertyUri, Literal literal, + String templateName, VitroRequest vreq) { super(subjectUri, propertyUri, vreq); this.literalValue = literal; + this.templateName = templateName; // Do delete url first, since used in building edit url this.deleteUrl = makeDeleteUrl(); @@ -52,6 +54,7 @@ public class DataPropertyStatementTemplateModel extends PropertyStatementTemplat "datapropKey", makeHash(dps), "cmd", "delete"); + params.put("templateName", templateName); params.putAll(UrlBuilder.getModelParams(vreq)); return UrlBuilder.getUrl(EDIT_PATH, params); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java index 2452851ff..f5036463c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java @@ -4,7 +4,11 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; import java.util.ArrayList; import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -17,11 +21,15 @@ import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException; +import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.DataPropertyListConfig; +import freemarker.cache.TemplateLoader; public class DataPropertyTemplateModel extends PropertyTemplateModel { @@ -31,6 +39,33 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel { private static final String EDIT_PATH = "editRequestDispatch"; private final List statements; + private static final String KEY_SUBJECT = "subject"; + private static final String KEY_PROPERTY = "property"; + + public static enum ConfigError { + NO_SELECT_QUERY("Missing select query specification"), + NO_TEMPLATE("Missing template specification"), + TEMPLATE_NOT_FOUND("Specified template does not exist"); + + String message; + + ConfigError(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public String toString() { + return getMessage(); + } + } + + private DataPropertyListConfig config; + private String objectKey; + private String queryString; + private Set constructQueries; DataPropertyTemplateModel(DataProperty dp, Individual subject, VitroRequest vreq, boolean editing, List populatedDataPropertyList) { @@ -38,15 +73,25 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel { super(dp, subject, vreq); setName(dp.getPublicName()); + // Get the config for this data property + try { + config = new DataPropertyListConfig(this, getFreemarkerTemplateLoader(), vreq, dp, editing); + } catch (Exception e) { + log.error(e, e); + } + + queryString = getSelectQuery(); + constructQueries = getConstructQueries(); + statements = new ArrayList(); // If the property is populated, get the data property statements via a sparql query if (populatedDataPropertyList.contains(dp)) { log.debug("Getting data for populated data property " + getUri()); DataPropertyStatementDao dpDao = vreq.getWebappDaoFactory().getDataPropertyStatementDao(); - List values = dpDao.getDataPropertyValuesForIndividualByProperty(subject, dp); + List values = dpDao.getDataPropertyValuesForIndividualByProperty(subject, dp, queryString, constructQueries); for (Literal value : values) { - statements.add(new DataPropertyStatementTemplateModel(subjectUri, propertyUri, value, vreq)); + statements.add(new DataPropertyStatementTemplateModel(subjectUri, propertyUri, value, getTemplateName(), vreq)); } } else { log.debug("Data property " + getUri() + " is unpopulated."); @@ -57,7 +102,6 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel { } } - protected void setAddUrl(Property property) { DataProperty dp = (DataProperty) property; @@ -91,6 +135,10 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel { addUrl = UrlBuilder.getUrl(EDIT_PATH, params); } + protected TemplateLoader getFreemarkerTemplateLoader() { + return FreemarkerConfigurationLoader.getConfig(vreq).getTemplateLoader(); + } + @Override protected int getPropertyDisplayTier(Property p) { return ((DataProperty)p).getDisplayTier(); @@ -101,6 +149,37 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel { return Route.DATA_PROPERTY_EDIT; } + public ConfigError checkQuery(String queryString) { + if (StringUtils.isBlank(queryString)) { + return ConfigError.NO_SELECT_QUERY; + } + return null; + } + + private String getSelectQuery() { + return config.getSelectQuery(); + } + + private Set getConstructQueries() { + return config.getConstructQueries(); + } + + protected String getTemplateName() { + return config.getTemplateName(); + } + + protected boolean hasDefaultListView() { + return config.isDefaultListView(); + } + + protected String getObjectKey() { + return objectKey; + } + + protected boolean isEmpty() { + return statements.isEmpty(); + } + /* Template properties */ public String getType() { @@ -111,6 +190,9 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel { return statements; } + public String getTemplate() { + return getTemplateName(); + } /* Template methods */ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyStatementTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyStatementTemplateModel.java index 28ff330c3..f68441b96 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyStatementTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyStatementTemplateModel.java @@ -34,7 +34,7 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl public ObjectPropertyStatementTemplateModel(String subjectUri, String propertyUri, String objectKey, Map data, String templateName, VitroRequest vreq) { super(subjectUri, propertyUri, vreq); - + this.data = Collections.unmodifiableMap(new HashMap(data)); this.objectUri = data.get(objectKey); this.templateName = templateName; diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyDaoStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyDaoStub.java index 53faa0201..15c6c81f2 100644 --- a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyDaoStub.java +++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/DataPropertyDaoStub.java @@ -26,6 +26,7 @@ public class DataPropertyDaoStub implements DataPropertyDao { // ---------------------------------------------------------------------- private final Map dpMap = new HashMap(); + private final Map configFilesMap = new HashMap(); public void addDataProperty(DataProperty dataProperty) { if (dataProperty == null) { @@ -40,6 +41,18 @@ public class DataPropertyDaoStub implements DataPropertyDao { dpMap.put(uri, dataProperty); } + public void setCustomListViewConfigFileName(DataProperty property, String filename) { + if (property == null) { + throw new NullPointerException("property may not be null."); + } + + String uri = property.getURI(); + if (uri == null) { + throw new NullPointerException("uri may not be null."); + } + + configFilesMap.put(uri, filename); + } // ---------------------------------------------------------------------- // Stub methods // ---------------------------------------------------------------------- @@ -49,6 +62,17 @@ public class DataPropertyDaoStub implements DataPropertyDao { return dpMap.get(dataPropertyURI); } + @Override + public String getCustomListViewConfigFileName(DataProperty dataProperty) { + if (dataProperty == null) { + return null; + } + String uri = dataProperty.getURI(); + if (uri == null) { + return null; + } + return configFilesMap.get(uri); + } // ---------------------------------------------------------------------- // Un-implemented methods // ---------------------------------------------------------------------- diff --git a/webapp/web/templates/freemarker/lib/lib-properties.ftl b/webapp/web/templates/freemarker/lib/lib-properties.ftl index 271473ff8..139687d1d 100644 --- a/webapp/web/templates/freemarker/lib/lib-properties.ftl +++ b/webapp/web/templates/freemarker/lib/lib-properties.ftl @@ -34,9 +34,9 @@ -<#macro dataPropertyList property editable> +<#macro dataPropertyList property editable template=property.template> <#list property.statements as statement> - <@propertyListItem property statement editable >${statement.value} + <@propertyListItem property statement editable ><#include "${template}">