From b3a0b4cef82ca4ec4852d2f33d420e198609221a Mon Sep 17 00:00:00 2001 From: Brian Caruso Date: Wed, 30 Oct 2013 16:24:02 -0400 Subject: [PATCH 1/2] Removing unused code and fixing NPE in IndividualRequestAnalysisContextImpl.java VIVO-229 --- .../IndividualRequestAnalysisContextImpl.java | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalysisContextImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalysisContextImpl.java index 5f3ebc7e4..a6ad31af7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalysisContextImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalysisContextImpl.java @@ -4,11 +4,6 @@ package edu.cornell.mannlib.vitro.webapp.controller.individual; import java.util.List; -import javax.servlet.ServletContext; - -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.beans.SelfEditingConfiguration; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; @@ -22,18 +17,13 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo; */ public class IndividualRequestAnalysisContextImpl implements IndividualRequestAnalysisContext { - private static final Log log = LogFactory - .getLog(IndividualRequestAnalysisContextImpl.class); - - - private final VitroRequest vreq; - private final ServletContext ctx; + + private final VitroRequest vreq; private final WebappDaoFactory wadf; private final IndividualDao iDao; public IndividualRequestAnalysisContextImpl(VitroRequest vreq) { - this.vreq = vreq; - this.ctx = vreq.getSession().getServletContext(); + this.vreq = vreq; this.wadf = vreq.getWebappDaoFactory(); this.iDao = wadf.getIndividualDao(); } From e1b763820210e975fd9386b2a091e40701e2bf60 Mon Sep 17 00:00:00 2001 From: brianjlowe Date: Thu, 31 Oct 2013 10:43:25 -0400 Subject: [PATCH 2/2] various performance tweaks --- .../vitro/webapp/beans/Individual.java | 7 + .../vitro/webapp/beans/ObjectProperty.java | 53 +++++- .../vitro/webapp/dao/ObjectPropertyDao.java | 26 +++ .../webapp/dao/WebappDaoFactoryConfig.java | 15 ++ .../filtering/ObjectPropertyDaoFiltering.java | 5 + .../webapp/dao/jena/DataPropertyDaoJena.java | 12 +- .../dao/jena/ObjectPropertyDaoJena.java | 120 +++++++++--- .../jena/ObjectPropertyStatementDaoJena.java | 179 ++++++++++-------- .../webapp/dao/jena/PropertyDaoJena.java | 71 +++---- .../dao/jena/PropertyInstanceDaoJena.java | 7 +- .../webapp/dao/jena/WebappDaoFactoryJena.java | 10 +- .../webapp/filters/RequestModelsPrep.java | 18 ++ .../webapp/ontology/update/ABoxUpdater.java | 23 ++- .../ontology/update/KnowledgeBaseUpdater.java | 6 +- .../webapp/servlet/setup/FileGraphSetup.java | 23 ++- .../servlet/setup/SimpleReasonerSetup.java | 39 +++- .../servlet/setup/UpdateKnowledgeBase.java | 38 +--- ...ApplicationConfigurationOntologyUtils.java | 2 +- .../individual/GroupedPropertyList.java | 67 ++++++- .../PropertyGroupTemplateModel.java | 7 + .../webapp/dao/ObjectPropertyDaoStub.java | 9 +- 21 files changed, 537 insertions(+), 200 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/Individual.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/Individual.java index e9892ba4b..0f19cc9c7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/Individual.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/Individual.java @@ -34,6 +34,13 @@ public interface Individual extends ResourceBean, Comparable { List getObjectPropertyList(); void setPropertyList(List propertyList); + /** + * Returns a list of ObjectProperty objects for which statements exist about + * the individual. Note that this method now returns multiple copies of + * a given predicate, with the rangeVClassURI changed to indicate the distinct + * types of the related objects. This supports finding the approriate list + * views for the "faux" qualified properties. + */ List getPopulatedObjectPropertyList(); void setPopulatedObjectPropertyList(List propertyList); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ObjectProperty.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ObjectProperty.java index 1c4e8a9b1..7d1d908fb 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ObjectProperty.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ObjectProperty.java @@ -22,7 +22,7 @@ import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; * a class representing an object property * */ -public class ObjectProperty extends Property implements Comparable, ResourceBean +public class ObjectProperty extends Property implements Comparable, ResourceBean, Cloneable { private static final Log log = LogFactory.getLog(ObjectProperty.class.getName()); @@ -610,6 +610,55 @@ public class ObjectProperty extends Property implements Comparable getObjectPropertiesForObjectPropertyStatements(List /*of ObjectPropertyStatement */ objectPropertyStatements); @@ -54,8 +66,22 @@ public interface ObjectPropertyDao extends PropertyDao { List getRootObjectProperties(); + /** + * Returns a list of ObjectProperty objects for which statements exist about + * the individual. Note that this method now returns multiple copies of + * a given predicate, with the rangeVClassURI changed to indicate the distinct + * types of the related objects. This supports finding the approriate list + * views for the "faux" qualified properties. + */ public List getObjectPropertyList(Individual subject); + /** + * Returns a list of ObjectProperty objects for which statements exist about + * the individual. Note that this method now returns multiple copies of + * a given predicate, with the rangeVClassURI changed to indicate the distinct + * types of the related objects. This supports finding the approriate list + * views for the "faux" qualified properties. + */ public List getObjectPropertyList(String subjectUri); public String getCustomListViewConfigFileName(ObjectProperty objectProperty); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java index aea5acc1c..ee5eaf2de 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java @@ -5,14 +5,20 @@ package edu.cornell.mannlib.vitro.webapp.dao; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import org.openjena.atlas.lib.Pair; + +import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; + public class WebappDaoFactoryConfig { private List preferredLanguages; private String defaultNamespace; private Set nonUserNamespaces; private boolean isUnderlyingStoreReasoned = false; + public Map>, String> customListViewConfigFileMap; public WebappDaoFactoryConfig() { preferredLanguages = Arrays.asList("en-US", "en", "EN"); @@ -53,4 +59,13 @@ public class WebappDaoFactoryConfig { return this.isUnderlyingStoreReasoned; } + public Map>, String> getCustomListViewConfigFileMap() { + return this.getCustomListViewConfigFileMap(); + } + + public void setCustomListViewConfigFileMap( + Map>, String> map) { + this.customListViewConfigFileMap = map; + } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java index 525301c3b..0a5848d98 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java @@ -54,6 +54,11 @@ class ObjectPropertyDaoFiltering extends BaseFiltering implements ObjectProperty return (newOprop == null) ? null : new ObjectPropertyFiltering(newOprop, filters); } + public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, String domainURI, String rangeURI, ObjectProperty base) { + ObjectProperty newOprop=innerObjectPropertyDao.getObjectPropertyByURIs(objectPropertyURI, domainURI, rangeURI, base); + return (newOprop == null) ? null : new ObjectPropertyFiltering(newOprop, filters); + } + public List getStatementsUsingObjectProperty(ObjectProperty op) { return ObjectPropertyStatementDaoFiltering.filterAndWrapList(innerObjectPropertyDao.getStatementsUsingObjectProperty(op),filters); } 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 c137de39c..71714fae7 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 @@ -45,15 +45,14 @@ import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean; import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.Individual; -import edu.cornell.mannlib.vitro.webapp.beans.Ontology; import edu.cornell.mannlib.vitro.webapp.beans.PropertyInstance; import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyDao; import edu.cornell.mannlib.vitro.webapp.dao.InsertException; -import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; public class DataPropertyDaoJena extends PropertyDaoJena implements DataPropertyDao { @@ -71,9 +70,10 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements } } - public DataPropertyDaoJena(DatasetWrapperFactory dwf, + public DataPropertyDaoJena(RDFService rdfService, + DatasetWrapperFactory dwf, WebappDaoFactoryJena wadf) { - super(dwf, wadf); + super(rdfService, dwf, wadf); } public void deleteDataProperty(DataProperty dtp) { @@ -672,7 +672,7 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements PREFIXES + "\n" + "SELECT DISTINCT ?property WHERE { \n" + " ?subject ?property ?object . \n" + - " ?property a owl:DatatypeProperty . \n" + + //" ?property a owl:DatatypeProperty . \n" + " FILTER ( \n" + " isLiteral(?object) && \n" + " ( !regex(str(?property), \"^" + VitroVocabulary.PUBLIC + "\" )) && \n" + @@ -708,7 +708,7 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements } log.debug("Data property query string:\n" + query); - ResultSet results = getPropertyQueryResults(query); + ResultSet results = getPropertyQueryResults(queryString); List properties = new ArrayList(); while (results.hasNext()) { QuerySolution sol = results.next(); 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 fbaef1052..9c38774ab 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 @@ -13,11 +13,13 @@ import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.openjena.atlas.lib.Pair; import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; import com.hp.hpl.jena.ontology.ConversionException; import com.hp.hpl.jena.ontology.DatatypeProperty; import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.ontology.OntProperty; import com.hp.hpl.jena.ontology.OntResource; import com.hp.hpl.jena.ontology.ProfileException; @@ -28,7 +30,6 @@ 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.Property; import com.hp.hpl.jena.rdf.model.RDFNode; @@ -37,30 +38,31 @@ 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.sparql.expr.NodeValue; 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; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; -import edu.cornell.mannlib.vitro.webapp.beans.Ontology; import edu.cornell.mannlib.vitro.webapp.dao.InsertException; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao; -import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectPropertyDao { private static final Log log = LogFactory.getLog(ObjectPropertyDaoJena.class.getName()); - - public ObjectPropertyDaoJena(DatasetWrapperFactory dwf, + + public ObjectPropertyDaoJena(RDFService rdfService, + DatasetWrapperFactory dwf, + Map>, String> + customListViewConfigFileMap, WebappDaoFactoryJena wadf) { - super(dwf, wadf); + super(rdfService, dwf, wadf); + this.customListViewConfigFileMap = customListViewConfigFileMap; } @Override @@ -69,7 +71,6 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } public void deleteObjectProperty(String propertyURI) { - OntProperty p = getOntModel().getOntProperty(propertyURI); ObjectProperty op = new ObjectProperty(); op.setURI(propertyURI); deleteObjectProperty(op); @@ -269,22 +270,35 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } public ObjectProperty getObjectPropertyByURI(String propertyURI) { + + long start = System.currentTimeMillis(); if( propertyURI == null ) return null; - getOntModel().enterCriticalSection(Lock.READ); + OntModel ontModel = getOntModel(); + OntModel localModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + + ontModel.enterCriticalSection(Lock.READ); try { - OntProperty op = getOntModel().getObjectProperty(propertyURI); + localModel.add(ontModel.listStatements(ontModel.getResource(propertyURI), null, (RDFNode) null)); + OntProperty op = localModel.getObjectProperty(propertyURI); return propertyFromOntProperty(op); } finally { - getOntModel().leaveCriticalSection(); + ontModel.leaveCriticalSection(); } } - public ObjectProperty getObjectPropertyByURIs(String propertyURI, String domainURI, String rangeURI) { + public ObjectProperty getObjectPropertyByURIs(String propertyURI, + String domainURI, String rangeURI) { + return getObjectPropertyByURIs(propertyURI, domainURI, rangeURI, null); + } + + public ObjectProperty getObjectPropertyByURIs(String propertyURI, + String domainURI, String rangeURI, ObjectProperty base) { if(log.isDebugEnabled()) { log.debug("Getting " + propertyURI + " with domain " + domainURI + " and range " + rangeURI); } - ObjectProperty op = getObjectPropertyByURI(propertyURI); + long start = System.currentTimeMillis(); + ObjectProperty op = (base != null) ? base : getObjectPropertyByURI(propertyURI); if (op == null || rangeURI == null) { return op; } @@ -293,7 +307,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp String propQuery = "PREFIX rdfs: \n" + "PREFIX config: \n" + "PREFIX vitro: \n" + - "SELECT ?range ?label ?group ?customForm ?displayRank ?displayLevel " + + "SELECT ?range ?rangeRoot ?label ?group ?customForm ?displayRank ?displayLevel " + " ?updateLevel ?editLinkSuppressed ?addLinkSuppressed ?deleteLinkSuppressed \n" + " ?collateBySubclass ?displayLimit ?individualSortProperty \n" + " ?entitySortDirection ?selectFromExisting ?offerCreateNew \n" + @@ -308,7 +322,8 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp if (rangeURI != null) { propQuery += " ?context config:qualifiedBy <" + rangeURI + "> . \n"; }; - propQuery += " ?context config:hasConfiguration ?configuration . \n" + + propQuery += " OPTIONAL { ?context config:qualifiedByRoot ?rangeRoot } \n" + + " ?context config:hasConfiguration ?configuration . \n" + " ?configuration a config:ObjectPropertyDisplayConfig . \n" + " OPTIONAL { ?configuration config:propertyGroup ?group } \n" + " OPTIONAL { ?configuration config:displayName ?label } \n" + @@ -334,6 +349,15 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp ResultSet rs = qe.execSelect(); if (rs.hasNext()) { QuerySolution qsoln = rs.nextSolution(); + // This is a bit of hack, used for things where the type of the + // immediately-related object ("root," for lack of a better term) + // is important to record but not the type directly associated with + // a configuration + Resource rangeRootRes = qsoln.getResource("rangeRoot"); + if (rangeRootRes != null) { + // reusing this obsolete field for now + op.setRangeEntityURI(rangeRootRes.getURI()); + } Resource groupRes = qsoln.getResource("group"); if (groupRes != null) { op.setGroupURI(groupRes.getURI()); @@ -407,7 +431,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } } finally { qe.close(); - } + } return op; } @@ -918,24 +942,30 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp "?property = vitro:additionalLink ||" + "!regex(str(?property), \"^http://vitro.mannlib.cornell.edu/ns/vitro/0.7#\" ))"); PROPERTY_FILTERS = StringUtils.join(namespaceFilters, " && "); - } + } protected static final String OBJECT_PROPERTY_QUERY_STRING = PREFIXES + "\n" + - "SELECT DISTINCT ?property WHERE { \n" + - " ?subject ?property ?object . \n" + + "SELECT DISTINCT ?property ?objType WHERE { \n" + + " ?subject ?property ?object . \n" + + " ?object a ?objType . \n" + // " ?property a owl:ObjectProperty . \n" + " FILTER ( \n" + " isURI(?object) && \n" + PROPERTY_FILTERS + "\n" + " ) \n" + - "}"; + "} ORDER BY ?property ?objType"; @Override public List getObjectPropertyList(Individual subject) { return getObjectPropertyList(subject.getURI()); } - + + // Returns a list of ObjectProperty objects for which statements exist about + // the individual. Note that this method now returns additional copies of + // a given predicate, with the rangeVClassURI changed to indicate the distinct + // types of the related objects. This supports finding the approriate list + // views for the "faux" qualified properties. @Override public List getObjectPropertyList(String subjectUri) { @@ -954,15 +984,35 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } log.debug("Object property query:\n" + query); - ResultSet results = getPropertyQueryResults(query); + ObjectProperty propRegister = new ObjectProperty(); + propRegister.setURI(""); + + ResultSet results = getPropertyQueryResults(queryString); List properties = new ArrayList(); while (results.hasNext()) { QuerySolution soln = results.next(); Resource resource = soln.getResource("property"); String uri = resource.getURI(); - log.debug("Found populated object property " + uri); - ObjectProperty property = getObjectPropertyByURI(uri); + Resource objType = soln.getResource("objType"); + String objTypeUri = objType.getURI(); + log.debug("Found populated object property " + uri + + " with object type " + objType); + ObjectProperty property = null; + if (uri.equals(propRegister.getURI())) { + property = propRegister.clone(); + } else { + property = getObjectPropertyByURI(uri); + if (property != null) { + propRegister = property; + // add canonical instance of the property first in the list + // before the range-changed versions + properties.add(property); + // isolate the canonical prop from what's about to happen next + property = property.clone(); + } + } if (property != null) { + property.setRangeVClassURI(objTypeUri); properties.add(property); } } @@ -998,12 +1048,15 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp // Map key is inner pair of object property and range class URI, // with first member of outer pair being a domain class URI. // If domain or range is unspecified, OWL.Thing.getURI() is used in the key. - Map>, String> customListViewConfigFileMap = null; + Map>, String> customListViewConfigFileMap; @Override public String getCustomListViewConfigFileName(ObjectProperty op) { if (customListViewConfigFileMap == null) { customListViewConfigFileMap = new HashMap>, String>(); + } + if (customListViewConfigFileMap.isEmpty()) { + long start = System.currentTimeMillis(); OntModel displayModel = getOntModelSelector().getDisplayModel(); //Get all property to list view config file mappings in the system QueryExecution qexec = QueryExecutionFactory.create(listViewConfigFileQuery, displayModel); @@ -1036,10 +1089,19 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp domainUri, new Pair( prop, rangeUri)), filename); } - } + } + // If there are no custom list views, put a bogus entry in the map + // to avoid further recomputation + if (customListViewConfigFileMap.isEmpty()) { + ObjectProperty bottom = new ObjectProperty(); + bottom.setURI(OWL.NS + "bottomObjectProperty"); + customListViewConfigFileMap.put( + new Pair>( + null, new Pair( + bottom, null)), "nothing"); + } qexec.close(); - } - + } String customListViewConfigFileName = customListViewConfigFileMap.get(new Pair>(op.getDomainVClassURI(), new Pair(op, op.getRangeVClassURI()))); if (customListViewConfigFileName == null) { log.debug("no list view found for " + op.getURI() + " qualified by range " + op.getRangeVClassURI() + " and domain " + op.getDomainVClassURI()); 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 45810e361..34eeb6dd8 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 @@ -11,7 +11,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -25,6 +24,7 @@ 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.ResultSetFactory; import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; @@ -35,6 +35,7 @@ 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.sparql.resultset.ResultSetMem; import com.hp.hpl.jena.util.iterator.ClosableIterator; import com.hp.hpl.jena.vocabulary.OWL; @@ -46,6 +47,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualUpdateEvent; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements ObjectPropertyStatementDao { @@ -92,7 +94,8 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec else { Map uriToObjectProperty = new HashMap(); - ObjectPropertyDaoJena opDaoJena = new ObjectPropertyDaoJena(dwf, getWebappDaoFactory()); + ObjectPropertyDaoJena opDaoJena = (ObjectPropertyDaoJena) getWebappDaoFactory().getObjectPropertyDao(); + //new ObjectPropertyDaoJena(rdfService, dwf, getWebappDaoFactory()); OntModel ontModel = getOntModelSelector().getABoxModel(); ontModel.enterCriticalSection(Lock.READ); @@ -278,26 +281,77 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec Set constructQueryStrings, String sortDirection) { - Model constructedModel = constructModelForSelectQueries( - subjectUri, propertyUri, constructQueryStrings); - - if(log.isDebugEnabled()) { - log.debug("Constructed model has " + constructedModel.size() + " statements."); + List> list = new ArrayList>(); + + long start = System.currentTimeMillis(); + + try { + Model constructedModel = constructModelForSelectQueries( + subjectUri, propertyUri, rangeUri, constructQueryStrings); + + if(log.isDebugEnabled()) { + log.debug("Constructed model has " + constructedModel.size() + " statements."); + } + + if("desc".equalsIgnoreCase( sortDirection ) ){ + queryString = queryString.replaceAll(" ASC\\(", " DESC("); + } + + ResultSet results = (constructedModel == null) ? selectFromRDFService( + queryString, subjectUri, propertyUri, domainUri, rangeUri) : selectFromConstructedModel( + queryString, subjectUri, propertyUri, domainUri, rangeUri, constructedModel); + + while (results.hasNext()) { + QuerySolution soln = results.nextSolution(); + RDFNode node = soln.get(objectKey); + if (node.isURIResource()) { + list.add(QueryUtils.querySolutionToStringValueMap(soln)); + } + } + if(log.isDebugEnabled()) { + long duration = System.currentTimeMillis() - start; + log.debug(duration + " to do list view for " + + propertyUri + " / " + domainUri + " / " + rangeUri); + } + } catch (Exception e) { + log.error("Error getting object property values for subject " + subjectUri + " and property " + propertyUri, e); + return Collections.emptyList(); } - - if("desc".equalsIgnoreCase( sortDirection ) ){ - queryString = queryString.replaceAll(" ASC\\(", " DESC("); - } - + return list; + } + + private ResultSet selectFromRDFService(String queryString, String subjectUri, + String propertyUri, String domainUri, String rangeUri) { + String[] part = queryString.split("[Ww][Hh][Ee][Rr][Ee]"); + part[1] = part[1].replace("?subject", "<" + subjectUri + ">"); + part[1] = part[1].replace("?property", "<" + propertyUri + ">"); + if (domainUri != null && !domainUri.startsWith(VitroVocabulary.PSEUDO_BNODE_NS)) { + part[1] = part[1].replace("?subjectType", "<" + domainUri + ">"); + } + if (rangeUri != null && !rangeUri.startsWith(VitroVocabulary.PSEUDO_BNODE_NS)) { + part[1] = part[1].replace("?objectType", "<" + rangeUri + ">"); + } + queryString = part[0] + "WHERE" + part[1]; + try { + return ResultSetFactory.fromJSON( + rdfService.sparqlSelectQuery(queryString, RDFService.ResultFormat.JSON)); + } catch (RDFServiceException e) { + throw new RuntimeException(e); + } + } + + private ResultSet selectFromConstructedModel(String queryString, + String subjectUri, String propertyUri, String domainUri, String rangeUri, + Model constructedModel) { 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(); + throw new RuntimeException(th); } - + QuerySolutionMap initialBindings = new QuerySolutionMap(); initialBindings.add("subject", ResourceFactory.createResource(subjectUri)); initialBindings.add("property", ResourceFactory.createResource(propertyUri)); @@ -307,52 +361,31 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec if (rangeUri != null && !rangeUri.startsWith(VitroVocabulary.PSEUDO_BNODE_NS)) { initialBindings.add("objectType", ResourceFactory.createResource(rangeUri)); } - - log.debug("Query string for object property " + propertyUri + ": " + queryString); - + + if(log.isDebugEnabled()) { + log.debug("Query string for object property " + propertyUri + ": " + queryString); + } + // Run the SPARQL query to get the properties - List> list = 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 soln = results.nextSolution(); - RDFNode node = soln.get(objectKey); - if (node.isURIResource()) { - list.add(QueryUtils.querySolutionToStringValueMap(soln)); - } - } - return list; - - } catch (Exception e) { - log.error("Error getting object property values for subject " + subjectUri + " and property " + propertyUri); - return Collections.emptyList(); + qexec = QueryExecutionFactory.create( + query, constructedModel, initialBindings); + return new ResultSetMem(qexec.execSelect()); } finally { - dataset.getLock().leaveCriticalSection(); - w.close(); if (qexec != null) { qexec.close(); } - } - + } } private Model constructModelForSelectQueries(String subjectUri, - String propertyUri, + String propertyUri, + String rangeUri, Set constructQueries) { - if (constructQueries == null) { + if (constructQueries.size() == 0 || constructQueries == null) { return null; } @@ -362,24 +395,18 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec queryString = queryString.replace("?subject", "<" + subjectUri + ">"); queryString = queryString.replace("?property", "<" + propertyUri + ">"); + if (rangeUri != null) { + queryString = queryString.replace("?objectType", "<" + rangeUri + ">"); + } - log.debug("CONSTRUCT query string for object property " + - propertyUri + ": " + queryString); + if (log.isDebugEnabled()) { + log.debug("CONSTRUCT query string for object property " + + propertyUri + ": " + queryString); + } - // we no longer need this query object, but we might want to do this - // query parse step to improve debugging, depending on the error returned - // through the RDF API -// try { -// 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; -// } - try { - //If RDFService is null, will do what code used to do before, otherwise employ rdfservice + //If RDFService is null, will do what code used to do before, + //otherwise employ rdfservice if(rdfService == null) { log.debug("RDF Service null, Using CONSTRUCT query string for object property " + propertyUri + ": " + queryString); @@ -402,7 +429,8 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec query, dataset); qe.execConstruct(constructedModel); } catch (Exception e) { - log.error("Error getting constructed model for subject " + subjectUri + " and property " + propertyUri); + log.error("Error getting constructed model for subject " + + subjectUri + " and property " + propertyUri); } finally { if (qe != null) { qe.close(); @@ -412,28 +440,31 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec } } else { String parseFormat = "N3"; - RDFService.ModelSerializationFormat resultFormat = RDFService.ModelSerializationFormat.N3; + RDFService.ModelSerializationFormat resultFormat = RDFService + .ModelSerializationFormat.N3; - /* If the test ObjectPropertyStatementDaoJenaTest.testN3WithSameAs() fails - * this code can be removed: */ + /* If the test ObjectPropertyStatementDaoJenaTest.testN3WithSameAs() + * fails this code can be removed: */ if( OWL.sameAs.getURI().equals( propertyUri )){ - // VIVO-111: owl:sameAs can be represented as = in n3 but Jena's parser does not recognize it. - // Switch to rdf/xml only for sameAs since it seems like n3 would be faster the rest of the time. + // VIVO-111: owl:sameAs can be represented as = in n3 but + // Jena's parser does not recognize it. + // Switch to rdf/xml only for sameAs since it seems like n3 + // would be faster the rest of the time. parseFormat = "RDF/XML"; resultFormat = RDFService.ModelSerializationFormat.RDFXML; } /* end of removal */ - InputStream is = rdfService.sparqlConstructQuery(queryString, resultFormat); + InputStream is = rdfService.sparqlConstructQuery( + queryString, resultFormat); constructedModel.read( is, null, parseFormat); } } catch (Exception e) { - log.error("Error getting constructed model for subject " + subjectUri + " and property " + propertyUri, e); + log.error("Error getting constructed model for subject " + + subjectUri + " and property " + propertyUri, e); } } - - return constructedModel; - + return constructedModel; } protected static final String MOST_SPECIFIC_TYPE_QUERY = "" diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyDaoJena.java index 057df054e..dc87b7065 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyDaoJena.java @@ -21,13 +21,13 @@ import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntProperty; import com.hp.hpl.jena.ontology.Restriction; -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.ResultSet; +import com.hp.hpl.jena.query.ResultSetFactory; import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; @@ -36,7 +36,6 @@ import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.sdb.util.Pair; import com.hp.hpl.jena.shared.Lock; -import com.hp.hpl.jena.sparql.resultset.ResultSetMem; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDFS; @@ -49,6 +48,8 @@ import edu.cornell.mannlib.vitro.webapp.dao.PropertyDao; import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { @@ -74,11 +75,14 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { log.debug("Query prefixes: " + PREFIXES); } + protected RDFService rdfService; protected DatasetWrapperFactory dwf; - public PropertyDaoJena(DatasetWrapperFactory dwf, + public PropertyDaoJena(RDFService rdfService, + DatasetWrapperFactory dwf, WebappDaoFactoryJena wadf) { super(wadf); + this.rdfService = rdfService; this.dwf = dwf; } @@ -86,6 +90,10 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { protected OntModel getOntModel() { return getOntModelSelector().getTBoxModel(); } + + protected RDFService getRDFService() { + return this.rdfService; + } public void addSuperproperty(ObjectProperty property, ObjectProperty superproperty) { addSuperproperty(property.getURI(),superproperty.getURI()); @@ -414,8 +422,8 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { return classSet; } - protected ResultSet getPropertyQueryResults(Query query) { - log.debug("SPARQL query:\n" + query.toString()); + protected ResultSet getPropertyQueryResults(String queryString) { + log.debug("SPARQL query:\n" + queryString); // RY Removing prebinding due to Jena bug: when isLiteral(?object) or // isURI(?object) is added to the query as a filter, the query fails with prebinding @@ -424,23 +432,32 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { //subjectBinding.add("subject", ResourceFactory.createResource(subjectUri)); // Run the SPARQL query to get the properties - DatasetWrapper w = dwf.getDatasetWrapper(); - Dataset dataset = w.getDataset(); - dataset.getLock().enterCriticalSection(Lock.READ); - ResultSet rs = null; + try { - QueryExecution qexec = QueryExecutionFactory.create( - query, dataset); //, subjectBinding); - try { - rs = new ResultSetMem(qexec.execSelect()); - } finally { - qexec.close(); - } - } finally { - dataset.getLock().leaveCriticalSection(); - w.close(); + return ResultSetFactory.fromJSON( + getRDFService().sparqlSelectQuery( + queryString, RDFService.ResultFormat.JSON)); + } catch (RDFServiceException e) { + throw new RuntimeException(e); } - return rs; + +// DatasetWrapper w = dwf.getDatasetWrapper(); +// Dataset dataset = w.getDataset(); +// dataset.getLock().enterCriticalSection(Lock.READ); +// ResultSet rs = null; +// try { +// QueryExecution qexec = QueryExecutionFactory.create( +// query, dataset); //, subjectBinding); +// try { +// rs = new ResultSetMem(qexec.execSelect()); +// } finally { +// qexec.close(); +// } +// } finally { +// dataset.getLock().leaveCriticalSection(); +// w.close(); +// } +// return rs; } /** @@ -865,20 +882,6 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { } return domainAndRangeURIs; } - - private String getURIStr(Resource res) { - String URIStr; - if (res == null) { - URIStr = OWL.Thing.getURI(); // TODO: rdf:Resource if using RDF model; or option to turn off entirely - } else { - if (res.isAnon()) { - URIStr = PSEUDO_BNODE_NS+res.getId().toString(); - } else { - URIStr = res.getURI(); - } - } - return URIStr; - } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJena.java index 19cbdffeb..e68caf10f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJena.java @@ -29,11 +29,14 @@ import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.dao.PropertyInstanceDao; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualDeletionEvent; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualUpdateEvent; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; public class PropertyInstanceDaoJena extends PropertyDaoJena implements PropertyInstanceDao { - public PropertyInstanceDaoJena(DatasetWrapperFactory dwf, WebappDaoFactoryJena wadf) { - super(dwf, wadf); + public PropertyInstanceDaoJena(RDFService rdfService, + DatasetWrapperFactory dwf, + WebappDaoFactoryJena wadf) { + super(rdfService, dwf, wadf); } public void deleteObjectPropertyStatement(String subjectURI, String propertyURI, String objectURI) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java index 9668c60e8..d75f4a204 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java @@ -50,6 +50,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactoryConfig; import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.model.RDFServiceModel; import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase; import edu.cornell.mannlib.vitro.webapp.utils.jena.URIUtils; @@ -109,6 +110,8 @@ public class WebappDaoFactoryJena implements WebappDaoFactory { Dataset dataset = makeInMemoryDataset(assertions, inferences); this.dwf = new StaticDatasetFactory(dataset); + this.rdfService = new RDFServiceModel(ontModelSelector.getFullModel()); + } public WebappDaoFactoryJena(OntModelSelector ontModelSelector, @@ -327,7 +330,7 @@ public class WebappDaoFactoryJena implements WebappDaoFactory { DataPropertyDao dataPropertyDao = null; public DataPropertyDao getDataPropertyDao() { if( dataPropertyDao == null ) - dataPropertyDao = new DataPropertyDaoJena(dwf, this); + dataPropertyDao = new DataPropertyDaoJena(rdfService, dwf, this); return dataPropertyDao; } @@ -358,14 +361,15 @@ public class WebappDaoFactoryJena implements WebappDaoFactory { private ObjectPropertyDao objectPropertyDao = null; public ObjectPropertyDao getObjectPropertyDao() { if( objectPropertyDao == null ) - objectPropertyDao = new ObjectPropertyDaoJena(dwf, this); + objectPropertyDao = new ObjectPropertyDaoJena( + rdfService, dwf, config.customListViewConfigFileMap, this); return objectPropertyDao; } private PropertyInstanceDao propertyInstanceDao = null; public PropertyInstanceDao getPropertyInstanceDao() { if( propertyInstanceDao == null ) - propertyInstanceDao = new PropertyInstanceDaoJena(dwf, this); + propertyInstanceDao = new PropertyInstanceDaoJena(rdfService, dwf, this); return propertyInstanceDao; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/RequestModelsPrep.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/RequestModelsPrep.java index 0edcf0e1e..d4da08f70 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/RequestModelsPrep.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/RequestModelsPrep.java @@ -10,6 +10,8 @@ import java.text.Collator; import java.util.Enumeration; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; import javax.servlet.Filter; @@ -24,6 +26,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.openjena.atlas.lib.Pair; import com.hp.hpl.jena.graph.BulkUpdateHandler; import com.hp.hpl.jena.graph.Graph; @@ -35,6 +38,7 @@ import com.hp.hpl.jena.rdf.model.ModelFactory; import edu.cornell.mannlib.vitro.webapp.auth.identifier.RequestIdentifiers; import edu.cornell.mannlib.vitro.webapp.auth.policy.ServletPolicyList; +import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; @@ -311,6 +315,8 @@ public class RequestModelsPrep implements Filter { config.setDefaultNamespace(defaultNamespace); config.setPreferredLanguages(langs); config.setUnderlyingStoreReasoned(isStoreReasoned(req)); + config.setCustomListViewConfigFileMap(getCustomListViewConfigFileMap( + req.getSession().getServletContext())); return config; } @@ -365,6 +371,18 @@ public class RequestModelsPrep implements Filter { "VitroConnection.DataSource.isStoreReasoned", "true"); return ("true".equals(isStoreReasoned)); } + + private Map>, String> + getCustomListViewConfigFileMap(ServletContext ctx) { + Map>, String> map = + (Map>, String>) + ctx.getAttribute("customListViewConfigFileMap"); + if (map == null) { + map = new ConcurrentHashMap>, String>(); + ctx.setAttribute("customListViewConfigFileMap", map); + } + return map; + } @Override public void destroy() { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ABoxUpdater.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ABoxUpdater.java index 74de6f79e..7679689f6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ABoxUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ABoxUpdater.java @@ -31,6 +31,8 @@ import com.hp.hpl.jena.vocabulary.RDF; import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset; import edu.cornell.mannlib.vitro.webapp.ontology.update.AtomicOntologyChange.AtomicChangeType; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; /** * Performs knowledge base updates to the abox to align with a new ontology version @@ -594,9 +596,11 @@ public class ABoxUpdater { return; } + long start = System.currentTimeMillis(); Iterator graphIt = dataset.listNames(); while(graphIt.hasNext()) { String graph = graphIt.next(); + //log.info(System.currentTimeMillis() - start + " to get graph"); if(!KnowledgeBaseUpdater.isUpdatableABoxGraph(graph)){ continue; } @@ -604,11 +608,23 @@ public class ABoxUpdater { Model renamePropAddModel = ModelFactory.createDefaultModel(); Model renamePropRetractModel = ModelFactory.createDefaultModel(); - + log.info("renaming " + oldProperty.getURI() + " in graph " + graph); aboxModel.enterCriticalSection(Lock.WRITE); try { + start = System.currentTimeMillis(); + +// String queryStr = "CONSTRUCT { ?s <" + oldProperty.getURI() + "> ?o } WHERE { GRAPH<" + graph + "> { ?s <" + oldProperty.getURI() + "> ?o } } "; +// try { +// renamePropRetractModel = RDFServiceUtils.parseModel(rdfService.sparqlConstructQuery(queryStr, RDFService.ModelSerializationFormat.NTRIPLE), RDFService.ModelSerializationFormat.NTRIPLE); +// } catch (RDFServiceException e) { +// log.error(e,e); +// } +// log.info(System.currentTimeMillis() - start + " to run sparql construct for " + renamePropRetractModel.size() + " statements" ); + start = System.currentTimeMillis(); renamePropRetractModel.add( aboxModel.listStatements( (Resource) null, oldProperty, (RDFNode) null)); + log.info(System.currentTimeMillis() - start + " to list " + renamePropRetractModel.size() + " old statements"); + start = System.currentTimeMillis(); StmtIterator stmItr = renamePropRetractModel.listStatements(); while(stmItr.hasNext()) { Statement tempStatement = stmItr.nextStatement(); @@ -616,8 +632,13 @@ public class ABoxUpdater { newProperty, tempStatement.getObject() ); } + log.info(System.currentTimeMillis() - start + " to make new statements"); + start = System.currentTimeMillis(); aboxModel.remove(renamePropRetractModel); + log.info(System.currentTimeMillis() - start + " to retract old statements"); + start = System.currentTimeMillis(); aboxModel.add(renamePropAddModel); + log.info(System.currentTimeMillis() - start + " to add new statements"); } finally { aboxModel.leaveCriticalSection(); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/KnowledgeBaseUpdater.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/KnowledgeBaseUpdater.java index 90707edca..305937dbc 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/KnowledgeBaseUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/KnowledgeBaseUpdater.java @@ -96,10 +96,10 @@ public class KnowledgeBaseUpdater { // update ABox data any time log.info("performing SPARQL CONSTRUCT additions"); - performSparqlConstructs(settings.getSparqlConstructAdditionsDir(), settings.getRDFService(), ADD); + //performSparqlConstructs(settings.getSparqlConstructAdditionsDir(), settings.getRDFService(), ADD); log.info("performing SPARQL CONSTRUCT retractions"); - performSparqlConstructs(settings.getSparqlConstructDeletionsDir(), settings.getRDFService(), RETRACT); + //performSparqlConstructs(settings.getSparqlConstructDeletionsDir(), settings.getRDFService(), RETRACT); log.info("\tupdating the abox"); updateABox(changes); @@ -207,9 +207,11 @@ public class KnowledgeBaseUpdater { StmtIterator sit = anonModel.listStatements(); while (sit.hasNext()) { Statement stmt = sit.nextStatement(); + long start = System.currentTimeMillis(); Iterator graphIt = dataset.listNames(); while(graphIt.hasNext()) { String graph = graphIt.next(); + log.info(System.currentTimeMillis() - start + " to get graph"); if(!isUpdatableABoxGraph(graph)) { continue; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java index a58a52386..6cdcea7a6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java @@ -79,7 +79,8 @@ public class FileGraphSetup implements ServletContextListener { cleanupDB(dataset, pathsToURIs(paths, ABOX), ABOX); OntModel aboxBaseModel = baseOms.getABoxModel(); - aboxChanged = readGraphs(paths, maker, ABOX, aboxBaseModel); + // Just update the ABox filegraphs in the DB; don't attach them to a base model. + aboxChanged = readGraphs(paths, maker, ABOX, /* aboxBaseModel */ null); // TBox files paths = getFilegraphPaths(ctx, RDF, TBOX, FILEGRAPH); @@ -108,7 +109,7 @@ public class FileGraphSetup implements ServletContextListener { if ( (aboxChanged || tboxChanged) && !isUpdateRequired(sce.getServletContext())) { log.info("a full recompute of the Abox will be performed because" + " the filegraph abox(s) and/or tbox(s) have changed or are being read for the first time." ); - SimpleReasonerSetup.setRecomputeRequired(sce.getServletContext()); + SimpleReasonerSetup.setRecomputeRequired(sce.getServletContext(), SimpleReasonerSetup.RecomputeMode.BACKGROUND); } } @@ -140,6 +141,14 @@ public class FileGraphSetup implements ServletContextListener { return paths; } + /* + * Reads graphs without using submodels to separate filegraph content from the + * base model. + */ + public boolean readGraphs(Set pathSet, RDFServiceModelMaker dataset, String type, OntModel baseModel) { + return readGraphs(pathSet, dataset, type, baseModel, false); + } + /* * Reads the graphs stored as files in sub-directories of * 1. updates the SDB store to reflect the current contents of the graph. @@ -148,7 +157,7 @@ public class FileGraphSetup implements ServletContextListener { * Note: no connection needs to be maintained between the in-memory copy of the * graph and the DB copy. */ - public boolean readGraphs(Set pathSet, RDFServiceModelMaker dataset, String type, OntModel baseModel) { + public boolean readGraphs(Set pathSet, RDFServiceModelMaker dataset, String type, OntModel baseModel, boolean useSubmodels) { int count = 0; @@ -172,8 +181,12 @@ public class FileGraphSetup implements ServletContextListener { log.warn("Ignoring " + type + " file graph " + p + " because the file extension is unrecognized."); } - if ( !model.isEmpty() ) { - baseModel.addSubModel(model); + if ( !model.isEmpty() && baseModel != null ) { + if (useSubmodels) { + baseModel.addSubModel(model); + } else { + baseModel.add(model); + } log.info("Attached file graph as " + type + " submodel " + p.getFileName()); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java index 43f6fa7d2..4256de861 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java @@ -12,7 +12,6 @@ import java.util.List; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -21,7 +20,6 @@ import com.hp.hpl.jena.query.Dataset; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.vocabulary.OWL; -import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector; @@ -117,7 +115,16 @@ public class SimpleReasonerSetup implements ServletContextListener { assertionsOms.getTBoxModel().register(simpleReasonerTBoxListener); inferencesOms.getTBoxModel().register(simpleReasonerTBoxListener); - log.info("Simple reasoner connected for the ABox"); + RecomputeMode mode = getRecomputeRequired(ctx); + if (RecomputeMode.FOREGROUND.equals(mode)) { + log.info("ABox inference recompute required."); + simpleReasoner.recompute(); + } else if (RecomputeMode.BACKGROUND.equals(mode)) { + log.info("starting ABox inference recompute in a separate thread."); + new Thread( + new ABoxRecomputer( + simpleReasoner),"ABoxRecomputer").start(); + } } catch (Throwable t) { t.printStackTrace(); @@ -179,15 +186,19 @@ public class SimpleReasonerSetup implements ServletContextListener { } } + public enum RecomputeMode { + FOREGROUND, BACKGROUND + } + private static final String RECOMPUTE_REQUIRED_ATTR = SimpleReasonerSetup.class.getName() + ".recomputeRequired"; - public static void setRecomputeRequired(ServletContext ctx) { - ctx.setAttribute(RECOMPUTE_REQUIRED_ATTR, true); + public static void setRecomputeRequired(ServletContext ctx, RecomputeMode mode) { + ctx.setAttribute(RECOMPUTE_REQUIRED_ATTR, mode); } - public static boolean isRecomputeRequired(ServletContext ctx) { - return (ctx.getAttribute(RECOMPUTE_REQUIRED_ATTR) != null); + public static RecomputeMode getRecomputeRequired(ServletContext ctx) { + return (RecomputeMode) ctx.getAttribute(RECOMPUTE_REQUIRED_ATTR); } private static final String MSTCOMPUTE_REQUIRED_ATTR = @@ -249,6 +260,18 @@ public class SimpleReasonerSetup implements ServletContextListener { log.debug("Classnames of reasoner plugins = " + list); return list; - + } + + private class ABoxRecomputer implements Runnable { + + private SimpleReasoner simpleReasoner; + + public ABoxRecomputer(SimpleReasoner simpleReasoner) { + this.simpleReasoner = simpleReasoner; + } + + public void run() { + simpleReasoner.recompute(); + } } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java index 817ce52db..58d2c66d1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java @@ -157,42 +157,24 @@ public class UpdateKnowledgeBase implements ServletContextListener { ss.fatal(this, "Exception updating knowledge base for ontology changes: ", ioe); } } - - SimpleReasoner simpleReasoner = (SimpleReasoner) sce.getServletContext() - .getAttribute(SimpleReasoner.class.getName()); - if (simpleReasoner != null) { - if ( (requiredUpdate && migrationChangesMade) - || JenaDataSourceSetupBase.isFirstStartup()) { - log.info("ABox inference recompute required."); - simpleReasoner.recompute(); - } else if (SimpleReasonerSetup.isRecomputeRequired(sce.getServletContext()) || migrationChangesMade) { - log.info("starting ABox inference recompute in a separate thread."); - new Thread( - new ABoxRecomputer( - simpleReasoner),"ABoxRecomputer").start(); - } - } + log.info("Simple reasoner connected for the ABox"); + if(JenaDataSourceSetupBase.isFirstStartup() + || (migrationChangesMade && requiredUpdate)) { + SimpleReasonerSetup.setRecomputeRequired( + ctx, SimpleReasonerSetup.RecomputeMode.FOREGROUND); + } else if (migrationChangesMade) { + SimpleReasonerSetup.setRecomputeRequired( + ctx, SimpleReasonerSetup.RecomputeMode.BACKGROUND); + } + } catch (Throwable t){ ss.fatal(this, "Exception updating knowledge base for ontology changes: ", t); } - - } - private class ABoxRecomputer implements Runnable { - private SimpleReasoner simpleReasoner; - - public ABoxRecomputer(SimpleReasoner simpleReasoner) { - this.simpleReasoner = simpleReasoner; - } - - public void run() { - simpleReasoner.recompute(); - } - } /** diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java index 24341a0f4..62a5e5d9f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java @@ -83,7 +83,7 @@ public class ApplicationConfigurationOntologyUtils { String rangeURI = qsoln.getResource("range").getURI(); if (appropriateDomain(domainRes, subject, tboxModel)) { ObjectProperty faux = opDao.getObjectPropertyByURIs( - opURI, domainURI, rangeURI); + opURI, domainURI, rangeURI, (prop != null) ? prop.clone() : null); if (faux != null) { additionalProps.add(faux); } else { 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 cedb9bde0..a009847c9 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 @@ -6,8 +6,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -73,13 +75,23 @@ public class GroupedPropertyList extends BaseTemplateModel { // so we cannot just rely on getting that list. List populatedObjectPropertyList = subject .getPopulatedObjectPropertyList(); + + Map> populatedObjTypes = makePopulatedObjTypeMap( + populatedObjectPropertyList); + + // save applicable ranges before deduping to filter later + populatedObjectPropertyList = dedupe(populatedObjectPropertyList); Collection additions = ApplicationConfigurationOntologyUtils .getAdditionalFauxSubpropertiesForList( populatedObjectPropertyList, subject, vreq); + + additions = filterAdditions(additions, populatedObjTypes); + if (log.isDebugEnabled()) { for (ObjectProperty t : additions) { - log.debug(t.getDomainPublic() + " " + t.getGroupURI() + " domain " + t.getDomainVClassURI()); + log.debug(t.getDomainPublic() + " " + t.getGroupURI() + " domain " + + t.getDomainVClassURI()); } log.debug("Added " + additions.size() + " properties due to application configuration ontology"); @@ -110,12 +122,15 @@ public class GroupedPropertyList extends BaseTemplateModel { mergeAllPossibleDataProperties(propertyList); } - propertyList = correctLanguageForProperties(propertyList); + if (editing) { + propertyList = correctLanguageForProperties(propertyList); + } + sort(propertyList); // Put the list into groups List propertyGroupList = addPropertiesToGroups(propertyList); - + // Build the template data model from the groupList groups = new ArrayList( propertyGroupList.size()); @@ -131,6 +146,34 @@ public class GroupedPropertyList extends BaseTemplateModel { } + private Map> makePopulatedObjTypeMap(List props) { + Map> map = new HashMap>(); + for (ObjectProperty prop : props) { + if(prop.getRangeVClassURI() != null) { + List typeList = map.get(prop.getURI()); + if(typeList == null) { + typeList = new ArrayList(); + map.put(prop.getURI(), typeList); + } + typeList.add(prop.getRangeVClassURI()); + } + } + return map; + } + + private List filterAdditions(Collection additions, + Map> populatedObjTypes) { + List filteredAdditions = new ArrayList(); + for (ObjectProperty prop : additions) { + List allowedTypes = populatedObjTypes.get(prop.getURI()); + if(allowedTypes != null && (allowedTypes.contains(prop.getRangeVClassURI()) + || allowedTypes.contains(prop.getRangeEntityURI()) ) ) { + filteredAdditions.add(prop); + } + } + return filteredAdditions; + } + // Use the language-filtering WebappDaoFactory to get the right version of // each property. When editing, the methods that add to the property list // are blissfully (and intentionally) language-unaware. @@ -187,6 +230,19 @@ public class GroupedPropertyList extends BaseTemplateModel { } } } + + //assumes sorted list + protected List dedupe(List propList) { + List dedupedList = new ArrayList(); + String uriRegister = ""; + for (ObjectProperty prop : propList) { + if(!uriRegister.equals(prop.getURI())) { + uriRegister = prop.getURI(); + dedupedList.add(prop); + } + } + return dedupedList; + } protected void sort(List propertyList) { try { @@ -325,10 +381,12 @@ public class GroupedPropertyList extends BaseTemplateModel { // Get the property groups PropertyGroupDao pgDao = wdf.getPropertyGroupDao(); + long start = System.currentTimeMillis(); List groupList = pgDao.getPublicGroups(false); // may be returned empty but not null // To test no property groups defined, use: // List groupList = new ArrayList(); + start = System.currentTimeMillis(); int groupCount = groupList.size(); /* @@ -353,7 +411,7 @@ public class GroupedPropertyList extends BaseTemplateModel { */ PropertyGroup groupForUnassignedProperties = pgDao .createDummyPropertyGroup("", MAX_GROUP_DISPLAY_RANK); - + if (groupCount > 1) { try { Collections.sort(groupList); @@ -377,6 +435,7 @@ public class GroupedPropertyList extends BaseTemplateModel { log.error("Exception on trying to prune unpopulated groups from group list: " + ex.getMessage()); } + log.debug(System.currentTimeMillis() - start + " to remove unpopulated groups"); // If the group for unassigned properties is populated, add it to the // group list. diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyGroupTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyGroupTemplateModel.java index 10b5ce4d9..b50469188 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyGroupTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyGroupTemplateModel.java @@ -8,6 +8,9 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayObjectProperty; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction; import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; @@ -37,6 +40,10 @@ public class PropertyGroupTemplateModel extends BaseTemplateModel { for (Property p : propertyList) { if (p instanceof ObjectProperty) { ObjectProperty op = (ObjectProperty) p; + RequestedAction dop = new DisplayObjectProperty(op); + if (!PolicyHelper.isAuthorizedForActions(vreq, dop)) { + continue; + } ObjectPropertyTemplateModel tm = ObjectPropertyTemplateModel.getObjectPropertyTemplateModel( op, subject, vreq, editing, populatedObjectPropertyList); if (!tm.isEmpty() || (editing && !tm.getAddUrl().isEmpty())) { diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDaoStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDaoStub.java index 54ba17477..dacbdbc88 100644 --- a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDaoStub.java +++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDaoStub.java @@ -67,7 +67,14 @@ public class ObjectPropertyDaoStub implements ObjectPropertyDao { } @Override - public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, String domainURI, String rangeURI) { + public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, + String domainURI, String rangeURI) { + return getObjectPropertyByURI(objectPropertyURI); + } + + @Override + public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, + String domainURI, String rangeURI, ObjectProperty base) { return getObjectPropertyByURI(objectPropertyURI); }