From 24bce9ff670236d256fcb79bd7f4a9324405a404 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Wed, 3 Dec 2014 09:46:25 -0500 Subject: [PATCH] VIVO-778 Wild restructuring Create TBoxChanges, createTBoxReasonerDriver, delete PelletListener, deal with repercussions all over. --- .../freemarker/BaseSiteAdminController.java | 15 +- .../controller/jena/JenaAdminActions.java | 5 +- .../webapp/dao/jena/DataPropertyDaoJena.java | 6 +- .../webapp/dao/jena/WebappDaoFactoryJena.java | 12 +- .../jena/pellet/InferenceModelUpdater.java | 74 ++--- .../dao/jena/pellet/PatternListBuilder.java | 83 ++--- .../dao/jena/pellet/PelletListener.java | 313 ------------------ .../fields/IndividualsViaVClassOptions.java | 6 +- .../servlet/setup/PelletReasonerSetup.java | 47 +-- .../tboxreasoner/BasicTBoxReasonerDriver.java | 162 +++++++++ .../ConfiguredReasonerListener.java | 5 + .../webapp/tboxreasoner/TBoxChanges.java | 82 +++++ .../tboxreasoner/TBoxReasonerDriver.java | 5 + .../tboxreasoner/TBoxReasonerWrapper.java | 53 +++ .../impl/pellet/PelletTBoxReasonerDriver.java | 115 +++++++ 15 files changed, 517 insertions(+), 466 deletions(-) delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PelletListener.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxChanges.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerWrapper.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerDriver.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/BaseSiteAdminController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/BaseSiteAdminController.java index 5bcdbc53e..09d423428 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/BaseSiteAdminController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/BaseSiteAdminController.java @@ -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."; } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaAdminActions.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaAdminActions.java index 08b007fef..7d3034394 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaAdminActions.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaAdminActions.java @@ -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: "); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java index 1e0d7a384..d2c185086 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java @@ -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() ) ); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java index a74cada20..db38709e3 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java @@ -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 diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/InferenceModelUpdater.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/InferenceModelUpdater.java index 36de3a795..095a1841c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/InferenceModelUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/InferenceModelUpdater.java @@ -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 patternList) { - Model filteredReasonerModel = filterReasonerModel(patternList); + public void update(List patternList) { + List filteredReasonerModel = reasoner + .filterResults(patternList); addNewInferences(filteredReasonerModel); removeOldInferences(filterInferencesModel(patternList), filteredReasonerModel); log.warn("Added: " + addCount + ", Retracted: " + retractCount); } - private Model filterReasonerModel( - LinkedList 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 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 patternList) { + List 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 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); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PatternListBuilder.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PatternListBuilder.java index dbc5d0417..544e16339 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PatternListBuilder.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PatternListBuilder.java @@ -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 build() { - LinkedList irpl = new LinkedList<>(); + LinkedList patterns = new LinkedList<>(); Set 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()) { - if (!(OWL_NS.equals(objProp.getNameSpace()))) { - irpl.add(ReasonerStatementPattern - .objectPattern(objProp)); - } + for (ObjectProperty objProp : reasoner.listObjectProperties()) { + if (!(OWL_NS.equals(objProp.getNameSpace()))) { + 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()) { - if (!(OWL_NS.equals(dataProp.getNameSpace()))) { - // TODO: THIS WILL WORK, BUT NEED TO GENERALIZE THE - // PATTERN CLASSES - irpl.add(ReasonerStatementPattern - .objectPattern(dataProp)); - } + 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)); } } - 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; } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PelletListener.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PelletListener.java deleted file mode 100644 index 0a706f13a..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PelletListener.java +++ /dev/null @@ -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 inferenceDrivingPatternAllowSet; - private Set inferenceDrivingPatternDenySet; - private Set 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 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; - } - -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java index 741624e5a..15ae28fa4 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java @@ -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; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java index 476717121..c434bb3e5 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java @@ -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"); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java new file mode 100644 index 000000000..a38bf27b7 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java @@ -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 currentChangeSet; + private final Set 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()); + + 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 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); + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ConfiguredReasonerListener.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ConfiguredReasonerListener.java index 8f9dc2ea5..cf7b90343 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ConfiguredReasonerListener.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ConfiguredReasonerListener.java @@ -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. diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxChanges.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxChanges.java new file mode 100644 index 000000000..11c6d1b87 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxChanges.java @@ -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 addedStatements = Collections + .synchronizedList(new ArrayList()); + + private final List removedStatements = Collections + .synchronizedList(new ArrayList()); + + private final List deletedDataPropertyUris = Collections + .synchronizedList(new ArrayList()); + private final List deletedObjectPropertyUris = Collections + .synchronizedList(new ArrayList()); + + // ---------------------------------------------------------------------- + // 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 getAddedStatements() { + return addedStatements; + } + + public List getRemovedStatements() { + return removedStatements; + } + + public List getDeletedDataPropertyUris() { + return deletedDataPropertyUris; + } + + public List getDeletedObjectPropertyUris() { + return deletedObjectPropertyUris; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java index 09c356adb..4ad552966 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java @@ -18,6 +18,10 @@ public interface TBoxReasonerDriver { void deleteDataProperty(Statement stmt); void deleteObjectProperty(Statement stmt); + + boolean isReasoning(); + + Status getStatus(); public static class Status { public static final Status SUCCESS = new Status(true, false, ""); @@ -51,4 +55,5 @@ public interface TBoxReasonerDriver { } } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerWrapper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerWrapper.java new file mode 100644 index 000000000..929937eaa --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerWrapper.java @@ -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 listObjectProperties(); + + /** + * List all of the DatatypeProperties from the reasoner model, after + * updating and reasoning. + */ + List listDatatypeProperties(); + + /** + * List all of the statements that satisfy any of these patterns, after + * updating and reasoning. + */ + List filterResults(List patternList); + + /** + * List all of the restrictions in the reasoner model, after updating and + * reasoning. + */ + List listRestrictions(); + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerDriver.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerDriver.java new file mode 100644 index 000000000..7e235e763 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerDriver.java @@ -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 listObjectProperties() { + try (LockedOntModel pelletModel = lockablePelletModel.read()) { + return pelletModel.listObjectProperties().toList(); + } + } + + @Override + public List listDatatypeProperties() { + try (LockedOntModel pelletModel = lockablePelletModel.read()) { + return pelletModel.listDatatypeProperties().toList(); + } + } + + @Override + public List filterResults( + List patternList) { + List filtered = new ArrayList<>(); + try (LockedOntModel pelletModel = lockablePelletModel.read()) { + for (ReasonerStatementPattern pattern : patternList) { + filtered.addAll(pattern.matchStatementsFromModel(pelletModel)); + } + } + for (Iterator 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 listRestrictions() { + try (LockedOntModel pelletModel = lockablePelletModel.read()) { + return pelletModel.listRestrictions().toList(); + } + } +}