From f55916b8d8ce90ada1dcb4240a917c9bcb597618 Mon Sep 17 00:00:00 2001 From: brianjlowe Date: Mon, 11 Jun 2012 21:03:16 +0000 Subject: [PATCH] event notification for RDF API and change to model setup for SimpleReasoner --- .../webapp/dao/jena/DifferenceGraph.java | 136 ++++++++++++++++++ .../webapp/dao/jena/IndividualDaoJena.java | 3 +- .../webapp/dao/jena/JenaChangeListener.java | 1 + .../webapp/dao/jena/RDFServiceDataset.java | 4 +- .../dao/jena/RDFServiceDatasetGraph.java | 4 +- .../webapp/dao/jena/RDFServiceGraph.java | 21 +++ .../vitro/webapp/rdfservice/ChangeSet.java | 30 ++++ .../webapp/rdfservice/impl/ChangeSetImpl.java | 27 +++- .../rdfservice/impl/RDFServiceImpl.java | 11 ++ .../rdfservice/impl/sdb/RDFServiceSDB.java | 8 ++ .../vitro/webapp/reasoner/SimpleReasoner.java | 12 +- .../webapp/servlet/setup/RDFServiceSetup.java | 2 +- 12 files changed, 245 insertions(+), 14 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DifferenceGraph.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DifferenceGraph.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DifferenceGraph.java new file mode 100644 index 000000000..1eb6cd0b3 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DifferenceGraph.java @@ -0,0 +1,136 @@ +package edu.cornell.mannlib.vitro.webapp.dao.jena; + +import java.util.Set; + +import com.hp.hpl.jena.graph.BulkUpdateHandler; +import com.hp.hpl.jena.graph.Capabilities; +import com.hp.hpl.jena.graph.Graph; +import com.hp.hpl.jena.graph.GraphEventManager; +import com.hp.hpl.jena.graph.GraphStatisticsHandler; +import com.hp.hpl.jena.graph.Node; +import com.hp.hpl.jena.graph.Reifier; +import com.hp.hpl.jena.graph.TransactionHandler; +import com.hp.hpl.jena.graph.Triple; +import com.hp.hpl.jena.graph.TripleMatch; +import com.hp.hpl.jena.graph.query.QueryHandler; +import com.hp.hpl.jena.shared.AddDeniedException; +import com.hp.hpl.jena.shared.DeleteDeniedException; +import com.hp.hpl.jena.shared.PrefixMapping; +import com.hp.hpl.jena.util.iterator.ExtendedIterator; +import com.hp.hpl.jena.util.iterator.WrappedIterator; + +public class DifferenceGraph implements Graph { + + private Graph g; + private Graph subtract; + + public DifferenceGraph(Graph g, Graph subtract) { + this.g = g; + this.subtract = subtract; + } + + @Override + public void close() { + // not clear what the best behavior here is + } + + @Override + public boolean contains(Triple arg0) { + return g.contains(arg0) && !subtract.contains(arg0); + } + + @Override + public boolean contains(Node arg0, Node arg1, Node arg2) { + return g.contains(arg0, arg1, arg2) && !subtract.contains(arg0, arg1, arg2); + } + + @Override + public void delete(Triple arg0) throws DeleteDeniedException { + g.delete(arg0); + } + + @Override + public boolean dependsOn(Graph arg0) { + return g.dependsOn(arg0); + } + + @Override + public ExtendedIterator find(TripleMatch arg0) { + Set tripSet = g.find(arg0).toSet(); + tripSet.removeAll(subtract.find(arg0).toSet()); + return WrappedIterator.create(tripSet.iterator()); + } + + @Override + public ExtendedIterator find(Node arg0, Node arg1, Node arg2) { + Set tripSet = g.find(arg0, arg1, arg2).toSet(); + tripSet.removeAll(subtract.find(arg0, arg1, arg2).toSet()); + return WrappedIterator.create(tripSet.iterator()); + } + + @Override + public BulkUpdateHandler getBulkUpdateHandler() { + return g.getBulkUpdateHandler(); + } + + @Override + public Capabilities getCapabilities() { + return g.getCapabilities(); + } + + @Override + public GraphEventManager getEventManager() { + return g.getEventManager(); + } + + @Override + public PrefixMapping getPrefixMapping() { + return g.getPrefixMapping(); + } + + @Override + public Reifier getReifier() { + return g.getReifier(); + } + + @Override + public GraphStatisticsHandler getStatisticsHandler() { + return g.getStatisticsHandler(); + } + + @Override + public TransactionHandler getTransactionHandler() { + return g.getTransactionHandler(); + } + + @Override + public boolean isClosed() { + return g.isClosed(); + } + + @Override + public boolean isEmpty() { + return g.isEmpty(); + } + + @Override + public boolean isIsomorphicWith(Graph arg0) { + return g.isIsomorphicWith(arg0); + } + + @Override + public QueryHandler queryHandler() { + return g.queryHandler(); + } + + @Override + public int size() { + return g.size() - subtract.size(); + } + + @Override + public void add(Triple arg0) throws AddDeniedException { + g.add(arg0); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualDaoJena.java index abb572095..c51db6f96 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/IndividualDaoJena.java @@ -109,7 +109,8 @@ public class IndividualDaoJena extends JenaBaseDao implements IndividualDao { public void removeVClass(String individualURI, String vclassURI) { OntModel ontModel = getOntModelSelector().getABoxModel(); ontModel.enterCriticalSection(Lock.WRITE); - ontModel.getBaseModel().notifyEvent(new IndividualUpdateEvent(getWebappDaoFactory().getUserURI(),true,individualURI)); + Object event = new IndividualUpdateEvent(getWebappDaoFactory().getUserURI(),true,individualURI); + ontModel.getBaseModel().notifyEvent(event); try { Resource indRes = ontModel.getResource(individualURI); getOntModel().remove(indRes, RDF.type, ontModel.getResource(vclassURI)); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaChangeListener.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaChangeListener.java index ee8cf9fbb..0a4a69ac1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaChangeListener.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaChangeListener.java @@ -42,6 +42,7 @@ public class JenaChangeListener implements ChangeListener { @Override public void notifyEvent(String graphURI, Object event) { + log.debug("event: " + event.getClass()); listener.notifyEvent(m, event); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDataset.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDataset.java index 7b71af018..2564a7822 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDataset.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDataset.java @@ -41,7 +41,7 @@ public class RDFServiceDataset implements Dataset { @Override public Model getDefaultModel() { - return ModelFactory.createModelForGraph(g.getDefaultGraph()); + return RDFServiceGraph.createRDFServiceModel(g.getDefaultGraph()); } @Override @@ -51,7 +51,7 @@ public class RDFServiceDataset implements Dataset { @Override public Model getNamedModel(String arg0) { - return ModelFactory.createModelForGraph(g.getGraph(Node.createURI(arg0))); + return RDFServiceGraph.createRDFServiceModel(g.getGraph(Node.createURI(arg0))); } @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDatasetGraph.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDatasetGraph.java index 9a7965777..49c68b934 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDatasetGraph.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDatasetGraph.java @@ -161,12 +161,12 @@ public class RDFServiceDatasetGraph implements DatasetGraph { } @Override - public Graph getDefaultGraph() { + public RDFServiceGraph getDefaultGraph() { return new RDFServiceGraph(rdfService); } @Override - public Graph getGraph(Node arg0) { + public RDFServiceGraph getGraph(Node arg0) { return new RDFServiceGraph(rdfService, arg0.getURI()); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java index 4b2afdd89..106da87e7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java @@ -24,6 +24,9 @@ import com.hp.hpl.jena.graph.query.QueryHandler; import com.hp.hpl.jena.graph.query.SimpleQueryHandler; import com.hp.hpl.jena.query.QuerySolution; import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.rdf.listeners.StatementListener; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.shared.AddDeniedException; import com.hp.hpl.jena.shared.DeleteDeniedException; import com.hp.hpl.jena.shared.PrefixMapping; @@ -434,4 +437,22 @@ public class RDFServiceGraph implements GraphWithPerform { } } + public static Model createRDFServiceModel(final RDFServiceGraph g) { + Model m = ModelFactory.createModelForGraph(g); + m.register(new StatementListener() { + @Override + public void notifyEvent(Model m, Object event) { + ChangeSet changeSet = g.getRDFService().manufactureChangeSet(); + changeSet.addPreChangeEvent(event); + try { + g.getRDFService().changeSetUpdate(changeSet); + } catch (RDFServiceException e) { + throw new RuntimeException(e); + } + } + + }); + return m; + } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/ChangeSet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/ChangeSet.java index 9ec46b7b5..f2ff916b6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/ChangeSet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/ChangeSet.java @@ -86,4 +86,34 @@ public interface ChangeSet { RDFService.ModelSerializationFormat serializationFormat, ModelChange.Operation operation, String graphURI); + + /** + * Add an event that will be be passed to any change listeners in advance of + * the change set additions and retractions being performed. The event + * will only be fired if the precondition (if any) is met. + * @param event + */ + public void addPreChangeEvent(Object event); + + /** + * Add an event that will be be passed to any change listeners after all of + * the change set additions and retractions are performed. + * @param event + */ + public void addPostChangeEvent(Object event); + + /** + * Return a list of events to pass to any change listeners in + * advance of the change set additions and retractions being performed. + * @return + */ + public List getPreChangeEvents(); + + /** + * Return a list of events to pass to any change listeners after + * the change set additions and retractions are performed. + * @return + */ + public List getPostChangeEvents(); + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/ChangeSetImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/ChangeSetImpl.java index 52f92ab75..0f79ede1a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/ChangeSetImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/ChangeSetImpl.java @@ -23,8 +23,10 @@ public class ChangeSetImpl implements ChangeSet { private String preconditionQuery; private RDFService.SPARQLQueryType queryType; - private ArrayList modelChanges; - + private ArrayList modelChanges = new ArrayList(); + private ArrayList preChangeEvents = new ArrayList(); + private ArrayList postChangeEvents = new ArrayList(); + /** * Getter for the precondition query * @@ -122,4 +124,25 @@ public class ChangeSetImpl implements ChangeSet { String graphURI) { return new ModelChangeImpl(serializedModel, serializationFormat, operation, graphURI); } + + @Override + public void addPreChangeEvent(Object o) { + this.preChangeEvents.add(o); + } + + @Override + public void addPostChangeEvent(Object o) { + this.postChangeEvents.add(o); + } + + @Override + public List getPreChangeEvents() { + return this.preChangeEvents; + } + + @Override + public List getPostChangeEvents() { + return this.postChangeEvents; + } + } 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 ea253a21e..e1b4885f0 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 @@ -143,6 +143,17 @@ public abstract class RDFServiceImpl implements RDFService { listener.removedStatement(sparqlTriple(triple).toString(), graphURI); } } + } + + public synchronized void notifyListenersOfEvent(Object event) { + + Iterator iter = registeredListeners.iterator(); + + while (iter.hasNext()) { + ChangeListener listener = iter.next(); + // TODO what is the graphURI parameter for? + listener.notifyEvent(null, event); + } } protected boolean isPreconditionSatisfied(String query, 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 64c3b17de..ea49d5982 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 @@ -124,9 +124,15 @@ public class RDFServiceSDB extends RDFServiceImpl implements RDFService { dataset.getLock().leaveCriticalSection(); } } + for (Object o : changeSet.getPreChangeEvents()) { + this.notifyListenersOfEvent(o); + } if (transaction) { conn.getTransactionHandler().commit(); } + for (Object o : changeSet.getPostChangeEvents()) { + this.notifyListenersOfEvent(o); + } } catch (Exception e) { log.error(e, e); if (transaction) { @@ -404,10 +410,12 @@ public class RDFServiceSDB extends RDFServiceImpl implements RDFService { } public void addedStatement(Statement stmt) { + log.debug("adding " + stmt + " to " + graphURI); s.notifyListeners(stmt.asTriple(), ModelChange.Operation.ADD, graphURI); } public void removedStatement(Statement stmt) { + log.debug("removing " + stmt + " from " + graphURI); s.notifyListeners(stmt.asTriple(), ModelChange.Operation.REMOVE, graphURI); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java index f55467e9b..272e8c0bd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java @@ -41,6 +41,7 @@ import com.hp.hpl.jena.vocabulary.RDFS; import edu.cornell.mannlib.vitro.webapp.dao.jena.ABoxJenaChangeListener; import edu.cornell.mannlib.vitro.webapp.dao.jena.CumulativeDeltaModeler; +import edu.cornell.mannlib.vitro.webapp.dao.jena.DifferenceGraph; import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceGraph; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.BulkUpdateEvent; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; @@ -89,7 +90,7 @@ public class SimpleReasoner extends StatementListener { this.tboxModel = tboxModel; this.aboxModel = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM, ModelFactory.createModelForGraph( - new RDFServiceGraph(rdfService))); + new DifferenceGraph(new RDFServiceGraph(rdfService), inferenceModel.getGraph()))); this.inferenceModel = inferenceModel; this.inferenceRebuildModel = inferenceRebuildModel; this.scratchpadModel = scratchpadModel; @@ -187,8 +188,7 @@ public class SimpleReasoner extends StatementListener { * Synchronized part of removedStatement. Interacts * with DeltaComputer. */ - protected synchronized void handleRemovedStatement(Statement stmt) { - + protected synchronized void handleRemovedStatement(Statement stmt) { if (batchMode1) { aBoxDeltaModeler1.removedStatement(stmt); } else if (batchMode2) { @@ -753,7 +753,7 @@ public class SimpleReasoner extends StatementListener { Iterator parentIt = parents.iterator(); while (parentIt.hasNext()) { - OntClass parentClass = parentIt.next(); + OntClass parentClass = parentIt.next(); // VIVO doesn't materialize statements that assert anonymous types // for individuals. Also, sharing an identical anonymous node is @@ -770,7 +770,7 @@ public class SimpleReasoner extends StatementListener { inferenceModel.enterCriticalSection(Lock.WRITE); try { if (inferenceModel.contains(infStmt)) { - inferenceModel.remove(infStmt); + inferenceModel.remove(infStmt); } } finally { inferenceModel.leaveCriticalSection(); @@ -1745,7 +1745,7 @@ public class SimpleReasoner extends StatementListener { @Override public synchronized void notifyEvent(Model model, Object event) { - + if (event instanceof BulkUpdateEvent) { if (((BulkUpdateEvent) event).getBegin()) { 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 53c5e4f2d..77bf91578 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 @@ -135,7 +135,7 @@ public class RDFServiceSetup extends JenaDataSourceSetupBase RDFServiceFactory rdfServiceFactory = new RDFServiceFactorySingle(rdfService); RDFServiceUtils.setRDFServiceFactory(ctx, rdfServiceFactory); - Graph g = new RDFServiceGraph(rdfService); +// Graph g = new RDFServiceGraph(rdfService); Dataset dataset = new RDFServiceDataset(rdfService); setStartupDataset(dataset, ctx);