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;
|
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 {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue