VIVO-778 Refactor the connections to the TBox reasoner.
Replace PelletListener with a TBoxReasonerModule in the Application. The reasoner will be accessible only through here, not as a context attribute or through the WebappDaoFactory. Split out the initialization of the TBox reasoner from SimpleReasonerSetup. Break out the filtering of TBox changes into a ConfiguredReasonerListener. Refactor the threading logic into a BasicTBoxReasonerDriver. Add a factory for creating VitroBackgroundThreads in an Executor. Isolate the actual reasoner into a TBoxReasoner implementation. In this case, PelletTBoxReasoner. Combine the consistency flag, error flag, explanation, and running status into one TBoxReasonerStatus object.
This commit is contained in:
parent
adf04bd2be
commit
4b71c1d6bb
32 changed files with 1526 additions and 986 deletions
|
@ -35,7 +35,6 @@ log4j.rootLogger=INFO, AllAppender
|
|||
|
||||
# These classes are too chatty to display INFO messages.
|
||||
log4j.logger.edu.cornell.mannlib.vitro.webapp.startup.StartupStatus=WARN
|
||||
log4j.logger.edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener=WARN
|
||||
log4j.logger.edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdateKnowledgeBase=DEBUG
|
||||
|
||||
# Spring as a whole is too chatty to display INFO messages.
|
||||
|
|
|
@ -16,6 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus;
|
|||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
|
||||
|
@ -41,6 +42,7 @@ public class ApplicationImpl implements Application {
|
|||
private FileStorage fileStorage;
|
||||
private ContentTripleSource contentTripleSource;
|
||||
private ConfigurationTripleSource configurationTripleSource;
|
||||
private TBoxReasonerModule tboxReasonerModule;
|
||||
|
||||
public void setServletContext(ServletContext ctx) {
|
||||
this.ctx = ctx;
|
||||
|
@ -140,6 +142,22 @@ public class ApplicationImpl implements Application {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TBoxReasonerModule getTBoxReasonerModule() {
|
||||
return tboxReasonerModule;
|
||||
}
|
||||
|
||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTBoxReasonerModule")
|
||||
public void setTBoxReasonerModule(TBoxReasonerModule module) {
|
||||
if (tboxReasonerModule == null) {
|
||||
tboxReasonerModule = module;
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Configuration includes multiple intances of TBoxReasonerModule: "
|
||||
+ tboxReasonerModule + ", and " + module);
|
||||
}
|
||||
}
|
||||
|
||||
@Validation
|
||||
public void validate() throws Exception {
|
||||
if (searchEngine == null) {
|
||||
|
@ -162,6 +180,10 @@ public class ApplicationImpl implements Application {
|
|||
throw new IllegalStateException(
|
||||
"Configuration did not include a ConfigurationTripleSource.");
|
||||
}
|
||||
if (tboxReasonerModule == null) {
|
||||
throw new IllegalStateException(
|
||||
"Configuration did not include a TBoxReasonerModule.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -244,4 +266,30 @@ public class ApplicationImpl implements Application {
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Setup the reasoners.
|
||||
//
|
||||
// This must happen after the FileGraphSetup.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public static class ReasonersSetup implements ServletContextListener {
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
ServletContext ctx = sce.getServletContext();
|
||||
Application app = ApplicationUtils.instance();
|
||||
StartupStatus ss = StartupStatus.getBean(ctx);
|
||||
ComponentStartupStatus css = new ComponentStartupStatusImpl(this,
|
||||
ss);
|
||||
|
||||
TBoxReasonerModule tboxReasoner = app.getTBoxReasonerModule();
|
||||
tboxReasoner.startup(app, css);
|
||||
ss.info(this, "Started the TBoxReasonerModule: " + tboxReasoner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
Application app = ApplicationUtils.instance();
|
||||
app.getTBoxReasonerModule().shutdown(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
|
||||
import edu.cornell.mannlib.vedit.beans.Option;
|
||||
import edu.cornell.mannlib.vedit.util.FormUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest;
|
||||
|
@ -24,7 +25,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMa
|
|||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.controller.IndexController;
|
||||
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||
|
||||
|
@ -159,26 +160,23 @@ public class BaseSiteAdminController extends FreemarkerHttpServlet {
|
|||
|
||||
if (PolicyHelper.isAuthorizedForActions(vreq, SimplePermission.EDIT_ONTOLOGY.ACTION)) {
|
||||
|
||||
String pelletError = null;
|
||||
String pelletExplanation = null;
|
||||
Object plObj = getServletContext().getAttribute("pelletListener");
|
||||
if ( (plObj != null) && (plObj instanceof PelletListener) ) {
|
||||
PelletListener pelletListener = (PelletListener) plObj;
|
||||
if (!pelletListener.isConsistent()) {
|
||||
pelletError = "INCONSISTENT ONTOLOGY: reasoning halted.";
|
||||
pelletExplanation = pelletListener.getExplanation();
|
||||
} else if ( pelletListener.isInErrorState() ) {
|
||||
pelletError = "An error occurred during reasoning. Reasoning has been halted. See error log for details.";
|
||||
}
|
||||
String error = null;
|
||||
String explanation = null;
|
||||
TBoxReasonerStatus status = ApplicationUtils.instance().getTBoxReasonerModule().getStatus();
|
||||
if (!status.isConsistent()) {
|
||||
error = "INCONSISTENT ONTOLOGY: reasoning halted.";
|
||||
explanation = status.getExplanation();
|
||||
} else if ( status.isInErrorState() ) {
|
||||
error = "An error occurred during reasoning. Reasoning has been halted. See error log for details.";
|
||||
}
|
||||
|
||||
if (pelletError != null) {
|
||||
Map<String, String> pellet = new HashMap<String, String>();
|
||||
pellet.put("error", pelletError);
|
||||
if (pelletExplanation != null) {
|
||||
pellet.put("explanation", pelletExplanation);
|
||||
if (error != null) {
|
||||
Map<String, String> tboxReasonerStatus = new HashMap<String, String>();
|
||||
tboxReasonerStatus.put("error", error);
|
||||
if (explanation != null) {
|
||||
tboxReasonerStatus.put("explanation", explanation);
|
||||
}
|
||||
map.put("pellet", pellet);
|
||||
map.put("tboxReasonerStatus", tboxReasonerStatus);
|
||||
}
|
||||
|
||||
Map<String, String> urls = new HashMap<String, String>();
|
||||
|
|
|
@ -44,10 +44,12 @@ import com.hp.hpl.jena.vocabulary.RDF;
|
|||
import com.hp.hpl.jena.vocabulary.RDFS;
|
||||
|
||||
import edu.cornell.mannlib.vedit.controller.BaseEditController;
|
||||
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule;
|
||||
|
||||
public class JenaAdminActions extends BaseEditController {
|
||||
|
||||
|
@ -190,9 +192,8 @@ public class JenaAdminActions extends BaseEditController {
|
|||
}
|
||||
|
||||
private void printRestrictions() {
|
||||
OntModel memoryModel = (OntModel) getServletContext().getAttribute("pelletOntModel");
|
||||
for (Restriction rest : memoryModel.listRestrictions().toList() ) {
|
||||
//System.out.println();
|
||||
TBoxReasonerModule reasoner = ApplicationUtils.instance().getTBoxReasonerModule();
|
||||
for (Restriction rest : reasoner.listRestrictions() ) {
|
||||
if (rest.isAllValuesFromRestriction()) {
|
||||
log.trace("All values from: ");
|
||||
AllValuesFromRestriction avfr = rest.asAllValuesFromRestriction();
|
||||
|
|
|
@ -41,6 +41,7 @@ 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.application.ApplicationUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.DataProperty;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement;
|
||||
|
@ -51,7 +52,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyDao;
|
|||
import edu.cornell.mannlib.vitro.webapp.dao.InsertException;
|
||||
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.pellet.PelletListener;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||
|
||||
public class DataPropertyDaoJena extends PropertyDaoJena implements
|
||||
|
@ -357,10 +358,8 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements
|
|||
}
|
||||
|
||||
protected boolean reasoningAvailable() {
|
||||
PelletListener pl = getWebappDaoFactory().getPelletListener();
|
||||
return !(
|
||||
( pl == null || !pl.isConsistent() || pl.isInErrorState() )
|
||||
);
|
||||
TBoxReasonerStatus status = ApplicationUtils.instance().getTBoxReasonerModule().getStatus();
|
||||
return status.isConsistent() && !status.isInErrorState();
|
||||
}
|
||||
|
||||
private String getRequiredDatatypeURI(Individual individual, DataProperty dataprop, List<String> vclassURIs) {
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.jena.iri.IRI;
|
||||
import org.apache.jena.iri.IRIFactory;
|
||||
import org.mindswap.pellet.jena.vocabulary.SWRL;
|
||||
|
||||
import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
|
||||
import com.hp.hpl.jena.graph.Node;
|
||||
|
@ -55,6 +54,8 @@ public class JenaBaseDao extends JenaBaseDaoCon {
|
|||
public static final boolean KEEP_ONLY_IF_TRUE = true; //used for updatePropertyBooleanValue()
|
||||
public static final boolean KEEP_ONLY_IF_FALSE = false; //used for updatePropertyBooleanValue()
|
||||
|
||||
private static final String SWRL_IMP = "http://www.w3.org/2003/11/swrl#Imp";
|
||||
|
||||
protected static final Log log = LogFactory.getLog(JenaBaseDao.class.getName());
|
||||
|
||||
/* ******************* static constants ****************** */
|
||||
|
@ -1090,7 +1091,7 @@ public class JenaBaseDao extends JenaBaseDaoCon {
|
|||
}
|
||||
|
||||
public void removeRulesMentioningResource(Resource res, OntModel ontModel) {
|
||||
Iterator<Resource> impIt = ontModel.listSubjectsWithProperty(RDF.type, SWRL.Imp);
|
||||
Iterator<Resource> impIt = ontModel.listSubjectsWithProperty(RDF.type, SWRL_IMP);
|
||||
while (impIt.hasNext()) {
|
||||
Resource imp = impIt.next();
|
||||
boolean removeMe = false;
|
||||
|
|
|
@ -47,7 +47,6 @@ import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupDao;
|
|||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactoryConfig;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener;
|
||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.model.RDFServiceModel;
|
||||
|
@ -70,8 +69,6 @@ public class WebappDaoFactoryJena implements WebappDaoFactory {
|
|||
|
||||
protected WebappDaoFactoryConfig config;
|
||||
|
||||
protected PelletListener pelletListener;
|
||||
|
||||
protected String userURI;
|
||||
|
||||
private Map<String,String> properties = new HashMap<String,String>();
|
||||
|
@ -238,18 +235,6 @@ public class WebappDaoFactoryJena implements WebappDaoFactory {
|
|||
return config.getNonUserNamespaces();
|
||||
}
|
||||
|
||||
/**
|
||||
* This enables the WebappDaoFactory to check the status of a reasoner.
|
||||
* This will likely be refactored in future releases.
|
||||
*/
|
||||
public void setPelletListener(PelletListener pl) {
|
||||
this.pelletListener = pl;
|
||||
}
|
||||
|
||||
public PelletListener getPelletListener() {
|
||||
return this.pelletListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getCommentsForResource(String resourceURI) {
|
||||
List<String> commentList = new LinkedList<String>();
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
|
||||
public class ObjectPropertyStatementPattern {
|
||||
|
||||
private Resource subject = null;
|
||||
private Property predicate = null;
|
||||
private Resource object = null;
|
||||
|
||||
public ObjectPropertyStatementPattern(Resource subject, Property predicate, Resource object) {
|
||||
this.subject = subject;
|
||||
this.predicate = predicate;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public Resource getSubject() {
|
||||
return this.subject;
|
||||
}
|
||||
public Property getPredicate() {
|
||||
return this.predicate;
|
||||
}
|
||||
public Resource getObject() {
|
||||
return this.object;
|
||||
}
|
||||
|
||||
public boolean matches(ObjectPropertyStatementPattern p2) {
|
||||
boolean sMatch = false;
|
||||
boolean pMatch = false;
|
||||
boolean oMatch = false;
|
||||
if (this.getSubject() == null || p2.getSubject()==null) {
|
||||
sMatch = true; // (this.getSubject() == null && p2.getSubject() == null);
|
||||
} else {
|
||||
sMatch = (this.getSubject().equals(p2.getSubject()));
|
||||
}
|
||||
if (this.getPredicate() == null || p2.getPredicate()==null) {
|
||||
pMatch = true; // (this.getPredicate() == null && p2.getPredicate() == null);
|
||||
} else {
|
||||
pMatch = (this.getPredicate().equals(p2.getPredicate()));
|
||||
}
|
||||
if (this.getObject() == null || p2.getObject()==null) {
|
||||
oMatch = true ; // (this.getObject() == null && p2.getObject() == null);
|
||||
} else {
|
||||
oMatch = (this.getObject().equals(p2.getObject()));
|
||||
}
|
||||
return (sMatch && pMatch && oMatch);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
|
||||
public class ObjectPropertyStatementPatternFactory {
|
||||
|
||||
//private static Set<ObjectPropertyStatementPattern> patternSet = new HashSet<ObjectPropertyStatementPattern>();
|
||||
|
||||
public static ObjectPropertyStatementPattern getPattern(Resource subject, Property predicate, Resource object) {
|
||||
//for (Iterator<ObjectPropertyStatementPattern> i = patternSet.iterator(); i.hasNext(); ) {
|
||||
// ObjectPropertyStatementPattern pat = i.next();
|
||||
// if ( ( (pat.getSubject()==null && subject==null) || (pat.getSubject().equals(subject)) )
|
||||
// && ( (pat.getPredicate()==null && predicate==null) || (pat.getPredicate().equals(predicate)) )
|
||||
// && ( (pat.getObject()==null && object==null) || (pat.getObject().equals(object)) ) ) {
|
||||
// return pat;
|
||||
// }
|
||||
//}
|
||||
ObjectPropertyStatementPattern newPat = new ObjectPropertyStatementPattern(subject,predicate,object);
|
||||
//patternSet.add(newPat);
|
||||
return newPat;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,732 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
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;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.mindswap.pellet.exceptions.InconsistentOntologyException;
|
||||
import org.mindswap.pellet.jena.PelletInfGraph;
|
||||
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;
|
||||
|
||||
public class PelletListener implements ModelChangedListener {
|
||||
|
||||
private static final Log log = LogFactory.getLog(PelletListener.class.getName());
|
||||
private boolean isReasoning = false;
|
||||
private boolean isSynchronizing = false;
|
||||
private boolean dirty = false;
|
||||
|
||||
private OntModel pelletModel;
|
||||
private OntModel fullModel;
|
||||
private OntModel mainModel;
|
||||
private Model inferenceModel;
|
||||
private ReasonerConfiguration reasonerConfiguration;
|
||||
private Set<ObjectPropertyStatementPattern> inferenceDrivingPatternAllowSet;
|
||||
private Set<ObjectPropertyStatementPattern> inferenceDrivingPatternDenySet;
|
||||
private Set<ObjectPropertyStatementPattern> inferenceReceivingPatternAllowSet;
|
||||
|
||||
private Map<Property,List<ObjectPropertyStatementPattern>> inferenceDrivingPatternMap;
|
||||
|
||||
private Model additionModel;
|
||||
private Model removalModel;
|
||||
|
||||
private Model deletedObjectProperties;
|
||||
private Model deletedDataProperties;
|
||||
|
||||
private boolean pipeOpen;
|
||||
|
||||
private boolean isConsistent = true;
|
||||
private boolean inErrorState = false;
|
||||
private String explanation = "";
|
||||
|
||||
public boolean isConsistent() {
|
||||
return this.isConsistent;
|
||||
}
|
||||
|
||||
public String getExplanation() {
|
||||
return this.explanation;
|
||||
}
|
||||
|
||||
public boolean isInErrorState() {
|
||||
return this.inErrorState;
|
||||
}
|
||||
|
||||
public boolean isReasoning() {
|
||||
return this.isReasoning;
|
||||
}
|
||||
|
||||
public void closePipe() {
|
||||
pipeOpen = false;
|
||||
}
|
||||
|
||||
public void openPipe() {
|
||||
pipeOpen = true;
|
||||
}
|
||||
|
||||
public synchronized boolean checkAndStartReasoning(){
|
||||
if( this.isReasoning )
|
||||
return false;
|
||||
else{
|
||||
this.isReasoning = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void endReasoning() {
|
||||
this.isReasoning = false;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return this.dirty;
|
||||
}
|
||||
|
||||
public void setDirty(boolean dirt) {
|
||||
this.dirty = dirt;
|
||||
}
|
||||
|
||||
private int inferenceRounds = 0;
|
||||
|
||||
private boolean foreground = false;
|
||||
private static final boolean FOREGROUND = true;
|
||||
private static final boolean BACKGROUND = false;
|
||||
private static final boolean DONT_SKIP_INITIAL_REASONING = false;
|
||||
|
||||
public PelletListener(OntModel fullModel, OntModel model, Model inferenceModel, ReasonerConfiguration reasonerConfiguration) {
|
||||
this(fullModel, model, inferenceModel, reasonerConfiguration, BACKGROUND);
|
||||
}
|
||||
|
||||
public PelletListener(OntModel fullModel, OntModel model, Model inferenceModel, ReasonerConfiguration reasonerConfiguration, boolean foreground) {
|
||||
this(fullModel, model, inferenceModel, reasonerConfiguration, foreground, DONT_SKIP_INITIAL_REASONING);
|
||||
}
|
||||
|
||||
public PelletListener(OntModel fullModel, OntModel model, Model inferenceModel, ReasonerConfiguration reasonerConfiguration, boolean foreground, boolean skipReasoningUponInitialization) {
|
||||
this.pelletModel = ModelFactory.createOntologyModel(reasonerConfiguration.getOntModelSpec());
|
||||
this.fullModel = fullModel;
|
||||
this.mainModel = model;
|
||||
this.inferenceModel = inferenceModel;
|
||||
if (this.inferenceModel == null) {
|
||||
log.trace("Inference model is null");
|
||||
}
|
||||
this.reasonerConfiguration = reasonerConfiguration;
|
||||
this.inferenceDrivingPatternAllowSet = reasonerConfiguration.getInferenceDrivingPatternAllowSet();
|
||||
this.inferenceDrivingPatternDenySet = reasonerConfiguration.getInferenceDrivingPatternDenySet();
|
||||
this.inferenceReceivingPatternAllowSet = reasonerConfiguration.getInferenceReceivingPatternAllowSet();
|
||||
|
||||
if (this.inferenceDrivingPatternAllowSet != null) {
|
||||
this.inferenceDrivingPatternMap = new HashMap<Property,List<ObjectPropertyStatementPattern>>();
|
||||
for (Iterator<ObjectPropertyStatementPattern> i = inferenceDrivingPatternAllowSet.iterator(); i.hasNext();) {
|
||||
ObjectPropertyStatementPattern pat = i.next();
|
||||
Property p = pat.getPredicate();
|
||||
List<ObjectPropertyStatementPattern> patList = inferenceDrivingPatternMap.get(p);
|
||||
if (patList == null) {
|
||||
patList = new LinkedList<ObjectPropertyStatementPattern>();
|
||||
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();
|
||||
this.mainModel.enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
for (ObjectPropertyStatementPattern pat : this.inferenceDrivingPatternAllowSet) {
|
||||
addedStatements(mainModel.listStatements((Resource) null, pat.getPredicate(), (RDFNode) null));
|
||||
}
|
||||
if (!skipReasoningUponInitialization) {
|
||||
this.foreground = foreground;
|
||||
notifyEvent(null,new EditEvent(null,false));
|
||||
} else if (inferenceModel.size() == 0){
|
||||
foreground = true;
|
||||
notifyEvent(null,new EditEvent(null,false));
|
||||
this.foreground = foreground;
|
||||
}
|
||||
} finally {
|
||||
this.mainModel.leaveCriticalSection();
|
||||
}
|
||||
|
||||
this.fullModel.getBaseModel().register(this);
|
||||
this.mainModel.getBaseModel().register(this);
|
||||
}
|
||||
|
||||
private class InferenceGetter implements Runnable {
|
||||
|
||||
private PelletListener pelletListener;
|
||||
|
||||
public InferenceGetter(PelletListener pelletListener) {
|
||||
this.pelletListener = pelletListener;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (pelletListener.isDirty()) {
|
||||
//pipeOpen = false;
|
||||
try {
|
||||
pelletListener.setDirty(false);
|
||||
inferenceRounds++;
|
||||
log.info("Getting new inferences");
|
||||
long startTime = System.currentTimeMillis();
|
||||
LinkedList<ObjectPropertyStatementPattern> irpl = new LinkedList<ObjectPropertyStatementPattern>();
|
||||
|
||||
if (inferenceReceivingPatternAllowSet != null) {
|
||||
irpl.addAll(inferenceReceivingPatternAllowSet);
|
||||
} else {
|
||||
irpl.add(ObjectPropertyStatementPatternFactory.getPattern(null,null,null));
|
||||
}
|
||||
|
||||
if (reasonerConfiguration.getQueryForAllObjectProperties()) {
|
||||
pelletModel.enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
ClosableIterator closeIt = pelletModel.listObjectProperties();
|
||||
try {
|
||||
for (Iterator objPropIt = closeIt; objPropIt.hasNext();) {
|
||||
ObjectProperty objProp = (ObjectProperty) objPropIt.next();
|
||||
if ( !("http://www.w3.org/2002/07/owl#".equals(objProp.getNameSpace())) ) {
|
||||
irpl.add(ObjectPropertyStatementPatternFactory.getPattern(null,objProp,null));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
closeIt.close();
|
||||
}
|
||||
} finally {
|
||||
pelletModel.leaveCriticalSection();
|
||||
}
|
||||
deletedObjectProperties.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
ClosableIterator sit = deletedObjectProperties.listSubjects();
|
||||
try {
|
||||
while (sit.hasNext()) {
|
||||
Resource subj = (Resource) sit.next();
|
||||
irpl.add(ObjectPropertyStatementPatternFactory.getPattern(null,ResourceFactory.createProperty(subj.getURI()),null));
|
||||
}
|
||||
} finally {
|
||||
sit.close();
|
||||
}
|
||||
deletedObjectProperties.removeAll();
|
||||
} finally {
|
||||
deletedObjectProperties.leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
||||
if (reasonerConfiguration.getQueryForAllDatatypeProperties()) {
|
||||
pelletModel.enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
ClosableIterator closeIt = pelletModel.listDatatypeProperties();
|
||||
try {
|
||||
for (Iterator dataPropIt = closeIt; dataPropIt.hasNext();) {
|
||||
DatatypeProperty dataProp = (DatatypeProperty) dataPropIt.next();
|
||||
if ( !("http://www.w3.org/2002/07/owl#".equals(dataProp.getNameSpace())) ) {
|
||||
// TODO: THIS WILL WORK, BUT NEED TO GENERALIZE THE PATTERN CLASSES
|
||||
irpl.add(ObjectPropertyStatementPatternFactory.getPattern(null,dataProp,null));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
closeIt.close();
|
||||
}
|
||||
} finally {
|
||||
pelletModel.leaveCriticalSection();
|
||||
}
|
||||
deletedDataProperties.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
ClosableIterator sit = deletedDataProperties.listSubjects();
|
||||
try {
|
||||
while (sit.hasNext()) {
|
||||
Resource subj = (Resource) sit.next();
|
||||
irpl.add(ObjectPropertyStatementPatternFactory.getPattern(null,ResourceFactory.createProperty(subj.getURI()),null));
|
||||
}
|
||||
} finally {
|
||||
sit.close();
|
||||
}
|
||||
deletedDataProperties.removeAll();
|
||||
} finally {
|
||||
deletedDataProperties.leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
||||
int addCount = 0;
|
||||
int retractCount = 0;
|
||||
|
||||
// force new reasoner (disabled)
|
||||
if (false && !reasonerConfiguration.isIncrementalReasoningEnabled()) {
|
||||
Model baseModel = pelletModel.getBaseModel();
|
||||
pelletModel = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
|
||||
pelletModel.getDocumentManager().setProcessImports(false);
|
||||
pelletModel.add(baseModel);
|
||||
}
|
||||
|
||||
pelletModel.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
pelletModel.rebind();
|
||||
pelletModel.prepare();
|
||||
} finally {
|
||||
pelletModel.leaveCriticalSection();
|
||||
}
|
||||
|
||||
for (Iterator<ObjectPropertyStatementPattern> patIt = irpl.iterator(); patIt.hasNext(); ) {
|
||||
ObjectPropertyStatementPattern pat = patIt.next();
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
String subjStr = (pat.getSubject() != null) ? pat.getSubject().getURI() : "*";
|
||||
String predStr = (pat.getPredicate() != null) ? pat.getPredicate().getURI() : "*";
|
||||
String objStr = (pat.getObject() != null) ? pat.getObject().getURI() : "*";
|
||||
log.debug("Querying for "+subjStr+" : "+predStr+" : "+objStr);
|
||||
}
|
||||
|
||||
Model tempModel = ModelFactory.createDefaultModel();
|
||||
|
||||
pelletModel.enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
|
||||
ClosableIterator ci = pelletModel.listStatements(pat.getSubject(),pat.getPredicate(),pat.getObject());
|
||||
try {
|
||||
for (ClosableIterator i=ci; i.hasNext();) {
|
||||
Statement stmt = (Statement) i.next();
|
||||
|
||||
boolean reject = false;
|
||||
|
||||
// this next part is only needed if we're using Jena's OWL reasoner instead of actually using Pellet
|
||||
try {
|
||||
if ( ( ((Resource)stmt.getObject()).equals(RDFS.Resource) ) ) {
|
||||
reject = true;
|
||||
} else if ( ( stmt.getSubject().equals(OWL.Nothing) ) ) {
|
||||
reject = true;
|
||||
} else if ( ( stmt.getObject().equals(OWL.Nothing) ) ) {
|
||||
reject = true;
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
|
||||
if (!reject) {
|
||||
tempModel.add(stmt);
|
||||
|
||||
boolean fullModelContainsStatement = false;
|
||||
fullModel.enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
fullModelContainsStatement = fullModel.contains(stmt);
|
||||
} finally {
|
||||
fullModel.leaveCriticalSection();
|
||||
}
|
||||
|
||||
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 {
|
||||
inferenceModel.add(stmt);
|
||||
addCount++;
|
||||
} finally {
|
||||
openPipe();
|
||||
fullModel.leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
ci.close();
|
||||
}
|
||||
} finally {
|
||||
pelletModel.leaveCriticalSection();
|
||||
}
|
||||
|
||||
// now we see what's in the inference model that isn't in the temp model and remove it
|
||||
|
||||
try {
|
||||
Queue<Statement> localRemovalQueue = new LinkedList<Statement>();
|
||||
inferenceModel.enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
ClosableIterator ci = inferenceModel.listStatements(pat.getSubject(),pat.getPredicate(),pat.getObject());
|
||||
try {
|
||||
for (ClosableIterator i=ci; i.hasNext();) {
|
||||
Statement stmt = (Statement) i.next();
|
||||
if (!tempModel.contains(stmt)) {
|
||||
localRemovalQueue.add(stmt);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
ci.close();
|
||||
}
|
||||
} finally {
|
||||
inferenceModel.leaveCriticalSection();
|
||||
}
|
||||
for (Iterator<Statement> i = localRemovalQueue.iterator(); i.hasNext(); ) {
|
||||
fullModel.enterCriticalSection(Lock.WRITE);
|
||||
closePipe();
|
||||
try {
|
||||
retractCount++;
|
||||
inferenceModel.remove(i.next());
|
||||
} finally {
|
||||
openPipe();
|
||||
fullModel.leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
||||
localRemovalQueue.clear();
|
||||
} catch (Exception e) {
|
||||
log.error("Error getting inferences", e);
|
||||
}
|
||||
tempModel = null;
|
||||
}
|
||||
this.pelletListener.isConsistent = true;
|
||||
this.pelletListener.inErrorState = false;
|
||||
this.pelletListener.explanation = "";
|
||||
if (log.isDebugEnabled()) {
|
||||
log.info("Added "+addCount+" statements entailed by assertions");
|
||||
log.info("Retracted "+retractCount+" statements no longer entailed by assertions");
|
||||
log.info("Done getting new inferences: "+(System.currentTimeMillis()-startTime)/1000+" seconds");
|
||||
}
|
||||
} catch (InconsistentOntologyException ioe) {
|
||||
this.pelletListener.isConsistent = false;
|
||||
String explanation = ((PelletInfGraph)pelletModel.getGraph()).getKB().getExplanation();
|
||||
this.pelletListener.explanation = explanation;
|
||||
log.error(ioe);
|
||||
log.error(explanation);
|
||||
} catch (Exception e) {
|
||||
this.pelletListener.inErrorState = true;
|
||||
log.error("Exception during inference", e);
|
||||
} finally {
|
||||
pelletListener.endReasoning();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void getInferences() {
|
||||
this.setDirty(true);
|
||||
if ( this.checkAndStartReasoning() ){
|
||||
if (foreground) {
|
||||
(new InferenceGetter(this)).run();
|
||||
} else {
|
||||
new Thread(new InferenceGetter(this), "PelletListener.InferenceGetter").start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
ObjectPropertyStatementPattern stPat = ObjectPropertyStatementPatternFactory.getPattern(stmt.getSubject(), stmt.getPredicate(), (Resource) stmt.getObject());
|
||||
if (inferenceDrivingPatternDenySet != null) {
|
||||
for (Iterator<ObjectPropertyStatementPattern> i = inferenceDrivingPatternDenySet.iterator(); i.hasNext(); ){
|
||||
ObjectPropertyStatementPattern 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<ObjectPropertyStatementPattern> patList = this.inferenceDrivingPatternMap.get(stmt.getPredicate());
|
||||
if (patList != null) {
|
||||
for (Iterator<ObjectPropertyStatementPattern> i = patList.iterator(); i.hasNext(); ){
|
||||
ObjectPropertyStatementPattern 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;
|
||||
ObjectPropertyStatementPattern stPat = ObjectPropertyStatementPatternFactory.getPattern(stmt.getSubject(), stmt.getPredicate(), (Resource) stmt.getObject());
|
||||
if (inferenceDrivingPatternDenySet != null) {
|
||||
for (Iterator<ObjectPropertyStatementPattern> i = inferenceDrivingPatternDenySet.iterator(); i.hasNext(); ){
|
||||
ObjectPropertyStatementPattern 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<ObjectPropertyStatementPattern> patList = this.inferenceDrivingPatternMap.get(stmt.getPredicate());
|
||||
if (patList != null) {
|
||||
for (Iterator<ObjectPropertyStatementPattern> i = patList.iterator(); i.hasNext(); ){
|
||||
ObjectPropertyStatementPattern 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 {
|
||||
isSynchronizing = true;
|
||||
while (removalModel.size()>0 || additionModel.size()>0) {
|
||||
Model tempModel = ModelFactory.createDefaultModel();
|
||||
removalModel.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
tempModel.add(removalModel);
|
||||
removalModel.removeAll();
|
||||
} finally {
|
||||
removalModel.leaveCriticalSection();
|
||||
}
|
||||
pelletModel.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
pelletModel.remove(tempModel);
|
||||
} finally {
|
||||
pelletModel.leaveCriticalSection();
|
||||
}
|
||||
tempModel.removeAll();
|
||||
additionModel.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
tempModel.add(additionModel);
|
||||
additionModel.removeAll();
|
||||
} finally {
|
||||
additionModel.leaveCriticalSection();
|
||||
}
|
||||
pelletModel.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
pelletModel.add(tempModel);
|
||||
} finally {
|
||||
pelletModel.leaveCriticalSection();
|
||||
}
|
||||
tempModel = null;
|
||||
|
||||
getInferences();
|
||||
|
||||
}
|
||||
} finally {
|
||||
isSynchronizing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -8,12 +8,12 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener;
|
||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerStatus;
|
||||
|
||||
public class IndividualsViaVClassOptions implements FieldOptions {
|
||||
|
||||
|
@ -101,20 +101,13 @@ public class IndividualsViaVClassOptions implements FieldOptions {
|
|||
return individualMap;
|
||||
}
|
||||
|
||||
protected boolean isReasoningAvailable( WebappDaoFactory wDaoFact){
|
||||
boolean inferenceAvailable = false;
|
||||
if (wDaoFact instanceof WebappDaoFactoryJena) {
|
||||
PelletListener pl = ((WebappDaoFactoryJena) wDaoFact).getPelletListener();
|
||||
if (pl != null && pl.isConsistent() && !pl.isInErrorState()
|
||||
&& !pl.isReasoning()) {
|
||||
inferenceAvailable = true;
|
||||
}
|
||||
}
|
||||
return inferenceAvailable;
|
||||
protected boolean isReasoningAvailable(){
|
||||
TBoxReasonerStatus status = ApplicationUtils.instance().getTBoxReasonerModule().getStatus();
|
||||
return status.isConsistent() && !status.isInErrorState();
|
||||
}
|
||||
|
||||
protected Map<String, Individual> addWhenMissingInference( String classUri , WebappDaoFactory wDaoFact ){
|
||||
boolean inferenceAvailable = isReasoningAvailable(wDaoFact);
|
||||
boolean inferenceAvailable = isReasoningAvailable();
|
||||
Map<String,Individual> individualMap = new HashMap<String,Individual>();
|
||||
if ( !inferenceAvailable ) {
|
||||
for (String subclassURI : wDaoFact.getVClassDao().getAllSubClassURIs(classUri)) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import edu.cornell.mannlib.vitro.webapp.application.VitroHomeDirectory;
|
|||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource;
|
||||
|
||||
|
@ -29,6 +30,8 @@ public interface Application {
|
|||
|
||||
ConfigurationTripleSource getConfigurationTripleSource();
|
||||
|
||||
TBoxReasonerModule getTBoxReasonerModule();
|
||||
|
||||
void shutdown();
|
||||
|
||||
public interface Component {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.ontology.Restriction;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.Application;
|
||||
|
||||
/**
|
||||
* A wrapper around the TBox reasoner
|
||||
*/
|
||||
public interface TBoxReasonerModule extends Application.Module {
|
||||
/**
|
||||
* What is the TBox reasoner doing now?
|
||||
*/
|
||||
TBoxReasonerStatus getStatus();
|
||||
|
||||
/**
|
||||
* What restrictions are currently in the reasoner's internal model?
|
||||
*/
|
||||
List<Restriction> listRestrictions();
|
||||
|
||||
/**
|
||||
* Wait until the TBox reasoner becomes quiet.
|
||||
*/
|
||||
void waitForTBoxReasoning();
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner;
|
||||
|
||||
/**
|
||||
* What is the current state of the TBox reasoner?
|
||||
*/
|
||||
public interface TBoxReasonerStatus {
|
||||
/**
|
||||
* Is reasoning in progress based on changes to the TBox?
|
||||
*/
|
||||
boolean isReasoning();
|
||||
|
||||
/**
|
||||
* Is the TBox free of inconsistency?
|
||||
*/
|
||||
boolean isConsistent();
|
||||
|
||||
/**
|
||||
* Did the reasoner fail in its most recent attempt?
|
||||
*/
|
||||
boolean isInErrorState();
|
||||
|
||||
/**
|
||||
* A description of the error state, or an empty string (never null).
|
||||
*/
|
||||
String getExplanation();
|
||||
|
||||
}
|
|
@ -97,13 +97,6 @@ public class FileGraphSetup implements ServletContextListener {
|
|||
OntDocumentManager.getInstance().setProcessImports(false);
|
||||
}
|
||||
|
||||
/*
|
||||
if (isUpdateRequired(ctx)) {
|
||||
log.info("mostSpecificType will be computed because a knowledge base migration was performed." );
|
||||
SimpleReasonerSetup.setMSTComputeRequired(ctx);
|
||||
} else
|
||||
*/
|
||||
|
||||
if ( (aboxChanged || tboxChanged) && !isUpdateRequired(ctx)) {
|
||||
log.info("a full recompute of the Abox will be performed because" +
|
||||
" the filegraph abox(s) and/or tbox(s) have changed or are being read for the first time." );
|
||||
|
|
|
@ -21,12 +21,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
import com.hp.hpl.jena.query.Dataset;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.vocabulary.OWL;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.ReasonerConfiguration;
|
||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
|
||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||
|
@ -51,40 +46,9 @@ public class SimpleReasonerSetup implements ServletContextListener {
|
|||
ServletContext ctx = sce.getServletContext();
|
||||
|
||||
try {
|
||||
// set up Pellet reasoning for the TBox
|
||||
OntModel tboxAssertionsModel = ModelAccess.on(ctx).getOntModel(ModelNames.TBOX_ASSERTIONS);
|
||||
OntModel tboxInferencesModel = ModelAccess.on(ctx).getOntModel(ModelNames.TBOX_INFERENCES);
|
||||
OntModel tboxUnionModel = ModelAccess.on(ctx).getOntModel(ModelNames.TBOX_UNION);
|
||||
log.debug("tboxAssertionsModel=" + tboxAssertionsModel);
|
||||
log.debug("tboxInferencesModel=" + tboxInferencesModel);
|
||||
log.debug("tboxUnionModel=" + tboxUnionModel);
|
||||
|
||||
WebappDaoFactory wadf = ModelAccess.on(ctx).getWebappDaoFactory();
|
||||
|
||||
if (!tboxAssertionsModel.getProfile().NAMESPACE().equals(OWL.NAMESPACE.getNameSpace())) {
|
||||
log.error("Not connecting Pellet reasoner - the TBox assertions model is not an OWL model");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set various Pellet options for incremental consistency checking, etc.
|
||||
//PelletOptions.DL_SAFE_RULES = true;
|
||||
//PelletOptions.USE_COMPLETION_QUEUE = true;
|
||||
//PelletOptions.USE_TRACING = true;
|
||||
//PelletOptions.TRACK_BRANCH_EFFECTS = true;
|
||||
//PelletOptions.USE_INCREMENTAL_CONSISTENCY = true;
|
||||
//PelletOptions.USE_INCREMENTAL_DELETION = true;
|
||||
|
||||
PelletListener pelletListener = new PelletListener(tboxUnionModel,tboxAssertionsModel,tboxInferencesModel,ReasonerConfiguration.DEFAULT);
|
||||
sce.getServletContext().setAttribute("pelletListener",pelletListener);
|
||||
sce.getServletContext().setAttribute("pelletOntModel", pelletListener.getPelletModel());
|
||||
|
||||
if (wadf instanceof WebappDaoFactoryJena) {
|
||||
((WebappDaoFactoryJena) wadf).setPelletListener(pelletListener);
|
||||
}
|
||||
|
||||
log.info("Pellet reasoner connected for the TBox");
|
||||
|
||||
waitForTBoxReasoning(sce);
|
||||
|
||||
// set up simple reasoning for the ABox
|
||||
|
||||
|
@ -139,23 +103,6 @@ public class SimpleReasonerSetup implements ServletContextListener {
|
|||
}
|
||||
}
|
||||
|
||||
public static void waitForTBoxReasoning(ServletContextEvent sce)
|
||||
throws InterruptedException {
|
||||
PelletListener pelletListener = (PelletListener) sce.getServletContext().getAttribute("pelletListener");
|
||||
if (pelletListener == null) {
|
||||
return ;
|
||||
}
|
||||
int sleeps = 0;
|
||||
// sleep at least once to make sure the TBox reasoning gets started
|
||||
while ((0 == sleeps) || ((sleeps < 1000) && pelletListener.isReasoning())) {
|
||||
if (((sleeps - 1) % 10) == 0) { // print message at 10 second intervals
|
||||
log.info("Waiting for initial TBox reasoning to complete");
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
sleeps++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
log.info("received contextDestroyed notification");
|
||||
|
@ -209,17 +156,6 @@ public class SimpleReasonerSetup implements ServletContextListener {
|
|||
return (RecomputeMode) ctx.getAttribute(RECOMPUTE_REQUIRED_ATTR);
|
||||
}
|
||||
|
||||
private static final String MSTCOMPUTE_REQUIRED_ATTR =
|
||||
SimpleReasonerSetup.class.getName() + ".MSTComputeRequired";
|
||||
|
||||
public static void setMSTComputeRequired(ServletContext ctx) {
|
||||
ctx.setAttribute(MSTCOMPUTE_REQUIRED_ATTR, true);
|
||||
}
|
||||
|
||||
private static boolean isMSTComputeRequired(ServletContext ctx) {
|
||||
return (ctx.getAttribute(MSTCOMPUTE_REQUIRED_ATTR) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the names of the plugin classes classes.
|
||||
*
|
||||
|
@ -278,6 +214,7 @@ public class SimpleReasonerSetup implements ServletContextListener {
|
|||
this.simpleReasoner = simpleReasoner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
simpleReasoner.recompute();
|
||||
}
|
||||
|
|
|
@ -89,7 +89,11 @@ public class UpdateKnowledgeBase implements ServletContextListener {
|
|||
putReportingPathsIntoSettings(ctx, settings);
|
||||
putNonReportingPathsIntoSettings(ctx, settings);
|
||||
|
||||
SimpleReasonerSetup.waitForTBoxReasoning(sce);
|
||||
try {
|
||||
ApplicationUtils.instance().getTBoxReasonerModule().waitForTBoxReasoning();
|
||||
} catch (Exception e) {
|
||||
// Should mean that the reasoner is not even started yet.
|
||||
}
|
||||
|
||||
WebappDaoFactory wadf = ModelAccess.on(ctx).getWebappDaoFactory();
|
||||
settings.setDefaultNamespace(wadf.getDefaultNamespace());
|
||||
|
|
|
@ -0,0 +1,349 @@
|
|||
/* $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 java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
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 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.
|
||||
*
|
||||
* Among the criteria for deciding on worthiness is the driving pattern set. In
|
||||
* the constructor, a map is made from this set, to reduce the number of tests
|
||||
* made against each statement. I don't know whether this optimization is
|
||||
* justified.
|
||||
*
|
||||
* 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 AtomicReference<TBoxChanges> changeSet;
|
||||
private final AtomicBoolean suspended;
|
||||
|
||||
public ConfiguredReasonerListener(
|
||||
ReasonerConfiguration reasonerConfiguration,
|
||||
TBoxReasonerDriver reasonerDriver) {
|
||||
this.reasonerConfiguration = reasonerConfiguration;
|
||||
this.reasonerDriver = reasonerDriver;
|
||||
|
||||
this.drivingPatternMap = new DrivingPatternMap(
|
||||
reasonerConfiguration.getInferenceDrivingPatternAllowSet());
|
||||
|
||||
this.changeSet = new AtomicReference<>(new TBoxChanges());
|
||||
this.suspended = new AtomicBoolean();
|
||||
}
|
||||
|
||||
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()) {
|
||||
TBoxChanges changes = changeSet.getAndSet(new TBoxChanges());
|
||||
this.reasonerDriver.runSynchronizer(changes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// 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) {
|
||||
changeSet.get().addStatement(stmt);
|
||||
}
|
||||
|
||||
private void removeIt(Statement stmt) {
|
||||
changeSet.get().removeStatement(stmt);
|
||||
}
|
||||
|
||||
private void deleteObjectProperty(Statement stmt) {
|
||||
changeSet.get().deleteObjectProperty(stmt);
|
||||
}
|
||||
|
||||
private void deleteDataProperty(Statement stmt) {
|
||||
changeSet.get().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,119 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.tboxreasoner;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.ModelFactory;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener;
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener.Suspension;
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern;
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableOntModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedOntModel;
|
||||
|
||||
/**
|
||||
* A tool that will adjust the inferences model to match the reasoner model,
|
||||
* after applying the proper filters to both.
|
||||
*/
|
||||
public class InferenceModelUpdater {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(InferenceModelUpdater.class);
|
||||
|
||||
private final TBoxReasoner reasoner;
|
||||
private final LockableModel lockableInferencesModel;
|
||||
private final LockableOntModel lockableFullModel;
|
||||
private final ConfiguredReasonerListener listener;
|
||||
|
||||
private int addCount;
|
||||
private int retractCount;
|
||||
|
||||
public int getAddCount() {
|
||||
return addCount;
|
||||
}
|
||||
|
||||
public int getRetractCount() {
|
||||
return retractCount;
|
||||
}
|
||||
|
||||
public InferenceModelUpdater(TBoxReasoner reasoner,
|
||||
LockableModel lockableInferencesModel,
|
||||
LockableOntModel lockableFullModel,
|
||||
ConfiguredReasonerListener listener) {
|
||||
this.reasoner = reasoner;
|
||||
this.lockableInferencesModel = lockableInferencesModel;
|
||||
this.lockableFullModel = lockableFullModel;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize the inferences model with the reasoner model, with this
|
||||
* proviso:
|
||||
*
|
||||
* If a statement exists anywhere in the full TBox, don't bother adding it
|
||||
* to the inferences model.
|
||||
*/
|
||||
public void update(List<ReasonerStatementPattern> patternList) {
|
||||
List<Statement> filteredReasonerModel = reasoner
|
||||
.filterResults(patternList);
|
||||
addNewInferences(filteredReasonerModel);
|
||||
removeOldInferences(filterInferencesModel(patternList),
|
||||
filteredReasonerModel);
|
||||
log.debug("Added: " + addCount + ", Retracted: " + retractCount);
|
||||
}
|
||||
|
||||
private void addNewInferences(List<Statement> filteredReasonerModel) {
|
||||
for (Statement stmt : filteredReasonerModel) {
|
||||
if (!fullModelContainsStatement(stmt)) {
|
||||
try (LockedModel inferenceModel = lockableInferencesModel
|
||||
.write(); Suspension susp = listener.suspend()) {
|
||||
inferenceModel.add(stmt);
|
||||
addCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean fullModelContainsStatement(Statement stmt) {
|
||||
try (LockedOntModel fullModel = lockableFullModel.read()) {
|
||||
return fullModel.contains(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
private Model filterInferencesModel(
|
||||
List<ReasonerStatementPattern> patternList) {
|
||||
Model filtered = ModelFactory.createDefaultModel();
|
||||
try (LockedModel inferencesModel = lockableInferencesModel.read()) {
|
||||
for (ReasonerStatementPattern pattern : patternList) {
|
||||
filtered.add(pattern.matchStatementsFromModel(inferencesModel));
|
||||
}
|
||||
}
|
||||
log.debug("Filtered inferences model: " + filtered.size());
|
||||
return filtered;
|
||||
}
|
||||
|
||||
private void removeOldInferences(Model filteredInferencesModel,
|
||||
List<Statement> filteredReasonerStatements) {
|
||||
Model filteredReasonerModel = ModelFactory.createDefaultModel();
|
||||
filteredReasonerModel.add(filteredReasonerStatements);
|
||||
|
||||
for (Statement stmt : filteredInferencesModel.listStatements().toList()) {
|
||||
if (!filteredReasonerModel.contains(stmt)) {
|
||||
try (LockedModel inferenceModel = lockableInferencesModel
|
||||
.write(); Suspension susp = listener.suspend()) {
|
||||
retractCount++;
|
||||
inferenceModel.remove(stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.tboxreasoner;
|
||||
|
||||
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
|
||||
import com.hp.hpl.jena.ontology.DatatypeProperty;
|
||||
import com.hp.hpl.jena.ontology.ObjectProperty;
|
||||
|
||||
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.TBoxReasoner;
|
||||
|
||||
/**
|
||||
* The list of patterns for filtering the models will include:
|
||||
*
|
||||
* All patterns specified by the ReasonerConfiguration,
|
||||
*
|
||||
* One pattern for each deleted property, to match the use of that property as a
|
||||
* predicate.
|
||||
*/
|
||||
public class PatternListBuilder {
|
||||
private static final String OWL_NS = "http://www.w3.org/2002/07/owl#";
|
||||
|
||||
private final ReasonerConfiguration reasonerConfiguration;
|
||||
private final TBoxReasoner reasoner;
|
||||
private final TBoxChanges changes;
|
||||
|
||||
public PatternListBuilder(ReasonerConfiguration reasonerConfiguration,
|
||||
TBoxReasoner reasoner, TBoxChanges changes) {
|
||||
this.reasonerConfiguration = reasonerConfiguration;
|
||||
this.reasoner = reasoner;
|
||||
this.changes = changes;
|
||||
}
|
||||
|
||||
public LinkedList<ReasonerStatementPattern> build() {
|
||||
LinkedList<ReasonerStatementPattern> patterns = new LinkedList<>();
|
||||
|
||||
Set<ReasonerStatementPattern> allowSet = reasonerConfiguration
|
||||
.getInferenceReceivingPatternAllowSet();
|
||||
if (allowSet != null) {
|
||||
patterns.addAll(allowSet);
|
||||
} else {
|
||||
patterns.add(ReasonerStatementPattern.ANY_OBJECT_PROPERTY);
|
||||
}
|
||||
|
||||
if (reasonerConfiguration.getQueryForAllObjectProperties()) {
|
||||
for (ObjectProperty objProp : reasoner.listObjectProperties()) {
|
||||
if (!(OWL_NS.equals(objProp.getNameSpace()))) {
|
||||
patterns.add(ReasonerStatementPattern
|
||||
.objectPattern(objProp));
|
||||
}
|
||||
}
|
||||
|
||||
for (String uri : changes.getDeletedObjectPropertyUris()) {
|
||||
patterns.add(ReasonerStatementPattern
|
||||
.objectPattern(createProperty(uri)));
|
||||
}
|
||||
}
|
||||
|
||||
if (reasonerConfiguration.getQueryForAllDatatypeProperties()) {
|
||||
for (DatatypeProperty dataProp : reasoner.listDatatypeProperties()) {
|
||||
if (!(OWL_NS.equals(dataProp.getNameSpace()))) {
|
||||
// TODO: THIS WILL WORK, BUT NEED TO GENERALIZE THE
|
||||
// PATTERN CLASSES
|
||||
patterns.add(ReasonerStatementPattern
|
||||
.objectPattern(dataProp));
|
||||
}
|
||||
}
|
||||
for (String uri : changes.getDeletedDataPropertyUris()) {
|
||||
patterns.add(ReasonerStatementPattern
|
||||
.objectPattern(createProperty(uri)));
|
||||
}
|
||||
}
|
||||
return patterns;
|
||||
}
|
||||
}
|
|
@ -1,22 +1,22 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet;
|
||||
package edu.cornell.mannlib.vitro.webapp.tboxreasoner;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mindswap.pellet.jena.PelletReasonerFactory;
|
||||
|
||||
import com.hp.hpl.jena.ontology.OntModelSpec;
|
||||
import com.hp.hpl.jena.vocabulary.OWL;
|
||||
import com.hp.hpl.jena.vocabulary.RDF;
|
||||
import com.hp.hpl.jena.vocabulary.RDFS;
|
||||
|
||||
import org.mindswap.pellet.jena.PelletReasonerFactory;
|
||||
|
||||
public class ReasonerConfiguration {
|
||||
|
||||
public Set<ObjectPropertyStatementPattern> inferenceDrivingPatternAllowSet;
|
||||
public Set<ObjectPropertyStatementPattern> inferenceDrivingPatternDenySet;
|
||||
public Set<ObjectPropertyStatementPattern> inferenceReceivingPatternAllowSet;
|
||||
public Set<ReasonerStatementPattern> inferenceDrivingPatternAllowSet;
|
||||
public Set<ReasonerStatementPattern> inferenceDrivingPatternDenySet;
|
||||
public Set<ReasonerStatementPattern> inferenceReceivingPatternAllowSet;
|
||||
|
||||
private boolean queryForAllObjectProperties = false;
|
||||
private boolean incrementalReasoningEnabled = true;
|
||||
|
@ -58,34 +58,34 @@ public class ReasonerConfiguration {
|
|||
|
||||
//ask the reasoner only to classify, realize, and infer disjointWith statements (based on a somewhat incomplete information)
|
||||
DEFAULT = new ReasonerConfiguration();
|
||||
HashSet<ObjectPropertyStatementPattern> defaultInferenceDrivingPatternAllowSet = new HashSet<ObjectPropertyStatementPattern>();
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.type,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDFS.subClassOf,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDFS.subPropertyOf,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.equivalentClass,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.unionOf,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.intersectionOf,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.complementOf,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.oneOf,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.onProperty,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.someValuesFrom,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.allValuesFrom,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.hasValue,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.minCardinality,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.maxCardinality,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.cardinality,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.first,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.rest,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.disjointWith,null));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.inverseOf,null));
|
||||
HashSet<ReasonerStatementPattern> defaultInferenceDrivingPatternAllowSet = new HashSet<>();
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDF.type));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDFS.subClassOf));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDFS.subPropertyOf));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.equivalentClass));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.unionOf));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.intersectionOf));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.complementOf));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.oneOf));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.onProperty));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.someValuesFrom));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.allValuesFrom));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.hasValue));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.minCardinality));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.maxCardinality));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.cardinality));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDF.first));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDF.rest));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.disjointWith));
|
||||
defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.inverseOf));
|
||||
DEFAULT.setInferenceDrivingPatternAllowSet(defaultInferenceDrivingPatternAllowSet);
|
||||
Set<ObjectPropertyStatementPattern> defaultInferenceReceivingPatternAllowSet = new HashSet<ObjectPropertyStatementPattern>();
|
||||
defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.type,null));
|
||||
defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDFS.subClassOf,null));
|
||||
defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDFS.subPropertyOf,null));
|
||||
defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.equivalentClass,null));
|
||||
defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.disjointWith,null));
|
||||
defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.inverseOf,null));
|
||||
Set<ReasonerStatementPattern> defaultInferenceReceivingPatternAllowSet = new HashSet<>();
|
||||
defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDF.type));
|
||||
defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDFS.subClassOf));
|
||||
defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDFS.subPropertyOf));
|
||||
defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.equivalentClass));
|
||||
defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.disjointWith));
|
||||
defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.inverseOf));
|
||||
DEFAULT.setInferenceReceivingPatternAllowSet(defaultInferenceReceivingPatternAllowSet);
|
||||
DEFAULT.setQueryForAllObjectProperties(false);
|
||||
|
||||
|
@ -107,36 +107,36 @@ public class ReasonerConfiguration {
|
|||
COMPLETE.setQueryForAllObjectProperties(true);
|
||||
COMPLETE.setReasonOnAllDatatypePropertyStatements(true);
|
||||
COMPLETE.setQueryForAllDatatypeProperties(true);
|
||||
Set<ObjectPropertyStatementPattern> completeInferenceReceivingPatternAllowSet = new HashSet<ObjectPropertyStatementPattern>();
|
||||
Set<ReasonerStatementPattern> completeInferenceReceivingPatternAllowSet = new HashSet<>();
|
||||
completeInferenceReceivingPatternAllowSet.addAll(defaultInferenceReceivingPatternAllowSet);
|
||||
completeInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null, OWL.sameAs, null));
|
||||
completeInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.sameAs));
|
||||
// getting NPEs inside Pellet with differentFrom on 2.0.0-rc7
|
||||
//completeInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null, OWL.differentFrom, null));
|
||||
//completeInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern( OWL.differentFrom, null));
|
||||
COMPLETE.setInferenceReceivingPatternAllowSet(completeInferenceReceivingPatternAllowSet);
|
||||
|
||||
}
|
||||
|
||||
public Set<ObjectPropertyStatementPattern> getInferenceDrivingPatternAllowSet() {
|
||||
public Set<ReasonerStatementPattern> getInferenceDrivingPatternAllowSet() {
|
||||
return this.inferenceDrivingPatternAllowSet;
|
||||
}
|
||||
|
||||
public void setInferenceDrivingPatternAllowSet(Set<ObjectPropertyStatementPattern> patternSet) {
|
||||
public void setInferenceDrivingPatternAllowSet(Set<ReasonerStatementPattern> patternSet) {
|
||||
this.inferenceDrivingPatternAllowSet = patternSet;
|
||||
}
|
||||
|
||||
public Set<ObjectPropertyStatementPattern> getInferenceDrivingPatternDenySet() {
|
||||
public Set<ReasonerStatementPattern> getInferenceDrivingPatternDenySet() {
|
||||
return this.inferenceDrivingPatternDenySet;
|
||||
}
|
||||
|
||||
public void setInferenceDrivingPatternDenySet(Set<ObjectPropertyStatementPattern> patternSet) {
|
||||
public void setInferenceDrivingPatternDenySet(Set<ReasonerStatementPattern> patternSet) {
|
||||
this.inferenceDrivingPatternDenySet = patternSet;
|
||||
}
|
||||
|
||||
public Set<ObjectPropertyStatementPattern> getInferenceReceivingPatternAllowSet() {
|
||||
public Set<ReasonerStatementPattern> getInferenceReceivingPatternAllowSet() {
|
||||
return this.inferenceReceivingPatternAllowSet;
|
||||
}
|
||||
|
||||
public void setInferenceReceivingPatternAllowSet(Set<ObjectPropertyStatementPattern> patternSet) {
|
||||
public void setInferenceReceivingPatternAllowSet(Set<ReasonerStatementPattern> patternSet) {
|
||||
this.inferenceReceivingPatternAllowSet = patternSet;
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.tboxreasoner;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
import com.hp.hpl.jena.shared.Lock;
|
||||
|
||||
/**
|
||||
* For now, this only models Object Properties.
|
||||
*
|
||||
* It should be easy to add Data Property patterns by making this abstract and
|
||||
* creating two concrete subclasses.
|
||||
*/
|
||||
public class ReasonerStatementPattern {
|
||||
public static final ReasonerStatementPattern ANY_OBJECT_PROPERTY = new ReasonerStatementPattern(
|
||||
null, null, null);
|
||||
|
||||
public static ReasonerStatementPattern objectPattern(Property predicate) {
|
||||
return new ReasonerStatementPattern(null, predicate, null);
|
||||
}
|
||||
|
||||
public static ReasonerStatementPattern objectPattern(Statement stmt) {
|
||||
if (!stmt.getObject().isResource()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Object of stmt must be a resource.");
|
||||
}
|
||||
return new ReasonerStatementPattern(stmt.getSubject(),
|
||||
stmt.getPredicate(), stmt.getObject().asResource());
|
||||
}
|
||||
|
||||
/**
|
||||
* Any or all of these may be null, which acts as a wild card.
|
||||
*/
|
||||
private final Resource subject;
|
||||
private final Property predicate;
|
||||
private final Resource object;
|
||||
private final String toString;
|
||||
|
||||
private ReasonerStatementPattern(Resource subject, Property predicate,
|
||||
Resource object) {
|
||||
this.subject = subject;
|
||||
this.predicate = predicate;
|
||||
this.object = object;
|
||||
this.toString = buildToString();
|
||||
}
|
||||
|
||||
public Property getPredicate() {
|
||||
return predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* All fields must match, either by being equal, or by being a wild card.
|
||||
*/
|
||||
public boolean matches(ReasonerStatementPattern that) {
|
||||
boolean sMatch = this.subject == null || that.subject == null
|
||||
|| this.subject.equals(that.subject);
|
||||
boolean pMatch = this.predicate == null || that.predicate == null
|
||||
|| this.predicate.equals(that.predicate);
|
||||
boolean oMatch = this.object == null || that.object == null
|
||||
|| this.object.equals(that.object);
|
||||
return sMatch && pMatch && oMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of statements from this model that match this pattern.
|
||||
*/
|
||||
public List<Statement> matchStatementsFromModel(Model m) {
|
||||
m.enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
return m.listStatements(subject, predicate, object).toList();
|
||||
} finally {
|
||||
m.leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
||||
public String buildToString() {
|
||||
return "ReasonerStatementPattern[subject="
|
||||
+ (subject == null ? "*" : subject.toString()) + ", predicate="
|
||||
+ (predicate == null ? "*" : predicate.toString())
|
||||
+ ", object=" + (object == null ? "*" : object.toString())
|
||||
+ "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.tboxreasoner;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.ontology.DatatypeProperty;
|
||||
import com.hp.hpl.jena.ontology.ObjectProperty;
|
||||
import com.hp.hpl.jena.ontology.Restriction;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
|
||||
/**
|
||||
* The functionality of a TBox reasoner.
|
||||
*
|
||||
* The reasoner will maintain its own TBox model. It will receive updates to
|
||||
* that model and perform reasoning on it. It will answer queries about the
|
||||
* contents of the model, when reasoning is complete.
|
||||
*/
|
||||
public interface TBoxReasoner {
|
||||
|
||||
/**
|
||||
* Add the additions and remove the removals.
|
||||
*/
|
||||
void updateReasonerModel(TBoxChanges changes);
|
||||
|
||||
/**
|
||||
* Chew on it and create the inferences. Report status.
|
||||
*/
|
||||
Status performReasoning();
|
||||
|
||||
/**
|
||||
* List all of the ObjectProperties from the reasoner model, after updating
|
||||
* and reasoning.
|
||||
*/
|
||||
List<ObjectProperty> listObjectProperties();
|
||||
|
||||
/**
|
||||
* List all of the DatatypeProperties from the reasoner model, after
|
||||
* updating and reasoning.
|
||||
*/
|
||||
List<DatatypeProperty> listDatatypeProperties();
|
||||
|
||||
/**
|
||||
* List all of the restrictions in the reasoner model, after updating and
|
||||
* reasoning.
|
||||
*/
|
||||
List<Restriction> listRestrictions();
|
||||
|
||||
/**
|
||||
* List all of the statements that satisfy any of these patterns, after
|
||||
* updating and reasoning.
|
||||
*/
|
||||
List<Statement> filterResults(List<ReasonerStatementPattern> patternList);
|
||||
|
||||
public static class Status {
|
||||
public static final Status SUCCESS = new Status(true, false, "");
|
||||
public static final Status ERROR = new Status(true, true, "");
|
||||
|
||||
public static final Status inconsistent(String explanation) {
|
||||
return new Status(false, false, explanation);
|
||||
}
|
||||
|
||||
private final boolean consistent;
|
||||
private final boolean inErrorState;
|
||||
private final String explanation;
|
||||
|
||||
private Status(boolean consistent, boolean inErrorState,
|
||||
String explanation) {
|
||||
this.consistent = consistent;
|
||||
this.inErrorState = inErrorState;
|
||||
this.explanation = explanation;
|
||||
}
|
||||
|
||||
public boolean isConsistent() {
|
||||
return consistent;
|
||||
}
|
||||
|
||||
public boolean isInErrorState() {
|
||||
return inErrorState;
|
||||
}
|
||||
|
||||
public String getExplanation() {
|
||||
return explanation;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.tboxreasoner;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerStatus;
|
||||
|
||||
|
||||
/**
|
||||
* What calls can the ConfiguredReasonerListener make to drive the TBox
|
||||
* reasoner?
|
||||
*/
|
||||
public interface TBoxReasonerDriver {
|
||||
|
||||
void runSynchronizer(TBoxChanges changeSet);
|
||||
|
||||
TBoxReasonerStatus getStatus();
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread.WorkLevel.IDLE;
|
||||
import static edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread.WorkLevel.WORKING;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener;
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.InferenceModelUpdater;
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.PatternListBuilder;
|
||||
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.TBoxReasoner;
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner.Status;
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableOntModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedOntModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread;
|
||||
|
||||
/**
|
||||
* The basic implementation of the TBoxReasonerDriver. It gets help from a
|
||||
* listener, an executor, and a reasoner.
|
||||
*
|
||||
* Create a listener that listens for changes to the TBox, but filters them
|
||||
* according to a ReasonerConfiguration object. The listener accumulates the
|
||||
* changes it likes, until it detects an ending EditEvent. Then it passes the
|
||||
* change set back to the driver.
|
||||
*
|
||||
* Each time a change set is received, a task is created and given to the
|
||||
* executor to run. The executor is single-threaded, so the change sets are
|
||||
* processed in sequence.
|
||||
*
|
||||
* Processing involves the following steps:
|
||||
*
|
||||
* 1. Telling the reasoner about the changes, so it can update its own internal
|
||||
* ontology model.
|
||||
*
|
||||
* 2. Telling the reasoner to re-inference its model. A status is returned.
|
||||
*
|
||||
* 3. Asking the reasoner for the inferences from its model. As with the initial
|
||||
* changes, these inferences are filtered according to the
|
||||
* ReasonerConfiguration.
|
||||
*
|
||||
* 4. Synchronizing the applications TBox inferences model with the inferences
|
||||
* obtained from the reasoner.
|
||||
*
|
||||
* ----------------------
|
||||
*
|
||||
* Possible optimization: if change sets come in quickly enough that the third
|
||||
* set is received while the first is still being processed, it would be
|
||||
* reasonable to merge the second and third sets into one.
|
||||
*/
|
||||
public class BasicTBoxReasonerDriver implements TBoxReasonerDriver {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(BasicTBoxReasonerDriver.class);
|
||||
|
||||
private final LockableOntModel lockableAssertionsModel;
|
||||
private final LockableModel lockableInferencesModel;
|
||||
private final LockableOntModel lockableFullModel;
|
||||
|
||||
private final ReasonerConfiguration reasonerConfiguration;
|
||||
|
||||
private final ConfiguredReasonerListener listener;
|
||||
|
||||
private final Set<TBoxChanges> pendingChangeSets;
|
||||
|
||||
private final ExecutorService executorService;
|
||||
|
||||
private final TBoxReasoner reasoner;
|
||||
|
||||
private TBoxReasoner.Status innerStatus;
|
||||
|
||||
public BasicTBoxReasonerDriver(OntModel assertionsModel,
|
||||
Model inferencesModel, OntModel fullModel, TBoxReasoner reasoner,
|
||||
ReasonerConfiguration reasonerConfiguration) {
|
||||
this.lockableAssertionsModel = new LockableOntModel(assertionsModel);
|
||||
this.lockableInferencesModel = new LockableModel(inferencesModel);
|
||||
this.lockableFullModel = new LockableOntModel(fullModel);
|
||||
this.reasoner = reasoner;
|
||||
this.reasonerConfiguration = reasonerConfiguration;
|
||||
|
||||
this.listener = new ConfiguredReasonerListener(reasonerConfiguration,
|
||||
this);
|
||||
|
||||
this.pendingChangeSets = Collections
|
||||
.synchronizedSet(new HashSet<TBoxChanges>());
|
||||
|
||||
this.executorService = Executors.newFixedThreadPool(1,
|
||||
new VitroBackgroundThread.Factory("TBoxReasoner"));
|
||||
|
||||
assertionsModel.getBaseModel().register(listener);
|
||||
fullModel.getBaseModel().register(listener);
|
||||
|
||||
doInitialReasoning();
|
||||
}
|
||||
|
||||
private void doInitialReasoning() {
|
||||
try (LockedOntModel assertionsModel = lockableAssertionsModel.read()) {
|
||||
for (ReasonerStatementPattern pat : reasonerConfiguration
|
||||
.getInferenceDrivingPatternAllowSet()) {
|
||||
listener.addedStatements(assertionsModel.listStatements(
|
||||
(Resource) null, pat.getPredicate(), (RDFNode) null));
|
||||
}
|
||||
}
|
||||
listener.notifyEvent(null, new EditEvent(null, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TBoxReasonerStatus getStatus() {
|
||||
return new FullStatus(innerStatus, !pendingChangeSets.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runSynchronizer(TBoxChanges changeSet) {
|
||||
if (!changeSet.isEmpty()) {
|
||||
executorService.execute(new ReasoningTask(changeSet));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down the thread that runs the reasoning tasks. Don't wait longer
|
||||
* than 1 minute.
|
||||
*/
|
||||
public void shutdown() {
|
||||
executorService.shutdown();
|
||||
int waited = 0;
|
||||
while (waited < 60 && !executorService.isTerminated()) {
|
||||
try {
|
||||
log.info("Waiting for TBox reasoner to terminate.");
|
||||
executorService.awaitTermination(5, TimeUnit.SECONDS);
|
||||
waited += 5;
|
||||
} catch (InterruptedException e) {
|
||||
// Should never happen.
|
||||
e.printStackTrace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!executorService.isTerminated()) {
|
||||
log.warn("Forcing TBox reasoner to terminate.");
|
||||
executorService.shutdownNow();
|
||||
}
|
||||
if (!executorService.isTerminated()) {
|
||||
log.error("TBox reasoner did not terminate.");
|
||||
}
|
||||
}
|
||||
|
||||
private class ReasoningTask implements Runnable {
|
||||
private final TBoxChanges changes;
|
||||
private List<ReasonerStatementPattern> patternList;
|
||||
|
||||
public ReasoningTask(TBoxChanges changes) {
|
||||
this.changes = changes;
|
||||
pendingChangeSets.add(changes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
setWorking();
|
||||
|
||||
reasoner.updateReasonerModel(changes);
|
||||
innerStatus = reasoner.performReasoning();
|
||||
|
||||
buildPatternList();
|
||||
updateInferencesModel();
|
||||
|
||||
setIdle();
|
||||
} finally {
|
||||
pendingChangeSets.remove(changes);
|
||||
}
|
||||
}
|
||||
|
||||
private void setWorking() {
|
||||
Thread current = Thread.currentThread();
|
||||
if (current instanceof VitroBackgroundThread) {
|
||||
((VitroBackgroundThread) current).setWorkLevel(WORKING);
|
||||
}
|
||||
}
|
||||
|
||||
private void setIdle() {
|
||||
Thread current = Thread.currentThread();
|
||||
if (current instanceof VitroBackgroundThread) {
|
||||
((VitroBackgroundThread) current).setWorkLevel(IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildPatternList() {
|
||||
PatternListBuilder patternListBuilder = new PatternListBuilder(
|
||||
reasonerConfiguration, reasoner, changes);
|
||||
this.patternList = patternListBuilder.build();
|
||||
}
|
||||
|
||||
private void updateInferencesModel() {
|
||||
InferenceModelUpdater inferenceModelUpdater = new InferenceModelUpdater(
|
||||
reasoner, lockableInferencesModel, lockableFullModel,
|
||||
listener);
|
||||
inferenceModelUpdater.update(patternList);
|
||||
}
|
||||
}
|
||||
|
||||
private static class FullStatus implements TBoxReasonerStatus {
|
||||
private final TBoxReasoner.Status reasonerStatus;
|
||||
private final boolean reasoning;
|
||||
|
||||
public FullStatus(Status reasonerStatus, boolean reasoning) {
|
||||
this.reasonerStatus = reasonerStatus;
|
||||
this.reasoning = reasoning;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReasoning() {
|
||||
return reasoning;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConsistent() {
|
||||
return reasonerStatus.isConsistent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInErrorState() {
|
||||
return reasonerStatus.isInErrorState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExplanation() {
|
||||
String explanation = reasonerStatus.getExplanation();
|
||||
return explanation == null ? "" : explanation;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.pellet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.mindswap.pellet.exceptions.InconsistentOntologyException;
|
||||
import org.mindswap.pellet.jena.PelletInfGraph;
|
||||
|
||||
import com.hp.hpl.jena.ontology.DatatypeProperty;
|
||||
import com.hp.hpl.jena.ontology.ObjectProperty;
|
||||
import com.hp.hpl.jena.ontology.Restriction;
|
||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
import com.hp.hpl.jena.vocabulary.OWL;
|
||||
import com.hp.hpl.jena.vocabulary.RDFS;
|
||||
|
||||
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.TBoxReasoner;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableOntModel;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedOntModel;
|
||||
|
||||
/**
|
||||
* An implementation the TBoxReasonerWrapper for Pellet.
|
||||
*/
|
||||
public class PelletTBoxReasoner implements TBoxReasoner {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(PelletTBoxReasoner.class);
|
||||
|
||||
private final LockableOntModel lockablePelletModel;
|
||||
|
||||
public PelletTBoxReasoner(ReasonerConfiguration reasonerConfiguration) {
|
||||
this.lockablePelletModel = new LockableOntModel(
|
||||
ModelFactory.createOntologyModel(reasonerConfiguration
|
||||
.getOntModelSpec()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateReasonerModel(TBoxChanges changes) {
|
||||
try (LockedOntModel pelletModel = lockablePelletModel.write()) {
|
||||
pelletModel.remove(changes.getRemovedStatements());
|
||||
pelletModel.add(changes.getAddedStatements());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status performReasoning() {
|
||||
try (LockedOntModel pelletModel = lockablePelletModel.write()) {
|
||||
try {
|
||||
pelletModel.rebind();
|
||||
pelletModel.prepare();
|
||||
return Status.SUCCESS;
|
||||
} catch (InconsistentOntologyException ioe) {
|
||||
String explanation = ((PelletInfGraph) pelletModel.getGraph())
|
||||
.getKB().getExplanation();
|
||||
log.error(ioe);
|
||||
log.error(explanation);
|
||||
return Status.inconsistent(explanation);
|
||||
} catch (Exception e) {
|
||||
log.error("Exception during inference", e);
|
||||
return Status.ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ObjectProperty> listObjectProperties() {
|
||||
try (LockedOntModel pelletModel = lockablePelletModel.read()) {
|
||||
return pelletModel.listObjectProperties().toList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DatatypeProperty> listDatatypeProperties() {
|
||||
try (LockedOntModel pelletModel = lockablePelletModel.read()) {
|
||||
return pelletModel.listDatatypeProperties().toList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Statement> filterResults(
|
||||
List<ReasonerStatementPattern> patternList) {
|
||||
List<Statement> filtered = new ArrayList<>();
|
||||
try (LockedOntModel pelletModel = lockablePelletModel.read()) {
|
||||
for (ReasonerStatementPattern pattern : patternList) {
|
||||
filtered.addAll(pattern.matchStatementsFromModel(pelletModel));
|
||||
}
|
||||
}
|
||||
for (Iterator<Statement> fit = filtered.iterator(); fit.hasNext(); ) {
|
||||
Statement stmt = fit.next();
|
||||
if (stmt.getObject().equals(RDFS.Resource)) {
|
||||
fit.remove();
|
||||
} else if (stmt.getSubject().equals(OWL.Nothing)) {
|
||||
fit.remove();
|
||||
} else if (stmt.getObject().equals(OWL.Nothing)) {
|
||||
fit.remove();
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Restriction> listRestrictions() {
|
||||
try (LockedOntModel pelletModel = lockablePelletModel.read()) {
|
||||
return pelletModel.listRestrictions().toList();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.pellet;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_ASSERTIONS;
|
||||
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_INFERENCES;
|
||||
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_UNION;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
import com.hp.hpl.jena.ontology.Restriction;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess;
|
||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.Application;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration;
|
||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.BasicTBoxReasonerDriver;
|
||||
|
||||
/**
|
||||
* Configure a Pellet reasoner on the TBox.
|
||||
*/
|
||||
public class PelletTBoxReasonerModule implements TBoxReasonerModule {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(PelletTBoxReasonerModule.class);
|
||||
|
||||
private PelletTBoxReasoner reasoner;
|
||||
private BasicTBoxReasonerDriver driver;
|
||||
|
||||
@Override
|
||||
public void startup(Application application, ComponentStartupStatus ss) {
|
||||
ServletContext ctx = application.getServletContext();
|
||||
|
||||
ContextModelAccess contextModels = ModelAccess.on(ctx);
|
||||
OntModel tboxAssertionsModel = contextModels
|
||||
.getOntModel(TBOX_ASSERTIONS);
|
||||
Model tboxInferencesModel = contextModels.getOntModel(TBOX_INFERENCES)
|
||||
.getBaseModel();
|
||||
OntModel tboxUnionModel = contextModels.getOntModel(TBOX_UNION);
|
||||
|
||||
reasoner = new PelletTBoxReasoner(ReasonerConfiguration.DEFAULT);
|
||||
driver = new BasicTBoxReasonerDriver(tboxAssertionsModel,
|
||||
tboxInferencesModel, tboxUnionModel, reasoner,
|
||||
ReasonerConfiguration.DEFAULT);
|
||||
|
||||
ss.info("Pellet reasoner connected for the TBox");
|
||||
|
||||
waitForTBoxReasoning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TBoxReasonerStatus getStatus() {
|
||||
if (driver == null) {
|
||||
throw new IllegalStateException(
|
||||
"PelletTBoxReasonerModule has not been started.");
|
||||
}
|
||||
return driver.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Restriction> listRestrictions() {
|
||||
if (reasoner == null) {
|
||||
throw new IllegalStateException(
|
||||
"PelletTBoxReasonerModule has not been started.");
|
||||
}
|
||||
return reasoner.listRestrictions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown(Application application) {
|
||||
driver.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForTBoxReasoning() {
|
||||
int sleeps = 0;
|
||||
// sleep at least once to make sure the TBox reasoning gets started
|
||||
while ((0 == sleeps)
|
||||
|| ((sleeps < 1000) && getStatus().isReasoning())) {
|
||||
if (((sleeps - 1) % 10) == 0) { // print message at 10 second
|
||||
// intervals
|
||||
log.info("Waiting for initial TBox reasoning to complete");
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// This should never happen.
|
||||
e.printStackTrace();
|
||||
}
|
||||
sleeps++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,8 @@ import java.util.Collections;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
@ -106,4 +108,25 @@ public class VitroBackgroundThread extends Thread {
|
|||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory class, for use in Executors, that creates threads with
|
||||
* successive names.
|
||||
*/
|
||||
public static class Factory implements ThreadFactory{
|
||||
private final String threadName;
|
||||
private final AtomicInteger index;
|
||||
|
||||
public Factory(String threadName) {
|
||||
this.threadName = threadName;
|
||||
this.index = new AtomicInteger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new VitroBackgroundThread(r, threadName + "_" + index.getAndIncrement());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import edu.cornell.mannlib.vitro.webapp.modules.Application;
|
|||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource;
|
||||
|
||||
|
@ -101,4 +102,11 @@ public class ApplicationStub implements Application {
|
|||
"ApplicationStub.getConfigurationTripleSource() not implemented.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TBoxReasonerModule getTBoxReasonerModule() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new RuntimeException("ApplicationStub.getTBoxReasonerModule() not implemented.");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.RemoveObsoletePermissions
|
|||
|
||||
edu.cornell.mannlib.vitro.webapp.servlet.setup.FileGraphSetup
|
||||
|
||||
edu.cornell.mannlib.vitro.webapp.application.ApplicationImpl$ReasonersSetup
|
||||
edu.cornell.mannlib.vitro.webapp.servlet.setup.SimpleReasonerSetup
|
||||
|
||||
#edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdateKnowledgeBase
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
<section class="pageBodyGroup" role="region">
|
||||
<h3>${i18n().ontology_editor}</h3>
|
||||
|
||||
<#if ontologyEditor.pellet?has_content>
|
||||
<#if ontologyEditor.tboxReasonerStatus?has_content>
|
||||
<div class="notice">
|
||||
<p>${ontologyEditor.pellet.error}</p>
|
||||
<#if ontologyEditor.pellet.explanation?has_content>
|
||||
<p>${i18n().cause} ${ontologyEditor.pellet.explanation}</p>
|
||||
<p>${ontologyEditor.tboxReasonerStatus.error}</p>
|
||||
<#if ontologyEditor.tboxReasonerStatus.explanation?has_content>
|
||||
<p>${i18n().cause} ${ontologyEditor.tboxReasonerStatus.explanation}</p>
|
||||
</#if>
|
||||
</div>
|
||||
</#if>
|
||||
|
|
Loading…
Add table
Reference in a new issue