VIVO-778 Accumulate the TBox changes in a change set object.
This commit is contained in:
parent
370df0b7ec
commit
6bb8987d9d
4 changed files with 127 additions and 129 deletions
|
@ -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();
|
||||
}
|
||||
while (!pendingChangeSets.isEmpty()) {
|
||||
TBoxChanges changeSet = pendingChangeSets.remove(0);
|
||||
|
||||
pelletModel.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
pelletModel.remove(tempModel);
|
||||
pelletModel.remove(changeSet.getRemovedStatements());
|
||||
pelletModel.add(changeSet.getAddedStatements());
|
||||
} 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();
|
||||
getInferences(changeSet);
|
||||
|
||||
}
|
||||
} finally {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue