From b5777a60ad1c47a821e8d8d44047a0fe512651b7 Mon Sep 17 00:00:00 2001 From: bjl23 Date: Thu, 27 Jan 2011 20:56:44 +0000 Subject: [PATCH] rewritten list view queries with UNIONs plus various and sundry other bugfixes and improvements; also probably new bugs --- .../controller/freemarker/UrlBuilder.java | 3 +- .../webapp/dao/jena/IndividualDaoSDB.java | 8 ++- .../vitro/webapp/dao/jena/IndividualSDB.java | 38 +++++++----- .../jena/ObjectPropertyStatementDaoSDB.java | 14 ++--- .../webapp/dao/jena/PropertyGroupDaoJena.java | 38 +++++++++--- .../webapp/dao/jena/VClassGroupDaoJena.java | 9 ++- .../webapp/dao/jena/WebappDaoFactoryJena.java | 39 ++++++++---- .../webapp/filters/VitroRequestPrep.java | 6 +- .../servlet/setup/JenaDataSourceSetupSDB.java | 17 ++++- .../utils/jena/NamespaceMapperJena.java | 13 ++++ .../BaseObjectPropertyDataPostProcessor.java | 1 + .../ObjectPropertyTemplateModel.java | 62 +++++++++++++++++++ webapp/web/config/listViewConfig-default.xml | 43 ++++++++++--- .../web/config/listViewConfig-vitroLink.xml | 8 +-- 14 files changed, 238 insertions(+), 61 deletions(-) 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 30ceef439..d27e52b68 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 @@ -15,6 +15,7 @@ import org.openrdf.model.URI; import org.openrdf.model.impl.URIImpl; import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl; import edu.cornell.mannlib.vitro.webapp.beans.Portal; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; @@ -259,7 +260,7 @@ public class UrlBuilder { } public static String getIndividualProfileUrl(String individualUri, WebappDaoFactory wadf) { - Individual individual = wadf.getIndividualDao().getIndividualByURI(individualUri); + Individual individual = new IndividualImpl(individualUri); return getIndividualProfileUrl(individual, individualUri, wadf); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualDaoSDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualDaoSDB.java index 35a8af48b..d9ec66455 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualDaoSDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualDaoSDB.java @@ -45,6 +45,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.jena.IndividualSDB.IndividualNotFoundException; import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactorySDB.SDBDatasetMode; public class IndividualDaoSDB extends IndividualDaoJena { @@ -66,7 +67,12 @@ public class IndividualDaoSDB extends IndividualDaoJena { } protected Individual makeIndividual(String individualURI) { - return new IndividualSDB(individualURI, this.dwf, datasetMode, getWebappDaoFactory()); + try { + return new IndividualSDB(individualURI, this.dwf, datasetMode, getWebappDaoFactory()); + } catch (IndividualNotFoundException e) { + // If the individual does not exist, return null. + return null; + } } private static final Log log = LogFactory.getLog(IndividualDaoSDB.class.getName()); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualSDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualSDB.java index 01b15dc7d..a3436763c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualSDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualSDB.java @@ -137,21 +137,21 @@ public class IndividualSDB extends IndividualImpl implements Individual { "CONSTRUCT " + "{ <"+individualURI+"> <" + RDFS.label.getURI() + "> ?ooo. \n" + - "<"+individualURI+"> a ?type . \n" + +// "<"+individualURI+"> a ?type . \n" + "<"+individualURI+"> <" + VitroVocabulary.MONIKER + "> ?moniker \n" + - "} WHERE {" + - "{ GRAPH ?g { \n" + + "} WHERE { GRAPH {" + + "{ \n" + "{ <"+individualURI+"> <" + RDFS.label.getURI() + "> ?ooo } \n" + - "UNION { GRAPH ?h { <" + + "UNION { <" + individualURI+"> <" + VitroVocabulary.MONIKER + - "> ?moniker } } \n" + - "} } \n" + - "UNION { GRAPH ?i { <" - + individualURI + "> a ?type } } \n" + - WebappDaoFactorySDB.getFilterBlock(graphVars, datasetMode) + - "}"; + "> ?moniker } \n" + + "} \n" + +// "UNION { <" +// + individualURI + "> a ?type } \n" + +// WebappDaoFactorySDB.getFilterBlock(graphVars, datasetMode) + + "} }"; model = QueryExecutionFactory.create( QueryFactory.create(getStatements), dataset) .execConstruct(); @@ -163,6 +163,10 @@ public class IndividualSDB extends IndividualImpl implements Individual { OntModel ontModel = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM, model); + if (model.isEmpty()) { + throw new IndividualNotFoundException(); + } + this.ind = ontModel.createOntResource(individualURI); } setUpURIParts(ind); @@ -182,6 +186,8 @@ public class IndividualSDB extends IndividualImpl implements Individual { !SKIP_INITIALIZATION); } + public class IndividualNotFoundException extends RuntimeException {} + private void setUpURIParts(OntResource ind) { if (ind != null) { if (ind.isAnon()) { @@ -304,8 +310,8 @@ public class IndividualSDB extends IndividualImpl implements Individual { int portalid = FlagMathUtils.numeric2Portalid(numericPortal); String portalTypeUri = VitroVocabulary.vitroURI + "Flag1Value" + portalid + "Thing"; - String Ask = "ASK { GRAPH ?g { <" + this.individualURI + - "> <" +RDF.type+ "> <" + portalTypeUri +">} }"; + String Ask = "ASK { <" + this.individualURI + + "> <" +RDF.type+ "> <" + portalTypeUri +">} "; if(!QueryExecutionFactory.create( QueryFactory.create(Ask), dataset).execAsk()) { return false; @@ -334,8 +340,8 @@ public class IndividualSDB extends IndividualImpl implements Individual { getObjects = "CONSTRUCT{<" + this.individualURI + "> <" + RDF.type + "> ?object}" + - "WHERE{ GRAPH ?g { <" + this.individualURI + "> <" + - RDF.type + "> ?object} }"; + "WHERE{ <" + this.individualURI + "> <" + + RDF.type + "> ?object }"; tempModel = QueryExecutionFactory.create( QueryFactory.create( getObjects), dataset).execConstruct(); @@ -394,8 +400,8 @@ public class IndividualSDB extends IndividualImpl implements Individual { getObjects = "CONSTRUCT{<" + this.individualURI + "> <" + RDF.type + "> ?object}" + - "WHERE{ GRAPH ?g { <" + this.individualURI + "> <" + - RDF.type + "> ?object} }"; + "WHERE{ <" + this.individualURI + "> <" + + RDF.type + "> ?object }"; tempModel = QueryExecutionFactory.create( QueryFactory.create( getObjects), dataset).execConstruct(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoSDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoSDB.java index 30ca46f6b..b41f2630b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoSDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoSDB.java @@ -50,19 +50,19 @@ public class ObjectPropertyStatementDaoSDB extends return entity; else { Map uriToObjectProperty = new HashMap(); - String[] graphVars = { "?g", "?h", "?i", "?j" }; + //String[] graphVars = { "?g", "?h", "?i", "?j" }; String query = "CONSTRUCT { \n" + " <" + entity.getURI() + "> ?p ?o . \n" + - " ?o a ?oType . \n" + + // " ?o a ?oType . \n" + " ?o <" + RDFS.label.getURI() + "> ?oLabel . \n" + " ?o <" + VitroVocabulary.MONIKER + "> ?oMoniker \n" + - "} WHERE { GRAPH ?g { \n" + + "} WHERE { GRAPH { \n" + " <" + entity.getURI() + "> ?p ?o \n" + - " OPTIONAL { GRAPH ?h { ?o a ?oType } } \n" + - " OPTIONAL { GRAPH ?i { ?o <" + RDFS.label.getURI() + "> ?oLabel } } \n" + - " OPTIONAL { GRAPH ?j { ?o <" + VitroVocabulary.MONIKER + "> ?oMoniker } } \n" + + //" OPTIONAL { GRAPH ?h { ?o a ?oType } } \n" + + // " OPTIONAL { { ?o <" + RDFS.label.getURI() + "> ?oLabel } } \n" + + // " OPTIONAL { { ?o <" + VitroVocabulary.MONIKER + "> ?oMoniker } } \n" + "} \n" + - WebappDaoFactorySDB.getFilterBlock(graphVars, datasetMode) + + //WebappDaoFactorySDB.getFilterBlock(graphVars, datasetMode) + "}"; long startTime = System.currentTimeMillis(); Model m = null; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyGroupDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyGroupDaoJena.java index 784cc1d7c..d21f9f105 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyGroupDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyGroupDaoJena.java @@ -15,7 +15,9 @@ import org.apache.commons.logging.LogFactory; import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; import com.hp.hpl.jena.ontology.Individual; import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.shared.Lock; @@ -129,26 +131,44 @@ public class PropertyGroupDaoJena extends JenaBaseDao implements PropertyGroupDa groupInd.setURI(group.getURI()); String groupURI = null; - try { - groupURI = (new WebappDaoFactoryJena(getOntModelSelector().getApplicationMetadataModel())).getIndividualDao().insertNewIndividual(groupInd); + + OntModel unionForURIGeneration = ModelFactory.createOntologyModel( + OntModelSpec.OWL_MEM, ModelFactory.createUnion( + getOntModelSelector().getApplicationMetadataModel(), + getOntModelSelector().getFullModel())); + + try { + groupURI = (new WebappDaoFactoryJena(unionForURIGeneration)). + getIndividualDao().insertNewIndividual(groupInd); } catch (InsertException ie) { - throw new RuntimeException(InsertException.class.getName() + "Unable to insert property group "+groupURI, ie); + throw new RuntimeException(InsertException.class.getName() + + "Unable to insert property group " + groupURI, ie); } if (groupURI != null) { getOntModel().enterCriticalSection(Lock.WRITE); try { - com.hp.hpl.jena.ontology.Individual groupJenaInd = getOntModel().getIndividual(groupURI); + com.hp.hpl.jena.ontology.Individual groupJenaInd = + getOntModel().getIndividual(groupURI); try { - groupJenaInd.addProperty(DISPLAY_RANK, Integer.toString(group.getDisplayRank()), XSDDatatype.XSDint); + groupJenaInd.addProperty(DISPLAY_RANK, Integer.toString( + group.getDisplayRank()), XSDDatatype.XSDint); } catch (Exception e) { - log.error("error setting displayRank for "+groupInd.getURI()); + log.error( + "error setting displayRank for " + + groupInd.getURI()); } - if (group.getPublicDescription() != null && group.getPublicDescription().length()>0) { + if (group.getPublicDescription() != null + && group.getPublicDescription().length()>0) { try { - groupJenaInd.addProperty(PUBLIC_DESCRIPTION_ANNOT, group.getPublicDescription(), XSDDatatype.XSDstring); + groupJenaInd.addProperty( + PUBLIC_DESCRIPTION_ANNOT, + group.getPublicDescription(), + XSDDatatype.XSDstring); } catch (Exception ex) { - log.error("error setting public description for "+groupInd.getURI()); + log.error( + "error setting public description for " + + groupInd.getURI()); } } } finally { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupDaoJena.java index 3ec90344b..ffab52251 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupDaoJena.java @@ -216,8 +216,15 @@ public class VClassGroupDaoJena extends JenaBaseDao implements VClassGroupDao { groupInd.setVClassURI(CLASSGROUP.getURI()); String groupURI = null; + + OntModel unionForURIGeneration = ModelFactory.createOntologyModel( + OntModelSpec.OWL_MEM, ModelFactory.createUnion( + getOntModelSelector().getApplicationMetadataModel(), + getOntModelSelector().getFullModel())); + try { - groupURI = (new WebappDaoFactoryJena(ontModel)).getIndividualDao().insertNewIndividual(groupInd); + groupURI = (new WebappDaoFactoryJena(unionForURIGeneration)). + getIndividualDao().insertNewIndividual(groupInd); } catch (InsertException ie) { throw new RuntimeException(InsertException.class.getName() + "Unable to insert class group "+groupURI, ie); } 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 6807768b9..5f00ca7b2 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 @@ -15,6 +15,7 @@ import com.hp.hpl.jena.iri.IRIFactory; import com.hp.hpl.jena.iri.Violation; import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.ontology.OntResource; import com.hp.hpl.jena.query.DataSource; import com.hp.hpl.jena.query.Dataset; @@ -175,22 +176,38 @@ public class WebappDaoFactoryJena implements WebappDaoFactory { if (languageUniversalsModel.size()>0) { this.ontModelSelector.getTBoxModel().addSubModel(languageUniversalsModel); } - DataSource dataset = DatasetFactory.create(); - dataset.addNamedModel(JenaDataSourceSetupBase.JENA_DB_MODEL, - (baseOntModelSelector != null) - ? baseOntModelSelector.getFullModel() - : ontModelSelector.getFullModel()); - if (inferenceOntModelSelector != null) { - dataset.addNamedModel(JenaDataSourceSetupBase.JENA_INF_MODEL, - inferenceOntModelSelector.getFullModel()); - } + Model assertions = (baseOntModelSelector != null) + ? baseOntModelSelector.getFullModel() + : ontModelSelector.getFullModel(); + Model inferences = (inferenceOntModelSelector != null) + ? inferenceOntModelSelector.getFullModel() + : null; + + Dataset dataset = makeInMemoryDataset(assertions, inferences); this.dwf = new StaticDatasetFactory(dataset); - - } + public static Dataset makeInMemoryDataset(Model assertions, Model inferences) { + DataSource dataset = DatasetFactory.create(); + + OntModel union = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + + if (assertions != null) { + dataset.addNamedModel(JenaDataSourceSetupBase.JENA_DB_MODEL, assertions); + union.addSubModel(assertions); + } + if (inferences != null) { + dataset.addNamedModel(JenaDataSourceSetupBase.JENA_INF_MODEL, + inferences); + union.addSubModel(inferences); + } + dataset.setDefaultModel(union); + dataset.addNamedModel("urn:x-arq:UnionGraph", union); + return dataset; + } + public WebappDaoFactoryJena(OntModelSelector ontModelSelector, String defaultNamespace, HashSet nonuserNamespaces, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/VitroRequestPrep.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/VitroRequestPrep.java index 8787e04ee..e127b075d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/VitroRequestPrep.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/VitroRequestPrep.java @@ -39,6 +39,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.FilterFactory; import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.HiddenFromDisplayBelowRoleLevelFilter; import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilterUtils; import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters; +import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena; import edu.cornell.mannlib.vitro.webapp.flags.AuthFlag; import edu.cornell.mannlib.vitro.webapp.flags.FlagException; import edu.cornell.mannlib.vitro.webapp.flags.PortalFlag; @@ -203,9 +204,8 @@ public class VitroRequestPrep implements Filter { // support for Dataset interface if using Jena in-memory model if (vreq.getDataset() == null) { - DataSource dataset = DatasetFactory.create(); - dataset.addNamedModel(JenaDataSourceSetupBase.JENA_DB_MODEL, vreq.getAssertionsOntModel()); - dataset.addNamedModel(JenaDataSourceSetupBase.JENA_INF_MODEL, vreq.getInferenceOntModel()); + Dataset dataset = WebappDaoFactoryJena.makeInMemoryDataset( + vreq.getAssertionsOntModel(), vreq.getInferenceOntModel()); vreq.setDataset(dataset); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupSDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupSDB.java index d88c3137c..f87aa538e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupSDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupSDB.java @@ -206,13 +206,16 @@ public class JenaDataSourceSetupSDB extends JenaDataSourceSetupBase implements j log.error("Unable to load application metadata model cache from DB", e); } + log.info("Adding vitro application ontology"); - // add the vitro ontologies to the tbox models + // add the vitroontologies to the tbox models OntModel vitroTBoxModel = (new JenaBaseDaoCon()).getConstModel(); baseOms.getTBoxModel().addSubModel(vitroTBoxModel); inferenceOms.getTBoxModel().addSubModel(vitroTBoxModel); unionOms.getTBoxModel().addSubModel(vitroTBoxModel); + log.error("Setting up union models and DAO factories"); + // create TBox + ABox union models and set up webapp DAO factories OntModel baseUnion = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, ModelFactory.createUnion(baseOms.getABoxModel(), baseOms.getTBoxModel())); @@ -262,6 +265,8 @@ public class JenaDataSourceSetupSDB extends JenaDataSourceSetupBase implements j // loadDataFromFilesystem(unionOms.getFullModel(), sce.getServletContext()); //} + log.info("Checking for user account data"); + if (userAccountsModel.size() == 0) { readOntologyFilesInPathSet(AUTHPATH, sce.getServletContext(), userAccountsModel); if (userAccountsModel.size() == 0) { @@ -269,20 +274,28 @@ public class JenaDataSourceSetupSDB extends JenaDataSourceSetupBase implements j } } + log.info("Checking for minimal interface metadata"); + ensureEssentialInterfaceData(unionOms.getApplicationMetadataModel(), sce, wadf); + //log.info("Setting up namespace mapper"); + NamespaceMapper namespaceMapper = new NamespaceMapperJena(masterUnion, masterUnion, defaultNamespace); sce.getServletContext().setAttribute("NamespaceMapper", namespaceMapper); unionOms.getFullModel().getBaseModel().register(namespaceMapper); sce.getServletContext().setAttribute("defaultNamespace", defaultNamespace); + log.info("SDB store ready for use"); + makeModelMakerFromConnectionProperties(TripleStoreType.RDB); VitroJenaModelMaker vjmm = getVitroJenaModelMaker(); setVitroJenaModelMaker(vjmm,sce); makeModelMakerFromConnectionProperties(TripleStoreType.SDB); VitroJenaSDBModelMaker vsmm = getVitroJenaSDBModelMaker(); setVitroJenaSDBModelMaker(vsmm,sce); + + log.info("Model makers set up"); } catch (Throwable t) { log.error("Throwable in " + this.getClass().getName(), t); @@ -587,7 +600,9 @@ public class JenaDataSourceSetupSDB extends JenaDataSourceSetupBase implements j SimpleReasonerSetup.setRecomputeRequired(ctx); } finally { + log.info("Adding indexes to SDB database tables."); store.getTableFormatter().addIndexes(); + log.info("Indexes created."); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/jena/NamespaceMapperJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/jena/NamespaceMapperJena.java index aaee33318..8cb5c702e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/jena/NamespaceMapperJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/jena/NamespaceMapperJena.java @@ -9,6 +9,9 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import com.hp.hpl.jena.ontology.Individual; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.rdf.listeners.StatementListener; @@ -26,6 +29,8 @@ import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapper; public class NamespaceMapperJena extends StatementListener implements NamespaceMapper { + private static final Log log = LogFactory.getLog(NamespaceMapperJena.class); + private HashMap prefixToNamespaceMap; private HashMap> namespaceToPrefixMap; @@ -60,15 +65,23 @@ public class NamespaceMapperJena extends StatementListener implements } + private static int LARGE_NS = 200; + private void rebuildNamespaceCache() { HashMap tempPrefixToNamespaceMap = new HashMap(); HashMap> tempNamespaceToPrefixMap = new HashMap>(); metadataModel.enterCriticalSection(Lock.READ); + int nsCount = 0; try { // Iterate through all the namespace objects ClosableIterator closeIt = metadataModel.listIndividuals(metadataModel.getResource(VitroVocabulary.NAMESPACE)); try { for (Iterator namespaceIt = closeIt; namespaceIt.hasNext();) { + nsCount++; + if (nsCount == LARGE_NS) { + log.warn("Unusually large number of different namespaces encountered; " + + "namespace mapper setup may take some time."); + } Individual namespaceInd = (Individual) namespaceIt.next(); String namespaceURI = null; RDFNode node = namespaceInd.getPropertyValue(metadataModel.getProperty(VitroVocabulary.NAMESPACE_NAMESPACEURI)); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseObjectPropertyDataPostProcessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseObjectPropertyDataPostProcessor.java index dd67215e5..03cc1e07b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseObjectPropertyDataPostProcessor.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseObjectPropertyDataPostProcessor.java @@ -44,6 +44,7 @@ public abstract class BaseObjectPropertyDataPostProcessor implements /** Postprocessing that applies to the list as a whole - reordering, removing duplicates, etc. */ protected void processList(List> data) { + objectPropertyTemplateModel.removeLessSpecificSolutions(data); objectPropertyTemplateModel.removeDuplicates(data); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java index fb5a9214f..559d5b3e1 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 @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -229,6 +230,67 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel } } + /** + * For performance reasons, we've had to rewrite SPARQL queries that would + * naturally use OPTIONAL blocks to use UNIONs instead. These UNION queries + * return a superset of the solutions returned by the originals. This + * method filters out the unwanted solutions with extra null values. + * + * This operation is polynomial time in the worst case, but should be linear + * with the actual queries used for list views. The ORDER BY clauses + * should minimize the seek distance for solution elimination. + * + * @param List> data + */ + protected void removeLessSpecificSolutions(List> data) { + List> redundantSolns = + new ArrayList>(); + for (int i = 0; i < data.size(); i++) { + Map soln = data.get(i); + boolean redundantSoln = false; + // seek forward + int j = i + 1; + while (!redundantSoln && (j < data.size())) { + redundantSoln = isEqualToOrLessSpecificThan(soln, data.get(j)); + j++; + } + // loop back around + j = 0; + while (!redundantSoln && (j < i)) { + redundantSoln = isEqualToOrLessSpecificThan(soln, data.get(j)); + j++; + } + if (redundantSoln) { + redundantSolns.add(soln); + } + } + data.removeAll(redundantSolns); + } + + /** + * Returns true if soln1 is equal to or less specific (i.e., has more null + * values) than soln2 + * @param List> soln1 + * @param List> soln2 + */ + private boolean isEqualToOrLessSpecificThan (Map soln1, + Map soln2) { + if (soln1.keySet().size() < soln2.keySet().size()) { + return true; + } + for (String key : soln1.keySet()) { + String value1 = soln1.get(key); + String value2 = soln2.get(key); + if (value2 == null && value1 != null) { + return false; + } + if (value1 != null && value2 != null && !value1.equals(value2)) { + return false; + } + } + return true; + } + /** The SPARQL query results may contain duplicate rows for a single object, if there are multiple solutions * to the entire query. Remove duplicates here by arbitrarily selecting only the first row returned. diff --git a/webapp/web/config/listViewConfig-default.xml b/webapp/web/config/listViewConfig-default.xml index 73cb92fd7..33d781186 100644 --- a/webapp/web/config/listViewConfig-default.xml +++ b/webapp/web/config/listViewConfig-default.xml @@ -11,9 +11,21 @@ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?object ?name ?moniker { - GRAPH ?g1 { ?subject ?property ?object } - OPTIONAL { GRAPH ?g2 { ?object rdfs:label ?name } } - OPTIONAL { GRAPH ?g3 { ?object vitro:moniker ?moniker } } + { + ?subject ?property ?object . + } + UNION { + ?subject ?property ?object . + ?object rdfs:label ?name + } + UNION { + ?subject ?property ?object . + ?object vitro:moniker ?moniker + } UNION { + ?subject ?property ?object . + ?object rdfs:label ?name . + ?object vitro:moniker ?moniker . + } } @@ -22,11 +34,28 @@ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?subclass ?object ?name ?moniker { - GRAPH ?g1 { ?subject ?property ?object - OPTIONAL { ?object a ?subclass } + + { + ?subject ?property ?object . + ?object a ?subclass . } - OPTIONAL { GRAPH ?g2 { ?object rdfs:label ?name } } - OPTIONAL { GRAPH ?g3 { ?object vitro:moniker ?moniker } } + UNION { + ?subject ?property ?object . + ?object a ?subclass . + ?object rdfs:label ?name + } + UNION { + ?subject ?property ?object . + ?object a ?subclass . + ?object vitro:moniker ?moniker + } UNION { + ?subject ?property ?object . + ?object a ?subclass . + ?object rdfs:label ?name . + ?object vitro:moniker ?moniker . + } + + } ORDER BY ?subclass diff --git a/webapp/web/config/listViewConfig-vitroLink.xml b/webapp/web/config/listViewConfig-vitroLink.xml index ab5dbca18..accf9f1b9 100644 --- a/webapp/web/config/listViewConfig-vitroLink.xml +++ b/webapp/web/config/listViewConfig-vitroLink.xml @@ -14,10 +14,10 @@ (afn:localname(?link) AS ?linkName) ?anchor ?url WHERE { - GRAPH ?g1 { ?subject ?property ?link } - OPTIONAL { GRAPH ?g2 { ?link vitro:linkAnchor ?anchor } } - OPTIONAL { GRAPH ?g3 { ?link vitro:linkURL ?url } } - OPTIONAL { GRAPH ?g4 { ?link vitro:linkDisplayRank ?rank } } + ?subject ?property ?link + OPTIONAL { ?link vitro:linkAnchor ?anchor } + OPTIONAL { ?link vitro:linkURL ?url } + OPTIONAL { ?link vitro:linkDisplayRank ?rank } } ORDER BY ?rank