VIVO-778 Wild restructuring

Create TBoxChanges, createTBoxReasonerDriver, delete PelletListener, deal with repercussions all over.
This commit is contained in:
Jim Blake 2014-12-03 09:46:25 -05:00
parent 4e15695281
commit 24bce9ff67
15 changed files with 517 additions and 466 deletions

View file

@ -24,9 +24,10 @@ 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.search.controller.IndexController;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver.Status;
public class BaseSiteAdminController extends FreemarkerHttpServlet {
@ -161,13 +162,13 @@ public class BaseSiteAdminController extends FreemarkerHttpServlet {
String pelletError = null;
String pelletExplanation = null;
Object plObj = getServletContext().getAttribute("pelletListener");
if ( (plObj != null) && (plObj instanceof PelletListener) ) {
PelletListener pelletListener = (PelletListener) plObj;
if (!pelletListener.isConsistent()) {
Object tbrObj = getServletContext().getAttribute("tboxReasoner");
if ( tbrObj instanceof TBoxReasonerDriver) {
Status status = ((TBoxReasonerDriver) tbrObj).getStatus();
if (!status.isConsistent()) {
pelletError = "INCONSISTENT ONTOLOGY: reasoning halted.";
pelletExplanation = pelletListener.getExplanation();
} else if ( pelletListener.isInErrorState() ) {
pelletExplanation = status.getExplanation();
} else if ( status.isInErrorState() ) {
pelletError = "An error occurred during reasoning. Reasoning has been halted. See error log for details.";
}
}

View file

@ -48,6 +48,7 @@ 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.tboxreasoner.TBoxReasonerWrapper;
public class JenaAdminActions extends BaseEditController {
@ -190,8 +191,8 @@ public class JenaAdminActions extends BaseEditController {
}
private void printRestrictions() {
OntModel memoryModel = (OntModel) getServletContext().getAttribute("pelletOntModel");
for (Restriction rest : memoryModel.listRestrictions().toList() ) {
TBoxReasonerWrapper reasoner = (TBoxReasonerWrapper) getServletContext().getAttribute("tboxReasonerWrapper");
for (Restriction rest : reasoner.listRestrictions() ) {
//System.out.println();
if (rest.isAllValuesFromRestriction()) {
log.trace("All values from: ");

View file

@ -51,8 +51,8 @@ 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.rdfservice.RDFService;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
public class DataPropertyDaoJena extends PropertyDaoJena implements
DataPropertyDao {
@ -357,9 +357,9 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements
}
protected boolean reasoningAvailable() {
PelletListener pl = getWebappDaoFactory().getPelletListener();
TBoxReasonerDriver pl = getWebappDaoFactory().getTBoxReasonerDriver();
return !(
( pl == null || !pl.isConsistent() || pl.isInErrorState() )
( pl == null || !pl.getStatus().isConsistent() || pl.getStatus().isInErrorState() )
);
}

View file

@ -47,10 +47,10 @@ 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;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
import edu.cornell.mannlib.vitro.webapp.utils.jena.URIUtils;
public class WebappDaoFactoryJena implements WebappDaoFactory {
@ -70,7 +70,7 @@ public class WebappDaoFactoryJena implements WebappDaoFactory {
protected WebappDaoFactoryConfig config;
protected PelletListener pelletListener;
protected TBoxReasonerDriver tbrd;
protected String userURI;
@ -242,12 +242,12 @@ public class WebappDaoFactoryJena implements WebappDaoFactory {
* 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 void setTBoxReasonerDriver(TBoxReasonerDriver tbrd) {
this.tbrd = tbrd;
}
public PelletListener getPelletListener() {
return this.pelletListener;
public TBoxReasonerDriver getTBoxReasonerDriver() {
return this.tbrd;
}
@Override

View file

@ -2,21 +2,19 @@
package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet;
import java.util.LinkedList;
import java.util.List;
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.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.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.TBoxReasonerWrapper;
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;
@ -30,8 +28,8 @@ public class InferenceModelUpdater {
private static final Log log = LogFactory
.getLog(InferenceModelUpdater.class);
private final LockableOntModel lockableReasonerModel;
private final LockableModel lockableInferenceModel;
private final TBoxReasonerWrapper reasoner;
private final LockableModel lockableInferencesModel;
private final LockableOntModel lockableFullModel;
private final ConfiguredReasonerListener listener;
@ -46,57 +44,36 @@ public class InferenceModelUpdater {
return retractCount;
}
public InferenceModelUpdater(OntModel reasonerModel, Model inferenceModel,
OntModel fullModel, ConfiguredReasonerListener listener) {
this.lockableReasonerModel = new LockableOntModel(reasonerModel);
this.lockableInferenceModel = new LockableModel(inferenceModel);
this.lockableFullModel = new LockableOntModel(fullModel);
public InferenceModelUpdater(TBoxReasonerWrapper 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 these
* provisos:
*
* Statements in the reasoner model about RDFS.Resource or OWL.Nothing are
* ignored.
* 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(LinkedList<ReasonerStatementPattern> patternList) {
Model filteredReasonerModel = filterReasonerModel(patternList);
public void update(List<ReasonerStatementPattern> patternList) {
List<Statement> filteredReasonerModel = reasoner
.filterResults(patternList);
addNewInferences(filteredReasonerModel);
removeOldInferences(filterInferencesModel(patternList),
filteredReasonerModel);
log.warn("Added: " + addCount + ", Retracted: " + retractCount);
}
private Model filterReasonerModel(
LinkedList<ReasonerStatementPattern> patternList) {
Model filtered = ModelFactory.createDefaultModel();
try (LockedOntModel reasonerModel = lockableReasonerModel.read()) {
for (ReasonerStatementPattern pattern : patternList) {
filtered.add(pattern.matchStatementsFromModel(reasonerModel));
}
}
for (Statement stmt : filtered.listStatements().toList()) {
if (stmt.getObject().equals(RDFS.Resource)) {
filtered.remove(stmt);
} else if (stmt.getSubject().equals(OWL.Nothing)) {
filtered.remove(stmt);
} else if (stmt.getObject().equals(OWL.Nothing)) {
filtered.remove(stmt);
}
}
log.warn("Filtered reasoner model: " + filtered.size());
return filtered;
}
private void addNewInferences(Model filteredReasonerModel) {
for (Statement stmt : filteredReasonerModel.listStatements().toList()) {
private void addNewInferences(List<Statement> filteredReasonerModel) {
for (Statement stmt : filteredReasonerModel) {
if (!fullModelContainsStatement(stmt)) {
try (LockedModel inferenceModel = lockableInferenceModel
try (LockedModel inferenceModel = lockableInferencesModel
.write(); Suspension susp = listener.suspend()) {
inferenceModel.add(stmt);
addCount++;
@ -112,11 +89,11 @@ public class InferenceModelUpdater {
}
private Model filterInferencesModel(
LinkedList<ReasonerStatementPattern> patternList) {
List<ReasonerStatementPattern> patternList) {
Model filtered = ModelFactory.createDefaultModel();
try (LockedOntModel reasonerModel = lockableReasonerModel.read()) {
try (LockedModel inferencesModel = lockableInferencesModel.read()) {
for (ReasonerStatementPattern pattern : patternList) {
filtered.add(pattern.matchStatementsFromModel(reasonerModel));
filtered.add(pattern.matchStatementsFromModel(inferencesModel));
}
}
log.warn("Filtered inferences model: " + filtered.size());
@ -124,10 +101,13 @@ public class InferenceModelUpdater {
}
private void removeOldInferences(Model filteredInferencesModel,
Model filteredReasonerModel) {
List<Statement> filteredReasonerStatements) {
Model filteredReasonerModel = ModelFactory.createDefaultModel();
filteredReasonerModel.add(filteredReasonerStatements);
for (Statement stmt : filteredInferencesModel.listStatements().toList()) {
if (!filteredReasonerModel.contains(stmt)) {
try (LockedModel inferenceModel = lockableInferenceModel
try (LockedModel inferenceModel = lockableInferencesModel
.write(); Suspension susp = listener.suspend()) {
retractCount++;
inferenceModel.remove(stmt);

View file

@ -9,16 +9,11 @@ import java.util.Set;
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.Model;
import com.hp.hpl.jena.rdf.model.Resource;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern;
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;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxChanges;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerWrapper;
/**
* The list of patterns for filtering the models will include:
@ -32,79 +27,55 @@ public class PatternListBuilder {
private static final String OWL_NS = "http://www.w3.org/2002/07/owl#";
private final ReasonerConfiguration reasonerConfiguration;
private final LockableOntModel lockableReasonerModel;
private final LockableModel lockableDeletedObjectProperties;
private final LockableModel lockableDeletedDataProperties;
private final TBoxReasonerWrapper reasoner;
private final TBoxChanges changes;
public PatternListBuilder(ReasonerConfiguration reasonerConfiguration,
OntModel reasonerModel, Model deletedObjectProperties,
Model deletedDataProperties) {
TBoxReasonerWrapper reasoner, TBoxChanges changes) {
this.reasonerConfiguration = reasonerConfiguration;
this.lockableReasonerModel = new LockableOntModel(reasonerModel);
this.lockableDeletedObjectProperties = new LockableModel(
deletedObjectProperties);
this.lockableDeletedDataProperties = new LockableModel(
deletedDataProperties);
this.reasoner = reasoner;
this.changes = changes;
}
/**
* @return
*/
public LinkedList<ReasonerStatementPattern> build() {
LinkedList<ReasonerStatementPattern> irpl = new LinkedList<>();
LinkedList<ReasonerStatementPattern> patterns = new LinkedList<>();
Set<ReasonerStatementPattern> allowSet = reasonerConfiguration
.getInferenceReceivingPatternAllowSet();
if (allowSet != null) {
irpl.addAll(allowSet);
patterns.addAll(allowSet);
} else {
irpl.add(ReasonerStatementPattern.ANY_OBJECT_PROPERTY);
patterns.add(ReasonerStatementPattern.ANY_OBJECT_PROPERTY);
}
if (reasonerConfiguration.getQueryForAllObjectProperties()) {
try (LockedOntModel reasonerModel = lockableReasonerModel.read()) {
for (ObjectProperty objProp : reasonerModel
.listObjectProperties().toList()) {
for (ObjectProperty objProp : reasoner.listObjectProperties()) {
if (!(OWL_NS.equals(objProp.getNameSpace()))) {
irpl.add(ReasonerStatementPattern
patterns.add(ReasonerStatementPattern
.objectPattern(objProp));
}
}
}
try (LockedModel deletedObjectProperties = lockableDeletedObjectProperties
.write()) {
for (Resource subj : deletedObjectProperties.listSubjects()
.toList()) {
irpl.add(ReasonerStatementPattern
.objectPattern(createProperty(subj.getURI())));
}
deletedObjectProperties.removeAll();
for (String uri : changes.getDeletedObjectPropertyUris()) {
patterns.add(ReasonerStatementPattern
.objectPattern(createProperty(uri)));
}
}
if (reasonerConfiguration.getQueryForAllDatatypeProperties()) {
try (LockedOntModel reasonerModel = lockableReasonerModel.read()) {
for (DatatypeProperty dataProp : reasonerModel
.listDatatypeProperties().toList()) {
for (DatatypeProperty dataProp : reasoner.listDatatypeProperties()) {
if (!(OWL_NS.equals(dataProp.getNameSpace()))) {
// TODO: THIS WILL WORK, BUT NEED TO GENERALIZE THE
// PATTERN CLASSES
irpl.add(ReasonerStatementPattern
patterns.add(ReasonerStatementPattern
.objectPattern(dataProp));
}
}
}
try (LockedModel deletedDataProperties = lockableDeletedDataProperties
.write()) {
for (Resource subj : deletedDataProperties.listSubjects()
.toList()) {
irpl.add(ReasonerStatementPattern
.objectPattern(createProperty(subj.getURI())));
}
deletedDataProperties.removeAll();
for (String uri : changes.getDeletedDataPropertyUris()) {
patterns.add(ReasonerStatementPattern
.objectPattern(createProperty(uri)));
}
}
return irpl;
return patterns;
}
}

View file

@ -1,313 +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.LinkedList;
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 com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.shared.Lock;
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
public class PelletListener implements TBoxReasonerDriver {
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<ReasonerStatementPattern> inferenceDrivingPatternAllowSet;
private Set<ReasonerStatementPattern> inferenceDrivingPatternDenySet;
private Set<ReasonerStatementPattern> inferenceReceivingPatternAllowSet;
private final ConfiguredReasonerListener listener;
private Model additionModel;
private Model removalModel;
private Model deletedObjectProperties;
private Model deletedDataProperties;
private Status status = Status.SUCCESS;
public boolean isConsistent() {
return this.status.isConsistent();
}
public String getExplanation() {
return this.status.getExplanation();
}
public boolean isInErrorState() {
return this.status.isInErrorState();
}
public boolean isReasoning() {
return this.isReasoning;
}
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 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();
this.additionModel = ModelFactory.createDefaultModel();
this.removalModel = ModelFactory.createDefaultModel();
this.deletedObjectProperties = ModelFactory.createDefaultModel();
this.deletedDataProperties = ModelFactory.createDefaultModel();
listener = new ConfiguredReasonerListener(reasonerConfiguration, this);
this.mainModel.enterCriticalSection(Lock.READ);
try {
for (ReasonerStatementPattern pat : this.inferenceDrivingPatternAllowSet) {
listener.addedStatements(mainModel.listStatements((Resource) null, pat.getPredicate(), (RDFNode) null));
}
if (!skipReasoningUponInitialization) {
this.foreground = foreground;
listener.notifyEvent(null,new EditEvent(null,false));
} else if (inferenceModel.size() == 0){
foreground = true;
listener.notifyEvent(null,new EditEvent(null,false));
this.foreground = foreground;
}
} finally {
this.mainModel.leaveCriticalSection();
}
this.fullModel.getBaseModel().register(listener);
this.mainModel.getBaseModel().register(listener);
}
@Override
public void addStatement(Statement stmt) {
additionModel.enterCriticalSection(Lock.WRITE);
try {
additionModel.add(stmt);
} finally {
additionModel.leaveCriticalSection();
}
}
@Override
public void removeStatement(Statement stmt) {
removalModel.enterCriticalSection(Lock.WRITE);
try {
removalModel.add(stmt);
} finally {
removalModel.leaveCriticalSection();
}
}
@Override
public void deleteDataProperty(Statement stmt) {
deletedDataProperties.enterCriticalSection(Lock.WRITE);
try {
deletedDataProperties.add(stmt);
} finally {
deletedDataProperties.leaveCriticalSection();
}
}
@Override
public void deleteObjectProperty(Statement stmt) {
deletedObjectProperties.enterCriticalSection(Lock.WRITE);
try {
deletedObjectProperties.add(stmt);
} finally {
deletedObjectProperties.leaveCriticalSection();
}
}
@Override
public void runSynchronizer() {
if ((additionModel.size() > 0) || (removalModel.size() > 0)) {
if (!isSynchronizing) {
if (foreground) {
log.debug("Running Pellet in foreground.");
(new PelletSynchronizer()).run();
} else {
log.debug("Running Pellet in background.");
new Thread(new PelletSynchronizer(),
"PelletListener.PelletSynchronizer").start();
}
}
}
}
private class InferenceGetter implements Runnable {
private PelletListener pelletListener;
public InferenceGetter(PelletListener pelletListener) {
this.pelletListener = pelletListener;
}
public void run() {
while (pelletListener.isDirty()) {
try {
pelletListener.setDirty(false);
log.info("Getting new inferences");
long startTime = System.currentTimeMillis();
PatternListBuilder patternListBuilder = new PatternListBuilder(
reasonerConfiguration, pelletModel,
deletedObjectProperties, deletedDataProperties);
LinkedList<ReasonerStatementPattern> irpl = patternListBuilder
.build();
pelletModel.enterCriticalSection(Lock.WRITE);
try {
pelletModel.rebind();
pelletModel.prepare();
} finally {
pelletModel.leaveCriticalSection();
}
InferenceModelUpdater inferenceModelUpdater = new InferenceModelUpdater(
pelletModel, inferenceModel, fullModel, listener);
inferenceModelUpdater.update(irpl);
this.pelletListener.status = Status.SUCCESS;
if (log.isInfoEnabled()) {
log.info("Added "+inferenceModelUpdater.getAddCount()+" statements entailed by assertions");
log.info("Retracted "+inferenceModelUpdater.getRetractCount()+" statements no longer entailed by assertions");
log.info("Done getting new inferences: "+(System.currentTimeMillis()-startTime)/1000+" seconds");
}
} catch (InconsistentOntologyException ioe) {
String explanation = ((PelletInfGraph)pelletModel.getGraph()).getKB().getExplanation();
this.pelletListener.status = Status.inconsistent(explanation);
log.error(ioe);
log.error(explanation);
} catch (Exception e) {
this.pelletListener.status = Status.ERROR;
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();
}
}
}
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 OntModel getPelletModel() {
return this.pelletModel;
}
}

View file

@ -12,8 +12,8 @@ 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.tboxreasoner.TBoxReasonerDriver;
public class IndividualsViaVClassOptions implements FieldOptions {
@ -104,8 +104,8 @@ public class IndividualsViaVClassOptions implements FieldOptions {
protected boolean isReasoningAvailable( WebappDaoFactory wDaoFact){
boolean inferenceAvailable = false;
if (wDaoFact instanceof WebappDaoFactoryJena) {
PelletListener pl = ((WebappDaoFactoryJena) wDaoFact).getPelletListener();
if (pl != null && pl.isConsistent() && !pl.isInErrorState()
TBoxReasonerDriver pl = ((WebappDaoFactoryJena) wDaoFact).getTBoxReasonerDriver();
if (pl != null && pl.getStatus().isConsistent() && !pl.getStatus().isInErrorState()
&& !pl.isReasoning()) {
inferenceAvailable = true;
}

View file

@ -14,15 +14,18 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.rdf.model.Model;
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.modelaccess.ContextModelAccess;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.BasicTBoxReasonerDriver;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerWrapper;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.pellet.PelletTBoxReasonerDriver;
/**
* Start the Pellet reasoner on the TBox.
@ -38,35 +41,22 @@ public class PelletReasonerSetup implements ServletContextListener {
ContextModelAccess contextModels = ModelAccess.on(ctx);
OntModel tboxAssertionsModel = contextModels
.getOntModel(TBOX_ASSERTIONS);
OntModel tboxInferencesModel = contextModels
.getOntModel(TBOX_INFERENCES);
Model tboxInferencesModel = contextModels
.getOntModel(TBOX_INFERENCES).getBaseModel();
OntModel tboxUnionModel = contextModels.getOntModel(TBOX_UNION);
WebappDaoFactory wadf = contextModels.getWebappDaoFactory();
if (!tboxAssertionsModel.getProfile().NAMESPACE()
.equals(OWL.NAMESPACE.getNameSpace())) {
ss.fatal(this, "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,
TBoxReasonerWrapper reasoner = new PelletTBoxReasonerDriver(
ReasonerConfiguration.DEFAULT);
sce.getServletContext().setAttribute("pelletListener", pelletListener);
sce.getServletContext().setAttribute("pelletOntModel",
pelletListener.getPelletModel());
TBoxReasonerDriver driver = new BasicTBoxReasonerDriver(
tboxAssertionsModel, tboxInferencesModel, tboxUnionModel,
reasoner, ReasonerConfiguration.DEFAULT);
sce.getServletContext().setAttribute("tboxReasoner", driver);
sce.getServletContext().setAttribute("tboxReasonerWrapper", reasoner);
if (wadf instanceof WebappDaoFactoryJena) {
((WebappDaoFactoryJena) wadf).setPelletListener(pelletListener);
((WebappDaoFactoryJena) wadf).setTBoxReasonerDriver(driver);
}
ss.info(this, "Pellet reasoner connected for the TBox");
@ -75,15 +65,14 @@ public class PelletReasonerSetup implements ServletContextListener {
}
public static void waitForTBoxReasoning(ServletContextEvent sce) {
PelletListener pelletListener = (PelletListener) sce
.getServletContext().getAttribute("pelletListener");
if (pelletListener == null) {
TBoxReasonerDriver driver = (TBoxReasonerDriver) sce.getServletContext().getAttribute("tboxReasoner");
if (driver == null) {
return;
}
int sleeps = 0;
// sleep at least once to make sure the TBox reasoning gets started
while ((0 == sleeps)
|| ((sleeps < 1000) && pelletListener.isReasoning())) {
|| ((sleeps < 1000) && driver.isReasoning())) {
if (((sleeps - 1) % 10) == 0) { // print message at 10 second
// intervals
log.info("Waiting for initial TBox reasoning to complete");

View file

@ -0,0 +1,162 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.tboxreasoner;
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.atomic.AtomicReference;
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 com.hp.hpl.jena.rdf.model.Statement;
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent;
import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.InferenceModelUpdater;
import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PatternListBuilder;
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;
/**
* The basic implementation of the TBoxReasonerDriver.
*/
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 AtomicReference<TBoxChanges> currentChangeSet;
private final Set<TBoxChanges> pendingChangeSets;
private final ExecutorService executorService;
private final TBoxReasonerWrapper reasoner;
private TBoxReasonerDriver.Status status;
public BasicTBoxReasonerDriver(OntModel assertionsModel,
Model inferencesModel, OntModel fullModel, TBoxReasonerWrapper 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.currentChangeSet = new AtomicReference<>(new TBoxChanges());
this.pendingChangeSets = Collections.synchronizedSet(new HashSet<TBoxChanges>());
this.executorService = Executors.newFixedThreadPool(1);
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 Status getStatus() {
return status;
}
@Override
public boolean isReasoning() {
return !pendingChangeSets.isEmpty();
}
@Override
public void addStatement(Statement stmt) {
currentChangeSet.get().addStatement(stmt);
}
@Override
public void removeStatement(Statement stmt) {
currentChangeSet.get().removeStatement(stmt);
}
@Override
public void deleteDataProperty(Statement stmt) {
currentChangeSet.get().deleteDataProperty(stmt);
}
@Override
public void deleteObjectProperty(Statement stmt) {
currentChangeSet.get().deleteObjectProperty(stmt);
}
@Override
public void runSynchronizer() {
TBoxChanges changes = currentChangeSet.getAndSet(new TBoxChanges());
if (changes.isEmpty()) {
return;
}
executorService.execute(new ReasoningTask(changes));
}
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 {
reasoner.updateReasonerModel(changes);
status = reasoner.performReasoning();
buildPatternList();
updateInferencesModel();
} finally {
pendingChangeSets.remove(changes);
}
}
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);
}
}
}

View file

@ -26,6 +26,11 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent;
* Listens for changes on a model. When a change is announced, it is passed
* along to the reasoner driver, if the configuration says that it is worthy.
*
* 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.

View file

@ -0,0 +1,82 @@
/* $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 then, 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

@ -19,6 +19,10 @@ public interface TBoxReasonerDriver {
void deleteObjectProperty(Statement stmt);
boolean isReasoning();
Status getStatus();
public static class Status {
public static final Status SUCCESS = new Status(true, false, "");
public static final Status ERROR = new Status(true, true, "");
@ -51,4 +55,5 @@ public interface TBoxReasonerDriver {
}
}
}

View file

@ -0,0 +1,53 @@
/* $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;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver.Status;
/**
* TODO
*/
public interface TBoxReasonerWrapper {
/**
* 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 statements that satisfy any of these patterns, after
* updating and reasoning.
*/
List<Statement> filterResults(List<ReasonerStatementPattern> patternList);
/**
* List all of the restrictions in the reasoner model, after updating and
* reasoning.
*/
List<Restriction> listRestrictions();
}

View file

@ -0,0 +1,115 @@
/* $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.TBoxReasonerDriver.Status;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerWrapper;
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 PelletTBoxReasonerDriver implements TBoxReasonerWrapper {
private static final Log log = LogFactory
.getLog(PelletTBoxReasonerDriver.class);
private final LockableOntModel lockablePelletModel;
public PelletTBoxReasonerDriver(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();
}
}
}