From 70ad9831eb0f512e8c5b0bded762e99cecc8a23a Mon Sep 17 00:00:00 2001 From: brianjlowe Date: Tue, 19 Jun 2012 20:14:57 +0000 Subject: [PATCH] NIHVIVO-3779 bulk updates and blank node handling for SPARQL implementation of RDF API, and associated bug fixes --- .../controller/edit/ReorderController.java | 2 +- .../edit/VclassRetryController.java | 3 +- .../vitro/webapp/dao/jena/JenaBaseDao.java | 40 ++- .../vitro/webapp/dao/jena/VClassDaoJena.java | 15 +- .../webapp/dao/jena/WebappDaoFactorySDB.java | 2 +- .../filters/WebappDaoFactorySDBPrep.java | 2 +- .../webapp/rdfservice/RDFServiceFactory.java | 2 - .../rdfservice/filter/FilteredResultSet.java | 65 ++++ .../SameAsFilteringRDFServiceFactory.java | 246 ++++++++++++++ .../rdfservice/impl/RDFServiceImpl.java | 11 +- .../rdfservice/impl/RDFServiceUtils.java | 39 +++ .../rdfservice/impl/sdb/ListeningGraph.java | 17 +- .../rdfservice/impl/sdb/RDFServiceSDB.java | 90 ++++-- .../impl/sparql/RDFServiceSparql.java | 302 +++++++++++++++--- .../webapp/servlet/setup/RDFServiceSetup.java | 9 +- 15 files changed, 737 insertions(+), 108 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/FilteredResultSet.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ReorderController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ReorderController.java index 8aeb939b1..67bbd6bf9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ReorderController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ReorderController.java @@ -106,7 +106,7 @@ public class ReorderController extends VitroAjaxController { private void reorderIndividuals(String[] individualUris, VitroRequest vreq, String rankPredicate) { //Testing new mechanism - OntModel writeModel = vreq.getJenaOntModel(); + OntModel writeModel = vreq.getOntModelSelector().getABoxModel(); Model additions = ModelFactory.createDefaultModel(); Model retractions = ModelFactory.createDefaultModel(); Property rankPredicateProperty = ResourceFactory.createProperty(rankPredicate); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassRetryController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassRetryController.java index 7cb320d77..422ba3af6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassRetryController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassRetryController.java @@ -49,7 +49,6 @@ public class VclassRetryController extends BaseEditController { //create an EditProcessObject for this and put it in the session EditProcessObject epo = super.createEpo(request); - epo.setDataAccessObject(request.getFullWebappDaoFactory().getVClassDao()); /*for testing*/ VClass testMask = new VClass(); @@ -65,7 +64,7 @@ public class VclassRetryController extends BaseEditController { action = epo.getAction(); } - VClassDao vcwDao = request.getFullWebappDaoFactory().getVClassDao(); + VClassDao vcwDao = request.getAssertionsWebappDaoFactory().getVClassDao(); epo.setDataAccessObject(vcwDao); VClassGroupDao cgDao = request.getFullWebappDaoFactory().getVClassGroupDao(); OntologyDao oDao = request.getFullWebappDaoFactory().getOntologyDao(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java index 15ace02c8..8bdd4fd00 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java @@ -1028,17 +1028,36 @@ public class JenaBaseDao extends JenaBaseDaoCon { return directSubjectList; } + /** + * Returns additions and retractions to perform + * @param ontRes + * @param ontModel + * @return Model[] where [0] is retractions and [1] is additions + */ + protected Model[] getSmartRemoval(OntResource ontRes, OntModel ontModel) { + Model[] changeSet = removeFromLists(ontRes, ontModel); + List stmtForDependentRes = DependentResourceDeleteJena.getDependentResourceDeleteList(ontRes,ontModel); + changeSet[0].add(removeUsingDescribe(ontRes, ontModel)); + changeSet[0].add(stmtForDependentRes); + return changeSet; + } + protected void smartRemove(OntResource ontRes, OntModel ontModel) { - removeFromLists(ontRes, ontModel); - List stmtForDependentRes = DependentResourceDeleteJena.getDependentResourceDeleteList(ontRes,ontModel); - removeUsingDescribe(ontRes, ontModel); - ontModel.remove(stmtForDependentRes); + Model[] changes = getSmartRemoval(ontRes, ontModel); + ontModel.remove(changes[0]); + ontModel.add(changes[1]); + } /** * Removes a resource from any rdf:Lists in which it is a member */ - private void removeFromLists(OntResource res, OntModel ontModel) { + private Model[] removeFromLists(OntResource res, OntModel ontModel) { + Model[] changeSet = new Model[2]; + Model retractions = ModelFactory.createDefaultModel(); + Model additions = ModelFactory.createDefaultModel(); + changeSet[0] = retractions; + changeSet[1] = additions; // Iterate through all of the list nodes this resource is attached to Iterator listNodeIt = ontModel.listSubjectsWithProperty(RDF.first, res); while (listNodeIt.hasNext()) { @@ -1056,16 +1075,17 @@ public class JenaBaseDao extends JenaBaseDaoCon { // if current node is list head if (!nextNode.equals(RDF.nil)) { // only repair the list if there is more than one node - ontModel.add(stmt.getSubject(), RDF.rest, nextNode); + additions.add(stmt.getSubject(), RDF.rest, nextNode); } } else { - ontModel.add(stmt.getSubject(), RDF.rest, nextNode); + additions.add(stmt.getSubject(), RDF.rest, nextNode); } } } //Remove any statements about this node - ontModel.remove(listNode, (Property) null, (RDFNode) null); + retractions.add(listNode, (Property) null, (RDFNode) null); } + return changeSet; } public void removeRulesMentioningResource(Resource res, OntModel ontModel) { @@ -1093,10 +1113,10 @@ public class JenaBaseDao extends JenaBaseDaoCon { // removes a resource and its bnode closure using ARQ's DESCRIBE semantics // plus any incoming properties - private void removeUsingDescribe(OntResource ontRes, OntModel ontModel) { + private Model removeUsingDescribe(OntResource ontRes, OntModel ontModel) { Model temp = describeResource(ontRes, ontModel); temp.add(ontModel.listStatements((Resource) null, (Property) null, ontRes)); - ontModel.remove(temp); + return temp; } private Model describeResource(Resource res, OntModel ontModel) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java index b2208eb22..481470a8f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java @@ -38,6 +38,7 @@ import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.ResIterator; @@ -1026,15 +1027,23 @@ public class VClassDaoJena extends JenaBaseDao implements VClassDao { try { OntResource subclass = getOntClass(ontModel,c2c.getSubclassURI()); OntResource superclass = getOntClass(ontModel,c2c.getSuperclassURI()); + Model removal = ModelFactory.createDefaultModel(); + Model additions = ModelFactory.createDefaultModel(); // to repair any rdf:Lists if ((subclass != null) && (superclass != null)) { - ontModel.removeAll(subclass, RDFS.subClassOf, superclass); + removal.add(ontModel.listStatements(subclass, RDFS.subClassOf, superclass)); } if (subclass.isAnon()) { - smartRemove(subclass, getOntModel()); + Model[] changeSet = getSmartRemoval(subclass, getOntModel()); + removal.add(changeSet[0]); + additions.add(changeSet[1]); } if (superclass.isAnon()) { - smartRemove(superclass, getOntModel()); + Model[] changeSet = getSmartRemoval(superclass, getOntModel()); + removal.add(changeSet[0]); + additions.add(changeSet[1]); } + ontModel.remove(removal); + ontModel.add(additions); } finally { ontModel.getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(),false)); ontModel.leaveCriticalSection(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactorySDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactorySDB.java index d33051beb..08d56c6f9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactorySDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactorySDB.java @@ -147,7 +147,7 @@ public class WebappDaoFactorySDB extends WebappDaoFactoryJena { @Override public void close() { super.close(); - this.rdfService.close(); + //this.rdfService.close(); } private class ReconnectingDatasetFactory implements DatasetWrapperFactory { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/WebappDaoFactorySDBPrep.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/WebappDaoFactorySDBPrep.java index eafe98550..615a736ce 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/WebappDaoFactorySDBPrep.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/WebappDaoFactorySDBPrep.java @@ -119,7 +119,7 @@ public class WebappDaoFactorySDBPrep implements Filter { vreq.setAssertionsWebappDaoFactory(assertions); vreq.setFullWebappDaoFactory(wadf); vreq.setDataset(dataset); - vreq.setOntModelSelector(oms); + vreq.setOntModelSelector(baseOms); vreq.setJenaOntModel(ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM, dataset.getDefaultModel())); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFServiceFactory.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFServiceFactory.java index 770b60a48..1e865ac5f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFServiceFactory.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFServiceFactory.java @@ -2,8 +2,6 @@ package edu.cornell.mannlib.vitro.webapp.rdfservice; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; - public interface RDFServiceFactory { public RDFService getRDFService(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/FilteredResultSet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/FilteredResultSet.java new file mode 100644 index 000000000..d51ecc411 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/FilteredResultSet.java @@ -0,0 +1,65 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.rdfservice.filter; + +import java.util.Iterator; +import java.util.List; + +import com.hp.hpl.jena.query.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.sparql.engine.binding.Binding; + +public class FilteredResultSet implements ResultSet { + + private Iterator solutIt; + private ResultSet originalResultSet; + private int rowNum = -1; + + public FilteredResultSet (List solutions, ResultSet originalResultSet) { + this.solutIt = solutions.iterator(); + this.originalResultSet = originalResultSet; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Attempt to remove an element"); + } + + @Override + public Model getResourceModel() { + return originalResultSet.getResourceModel(); + } + + @Override + public List getResultVars() { + return originalResultSet.getResultVars(); + } + + @Override + public int getRowNumber() { + return rowNum; + } + + @Override + public boolean hasNext() { + return solutIt.hasNext(); + } + + @Override + public QuerySolution next() { + return nextSolution(); + } + + @Override + public Binding nextBinding() { + throw new UnsupportedOperationException("Can we ignore this?"); + } + + @Override + public QuerySolution nextSolution() { + rowNum++; + return solutIt.next(); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java new file mode 100644 index 000000000..1f2cc6db1 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java @@ -0,0 +1,246 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.rdfservice.filter; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.QueryExecution; +import com.hp.hpl.jena.query.QueryExecutionFactory; +import com.hp.hpl.jena.query.QueryFactory; +import com.hp.hpl.jena.query.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.query.ResultSetFactory; +import com.hp.hpl.jena.query.ResultSetFormatter; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.rdf.model.StmtIterator; +import com.hp.hpl.jena.vocabulary.OWL; + +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; +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.impl.RDFServiceImpl; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; + +public class SameAsFilteringRDFServiceFactory implements RDFServiceFactory { + + private final static Log log = LogFactory.getLog( + SameAsFilteringRDFServiceFactory.class); + private RDFServiceFactory f; + private Model sameAsModel; + + public SameAsFilteringRDFServiceFactory(RDFServiceFactory rdfServiceFactory) { + this.f = rdfServiceFactory; + try { + InputStream in = f.getRDFService().sparqlConstructQuery("CONSTRUCT { ?s <" + OWL.sameAs.getURI() + "> ?o } WHERE { ?s <" + OWL.sameAs.getURI() + "> ?o } ", ModelSerializationFormat.N3); + sameAsModel = RDFServiceUtils.parseModel(in, ModelSerializationFormat.N3); + } catch (RDFServiceException e) { + throw new RuntimeException(e); + } + } + + @Override + public RDFService getRDFService() { + return new SameAsFilteringRDFService(f.getRDFService()); + } + + @Override + public void registerListener(ChangeListener changeListener) throws RDFServiceException { + f.registerListener(changeListener); + } + + @Override + public void unregisterListener(ChangeListener changeListener) throws RDFServiceException { + f.registerListener(changeListener); + } + + public class SameAsFilteringRDFService extends RDFServiceImpl implements RDFService { + + private final Log log = LogFactory.getLog(SameAsFilteringRDFService.class); + + private RDFService s; + + public SameAsFilteringRDFService(RDFService rdfService) { + this.s = rdfService; + } + + @Override + public InputStream sparqlConstructQuery(String query, + RDFService.ModelSerializationFormat resultFormat) + throws RDFServiceException { + Model m = RDFServiceUtils.parseModel( + s.sparqlConstructQuery(query, resultFormat), resultFormat); + Model filtered = ModelFactory.createDefaultModel(); + StmtIterator stmtIt = m.listStatements(); + while (stmtIt.hasNext()) { + Statement stmt = stmtIt.nextStatement(); + if (!isRedundant(stmt)) { + filtered.add(stmt); + } + } + ByteArrayOutputStream out = new ByteArrayOutputStream(); + filtered.write(out, RDFServiceUtils.getSerializationFormatString( + resultFormat)); + return new ByteArrayInputStream(out.toByteArray()); + } + + @Override + public InputStream sparqlSelectQuery(String query, ResultFormat resultFormat) + throws RDFServiceException { + ResultSet rs = ResultSetFactory.load( + s.sparqlSelectQuery(query, resultFormat), + RDFServiceUtils.getJenaResultSetFormat(resultFormat)); + List solutions = new ArrayList(); + while (rs.hasNext()) { + QuerySolution solution = rs.nextSolution(); + if (!isRedundant(solution)) { + solutions.add(solution); + } + } + ResultSet resultSet = new FilteredResultSet(solutions, rs); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + switch (resultFormat) { + case CSV: + ResultSetFormatter.outputAsCSV(outputStream,resultSet); + break; + case TEXT: + ResultSetFormatter.out(outputStream,resultSet); + break; + case JSON: + ResultSetFormatter.outputAsJSON(outputStream, resultSet); + break; + case XML: + ResultSetFormatter.outputAsXML(outputStream, resultSet); + break; + default: + throw new RDFServiceException("unrecognized result format"); + } + return new ByteArrayInputStream(outputStream.toByteArray()); + } + + private boolean isRedundant(Statement s) { + List sameAsResources = getSameAsResources(s.getSubject()); + if (sameAsResources.size() > 0 && !sameAsResources.get(0).equals(s.getSubject())) { + return true; + } + if (s.getObject().isLiteral() || s.getObject().isAnon()) { + return false; + } + sameAsResources = getSameAsResources(s.getObject().asResource()); + if (sameAsResources.size() > 0 && !sameAsResources.get(0).equals(s.getObject().asResource())) { + return true; + } + return false; + } + + private List getSameAsResources(Resource resource) { + List sameAsResources = new ArrayList(); + if (resource.isAnon()) { + return sameAsResources; + } + String queryStr = "SELECT DISTINCT ?s WHERE { <" + resource.getURI() + "> <" + OWL.sameAs.getURI() + "> ?s } ORDER BY ?s"; + try { + Query query = QueryFactory.create(queryStr); + QueryExecution qe = QueryExecutionFactory.create(query, sameAsModel); + try { + ResultSet rs = qe.execSelect(); + //ResultSet rs = JSONInput.fromJSON(s.sparqlSelectQuery(queryStr, ResultFormat.JSON)); + while (rs.hasNext()) { + QuerySolution q = rs.next(); + Resource res = q.getResource("s"); + if (s != null) { + log.info("adding same as " + res.getURI()); + sameAsResources.add(res); + } + } + } finally { + qe.close(); + } + return sameAsResources; + } catch (/*RDFService*/Exception e) { + throw new RuntimeException(e); + } + } + + private boolean isRedundant(QuerySolution q) { + Iterator varIt = q.varNames(); + while(varIt.hasNext()) { + String varName = varIt.next(); + RDFNode n = q.get(varName); + if (n.isResource()) { + Resource r = n.asResource(); + List sames = getSameAsResources(r); + if (sames.size() > 0 && !sames.get(0).equals(r)) { + return true; + } + } + } + return false; + } + + @Override + public boolean changeSetUpdate(ChangeSet changeSet) + throws RDFServiceException { + return s.changeSetUpdate(changeSet); + } + + @Override + public InputStream sparqlDescribeQuery(String query, + ModelSerializationFormat resultFormat) + throws RDFServiceException { + Model m = RDFServiceUtils.parseModel( + s.sparqlConstructQuery(query, resultFormat), resultFormat); + Model filtered = ModelFactory.createDefaultModel(); + StmtIterator stmtIt = m.listStatements(); + while (stmtIt.hasNext()) { + Statement stmt = stmtIt.nextStatement(); + if (!isRedundant(stmt)) { + filtered.add(stmt); + } + } + ByteArrayOutputStream out = new ByteArrayOutputStream(); + filtered.write(out, RDFServiceUtils.getSerializationFormatString( + resultFormat)); + return new ByteArrayInputStream(out.toByteArray()); + } + + @Override + public boolean sparqlAskQuery(String query) throws RDFServiceException { + return s.sparqlAskQuery(query); + } + + @Override + public List getGraphURIs() throws RDFServiceException { + return s.getGraphURIs(); + } + + @Override + public void getGraphMetadata() throws RDFServiceException { + s.getGraphMetadata(); + } + + @Override + public void close() { + s.close(); + } + + + } + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java index 0cd30e15c..3bb6a03f5 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java @@ -132,7 +132,11 @@ public abstract class RDFServiceImpl implements RDFService { return new ChangeSetImpl(); } - protected void notifyListeners(Triple triple, ModelChange.Operation operation, String graphURI) { + // I switched the following two methods back to public so they could be + // used by the ListeningGraph, which is common to both implementations. + // This could probably be improved later. BJL + + public void notifyListeners(Triple triple, ModelChange.Operation operation, String graphURI) { Iterator iter = registeredListeners.iterator(); while (iter.hasNext()) { @@ -145,8 +149,7 @@ public abstract class RDFServiceImpl implements RDFService { } } - protected void notifyListenersOfEvent(Object event) { - + public void notifyListenersOfEvent(Object event) { Iterator iter = registeredListeners.iterator(); while (iter.hasNext()) { @@ -181,7 +184,7 @@ public abstract class RDFServiceImpl implements RDFService { case RDFXML: return "RDF/XML"; case N3: - return "N3"; + return "TTL"; default: log.error("unexpected format in getFormatString"); return null; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java index 10b6313f7..a34aef1e5 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java @@ -8,8 +8,14 @@ import java.io.UnsupportedEncodingException; import javax.servlet.ServletContext; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.sparql.resultset.ResultSetFormat; + import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ModelSerializationFormat; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ResultFormat; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory; public class RDFServiceUtils { @@ -35,6 +41,39 @@ public class RDFServiceUtils { } } + public static Model parseModel(InputStream in, ModelSerializationFormat format) { + Model model = ModelFactory.createDefaultModel(); + model.read(in, null, + getSerializationFormatString(format)); + return model; + } + + public static ResultSetFormat getJenaResultSetFormat(ResultFormat resultFormat) { + switch(resultFormat) { + case JSON: + return ResultSetFormat.syntaxJSON; + case CSV: + return ResultSetFormat.syntaxCSV; + case XML: + return ResultSetFormat.syntaxXML; + case TEXT: + return ResultSetFormat.syntaxText; + default: + throw new RuntimeException("unsupported ResultFormat"); + } + } + + public static String getSerializationFormatString(RDFService.ModelSerializationFormat format) { + switch (format) { + case RDFXML: + return "RDF/XML"; + case N3: + return "N3"; + default: + throw new RuntimeException("unexpected format in getFormatString"); + } + } + public static RDFService getRDFService(VitroRequest vreq) { return getRDFServiceFactory( vreq.getSession().getServletContext()).getRDFService(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/ListeningGraph.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/ListeningGraph.java index 2db8d1e64..07271054f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/ListeningGraph.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/ListeningGraph.java @@ -32,12 +32,13 @@ import com.hp.hpl.jena.util.iterator.WrappedIterator; import edu.cornell.mannlib.vitro.webapp.dao.jena.EmptyReifier; import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceImpl; public class ListeningGraph implements GraphWithPerform { private static final Log log = LogFactory.getLog(ListeningGraph.class); - private RDFServiceSDB rdfServiceSDB; + private RDFServiceImpl rdfServiceImpl; private String graphURI; private BulkUpdateHandler bulkUpdateHandler; @@ -46,9 +47,9 @@ public class ListeningGraph implements GraphWithPerform { private Reifier reifier = new EmptyReifier(this); private QueryHandler queryHandler; - public ListeningGraph(String graphURI, RDFServiceSDB rdfServiceSDB) { + public ListeningGraph(String graphURI, RDFServiceImpl rdfServiceImpl) { this.graphURI = graphURI; - this.rdfServiceSDB = rdfServiceSDB; + this.rdfServiceImpl = rdfServiceImpl; } @Override @@ -58,7 +59,10 @@ public class ListeningGraph implements GraphWithPerform { @Override public void performAdd(Triple triple) throws AddDeniedException { - this.rdfServiceSDB.notifyListeners(triple, ModelChange.Operation.ADD, graphURI); + if (log.isDebugEnabled()) { + log.debug("adding " + triple + " to " + graphURI); + } + this.rdfServiceImpl.notifyListeners(triple, ModelChange.Operation.ADD, graphURI); } @Override @@ -68,7 +72,10 @@ public class ListeningGraph implements GraphWithPerform { @Override public void performDelete(Triple triple) throws DeleteDeniedException { - this.rdfServiceSDB.notifyListeners(triple, ModelChange.Operation.REMOVE, graphURI); + if (log.isDebugEnabled()) { + log.debug("deleting " + triple + " from " + graphURI); + } + this.rdfServiceImpl.notifyListeners(triple, ModelChange.Operation.REMOVE, graphURI); } @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceSDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceSDB.java index 1c4487b26..b78649ffc 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceSDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceSDB.java @@ -197,6 +197,11 @@ public class RDFServiceSDB extends RDFServiceImpl implements RDFService { log.debug("removal model size " + model.size()); log.debug("blank node model size " + blankNodeModel.size()); + if (blankNodeModel.size() == 1) { + log.warn("Deleting single triple with blank node: " + blankNodeModel); + log.warn("This likely indicates a problem; excessive data may be deleted."); + } + String rootFinder = "SELECT ?s WHERE { ?s ?p ?o OPTIONAL { ?ss ?pp ?s } FILTER (!bound(?ss)) }"; Query rootFinderQuery = QueryFactory.create(rootFinder); QueryExecution qe = QueryExecutionFactory.create(rootFinderQuery, blankNodeModel); @@ -210,33 +215,37 @@ public class RDFServiceSDB extends RDFServiceImpl implements RDFService { QueryExecution qee = QueryExecutionFactory.create(treeFinderQuery, blankNodeModel); try { Model tree = qee.execDescribe(); - StmtIterator sit = tree.listStatements(s, null, (RDFNode) null); - while (sit.hasNext()) { - Statement stmt = sit.nextStatement(); - RDFNode n = stmt.getObject(); - Model m2 = ModelFactory.createDefaultModel(); - if (n.isResource()) { - Resource s2 = (Resource) n; - // now run yet another describe query - String smallerTree = makeDescribe(s2); - Query smallerTreeQuery = QueryFactory.create(smallerTree); - QueryExecution qe3 = QueryExecutionFactory.create( - smallerTreeQuery, tree); - try { - qe3.execDescribe(m2); - } finally { - qe3.close(); - } - } - m2.add(stmt); - DataSource ds = DatasetFactory.create(); - if (graphURI == null) { - ds.setDefaultModel(dataset.getDefaultModel()); - } else { - ds.addNamedModel(graphURI, dataset.getNamedModel(graphURI)); - } - removeUsingSparqlUpdate(ds, m2, graphURI); - } + DataSource ds = DatasetFactory.create(); + if (graphURI == null) { + ds.setDefaultModel(dataset.getDefaultModel()); + } else { + ds.addNamedModel(graphURI, dataset.getNamedModel(graphURI)); + } + if (s.isAnon()) { + removeUsingSparqlUpdate(ds, tree, graphURI); + } else { + StmtIterator sit = tree.listStatements(s, null, (RDFNode) null); + while (sit.hasNext()) { + Statement stmt = sit.nextStatement(); + RDFNode n = stmt.getObject(); + Model m2 = ModelFactory.createDefaultModel(); + if (n.isResource()) { + Resource s2 = (Resource) n; + // now run yet another describe query + String smallerTree = makeDescribe(s2); + Query smallerTreeQuery = QueryFactory.create(smallerTree); + QueryExecution qe3 = QueryExecutionFactory.create( + smallerTreeQuery, tree); + try { + qe3.execDescribe(m2); + } finally { + qe3.close(); + } + } + m2.add(stmt); + removeUsingSparqlUpdate(ds, m2, graphURI); + } + } } finally { qee.close(); } @@ -279,12 +288,13 @@ public class RDFServiceSDB extends RDFServiceImpl implements RDFService { StringBuffer queryBuff = new StringBuffer(); queryBuff.append("CONSTRUCT { \n"); - queryBuff.append(patternBuff); + addStatementPatterns(stmtIt, queryBuff, !WHERE_CLAUSE); queryBuff.append("} WHERE { \n"); if (graphURI != null) { queryBuff.append(" GRAPH <" + graphURI + "> { \n"); } - queryBuff.append(patternBuff); + stmtIt = model.listStatements(); + addStatementPatterns(stmtIt, queryBuff, !WHERE_CLAUSE); if (graphURI != null) { queryBuff.append(" } \n"); } @@ -314,6 +324,28 @@ public class RDFServiceSDB extends RDFServiceImpl implements RDFService { } } + private static final boolean WHERE_CLAUSE = true; + + private void addStatementPatterns(StmtIterator stmtIt, StringBuffer patternBuff, boolean whereClause) { + while(stmtIt.hasNext()) { + Triple t = stmtIt.next().asTriple(); + patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getSubject(), null)); + patternBuff.append(" "); + patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getPredicate(), null)); + patternBuff.append(" "); + patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getObject(), null)); + patternBuff.append(" .\n"); + if (whereClause) { + if (t.getSubject().isBlank()) { + patternBuff.append(" FILTER(isBlank(" + SparqlGraph.sparqlNodeDelete(t.getSubject(), null)).append(")) \n"); + } + if (t.getObject().isBlank()) { + patternBuff.append(" FILTER(isBlank(" + SparqlGraph.sparqlNodeDelete(t.getObject(), null)).append(")) \n"); + } + } + } + } + private Model parseModel(ModelChange modelChange) { Model model = ModelFactory.createDefaultModel(); model.read(modelChange.getSerializedModel(), null, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java index 8f229443c..ea8a1023e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sparql; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; +import java.io.StringWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -27,13 +28,16 @@ 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.ResultSetFormatter; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; +import edu.cornell.mannlib.vitro.webapp.dao.jena.SparqlGraph; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange; @@ -41,6 +45,7 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.ChangeSetImpl; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceImpl; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sdb.ListeningGraph; /* * API to write, read, and update Vitro's RDF store, with support @@ -98,33 +103,62 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService { * * @return boolean - indicates whether the precondition was satisfied */ - @Override - public boolean changeSetUpdate(ChangeSet changeSet) throws RDFServiceException { - - if (changeSet.getPreconditionQuery() != null + @Override + public boolean changeSetUpdate(ChangeSet changeSet) + throws RDFServiceException { + + if (changeSet.getPreconditionQuery() != null && !isPreconditionSatisfied( changeSet.getPreconditionQuery(), changeSet.getPreconditionQueryType())) { return false; } - - Iterator csIt = changeSet.getModelChanges().iterator(); - - while (csIt.hasNext()) { - - ModelChange modelChange = csIt.next(); - - if (modelChange.getOperation() == ModelChange.Operation.ADD) { - performAdd(modelChange); - } else if (modelChange.getOperation() == ModelChange.Operation.REMOVE) { - performRemove(modelChange); - } else { - log.error("unrecognized operation type"); - } - } - - return true; - } + + try { + for (Object o : changeSet.getPreChangeEvents()) { + this.notifyListenersOfEvent(o); + } + + Iterator csIt = changeSet.getModelChanges().iterator(); + while (csIt.hasNext()) { + ModelChange modelChange = csIt.next(); + modelChange.getSerializedModel().mark(Integer.MAX_VALUE); + performChange(modelChange); + } + + // notify listeners of triple changes + csIt = changeSet.getModelChanges().iterator(); + while (csIt.hasNext()) { + ModelChange modelChange = csIt.next(); + modelChange.getSerializedModel().reset(); + Model model = ModelFactory.createModelForGraph( + new ListeningGraph(modelChange.getGraphURI(), this)); + if (modelChange.getOperation() == ModelChange.Operation.ADD) { + model.read(modelChange.getSerializedModel(), null, + getSerializationFormatString( + modelChange.getSerializationFormat())); + } else if (modelChange.getOperation() == ModelChange.Operation.REMOVE){ + Model temp = ModelFactory.createDefaultModel(); + temp.read(modelChange.getSerializedModel(), null, + getSerializationFormatString( + modelChange.getSerializationFormat())); + model.remove(temp); + } else { + log.error("Unsupported model change type " + + modelChange.getOperation().getClass().getName()); + } + } + + for (Object o : changeSet.getPostChangeEvents()) { + this.notifyListenersOfEvent(o); + } + + } catch (Exception e) { + log.error(e, e); + throw new RDFServiceException(e); + } + return true; + } /** * Performs a SPARQL construct query against the knowledge base. The query may have @@ -368,6 +402,43 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService { } } + public void addModel(Model model, String graphURI) { + verbModel(model, graphURI, "INSERT"); + } + + public void deleteModel(Model model, String graphURI) { + verbModel(model, graphURI, "DELETE"); + } + + private void verbModel(Model model, String graphURI, String verb) { + Model m = ModelFactory.createDefaultModel(); + int testLimit = 1000; + StmtIterator stmtIt = model.listStatements(); + int count = 0; + try { + while (stmtIt.hasNext()) { + count++; + m.add(stmtIt.nextStatement()); + if (count % testLimit == 0 || !stmtIt.hasNext()) { + StringWriter sw = new StringWriter(); + m.write(sw, "N-TRIPLE"); + StringBuffer updateStringBuff = new StringBuffer(); + updateStringBuff.append(verb + " DATA { " + ((graphURI != null) ? "GRAPH <" + graphURI + "> { " : "" )); + updateStringBuff.append(sw); + updateStringBuff.append(((graphURI != null) ? " } " : "") + " }"); + + String updateString = updateStringBuff.toString(); + + executeUpdate(updateString); + + m.removeAll(); + } + } + } finally { + stmtIt.close(); + } + } + protected void addTriple(Triple t, String graphURI) { StringBuffer updateString = new StringBuffer(); @@ -438,32 +509,165 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService { } } - protected void performAdd(ModelChange modelChange) throws RDFServiceException { - - Model model = ModelFactory.createDefaultModel(); - model.read(modelChange.getSerializedModel(),getSerializationFormatString(modelChange.getSerializationFormat())); - - StmtIterator stmtIt = model.listStatements(); - - while (stmtIt.hasNext()) { - Statement stmt = stmtIt.next(); - Triple triple = new Triple(stmt.getSubject().asNode(), stmt.getPredicate().asNode(), stmt.getObject().asNode()); - addTriple(triple, modelChange.getGraphURI()); - } - } - - protected void performRemove(ModelChange modelChange) throws RDFServiceException { - - Model model = ModelFactory.createDefaultModel(); - model.read(modelChange.getSerializedModel(),getSerializationFormatString(modelChange.getSerializationFormat())); - - StmtIterator stmtIt = model.listStatements(); - - while (stmtIt.hasNext()) { - Statement stmt = stmtIt.next(); - Triple triple = new Triple(stmt.getSubject().asNode(), stmt.getPredicate().asNode(), stmt.getObject().asNode()); - removeTriple(triple, modelChange.getGraphURI()); - } - } + private void performChange(ModelChange modelChange) { + Model model = parseModel(modelChange); + if (modelChange.getOperation() == ModelChange.Operation.ADD) { + addModel(model, modelChange.getGraphURI()); + } else if (modelChange.getOperation() == ModelChange.Operation.REMOVE) { + deleteModel(model, modelChange.getGraphURI()); + removeBlankNodesWithSparqlUpdate(model, modelChange.getGraphURI()); + } else { + log.error("unrecognized operation type"); + } + } + + private void removeBlankNodesWithSparqlUpdate(Model model, String graphURI) { + List blankNodeStatements = new ArrayList(); + StmtIterator stmtIt = model.listStatements(); + while (stmtIt.hasNext()) { + Statement stmt = stmtIt.nextStatement(); + if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) { + blankNodeStatements.add(stmt); + } + } + + if(blankNodeStatements.size() == 0) { + return; + } + + Model blankNodeModel = ModelFactory.createDefaultModel(); + blankNodeModel.add(blankNodeStatements); + + log.debug("removal model size " + model.size()); + log.debug("blank node model size " + blankNodeModel.size()); + + if (blankNodeModel.size() == 1) { + log.warn("Deleting single triple with blank node: " + blankNodeModel); + log.warn("This likely indicates a problem; excessive data may be deleted."); + } + + String rootFinder = "SELECT ?s WHERE { ?s ?p ?o OPTIONAL { ?ss ?pp ?s } FILTER (!bound(?ss)) }"; + Query rootFinderQuery = QueryFactory.create(rootFinder); + QueryExecution qe = QueryExecutionFactory.create(rootFinderQuery, blankNodeModel); + try { + ResultSet rs = qe.execSelect(); + while (rs.hasNext()) { + QuerySolution qs = rs.next(); + com.hp.hpl.jena.rdf.model.Resource s = qs.getResource("s"); + String treeFinder = makeDescribe(s); + Query treeFinderQuery = QueryFactory.create(treeFinder); + QueryExecution qee = QueryExecutionFactory.create(treeFinderQuery, blankNodeModel); + try { + Model tree = qee.execDescribe(); + if (s.isAnon()) { + removeUsingSparqlUpdate(tree, graphURI); + } else { + StmtIterator sit = tree.listStatements(s, null, (RDFNode) null); + while (sit.hasNext()) { + Statement stmt = sit.nextStatement(); + RDFNode n = stmt.getObject(); + Model m2 = ModelFactory.createDefaultModel(); + if (n.isResource()) { + com.hp.hpl.jena.rdf.model.Resource s2 = + (com.hp.hpl.jena.rdf.model.Resource) n; + // now run yet another describe query + String smallerTree = makeDescribe(s2); + Query smallerTreeQuery = QueryFactory.create(smallerTree); + QueryExecution qe3 = QueryExecutionFactory.create( + smallerTreeQuery, tree); + try { + qe3.execDescribe(m2); + } finally { + qe3.close(); + } + } + m2.add(stmt); + removeUsingSparqlUpdate(m2, graphURI); + } + } + } finally { + qee.close(); + } + } + } finally { + qe.close(); + } + } + + private void removeUsingSparqlUpdate(Model model, String graphURI) { + + + StmtIterator stmtIt = model.listStatements(); + + if (!stmtIt.hasNext()) { + stmtIt.close(); + return; + } + + StringBuffer queryBuff = new StringBuffer(); + queryBuff.append("DELETE { \n"); + if (graphURI != null) { + queryBuff.append(" GRAPH <" + graphURI + "> { \n"); + } + addStatementPatterns(stmtIt, queryBuff, !WHERE_CLAUSE); + if (graphURI != null) { + queryBuff.append(" } \n"); + } + queryBuff.append("} WHERE { \n"); + if (graphURI != null) { + queryBuff.append(" GRAPH <" + graphURI + "> { \n"); + } + stmtIt = model.listStatements(); + addStatementPatterns(stmtIt, queryBuff, WHERE_CLAUSE); + if (graphURI != null) { + queryBuff.append(" } \n"); + } + queryBuff.append("} \n"); + + if(log.isDebugEnabled()) { + log.debug(queryBuff.toString()); + } + executeUpdate(queryBuff.toString()); + } + + private static final boolean WHERE_CLAUSE = true; + + private void addStatementPatterns(StmtIterator stmtIt, StringBuffer patternBuff, boolean whereClause) { + while(stmtIt.hasNext()) { + Triple t = stmtIt.next().asTriple(); + patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getSubject(), null)); + patternBuff.append(" "); + patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getPredicate(), null)); + patternBuff.append(" "); + patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getObject(), null)); + patternBuff.append(" .\n"); + if (whereClause) { + if (t.getSubject().isBlank()) { + patternBuff.append(" FILTER(isBlank(" + SparqlGraph.sparqlNodeDelete(t.getSubject(), null)).append(")) \n"); + } + if (t.getObject().isBlank()) { + patternBuff.append(" FILTER(isBlank(" + SparqlGraph.sparqlNodeDelete(t.getObject(), null)).append(")) \n"); + } + } + } + } + + private String makeDescribe(com.hp.hpl.jena.rdf.model.Resource s) { + StringBuffer query = new StringBuffer("DESCRIBE <") ; + if (s.isAnon()) { + query.append("_:" + s.getId().toString()); + } else { + query.append(s.getURI()); + } + query.append(">"); + return query.toString(); + } + + private Model parseModel(ModelChange modelChange) { + Model model = ModelFactory.createDefaultModel(); + model.read(modelChange.getSerializedModel(), null, + getSerializationFormatString(modelChange.getSerializationFormat())); + return model; + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFServiceSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFServiceSetup.java index 63a0f3a18..6e34dbd03 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFServiceSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFServiceSetup.java @@ -22,6 +22,7 @@ import com.hp.hpl.jena.sdb.util.StoreUtils; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory; +import edu.cornell.mannlib.vitro.webapp.rdfservice.filter.SameAsFilteringRDFServiceFactory; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceFactorySingle; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sdb.RDFServiceSDB; @@ -49,6 +50,11 @@ implements javax.servlet.ServletContextListener { } else { useSDB(ctx, ss); } + + //experimental + //RDFServiceFactory factory = RDFServiceUtils.getRDFServiceFactory(ctx); + //RDFServiceUtils.setRDFServiceFactory(ctx, new SameAsFilteringRDFServiceFactory(factory)); + } catch (SQLException e) { ss.fatal(this, "Exception in RDFServiceSetup", e); } @@ -57,7 +63,8 @@ implements javax.servlet.ServletContextListener { private void useEndpoint(String endpointURI, ServletContext ctx) { RDFService rdfService = new RDFServiceSparql(endpointURI); RDFServiceFactory rdfServiceFactory = new RDFServiceFactorySingle(rdfService); - RDFServiceUtils.setRDFServiceFactory(ctx, rdfServiceFactory); + RDFServiceUtils.setRDFServiceFactory(ctx, rdfServiceFactory); + log.info("Using endpoint at " + endpointURI); } private void useSDB(ServletContext ctx, StartupStatus ss) throws SQLException {