VIVO-778 Extract ConfiguredReasonerListener from PelletListener.
Separate the filtered listener from the reasoner driver.
This commit is contained in:
parent
85b9067eee
commit
370df0b7ec
3 changed files with 426 additions and 295 deletions
|
@ -2,11 +2,8 @@
|
|||
|
||||
package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
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.ObjectProperty;
|
||||
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.ModelChangedListener;
|
||||
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.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
||||
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.util.iterator.ClosableIterator;
|
||||
import com.hp.hpl.jena.vocabulary.OWL;
|
||||
import com.hp.hpl.jena.vocabulary.RDF;
|
||||
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.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.TBoxReasonerDriver;
|
||||
|
||||
public class PelletListener implements ModelChangedListener {
|
||||
public class PelletListener implements TBoxReasonerDriver {
|
||||
|
||||
private static final Log log = LogFactory.getLog(PelletListener.class.getName());
|
||||
private boolean isReasoning = false;
|
||||
|
@ -56,7 +50,7 @@ public class PelletListener implements ModelChangedListener {
|
|||
private Set<ReasonerStatementPattern> inferenceDrivingPatternDenySet;
|
||||
private Set<ReasonerStatementPattern> inferenceReceivingPatternAllowSet;
|
||||
|
||||
private Map<Property,List<ReasonerStatementPattern>> inferenceDrivingPatternMap;
|
||||
private final ConfiguredReasonerListener listener;
|
||||
|
||||
private Model additionModel;
|
||||
private Model removalModel;
|
||||
|
@ -64,8 +58,6 @@ public class PelletListener implements ModelChangedListener {
|
|||
private Model deletedObjectProperties;
|
||||
private Model deletedDataProperties;
|
||||
|
||||
private boolean pipeOpen;
|
||||
|
||||
private boolean isConsistent = true;
|
||||
private boolean inErrorState = false;
|
||||
private String explanation = "";
|
||||
|
@ -86,14 +78,6 @@ public class PelletListener implements ModelChangedListener {
|
|||
return this.isReasoning;
|
||||
}
|
||||
|
||||
public void closePipe() {
|
||||
pipeOpen = false;
|
||||
}
|
||||
|
||||
public void openPipe() {
|
||||
pipeOpen = true;
|
||||
}
|
||||
|
||||
public synchronized boolean checkAndStartReasoning(){
|
||||
if( this.isReasoning )
|
||||
return false;
|
||||
|
@ -143,45 +127,88 @@ public class PelletListener implements ModelChangedListener {
|
|||
this.inferenceDrivingPatternDenySet = reasonerConfiguration.getInferenceDrivingPatternDenySet();
|
||||
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.removalModel = ModelFactory.createDefaultModel();
|
||||
this.deletedObjectProperties = ModelFactory.createDefaultModel();
|
||||
this.deletedDataProperties = ModelFactory.createDefaultModel();
|
||||
|
||||
listener = new ConfiguredReasonerListener(reasonerConfiguration, this);
|
||||
|
||||
this.mainModel.enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
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) {
|
||||
this.foreground = foreground;
|
||||
notifyEvent(null,new EditEvent(null,false));
|
||||
listener.notifyEvent(null,new EditEvent(null,false));
|
||||
} else if (inferenceModel.size() == 0){
|
||||
foreground = true;
|
||||
notifyEvent(null,new EditEvent(null,false));
|
||||
listener.notifyEvent(null,new EditEvent(null,false));
|
||||
this.foreground = foreground;
|
||||
}
|
||||
} finally {
|
||||
this.mainModel.leaveCriticalSection();
|
||||
}
|
||||
|
||||
this.fullModel.getBaseModel().register(this);
|
||||
this.mainModel.getBaseModel().register(this);
|
||||
this.fullModel.getBaseModel().register(listener);
|
||||
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 {
|
||||
|
@ -333,12 +360,10 @@ public class PelletListener implements ModelChangedListener {
|
|||
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
|
||||
fullModel.enterCriticalSection(Lock.WRITE);
|
||||
closePipe();
|
||||
try {
|
||||
try (Suspension susp = listener.suspend()) {
|
||||
inferenceModel.add(stmt);
|
||||
addCount++;
|
||||
} finally {
|
||||
openPipe();
|
||||
fullModel.leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
@ -360,12 +385,10 @@ public class PelletListener implements ModelChangedListener {
|
|||
}
|
||||
for (Iterator<Statement> i = localRemovalQueue.iterator(); i.hasNext(); ) {
|
||||
fullModel.enterCriticalSection(Lock.WRITE);
|
||||
closePipe();
|
||||
try {
|
||||
try (Suspension susp = listener.suspend()) {
|
||||
retractCount++;
|
||||
inferenceModel.remove(i.next());
|
||||
} finally {
|
||||
openPipe();
|
||||
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 {
|
||||
public void run() {
|
||||
try {
|
||||
|
@ -657,54 +478,9 @@ 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() {
|
||||
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