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:
Jim Blake 2014-12-08 10:54:07 -05:00
parent adf04bd2be
commit 4b71c1d6bb
32 changed files with 1526 additions and 986 deletions

View file

@ -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.

View file

@ -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);
}
}
}

View file

@ -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>();

View file

@ -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();

View file

@ -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) {

View file

@ -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;

View file

@ -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>();

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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)) {

View file

@ -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 {

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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." );

View file

@ -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();
}

View file

@ -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());

View file

@ -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));
}
}

View file

@ -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);
}
}
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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();
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}
}

View file

@ -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++;
}
}
}

View file

@ -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());
}
}
}

View file

@ -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.");
}
}

View file

@ -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

View file

@ -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>