VIVO-778 Extract ConfiguredReasonerListener from PelletListener.
Separate the filtered listener from the reasoner driver.
This commit is contained in:
parent
e0abd88ac2
commit
21727afd13
3 changed files with 426 additions and 295 deletions
|
@ -2,11 +2,8 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet;
|
package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -19,28 +16,25 @@ import org.mindswap.pellet.jena.PelletReasonerFactory;
|
||||||
import com.hp.hpl.jena.ontology.DatatypeProperty;
|
import com.hp.hpl.jena.ontology.DatatypeProperty;
|
||||||
import com.hp.hpl.jena.ontology.ObjectProperty;
|
import com.hp.hpl.jena.ontology.ObjectProperty;
|
||||||
import com.hp.hpl.jena.ontology.OntModel;
|
import com.hp.hpl.jena.ontology.OntModel;
|
||||||
import com.hp.hpl.jena.rdf.model.Literal;
|
|
||||||
import com.hp.hpl.jena.rdf.model.Model;
|
import com.hp.hpl.jena.rdf.model.Model;
|
||||||
import com.hp.hpl.jena.rdf.model.ModelChangedListener;
|
|
||||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||||
import com.hp.hpl.jena.rdf.model.Property;
|
|
||||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||||
import com.hp.hpl.jena.rdf.model.Resource;
|
import com.hp.hpl.jena.rdf.model.Resource;
|
||||||
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
||||||
import com.hp.hpl.jena.rdf.model.Statement;
|
import com.hp.hpl.jena.rdf.model.Statement;
|
||||||
import com.hp.hpl.jena.rdf.model.StmtIterator;
|
|
||||||
import com.hp.hpl.jena.shared.Lock;
|
import com.hp.hpl.jena.shared.Lock;
|
||||||
import com.hp.hpl.jena.util.iterator.ClosableIterator;
|
import com.hp.hpl.jena.util.iterator.ClosableIterator;
|
||||||
import com.hp.hpl.jena.vocabulary.OWL;
|
import com.hp.hpl.jena.vocabulary.OWL;
|
||||||
import com.hp.hpl.jena.vocabulary.RDF;
|
|
||||||
import com.hp.hpl.jena.vocabulary.RDFS;
|
import com.hp.hpl.jena.vocabulary.RDFS;
|
||||||
|
|
||||||
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;
|
||||||
|
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.ReasonerConfiguration;
|
||||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern;
|
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
|
||||||
|
|
||||||
public class PelletListener implements ModelChangedListener {
|
public class PelletListener implements TBoxReasonerDriver {
|
||||||
|
|
||||||
private static final Log log = LogFactory.getLog(PelletListener.class.getName());
|
private static final Log log = LogFactory.getLog(PelletListener.class.getName());
|
||||||
private boolean isReasoning = false;
|
private boolean isReasoning = false;
|
||||||
|
@ -56,7 +50,7 @@ public class PelletListener implements ModelChangedListener {
|
||||||
private Set<ReasonerStatementPattern> inferenceDrivingPatternDenySet;
|
private Set<ReasonerStatementPattern> inferenceDrivingPatternDenySet;
|
||||||
private Set<ReasonerStatementPattern> inferenceReceivingPatternAllowSet;
|
private Set<ReasonerStatementPattern> inferenceReceivingPatternAllowSet;
|
||||||
|
|
||||||
private Map<Property,List<ReasonerStatementPattern>> inferenceDrivingPatternMap;
|
private final ConfiguredReasonerListener listener;
|
||||||
|
|
||||||
private Model additionModel;
|
private Model additionModel;
|
||||||
private Model removalModel;
|
private Model removalModel;
|
||||||
|
@ -64,8 +58,6 @@ public class PelletListener implements ModelChangedListener {
|
||||||
private Model deletedObjectProperties;
|
private Model deletedObjectProperties;
|
||||||
private Model deletedDataProperties;
|
private Model deletedDataProperties;
|
||||||
|
|
||||||
private boolean pipeOpen;
|
|
||||||
|
|
||||||
private boolean isConsistent = true;
|
private boolean isConsistent = true;
|
||||||
private boolean inErrorState = false;
|
private boolean inErrorState = false;
|
||||||
private String explanation = "";
|
private String explanation = "";
|
||||||
|
@ -86,14 +78,6 @@ public class PelletListener implements ModelChangedListener {
|
||||||
return this.isReasoning;
|
return this.isReasoning;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closePipe() {
|
|
||||||
pipeOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void openPipe() {
|
|
||||||
pipeOpen = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized boolean checkAndStartReasoning(){
|
public synchronized boolean checkAndStartReasoning(){
|
||||||
if( this.isReasoning )
|
if( this.isReasoning )
|
||||||
return false;
|
return false;
|
||||||
|
@ -143,45 +127,88 @@ public class PelletListener implements ModelChangedListener {
|
||||||
this.inferenceDrivingPatternDenySet = reasonerConfiguration.getInferenceDrivingPatternDenySet();
|
this.inferenceDrivingPatternDenySet = reasonerConfiguration.getInferenceDrivingPatternDenySet();
|
||||||
this.inferenceReceivingPatternAllowSet = reasonerConfiguration.getInferenceReceivingPatternAllowSet();
|
this.inferenceReceivingPatternAllowSet = reasonerConfiguration.getInferenceReceivingPatternAllowSet();
|
||||||
|
|
||||||
if (this.inferenceDrivingPatternAllowSet != null) {
|
|
||||||
this.inferenceDrivingPatternMap = new HashMap<>();
|
|
||||||
for (Iterator<ReasonerStatementPattern> i = inferenceDrivingPatternAllowSet.iterator(); i.hasNext();) {
|
|
||||||
ReasonerStatementPattern pat = i.next();
|
|
||||||
Property p = pat.getPredicate();
|
|
||||||
List<ReasonerStatementPattern> patList = inferenceDrivingPatternMap.get(p);
|
|
||||||
if (patList == null) {
|
|
||||||
patList = new LinkedList<>();
|
|
||||||
patList.add(pat);
|
|
||||||
inferenceDrivingPatternMap.put(p, patList);
|
|
||||||
} else {
|
|
||||||
patList.add(pat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.pipeOpen = true;
|
|
||||||
this.additionModel = ModelFactory.createDefaultModel();
|
this.additionModel = ModelFactory.createDefaultModel();
|
||||||
this.removalModel = ModelFactory.createDefaultModel();
|
this.removalModel = ModelFactory.createDefaultModel();
|
||||||
this.deletedObjectProperties = ModelFactory.createDefaultModel();
|
this.deletedObjectProperties = ModelFactory.createDefaultModel();
|
||||||
this.deletedDataProperties = ModelFactory.createDefaultModel();
|
this.deletedDataProperties = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
listener = new ConfiguredReasonerListener(reasonerConfiguration, this);
|
||||||
|
|
||||||
this.mainModel.enterCriticalSection(Lock.READ);
|
this.mainModel.enterCriticalSection(Lock.READ);
|
||||||
try {
|
try {
|
||||||
for (ReasonerStatementPattern pat : this.inferenceDrivingPatternAllowSet) {
|
for (ReasonerStatementPattern pat : this.inferenceDrivingPatternAllowSet) {
|
||||||
addedStatements(mainModel.listStatements((Resource) null, pat.getPredicate(), (RDFNode) null));
|
listener.addedStatements(mainModel.listStatements((Resource) null, pat.getPredicate(), (RDFNode) null));
|
||||||
}
|
}
|
||||||
if (!skipReasoningUponInitialization) {
|
if (!skipReasoningUponInitialization) {
|
||||||
this.foreground = foreground;
|
this.foreground = foreground;
|
||||||
notifyEvent(null,new EditEvent(null,false));
|
listener.notifyEvent(null,new EditEvent(null,false));
|
||||||
} else if (inferenceModel.size() == 0){
|
} else if (inferenceModel.size() == 0){
|
||||||
foreground = true;
|
foreground = true;
|
||||||
notifyEvent(null,new EditEvent(null,false));
|
listener.notifyEvent(null,new EditEvent(null,false));
|
||||||
this.foreground = foreground;
|
this.foreground = foreground;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.mainModel.leaveCriticalSection();
|
this.mainModel.leaveCriticalSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fullModel.getBaseModel().register(this);
|
this.fullModel.getBaseModel().register(listener);
|
||||||
this.mainModel.getBaseModel().register(this);
|
this.mainModel.getBaseModel().register(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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)) {
|
||||||
|
if (!isSynchronizing) {
|
||||||
|
if (foreground) {
|
||||||
|
log.debug("Running Pellet in foreground.");
|
||||||
|
(new PelletSynchronizer()).run();
|
||||||
|
} else {
|
||||||
|
log.debug("Running Pellet in background.");
|
||||||
|
new Thread(new PelletSynchronizer(),
|
||||||
|
"PelletListener.PelletSynchronizer").start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class InferenceGetter implements Runnable {
|
private class InferenceGetter implements Runnable {
|
||||||
|
@ -333,12 +360,10 @@ public class PelletListener implements ModelChangedListener {
|
||||||
if (!fullModelContainsStatement) {
|
if (!fullModelContainsStatement) {
|
||||||
// in theory we should be able to lock only the inference model, but I'm not sure yet if Jena propagates the locking upward
|
// in theory we should be able to lock only the inference model, but I'm not sure yet if Jena propagates the locking upward
|
||||||
fullModel.enterCriticalSection(Lock.WRITE);
|
fullModel.enterCriticalSection(Lock.WRITE);
|
||||||
closePipe();
|
try (Suspension susp = listener.suspend()) {
|
||||||
try {
|
|
||||||
inferenceModel.add(stmt);
|
inferenceModel.add(stmt);
|
||||||
addCount++;
|
addCount++;
|
||||||
} finally {
|
} finally {
|
||||||
openPipe();
|
|
||||||
fullModel.leaveCriticalSection();
|
fullModel.leaveCriticalSection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,12 +385,10 @@ public class PelletListener implements ModelChangedListener {
|
||||||
}
|
}
|
||||||
for (Iterator<Statement> i = localRemovalQueue.iterator(); i.hasNext(); ) {
|
for (Iterator<Statement> i = localRemovalQueue.iterator(); i.hasNext(); ) {
|
||||||
fullModel.enterCriticalSection(Lock.WRITE);
|
fullModel.enterCriticalSection(Lock.WRITE);
|
||||||
closePipe();
|
try (Suspension susp = listener.suspend()) {
|
||||||
try {
|
|
||||||
retractCount++;
|
retractCount++;
|
||||||
inferenceModel.remove(i.next());
|
inferenceModel.remove(i.next());
|
||||||
} finally {
|
} finally {
|
||||||
openPipe();
|
|
||||||
fullModel.leaveCriticalSection();
|
fullModel.leaveCriticalSection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,208 +435,6 @@ public class PelletListener implements ModelChangedListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: These next two methods are really ugly; I need to refactor them to remove redundancy.
|
|
||||||
|
|
||||||
private void tryAdd(Statement stmt) {
|
|
||||||
boolean sendToPellet = false;
|
|
||||||
if ( pipeOpen && reasonerConfiguration.getReasonOnAllDatatypePropertyStatements() && stmt.getObject().isLiteral() ) {
|
|
||||||
sendToPellet = true;
|
|
||||||
} else
|
|
||||||
if ( pipeOpen && hasCardinalityPredicate(stmt) ) { // see comment on this method
|
|
||||||
sendToPellet = true;
|
|
||||||
} else
|
|
||||||
if ( (stmt.getObject().isResource()) && !((stmt.getPredicate().getURI().indexOf(VitroVocabulary.vitroURI)==0)) ) {
|
|
||||||
if (pipeOpen) {
|
|
||||||
sendToPellet = false;
|
|
||||||
boolean denied = false;
|
|
||||||
ReasonerStatementPattern stPat = ReasonerStatementPattern.objectPattern(stmt);
|
|
||||||
if (inferenceDrivingPatternDenySet != null) {
|
|
||||||
for (Iterator<ReasonerStatementPattern> i = inferenceDrivingPatternDenySet.iterator(); i.hasNext(); ){
|
|
||||||
ReasonerStatementPattern pat = i.next();
|
|
||||||
if (pat.matches(stPat)) {
|
|
||||||
denied = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!denied) {
|
|
||||||
if (inferenceDrivingPatternAllowSet==null) {
|
|
||||||
sendToPellet = true;
|
|
||||||
} else {
|
|
||||||
// TODO: O(1) implementation of this
|
|
||||||
List<ReasonerStatementPattern> patList = this.inferenceDrivingPatternMap.get(stmt.getPredicate());
|
|
||||||
if (patList != null) {
|
|
||||||
for (Iterator<ReasonerStatementPattern> i = patList.iterator(); i.hasNext(); ){
|
|
||||||
ReasonerStatementPattern pat = i.next();
|
|
||||||
if (pat.matches(stPat)) {
|
|
||||||
sendToPellet = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sendToPellet) {
|
|
||||||
//long startTime = System.currentTimeMillis();
|
|
||||||
String valueStr = (stmt.getObject().isResource()) ? ((Resource)stmt.getObject()).getLocalName() : ((Literal)stmt.getObject()).getLexicalForm();
|
|
||||||
if ( log.isDebugEnabled() ) {
|
|
||||||
log.debug( "Adding to Pellet: " + renderStatement( stmt ) );
|
|
||||||
}
|
|
||||||
additionModel.enterCriticalSection(Lock.WRITE);
|
|
||||||
try {
|
|
||||||
additionModel.add(stmt);
|
|
||||||
} finally {
|
|
||||||
additionModel.leaveCriticalSection();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ( log.isDebugEnabled() ) {
|
|
||||||
log.debug( "Not adding to Pellet: " + renderStatement( stmt ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void tryRemove(Statement stmt) {
|
|
||||||
boolean removeFromPellet = false;
|
|
||||||
if ( pipeOpen && reasonerConfiguration.getReasonOnAllDatatypePropertyStatements() && stmt.getObject().isLiteral() ) {
|
|
||||||
removeFromPellet = true;
|
|
||||||
} else
|
|
||||||
if ( pipeOpen && hasCardinalityPredicate(stmt) ) { // see comment on this method
|
|
||||||
removeFromPellet = true;
|
|
||||||
} else
|
|
||||||
if ( stmt.getObject().isResource() ) {
|
|
||||||
if (pipeOpen) {
|
|
||||||
if (reasonerConfiguration.getQueryForAllObjectProperties() && stmt.getPredicate().equals(RDF.type) && stmt.getObject().equals(OWL.ObjectProperty)) {
|
|
||||||
deletedObjectProperties.enterCriticalSection(Lock.WRITE);
|
|
||||||
try {
|
|
||||||
deletedObjectProperties.add(stmt);
|
|
||||||
} finally {
|
|
||||||
deletedObjectProperties.leaveCriticalSection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (reasonerConfiguration.getQueryForAllDatatypeProperties() && stmt.getPredicate().equals(RDF.type) && stmt.getObject().equals(OWL.DatatypeProperty)) {
|
|
||||||
deletedDataProperties.enterCriticalSection(Lock.WRITE);
|
|
||||||
try{
|
|
||||||
deletedDataProperties.add(stmt);
|
|
||||||
} finally {
|
|
||||||
deletedDataProperties.leaveCriticalSection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removeFromPellet = false;
|
|
||||||
boolean denied = false;
|
|
||||||
ReasonerStatementPattern stPat = ReasonerStatementPattern.objectPattern(stmt);
|
|
||||||
if (inferenceDrivingPatternDenySet != null) {
|
|
||||||
for (Iterator<ReasonerStatementPattern> i = inferenceDrivingPatternDenySet.iterator(); i.hasNext(); ){
|
|
||||||
ReasonerStatementPattern pat = i.next();
|
|
||||||
if (pat.matches(stPat)) {
|
|
||||||
denied = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!denied) {
|
|
||||||
if (inferenceDrivingPatternAllowSet==null) {
|
|
||||||
removeFromPellet = true;
|
|
||||||
} else {
|
|
||||||
// TODO: O(1) implementation of this
|
|
||||||
List<ReasonerStatementPattern> patList = this.inferenceDrivingPatternMap.get(stmt.getPredicate());
|
|
||||||
if (patList != null) {
|
|
||||||
for (Iterator<ReasonerStatementPattern> i = patList.iterator(); i.hasNext(); ){
|
|
||||||
ReasonerStatementPattern pat = i.next();
|
|
||||||
if (pat.matches(stPat)) {
|
|
||||||
removeFromPellet = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (removeFromPellet) {
|
|
||||||
String valueStr = (stmt.getObject().isResource()) ? ((Resource)stmt.getObject()).getLocalName() : ((Literal)stmt.getObject()).getLexicalForm();
|
|
||||||
log.info("Removing from Pellet: "+stmt.getSubject().getLocalName()+" "+stmt.getPredicate().getLocalName()+" "+valueStr);
|
|
||||||
removalModel.enterCriticalSection(Lock.WRITE);
|
|
||||||
try {
|
|
||||||
removalModel.add(stmt);
|
|
||||||
} finally {
|
|
||||||
removalModel.leaveCriticalSection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The pattern matching stuff needs to get reworked.
|
|
||||||
// It originally assumed that only resources would be in object
|
|
||||||
// position, but cardinality axioms will have e.g. nonNegativeIntegers.
|
|
||||||
// This is a temporary workaround: all cardinality statements will
|
|
||||||
// be exposed to Pellet, regardless of configuration patterns.
|
|
||||||
private boolean hasCardinalityPredicate(Statement stmt) {
|
|
||||||
return (
|
|
||||||
stmt.getPredicate().equals(OWL.cardinality) ||
|
|
||||||
stmt.getPredicate().equals(OWL.minCardinality) ||
|
|
||||||
stmt.getPredicate().equals(OWL.maxCardinality)
|
|
||||||
) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addedStatement(Statement arg0) {
|
|
||||||
tryAdd(arg0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addedStatements(Statement[] arg0) {
|
|
||||||
for (int i=0; i<arg0.length; i++) {
|
|
||||||
tryAdd(arg0[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addedStatements( List arg0 ) {
|
|
||||||
for ( Iterator i = arg0.iterator(); i.hasNext(); ) {
|
|
||||||
tryAdd( (Statement) i.next() );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addedStatements(StmtIterator arg0) {
|
|
||||||
for (Iterator i = arg0; i.hasNext(); ) {
|
|
||||||
tryAdd( (Statement) i.next() );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addedStatements(Model arg0) {
|
|
||||||
for (Iterator i = arg0.listStatements(); i.hasNext(); ) {
|
|
||||||
tryAdd( (Statement) i.next() );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void notifyEvent(Model arg0, Object arg1) {
|
|
||||||
if (arg1 instanceof EditEvent) {
|
|
||||||
EditEvent ee = (EditEvent) arg1;
|
|
||||||
if (!ee.getBegin()) {
|
|
||||||
if ( (additionModel.size() > 0) || (removalModel.size()>0) ) {
|
|
||||||
if (!isSynchronizing) {
|
|
||||||
if (foreground) {
|
|
||||||
log.debug("Running Pellet in foreground.");
|
|
||||||
(new PelletSynchronizer()).run();
|
|
||||||
} else {
|
|
||||||
log.debug("Running Pellet in background.");
|
|
||||||
new Thread(new PelletSynchronizer(), "PelletListener.PelletSynchronizer").start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PelletSynchronizer implements Runnable {
|
private class PelletSynchronizer implements Runnable {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
@ -658,53 +479,8 @@ public class PelletListener implements ModelChangedListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removedStatement(Statement arg0) {
|
|
||||||
tryRemove(arg0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void removedStatements(Statement[] arg0) {
|
|
||||||
for (int i=0; i<arg0.length; i++) {
|
|
||||||
tryRemove(arg0[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void removedStatements(List arg0) {
|
|
||||||
for (Iterator i = arg0.iterator(); i.hasNext(); ) {
|
|
||||||
tryRemove( (Statement) i.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void removedStatements(StmtIterator arg0) {
|
|
||||||
for (Iterator i = arg0; i.hasNext();) {
|
|
||||||
tryRemove( (Statement) i.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void removedStatements(Model arg0) {
|
|
||||||
for (Iterator i = arg0.listStatements(); i.hasNext();) {
|
|
||||||
tryRemove( (Statement) i.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public OntModel getPelletModel() {
|
public OntModel getPelletModel() {
|
||||||
return this.pelletModel;
|
return this.pelletModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String renderStatement(Statement stmt) {
|
|
||||||
String subjStr = (stmt.getSubject().getURI() != null) ? stmt.getSubject().getURI() : stmt.getSubject().getId().toString();
|
|
||||||
String predStr = stmt.getPredicate().getURI();
|
|
||||||
String objStr = "";
|
|
||||||
RDFNode obj = stmt.getObject();
|
|
||||||
if (obj.isLiteral()) {
|
|
||||||
objStr = "\""+(((Literal)obj).getLexicalForm());
|
|
||||||
} else {
|
|
||||||
objStr = (((Resource)stmt.getObject()).getURI() != null) ? ((Resource)stmt.getObject()).getURI() : ((Resource)stmt.getObject()).getId().toString();
|
|
||||||
}
|
|
||||||
return (subjStr+" : "+predStr+" : "+objStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,334 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.tboxreasoner;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import com.hp.hpl.jena.rdf.model.Model;
|
||||||
|
import com.hp.hpl.jena.rdf.model.ModelChangedListener;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Property;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Statement;
|
||||||
|
import com.hp.hpl.jena.rdf.model.StmtIterator;
|
||||||
|
import com.hp.hpl.jena.vocabulary.OWL;
|
||||||
|
import com.hp.hpl.jena.vocabulary.RDF;
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* changes do not trigger additional reasoning.
|
||||||
|
*/
|
||||||
|
public class ConfiguredReasonerListener implements ModelChangedListener {
|
||||||
|
private static final Log log = LogFactory
|
||||||
|
.getLog(ConfiguredReasonerListener.class);
|
||||||
|
|
||||||
|
private final ReasonerConfiguration reasonerConfiguration;
|
||||||
|
private final TBoxReasonerDriver reasonerDriver;
|
||||||
|
private final DrivingPatternMap drivingPatternMap;
|
||||||
|
|
||||||
|
private final AtomicBoolean suspended = new AtomicBoolean();
|
||||||
|
|
||||||
|
public ConfiguredReasonerListener(
|
||||||
|
ReasonerConfiguration reasonerConfiguration,
|
||||||
|
TBoxReasonerDriver reasonerDriver) {
|
||||||
|
this.reasonerConfiguration = reasonerConfiguration;
|
||||||
|
this.reasonerDriver = reasonerDriver;
|
||||||
|
|
||||||
|
this.drivingPatternMap = new DrivingPatternMap(
|
||||||
|
reasonerConfiguration.getInferenceDrivingPatternAllowSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Suspension suspend() {
|
||||||
|
if (!suspended.compareAndSet(false, true)) {
|
||||||
|
throw new IllegalStateException("Listener is already suspended.");
|
||||||
|
}
|
||||||
|
return new Suspension();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Suspension implements AutoCloseable {
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
boolean wasSuspended = suspended.compareAndSet(true, false);
|
||||||
|
if (!wasSuspended) {
|
||||||
|
log.warn("Listener was already not suspended.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists of patterns, mapped by their predicates.
|
||||||
|
*/
|
||||||
|
public class DrivingPatternMap extends
|
||||||
|
HashMap<Property, List<ReasonerStatementPattern>> {
|
||||||
|
|
||||||
|
public DrivingPatternMap(Set<ReasonerStatementPattern> patternSet) {
|
||||||
|
if (patternSet != null) {
|
||||||
|
for (ReasonerStatementPattern pat : patternSet) {
|
||||||
|
Property p = pat.getPredicate();
|
||||||
|
if (!containsKey(p)) {
|
||||||
|
put(p, new LinkedList<ReasonerStatementPattern>());
|
||||||
|
}
|
||||||
|
get(p).add(pat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Implement the ModelChangedListener methods. Delegate to the methods that
|
||||||
|
// check criteria.
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addedStatement(Statement s) {
|
||||||
|
tryAdd(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addedStatements(Statement[] statements) {
|
||||||
|
for (Statement stmt : statements) {
|
||||||
|
tryAdd(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addedStatements(List<Statement> statements) {
|
||||||
|
for (Statement stmt : statements) {
|
||||||
|
tryAdd(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addedStatements(StmtIterator statements) {
|
||||||
|
for (Statement stmt : statements.toList()) {
|
||||||
|
tryAdd(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addedStatements(Model m) {
|
||||||
|
for (Statement stmt : m.listStatements().toList()) {
|
||||||
|
tryAdd(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removedStatement(Statement s) {
|
||||||
|
tryRemove(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removedStatements(Statement[] statements) {
|
||||||
|
for (Statement stmt : statements) {
|
||||||
|
tryRemove(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removedStatements(List<Statement> statements) {
|
||||||
|
for (Statement stmt : statements) {
|
||||||
|
tryRemove(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removedStatements(StmtIterator statements) {
|
||||||
|
for (Statement stmt : statements.toList()) {
|
||||||
|
tryRemove(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removedStatements(Model m) {
|
||||||
|
for (Statement stmt : m.listStatements().toList()) {
|
||||||
|
tryRemove(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyEvent(Model m, Object event) {
|
||||||
|
if (event instanceof EditEvent) {
|
||||||
|
EditEvent ee = (EditEvent) event;
|
||||||
|
if (!ee.getBegin()) {
|
||||||
|
this.reasonerDriver.runSynchronizer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Check the criteria to determine whether each addition or removal should
|
||||||
|
// be passed to the reasoner.
|
||||||
|
//
|
||||||
|
// When the listener is suspended, nothing is passed on.
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
public void tryAdd(Statement stmt) {
|
||||||
|
if (suspended.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDataProperty(stmt)) {
|
||||||
|
if (reasonOnAllDataProperties() || hasCardinalityPredicate(stmt)) {
|
||||||
|
addIt(stmt);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (predicateIsInVitroNamespace(stmt)
|
||||||
|
|| statementMatchesDenyPattern(stmt)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thereAreNoDrivingPatterns() || statementMatchesDrivingPattern(stmt)) {
|
||||||
|
addIt(stmt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tryRemove(Statement stmt) {
|
||||||
|
if (suspended.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDataProperty(stmt)) {
|
||||||
|
if (reasonOnAllDataProperties() || hasCardinalityPredicate(stmt)) {
|
||||||
|
removeIt(stmt);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actOnObjectPropertyDeclarations() && declaresObjectProperty(stmt)) {
|
||||||
|
deleteObjectProperty(stmt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actOnDataPropertyDeclarations() && declaresDataProperty(stmt)) {
|
||||||
|
deleteDataProperty(stmt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statementMatchesDenyPattern(stmt)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thereAreNoDrivingPatterns() || statementMatchesDrivingPattern(stmt)) {
|
||||||
|
removeIt(stmt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDataProperty(Statement stmt) {
|
||||||
|
return stmt.getObject().isLiteral();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean reasonOnAllDataProperties() {
|
||||||
|
return reasonerConfiguration.getReasonOnAllDatatypePropertyStatements();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean predicateIsInVitroNamespace(Statement stmt) {
|
||||||
|
return stmt.getPredicate().getURI().indexOf(VitroVocabulary.vitroURI) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean statementMatchesDenyPattern(Statement stmt) {
|
||||||
|
Set<ReasonerStatementPattern> denyPatterns = reasonerConfiguration.inferenceDrivingPatternDenySet;
|
||||||
|
if (denyPatterns == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReasonerStatementPattern stPat = ReasonerStatementPattern
|
||||||
|
.objectPattern(stmt);
|
||||||
|
|
||||||
|
for (ReasonerStatementPattern pat : denyPatterns) {
|
||||||
|
if (pat.matches(stPat)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean thereAreNoDrivingPatterns() {
|
||||||
|
return reasonerConfiguration.inferenceDrivingPatternAllowSet == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean statementMatchesDrivingPattern(Statement stmt) {
|
||||||
|
List<ReasonerStatementPattern> drivePatterns = drivingPatternMap
|
||||||
|
.get(stmt.getPredicate());
|
||||||
|
if (drivePatterns == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReasonerStatementPattern stPat = ReasonerStatementPattern
|
||||||
|
.objectPattern(stmt);
|
||||||
|
|
||||||
|
for (ReasonerStatementPattern pat : drivePatterns) {
|
||||||
|
if (pat.matches(stPat)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean actOnObjectPropertyDeclarations() {
|
||||||
|
return reasonerConfiguration.getQueryForAllObjectProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean declaresObjectProperty(Statement stmt) {
|
||||||
|
return stmt.getPredicate().equals(RDF.type)
|
||||||
|
&& stmt.getObject().equals(OWL.ObjectProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean actOnDataPropertyDeclarations() {
|
||||||
|
return reasonerConfiguration.getQueryForAllDatatypeProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean declaresDataProperty(Statement stmt) {
|
||||||
|
return stmt.getPredicate().equals(RDF.type)
|
||||||
|
&& stmt.getObject().equals(OWL.DatatypeProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addIt(Statement stmt) {
|
||||||
|
this.reasonerDriver.addStatement(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeIt(Statement stmt) {
|
||||||
|
this.reasonerDriver.removeStatement(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteObjectProperty(Statement stmt) {
|
||||||
|
this.reasonerDriver.deleteObjectProperty(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteDataProperty(Statement stmt) {
|
||||||
|
this.reasonerDriver.deleteDataProperty(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pattern matching stuff needs to get reworked.
|
||||||
|
// It originally assumed that only resources would be in object
|
||||||
|
// position, but cardinality axioms will have e.g. nonNegativeIntegers.
|
||||||
|
// This is a temporary workaround: all cardinality statements will
|
||||||
|
// be exposed to Pellet, regardless of configuration patterns.
|
||||||
|
private boolean hasCardinalityPredicate(Statement stmt) {
|
||||||
|
return (stmt.getPredicate().equals(OWL.cardinality)
|
||||||
|
|| stmt.getPredicate().equals(OWL.minCardinality) || stmt
|
||||||
|
.getPredicate().equals(OWL.maxCardinality));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue