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

View file

@ -7,6 +7,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.logging.Log;
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;
/**
* Listens for changes on a model. When a change is announced, it is passed
* along to the reasoner driver, if the configuration says that it is worthy.
* Listens for changes on a model. When a change is announced, it is checked for
* 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
* 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 TBoxReasonerDriver reasonerDriver;
private final DrivingPatternMap drivingPatternMap;
private final AtomicBoolean suspended = new AtomicBoolean();
private final AtomicReference<TBoxChanges> changeSet;
private final AtomicBoolean suspended;
public ConfiguredReasonerListener(
ReasonerConfiguration reasonerConfiguration,
@ -48,6 +54,9 @@ public class ConfiguredReasonerListener implements ModelChangedListener {
this.drivingPatternMap = new DrivingPatternMap(
reasonerConfiguration.getInferenceDrivingPatternAllowSet());
this.changeSet = new AtomicReference<>(new TBoxChanges());
this.suspended = new AtomicBoolean();
}
public Suspension suspend() {
@ -162,7 +171,8 @@ public class ConfiguredReasonerListener implements ModelChangedListener {
if (event instanceof EditEvent) {
EditEvent ee = (EditEvent) event;
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) {
this.reasonerDriver.addStatement(stmt);
changeSet.get().addStatement(stmt);
}
private void removeIt(Statement stmt) {
this.reasonerDriver.removeStatement(stmt);
changeSet.get().removeStatement(stmt);
}
private void deleteObjectProperty(Statement stmt) {
this.reasonerDriver.deleteObjectProperty(stmt);
changeSet.get().deleteObjectProperty(stmt);
}
private void deleteDataProperty(Statement stmt) {
this.reasonerDriver.deleteDataProperty(stmt);
changeSet.get().deleteDataProperty(stmt);
}
// 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;
import com.hp.hpl.jena.rdf.model.Statement;
/**
* What calls can the ConfiguredReasonerListener make to drive the TBox reasoner?
*/
public interface TBoxReasonerDriver {
void runSynchronizer();
void addStatement(Statement stmt);
void removeStatement(Statement stmt);
void deleteDataProperty(Statement stmt);
void deleteObjectProperty(Statement stmt);
void runSynchronizer(TBoxChanges changeSet);
}