From 7d60677d4fafb46c761e9db014b841d8d0280e8e Mon Sep 17 00:00:00 2001 From: stellamit Date: Thu, 17 Nov 2011 21:49:07 +0000 Subject: [PATCH] NIHVIVO-3040 separate thread for ABox reasoning based on TBox updates. --- .../vitro/webapp/reasoner/ModelUpdate.java | 64 ++++ .../vitro/webapp/reasoner/SimpleReasoner.java | 329 +----------------- .../reasoner/SimpleReasonerTBoxListener.java | 102 +++++- .../servlet/setup/SimpleReasonerSetup.java | 25 +- .../webapp/reasoner/SimpleReasonerTest.java | 198 +++++++---- 5 files changed, 320 insertions(+), 398 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ModelUpdate.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ModelUpdate.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ModelUpdate.java new file mode 100644 index 000000000..abd7be02d --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ModelUpdate.java @@ -0,0 +1,64 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.reasoner; + +import com.hp.hpl.jena.rdf.model.Statement; + + +public class ModelUpdate { + + public static enum Operation {ADD, RETRACT}; + + private Operation operation; + private Statement statement; + private String modelURI; + //JenaDataSourceSetupBase.JENA_DB_MODEL; + //JenaDataSourceSetupBase.JENA_TBOX_ASSERTIONS_MODEL; + + + public ModelUpdate() { + + } + + public ModelUpdate(Statement statement, + Operation operation, + String modelURI) { + + this.operation = operation; + this.statement = statement; + this.modelURI = modelURI; + } + + public Operation getOperation() { + return operation; + } + + public void setOperation(Operation operation) { + this.operation = operation; + } + + public Statement getStatement() { + return statement; + } + + public void setStatement(Statement statement) { + this.statement = statement; + } + + public String getModelURI() { + return modelURI; + } + + public void setModelURI(String modelURI) { + this.modelURI = modelURI; + } + + @Override public String toString() { + String ret = "operation = " + this.operation + ","; + ret += " model = " + this.modelURI + ","; + ret += " statement = " + SimpleReasoner.stmtString(statement); + + + return ret; + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java index 0ead5c18b..d9c007b2f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java @@ -14,7 +14,6 @@ import com.hp.hpl.jena.ontology.AnnotationProperty; import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; -import com.hp.hpl.jena.ontology.OntProperty; import com.hp.hpl.jena.query.Query; import com.hp.hpl.jena.query.QueryExecution; import com.hp.hpl.jena.query.QueryExecutionFactory; @@ -33,7 +32,6 @@ import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.JenaException; import com.hp.hpl.jena.shared.Lock; -import com.hp.hpl.jena.util.iterator.ExtendedIterator; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; @@ -58,10 +56,6 @@ public class SimpleReasoner extends StatementListener { private Model inferenceRebuildModel; // work area for re-computing all ABox inferences private Model scratchpadModel; // work area for re-computing all ABox inferences - private static final String topObjectPropertyURI = "http://www.w3.org/2002/07/owl#topObjectProperty"; - private static final String bottomObjectPropertyURI = "http://www.w3.org/2002/07/owl#bottomObjectProperty"; - private static final String topDataPropertyURI = "http://www.w3.org/2002/07/owl#topDataProperty"; - private static final String bottomDataPropertyURI = "http://www.w3.org/2002/07/owl#bottomDataProperty"; private static final String mostSpecificTypePropertyURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType"; private AnnotationProperty mostSpecificType = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createAnnotationProperty(mostSpecificTypePropertyURI); @@ -137,8 +131,6 @@ public class SimpleReasoner extends StatementListener { addedABoxTypeAssertion(stmt, inferenceModel, new HashSet()); setMostSpecificTypes(stmt.getSubject(), inferenceModel, new HashSet()); } - // uncomment this to enable subproperty/equivalent property inferencing. sjm222 5/13/2011 - // addedABoxAssertion(stmt,inferenceModel); for (ReasonerPlugin plugin : getPluginList()) { try { @@ -181,10 +173,7 @@ public class SimpleReasoner extends StatementListener { removedABoxTypeAssertion(stmt, inferenceModel); setMostSpecificTypes(stmt.getSubject(), inferenceModel, new HashSet()); } - - // uncomment this to enable subproperty/equivalent property inferencing. sjm222 5/13/2011 - // removedABoxAssertion(stmt, inferenceModel); - + for (ReasonerPlugin plugin : getPluginList()) { try { if (plugin.isInterestedInRemovedStatement(stmt)) { @@ -204,16 +193,11 @@ public class SimpleReasoner extends StatementListener { /* * Performs incremental selected ABox reasoning based - * on changes to the class or property hierarchy. + * on changes to the class hierarchy. * * Handles rdfs:subclassOf, owl:equivalentClass, - * rdfs:subPropertyOf and owl:equivalentProperty assertions - */ + */ public void addedTBoxStatement(Statement stmt) { - addedTBoxStatement(stmt, inferenceModel); - } - - public void addedTBoxStatement(Statement stmt, Model inferenceModel) { try { log.debug("added TBox assertion = " + stmt.toString()); @@ -254,21 +238,6 @@ public class SimpleReasoner extends StatementListener { addedSubClass(object,subject,inferenceModel); } } - /* uncomment this to enable sub property/equivalent property inferencing. sjm222 5/13/2011 - else if (stmt.getPredicate().equals(RDFS.subPropertyOf) || stmt.getPredicate().equals(OWL.equivalentProperty)) { - OntProperty subject = tboxModel.getOntProperty((stmt.getSubject()).getURI()); - OntProperty object = tboxModel.getOntProperty(((Resource)stmt.getObject()).getURI()); - - if (stmt.getPredicate().equals(RDFS.subPropertyOf)) { - addedSubProperty(subject,object,inferenceModel); - } else { - // equivalent property is the same as subProperty in both directions - addedSubProperty(subject,object,inferenceModel); - addedSubProperty(object,subject,inferenceModel); - } - } - */ - } catch (Exception e) { // don't stop the edit if there's an exception log.error("Exception while adding inference(s): " + e.getMessage()); @@ -277,10 +246,9 @@ public class SimpleReasoner extends StatementListener { /* * Performs incremental selected ABox reasoning based - * on changes to the class or property hierarchy. + * on changes to the class hierarchy. * * Handles rdfs:subclassOf, owl:equivalentClass, - * rdfs:subPropertyOf and owl:equivalentProperty assertions */ public void removedTBoxStatement(Statement stmt) { @@ -323,20 +291,6 @@ public class SimpleReasoner extends StatementListener { removedSubClass(object,subject,inferenceModel); } } - /* uncomment this to enable sub property / equivalent property inferencing. sjm222 5/13/2011. - else if (stmt.getPredicate().equals(RDFS.subPropertyOf) || stmt.getPredicate().equals(OWL.equivalentProperty)) { - OntProperty subject = tboxModel.getOntProperty((stmt.getSubject()).getURI()); - OntProperty object = tboxModel.getOntProperty(((Resource)stmt.getObject()).getURI()); - - if (stmt.getPredicate().equals(RDFS.subPropertyOf)) { - removedSubProperty(subject,object); - } else { - // equivalent property is the same as subProperty in both directions - removedSubProperty(subject,object); - removedSubProperty(object,subject); - } - } - */ } catch (Exception e) { // don't stop the edit if there's an exception log.error("Exception while removing inference(s): " + e.getMessage()); @@ -433,69 +387,6 @@ public class SimpleReasoner extends StatementListener { } } - /* - * Performs incremental property-based reasoning. - * - * Materializes inferences based on the rdfs:subPropertyOf relationship. - * If it is added that x propB y and propB is a sub-property of propA - * then add x propA y to the inference graph. - */ - public void addedABoxAssertion(Statement stmt, Model inferenceModel) { - - tboxModel.enterCriticalSection(Lock.READ); - - try { - OntProperty prop = tboxModel.getOntProperty(stmt.getPredicate().getURI()); - - if (prop != null) { - - // not reasoning on properties in the OWL, RDF or RDFS namespace - if ((prop.getNameSpace()).equals(OWL.NS) || - (prop.getNameSpace()).equals("http://www.w3.org/2000/01/rdf-schema#") || - (prop.getNameSpace()).equals("http://www.w3.org/1999/02/22-rdf-syntax-ns#")) { - return; - } - - //TODO: have trouble paramterizing the template with ? extends OntProperty - List superProperties = prop.listSuperProperties(false).toList(); - superProperties.addAll(prop.listEquivalentProperties().toList()); - Iterator superIt = superProperties.iterator(); - - while (superIt.hasNext()) { - OntProperty superProp = superIt.next(); - - if ( !((prop.isObjectProperty() && superProp.isObjectProperty()) || (prop.isDatatypeProperty() && superProp.isDatatypeProperty())) ) { - log.warn("sub-property and super-property do not have the same type. No inferencing will be performed. sub-property: " + prop.getURI() + " super-property:" + superProp.getURI()); - continue; - } - - if (superProp.getURI().equals(topObjectPropertyURI) || superProp.getURI().equals(topDataPropertyURI)) { - continue; - } - - Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), superProp, stmt.getObject()); - aboxModel.enterCriticalSection(Lock.READ); - try { - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt) ) { - inferenceModel.add(infStmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - } finally { - aboxModel.leaveCriticalSection(); - } - } - } else { - log.debug("Didn't find target property (the predicate of the added statement) in the TBox: " + stmt.getPredicate().getURI()); - } - } finally { - tboxModel.leaveCriticalSection(); - } - } - /* * If it is removed that B is of type A, then for each superclass of A remove * the inferred statement that B is of that type UNLESS it is otherwise entailed @@ -577,59 +468,6 @@ public class SimpleReasoner extends StatementListener { } } - /* - * Performs incremental property-based reasoning. - * - * Retracts inferences based on the rdfs:subPropertyOf relationship. - * If it is removed that x propB y and propB is a sub-property of propA - * then remove x propA y from the inference graph UNLESS it that - * statement is otherwise entailed. - */ - public void removedABoxAssertion(Statement stmt, Model inferenceModel) { - - tboxModel.enterCriticalSection(Lock.READ); - - try { - OntProperty prop = tboxModel.getOntProperty(stmt.getPredicate().getURI()); - - if (prop != null) { - - //TODO: trouble parameterizing these templates with "? extends OntProperty" - List superProperties = prop.listSuperProperties(false).toList(); - superProperties.addAll(prop.listEquivalentProperties().toList()); - Iterator superIt = superProperties.iterator(); - - while (superIt.hasNext()) { - OntProperty superProp = superIt.next(); - - if ( !((prop.isObjectProperty() && superProp.isObjectProperty()) || (prop.isDatatypeProperty() && superProp.isDatatypeProperty())) ) { - log.warn("sub-property and super-property do not have the same type. No inferencing will be performed. sub-property: " + prop.getURI() + " super-property:" + superProp.getURI()); - return; - } - - // if the statement is still entailed without the removed - // statement then don't remove it from the inferences - if (entailedByPropertySubsumption(stmt.getSubject(), superProp, stmt.getObject())) continue; - - Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), superProp, stmt.getObject()); - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (inferenceModel.contains(infStmt)) { - inferenceModel.remove(infStmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - } - } else { - log.debug("Didn't find target predicate (the predicate of the removed statement) in the TBox: " + stmt.getPredicate().getURI()); - } - } finally { - tboxModel.leaveCriticalSection(); - } - } - // Returns true if it is entailed by class subsumption that // subject is of type cls; otherwise returns false. public boolean entailedType(Resource subject, OntClass cls) { @@ -663,29 +501,6 @@ public class SimpleReasoner extends StatementListener { } } - // Returns true if the statement is entailed by property subsumption - public boolean entailedByPropertySubsumption(Resource subject, OntProperty prop, RDFNode object) { - - aboxModel.enterCriticalSection(Lock.READ); - tboxModel.enterCriticalSection(Lock.READ); - - try { - - ExtendedIterator iter = prop.listSubProperties(false); - - while (iter.hasNext()) { - OntProperty subProp = iter.next(); - Statement stmt = ResourceFactory.createStatement(subject, subProp, object); - if (aboxModel.contains(stmt)) return true; - } - - return false; - } finally { - aboxModel.leaveCriticalSection(); - tboxModel.leaveCriticalSection(); - } - } - /* * If it is added that B is a subClass of A, then for each * individual that is typed as B, either in the ABox or in the @@ -707,6 +522,7 @@ public class SimpleReasoner extends StatementListener { } finally { aboxModel.leaveCriticalSection(); } + for (Resource subject : subjectList) { Statement infStmt = ResourceFactory.createStatement(subject, RDF.type, superClass); @@ -765,93 +581,6 @@ public class SimpleReasoner extends StatementListener { } } - /* - * If it is added that B is a subProperty of A, then for each assertion - * involving predicate B, either in the ABox or in the inferred model - * assert the same relationship for predicate A - */ - public void addedSubProperty(OntProperty subProp, OntProperty superProp, Model inferenceModel) { - - if ( !((subProp.isObjectProperty() && superProp.isObjectProperty()) || (subProp.isDatatypeProperty() && superProp.isDatatypeProperty())) ) { - log.warn("sub-property and super-property do not have the same type. No inferencing will be performed. sub-property: " + subProp.getURI() + " super-property:" + superProp.getURI()); - return; - } - - aboxModel.enterCriticalSection(Lock.READ); - inferenceModel.enterCriticalSection(Lock.WRITE); - - try { - OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - unionModel.addSubModel(aboxModel); - unionModel.addSubModel(inferenceModel); - - StmtIterator iter = unionModel.listStatements((Resource) null, subProp, (RDFNode) null); - - while (iter.hasNext()) { - - Statement stmt = iter.next(); - Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), superProp, stmt.getObject()); - - inferenceModel.enterCriticalSection(Lock.WRITE); - - if (!inferenceModel.contains(infStmt)) { - inferenceModel.add(infStmt); - } - } - } finally { - aboxModel.leaveCriticalSection(); - inferenceModel.leaveCriticalSection(); - } - } - - /* - * If it is removed that B is a subProperty of A, then for each - * assertion involving predicate B, either in the ABox or in the - * inferred model, remove the same assertion involving predicate - * A from the inferred model, UNLESS the assertion is otherwise - * entailed by property subsumption. - */ - public void removedSubProperty(OntProperty subProp, OntProperty superProp) { - - log.debug("subProperty = " + subProp.getURI() + " superProperty = " + subProp.getURI()); - - if ( !((subProp.isObjectProperty() && superProp.isObjectProperty()) || (subProp.isDatatypeProperty() && superProp.isDatatypeProperty())) ) { - log.warn("sub-property and super-property do not have the same type. No inferencing will be performed. sub-property: " + subProp.getURI() + " super-property:" + superProp.getURI()); - return; - } - - aboxModel.enterCriticalSection(Lock.READ); - inferenceModel.enterCriticalSection(Lock.WRITE); - - try { - OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - unionModel.addSubModel(aboxModel); - unionModel.addSubModel(inferenceModel); - - StmtIterator iter = unionModel.listStatements((Resource) null, subProp, (RDFNode) null); - - while (iter.hasNext()) { - - Statement stmt = iter.next(); - - // if the statement is entailed without the removed subPropertyOf - // relationship then don't remove it from the inferences - if (entailedByPropertySubsumption(stmt.getSubject(), superProp, stmt.getObject())) continue; - - Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), superProp, stmt.getObject()); - - inferenceModel.enterCriticalSection(Lock.WRITE); - - if (inferenceModel.contains(infStmt)) { - inferenceModel.remove(infStmt); - } - } - } finally { - aboxModel.leaveCriticalSection(); - inferenceModel.leaveCriticalSection(); - } - } - /* * Find the most specific types (classes) of an individual and * indicate them for the individual with the core:mostSpecificType @@ -1077,50 +806,6 @@ public class SimpleReasoner extends StatementListener { return; } } - - /* - log.info("Computing property-based ABox inferences"); - iter = tboxModel.listStatements((Resource) null, RDFS.subPropertyOf, (RDFNode) null); - int numStmts = 0; - - while (iter.hasNext()) { - Statement stmt = iter.next(); - - if (stmt.getSubject().getURI().equals(bottomObjectPropertyURI) || stmt.getSubject().getURI().equals(bottomDataPropertyURI) || - (stmt.getObject().isResource() && (stmt.getObject().asResource().getURI().equals(topObjectPropertyURI) || - stmt.getObject().asResource().getURI().equals(topDataPropertyURI))) ) { - continue; - } - - if ( stmt.getSubject().equals(stmt.getObject()) ) { - continue; - } - - addedTBoxStatement(stmt, inferenceRebuildModel); - - numStmts++; - if ((numStmts % 500) == 0) { - log.info("Still computing property-based ABox inferences..."); - } - } - - iter = tboxModel.listStatements((Resource) null, OWL.equivalentProperty, (RDFNode) null); - - while (iter.hasNext()) { - Statement stmt = iter.next(); - - if ( stmt.getSubject().equals(stmt.getObject()) ) { - continue; - } - - addedTBoxStatement(stmt, inferenceRebuildModel); - - numStmts++; - if ((numStmts % 500) == 0) { - log.info("Still computing property-based ABox inferences..."); - } - } - */ } catch (Exception e) { log.error("Exception while recomputing ABox inference model", e); inferenceRebuildModel.removeAll(); // don't do this in the finally, it's needed in the case @@ -1388,13 +1073,11 @@ public class SimpleReasoner extends StatementListener { } } setMostSpecificTypes(stmt.getSubject(), inferenceModel, new HashSet()); - //TODO update this part when subproperty inferencing is added. } catch (NullPointerException npe) { abort = true; break; } catch (Exception e) { - log.error("exception in batch mode ",e); - //log.error("exception while computing inferences for batch " + qualifier + " update: " + e.getMessage()); + log.error("exception in batch mode ",e); } num++; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTBoxListener.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTBoxListener.java index c4ac1a28b..340d78396 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTBoxListener.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTBoxListener.java @@ -1,10 +1,18 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + /* $This file is distributed under the terms of the license in /doc/license.txt$ */ package edu.cornell.mannlib.vitro.webapp.reasoner; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import com.hp.hpl.jena.rdf.listeners.StatementListener; import com.hp.hpl.jena.rdf.model.Statement; +import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase; +import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; + /** * Route notification of changes to TBox to the incremental ABox reasoner. @@ -15,23 +23,95 @@ import com.hp.hpl.jena.rdf.model.Statement; public class SimpleReasonerTBoxListener extends StatementListener { - private SimpleReasoner simpleReasoner = null; + private static final Log log = LogFactory.getLog(SimpleReasonerTBoxListener.class); + + private SimpleReasoner simpleReasoner; + private Thread workerThread; + private boolean stopRequested; + private String name; + + private volatile boolean processingUpdates = false; + private ConcurrentLinkedQueue modelUpdates = null; public SimpleReasonerTBoxListener(SimpleReasoner simpleReasoner) { this.simpleReasoner = simpleReasoner; + this.stopRequested = false; + this.modelUpdates = new ConcurrentLinkedQueue(); + this.processingUpdates = false; + } + + public SimpleReasonerTBoxListener(SimpleReasoner simpleReasoner, String name) { + this.simpleReasoner = simpleReasoner; + this.name = name; + this.stopRequested = false; + this.modelUpdates = new ConcurrentLinkedQueue(); + this.processingUpdates = false; } @Override - public void addedStatement(Statement stmt) { - //simpleReasoner.startBatchMode(); - simpleReasoner.addedTBoxStatement(stmt); - //simpleReasoner.endBatchMode(); + public void addedStatement(Statement statement) { + ModelUpdate mu = new ModelUpdate(statement, ModelUpdate.Operation.ADD, JenaDataSourceSetupBase.JENA_TBOX_ASSERTIONS_MODEL); + processUpdate(mu); + } + + @Override + public void removedStatement(Statement statement) { + ModelUpdate mu = new ModelUpdate(statement, ModelUpdate.Operation.RETRACT, JenaDataSourceSetupBase.JENA_TBOX_ASSERTIONS_MODEL); + processUpdate(mu); } - @Override - public void removedStatement(Statement stmt) { - //simpleReasoner.startBatchMode(); - simpleReasoner.removedTBoxStatement(stmt); - //simpleReasoner.endBatchMode(); + private synchronized void processUpdate(ModelUpdate mu) { + if (!processingUpdates && (modelUpdates.peek() != null)) { + log.error("TBoxProcessor thread was not running and work queue is not empty. size = " + modelUpdates.size()); + } + + modelUpdates.add(mu); + + if (!processingUpdates) { + processingUpdates = true; + workerThread = new TBoxUpdateProcessor("TBoxUpdateProcessor (" + getName() + ")"); + workerThread.start(); + } } + + private synchronized ModelUpdate nextUpdate() { + ModelUpdate mu = modelUpdates.poll(); + processingUpdates = (mu != null); + return mu; + } + + public String getName() { + return (name == null) ? "SimpleReasonerTBoxListener" : name; + } + + public void setStopRequested() { + this.stopRequested = true; + } + + private class TBoxUpdateProcessor extends VitroBackgroundThread { + public TBoxUpdateProcessor(String name) { + super(name); + } + + @Override + public void run() { + try { + log.debug("starting thread"); + ModelUpdate mu = nextUpdate(); + while (mu != null && !stopRequested) { + if (mu.getOperation() == ModelUpdate.Operation.ADD) { + simpleReasoner.addedTBoxStatement(mu.getStatement()); + } else if (mu.getOperation() == ModelUpdate.Operation.RETRACT) { + simpleReasoner.removedTBoxStatement(mu.getStatement()); + } else { + log.error("unexpected operation value in ModelUpdate object: " + mu.getOperation()); + } + mu = nextUpdate(); + } + } finally { + processingUpdates = false; + log.debug("ending thread"); + } + } + } } \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java index d1235fffc..7cd5b964c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java @@ -153,7 +153,9 @@ public class SimpleReasonerSetup implements ServletContextListener { new Thread(new MostSpecificTypeRecomputer(simpleReasoner),"MostSpecificTypeComputer").start(); } - assertionsOms.getTBoxModel().register(new SimpleReasonerTBoxListener(simpleReasoner)); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = new SimpleReasonerTBoxListener(simpleReasoner); + sce.getServletContext().setAttribute(SimpleReasonerTBoxListener.class.getName(),simpleReasonerTBoxListener); + assertionsOms.getTBoxModel().register(simpleReasonerTBoxListener); log.info("Simple reasoner connected for the ABox"); @@ -165,12 +167,19 @@ public class SimpleReasonerSetup implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent sce) { log.info("received contextDestroyed notification"); - SimpleReasoner simpleReasoner = getSimpleReasonerFromServletContext(sce.getServletContext()); - + + SimpleReasoner simpleReasoner = getSimpleReasonerFromServletContext(sce.getServletContext()); if (simpleReasoner != null) { log.info("sending stop request to SimpleReasoner"); simpleReasoner.setStopRequested(); } + + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getSimpleReasonerTBoxListenerFromContext(sce.getServletContext()); + if (simpleReasonerTBoxListener != null) { + log.info("sending stop request to simpleReasonerTBoxListener"); + simpleReasonerTBoxListener.setStopRequested(); + } + } public static SimpleReasoner getSimpleReasonerFromServletContext(ServletContext ctx) { @@ -183,6 +192,16 @@ public class SimpleReasonerSetup implements ServletContextListener { } } + public static SimpleReasonerTBoxListener getSimpleReasonerTBoxListenerFromContext(ServletContext ctx) { + Object simpleReasonerTBoxListener = ctx.getAttribute(SimpleReasonerTBoxListener.class.getName()); + + if (simpleReasonerTBoxListener instanceof SimpleReasonerTBoxListener) { + return (SimpleReasonerTBoxListener) simpleReasonerTBoxListener; + } else { + return null; + } + } + private static final String RECOMPUTE_REQUIRED_ATTR = SimpleReasonerSetup.class.getName() + ".recomputeRequired"; diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java index 34b8fc886..7de4d28be 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java @@ -3,13 +3,14 @@ package edu.cornell.mannlib.vitro.webapp.reasoner; +import java.util.Iterator; + import org.apache.log4j.Level; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mindswap.pellet.jena.PelletReasonerFactory; -import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; import com.hp.hpl.jena.ontology.AnnotationProperty; import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; @@ -17,28 +18,28 @@ import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.ontology.OntProperty; 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.ResourceFactory; import com.hp.hpl.jena.rdf.model.Statement; -import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; import edu.cornell.mannlib.vitro.testing.AbstractTestClass; +import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; public class SimpleReasonerTest extends AbstractTestClass { - private Resource objectProperty = ResourceFactory.createResource("http://www.w3.org/2002/07/owl#ObjectProperty"); private static final String mostSpecificTypePropertyURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType"; + long delay = 50; @Before public void suppressErrorOutput() { suppressSyserr(); //Turn off log messages to console setLoggerLevel(SimpleReasoner.class, Level.OFF); + setLoggerLevel(SimpleReasonerTBoxListener.class, Level.OFF); } /* @@ -51,7 +52,6 @@ public class SimpleReasonerTest extends AbstractTestClass { // Create a Tbox with a simple class hierarchy. B is a subclass of A. // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntClass classA = tBox.createClass("http://test.vivo/A"); classA.setLabel("class A", "en-US"); @@ -90,7 +90,6 @@ public class SimpleReasonerTest extends AbstractTestClass { // Create a Tbox with a simple class hierarchy. D and E are subclasses // of C. B and C are subclasses of A. Pellet will compute TBox inferences. OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntClass classA = tBox.createClass("http://test.vivo/A"); classA.setLabel("class A", "en-US"); @@ -137,20 +136,20 @@ public class SimpleReasonerTest extends AbstractTestClass { * Test inference based on class equivalence */ @Test - public void addABoxTypeAssertion3(){ + public void addABoxTypeAssertion3() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); // Add classes A, B and C to the TBox // A is equivalent to B @@ -168,6 +167,10 @@ public class SimpleReasonerTest extends AbstractTestClass { classA.addEquivalentClass(classB); classA.addSubClass(classC); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Add a statement that individual x is of type C to the ABox Resource ind_x = aBox.createResource("http://test.vivo/x"); aBox.add(ind_x, RDF.type, classC); @@ -178,28 +181,30 @@ public class SimpleReasonerTest extends AbstractTestClass { // Verify that "x is of type B" was inferred Statement xisb = ResourceFactory.createStatement(ind_x, RDF.type, classB); - Assert.assertTrue(inf.contains(xisb)); + Assert.assertTrue(inf.contains(xisb)); + + simpleReasonerTBoxListener.setStopRequested();; } /* * Test inference based on class equivalence */ @Test - public void addABoxTypeAssertion4() { + public void addABoxTypeAssertion4() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); - + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); + // Add classes A and B to the TBox // A is equivalent to B @@ -211,13 +216,19 @@ public class SimpleReasonerTest extends AbstractTestClass { classA.addEquivalentClass(classB); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Add a statement that individual x is of type B to the ABox Resource ind_x = aBox.createResource("http://test.vivo/x"); aBox.add(ind_x, RDF.type, classB); // Verify that "x is of type A" was inferred Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); - Assert.assertTrue(inf.contains(xisa)); + Assert.assertTrue(inf.contains(xisa)); + + simpleReasonerTBoxListener.setStopRequested(); } @@ -225,20 +236,20 @@ public class SimpleReasonerTest extends AbstractTestClass { * Test inference based on class equivalence */ @Test - public void addABoxTypeAssertion5() { + public void addABoxTypeAssertion5() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); // Add classes classes A and B to the TBox // A is equivalent to B @@ -251,6 +262,10 @@ public class SimpleReasonerTest extends AbstractTestClass { classA.addEquivalentClass(classB); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Add a statement that individual x is of type B to the ABox Resource ind_x = aBox.createResource("http://test.vivo/x"); aBox.add(ind_x, RDF.type, classB); @@ -264,6 +279,8 @@ public class SimpleReasonerTest extends AbstractTestClass { // Verify that "x is of type A" was removed from the inference graph Assert.assertFalse(inf.contains(xisa)); + + simpleReasonerTBoxListener.setStopRequested(); } /* @@ -281,7 +298,6 @@ public class SimpleReasonerTest extends AbstractTestClass { // and B is a subclass of A. Pellet will compute TBox inferences. OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntClass classA = tBox.createClass("http://test.vivo/A"); classA.setLabel("class A", "en-US"); @@ -340,20 +356,20 @@ public class SimpleReasonerTest extends AbstractTestClass { * as a test of equivalentClass statements also. */ @Test - public void addTBoxSubClassAssertion1(){ + public void addTBoxSubClassAssertion1() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); // Add classes classes A, B, C and D to the TBox @@ -377,6 +393,10 @@ public class SimpleReasonerTest extends AbstractTestClass { classA.addSubClass(classC); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Verify that "x is of type A" was inferred Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); Assert.assertTrue(inf.contains(xisa)); @@ -389,6 +409,7 @@ public class SimpleReasonerTest extends AbstractTestClass { Statement xisd = ResourceFactory.createStatement(ind_x, RDF.type, classD); Assert.assertFalse(inf.contains(xisd)); + simpleReasonerTBoxListener.setStopRequested(); } /* @@ -408,21 +429,21 @@ public class SimpleReasonerTest extends AbstractTestClass { * */ @Test - public void addTBoxSubClassAssertion2() { + public void addTBoxSubClassAssertion2() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); - + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); + // Add classes classes A, B, C and D to the TBox // D is a subclass of C @@ -440,16 +461,26 @@ public class SimpleReasonerTest extends AbstractTestClass { classC.addSubClass(classD); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Add a statement that individual x is of type D to the ABox Resource ind_x = aBox.createResource("http://test.vivo/x"); aBox.add(ind_x, RDF.type, classD); // Add a statement that C is a subclass of A to the TBox classA.addSubClass(classC); - + + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Verify that "x is of type A" was inferred Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); - Assert.assertTrue(inf.contains(xisa)); + Assert.assertTrue(inf.contains(xisa)); + + simpleReasonerTBoxListener.setStopRequested(); } @Test @@ -469,19 +500,19 @@ public class SimpleReasonerTest extends AbstractTestClass { * as a test of equivalentClass assertions also. * */ - public void removeTBoxSubClassAssertion1(){ + public void removeTBoxSubClassAssertion1() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); // Add classes A, B, C, D, E, F, G and H to the TBox. // B, C and D are subclasses of A. @@ -521,6 +552,10 @@ public class SimpleReasonerTest extends AbstractTestClass { classC.addSubClass(classG); classD.addSubClass(classH); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Add a statement that individual x is of type E to the ABox Resource ind_x = aBox.createResource("http://test.vivo/x"); aBox.add(ind_x, RDF.type, classE); @@ -528,6 +563,10 @@ public class SimpleReasonerTest extends AbstractTestClass { // Remove the statement that B is a subclass of A from the TBox classA.removeSubClass(classB); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Verify that "x is of type A" is not in the inference graph Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); Assert.assertFalse(inf.contains(xisa)); @@ -544,9 +583,15 @@ public class SimpleReasonerTest extends AbstractTestClass { // Remove the statement that C is a subclass of A from the TBox classA.removeSubClass(classC); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Verify that "y is of type A" is in the inference graph Statement yisa = ResourceFactory.createStatement(ind_y, RDF.type, classA); Assert.assertTrue(inf.contains(yisa)); + + simpleReasonerTBoxListener.setStopRequested(); } @@ -554,20 +599,20 @@ public class SimpleReasonerTest extends AbstractTestClass { * tests rdfs:subPropertyOf materialization for object properties. */ // @Test uncomment when sub/equiv property inferencing is enabled. sjm222 5/13/2011 - public void addABoxAssertion1(){ + public void addABoxAssertion1() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); // Add object properties propA and propB to the TBox. // propB is a sub-property of propA. @@ -604,14 +649,14 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); - + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); + // Add object properties propA and propB to the TBox. // propB is a sub-property of propA. @@ -646,14 +691,14 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); - + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); + // Add properties A, B and C to the TBox // A is equivalent to B // C is a subclass of A @@ -701,13 +746,13 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); // Add object properties propA and propB to the TBox. // propB is a sub-property of propA. @@ -744,14 +789,14 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); - + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); + // Add properties A and B to the TBox // A is equivalent to B @@ -801,14 +846,14 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); - + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); + // Add properties A, B, C and D to the TBox OntProperty propA = tBox.createOntProperty("http://test.vivo/A"); tBox.add(propA, RDF.type, objectProperty); @@ -869,14 +914,14 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); - + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); + // Add properties A, B, C, D, E, F, G and H to the TBox. // B, C and D are subproperties of A. // E is a subproperty of B. @@ -960,7 +1005,7 @@ public class SimpleReasonerTest extends AbstractTestClass { * to an added/removed ABox type assertion. */ @Test - public void mstTest1(){ + public void mstTest1() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences @@ -971,7 +1016,8 @@ public class SimpleReasonerTest extends AbstractTestClass { SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); // Set up the Tbox with a class hierarchy. C is a subclass of A // and Y. D and E are subclasses C. B is a subclass of D. @@ -1005,6 +1051,10 @@ public class SimpleReasonerTest extends AbstractTestClass { classD.addSubClass(classB); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Add the statement individual x is of type Y to the ABox Resource ind_x = aBox.createResource("http://test.vivo/x"); aBox.add(ind_x, RDF.type, classD); @@ -1023,6 +1073,8 @@ public class SimpleReasonerTest extends AbstractTestClass { aBox.remove(ind_x, RDF.type, classD); // retract assertion that x is of type D. // Verify that D is not longer the most specific type Assert.assertFalse(inf.contains(ind_x, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + + simpleReasonerTBoxListener.setStopRequested(); } @@ -1031,7 +1083,7 @@ public class SimpleReasonerTest extends AbstractTestClass { * to an added ABox type assertion. */ @Test - public void mstTest2(){ + public void mstTest2() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences @@ -1042,7 +1094,8 @@ public class SimpleReasonerTest extends AbstractTestClass { SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); // Set up the Tbox with a class hierarchy. B is a subclass of A, // C is a subclass of B, and A is a subclass of C. @@ -1063,16 +1116,20 @@ public class SimpleReasonerTest extends AbstractTestClass { classB.addSubClass(classC); classC.addSubClass(classA); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // Add the statement individual x is of type B to the ABox Resource ind_x = aBox.createResource("http://test.vivo/x"); aBox.add(ind_x, RDF.type, classB); - - StmtIterator stmtIterator = aBox.listStatements(ind_x, mostSpecificType, (RDFNode)null); - + // Verify ind_x mostSpecificType annotation for A, B and C Assert.assertTrue(inf.contains(ind_x, mostSpecificType, ResourceFactory.createResource(classA.getURI()))); Assert.assertTrue(inf.contains(ind_x, mostSpecificType, ResourceFactory.createResource(classB.getURI()))); Assert.assertTrue(inf.contains(ind_x, mostSpecificType, ResourceFactory.createResource(classC.getURI()))); + + simpleReasonerTBoxListener.setStopRequested(); } /* @@ -1080,7 +1137,7 @@ public class SimpleReasonerTest extends AbstractTestClass { * to an added/removed TBox assertions. */ @Test - public void mstTest3(){ + public void mstTest3() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences @@ -1091,7 +1148,8 @@ public class SimpleReasonerTest extends AbstractTestClass { SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); OntClass OWL_THING = tBox.createClass(OWL.Thing.getURI()); AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); @@ -1120,6 +1178,10 @@ public class SimpleReasonerTest extends AbstractTestClass { OntClass classG = tBox.createClass("http://test.vivo/G"); classE.setLabel("class G", "en-US"); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + // add individuals x, y and z to the aBox Resource ind_x = aBox.createResource("http://test.vivo/x"); Resource ind_y = aBox.createResource("http://test.vivo/y"); @@ -1150,16 +1212,30 @@ public class SimpleReasonerTest extends AbstractTestClass { classD.addSubClass(classF); classD.addSubClass(classG); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + Assert.assertFalse(inf.contains(ind_y, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); Assert.assertTrue(inf.contains(ind_y, mostSpecificType, ResourceFactory.createResource(classF.getURI()))); // If F is removed as a subclass of D, then D should once again be a most specific type // for y. classD.removeSubClass(classF); - Assert.assertTrue(inf.contains(ind_y, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + + Assert.assertTrue(inf.contains(ind_y, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + + simpleReasonerTBoxListener.setStopRequested(); } + SimpleReasonerTBoxListener getTBoxListener(SimpleReasoner simpleReasoner) { + return new SimpleReasonerTBoxListener(simpleReasoner, new Exception().getStackTrace()[1].getMethodName()); + } + // To help in debugging the unit test void printModel(Model model, String modelName) {