diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaExportController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaExportController.java index e463a4a89..20e3726fe 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaExportController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaExportController.java @@ -31,7 +31,6 @@ import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID; import edu.cornell.mannlib.vitro.webapp.dao.jena.JenaModelUtils; -import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceModelMaker; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; @@ -262,21 +261,6 @@ public class JenaExportController extends BaseEditController { } } - private OntModel getOntModelFromAttribute( String attributeName, VitroRequest vreq ) { - - Object o = vreq.getAttribute( attributeName ); - if ( (o != null) && (o instanceof OntModel) ) { - return (OntModel) o; - } else { - o = getServletContext().getAttribute( attributeName ); - if ( (o != null) && (o instanceof OntModel) ) { - return (OntModel) o; - } else { - throw new RuntimeException("Unable to find OntModel in request or context attribute "+attributeName); - } - } - } - static final String FULL_GRAPH = "?g"; static Map formatToExtension; static Map formatToMimetype; @@ -301,14 +285,12 @@ public class JenaExportController extends BaseEditController { private static final String ABOX_FULL_CONSTRUCT = "CONSTRUCT { ?s ?p ?o } " + "WHERE { GRAPH ?g { ?s ?p ?o } FILTER (!regex(str(?g), \"tbox\")) " + - "FILTER (?g != <" + ModelNames.APPLICATION_METADATA + ">) " + - "FILTER (?g != <" + RDFServiceModelMaker.METADATA_MODEL_URI + ">) }"; + "FILTER (?g != <" + ModelNames.APPLICATION_METADATA + ">) }"; private static final String ABOX_ASSERTED_CONSTRUCT = "CONSTRUCT { ?s ?p ?o } " + "WHERE { GRAPH ?g { ?s ?p ?o } FILTER (!regex(str(?g), \"tbox\")) " + "FILTER (?g != <" + ModelNames.ABOX_INFERENCES + ">) " + - "FILTER (?g != <" + ModelNames.APPLICATION_METADATA + ">) " + - "FILTER (?g != <" + RDFServiceModelMaker.METADATA_MODEL_URI + ">) }"; + "FILTER (?g != <" + ModelNames.APPLICATION_METADATA + ">) }"; private static final String FULL_FULL_CONSTRUCT = "CONSTRUCT { ?s ?p ?o } " + "WHERE { ?s ?p ?o }"; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/BlankNodeFilteringModelMaker.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/BlankNodeFilteringModelMaker.java new file mode 100644 index 000000000..4d87cad5e --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/BlankNodeFilteringModelMaker.java @@ -0,0 +1,125 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.dao.jena; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.graph.Graph; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.ModelMaker; +import com.hp.hpl.jena.rdf.model.ModelReader; +import com.hp.hpl.jena.shared.CannotCreateException; + +import edu.cornell.mannlib.vitro.webapp.modelaccess.adapters.AbstractModelMakerDecorator; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ModelSerializationFormat; +import edu.cornell.mannlib.vitro.webapp.rdfservice.adapters.VitroModelFactory; + +/** + * Still not sure why this is needed, but... + * + * Let's assume that there are some model operations that are implemented by + * multiple SPARQL queries against the RDFService. Those multiple queries might + * return different values for the same blank node, so when the results of the + * queries were combined, the relationships would be lost. + * + * To avoid this, we assume that all of the statements involving blank nodes + * will fit nicely into memory, and we fetch them all at once. After that, all + * of our operations are against the union of the actual model minus blank nodes + * and the memory model. + * + * The models do retain the same ID for each blank node on successive + * operations, so we can execute repeated queries and it will work fine. + * + * Writing blank nodes is probably a different matter, unless unrelated to + * existing blank nodes. + */ +public class BlankNodeFilteringModelMaker extends AbstractModelMakerDecorator { + private static final Log log = LogFactory + .getLog(BlankNodeFilteringModelMaker.class); + + private final RDFService rdfService; + + public BlankNodeFilteringModelMaker(RDFService rdfService, ModelMaker inner) { + super(inner); + this.rdfService = rdfService; + } + + @Override + public Model createModel(String name) { + return wrapModelWithFilter(name, super.createModel(name)); + } + + @Override + public Model createModel(String name, boolean strict) { + return wrapModelWithFilter(name, super.createModel(name, strict)); + } + + @Override + public Model openModel(String name) { + return wrapModelWithFilter(name, super.openModel(name)); + } + + @Override + public Model openModelIfPresent(String name) { + return wrapModelWithFilter(name, super.openModelIfPresent(name)); + } + + @Override + public Model getModel(String name) { + return wrapModelWithFilter(name, super.getModel(name)); + } + + @Override + public Model getModel(String name, ModelReader loadIfAbsent) { + return wrapModelWithFilter(name, super.getModel(name, loadIfAbsent)); + } + + @Override + public Model openModel(String name, boolean strict) { + return wrapModelWithFilter(name, super.openModel(name, strict)); + } + + public Model wrapModelWithFilter(String name, Model model) { + if (model == null) { + return null; + } + + String bnodeQuery = String.format("construct { ?s ?p ?o } \n" // + + "where { \n" // + + " graph <%s> { \n" // + + " ?s ?p ?o \n " + + " filter (isBlank(?s) || isBlank(?o)) \n" + " } \n" // + + "}", name); + + Model bnodeModel = ModelFactory.createDefaultModel(); + long start = System.currentTimeMillis(); + try { + bnodeModel.read(rdfService.sparqlConstructQuery(bnodeQuery, + ModelSerializationFormat.N3), null, "N3"); + log.debug("constructed a model of blank nodes of size: " + + bnodeModel.size() + " for graph " + name); + } catch (Exception e) { + log.error("error trying to create a blank node model: ", e); + throw new CannotCreateException(name); + } + + long timeElapsedMillis = System.currentTimeMillis() - start; + log.debug("msecs to find blank nodes for graph " + name + " " + + timeElapsedMillis); + + Graph bnodeFilteringGraph = new BlankNodeFilteringGraph( + model.getGraph()); + Model bnodeFilteringModel = ModelFactory + .createModelForGraph(bnodeFilteringGraph); + + Model specialUnionModel = VitroModelFactory.createUnion( + bnodeFilteringModel, bnodeModel); + bnodeFilteringModel + .register(new BlankNodeStatementListener(bnodeModel)); + + return specialUnionModel; + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceModelMaker.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceModelMaker.java index ec490d477..3325605d6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceModelMaker.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceModelMaker.java @@ -2,320 +2,162 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena; -import java.text.Collator; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; import java.util.Set; +import java.util.TreeSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import com.hp.hpl.jena.graph.BulkUpdateHandler; -import com.hp.hpl.jena.graph.Graph; import com.hp.hpl.jena.graph.GraphMaker; -import com.hp.hpl.jena.query.Dataset; -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.ModelMaker; import com.hp.hpl.jena.rdf.model.ModelReader; -import com.hp.hpl.jena.rdf.model.RDFNode; -import com.hp.hpl.jena.rdf.model.Resource; -import com.hp.hpl.jena.rdf.model.ResourceFactory; -import com.hp.hpl.jena.rdf.model.Statement; -import com.hp.hpl.jena.rdf.model.StmtIterator; +import com.hp.hpl.jena.shared.AlreadyExistsException; +import com.hp.hpl.jena.shared.CannotCreateException; +import com.hp.hpl.jena.shared.DoesNotExistException; import com.hp.hpl.jena.util.iterator.ExtendedIterator; import com.hp.hpl.jena.util.iterator.WrappedIterator; +import com.ibm.icu.text.Collator; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; -import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ModelSerializationFormat; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; -import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory; -import edu.cornell.mannlib.vitro.webapp.rdfservice.adapters.VitroModelFactory; public class RDFServiceModelMaker implements ModelMaker { - private final static Log log = LogFactory.getLog(RDFServiceModelMaker.class); - - private RDFServiceFactory rdfServiceFactory; - - public static final String METADATA_MODEL_URI = - "http://vitro.mannlib.cornell.edu/ns/vitro/sdb/metadata"; - - public static final String HAS_NAMED_MODEL_URI = - "http://vitro.mannlib.cornell.edu/ns/vitro/sdb/hasNamedModel"; - - private Resource dbResource; // a resource representing the triple store - - public RDFServiceModelMaker(RDFServiceFactory rdfServiceFactory) { - this.rdfServiceFactory = rdfServiceFactory; - - RDFService rdfService = rdfServiceFactory.getRDFService(); - if (rdfService != null) { - try { - setUpMetadata(rdfService); - } catch (RDFServiceException se) { - log.error("unable to set up the cache of graph names"); - } finally { - rdfService.close(); - } - } - } - - protected RDFService getRDFService() { - return rdfServiceFactory.getRDFService(); - } - - Model getMetadataModel() { - return getModel(METADATA_MODEL_URI); - } - - public void close() { - // getRDFService().close(); ? - } + private final static Log log = LogFactory.getLog(RDFServiceModelMaker.class); - public Model createModel(String modelName) { - - Model model = getModel(modelName); - Model metadataModel = getMetadataModel(); - - Literal modelNameLiteral = ResourceFactory.createPlainLiteral(modelName); - Statement metadataStatment = ResourceFactory.createStatement(dbResource,metadataModel.getProperty( - HAS_NAMED_MODEL_URI), modelNameLiteral); - - // to get around blank node filtering on BlankNodeFiltering graph - List stmtList = new ArrayList(); - stmtList.add(metadataStatment); - - try { - metadataModel.add(stmtList); - } finally { - metadataModel.close(); - } - return model; - } + private RDFService service; + private RDFServiceDataset dataset; - public Model createModel(String arg0, boolean arg1) { - // TODO Figure out if we can offer a "create if not found" option using SDB - return createModel(arg0); - } + public RDFServiceModelMaker(RDFService service) { + this.service = service; + this.dataset = new RDFServiceDataset(service); + } - public GraphMaker getGraphMaker() { - throw new UnsupportedOperationException( - "GraphMaker not supported by " + this.getClass().getName()); - } + @Override + public void close() { + dataset.close(); + // service.close(); ? + } - public boolean hasModel(String arg0) { - Model metadataModel = getMetadataModel(); - try { - StmtIterator stmtIt = metadataModel.listStatements( - dbResource, metadataModel.getProperty( - HAS_NAMED_MODEL_URI), arg0); - try { - return stmtIt.hasNext(); - } finally { - if (stmtIt != null) { - stmtIt.close(); - } - } - } finally { - metadataModel.close(); - } - } + @Override + public Model createModel(String name) { + Model model = getModel(name); + if (model == null) { + throw new CannotCreateException(name); + } else { + return model; + } + } - public ExtendedIterator listModels() { - Model metadataModel = getMetadataModel(); - try { - return listModelNames(metadataModel); - } finally { - metadataModel.close(); - } - } - - private ExtendedIterator listModelNames(Model metadataModel) { - - Set modelNameSet = new HashSet(); - - Iterator metadataNameIt = metadataModel.listObjectsOfProperty( - metadataModel.getProperty(HAS_NAMED_MODEL_URI)); - while (metadataNameIt.hasNext()) { - RDFNode rdfNode = metadataNameIt.next(); - if (rdfNode.isLiteral()) { - modelNameSet.add(((Literal) rdfNode).getLexicalForm()); - } - } - - RDFService service = getRDFService(); - try { - modelNameSet.addAll(service.getGraphURIs()); - } catch (RDFServiceException e) { - throw new RuntimeException(e); - } finally { - service.close(); - } - - List modelNameList = new ArrayList(); - modelNameList.addAll(modelNameSet); - Collections.sort(modelNameList, Collator.getInstance()); - - return WrappedIterator.create(modelNameList.iterator()); - } + @Override + public Model createModel(String name, boolean strict) { + if (this.hasModel(name) && strict) { + throw new AlreadyExistsException(name); + } else { + return createModel(name); + } + } - public Model openModel(String graph, boolean arg1) { - - RDFService rdfService = getRDFService(); - - String bnodeQuery = "construct { ?s ?p ?o } where { "; - bnodeQuery += (graph != null) ? "graph <" + graph + "> {" : ""; - bnodeQuery += "?s ?p ?o filter (isBlank(?s) || isBlank(?o)) }"; - bnodeQuery += (graph != null) ? "}" : ""; - - Model bnodeModel = ModelFactory.createDefaultModel(); - long start = System.currentTimeMillis(); - try { - bnodeModel.read(rdfService.sparqlConstructQuery(bnodeQuery, ModelSerializationFormat.N3), null, "N3"); - log.debug("constructed a model of blank nodes of size: " + bnodeModel.size() + " for graph " + graph); - } catch (RDFServiceException se) { - log.error("Error trying to create blank node model.", se); - return null; - } catch (Exception e) { - log.error("error trying to create a blank node model: " + e.getMessage()); - return null; - } + @Override + public GraphMaker getGraphMaker() { + throw new UnsupportedOperationException("GraphMaker not supported by " + + this.getClass().getName()); + } - long timeElapsedMillis = System.currentTimeMillis() - start; - log.debug("msecs to find blank nodes for graph " + graph + " " + timeElapsedMillis); + private Set getModelNames() { + try { + @SuppressWarnings("unchecked") + Set names = new TreeSet<>(Collator.getInstance()); + names.addAll(service.getGraphURIs()); + return names; + } catch (RDFServiceException e) { + throw new RuntimeException(e); + } + } - Model model = null; - try { - Dataset dataset = new RDFServiceDataset(rdfService); - model = dataset.getNamedModel(graph); - } finally { - rdfService.close(); - } - - Graph bnodeFilteringGraph = new BlankNodeFilteringGraph(model.getGraph()); - Model bnodeFilteringModel = ModelFactory.createModelForGraph(bnodeFilteringGraph); - - Model specialUnionModel = VitroModelFactory.createUnion(bnodeFilteringModel, bnodeModel); - bnodeFilteringModel.register(new BlankNodeStatementListener(bnodeModel)); - - return specialUnionModel; - } + @Override + public boolean hasModel(String name) { + return getModelNames().contains(name); + } - public void removeModel(String arg0) { - Model m = getModel(arg0); - m.removeAll(null,null,null); - Model metadataModel = getMetadataModel(); - try { - metadataModel.remove(dbResource, metadataModel.getProperty( - HAS_NAMED_MODEL_URI),metadataModel.createLiteral(arg0)); - } finally { - metadataModel.close(); - } - } + @Override + public ExtendedIterator listModels() { + return WrappedIterator.create(getModelNames().iterator()); + } - public Model addDescription(Model arg0, Resource arg1) { - throw new UnsupportedOperationException( - "addDescription not supported by " + this.getClass().getName()); - } + @Override + public Model openModel(String name, boolean strict) { + if (strict && !this.hasModel(name)) { + throw new DoesNotExistException(name); + } else { + return getModel(name); + } + } - public Model createModelOver(String arg0) { - throw new UnsupportedOperationException( - "createModelOver not supported by " + this.getClass().getName()); - } + /** + * The contract says to disassociate the name while leaving the model + * undisturbed. However, you should then be able to create a new model with + * the same name, and that doesn't make any sense in this context. + */ + @Override + public void removeModel(String name) { + Model m = getModel(name); + m.removeAll(null, null, null); + } - public Model getDescription() { - throw new UnsupportedOperationException( - "createModelOver not supported by " + this.getClass().getName()); - } + @Override + public Model createDefaultModel() { + return dataset.getDefaultModel(); + } - public Model getDescription(Resource arg0) { - throw new UnsupportedOperationException( - "getDescription not supported by "+this.getClass().getName()); - } + @Override + public Model createFreshModel() { + throw new UnsupportedOperationException( + "createFreshModel not supported by " + + this.getClass().getName()); + } - public Model openModel() { - RDFService service = getRDFService(); - try { - Dataset dataset = new RDFServiceDataset(service); - return dataset.getDefaultModel(); - } finally { - service.close(); - } - } + @Override + public Model openModel(String name) { + Model m = getModel(name); + if (m == null) { + throw new DoesNotExistException(name); + } else { + return m; + } + } - public Model createDefaultModel() { - return openModel(); - } + @Override + public Model openModelIfPresent(String name) { + if (this.hasModel(name)) { + return getModel(name); + } else { + return null; + } + } - public Model createFreshModel() { - throw new UnsupportedOperationException( - "createFreshModel not supported by " + this.getClass().getName()); - } + @Override + public Model getModel(String name, ModelReader loadIfNotAbsent) { + Model m = getModel(name); + if (m == null) { + // Ignore the ModelReader. If the model is not present, give up. + throw new CannotCreateException(name); + } else { + return m; + } + } - /** - * @deprecated - */ - public Model createModel() { - return openModel(); - } + /** + * Return a model from the RDFService. If the model does not exist, create + * an empty one. + */ + @Override + public Model getModel(String name) { + if (name == null) { + return null; + } + return dataset.getNamedModel(name); + } - /** - * @deprecated - */ - public Model getModel() { - return openModel(); - } - - public Model openModel(String arg0) { - return openModel(); - } - - public Model openModelIfPresent(String arg0) { - return (this.hasModel(arg0)) - ? openModel(arg0, false) - : null; - } - - public Model getModel(String modelName) { - return openModel(modelName, true); - } - - public Model getModel(String arg0, ModelReader arg1) { - throw new UnsupportedOperationException( - "getModel(String, ModelReader) not supported by " + - this.getClass().getName()); - } - - private void setUpMetadata(RDFService rdfService) throws RDFServiceException { - Model metadataModel = getMetadataModel(); - - if (metadataModel.size() == 0) { - // set up the model name metadata to avoid expensive calls to - // listNames() - Resource resource = metadataModel.createResource(); - this.dbResource = resource; - - List graphNames = rdfService.getGraphURIs(); - Iterator nameIt = graphNames.iterator(); - while (nameIt.hasNext()) { - String name = nameIt.next(); - metadataModel.add(dbResource,metadataModel.getProperty( - HAS_NAMED_MODEL_URI),name); - } - } else { - StmtIterator stmtIt = metadataModel.listStatements( - (Resource) null, metadataModel.getProperty( - HAS_NAMED_MODEL_URI),(RDFNode) null); - if (stmtIt.hasNext()) { - Statement stmt = stmtIt.nextStatement(); - dbResource = stmt.getSubject(); - } - stmtIt.close(); - } - } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/modelaccess/ModelNames.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/modelaccess/ModelNames.java index d75429921..677ac815a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/modelaccess/ModelNames.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/modelaccess/ModelNames.java @@ -8,11 +8,19 @@ package edu.cornell.mannlib.vitro.webapp.modelaccess; public class ModelNames { public static final String ABOX_ASSERTIONS = "http://vitro.mannlib.cornell.edu/default/vitro-kb-2"; public static final String ABOX_INFERENCES = "http://vitro.mannlib.cornell.edu/default/vitro-kb-inf"; + public static final String ABOX_UNION = "vitro:aboxOntModel"; + public static final String TBOX_ASSERTIONS = "http://vitro.mannlib.cornell.edu/default/asserted-tbox"; public static final String TBOX_INFERENCES = "http://vitro.mannlib.cornell.edu/default/inferred-tbox"; + public static final String TBOX_UNION = "vitro:tboxOntModel"; + + public static final String FULL_ASSERTIONS = "vitro:baseOntModel"; + public static final String FULL_INFERENCES = "vitro:inferenceOntModel"; + public static final String FULL_UNION = "vitro:jenaOntModel"; + + public static final String APPLICATION_METADATA = "http://vitro.mannlib.cornell.edu/default/vitro-kb-applicationMetadata"; public static final String USER_ACCOUNTS = "http://vitro.mannlib.cornell.edu/default/vitro-kb-userAccounts"; public static final String DISPLAY = "http://vitro.mannlib.cornell.edu/default/vitro-kb-displayMetadata"; public static final String DISPLAY_TBOX = "http://vitro.mannlib.cornell.edu/default/vitro-kb-displayMetadataTBOX"; public static final String DISPLAY_DISPLAY = "http://vitro.mannlib.cornell.edu/default/vitro-kb-displayMetadata-displayModel"; - public static final String APPLICATION_METADATA = "http://vitro.mannlib.cornell.edu/default/vitro-kb-applicationMetadata"; }