From 1ab53d0b020f891de2506be5c810f9fa490b5c67 Mon Sep 17 00:00:00 2001 From: brianjlowe Date: Tue, 14 May 2013 15:54:03 -0400 Subject: [PATCH] initial work on VIVO-60 application ontology support for property/range combinations --- .../controller/freemarker/UrlBuilder.java | 4 +- .../dao/ObjectPropertyStatementDao.java | 2 +- .../ObjectPropertyStatementDaoFiltering.java | 6 +- .../dao/jena/ObjectPropertyDaoJena.java | 22 ++++- .../jena/ObjectPropertyStatementDaoJena.java | 2 + .../vitro/webapp/dao/jena/VClassDaoSDB.java | 16 ++- ...ApplicationConfigurationOntologyUtils.java | 99 +++++++++++++++++++ .../individual/GroupedPropertyList.java | 22 ++++- .../ObjectPropertyTemplateModel.java | 5 +- .../dao/ObjectPropertyStatementDaoStub.java | 2 +- 10 files changed, 152 insertions(+), 28 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java index f43113d8a..80994386c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java @@ -303,7 +303,7 @@ public class UrlBuilder { } public static String urlEncode(String str) { - String encoding = "ISO-8859-1"; + String encoding = "UTF-8"; String encodedUrl = null; try { encodedUrl = URLEncoder.encode(str, encoding); @@ -314,7 +314,7 @@ public class UrlBuilder { } public static String urlDecode(String str) { - String encoding = "ISO-8859-1"; + String encoding = "UTF-8"; String decodedUrl = null; try { decodedUrl = URLDecoder.decode(str, encoding); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDao.java index 93d52f2ac..34bd23d46 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDao.java @@ -41,7 +41,7 @@ public interface ObjectPropertyStatementDao { public Map getMostSpecificTypesInClassgroupsForIndividual(String subjectUri); List> getObjectPropertyStatementsForIndividualByProperty( - String subjectUri, String propertyUri, String objectKey, + String subjectUri, String propertyUri, String objectKey, String rangeUri, String queryString, Set constructQueryStrings, String sortDirection); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java index 5f09c5188..1bf06d3db 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java @@ -86,12 +86,12 @@ class ObjectPropertyStatementDaoFiltering extends BaseFiltering implements Objec @Override public List> getObjectPropertyStatementsForIndividualByProperty( - String subjectUri, String propertyUri, String objectKey, String query, - Set queryStrings, String sortDirection) { + String subjectUri, String propertyUri, String objectKey, String rangeUri, + String query, Set queryStrings, String sortDirection) { List> data = innerObjectPropertyStatementDao.getObjectPropertyStatementsForIndividualByProperty( - subjectUri, propertyUri, objectKey, query, queryStrings,sortDirection); + subjectUri, propertyUri, objectKey, rangeUri, query, queryStrings,sortDirection); /* Filter the data * diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java index 1c71bcc48..d8560682f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java @@ -27,6 +27,7 @@ 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; +import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; @@ -38,6 +39,7 @@ import com.hp.hpl.jena.util.iterator.ClosableIterator; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; +import com.hp.hpl.jena.sdb.util.Pair; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean; import edu.cornell.mannlib.vitro.webapp.beans.Individual; @@ -859,12 +861,16 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } } - Map customListViewConfigFileMap = null; + //TODO private void addPropertyClassCombinationsToListViewMap(HashMap) + + // Map key is pair of object property and range class URI + // If range is unspecified, OWL.Thing.getURI() is used in the key. + Map, String> customListViewConfigFileMap = null; @Override public String getCustomListViewConfigFileName(ObjectProperty op) { if (customListViewConfigFileMap == null) { - customListViewConfigFileMap = new HashMap(); + customListViewConfigFileMap = new HashMap, String>(); OntModel displayModel = getOntModelSelector().getDisplayModel(); //Get all property to list view config file mappings in the system QueryExecution qexec = QueryExecutionFactory.create(listViewConfigFileQuery, displayModel); @@ -883,12 +889,18 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } } else { String filename = soln.getLiteral("filename").getLexicalForm(); - customListViewConfigFileMap.put(prop, filename); + customListViewConfigFileMap.put(new Pair(prop, OWL.Thing.getURI()), filename); } } qexec.close(); - } - return customListViewConfigFileMap.get(op); + } + + String customListViewConfigFileName = customListViewConfigFileMap.get(new Pair(op, op.getRangeVClassURI())); + if (customListViewConfigFileName == null) { + customListViewConfigFileName = customListViewConfigFileMap.get(new Pair(op, OWL.Thing.getURI())); + } + + return customListViewConfigFileName; } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJena.java index 84255162a..82b6e566f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJena.java @@ -271,6 +271,7 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec String subjectUri, String propertyUri, String objectKey, + String rangeUri, String queryString, Set constructQueryStrings, String sortDirection) { @@ -296,6 +297,7 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec QuerySolutionMap initialBindings = new QuerySolutionMap(); initialBindings.add("subject", ResourceFactory.createResource(subjectUri)); initialBindings.add("property", ResourceFactory.createResource(propertyUri)); + initialBindings.add("objectType", ResourceFactory.createResource(rangeUri)); // Run the SPARQL query to get the properties List> list = new ArrayList>(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoSDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoSDB.java index c177161fa..a5cb04e47 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoSDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoSDB.java @@ -2,24 +2,20 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena; -import java.util.List; - -import com.hp.hpl.jena.ontology.AnnotationProperty; -import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.query.Dataset; 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.QuerySolutionMap; import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.util.iterator.ClosableIterator; import com.hp.hpl.jena.vocabulary.RDF; @@ -57,13 +53,13 @@ public class VClassDaoSDB extends VClassDaoJena { try { if ((group != null) && (group.getURI() != null)) { Resource groupRes = ResourceFactory.createResource(group.getURI()); - AnnotationProperty inClassGroup = getOntModel().getAnnotationProperty(VitroVocabulary.IN_CLASSGROUP); + Property inClassGroup = ResourceFactory.createProperty(VitroVocabulary.IN_CLASSGROUP); if (inClassGroup != null) { - ClosableIterator annotIt = getOntModel().listStatements((OntClass)null,inClassGroup,groupRes); + StmtIterator annotIt = getOntModel().listStatements((Resource)null,inClassGroup, groupRes); try { while (annotIt.hasNext()) { try { - Statement annot = (Statement) annotIt.next(); + Statement annot = (Statement) annotIt.nextStatement(); Resource cls = (Resource) annot.getSubject(); VClass vcw = (VClass) getVClassByURI(cls.getURI()); if (vcw != null) { @@ -95,7 +91,7 @@ public class VClassDaoSDB extends VClassDaoJena { Model aboxModel = getOntModelSelector().getABoxModel(); aboxModel.enterCriticalSection(Lock.READ); try { - ClosableIterator countIt = aboxModel.listStatements(null,RDF.type,cls); + StmtIterator countIt = aboxModel.listStatements(null,RDF.type,cls); try { if (countIt.hasNext()) { classIsInstantiated = true; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java new file mode 100644 index 000000000..7c7855fea --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java @@ -0,0 +1,99 @@ +package edu.cornell.mannlib.vitro.webapp.utils; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +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; +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.Resource; + +import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext; + +public class ApplicationConfigurationOntologyUtils { + + private static final Log log = LogFactory.getLog(ApplicationConfigurationOntologyUtils.class); + + public static List getAdditionalFauxSubpropertiesForList(List propList, VitroRequest vreq) { + Model displayModel = ModelContext.getDisplayModel(vreq.getSession().getServletContext()); + Model tboxModel = ModelContext.getUnionOntModelSelector(vreq.getSession().getServletContext()).getTBoxModel(); + return getAdditionalFauxSubpropertiesForList(propList, displayModel, tboxModel); + } + + public static List getAdditionalFauxSubpropertiesForList(List propList, + Model displayModel, + Model tboxModel) { + List additionalProps = new ArrayList(); + Model union = ModelFactory.createUnion(displayModel, tboxModel); + String propQuery = "PREFIX rdfs: \n" + + "PREFIX config: \n" + + "SELECT ?range ?label ?listView ?group WHERE { \n" + + " ?p rdfs:subPropertyOf ?property . \n" + + " ?context config:configContextFor ?p . \n" + + " ?context config:qualifiedBy ?range . \n" + + " ?context config:hasConfiguration ?configuration . \n" + + " OPTIONAL { ?configuration config:propertyGroup ?group } \n" + + " OPTIONAL { ?configuration config:displayName ?label } \n" + + " OPTIONAL { ?configuration config:hasListView ?lv . ?lv config:listViewConfigFile ?listView } \n" + + "}"; + + for (ObjectProperty op : propList) { + String queryStr = propQuery.replaceAll("\\?property", "<" + op.getURI() + ">"); + log.debug(queryStr); + Query q = QueryFactory.create(queryStr); + QueryExecution qe = QueryExecutionFactory.create(q, union); + try { + ResultSet rs = qe.execSelect(); + while (rs.hasNext()) { + ObjectProperty newProp = new ObjectProperty(); + newProp.setURI(op.getURI()); + QuerySolution qsoln = rs.nextSolution(); + log.debug(qsoln); + Resource rangeRes = qsoln.getResource("range"); + if (rangeRes != null) { + newProp.setRangeVClassURI(rangeRes.getURI()); + } else { + newProp.setRangeVClassURI(op.getRangeVClassURI()); + } + Resource groupRes = qsoln.getResource("group"); + if (groupRes != null) { + newProp.setGroupURI(groupRes.getURI()); + } else { + newProp.setGroupURI(op.getURI()); + } + Literal labelLit = qsoln.getLiteral("label"); + if (labelLit != null) { + newProp.setDomainPublic(labelLit.getLexicalForm()); + } else { + newProp.setDomainPublic(op.getDomainPublic()); + } + Literal listViewLit = qsoln.getLiteral("listView"); + if (listViewLit != null) { + // TODO where do we get the list views from? + } else { + // newProp.set + } + additionalProps.add(newProp); + } + } finally { + qe.close(); + } + } + + return additionalProps; + } + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java index a080cde0b..ac2b6e2a0 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java @@ -25,6 +25,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.PropertyGroupDao; import edu.cornell.mannlib.vitro.webapp.dao.PropertyInstanceDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.utils.ApplicationConfigurationOntologyUtils; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel; /* @@ -72,13 +73,27 @@ public class GroupedPropertyList extends BaseTemplateModel { // so we cannot just rely on getting that list. List populatedObjectPropertyList = subject .getPopulatedObjectPropertyList(); + + List additions = ApplicationConfigurationOntologyUtils + .getAdditionalFauxSubpropertiesForList( + populatedObjectPropertyList, vreq); + if (log.isDebugEnabled()) { + for (ObjectProperty t : additions) { + log.debug(t.getDomainPublic() + " " + t.getGroupURI()); + } + log.debug("Added " + additions.size() + + " properties due to application configuration ontology"); + } + + populatedObjectPropertyList.addAll(additions); + propertyList.addAll(populatedObjectPropertyList); // If editing this page, merge in object properties applicable to the individual that are currently // unpopulated, so the properties are displayed to allow statements to be added to these properties. // RY In future, we should limit this to properties that the user has permission to add properties to. if (editing) { - mergeAllPossibleObjectProperties(populatedObjectPropertyList, propertyList); + mergeAllPossibleObjectProperties(populatedObjectPropertyList, propertyList); } // Now do much the same with data properties: get the list of populated data properties, then add in placeholders for missing ones @@ -108,7 +123,7 @@ public class GroupedPropertyList extends BaseTemplateModel { subject, editing, populatedDataPropertyList, populatedObjectPropertyList)); } - + if (!editing) { pruneEmptyProperties(); } @@ -351,7 +366,6 @@ public class GroupedPropertyList extends BaseTemplateModel { } else { String groupUriForProperty = p.getGroupURI(); boolean assignedToGroup = false; - if (groupUriForProperty != null) { for (PropertyGroup pg : groupList) { String groupUri = pg.getURI(); @@ -359,7 +373,7 @@ public class GroupedPropertyList extends BaseTemplateModel { pg.getPropertyList().add(p); assignedToGroup = true; break; - } + } } } 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 9d6bec0f0..b55d7febf 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 @@ -80,6 +80,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel private PropertyListConfig config; private String objectKey; private String sortDirection; + private String rangeURI; ObjectPropertyTemplateModel(ObjectProperty op, Individual subject, VitroRequest vreq, boolean editing) @@ -89,6 +90,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel setName(op.getDomainPublic()); sortDirection = op.getDomainEntitySortDirection(); + rangeURI = op.getRangeVClassURI(); // Get the config for this object property try { @@ -147,8 +149,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel protected List> getStatementData() { ObjectPropertyStatementDao opDao = vreq.getWebappDaoFactory().getObjectPropertyStatementDao(); - - return opDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, objectKey, getSelectQuery(), getConstructQueries(), sortDirection); + return opDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, objectKey, rangeURI, getSelectQuery(), getConstructQueries(), sortDirection); } protected abstract boolean isEmpty(); diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDaoStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDaoStub.java index aebcd0fb1..d5913a557 100644 --- a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDaoStub.java +++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDaoStub.java @@ -216,7 +216,7 @@ public class ObjectPropertyStatementDaoStub implements @Override public List> getObjectPropertyStatementsForIndividualByProperty( - String subjectUri, String propertyUri, String objectKey, + String subjectUri, String propertyUri, String objectKey, String rangeUri, String query, Set constructQueries, String sortDir) { throw new RuntimeException( "ObjectPropertyStatementDaoStub.getObjectPropertyStatementsForIndividualByProperty() not implemented.");