VIVO-778 Accumulate the TBox changes in a change set object.

This commit is contained in:
Jim Blake 2014-12-03 10:18:03 -05:00
parent 370df0b7ec
commit 6bb8987d9d
4 changed files with 127 additions and 129 deletions

View file

@ -2,8 +2,11 @@
package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet; package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
@ -32,6 +35,7 @@ import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener.Suspension; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener.Suspension;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxChanges;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
public class PelletListener implements TBoxReasonerDriver { public class PelletListener implements TBoxReasonerDriver {
@ -52,12 +56,6 @@ public class PelletListener implements TBoxReasonerDriver {
private final ConfiguredReasonerListener listener; private final ConfiguredReasonerListener listener;
private Model additionModel;
private Model removalModel;
private Model deletedObjectProperties;
private Model deletedDataProperties;
private boolean isConsistent = true; private boolean isConsistent = true;
private boolean inErrorState = false; private boolean inErrorState = false;
private String explanation = ""; private String explanation = "";
@ -99,6 +97,8 @@ public class PelletListener implements TBoxReasonerDriver {
this.dirty = dirt; this.dirty = dirt;
} }
private final List<TBoxChanges> pendingChangeSets = Collections.synchronizedList(new ArrayList<TBoxChanges>());
private int inferenceRounds = 0; private int inferenceRounds = 0;
private boolean foreground = false; private boolean foreground = false;
@ -127,11 +127,6 @@ public class PelletListener implements TBoxReasonerDriver {
this.inferenceDrivingPatternDenySet = reasonerConfiguration.getInferenceDrivingPatternDenySet(); this.inferenceDrivingPatternDenySet = reasonerConfiguration.getInferenceDrivingPatternDenySet();
this.inferenceReceivingPatternAllowSet = reasonerConfiguration.getInferenceReceivingPatternAllowSet(); this.inferenceReceivingPatternAllowSet = reasonerConfiguration.getInferenceReceivingPatternAllowSet();
this.additionModel = ModelFactory.createDefaultModel();
this.removalModel = ModelFactory.createDefaultModel();
this.deletedObjectProperties = ModelFactory.createDefaultModel();
this.deletedDataProperties = ModelFactory.createDefaultModel();
listener = new ConfiguredReasonerListener(reasonerConfiguration, this); listener = new ConfiguredReasonerListener(reasonerConfiguration, this);
this.mainModel.enterCriticalSection(Lock.READ); this.mainModel.enterCriticalSection(Lock.READ);
@ -156,48 +151,9 @@ public class PelletListener implements TBoxReasonerDriver {
} }
@Override @Override
public void addStatement(Statement stmt) { public void runSynchronizer(TBoxChanges changeSet) {
additionModel.enterCriticalSection(Lock.WRITE); if (!changeSet.isEmpty()) {
try { pendingChangeSets.add(changeSet);
additionModel.add(stmt);
} finally {
additionModel.leaveCriticalSection();
}
}
@Override
public void removeStatement(Statement stmt) {
removalModel.enterCriticalSection(Lock.WRITE);
try {
removalModel.add(stmt);
} finally {
removalModel.leaveCriticalSection();
}
}
@Override
public void deleteDataProperty(Statement stmt) {
deletedDataProperties.enterCriticalSection(Lock.WRITE);
try {
deletedDataProperties.add(stmt);
} finally {
deletedDataProperties.leaveCriticalSection();
}
}
@Override
public void deleteObjectProperty(Statement stmt) {
deletedObjectProperties.enterCriticalSection(Lock.WRITE);
try {
deletedObjectProperties.add(stmt);
} finally {
deletedObjectProperties.leaveCriticalSection();
}
}
@Override
public void runSynchronizer() {
if ((additionModel.size() > 0) || (removalModel.size() > 0)) {
if (!isSynchronizing) { if (!isSynchronizing) {
if (foreground) { if (foreground) {
log.debug("Running Pellet in foreground."); log.debug("Running Pellet in foreground.");
@ -214,9 +170,11 @@ public class PelletListener implements TBoxReasonerDriver {
private class InferenceGetter implements Runnable { private class InferenceGetter implements Runnable {
private PelletListener pelletListener; private PelletListener pelletListener;
private TBoxChanges changeSet;
public InferenceGetter(PelletListener pelletListener) { public InferenceGetter(PelletListener pelletListener, TBoxChanges changeSet) {
this.pelletListener = pelletListener; this.pelletListener = pelletListener;
this.changeSet = changeSet;
} }
public void run() { public void run() {
@ -252,20 +210,8 @@ public class PelletListener implements TBoxReasonerDriver {
} finally { } finally {
pelletModel.leaveCriticalSection(); pelletModel.leaveCriticalSection();
} }
deletedObjectProperties.enterCriticalSection(Lock.WRITE); for (String uri: changeSet.getDeletedObjectPropertyUris()) {
try { irpl.add(ReasonerStatementPattern.objectPattern(ResourceFactory.createProperty(uri)));
ClosableIterator sit = deletedObjectProperties.listSubjects();
try {
while (sit.hasNext()) {
Resource subj = (Resource) sit.next();
irpl.add(ReasonerStatementPattern.objectPattern(ResourceFactory.createProperty(subj.getURI())));
}
} finally {
sit.close();
}
deletedObjectProperties.removeAll();
} finally {
deletedObjectProperties.leaveCriticalSection();
} }
} }
@ -287,20 +233,8 @@ public class PelletListener implements TBoxReasonerDriver {
} finally { } finally {
pelletModel.leaveCriticalSection(); pelletModel.leaveCriticalSection();
} }
deletedDataProperties.enterCriticalSection(Lock.WRITE); for (String uri: changeSet.getDeletedDataPropertyUris()) {
try { irpl.add(ReasonerStatementPattern.objectPattern(ResourceFactory.createProperty(uri)));
ClosableIterator sit = deletedDataProperties.listSubjects();
try {
while (sit.hasNext()) {
Resource subj = (Resource) sit.next();
irpl.add(ReasonerStatementPattern.objectPattern(ResourceFactory.createProperty(subj.getURI())));
}
} finally {
sit.close();
}
deletedDataProperties.removeAll();
} finally {
deletedDataProperties.leaveCriticalSection();
} }
} }
@ -424,13 +358,13 @@ public class PelletListener implements TBoxReasonerDriver {
} }
private void getInferences() { private void getInferences(TBoxChanges changeSet) {
this.setDirty(true); this.setDirty(true);
if ( this.checkAndStartReasoning() ){ if ( this.checkAndStartReasoning() ){
if (foreground) { if (foreground) {
(new InferenceGetter(this)).run(); (new InferenceGetter(this, changeSet)).run();
} else { } else {
new Thread(new InferenceGetter(this), "PelletListener.InferenceGetter").start(); new Thread(new InferenceGetter(this, changeSet), "PelletListener.InferenceGetter").start();
} }
} }
} }
@ -439,38 +373,18 @@ public class PelletListener implements TBoxReasonerDriver {
public void run() { public void run() {
try { try {
isSynchronizing = true; isSynchronizing = true;
while (removalModel.size()>0 || additionModel.size()>0) { while (!pendingChangeSets.isEmpty()) {
Model tempModel = ModelFactory.createDefaultModel(); TBoxChanges changeSet = pendingChangeSets.remove(0);
removalModel.enterCriticalSection(Lock.WRITE);
try {
tempModel.add(removalModel);
removalModel.removeAll();
} finally {
removalModel.leaveCriticalSection();
}
pelletModel.enterCriticalSection(Lock.WRITE);
try {
pelletModel.remove(tempModel);
} finally {
pelletModel.leaveCriticalSection();
}
tempModel.removeAll();
additionModel.enterCriticalSection(Lock.WRITE);
try {
tempModel.add(additionModel);
additionModel.removeAll();
} finally {
additionModel.leaveCriticalSection();
}
pelletModel.enterCriticalSection(Lock.WRITE);
try {
pelletModel.add(tempModel);
} finally {
pelletModel.leaveCriticalSection();
}
tempModel = null;
getInferences(); pelletModel.enterCriticalSection(Lock.WRITE);
try {
pelletModel.remove(changeSet.getRemovedStatements());
pelletModel.add(changeSet.getAddedStatements());
} finally {
pelletModel.leaveCriticalSection();
}
getInferences(changeSet);
} }
} finally { } finally {

View file

@ -7,6 +7,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -23,8 +24,11 @@ import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent;
/** /**
* Listens for changes on a model. When a change is announced, it is passed * Listens for changes on a model. When a change is announced, it is checked for
* along to the reasoner driver, if the configuration says that it is worthy. * worthiness. If worthy, it is added to a change set.
*
* When an ending EditEvent is received, the current change set is passed along
* to the reasoner driver, and a new change set is begun.
* *
* It is possible to "suspend" the listener, so it will ignore any changes. This * It is possible to "suspend" the listener, so it will ignore any changes. This
* is useful when the reasoner itself makes changes to the models, so those * is useful when the reasoner itself makes changes to the models, so those
@ -36,9 +40,11 @@ public class ConfiguredReasonerListener implements ModelChangedListener {
private final ReasonerConfiguration reasonerConfiguration; private final ReasonerConfiguration reasonerConfiguration;
private final TBoxReasonerDriver reasonerDriver; private final TBoxReasonerDriver reasonerDriver;
private final DrivingPatternMap drivingPatternMap; private final DrivingPatternMap drivingPatternMap;
private final AtomicBoolean suspended = new AtomicBoolean(); private final AtomicReference<TBoxChanges> changeSet;
private final AtomicBoolean suspended;
public ConfiguredReasonerListener( public ConfiguredReasonerListener(
ReasonerConfiguration reasonerConfiguration, ReasonerConfiguration reasonerConfiguration,
@ -48,6 +54,9 @@ public class ConfiguredReasonerListener implements ModelChangedListener {
this.drivingPatternMap = new DrivingPatternMap( this.drivingPatternMap = new DrivingPatternMap(
reasonerConfiguration.getInferenceDrivingPatternAllowSet()); reasonerConfiguration.getInferenceDrivingPatternAllowSet());
this.changeSet = new AtomicReference<>(new TBoxChanges());
this.suspended = new AtomicBoolean();
} }
public Suspension suspend() { public Suspension suspend() {
@ -162,7 +171,8 @@ public class ConfiguredReasonerListener implements ModelChangedListener {
if (event instanceof EditEvent) { if (event instanceof EditEvent) {
EditEvent ee = (EditEvent) event; EditEvent ee = (EditEvent) event;
if (!ee.getBegin()) { if (!ee.getBegin()) {
this.reasonerDriver.runSynchronizer(); TBoxChanges changes = changeSet.getAndSet(new TBoxChanges());
this.reasonerDriver.runSynchronizer(changes);
} }
} }
} }
@ -305,19 +315,19 @@ public class ConfiguredReasonerListener implements ModelChangedListener {
} }
private void addIt(Statement stmt) { private void addIt(Statement stmt) {
this.reasonerDriver.addStatement(stmt); changeSet.get().addStatement(stmt);
} }
private void removeIt(Statement stmt) { private void removeIt(Statement stmt) {
this.reasonerDriver.removeStatement(stmt); changeSet.get().removeStatement(stmt);
} }
private void deleteObjectProperty(Statement stmt) { private void deleteObjectProperty(Statement stmt) {
this.reasonerDriver.deleteObjectProperty(stmt); changeSet.get().deleteObjectProperty(stmt);
} }
private void deleteDataProperty(Statement stmt) { private void deleteDataProperty(Statement stmt) {
this.reasonerDriver.deleteDataProperty(stmt); changeSet.get().deleteDataProperty(stmt);
} }
// The pattern matching stuff needs to get reworked. // The pattern matching stuff needs to get reworked.

View file

@ -0,0 +1,83 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.tboxreasoner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
/**
* Accumulate changes to the TBox as they arrive. Then make them available to
* the TBox reasoner.
*/
public class TBoxChanges {
private final List<Statement> addedStatements = Collections
.synchronizedList(new ArrayList<Statement>());
private final List<Statement> removedStatements = Collections
.synchronizedList(new ArrayList<Statement>());
private final List<String> deletedDataPropertyUris = Collections
.synchronizedList(new ArrayList<String>());
private final List<String> deletedObjectPropertyUris = Collections
.synchronizedList(new ArrayList<String>());
// ----------------------------------------------------------------------
// These methods are called when populating the changeSet. They must be
// thread-safe.
// ----------------------------------------------------------------------
public void addStatement(Statement stmt) {
addedStatements.add(stmt);
}
public void removeStatement(Statement stmt) {
removedStatements.remove(stmt);
}
public void deleteDataProperty(Statement stmt) {
Resource subject = stmt.getSubject();
if (subject.isURIResource()) {
deletedDataPropertyUris.add(subject.getURI());
}
}
public void deleteObjectProperty(Statement stmt) {
Resource subject = stmt.getSubject();
if (subject.isURIResource()) {
deletedObjectPropertyUris.add(subject.getURI());
}
}
// ----------------------------------------------------------------------
// These methods are called when processing the changeSet. By that time, it
// is owned and accessed by a single thread.
// ----------------------------------------------------------------------
public boolean isEmpty() {
return addedStatements.isEmpty() && removedStatements.isEmpty()
&& deletedDataPropertyUris.isEmpty()
&& deletedObjectPropertyUris.isEmpty();
}
public List<Statement> getAddedStatements() {
return addedStatements;
}
public List<Statement> getRemovedStatements() {
return removedStatements;
}
public List<String> getDeletedDataPropertyUris() {
return deletedDataPropertyUris;
}
public List<String> getDeletedObjectPropertyUris() {
return deletedObjectPropertyUris;
}
}

View file

@ -2,20 +2,11 @@
package edu.cornell.mannlib.vitro.webapp.tboxreasoner; package edu.cornell.mannlib.vitro.webapp.tboxreasoner;
import com.hp.hpl.jena.rdf.model.Statement;
/** /**
* What calls can the ConfiguredReasonerListener make to drive the TBox reasoner? * What calls can the ConfiguredReasonerListener make to drive the TBox reasoner?
*/ */
public interface TBoxReasonerDriver { public interface TBoxReasonerDriver {
void runSynchronizer(); void runSynchronizer(TBoxChanges changeSet);
void addStatement(Statement stmt);
void removeStatement(Statement stmt);
void deleteDataProperty(Statement stmt);
void deleteObjectProperty(Statement stmt);
} }