From 468a7214fec6f0ae564b1cea4078b653b3940564 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Wed, 26 Nov 2014 11:16:17 -0500 Subject: [PATCH 01/10] VIVO-778 Clean up ObjectPropertyStatementPattern Rename to ReasonerStatementPattern, move to a new package and refactor. --- .../ObjectPropertyStatementPattern.java | 52 ----- ...ObjectPropertyStatementPatternFactory.java | 26 --- .../dao/jena/pellet/PelletListener.java | 180 ++++++++---------- .../servlet/setup/SimpleReasonerSetup.java | 2 +- .../ReasonerConfiguration.java | 84 ++++---- .../ReasonerStatementPattern.java | 94 +++++++++ 6 files changed, 216 insertions(+), 222 deletions(-) delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ObjectPropertyStatementPattern.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ObjectPropertyStatementPatternFactory.java rename webapp/src/edu/cornell/mannlib/vitro/webapp/{dao/jena/pellet => tboxreasoner}/ReasonerConfiguration.java (52%) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ReasonerStatementPattern.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ObjectPropertyStatementPattern.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ObjectPropertyStatementPattern.java deleted file mode 100644 index 001ecee14..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ObjectPropertyStatementPattern.java +++ /dev/null @@ -1,52 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet; - -import com.hp.hpl.jena.rdf.model.Property; -import com.hp.hpl.jena.rdf.model.Resource; - -public class ObjectPropertyStatementPattern { - - private Resource subject = null; - private Property predicate = null; - private Resource object = null; - - public ObjectPropertyStatementPattern(Resource subject, Property predicate, Resource object) { - this.subject = subject; - this.predicate = predicate; - this.object = object; - } - - public Resource getSubject() { - return this.subject; - } - public Property getPredicate() { - return this.predicate; - } - public Resource getObject() { - return this.object; - } - - public boolean matches(ObjectPropertyStatementPattern p2) { - boolean sMatch = false; - boolean pMatch = false; - boolean oMatch = false; - if (this.getSubject() == null || p2.getSubject()==null) { - sMatch = true; // (this.getSubject() == null && p2.getSubject() == null); - } else { - sMatch = (this.getSubject().equals(p2.getSubject())); - } - if (this.getPredicate() == null || p2.getPredicate()==null) { - pMatch = true; // (this.getPredicate() == null && p2.getPredicate() == null); - } else { - pMatch = (this.getPredicate().equals(p2.getPredicate())); - } - if (this.getObject() == null || p2.getObject()==null) { - oMatch = true ; // (this.getObject() == null && p2.getObject() == null); - } else { - oMatch = (this.getObject().equals(p2.getObject())); - } - return (sMatch && pMatch && oMatch); - } - -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ObjectPropertyStatementPatternFactory.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ObjectPropertyStatementPatternFactory.java deleted file mode 100644 index 57fb8f900..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ObjectPropertyStatementPatternFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet; - -import com.hp.hpl.jena.rdf.model.Property; -import com.hp.hpl.jena.rdf.model.Resource; - -public class ObjectPropertyStatementPatternFactory { - - //private static Set patternSet = new HashSet(); - - public static ObjectPropertyStatementPattern getPattern(Resource subject, Property predicate, Resource object) { - //for (Iterator i = patternSet.iterator(); i.hasNext(); ) { - // ObjectPropertyStatementPattern pat = i.next(); - // if ( ( (pat.getSubject()==null && subject==null) || (pat.getSubject().equals(subject)) ) - // && ( (pat.getPredicate()==null && predicate==null) || (pat.getPredicate().equals(predicate)) ) - // && ( (pat.getObject()==null && object==null) || (pat.getObject().equals(object)) ) ) { - // return pat; - // } - //} - ObjectPropertyStatementPattern newPat = new ObjectPropertyStatementPattern(subject,predicate,object); - //patternSet.add(newPat); - return newPat; - } - -} 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 index 47634ddba..d76547497 100644 --- 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 @@ -37,6 +37,8 @@ import com.hp.hpl.jena.vocabulary.RDFS; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern; public class PelletListener implements ModelChangedListener { @@ -50,11 +52,11 @@ public class PelletListener implements ModelChangedListener { private OntModel mainModel; private Model inferenceModel; private ReasonerConfiguration reasonerConfiguration; - private Set inferenceDrivingPatternAllowSet; - private Set inferenceDrivingPatternDenySet; - private Set inferenceReceivingPatternAllowSet; + private Set inferenceDrivingPatternAllowSet; + private Set inferenceDrivingPatternDenySet; + private Set inferenceReceivingPatternAllowSet; - private Map> inferenceDrivingPatternMap; + private Map> inferenceDrivingPatternMap; private Model additionModel; private Model removalModel; @@ -142,13 +144,13 @@ public class PelletListener implements ModelChangedListener { this.inferenceReceivingPatternAllowSet = reasonerConfiguration.getInferenceReceivingPatternAllowSet(); if (this.inferenceDrivingPatternAllowSet != null) { - this.inferenceDrivingPatternMap = new HashMap>(); - for (Iterator i = inferenceDrivingPatternAllowSet.iterator(); i.hasNext();) { - ObjectPropertyStatementPattern pat = i.next(); + this.inferenceDrivingPatternMap = new HashMap<>(); + for (Iterator i = inferenceDrivingPatternAllowSet.iterator(); i.hasNext();) { + ReasonerStatementPattern pat = i.next(); Property p = pat.getPredicate(); - List patList = inferenceDrivingPatternMap.get(p); + List patList = inferenceDrivingPatternMap.get(p); if (patList == null) { - patList = new LinkedList(); + patList = new LinkedList<>(); patList.add(pat); inferenceDrivingPatternMap.put(p, patList); } else { @@ -163,7 +165,7 @@ public class PelletListener implements ModelChangedListener { this.deletedDataProperties = ModelFactory.createDefaultModel(); this.mainModel.enterCriticalSection(Lock.READ); try { - for (ObjectPropertyStatementPattern pat : this.inferenceDrivingPatternAllowSet) { + for (ReasonerStatementPattern pat : this.inferenceDrivingPatternAllowSet) { addedStatements(mainModel.listStatements((Resource) null, pat.getPredicate(), (RDFNode) null)); } if (!skipReasoningUponInitialization) { @@ -198,12 +200,12 @@ public class PelletListener implements ModelChangedListener { inferenceRounds++; log.info("Getting new inferences"); long startTime = System.currentTimeMillis(); - LinkedList irpl = new LinkedList(); + LinkedList irpl = new LinkedList<>(); if (inferenceReceivingPatternAllowSet != null) { irpl.addAll(inferenceReceivingPatternAllowSet); } else { - irpl.add(ObjectPropertyStatementPatternFactory.getPattern(null,null,null)); + irpl.add(ReasonerStatementPattern.ANY_OBJECT_PROPERTY); } if (reasonerConfiguration.getQueryForAllObjectProperties()) { @@ -214,7 +216,7 @@ public class PelletListener implements ModelChangedListener { for (Iterator objPropIt = closeIt; objPropIt.hasNext();) { ObjectProperty objProp = (ObjectProperty) objPropIt.next(); if ( !("http://www.w3.org/2002/07/owl#".equals(objProp.getNameSpace())) ) { - irpl.add(ObjectPropertyStatementPatternFactory.getPattern(null,objProp,null)); + irpl.add(ReasonerStatementPattern.objectPattern(objProp)); } } } finally { @@ -229,7 +231,7 @@ public class PelletListener implements ModelChangedListener { try { while (sit.hasNext()) { Resource subj = (Resource) sit.next(); - irpl.add(ObjectPropertyStatementPatternFactory.getPattern(null,ResourceFactory.createProperty(subj.getURI()),null)); + irpl.add(ReasonerStatementPattern.objectPattern(ResourceFactory.createProperty(subj.getURI()))); } } finally { sit.close(); @@ -249,7 +251,7 @@ public class PelletListener implements ModelChangedListener { DatatypeProperty dataProp = (DatatypeProperty) dataPropIt.next(); if ( !("http://www.w3.org/2002/07/owl#".equals(dataProp.getNameSpace())) ) { // TODO: THIS WILL WORK, BUT NEED TO GENERALIZE THE PATTERN CLASSES - irpl.add(ObjectPropertyStatementPatternFactory.getPattern(null,dataProp,null)); + irpl.add(ReasonerStatementPattern.objectPattern(dataProp)); } } } finally { @@ -264,7 +266,7 @@ public class PelletListener implements ModelChangedListener { try { while (sit.hasNext()) { Resource subj = (Resource) sit.next(); - irpl.add(ObjectPropertyStatementPatternFactory.getPattern(null,ResourceFactory.createProperty(subj.getURI()),null)); + irpl.add(ReasonerStatementPattern.objectPattern(ResourceFactory.createProperty(subj.getURI()))); } } finally { sit.close(); @@ -294,68 +296,55 @@ public class PelletListener implements ModelChangedListener { pelletModel.leaveCriticalSection(); } - for (Iterator patIt = irpl.iterator(); patIt.hasNext(); ) { - ObjectPropertyStatementPattern pat = patIt.next(); - - if (log.isDebugEnabled()) { - String subjStr = (pat.getSubject() != null) ? pat.getSubject().getURI() : "*"; - String predStr = (pat.getPredicate() != null) ? pat.getPredicate().getURI() : "*"; - String objStr = (pat.getObject() != null) ? pat.getObject().getURI() : "*"; - log.debug("Querying for "+subjStr+" : "+predStr+" : "+objStr); - } + for (Iterator patIt = irpl.iterator(); patIt.hasNext(); ) { + ReasonerStatementPattern pat = patIt.next(); + log.debug("Querying for "+pat); Model tempModel = ModelFactory.createDefaultModel(); pelletModel.enterCriticalSection(Lock.READ); try { - - ClosableIterator ci = pelletModel.listStatements(pat.getSubject(),pat.getPredicate(),pat.getObject()); - try { - for (ClosableIterator i=ci; i.hasNext();) { - Statement stmt = (Statement) i.next(); - - boolean reject = false; - - // this next part is only needed if we're using Jena's OWL reasoner instead of actually using Pellet - try { - if ( ( ((Resource)stmt.getObject()).equals(RDFS.Resource) ) ) { - reject = true; - } else if ( ( stmt.getSubject().equals(OWL.Nothing) ) ) { - reject = true; - } else if ( ( stmt.getObject().equals(OWL.Nothing) ) ) { - reject = true; - } - } catch (Exception e) {} - - if (!reject) { - tempModel.add(stmt); - - boolean fullModelContainsStatement = false; - fullModel.enterCriticalSection(Lock.READ); - try { - fullModelContainsStatement = fullModel.contains(stmt); - } finally { - fullModel.leaveCriticalSection(); - } - - if (!fullModelContainsStatement) { - // in theory we should be able to lock only the inference model, but I'm not sure yet if Jena propagates the locking upward - fullModel.enterCriticalSection(Lock.WRITE); - closePipe(); - try { - inferenceModel.add(stmt); - addCount++; - } finally { - openPipe(); - fullModel.leaveCriticalSection(); - } - } - - } - } - } finally { - ci.close(); - } + for(Statement stmt : pat.matchStatementsFromModel(pelletModel)) { + + boolean reject = false; + + // this next part is only needed if we're using Jena's OWL reasoner instead of actually using Pellet + try { + if ( ( ((Resource)stmt.getObject()).equals(RDFS.Resource) ) ) { + reject = true; + } else if ( ( stmt.getSubject().equals(OWL.Nothing) ) ) { + reject = true; + } else if ( ( stmt.getObject().equals(OWL.Nothing) ) ) { + reject = true; + } + } catch (Exception e) {} + + if (!reject) { + tempModel.add(stmt); + + boolean fullModelContainsStatement = false; + fullModel.enterCriticalSection(Lock.READ); + try { + fullModelContainsStatement = fullModel.contains(stmt); + } finally { + fullModel.leaveCriticalSection(); + } + + if (!fullModelContainsStatement) { + // in theory we should be able to lock only the inference model, but I'm not sure yet if Jena propagates the locking upward + fullModel.enterCriticalSection(Lock.WRITE); + closePipe(); + try { + inferenceModel.add(stmt); + addCount++; + } finally { + openPipe(); + fullModel.leaveCriticalSection(); + } + } + + } + } } finally { pelletModel.leaveCriticalSection(); } @@ -364,22 +353,11 @@ public class PelletListener implements ModelChangedListener { try { Queue localRemovalQueue = new LinkedList(); - inferenceModel.enterCriticalSection(Lock.READ); - try { - ClosableIterator ci = inferenceModel.listStatements(pat.getSubject(),pat.getPredicate(),pat.getObject()); - try { - for (ClosableIterator i=ci; i.hasNext();) { - Statement stmt = (Statement) i.next(); - if (!tempModel.contains(stmt)) { - localRemovalQueue.add(stmt); - } - } - } finally { - ci.close(); - } - } finally { - inferenceModel.leaveCriticalSection(); - } + for (Statement stmt : pat.matchStatementsFromModel(inferenceModel)) { + if (!tempModel.contains(stmt)) { + localRemovalQueue.add(stmt); + } + } for (Iterator i = localRemovalQueue.iterator(); i.hasNext(); ) { fullModel.enterCriticalSection(Lock.WRITE); closePipe(); @@ -448,10 +426,10 @@ public class PelletListener implements ModelChangedListener { if (pipeOpen) { sendToPellet = false; boolean denied = false; - ObjectPropertyStatementPattern stPat = ObjectPropertyStatementPatternFactory.getPattern(stmt.getSubject(), stmt.getPredicate(), (Resource) stmt.getObject()); + ReasonerStatementPattern stPat = ReasonerStatementPattern.objectPattern(stmt); if (inferenceDrivingPatternDenySet != null) { - for (Iterator i = inferenceDrivingPatternDenySet.iterator(); i.hasNext(); ){ - ObjectPropertyStatementPattern pat = i.next(); + for (Iterator i = inferenceDrivingPatternDenySet.iterator(); i.hasNext(); ){ + ReasonerStatementPattern pat = i.next(); if (pat.matches(stPat)) { denied = true; break; @@ -463,10 +441,10 @@ public class PelletListener implements ModelChangedListener { sendToPellet = true; } else { // TODO: O(1) implementation of this - List patList = this.inferenceDrivingPatternMap.get(stmt.getPredicate()); + List patList = this.inferenceDrivingPatternMap.get(stmt.getPredicate()); if (patList != null) { - for (Iterator i = patList.iterator(); i.hasNext(); ){ - ObjectPropertyStatementPattern pat = i.next(); + for (Iterator i = patList.iterator(); i.hasNext(); ){ + ReasonerStatementPattern pat = i.next(); if (pat.matches(stPat)) { sendToPellet = true; break; @@ -526,10 +504,10 @@ public class PelletListener implements ModelChangedListener { } removeFromPellet = false; boolean denied = false; - ObjectPropertyStatementPattern stPat = ObjectPropertyStatementPatternFactory.getPattern(stmt.getSubject(), stmt.getPredicate(), (Resource) stmt.getObject()); + ReasonerStatementPattern stPat = ReasonerStatementPattern.objectPattern(stmt); if (inferenceDrivingPatternDenySet != null) { - for (Iterator i = inferenceDrivingPatternDenySet.iterator(); i.hasNext(); ){ - ObjectPropertyStatementPattern pat = i.next(); + for (Iterator i = inferenceDrivingPatternDenySet.iterator(); i.hasNext(); ){ + ReasonerStatementPattern pat = i.next(); if (pat.matches(stPat)) { denied = true; break; @@ -541,10 +519,10 @@ public class PelletListener implements ModelChangedListener { removeFromPellet = true; } else { // TODO: O(1) implementation of this - List patList = this.inferenceDrivingPatternMap.get(stmt.getPredicate()); + List patList = this.inferenceDrivingPatternMap.get(stmt.getPredicate()); if (patList != null) { - for (Iterator i = patList.iterator(); i.hasNext(); ){ - ObjectPropertyStatementPattern pat = i.next(); + for (Iterator i = patList.iterator(); i.hasNext(); ){ + ReasonerStatementPattern pat = i.next(); if (pat.matches(stPat)) { removeFromPellet = true; break; 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 08d3b5cc3..48a2fb1e2 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 @@ -26,7 +26,6 @@ import com.hp.hpl.jena.vocabulary.OWL; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena; import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener; -import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.ReasonerConfiguration; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; @@ -34,6 +33,7 @@ import edu.cornell.mannlib.vitro.webapp.reasoner.ReasonerPlugin; import edu.cornell.mannlib.vitro.webapp.reasoner.SimpleReasoner; import edu.cornell.mannlib.vitro.webapp.reasoner.SimpleReasonerTBoxListener; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration; import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; public class SimpleReasonerSetup implements ServletContextListener { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ReasonerConfiguration.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ReasonerConfiguration.java similarity index 52% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ReasonerConfiguration.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ReasonerConfiguration.java index 970c14e4d..8f6889ba2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ReasonerConfiguration.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ReasonerConfiguration.java @@ -1,22 +1,22 @@ /* $This file is distributed under the terms of the license in /doc/license.txt$ */ -package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet; +package edu.cornell.mannlib.vitro.webapp.tboxreasoner; import java.util.HashSet; import java.util.Set; +import org.mindswap.pellet.jena.PelletReasonerFactory; + import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; -import org.mindswap.pellet.jena.PelletReasonerFactory; - public class ReasonerConfiguration { - public Set inferenceDrivingPatternAllowSet; - public Set inferenceDrivingPatternDenySet; - public Set inferenceReceivingPatternAllowSet; + public Set inferenceDrivingPatternAllowSet; + public Set inferenceDrivingPatternDenySet; + public Set inferenceReceivingPatternAllowSet; private boolean queryForAllObjectProperties = false; private boolean incrementalReasoningEnabled = true; @@ -58,34 +58,34 @@ public class ReasonerConfiguration { //ask the reasoner only to classify, realize, and infer disjointWith statements (based on a somewhat incomplete information) DEFAULT = new ReasonerConfiguration(); - HashSet defaultInferenceDrivingPatternAllowSet = new HashSet(); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.type,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDFS.subClassOf,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDFS.subPropertyOf,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.equivalentClass,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.unionOf,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.intersectionOf,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.complementOf,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.oneOf,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.onProperty,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.someValuesFrom,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.allValuesFrom,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.hasValue,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.minCardinality,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.maxCardinality,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.cardinality,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.first,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.rest,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.disjointWith,null)); - defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.inverseOf,null)); + HashSet defaultInferenceDrivingPatternAllowSet = new HashSet<>(); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDF.type)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDFS.subClassOf)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDFS.subPropertyOf)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.equivalentClass)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.unionOf)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.intersectionOf)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.complementOf)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.oneOf)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.onProperty)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.someValuesFrom)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.allValuesFrom)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.hasValue)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.minCardinality)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.maxCardinality)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.cardinality)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDF.first)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDF.rest)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.disjointWith)); + defaultInferenceDrivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.inverseOf)); DEFAULT.setInferenceDrivingPatternAllowSet(defaultInferenceDrivingPatternAllowSet); - Set defaultInferenceReceivingPatternAllowSet = new HashSet(); - defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.type,null)); - defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDFS.subClassOf,null)); - defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDFS.subPropertyOf,null)); - defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.equivalentClass,null)); - defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.disjointWith,null)); - defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.inverseOf,null)); + Set defaultInferenceReceivingPatternAllowSet = new HashSet<>(); + defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDF.type)); + defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDFS.subClassOf)); + defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(RDFS.subPropertyOf)); + defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.equivalentClass)); + defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.disjointWith)); + defaultInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.inverseOf)); DEFAULT.setInferenceReceivingPatternAllowSet(defaultInferenceReceivingPatternAllowSet); DEFAULT.setQueryForAllObjectProperties(false); @@ -107,36 +107,36 @@ public class ReasonerConfiguration { COMPLETE.setQueryForAllObjectProperties(true); COMPLETE.setReasonOnAllDatatypePropertyStatements(true); COMPLETE.setQueryForAllDatatypeProperties(true); - Set completeInferenceReceivingPatternAllowSet = new HashSet(); + Set completeInferenceReceivingPatternAllowSet = new HashSet<>(); completeInferenceReceivingPatternAllowSet.addAll(defaultInferenceReceivingPatternAllowSet); - completeInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null, OWL.sameAs, null)); + completeInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern(OWL.sameAs)); // getting NPEs inside Pellet with differentFrom on 2.0.0-rc7 - //completeInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null, OWL.differentFrom, null)); + //completeInferenceReceivingPatternAllowSet.add(ReasonerStatementPattern.objectPattern( OWL.differentFrom, null)); COMPLETE.setInferenceReceivingPatternAllowSet(completeInferenceReceivingPatternAllowSet); } - public Set getInferenceDrivingPatternAllowSet() { + public Set getInferenceDrivingPatternAllowSet() { return this.inferenceDrivingPatternAllowSet; } - public void setInferenceDrivingPatternAllowSet(Set patternSet) { + public void setInferenceDrivingPatternAllowSet(Set patternSet) { this.inferenceDrivingPatternAllowSet = patternSet; } - public Set getInferenceDrivingPatternDenySet() { + public Set getInferenceDrivingPatternDenySet() { return this.inferenceDrivingPatternDenySet; } - public void setInferenceDrivingPatternDenySet(Set patternSet) { + public void setInferenceDrivingPatternDenySet(Set patternSet) { this.inferenceDrivingPatternDenySet = patternSet; } - public Set getInferenceReceivingPatternAllowSet() { + public Set getInferenceReceivingPatternAllowSet() { return this.inferenceReceivingPatternAllowSet; } - public void setInferenceReceivingPatternAllowSet(Set patternSet) { + public void setInferenceReceivingPatternAllowSet(Set patternSet) { this.inferenceReceivingPatternAllowSet = patternSet; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ReasonerStatementPattern.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ReasonerStatementPattern.java new file mode 100644 index 000000000..e1c1c627e --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ReasonerStatementPattern.java @@ -0,0 +1,94 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.tboxreasoner; + +import java.util.List; + +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.shared.Lock; + +/** + * For now, this only models Object Properties. + * + * It should be easy to add Data Property patterns by making this abstract and + * creating two concrete subclasses. + */ +public class ReasonerStatementPattern { + public static final ReasonerStatementPattern ANY_OBJECT_PROPERTY = new ReasonerStatementPattern( + null, null, null); + + public static ReasonerStatementPattern objectPattern(Property predicate) { + return new ReasonerStatementPattern(null, predicate, null); + } + + public static ReasonerStatementPattern objectPattern(Statement stmt) { + if (!stmt.getObject().isResource()) { + throw new IllegalArgumentException( + "Object of stmt must be a resource."); + } + return new ReasonerStatementPattern(stmt.getSubject(), + stmt.getPredicate(), stmt.getObject().asResource()); + } + + /** + * Any or all of these may be null, which acts as a wild card. + */ + private final Resource subject; + private final Property predicate; + private final Resource object; + private final String toString; + + private ReasonerStatementPattern(Resource subject, Property predicate, + Resource object) { + this.subject = subject; + this.predicate = predicate; + this.object = object; + this.toString = buildToString(); + } + + public Property getPredicate() { + return predicate; + } + + /** + * All fields must match, either by being equal, or by being a wild card. + */ + public boolean matches(ReasonerStatementPattern that) { + boolean sMatch = this.subject == null || that.subject == null + || this.subject.equals(that.subject); + boolean pMatch = this.predicate == null || that.predicate == null + || this.predicate.equals(that.predicate); + boolean oMatch = this.object == null || that.object == null + || this.object.equals(that.object); + return sMatch && pMatch && oMatch; + } + + /** + * Get a list of statements from this model that match this pattern. + */ + public List matchStatementsFromModel(Model m) { + m.enterCriticalSection(Lock.READ); + try { + return m.listStatements(subject, predicate, object).toList(); + } finally { + m.leaveCriticalSection(); + } + } + + public String buildToString() { + return "ReasonerStatementPattern[subject=" + + (subject == null ? "*" : subject.toString()) + ", predicate=" + + (predicate == null ? "*" : predicate.toString()) + + ", object=" + (object == null ? "*" : object.toString()) + + "]"; + } + + @Override + public String toString() { + return toString; + } + +} From ac5c73ef42cb4265632d18aa266027a45200d783 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Fri, 21 Nov 2014 14:04:01 -0500 Subject: [PATCH 02/10] VIVO-778 Separate PelletReasonerSetup from SimpleReasonerSetup. --- .../webapp/servlet/setup/FileGraphSetup.java | 7 -- .../servlet/setup/PelletReasonerSetup.java | 106 ++++++++++++++++++ .../servlet/setup/SimpleReasonerSetup.java | 67 +---------- .../servlet/setup/UpdateKnowledgeBase.java | 2 +- .../WEB-INF/resources/startup_listeners.txt | 1 + 5 files changed, 110 insertions(+), 73 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java index 4fbd5d8c2..8e4cc757c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java @@ -97,13 +97,6 @@ public class FileGraphSetup implements ServletContextListener { OntDocumentManager.getInstance().setProcessImports(false); } - /* - if (isUpdateRequired(ctx)) { - log.info("mostSpecificType will be computed because a knowledge base migration was performed." ); - SimpleReasonerSetup.setMSTComputeRequired(ctx); - } else - */ - if ( (aboxChanged || tboxChanged) && !isUpdateRequired(ctx)) { log.info("a full recompute of the Abox will be performed because" + " the filegraph abox(s) and/or tbox(s) have changed or are being read for the first time." ); 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 new file mode 100644 index 000000000..476717121 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java @@ -0,0 +1,106 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.servlet.setup; + +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_ASSERTIONS; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_INFERENCES; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_UNION; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +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 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.ReasonerConfiguration; + +/** + * Start the Pellet reasoner on the TBox. + */ +public class PelletReasonerSetup implements ServletContextListener { + private static final Log log = LogFactory.getLog(PelletReasonerSetup.class); + + @Override + public void contextInitialized(ServletContextEvent sce) { + ServletContext ctx = sce.getServletContext(); + StartupStatus ss = StartupStatus.getBean(ctx); + + ContextModelAccess contextModels = ModelAccess.on(ctx); + OntModel tboxAssertionsModel = contextModels + .getOntModel(TBOX_ASSERTIONS); + OntModel tboxInferencesModel = contextModels + .getOntModel(TBOX_INFERENCES); + 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, + ReasonerConfiguration.DEFAULT); + sce.getServletContext().setAttribute("pelletListener", pelletListener); + sce.getServletContext().setAttribute("pelletOntModel", + pelletListener.getPelletModel()); + + if (wadf instanceof WebappDaoFactoryJena) { + ((WebappDaoFactoryJena) wadf).setPelletListener(pelletListener); + } + + ss.info(this, "Pellet reasoner connected for the TBox"); + + waitForTBoxReasoning(sce); + } + + public static void waitForTBoxReasoning(ServletContextEvent sce) { + PelletListener pelletListener = (PelletListener) sce + .getServletContext().getAttribute("pelletListener"); + if (pelletListener == null) { + return; + } + int sleeps = 0; + // sleep at least once to make sure the TBox reasoning gets started + while ((0 == sleeps) + || ((sleeps < 1000) && pelletListener.isReasoning())) { + if (((sleeps - 1) % 10) == 0) { // print message at 10 second + // intervals + log.info("Waiting for initial TBox reasoning to complete"); + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // This should never happen. + e.printStackTrace(); + } + sleeps++; + } + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + // Nothing to tear down + } + +} 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 48a2fb1e2..3422eccff 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 @@ -21,11 +21,7 @@ import org.apache.commons.logging.LogFactory; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.query.Dataset; import com.hp.hpl.jena.rdf.model.Model; -import com.hp.hpl.jena.vocabulary.OWL; -import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; -import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena; -import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; @@ -33,7 +29,6 @@ import edu.cornell.mannlib.vitro.webapp.reasoner.ReasonerPlugin; import edu.cornell.mannlib.vitro.webapp.reasoner.SimpleReasoner; import edu.cornell.mannlib.vitro.webapp.reasoner.SimpleReasonerTBoxListener; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration; import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; public class SimpleReasonerSetup implements ServletContextListener { @@ -51,41 +46,10 @@ public class SimpleReasonerSetup implements ServletContextListener { ServletContext ctx = sce.getServletContext(); try { - // set up Pellet reasoning for the TBox OntModel tboxAssertionsModel = ModelAccess.on(ctx).getOntModel(ModelNames.TBOX_ASSERTIONS); OntModel tboxInferencesModel = ModelAccess.on(ctx).getOntModel(ModelNames.TBOX_INFERENCES); OntModel tboxUnionModel = ModelAccess.on(ctx).getOntModel(ModelNames.TBOX_UNION); - log.debug("tboxAssertionsModel=" + tboxAssertionsModel); - log.debug("tboxInferencesModel=" + tboxInferencesModel); - log.debug("tboxUnionModel=" + tboxUnionModel); - WebappDaoFactory wadf = ModelAccess.on(ctx).getWebappDaoFactory(); - - if (!tboxAssertionsModel.getProfile().NAMESPACE().equals(OWL.NAMESPACE.getNameSpace())) { - log.error("Not connecting Pellet reasoner - the TBox assertions model is not an OWL model"); - return; - } - - // Set various Pellet options for incremental consistency checking, etc. - //PelletOptions.DL_SAFE_RULES = true; - //PelletOptions.USE_COMPLETION_QUEUE = true; - //PelletOptions.USE_TRACING = true; - //PelletOptions.TRACK_BRANCH_EFFECTS = true; - //PelletOptions.USE_INCREMENTAL_CONSISTENCY = true; - //PelletOptions.USE_INCREMENTAL_DELETION = true; - - PelletListener pelletListener = new PelletListener(tboxUnionModel,tboxAssertionsModel,tboxInferencesModel,ReasonerConfiguration.DEFAULT); - sce.getServletContext().setAttribute("pelletListener",pelletListener); - sce.getServletContext().setAttribute("pelletOntModel", pelletListener.getPelletModel()); - - if (wadf instanceof WebappDaoFactoryJena) { - ((WebappDaoFactoryJena) wadf).setPelletListener(pelletListener); - } - - log.info("Pellet reasoner connected for the TBox"); - - waitForTBoxReasoning(sce); - // set up simple reasoning for the ABox RDFService rdfService = ModelAccess.on(ctx).getRDFService(); @@ -139,23 +103,6 @@ public class SimpleReasonerSetup implements ServletContextListener { } } - public static void waitForTBoxReasoning(ServletContextEvent sce) - throws InterruptedException { - PelletListener pelletListener = (PelletListener) sce.getServletContext().getAttribute("pelletListener"); - if (pelletListener == null) { - return ; - } - int sleeps = 0; - // sleep at least once to make sure the TBox reasoning gets started - while ((0 == sleeps) || ((sleeps < 1000) && pelletListener.isReasoning())) { - if (((sleeps - 1) % 10) == 0) { // print message at 10 second intervals - log.info("Waiting for initial TBox reasoning to complete"); - } - Thread.sleep(1000); - sleeps++; - } - } - @Override public void contextDestroyed(ServletContextEvent sce) { log.info("received contextDestroyed notification"); @@ -209,17 +156,6 @@ public class SimpleReasonerSetup implements ServletContextListener { return (RecomputeMode) ctx.getAttribute(RECOMPUTE_REQUIRED_ATTR); } - private static final String MSTCOMPUTE_REQUIRED_ATTR = - SimpleReasonerSetup.class.getName() + ".MSTComputeRequired"; - - public static void setMSTComputeRequired(ServletContext ctx) { - ctx.setAttribute(MSTCOMPUTE_REQUIRED_ATTR, true); - } - - private static boolean isMSTComputeRequired(ServletContext ctx) { - return (ctx.getAttribute(MSTCOMPUTE_REQUIRED_ATTR) != null); - } - /** * Read the names of the plugin classes classes. * @@ -278,7 +214,8 @@ public class SimpleReasonerSetup implements ServletContextListener { this.simpleReasoner = simpleReasoner; } - public void run() { + @Override + public void run() { simpleReasoner.recompute(); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java index d7931035e..92a4e81e5 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java @@ -89,7 +89,7 @@ public class UpdateKnowledgeBase implements ServletContextListener { putReportingPathsIntoSettings(ctx, settings); putNonReportingPathsIntoSettings(ctx, settings); - SimpleReasonerSetup.waitForTBoxReasoning(sce); + PelletReasonerSetup.waitForTBoxReasoning(sce); WebappDaoFactory wadf = ModelAccess.on(ctx).getWebappDaoFactory(); settings.setDefaultNamespace(wadf.getDefaultNamespace()); diff --git a/webapp/web/WEB-INF/resources/startup_listeners.txt b/webapp/web/WEB-INF/resources/startup_listeners.txt index c5c9803eb..02a1f48fd 100644 --- a/webapp/web/WEB-INF/resources/startup_listeners.txt +++ b/webapp/web/WEB-INF/resources/startup_listeners.txt @@ -34,6 +34,7 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.RemoveObsoletePermissions edu.cornell.mannlib.vitro.webapp.servlet.setup.FileGraphSetup +edu.cornell.mannlib.vitro.webapp.servlet.setup.PelletListenerSetup edu.cornell.mannlib.vitro.webapp.servlet.setup.SimpleReasonerSetup #edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdateKnowledgeBase From e0abd88ac2be9b53615a2d5cfe02339e6795d1cd Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Wed, 26 Nov 2014 11:38:13 -0500 Subject: [PATCH 03/10] BOGUS - add a TBoxReasonerSmokeTest at startup to insure that the generated inferences don't change by my actions. --- webapp/rdf/tbox/savedInferences.n3 | 2543 +++++++++++++++++ .../servlet/setup/TBoxReasonerSmokeTest.java | 73 + 2 files changed, 2616 insertions(+) create mode 100644 webapp/rdf/tbox/savedInferences.n3 create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/TBoxReasonerSmokeTest.java diff --git a/webapp/rdf/tbox/savedInferences.n3 b/webapp/rdf/tbox/savedInferences.n3 new file mode 100644 index 000000000..9e7f4d50a --- /dev/null +++ b/webapp/rdf/tbox/savedInferences.n3 @@ -0,0 +1,2543 @@ +@prefix ocresd: . +@prefix geo: . +@prefix foaf: . +@prefix scires: . +@prefix cito: . +@prefix fabio: . +@prefix vcard: . +@prefix rdfs: . +@prefix obo: . +@prefix ocrer: . +@prefix vitro: . +@prefix event: . +@prefix bibo: . +@prefix xsd: . +@prefix owl: . +@prefix rdf: . +@prefix c4o: . +@prefix vitro-public: . +@prefix skos: . +@prefix vivo: . + +vcard:Identification rdfs:subClassOf vcard:Security , vcard:TimeZone , vcard:Calendar , vcard:Geo , owl:Thing , vcard:Geographical ; + owl:equivalentClass vcard:Identification , vcard:Explanatory , vcard:Organizational , vcard:Communication , vcard:Addressing . + +vcard:hasFormattedName + rdfs:subPropertyOf vcard:hasFormattedName , owl:topObjectProperty . + +geo:countryAreaNotes rdfs:subPropertyOf + geo:countryAreaNotes , owl:topDataProperty . + +vivo:dateTime rdfs:subPropertyOf vivo:dateTime , owl:topDataProperty . + +fabio:Erratum rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass fabio:Erratum . + +vivo:Certificate rdfs:subClassOf skos:Concept , owl:Thing ; + owl:equivalentClass vivo:Certificate . + +vivo:AdministratorRole + rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:AdministratorRole . + +obo:ERO_0000398 rdfs:subPropertyOf owl:topObjectProperty , obo:ERO_0000398 . + +geo:codeUN rdfs:subPropertyOf geo:codeUN , owl:topDataProperty . + +bibo:performer rdfs:subPropertyOf bibo:performer , owl:topObjectProperty . + +obo:OBI_0000304 rdfs:subPropertyOf obo:OBI_0000304 , owl:topObjectProperty . + +geo:countryArea rdfs:subPropertyOf geo:countryArea , owl:topDataProperty . + +vcard:hasOrganizationName + rdfs:subPropertyOf vcard:hasOrganizationName , owl:topObjectProperty . + +bibo:pmid rdfs:subPropertyOf vivo:identifier , bibo:pmid , owl:topDataProperty . + +obo:RO_0000056 rdfs:subPropertyOf obo:RO_0000056 , owl:topObjectProperty ; + owl:inverseOf obo:RO_0000057 . + +vivo:PostdocOrFellowAdvisingRelationship + rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:PostdocOrFellowAdvisingRelationship . + +vivo:PrimaryPosition rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:PrimaryPosition . + +skos:broader rdfs:subPropertyOf skos:broader , owl:topObjectProperty . + +vivo:contributingRole + rdfs:subPropertyOf vivo:contributingRole , owl:topObjectProperty . + +geo:hasShortName rdfs:subPropertyOf geo:hasShortName , owl:topDataProperty . + +ocresd:Phase_4 rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass ocresd:Phase_4 . + +vivo:Competition rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:Competition . + +geo:codeFAOTERM rdfs:subPropertyOf geo:codeFAOTERM , owl:topDataProperty . + +obo:ERO_0000776 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000776 . + +bibo:eissn rdfs:subPropertyOf vivo:identifier , bibo:eissn , owl:topDataProperty . + +vivo:AwardReceipt rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:AwardReceipt . + +ocrer:Interventional_study + a owl:Class ; + rdfs:subClassOf owl:Thing ; + owl:equivalentClass ocrer:Interventional_study . + +vivo:F1000Link rdfs:subClassOf vcard:Geographical , owl:Thing , vcard:Identification , vcard:Organizational , vcard:Geo , vcard:Addressing , vcard:Security , vcard:Explanatory , vcard:Communication , vcard:Calendar , vcard:TimeZone ; + owl:equivalentClass vivo:F1000Link . + +vcard:Video rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Video . + +vivo:grantDirectCosts + rdfs:subPropertyOf vivo:grantDirectCosts , owl:topDataProperty . + +geo:countryAreaUnit rdfs:subPropertyOf + geo:countryAreaUnit , owl:topDataProperty . + +geo:isAdministeredBy rdfs:subPropertyOf + geo:isAdministeredBy , owl:topObjectProperty . + +obo:ERO_0000071 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000071 . + +obo:ERO_0000919 rdfs:subPropertyOf owl:topObjectProperty , obo:ERO_0000919 ; + owl:inverseOf obo:ERO_0000918 . + +vivo:offeredBy rdfs:subPropertyOf vivo:offeredBy , owl:topObjectProperty ; + owl:inverseOf vivo:offers . + +vitro:bannerWidth rdfs:subPropertyOf vitro:bannerWidth , owl:topDataProperty . + +obo:ERO_0000790 rdfs:subClassOf obo:BFO_0000020 , owl:Thing , obo:BFO_0000023 , obo:BFO_0000001 , obo:BFO_0000002 , obo:BFO_0000017 ; + owl:disjointWith obo:ARG_2000021 , obo:BFO_0000019 , obo:ARG_2000022 ; + owl:equivalentClass obo:ERO_0000790 . + +vivo:Course rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:Course . + +geo:hasNationality rdfs:subPropertyOf geo:hasNationality , owl:topDataProperty . + +vcard:TelephoneType rdfs:subClassOf owl:Thing ; + owl:equivalentClass vcard:TelephoneType . + +vcard:TimeZone rdfs:subClassOf owl:Thing ; + owl:equivalentClass vcard:TimeZone . + +vitro:ClassGroup rdfs:subClassOf owl:Thing ; + owl:equivalentClass vitro:ClassGroup . + +vivo:SubnationalRegion + rdfs:subClassOf obo:BFO_0000141 , vivo:Location , obo:BFO_0000001 , owl:Thing , obo:BFO_0000006 , vivo:GeographicLocation , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:SubnationalRegion . + +geo:nameShortES rdfs:subPropertyOf geo:nameShortES , owl:topDataProperty . + +obo:ERO_0000481 rdfs:subPropertyOf obo:ERO_0000481 , owl:topObjectProperty ; + owl:inverseOf scires:protocolRealizedBy . + +vivo:hasCollaborator rdfs:subPropertyOf + vivo:hasCollaborator , owl:topObjectProperty . + +vivo:Student rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Student . + +vitro:bannerImage rdfs:subPropertyOf vitro:bannerImage , owl:topDataProperty . + +vcard:FormattedName rdfs:subClassOf vcard:Addressing , vcard:Geographical , vcard:Calendar , vcard:Geo , vcard:Organizational , vcard:Security , owl:Thing , vcard:Communication , vcard:Explanatory , vcard:TimeZone ; + owl:equivalentClass vcard:FormattedName . + +bibo:director rdfs:subPropertyOf bibo:director , owl:topObjectProperty . + +obo:BFO_0000051 rdfs:subPropertyOf obo:BFO_0000051 , owl:topObjectProperty . + +geo:nameOfficialES rdfs:subPropertyOf geo:nameOfficialES , owl:topDataProperty . + +vivo:FacultyAdministrativePosition + rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:FacultyAdministrativePosition . + +obo:ERO_0000393 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000393 . + +bibo:sici rdfs:subPropertyOf vivo:identifier , bibo:sici , owl:topDataProperty . + +vcard:revision rdfs:subPropertyOf vcard:revision , owl:topDataProperty . + +owl:bottomDataProperty + a owl:DatatypeProperty , owl:FunctionalProperty ; + rdfs:subPropertyOf vcard:photo , vcard:language , bibo:eanucc13 , geo:nameShortAR , vcard:calendarLink , vitro:logotypeHeight , geo:nameOfficialFR , owl:topDataProperty , geo:countryAreaYear , geo:hasMinLatitude , vitro:bannerHeight , geo:population , bibo:isbn13 , bibo:issn , vitro:urlPrefix , bibo:isbn10 , obo:ARG_0000197 , vcard:familyName , vivo:outreachOverview , vivo:isCorrespondingAuthor , geo:nameListRU , vivo:licenseNumber , vivo:majorField , obo:ERO_0000045 , vitro:displayLimit , vivo:sponsorAwardId , geo:nationalityAR , geo:nameCurrencyEN , geo:countryAreaNotes , geo:GDP , vivo:localAwardId , bibo:upc , vitro:namespaceURI , geo:hasMinLongitude , vivo:eRACommonsId , vivo:reportId , geo:nameCurrencyIT , vivo:teachingOverview , bibo:numPages , geo:nameListEN , vitro-public:mimeType , geo:nationalityZH , geo:codeDBPediaID , obo:ARG_0000172 , geo:countryAreaTotal , vcard:calendarBusy , geo:countryAreaUnit , obo:ERO_0000046 , geo:nameOfficialZH , , vitro:rootLogotypeImage , geo:agriculturalAreaTotal , geo:codeISO3 , geo:nameShortFR , geo:GDPUnit , vivo:dateTime , vitro:acknowledgeText , bibo:lccn , vitro:md5password , vitro:bannerWidth , vivo:supplementalInformation , bibo:oclcnum , geo:nameCurrencyRU , geo:landArea , vivo:patentNumber , vcard:locality , geo:hasCurrency , bibo:uri , vivo:grantDirectCosts , geo:codeGAUL , vcard:instantMessage , vitro:firstTime , bibo:pageEnd , bibo:sici , vcard:honorificSuffix , vivo:overview , geo:nameListFR , vivo:totalAwardAmount , obo:ERO_0000774 , geo:nameShortIT , vitro:moniker , vivo:researcherId , vivo:abbreviation , geo:populationUnit , geo:hasNationality , bibo:gtin14 , geo:hasStatistics , geo:nameOfficialAR , vitro:logotypeImage , geo:countryArea , vivo:hrJobTitle , geo:hasMaxLatitude , vcard:gender , geo:hasListName , geo:nameShortES , geo:GDPNotes , geo:nameCurrencyZH , obo:ERO_0000044 , c4o:hasGlobalCountValue , geo:codeUNDP , geo:HDITotal , vitro-public:filename , geo:GDPTotalInCurrentPrices , geo:nationalityIT , vcard:givenName , bibo:pageStart , vivo:termLabel , vivo:identifier , vcard:url , obo:ERO_0000424 , vivo:seatingCapacity , vivo:hideFromDisplay , vivo:entryTerm , vitro:rootBreadCrumbAnchor , geo:populationTotal , vcard:country , geo:codeISO2 , geo:nameListES , vcard:sound , geo:validUntil , geo:hasCode , geo:landAreaUnit , vcard:region , bibo:volume , geo:hasOfficialName , vivo:middleName , vivo:preferredDisplayOrder , vcard:productId , bibo:issue , vcard:anniversary , vivo:termType , scires:irbNumber , geo:hasCoordinate , vcard:related , vcard:organizationName , vcard:birthdate , geo:landAreaYear , bibo:prefixName , geo:HDIYear , bibo:number , vitro:themeDir , geo:hasMaxLongitude , geo:nationalityFR , geo:HDINotes , vitro:modTime , bibo:chapter , geo:nameShortRU , vivo:cclCode , vcard:key , obo:ARG_0000015 , geo:agriculturalArea , bibo:pmid , obo:ERO_0000050 , obo:ARG_0000001 , vivo:researchOverview , vitro:imageThumbWidth , vcard:revision , bibo:eissn , bibo:identifier , vitro:contactMail , geo:HDIUnit , vivo:rank , vivo:hasMonetaryAmount , vitro:hidden , vitro:displayRank , geo:codeCurrency , vcard:additionalName , geo:codeUN , geo:nameShortEN , geo:nameCurrencyAR , vcard:source , bibo:locator , vivo:iclCode , geo:codeFAOTERM , geo:nameShortZH , vitro:shortHand , vitro-public:directDownloadUrl , bibo:section , vcard:category , geo:populationYear , geo:codeFAOSTAT , vcard:organizationalUnitName , geo:nationalityEN , bibo:coden , vcard:postalCode , owl:bottomDataProperty , vitro:oldpassword , vivo:scopusId , vcard:uid , geo:landAreaNotes , geo:nameListIT , geo:nameCurrencyFR , vivo:contactInformation , geo:validSince , geo:GDPYear , geo:nameListZH , vitro:logotypeWidth , bibo:shortDescription , vivo:placeOfPublication , obo:ERO_0000054 , vivo:pmcid , vcard:timeZone , vcard:note , geo:agriculturalAreaYear , geo:nationalityRU , bibo:abstract , geo:nameOfficialES , vitro:aboutText , vitro:roleURI , vitro:copyrightURL , vitro:rootBreadCrumbURL , vitro:loginCount , vcard:nickName , geo:nameCurrencyES , geo:codeAGROVOC , vcard:role , geo:hasShortName , scires:nctId , obo:ARG_2000012 , vivo:description , vitro:username , vivo:courseCredits , geo:agriculturalAreaNotes , geo:nameOfficialIT , vivo:hasValue , vcard:telephone , geo:landAreaTotal , vcard:honorificPrefix , vitro:copyrightAnchor , vivo:freetextKeyword , vcard:logo , vcard:streetAddress , geo:HDI , vcard:email , bibo:doi , vitro:bannerImage , vivo:departmentOrSchool , geo:agriculturalAreaUnit , geo:nameListAR , bibo:edition , geo:nameOfficialEN , vcard:formattedName , obo:ERO_0000072 , geo:nameOfficialRU , vcard:sortAs , c4o:hasGlobalCountDate , vcard:geo , vitro-public:attribution , vcard:calendarRequest , geo:populationNotes , vcard:title , vivo:nihmsid , geo:nationalityES , bibo:asin , scires:studyPopulationCount . + +vcard:Addressing rdfs:subClassOf vcard:TimeZone , vcard:Security , vcard:Geo , owl:Thing , vcard:Calendar , vcard:Geographical ; + owl:equivalentClass vcard:Explanatory , vcard:Identification , vcard:Organizational , vcard:Communication , vcard:Addressing . + +event:Event rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass event:Event . + +bibo:Legislation rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Legislation . + +obo:ERO_0000789 rdfs:subClassOf obo:BFO_0000023 , obo:BFO_0000002 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000020 , obo:BFO_0000001 ; + owl:disjointWith obo:BFO_0000019 , obo:ARG_2000021 , obo:ARG_2000022 ; + owl:equivalentClass obo:ERO_0000789 . + + + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:IAO_0000027 , obo:BFO_0000002 ; + owl:equivalentClass . + +obo:ERO_0000038 rdfs:subPropertyOf obo:ERO_0000038 , owl:topObjectProperty . + +scires:protocolRealizedBy + rdfs:subPropertyOf scires:protocolRealizedBy , owl:topObjectProperty . + +vivo:Dataset rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Dataset . + +obo:ERO_0000006 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000006 . + +vitro-public:image rdfs:subPropertyOf vitro-public:image , owl:topObjectProperty . + +vivo:OrganizingProcess + rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:OrganizingProcess . + +geo:economic_region rdfs:subClassOf geo:area , owl:Thing ; + owl:equivalentClass geo:economic_region . + +obo:ERO_0000020 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000020 . + +obo:ERO_0000914 rdfs:subClassOf obo:BFO_0000017 , owl:Thing , obo:BFO_0000002 , obo:BFO_0000023 , obo:BFO_0000001 , obo:BFO_0000020 ; + owl:disjointWith obo:BFO_0000019 , obo:ARG_2000022 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000914 . + +geo:populationTotal rdfs:subPropertyOf + geo:populationTotal , owl:topDataProperty . + +vivo:patentNumber rdfs:subPropertyOf vivo:identifier , vivo:patentNumber , owl:topDataProperty . + +geo:hasOfficialName rdfs:subPropertyOf + geo:hasOfficialName , owl:topDataProperty . + +obo:ARG_2000008 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , obo:IAO_0000109 , owl:Thing , obo:BFO_0000031 , obo:IAO_0000027 , obo:BFO_0000002 ; + owl:equivalentClass obo:ARG_2000008 . + +bibo:Letter rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Letter . + +vcard:hasURL rdfs:subPropertyOf vcard:hasURL , owl:topObjectProperty . + +bibo:Brief rdfs:subClassOf bibo:Document , obo:IAO_0000030 , bibo:LegalDocument , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Brief . + +vcard:role rdfs:subPropertyOf vcard:role , owl:topDataProperty . + +obo:ARG_2000022 rdfs:subClassOf owl:Thing , obo:BFO_0000001 , obo:BFO_0000020 , obo:BFO_0000002 ; + owl:disjointWith obo:ERO_0000914 , obo:BFO_0000023 , obo:ERO_0000787 , obo:ERO_0000785 , vivo:PrincipalInvestigatorRole , vivo:AdvisorRole , vivo:CoPrincipalInvestigatorRole , obo:ERO_0000224 , vivo:AttendeeRole , vivo:OutreachProviderRole , obo:ERO_0000778 , obo:BFO_0000034 , obo:ERO_0000595 , obo:BFO_0000016 , obo:OBI_0000017 , vivo:LeaderRole , obo:ERO_0000784 , vivo:ReviewerRole , vivo:PeerReviewerRole , obo:ERO_0000789 , obo:ERO_0000777 , obo:ERO_0000790 , vivo:EditorRole , vivo:MemberRole , vivo:ResearcherRole , obo:BFO_0000017 , obo:ERO_0000012 , vivo:OrganizerRole , obo:ERO_0000783 , obo:ERO_0000779 , vivo:TeacherRole , vivo:AdviseeRole , obo:ERO_0000788 , obo:ERO_0000786 , obo:ERO_0000780 , obo:ERO_0000776 , obo:ERO_0000225 , vivo:AdministratorRole , vivo:ClinicalRole , vivo:PresenterRole , vivo:InvestigatorRole ; + owl:equivalentClass obo:ARG_2000022 . + +geo:nameShortEN rdfs:subPropertyOf geo:nameShortEN , owl:topDataProperty . + +obo:RO_0001025 rdfs:subPropertyOf obo:RO_0001025 , owl:topObjectProperty ; + owl:inverseOf obo:RO_0001015 . + +obo:OBI_0000312 rdfs:subPropertyOf obo:OBI_0000312 , obo:RO_0000056 , owl:topObjectProperty ; + owl:inverseOf obo:OBI_0000299 . + +bibo:unpublished a owl:Thing . + +bibo:abstract rdfs:subPropertyOf bibo:abstract , owl:topDataProperty . + +vcard:honorificSuffix + rdfs:subPropertyOf vcard:honorificSuffix , owl:topDataProperty . + +vivo:equipmentFor rdfs:subPropertyOf vivo:equipmentFor , owl:topObjectProperty ; + owl:inverseOf vivo:hasEquipment . + +bibo:Hearing rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass bibo:Hearing . + +vcard:None rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:None . + +obo:ERO_0000595 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000595 . + +vcard:hasCalendarRequest + rdfs:subPropertyOf vcard:hasCalendarRequest , owl:topObjectProperty . + +geo:nameOfficialEN rdfs:subPropertyOf geo:nameOfficialEN , owl:topDataProperty . + +obo:ARG_2000400 a obo:IAO_0000003 , obo:IAO_0000030 , obo:IAO_0000009 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 . + + + a owl:ObjectProperty ; + rdfs:subPropertyOf , owl:topObjectProperty . + +vcard:hasAddress rdfs:subPropertyOf vcard:hasAddress , owl:topObjectProperty . + +vcard:Logo rdfs:subClassOf vcard:Communication , vcard:Geo , vcard:Security , vcard:Geographical , vcard:Addressing , owl:Thing , vcard:Identification , vcard:TimeZone , vcard:Calendar , vcard:Explanatory ; + owl:equivalentClass vcard:Logo . + +geo:landAreaYear rdfs:subPropertyOf geo:landAreaYear , owl:topDataProperty . + +bibo:Manual rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Manual . + +obo:ERO_0000784 rdfs:subClassOf obo:BFO_0000017 , obo:BFO_0000020 , obo:BFO_0000023 , obo:BFO_0000002 , owl:Thing , obo:BFO_0000001 ; + owl:disjointWith obo:BFO_0000019 , obo:ARG_2000022 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000784 . + +geo:nationalityIT rdfs:subPropertyOf geo:nationalityIT , owl:topDataProperty . + +obo:ARG_2000376 rdfs:subClassOf owl:Thing ; + owl:equivalentClass obo:ARG_2000376 . + +bibo:isbn13 rdfs:subPropertyOf bibo:isbn13 , vivo:identifier , owl:topDataProperty . + +obo:ERO_0001261 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001261 . + +obo:ERO_0000033 rdfs:subPropertyOf obo:ERO_0000033 , owl:topObjectProperty . + +vcard:Individual rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:ARG_2000379 , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vcard:Individual . + +geo:nationalityFR rdfs:subPropertyOf geo:nationalityFR , owl:topDataProperty . + +bibo:AudioDocument rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:AudioDocument . + +vivo:validIn rdfs:subPropertyOf vivo:validIn , owl:topObjectProperty . + +vivo:inPress a owl:Thing . + +bibo:Report rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Report . + +obo:ARG_2000390 rdfs:subPropertyOf owl:topObjectProperty , obo:ARG_2000390 . + +vcard:givenName rdfs:subPropertyOf vcard:givenName , owl:topDataProperty . + +foaf:Group rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass foaf:Group . + +geo:disputed rdfs:subClassOf obo:BFO_0000141 , vivo:GeopoliticalEntity , geo:area , vivo:GeographicRegion , owl:Thing , obo:BFO_0000006 , obo:BFO_0000004 , vivo:GeographicLocation , obo:BFO_0000001 , vivo:Location , obo:BFO_0000002 ; + owl:equivalentClass geo:disputed . + +bibo:Performance rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass bibo:Performance . + +vcard:birthdate rdfs:subPropertyOf vcard:birthdate , owl:topDataProperty . + +vcard:Fax rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Fax . + +vcard:instantMessage rdfs:subPropertyOf + vcard:instantMessage , owl:topDataProperty . + +geo:agriculturalAreaUnit + rdfs:subPropertyOf geo:agriculturalAreaUnit , owl:topDataProperty . + +geo:codeUNDP rdfs:subPropertyOf geo:codeUNDP , owl:topDataProperty . + +vcard:gender rdfs:subPropertyOf vcard:gender , owl:topDataProperty . + +obo:RO_0002234 rdfs:subPropertyOf obo:RO_0002234 , owl:topObjectProperty . + +vcard:url rdfs:subPropertyOf vcard:url , owl:topDataProperty . + +vcard:Nickname rdfs:subClassOf vcard:Geo , owl:Thing , vcard:Geographical , vcard:Calendar , vcard:Addressing , vcard:TimeZone , vcard:Explanatory , vcard:Security , vcard:Communication , vcard:Organizational ; + owl:equivalentClass vcard:Nickname . + +vivo:ResearchProposal + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:ResearchProposal . + +c4o:hasGlobalCountDate + rdfs:subPropertyOf c4o:hasGlobalCountDate , owl:topDataProperty . + +vivo:CoreLaboratory rdfs:subClassOf foaf:Agent , vivo:Laboratory , obo:BFO_0000001 , owl:Thing , foaf:Organization , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:CoreLaboratory . + +vivo:abbreviation rdfs:subPropertyOf vivo:abbreviation , owl:topDataProperty . + +bibo:distributor rdfs:subPropertyOf bibo:distributor , owl:topObjectProperty ; + owl:inverseOf vivo:distributes . + +vcard:Work rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Work . + +vivo:overview rdfs:subPropertyOf vivo:overview , owl:topDataProperty . + +geo:nationalityRU rdfs:subPropertyOf geo:nationalityRU , owl:topDataProperty . + +vcard:Pager rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Pager . + +vivo:reviewedIn rdfs:subPropertyOf vivo:reviewedIn , owl:topObjectProperty ; + owl:inverseOf bibo:reviewOf . + +vcard:hasCalendarLink + rdfs:subPropertyOf vcard:hasCalendarLink , owl:topObjectProperty . + +geo:nameCurrencyES rdfs:subPropertyOf geo:nameCurrencyES , owl:topDataProperty . + +obo:ERO_0000046 rdfs:subPropertyOf obo:ERO_0000046 , owl:topDataProperty . + +vivo:start rdfs:subPropertyOf vivo:start , owl:topObjectProperty . + +bibo:presents rdfs:subPropertyOf bibo:presents , owl:topObjectProperty ; + owl:inverseOf bibo:presentedAt . + +vivo:proceedingsOf rdfs:subPropertyOf vivo:proceedingsOf , owl:topObjectProperty . + +obo:ERO_0000014 rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:ERO_0000014 . + +vivo:grantSubcontractedThrough + rdfs:subPropertyOf vivo:grantSubcontractedThrough , owl:topObjectProperty ; + owl:inverseOf vivo:subcontractsGrant . + +vcard:Coworker rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Coworker . + +vivo:ServiceProvidingLaboratory + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , foaf:Organization , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:ServiceProvidingLaboratory . + +cito:isCitedAsDataSourceBy + rdfs:subPropertyOf cito:isCitedAsDataSourceBy , owl:topObjectProperty . + +vivo:ClinicalOrganization + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:ClinicalOrganization . + +bibo:translationOf rdfs:subPropertyOf bibo:translationOf , owl:topObjectProperty ; + owl:inverseOf vivo:hasTranslation . + +obo:RO_0003001 rdfs:subPropertyOf obo:RO_0003001 , owl:topObjectProperty . + +vivo:assignedBy rdfs:subPropertyOf vivo:assignedBy , owl:topObjectProperty ; + owl:inverseOf vivo:assigns . + +obo:ERO_0000424 rdfs:subPropertyOf obo:ERO_0000424 , owl:topDataProperty . + +vivo:rank rdfs:subPropertyOf vivo:rank , owl:topDataProperty . + +vivo:hasFundingVehicle + a owl:ObjectProperty ; + rdfs:subPropertyOf vivo:hasFundingVehicle , vivo:supportedBy , owl:topObjectProperty ; + owl:inverseOf vivo:fundingVehicleFor . + +vitro:displayRank rdfs:subPropertyOf vitro:displayRank , owl:topDataProperty . + +vitro:copyrightURL rdfs:subPropertyOf vitro:copyrightURL , owl:topDataProperty . + +obo:RO_0001019 rdfs:subPropertyOf obo:RO_0001019 , owl:topObjectProperty ; + owl:inverseOf obo:RO_0001018 . + +vivo:hasFacility a owl:ObjectProperty ; + rdfs:subPropertyOf vivo:hasFacility , owl:topObjectProperty ; + owl:inverseOf vivo:facilityFor . + +vivo:Hospital rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Hospital . + +vitro:moniker rdfs:subPropertyOf vitro:moniker , owl:topDataProperty . + +vivo:researchOverview + rdfs:subPropertyOf vivo:researchOverview , owl:topDataProperty . + +vivo:ReviewerRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:ReviewerRole . + +vitro:username rdfs:subPropertyOf vitro:username , owl:topDataProperty . + +obo:ERO_0001518 rdfs:subPropertyOf obo:ERO_0001518 , owl:topObjectProperty . + +bibo:recipient rdfs:subPropertyOf bibo:recipient , owl:topObjectProperty . + +obo:ARG_0000172 rdfs:subPropertyOf obo:ARG_0000172 , owl:topDataProperty . + +bibo:Manuscript rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Manuscript . + +bibo:presentedAt rdfs:subPropertyOf bibo:presentedAt , owl:topObjectProperty . + +obo:BFO_0000040 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass obo:BFO_0000040 . + +vcard:RelatedType rdfs:subClassOf owl:Thing ; + owl:equivalentClass vcard:RelatedType . + +vcard:Group rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:ARG_2000379 , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vcard:Group . + +geo:HDINotes rdfs:subPropertyOf geo:HDINotes , owl:topDataProperty . + +geo:HDIYear rdfs:subPropertyOf geo:HDIYear , owl:topDataProperty . + +obo:ERO_0000778 rdfs:subClassOf owl:Thing , obo:BFO_0000017 , obo:BFO_0000001 , obo:BFO_0000023 , obo:BFO_0000002 , obo:BFO_0000020 ; + owl:disjointWith obo:ARG_2000021 , obo:BFO_0000019 , obo:ARG_2000022 ; + owl:equivalentClass obo:ERO_0000778 . + +vivo:Position rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:Position . + +vcard:hasSound rdfs:subPropertyOf owl:topObjectProperty , vcard:hasSound . + +obo:ERO_0001255 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001255 . + +vcard:Address rdfs:subClassOf vcard:Geo , vcard:TimeZone , vcard:Geographical , vcard:Communication , vcard:Calendar , vcard:Explanatory , vcard:Security , vcard:Organizational , owl:Thing , vcard:Identification ; + owl:equivalentClass vcard:Address . + +obo:OBI_0000011 rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:OBI_0000011 . + +vitro:modTime rdfs:subPropertyOf vitro:modTime , owl:topDataProperty . + +geo:nameCurrencyEN rdfs:subPropertyOf geo:nameCurrencyEN , owl:topDataProperty . + +owl:topDataProperty a owl:DatatypeProperty ; + rdfs:subPropertyOf owl:topDataProperty . + +geo:nameListES rdfs:subPropertyOf geo:nameListES , owl:topDataProperty . + +vivo:Certification rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:Certification . + +vitro:aboutText rdfs:subPropertyOf vitro:aboutText , owl:topDataProperty . + +geo:population rdfs:subPropertyOf geo:population , owl:topDataProperty . + +rdfs:seeAlso a owl:AnnotationProperty . + +obo:ARG_2000029 rdfs:subPropertyOf obo:ARG_2000029 , owl:topObjectProperty . + +vivo:contactInformation + a owl:DatatypeProperty ; + rdfs:subPropertyOf vivo:contactInformation , owl:topDataProperty . + +bibo:DocumentStatus rdfs:subClassOf owl:Thing ; + owl:equivalentClass bibo:DocumentStatus . + +vivo:dateFiled rdfs:subPropertyOf vivo:dateFiled , owl:topObjectProperty . + +obo:BFO_0000141 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass obo:BFO_0000141 . + +bibo:issuer rdfs:subPropertyOf bibo:issuer , owl:topObjectProperty . + +geo:agriculturalAreaTotal + rdfs:subPropertyOf geo:agriculturalAreaTotal , owl:topDataProperty . + +vivo:freetextKeyword rdfs:subPropertyOf + vivo:freetextKeyword , owl:topDataProperty . + +vivo:EditorRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:EditorRole . + +vivo:dateTimeInterval + rdfs:subPropertyOf vivo:dateTimeInterval , owl:topObjectProperty . + +bibo:Interview rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass bibo:Interview . + +vivo:featuredIn rdfs:subPropertyOf vivo:featuredIn , owl:topObjectProperty . + + + rdfs:subPropertyOf , owl:topObjectProperty . + +obo:ARG_2000011 rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing , obo:OBI_0000011 ; + owl:equivalentClass obo:ARG_2000011 . + +vitro:bannerHeight rdfs:subPropertyOf vitro:bannerHeight , owl:topDataProperty . + +vcard:Unknown rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Unknown . + +vivo:hasPublicationVenue + rdfs:subPropertyOf vivo:hasPublicationVenue , owl:topObjectProperty . + +obo:ERO_0000395 rdfs:subClassOf obo:ERO_0000005 , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000395 . + +bibo:affirmedBy rdfs:subPropertyOf bibo:affirmedBy , owl:topObjectProperty . + +vivo:FacultyMentoringRelationship + rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:FacultyMentoringRelationship . + +vivo:GraduateAdvisingRelationship + rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:GraduateAdvisingRelationship . + +vitro:shortHand rdfs:subPropertyOf vitro:shortHand , owl:topDataProperty . + +owl:priorVersion a owl:AnnotationProperty . + +vcard:timeZone rdfs:subPropertyOf vcard:timeZone , owl:topDataProperty . + +obo:RO_0000053 rdfs:subPropertyOf obo:RO_0000053 , owl:topObjectProperty ; + owl:inverseOf obo:RO_0000052 . + +vivo:translatorOf rdfs:subPropertyOf vivo:translatorOf , owl:topObjectProperty ; + owl:inverseOf bibo:translator . + +vivo:geographicFocus rdfs:subPropertyOf + vivo:geographicFocus , owl:topObjectProperty ; + owl:inverseOf vivo:geographicFocusOf . + +vitro:hidden rdfs:subPropertyOf vitro:hidden , owl:topDataProperty . + +geo:landAreaTotal rdfs:subPropertyOf geo:landAreaTotal , owl:topDataProperty . + +vivo:NewsRelease rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:NewsRelease . + +geo:validUntil rdfs:subPropertyOf geo:validUntil , owl:topDataProperty . + +vcard:sortAs rdfs:subPropertyOf vcard:sortAs , owl:topDataProperty . + +foaf:Organization rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass foaf:Organization . + +ocresd:Phase_1 rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass ocresd:Phase_1 . + +bibo:published a owl:Thing . + +geo:populationYear rdfs:subPropertyOf geo:populationYear , owl:topDataProperty . + +obo:ERO_0000054 rdfs:subPropertyOf obo:ERO_0000054 , owl:topDataProperty . + +vcard:logo rdfs:subPropertyOf vcard:logo , owl:topDataProperty . + +vivo:hasPrerequisite rdfs:subPropertyOf + vivo:hasPrerequisite , owl:topObjectProperty . + +vivo:UndergraduateAdvisingRelationship + rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:UndergraduateAdvisingRelationship . + +vivo:EmeritusFaculty rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:EmeritusFaculty . + +bibo:reversedBy rdfs:subPropertyOf bibo:reversedBy , owl:topObjectProperty . + +obo:ARG_0000001 rdfs:subPropertyOf obo:ARG_0000001 , owl:topDataProperty . + +obo:IAO_0000033 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000033 . + +vcard:Text rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Text . + +geo:nameListEN rdfs:subPropertyOf geo:nameListEN , owl:topDataProperty . + +vivo:sponsoredBy rdfs:subPropertyOf owl:topObjectProperty , vivo:sponsoredBy ; + owl:inverseOf vivo:sponsors . + +vitro:firstTime rdfs:subPropertyOf vitro:firstTime , owl:topDataProperty . + +geo:geographical_region + rdfs:subClassOf owl:Thing , vivo:GeographicLocation , geo:area , obo:BFO_0000004 , obo:BFO_0000141 , obo:BFO_0000002 , obo:BFO_0000006 , obo:BFO_0000001 , vivo:Location ; + owl:equivalentClass geo:geographical_region . + +geo:nameShortZH rdfs:subPropertyOf geo:nameShortZH , owl:topDataProperty . + +vivo:AcademicDegree rdfs:subClassOf owl:Thing ; + owl:equivalentClass vivo:AcademicDegree . + +vcard:Other rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Other . + +bibo:PersonalCommunicationDocument + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:PersonalCommunicationDocument . + +vivo:Translation rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Translation . + +geo:validSince rdfs:subPropertyOf geo:validSince , owl:topDataProperty . + +vivo:researchAreaOf rdfs:subPropertyOf + vivo:researchAreaOf , owl:topObjectProperty ; + owl:inverseOf vivo:hasResearchArea . + +vivo:invited a owl:Thing . + +scires:Phase4ClinicalTrial + rdfs:subClassOf ocrer:Interventional_study , owl:Thing ; + owl:equivalentClass scires:Phase4ClinicalTrial . + +vivo:facilityFor rdfs:subPropertyOf vivo:facilityFor , owl:topObjectProperty . + +vivo:expirationDate rdfs:subPropertyOf + vivo:expirationDate , owl:topObjectProperty . + +obo:BFO_0000034 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:BFO_0000034 . + +vivo:geographicFocusOf + rdfs:subPropertyOf vivo:geographicFocusOf , owl:topObjectProperty . + +vivo:ConferenceSeries + rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:ConferenceSeries . + +vcard:geo rdfs:subPropertyOf vcard:geo , owl:topDataProperty . + +bibo:interviewer rdfs:subPropertyOf bibo:interviewer , owl:topObjectProperty . + +bibo:AudioVisualDocument + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:AudioVisualDocument . + +vivo:UndergraduateStudent + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , foaf:Person , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:UndergraduateStudent . + +obo:BFO_0000002 rdfs:subClassOf owl:Thing ; + owl:equivalentClass obo:BFO_0000002 . + +owl:topObjectProperty + a owl:SymmetricProperty , owl:ReflexiveProperty , owl:TransitiveProperty ; + rdfs:subPropertyOf owl:topObjectProperty . + +bibo:Thesis rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Thesis . + +vivo:GraduateStudent rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , foaf:Person , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:GraduateStudent . + +vivo:Relationship rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:Relationship . + +obo:ERO_0000390 rdfs:subPropertyOf obo:ERO_0000390 , owl:topObjectProperty . + +geo:nameOfficialZH rdfs:subPropertyOf geo:nameOfficialZH , owl:topDataProperty . + +vivo:DateTimeInterval + rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000008 ; + owl:equivalentClass vivo:DateTimeInterval . + +obo:ERO_0000565 rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000565 . + +vitro-public:attribution + rdfs:subPropertyOf vitro-public:attribution , owl:topDataProperty . + +obo:IAO_0000102 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000102 . + +bibo:Patent rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Patent . + +obo:ERO_0000786 rdfs:subClassOf obo:BFO_0000017 , obo:BFO_0000020 , obo:BFO_0000023 , obo:BFO_0000002 , owl:Thing , obo:BFO_0000001 ; + owl:disjointWith obo:BFO_0000019 , obo:ARG_2000022 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000786 . + +bibo:Article rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Article . + +vcard:honorificPrefix + rdfs:subPropertyOf vcard:honorificPrefix , owl:topDataProperty . + +obo:ERO_0001263 rdfs:subClassOf obo:ERO_0000005 , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001263 . + +obo:OBI_0000272 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:OBI_0000272 . + +vivo:nihmsid rdfs:subPropertyOf vivo:identifier , vivo:nihmsid , owl:topDataProperty . + +vcard:note rdfs:subPropertyOf vcard:note , owl:topDataProperty . + +obo:ERO_0000224 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000224 . + +vivo:features rdfs:subPropertyOf owl:topObjectProperty , vivo:features ; + owl:inverseOf vivo:featuredIn . + +geo:codeISO2 rdfs:subPropertyOf geo:codeISO2 , owl:topDataProperty . + +vitro-public:mainImage + rdfs:subPropertyOf vitro-public:mainImage , owl:topObjectProperty . + +vivo:eligibleFor rdfs:subPropertyOf vivo:eligibleFor , owl:topObjectProperty . + +vcard:Date rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Date . + +vivo:ResearcherRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:ResearcherRole . + +vcard:Friend rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Friend . + +vivo:termType rdfs:subPropertyOf vivo:termType , owl:topDataProperty . + +vivo:degreeCandidacy rdfs:subPropertyOf + owl:topObjectProperty , vivo:degreeCandidacy . + +vivo:supportedBy rdfs:subPropertyOf vivo:supportedBy , owl:topObjectProperty . + +vcard:hasTimeZone rdfs:subPropertyOf vcard:hasTimeZone , owl:topObjectProperty . + +geo:self_governing rdfs:subClassOf obo:BFO_0000002 , owl:Thing , vivo:GeographicLocation , vivo:GeographicRegion , obo:BFO_0000001 , obo:BFO_0000004 , obo:BFO_0000141 , vivo:Location , obo:BFO_0000006 , geo:area ; + owl:equivalentClass geo:self_governing . + +bibo:rejected a owl:Thing . + +vivo:dateTimeValue rdfs:subPropertyOf owl:topObjectProperty , vivo:dateTimeValue . + +bibo:Proceedings rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Proceedings . + +vivo:NonFacultyAcademic + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:NonFacultyAcademic . + +obo:BFO_0000015 rdfs:subClassOf obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:BFO_0000015 . + +vivo:FacultyMember rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:FacultyMember . + +bibo:Journal rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , bibo:Collection , obo:BFO_0000002 ; + owl:equivalentClass bibo:Journal . + +vcard:Female rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Female . + +vcard:country rdfs:subPropertyOf vcard:country , owl:topDataProperty . + +ocresd:OCRE100038 rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass ocresd:OCRE100038 . + +vivo:assigns rdfs:subPropertyOf vivo:assigns , owl:topObjectProperty . + +obo:ERO_0001521 rdfs:subPropertyOf obo:ERO_0001521 , owl:topObjectProperty ; + owl:inverseOf obo:ERO_0001520 . + +vivo:Authorship rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:Authorship . + +vcard:Gender rdfs:subClassOf owl:Thing ; + owl:equivalentClass vcard:Gender . + +vcard:hasRelated rdfs:subPropertyOf vcard:hasRelated , owl:topObjectProperty . + +vcard:streetAddress rdfs:subPropertyOf + vcard:streetAddress , owl:topDataProperty . + +vivo:Presentation rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:Presentation . + +vivo:TeacherRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:TeacherRole . + +vitro:rootBreadCrumbURL + rdfs:subPropertyOf vitro:rootBreadCrumbURL , owl:topDataProperty . + +vivo:OutreachProviderRole + rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:OutreachProviderRole . + +obo:ERO_0000016 rdfs:subClassOf owl:Thing ; + owl:equivalentClass obo:ERO_0000016 . + +vivo:Association rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Association . + +geo:hasMember rdfs:subPropertyOf geo:hasMember , owl:topObjectProperty . + +obo:BFO_0000148 rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:BFO_0000148 . + +vitro:logotypeHeight rdfs:subPropertyOf + vitro:logotypeHeight , owl:topDataProperty . + +bibo:Image rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Image . + +bibo:isbn10 rdfs:subPropertyOf bibo:isbn10 , vivo:identifier , owl:topDataProperty . + +obo:IAO_0000027 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000027 . + +bibo:LegalCaseDocument + rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:LegalCaseDocument . + +vcard:calendarBusy rdfs:subPropertyOf vcard:calendarBusy , owl:topDataProperty . + +vivo:County rdfs:subClassOf vivo:GeographicLocation , obo:BFO_0000004 , owl:Thing , obo:BFO_0000006 , vivo:Location , obo:BFO_0000141 , obo:BFO_0000001 , obo:BFO_0000002 , vivo:GeographicRegion ; + owl:equivalentClass vivo:County . + +obo:RO_0002351 rdfs:subPropertyOf obo:RO_0002351 , owl:topObjectProperty ; + owl:inverseOf obo:RO_0002350 . + +obo:OBI_0500000 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:IAO_0000033 , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:OBI_0500000 . + +bibo:Slideshow rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Slideshow . + +vitro:urlPrefix rdfs:subPropertyOf vitro:urlPrefix , owl:topDataProperty . + +bibo:Website rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Website . + +vcard:Geo rdfs:subClassOf owl:Thing ; + owl:equivalentClass vcard:Geo . + +owl:bottomObjectProperty + a owl:SymmetricProperty , owl:InverseFunctionalProperty , owl:FunctionalProperty , owl:AsymmetricProperty , owl:TransitiveProperty , owl:IrreflexiveProperty , owl:ObjectProperty ; + rdfs:subPropertyOf owl:sameAs , , obo:RO_0003000 , obo:RO_0002353 , vcard:hasFormattedName , obo:OBI_0000304 , bibo:court , obo:IAO_0000417 , vcard:hasMember , owl:topObjectProperty , vitro-public:image , vivo:fundingVehicleFor , vivo:relatedBy , vivo:dateTimeInterval , vivo:hasPublicationVenue , vivo:offeredBy , vivo:end , bibo:presentedAt , , c4o:hasGlobalCountSource , obo:ERO_0000918 , vitro:rootTab , obo:ERO_0000543 , vcard:hasKey , obo:ARG_2000029 , obo:ERO_0000482 , vivo:hasSubjectArea , vivo:supports , obo:RO_0002351 , obo:ERO_0000070 , vivo:reviewedIn , obo:ERO_0000033 , geo:isAdministeredBy , bibo:performer , c4o:hasGlobalCitationFrequency , vivo:dateFiled , skos:broader , obo:OBI_0000833 , obo:OBI_0000417 , geo:isPredecessorOf , obo:OBI_0000299 , vivo:governingAuthorityFor , obo:ERO_0000037 , obo:RO_0001015 , bibo:distributor , obo:ERO_0000572 , geo:isInGroup , bibo:reversedBy , scires:documentationFor , obo:RO_0001019 , vcard:hasOrganizationalUnitName , cito:isCitedAsDataSourceBy , obo:OBI_0000293 , obo:ERO_0001521 , bibo:interviewer , vivo:sponsors , obo:ERO_0000029 , vcard:hasOrganizationName , vcard:hasLogo , vivo:publicationVenueFor , , obo:BFO_0000051 , vcard:hasLanguage , vivo:subcontractsGrant , vcard:hasTelephone , obo:RO_0002234 , vivo:hasCollaborator , obo:BFO_0000055 , vcard:hasGeo , geo:isSuccessorOf , vivo:facilityFor , vivo:supportedInformationResource , vcard:hasCategory , vivo:hasResearchArea , vivo:expirationDate , vivo:affiliatedOrganization , vivo:publisherOf , bibo:reviewOf , obo:IAO_0000039 , vivo:hasPrerequisite , obo:RO_0000053 , bibo:status , vivo:conceptAssociatedWith , vivo:relates , vitro-public:mainImage , vivo:sponsoredBy , obo:RO_0000057 , vivo:assigneeFor , vitro-public:thumbnailImage , vivo:hasFacility , bibo:issuer , obo:ERO_0000397 , obo:RO_0002220 , vivo:hasEquipment , obo:RO_0001025 , bibo:presents , vivo:supportedBy , obo:ARG_2000391 , owl:DeprecatedProperty , bibo:degree , vivo:eligibleFor , vivo:validIn , scires:accessProvidedBy , vivo:featuredIn , vivo:start , vcard:hasInstantMessage , obo:OBI_0000643 , vivo:geographicFocusOf , vivo:assignee , vivo:features , obo:ARG_2000028 , vcard:hasCalendarLink , vivo:offers , vivo:dateTimeValue , bibo:interviewee , bibo:subsequentLegalDecision , scires:protocolRealizedBy , obo:RO_0002350 , vivo:grantSubcontractedThrough , vivo:assigns , geo:hasBorderWith , vivo:subjectAreaOf , , bibo:cites , vivo:contributingRole , obo:ERO_0000460 , vivo:translatorOf , vivo:hasSuccessorOrganization , obo:ARG_2000399 , vivo:distributes , vivo:distributesFundingFrom , obo:ERO_0000775 , obo:RO_0003001 , vcard:hasRelated , skos:related , vivo:roleContributesTo , vitro-public:downloadLocation , vcard:hasPhoto , bibo:citedBy , vivo:proceedingsOf , obo:ERO_0001520 , vivo:prerequisiteFor , obo:ERO_0000919 , bibo:director , vcard:hasTitle , vivo:hasAssociatedConcept , obo:BFO_0000050 , skos:narrower , vivo:geographicFocus , obo:RO_0002233 , obo:ERO_0000034 , vivo:hasPredecessorOrganization , obo:BFO_0000054 , obo:ERO_0000398 , obo:RO_0001000 , obo:ERO_0000038 , vivo:hasGoverningAuthority , vivo:confirmedOrcidId , obo:RO_0000052 , vivo:degreeCandidacy , vivo:hasProceedings , vivo:researchAreaOf , obo:ERO_0000481 , bibo:annotates , obo:RO_0000056 , geo:hasMember , vivo:publisher , bibo:affirmedBy , obo:ERO_0000390 , , vivo:dateTimePrecision , bibo:recipient , owl:bottomObjectProperty , obo:IAO_0000142 , cito:citesAsDataSource , vivo:orcidId , obo:ARG_2000390 , vcard:hasSound , vivo:assignedBy , vcard:hasCalendarRequest , vcard:hasCalenderBusy , vcard:hasNickname , vivo:hasTranslation , bibo:transcriptOf , vivo:informationResourceSupportedBy , obo:IAO_0000221 , vcard:hasNote , obo:OBI_0000312 , bibo:translator , vivo:hasFundingVehicle , obo:IAO_0000136 , obo:RO_0001018 , vcard:hasAddress , vivo:dateIssued , vcard:hasTimeZone , vcard:hasURL , vivo:reproduces , vcard:hasName , vcard:hasEmail , obo:ERO_0000031 , bibo:reproducedIn , obo:ERO_0001518 , bibo:translationOf , vivo:equipmentFor , vivo:providesFundingThrough . + +skos:Concept rdfs:subClassOf owl:Thing ; + owl:equivalentClass skos:Concept . + +bibo:DocumentPart rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:DocumentPart . + +vcard:CalendarBusy rdfs:subClassOf vcard:Security , vcard:TimeZone , owl:Thing , vcard:Geographical , vcard:Geo ; + owl:equivalentClass vcard:CalendarBusy . + +bibo:Issue rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Issue . + +vivo:Licensure rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:Licensure . + +geo:GDPTotalInCurrentPrices + rdfs:subPropertyOf geo:GDPTotalInCurrentPrices , owl:topDataProperty . + +geo:nameShortAR rdfs:subPropertyOf geo:nameShortAR , owl:topDataProperty . + +vivo:assigneeFor rdfs:subPropertyOf vivo:assigneeFor , owl:topObjectProperty . + +vivo:submitted a owl:Thing . + +vivo:reproduces rdfs:subPropertyOf vivo:reproduces , owl:topObjectProperty . + +vivo:supports rdfs:subPropertyOf vivo:supports , owl:topObjectProperty ; + owl:inverseOf vivo:supportedBy . + +vcard:hasNote rdfs:subPropertyOf vcard:hasNote , owl:topObjectProperty . + +vcard:hasGeo rdfs:subPropertyOf vcard:hasGeo , owl:topObjectProperty . + +vivo:Screenplay rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Screenplay . + +vcard:hasName rdfs:subPropertyOf vcard:hasName , owl:topObjectProperty . + +vivo:ClinicalRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:ClinicalRole . + +bibo:issn rdfs:subPropertyOf vivo:identifier , bibo:issn , owl:topDataProperty . + +geo:countryAreaTotal rdfs:subPropertyOf + geo:countryAreaTotal , owl:topDataProperty . + +vivo:Grant rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:Grant . + +geo:nameOfficialAR rdfs:subPropertyOf geo:nameOfficialAR , owl:topDataProperty . + +vivo:MemberRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:MemberRole . + +obo:IAO_0000142 rdfs:subPropertyOf obo:IAO_0000142 , owl:topObjectProperty . + +geo:non_self_governing + rdfs:subClassOf vivo:Location , obo:BFO_0000004 , obo:BFO_0000001 , geo:area , obo:BFO_0000141 , owl:Thing , obo:BFO_0000002 , vivo:GeographicLocation , vivo:GeographicRegion , vivo:GeopoliticalEntity , obo:BFO_0000006 ; + owl:equivalentClass geo:non_self_governing . + +bibo:court rdfs:subPropertyOf bibo:court , owl:topObjectProperty . + +obo:ERO_0001257 rdfs:subClassOf obo:ERO_0000005 , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001257 . + +obo:ERO_0000029 rdfs:subPropertyOf obo:ERO_0000029 , owl:topObjectProperty ; + owl:inverseOf scires:accessProvidedBy . + +owl:DeprecatedProperty + a owl:ObjectProperty ; + rdfs:subPropertyOf owl:DeprecatedProperty , owl:topObjectProperty . + +vivo:outreachOverview + rdfs:subPropertyOf vivo:outreachOverview , owl:topDataProperty . + +vivo:publisher rdfs:subPropertyOf vivo:publisher , owl:topObjectProperty . + +bibo:volume rdfs:subPropertyOf bibo:volume , owl:topDataProperty . + +scires:studyPopulationCount + rdfs:subPropertyOf scires:studyPopulationCount , owl:topDataProperty . + +vivo:CaseStudy rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:CaseStudy . + +geo:nameCurrencyZH rdfs:subPropertyOf geo:nameCurrencyZH , owl:topDataProperty . + +vivo:Building rdfs:subClassOf obo:BFO_0000141 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000029 , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Building . + +vcard:Photo rdfs:subClassOf vcard:TimeZone , vcard:Communication , vcard:Geo , vcard:Addressing , owl:Thing , vcard:Geographical , vcard:Organizational , vcard:Calendar , vcard:Security , vcard:Explanatory ; + owl:equivalentClass vcard:Photo . + +vivo:Program rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Program . + +bibo:CourtReporter rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , bibo:Collection , obo:BFO_0000002 ; + owl:equivalentClass bibo:CourtReporter . + +vivo:Review rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Review . + +vivo:SeminarSeries rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:SeminarSeries . + +vivo:Team rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Team . + +geo:GDPUnit rdfs:subPropertyOf geo:GDPUnit , owl:topDataProperty . + +vivo:sponsorAwardId rdfs:subPropertyOf + vivo:sponsorAwardId , owl:topDataProperty . + +bibo:Series rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Series . + +vitro-public:FileByteStream + rdfs:subClassOf owl:Thing ; + owl:equivalentClass vitro-public:FileByteStream . + +c4o:GlobalCitationCount + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , obo:IAO_0000109 , owl:Thing , obo:BFO_0000031 , obo:IAO_0000027 , obo:BFO_0000002 ; + owl:equivalentClass c4o:GlobalCitationCount . + +vitro:acknowledgeText + rdfs:subPropertyOf vitro:acknowledgeText , owl:topDataProperty . + +obo:OBI_0000833 rdfs:subPropertyOf obo:OBI_0000833 , owl:topObjectProperty . + +vcard:Calendar rdfs:subClassOf vcard:TimeZone , owl:Thing , vcard:Geographical , vcard:Geo ; + owl:equivalentClass vcard:Security , vcard:Calendar . + +vivo:hasResearchArea rdfs:subPropertyOf + vivo:hasResearchArea , owl:topObjectProperty . + +geo:special_group rdfs:subClassOf geo:area , owl:Thing ; + owl:equivalentClass geo:special_group . + +obo:BFO_0000055 rdfs:subPropertyOf obo:BFO_0000055 , owl:topObjectProperty . + +obo:ERO_0000397 rdfs:subPropertyOf obo:ERO_0000397 , owl:topObjectProperty ; + owl:inverseOf obo:ERO_0000398 . + +vivo:providesFundingThrough + rdfs:subPropertyOf vivo:providesFundingThrough , owl:topObjectProperty ; + owl:inverseOf vivo:distributesFundingFrom . + +vcard:Emergency rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Emergency . + +obo:IAO_0000109 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000109 . + +obo:BFO_0000023 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:BFO_0000023 . + +geo:landAreaUnit rdfs:subPropertyOf geo:landAreaUnit , owl:topDataProperty . + +geo:agriculturalArea rdfs:subPropertyOf + geo:agriculturalArea , owl:topDataProperty . + +bibo:oclcnum rdfs:subPropertyOf vivo:identifier , bibo:oclcnum , owl:topDataProperty . + +vivo:courseCredits rdfs:subPropertyOf vivo:courseCredits , owl:topDataProperty . + +vivo:termLabel rdfs:subPropertyOf vivo:termLabel , owl:topDataProperty . + +vcard:additionalName rdfs:subPropertyOf + vcard:additionalName , owl:topDataProperty . + +vivo:yearMonthPrecision + a skos:Concept , owl:Thing . + +vcard:hasNickname rdfs:subPropertyOf vcard:hasNickname , owl:topObjectProperty . + +vcard:hasKey rdfs:subPropertyOf vcard:hasKey , owl:topObjectProperty . + +obo:ARG_2000399 rdfs:subPropertyOf obo:ARG_2000399 , owl:topObjectProperty . + +ocresd:Phase_3 rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass ocresd:Phase_3 . + +vcard:Related rdfs:subClassOf vcard:TimeZone , owl:Thing , vcard:Geographical , vcard:Communication , vcard:Addressing , vcard:Calendar , vcard:Identification , vcard:Security , vcard:Geo , vcard:Explanatory ; + owl:equivalentClass vcard:Related . + +fabio:Comment rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass fabio:Comment . + +obo:OBI_0000293 rdfs:subPropertyOf owl:topObjectProperty , obo:RO_0000057 , obo:OBI_0000293 . + +geo:hasCurrency rdfs:subPropertyOf geo:hasCurrency , owl:topDataProperty . + +vcard:Kind rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vcard:Kind . + +obo:ERO_0000775 rdfs:subPropertyOf obo:ERO_0000775 , owl:topObjectProperty . + +bibo:doi rdfs:subPropertyOf vivo:identifier , bibo:doi , owl:topDataProperty . + +vitro:logotypeImage rdfs:subPropertyOf + vitro:logotypeImage , owl:topDataProperty . + +vcard:OrganizationUnitName + rdfs:subClassOf vcard:Communication , vcard:Geographical , vcard:Organizational , vcard:Geo , vcard:TimeZone , owl:Thing , vcard:Explanatory , vcard:Security , vcard:Calendar , vcard:Addressing , vcard:Identification ; + owl:equivalentClass vcard:OrganizationUnitName . + +bibo:locator rdfs:subPropertyOf bibo:locator , owl:topDataProperty . + +vcard:CalendarLink rdfs:subClassOf vcard:Security , vcard:TimeZone , owl:Thing , vcard:Geographical , vcard:Geo ; + owl:equivalentClass vcard:CalendarLink . + +vivo:PresenterRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:PresenterRole . + +geo:nationalityES rdfs:subPropertyOf owl:topDataProperty , geo:nationalityES . + +vivo:Credential rdfs:subClassOf owl:Thing ; + owl:equivalentClass vivo:Credential . + +obo:ERO_0000918 rdfs:subPropertyOf obo:ERO_0000918 , owl:topObjectProperty . + +obo:ERO_0000070 rdfs:subPropertyOf obo:ERO_0000070 , owl:topObjectProperty ; + owl:inverseOf obo:ERO_0000031 . + +geo:nameListZH rdfs:subPropertyOf geo:nameListZH , owl:topDataProperty . + +vcard:formattedName rdfs:subPropertyOf + vcard:formattedName , owl:topDataProperty . + +vitro:loginCount rdfs:subPropertyOf vitro:loginCount , owl:topDataProperty . + +vivo:Division rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Division . + +vivo:OrganizerRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:OrganizerRole . + +vivo:affiliatedOrganization + rdfs:subPropertyOf owl:topObjectProperty , vivo:affiliatedOrganization . + +geo:landAreaNotes rdfs:subPropertyOf geo:landAreaNotes , owl:topDataProperty . + +vivo:ResearchOrganization + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:ResearchOrganization . + +geo:hasListName rdfs:subPropertyOf geo:hasListName , owl:topDataProperty . + +vivo:reportId rdfs:subPropertyOf vivo:identifier , vivo:reportId , owl:topDataProperty . + +obo:IAO_0000003 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000003 . + +geo:GDP rdfs:subPropertyOf geo:GDP , owl:topDataProperty . + +bibo:Collection rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Collection . + + + rdfs:subPropertyOf , owl:topDataProperty . + +geo:codeGAUL rdfs:subPropertyOf geo:codeGAUL , owl:topDataProperty . + +vcard:productId rdfs:subPropertyOf vcard:productId , owl:topDataProperty . + +vivo:AcademicDepartment + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , foaf:Organization , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:AcademicDepartment . + +vivo:PostdoctoralTraining + rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:PostdoctoralTraining . + +vivo:Blog rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , bibo:Collection , obo:BFO_0000002 ; + owl:equivalentClass vivo:Blog . + +vcard:Language rdfs:subClassOf vcard:Geo , owl:Thing , vcard:TimeZone , vcard:Geographical , vcard:Identification , vcard:Security , vcard:Organizational , vcard:Explanatory , vcard:Calendar , vcard:Addressing ; + owl:equivalentClass vcard:Language . + +obo:OBI_0100026 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass obo:OBI_0100026 . + +bibo:transcriptOf rdfs:subPropertyOf bibo:transcriptOf , owl:topObjectProperty . + +vivo:Library rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Library . + +vcard:Category rdfs:subClassOf vcard:Geo , owl:Thing , vcard:TimeZone , vcard:Organizational , vcard:Geographical , vcard:Communication , vcard:Addressing , vcard:Security , vcard:Identification , vcard:Calendar ; + owl:equivalentClass vcard:Category . + +geo:GDPNotes rdfs:subPropertyOf geo:GDPNotes , owl:topDataProperty . + +vivo:cclCode rdfs:subPropertyOf vivo:cclCode , owl:topDataProperty . + +vivo:Department rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Department . + +obo:BFO_0000004 rdfs:subClassOf obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:BFO_0000004 . + +bibo:issue rdfs:subPropertyOf bibo:issue , owl:topDataProperty . + +vcard:Home rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Home . + +obo:IAO_0000136 rdfs:subPropertyOf obo:IAO_0000136 , owl:topObjectProperty . + +obo:BFO_0000050 rdfs:subPropertyOf obo:BFO_0000050 , owl:topObjectProperty ; + owl:inverseOf obo:BFO_0000051 . + +obo:ERO_0000392 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000392 . + +geo:other rdfs:subClassOf vivo:GeographicLocation , vivo:Location , obo:BFO_0000141 , obo:BFO_0000001 , obo:BFO_0000002 , vivo:GeographicRegion , vivo:GeopoliticalEntity , obo:BFO_0000006 , geo:area , obo:BFO_0000004 , owl:Thing ; + owl:equivalentClass geo:other . + +bibo:Statute rdfs:subClassOf bibo:Document , obo:IAO_0000030 , bibo:LegalDocument , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Statute . + +vcard:hasPhoto rdfs:subPropertyOf vcard:hasPhoto , owl:topObjectProperty . + +bibo:section rdfs:subPropertyOf bibo:section , owl:topDataProperty . + +obo:IAO_0000104 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000104 . + +obo:ERO_0000788 rdfs:subClassOf obo:BFO_0000001 , obo:BFO_0000023 , obo:BFO_0000002 , obo:BFO_0000020 , owl:Thing , obo:BFO_0000017 ; + owl:disjointWith obo:ARG_2000022 , obo:ARG_2000021 , obo:BFO_0000019 ; + owl:equivalentClass obo:ERO_0000788 . + +vivo:hasValue rdfs:subPropertyOf vivo:hasValue , owl:topDataProperty . + +vivo:PopulatedPlace rdfs:subClassOf vivo:Location , owl:Thing , obo:BFO_0000006 , obo:BFO_0000001 , vivo:GeographicRegion , obo:BFO_0000002 , vivo:GeographicLocation , obo:BFO_0000004 , obo:BFO_0000141 ; + owl:equivalentClass vivo:PopulatedPlace . + +obo:ERO_0000037 rdfs:subPropertyOf owl:topObjectProperty , obo:ERO_0000037 ; + owl:inverseOf obo:ERO_0000390 . + +vivo:offers rdfs:subPropertyOf vivo:offers , owl:topObjectProperty . + +vivo:Speech rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Speech . + +vivo:University rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:University . + +geo:nameCurrencyAR rdfs:subPropertyOf geo:nameCurrencyAR , owl:topDataProperty . + +vivo:scopusId rdfs:subPropertyOf vivo:scopusId , owl:topDataProperty . + +vivo:licenseNumber rdfs:subPropertyOf vivo:licenseNumber , owl:topDataProperty . + +obo:ERO_0000005 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000005 . + +foaf:Person rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass foaf:Person . + +obo:OBI_0000417 rdfs:subPropertyOf obo:OBI_0000417 , owl:topObjectProperty ; + owl:inverseOf obo:OBI_0000833 . + +vivo:Newsletter rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , bibo:Collection , obo:BFO_0000002 ; + owl:equivalentClass vivo:Newsletter . + +vivo:hasGoverningAuthority + a owl:ObjectProperty ; + rdfs:subPropertyOf vivo:hasGoverningAuthority , owl:topObjectProperty ; + owl:inverseOf vivo:governingAuthorityFor . + +geo:nationalityEN rdfs:subPropertyOf geo:nationalityEN , owl:topDataProperty . + +bibo:Film rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Film . + +vivo:pmcid rdfs:subPropertyOf vivo:pmcid , vivo:identifier , owl:topDataProperty . + +vivo:EducationalProcess + rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:EducationalProcess . + +obo:IAO_0000030 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000030 . + +vcard:Acquaintance rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Acquaintance . + +vitro-public:File rdfs:subClassOf owl:Thing ; + owl:equivalentClass vitro-public:File . + +vitro:displayLimit rdfs:subPropertyOf vitro:displayLimit , owl:topDataProperty . + +obo:ARG_2000021 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000002 , owl:Thing , obo:BFO_0000001 ; + owl:disjointWith vivo:EditorRole , obo:ERO_0000224 , obo:BFO_0000034 , vivo:AttendeeRole , vivo:OutreachProviderRole , obo:ERO_0000914 , obo:ERO_0000790 , vivo:OrganizerRole , obo:OBI_0000017 , vivo:InvestigatorRole , obo:ERO_0000012 , vivo:ResearcherRole , vivo:AdvisorRole , obo:ERO_0000788 , obo:ERO_0000783 , vivo:TeacherRole , obo:ERO_0000786 , obo:ERO_0000778 , vivo:PrincipalInvestigatorRole , obo:ERO_0000225 , vivo:MemberRole , obo:ERO_0000779 , vivo:AdviseeRole , vivo:CoPrincipalInvestigatorRole , obo:ERO_0000789 , vivo:LeaderRole , obo:ERO_0000784 , obo:ERO_0000776 , vivo:ClinicalRole , vivo:AdministratorRole , vivo:ReviewerRole , vivo:PresenterRole , obo:ERO_0000595 , obo:BFO_0000023 , obo:BFO_0000017 , obo:ERO_0000787 , obo:BFO_0000016 , obo:ERO_0000785 , obo:ERO_0000777 , vivo:PeerReviewerRole , obo:ERO_0000780 ; + owl:equivalentClass obo:ARG_2000021 . + +obo:BFO_0000017 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:ARG_2000021 ; + owl:equivalentClass obo:BFO_0000017 . + +geo:HDIUnit rdfs:subPropertyOf geo:HDIUnit , owl:topDataProperty . + +vivo:yearPrecision a skos:Concept , owl:Thing . + +obo:RO_0002220 rdfs:subPropertyOf owl:topObjectProperty , obo:RO_0002220 . + +vivo:entryTerm rdfs:subPropertyOf vivo:entryTerm , owl:topDataProperty . + +vcard:Cell rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Cell . + +geo:hasMinLatitude rdfs:subPropertyOf geo:hasMinLatitude , owl:topDataProperty . + +vcard:Explanatory rdfs:subClassOf vcard:Geo , vcard:Security , vcard:Calendar , vcard:TimeZone , owl:Thing , vcard:Geographical ; + owl:equivalentClass vcard:Addressing , vcard:Identification , vcard:Organizational , vcard:Communication , vcard:Explanatory . + +vivo:PrincipalInvestigatorRole + rdfs:subClassOf obo:BFO_0000002 , obo:BFO_0000023 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000020 , obo:BFO_0000017 , vivo:ResearcherRole ; + owl:disjointWith obo:BFO_0000019 , obo:ARG_2000022 , obo:ARG_2000021 ; + owl:equivalentClass vivo:PrincipalInvestigatorRole . + +obo:BFO_0000031 rdfs:subClassOf obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:BFO_0000031 . + +vivo:DateTimeValue rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000008 ; + owl:equivalentClass vivo:DateTimeValue . + +scires:accessProvidedBy + rdfs:subPropertyOf scires:accessProvidedBy , owl:topObjectProperty . + +vivo:hasTranslation rdfs:subPropertyOf + vivo:hasTranslation , owl:topObjectProperty . + +geo:GDPYear rdfs:subPropertyOf geo:GDPYear , owl:topDataProperty . + +geo:hasStatistics rdfs:subPropertyOf geo:hasStatistics , owl:topDataProperty . + +vivo:NonAcademicPosition + rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:NonAcademicPosition . + +vivo:subcontractsGrant + rdfs:subPropertyOf vivo:subcontractsGrant , owl:topObjectProperty . + +bibo:Excerpt rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Excerpt . + +vivo:GovernmentAgency + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:GovernmentAgency . + +vivo:Facility rdfs:subClassOf obo:BFO_0000141 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Facility . + +vitro-public:downloadLocation + rdfs:subPropertyOf vitro-public:downloadLocation , owl:topObjectProperty . + +obo:ERO_0000783 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000783 . + +vivo:EmeritusLibrarian + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:EmeritusLibrarian . + +obo:ERO_0001260 rdfs:subClassOf obo:ERO_0000005 , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001260 . + +obo:RO_0002353 rdfs:subPropertyOf obo:RO_0002353 , owl:topObjectProperty ; + owl:inverseOf obo:RO_0002234 . + +vivo:Score rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Score . + +bibo:lccn rdfs:subPropertyOf bibo:lccn , vivo:identifier , owl:topDataProperty . + +geo:nameListAR rdfs:subPropertyOf geo:nameListAR , owl:topDataProperty . + +vcard:Sound rdfs:subClassOf vcard:Identification , vcard:Organizational , vcard:TimeZone , vcard:Calendar , owl:Thing , vcard:Communication , vcard:Security , vcard:Geographical , vcard:Addressing , vcard:Geo ; + owl:equivalentClass vcard:Sound . + +vcard:hasEmail rdfs:subPropertyOf vcard:hasEmail , owl:topObjectProperty . + +c4o:hasGlobalCitationFrequency + rdfs:subPropertyOf c4o:hasGlobalCitationFrequency , owl:topObjectProperty . + +vcard:postalCode rdfs:subPropertyOf vcard:postalCode , owl:topDataProperty . + +vcard:telephone rdfs:subPropertyOf vcard:telephone , owl:topDataProperty . + +vcard:CalendarRequest + rdfs:subClassOf vcard:Security , vcard:TimeZone , owl:Thing , vcard:Geographical , vcard:Geo ; + owl:equivalentClass vcard:CalendarRequest . + +vcard:Sibling rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Sibling . + +obo:RO_0002233 rdfs:subPropertyOf obo:RO_0002233 , owl:topObjectProperty . + +bibo:status rdfs:subPropertyOf bibo:status , owl:topObjectProperty . + +cito:citesAsDataSource + rdfs:subPropertyOf owl:topObjectProperty , cito:citesAsDataSource ; + owl:inverseOf cito:isCitedAsDataSourceBy . + +geo:codeFAOSTAT rdfs:subPropertyOf geo:codeFAOSTAT , owl:topDataProperty . + +geo:populationUnit rdfs:subPropertyOf geo:populationUnit , owl:topDataProperty . + +vcard:Code rdfs:subClassOf owl:Thing ; + owl:equivalentClass vcard:Code . + +obo:IAO_0000144 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000144 . + +obo:ERO_0001259 rdfs:subClassOf obo:ERO_0000005 , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001259 . + +scires:documentationFor + rdfs:subPropertyOf scires:documentationFor , owl:topObjectProperty . + +vivo:PostdocPosition rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , vivo:Position , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:PostdocPosition . + +vivo:sponsors rdfs:subPropertyOf vivo:sponsors , owl:topObjectProperty . + +obo:ERO_0000543 rdfs:subPropertyOf obo:ERO_0000543 , owl:topObjectProperty . + +geo:hasMaxLongitude rdfs:subPropertyOf + geo:hasMaxLongitude , owl:topDataProperty . + + + a owl:ObjectProperty ; + rdfs:subPropertyOf , owl:topObjectProperty . + +vivo:BlogPosting rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:BlogPosting . + +bibo:upc rdfs:subPropertyOf vivo:identifier , bibo:upc , owl:topDataProperty . + +bibo:AcademicArticle rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:AcademicArticle . + +obo:ERO_0000045 rdfs:subPropertyOf obo:ERO_0000045 , owl:topDataProperty . + +vivo:roleContributesTo + rdfs:subPropertyOf vivo:roleContributesTo , owl:topObjectProperty . + +vitro-public:filename + rdfs:subPropertyOf vitro-public:filename , owl:topDataProperty . + +vivo:Equipment rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Equipment . + +vcard:Sweetheart rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Sweetheart . + +vivo:Room rdfs:subClassOf obo:BFO_0000141 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000029 , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Room . + +vcard:Muse rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Muse . + +vivo:publicationVenueFor + rdfs:subPropertyOf vivo:publicationVenueFor , owl:topObjectProperty ; + owl:inverseOf vivo:hasPublicationVenue . + +obo:RO_0003000 rdfs:subPropertyOf obo:RO_0003000 , owl:topObjectProperty ; + owl:inverseOf obo:RO_0003001 . + +obo:OBI_0000835 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass obo:OBI_0000835 . + +bibo:Standard rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Standard . + +bibo:prefixName rdfs:subPropertyOf bibo:prefixName , owl:topDataProperty . + +vivo:confirmedOrcidId + rdfs:subPropertyOf vivo:confirmedOrcidId , owl:topObjectProperty . + +obo:RO_0001018 rdfs:subPropertyOf obo:RO_0001018 , owl:topObjectProperty . + +vivo:hasProceedings rdfs:subPropertyOf + vivo:hasProceedings , owl:topObjectProperty ; + owl:inverseOf vivo:proceedingsOf . + + + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:IAO_0000027 , obo:BFO_0000002 ; + owl:equivalentClass . + +vcard:Kin rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Kin . + +bibo:reviewOf rdfs:subPropertyOf bibo:reviewOf , owl:topObjectProperty . + +bibo:eanucc13 rdfs:subPropertyOf vivo:identifier , bibo:eanucc13 , owl:topDataProperty . + +bibo:degree rdfs:subPropertyOf owl:topObjectProperty , bibo:degree . + +bibo:Newspaper rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , bibo:Collection , obo:BFO_0000002 ; + owl:equivalentClass bibo:Newspaper . + +obo:RO_0000057 rdfs:subPropertyOf owl:topObjectProperty , obo:RO_0000057 . + +vivo:hideFromDisplay rdfs:subPropertyOf + vivo:hideFromDisplay , owl:topDataProperty . + +vivo:NonAcademic rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:NonAcademic . + +vivo:Continent rdfs:subClassOf obo:BFO_0000141 , vivo:Location , obo:BFO_0000001 , owl:Thing , obo:BFO_0000006 , vivo:GeographicLocation , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Continent . + +bibo:ThesisDegree rdfs:subClassOf skos:Concept , owl:Thing ; + owl:equivalentClass bibo:ThesisDegree . + +obo:RO_0001000 rdfs:subPropertyOf obo:RO_0001000 , owl:topObjectProperty . + +c4o:hasGlobalCountSource + rdfs:subPropertyOf c4o:hasGlobalCountSource , owl:topObjectProperty . + +vivo:yearMonthDayTimePrecision + a skos:Concept , owl:Thing . + +obo:ERO_0000777 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , obo:BFO_0000023 , obo:BFO_0000002 , obo:BFO_0000017 , owl:Thing ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000777 . + +bibo:Magazine rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , bibo:Collection , obo:BFO_0000002 ; + owl:equivalentClass bibo:Magazine . + +obo:ERO_0001254 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001254 . + +vivo:majorField rdfs:subPropertyOf vivo:majorField , owl:topDataProperty . + +obo:ERO_0000072 rdfs:subPropertyOf obo:ERO_0000072 , owl:topDataProperty . + +vcard:Neighbor rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Neighbor . + +bibo:interviewee rdfs:subPropertyOf bibo:interviewee , owl:topObjectProperty . + +vcard:Geographical rdfs:subClassOf owl:Thing ; + owl:equivalentClass vcard:Geographical . + +bibo:identifier rdfs:subPropertyOf bibo:identifier , owl:topDataProperty . + +vcard:anniversary rdfs:subPropertyOf vcard:anniversary , owl:topDataProperty . + +vivo:hasAssociatedConcept + rdfs:subPropertyOf vivo:hasAssociatedConcept , owl:topObjectProperty . + +vcard:Security rdfs:subClassOf vcard:TimeZone , owl:Thing , vcard:Geographical , vcard:Geo ; + owl:equivalentClass vcard:Security , vcard:Calendar . + +geo:organization rdfs:subClassOf geo:area , owl:Thing ; + owl:equivalentClass geo:organization . + +obo:IAO_0000005 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000005 . + +obo:ARG_2000028 rdfs:subPropertyOf obo:ARG_2000028 , owl:topObjectProperty ; + owl:inverseOf obo:ARG_2000029 . + +vivo:distributes rdfs:subPropertyOf vivo:distributes , owl:topObjectProperty . + +obo:ERO_0000482 rdfs:subPropertyOf owl:topObjectProperty , obo:ERO_0000482 . + +vcard:Coresident rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Coresident . + +vcard:familyName rdfs:subPropertyOf vcard:familyName , owl:topDataProperty . + +vcard:hasCalenderBusy + rdfs:subPropertyOf vcard:hasCalenderBusy , owl:topObjectProperty . + +vivo:description rdfs:subPropertyOf vivo:description , owl:topDataProperty . + + + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:IAO_0000027 , obo:BFO_0000002 ; + owl:equivalentClass . + +vivo:ConferencePaper rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:ConferencePaper . + +owl:incompatibleWith a owl:AnnotationProperty . + +obo:BFO_0000038 rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:BFO_0000038 . + +owl:versionInfo a owl:AnnotationProperty . + +obo:ARG_2000010 rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:ARG_2000010 . + +bibo:peerReviewed a owl:Thing . + +obo:BFO_0000006 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass obo:BFO_0000006 . + +vivo:yearMonthDayPrecision + a skos:Concept , owl:Thing . + +vcard:sound rdfs:subPropertyOf vcard:sound , owl:topDataProperty . + +skos:narrower rdfs:subPropertyOf skos:narrower , owl:topObjectProperty ; + owl:inverseOf skos:broader . + +bibo:Quote rdfs:subClassOf bibo:DocumentPart , bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Quote . + +bibo:CollectedDocument + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:CollectedDocument . + +ocresd:Single_group_study + rdfs:subClassOf owl:Thing ; + owl:equivalentClass ocresd:Single_group_study . + +obo:ERO_0000394 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000394 . + +vitro:Application rdfs:subClassOf owl:Thing ; + owl:equivalentClass vitro:Application . + +vcard:organizationalUnitName + rdfs:subPropertyOf vcard:organizationalUnitName , owl:topDataProperty . + +bibo:uri rdfs:subPropertyOf vivo:identifier , bibo:uri , owl:topDataProperty . + +vcard:URL rdfs:subClassOf vcard:Addressing , vcard:Geo , owl:Thing , vcard:Geographical , vcard:Identification , vcard:Calendar , vcard:Organizational , vcard:TimeZone , vcard:Communication , vcard:Security ; + owl:equivalentClass vcard:URL . + +bibo:LegalDocument rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:LegalDocument . + +obo:BFO_0000020 rdfs:subClassOf obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:BFO_0000020 . + +obo:RO_0000052 rdfs:subPropertyOf obo:RO_0000052 , owl:topObjectProperty . + +vivo:Foundation rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Foundation . + +vivo:StateOrProvince rdfs:subClassOf vivo:GeographicRegion , obo:BFO_0000006 , obo:BFO_0000141 , obo:BFO_0000002 , owl:Thing , obo:BFO_0000001 , vivo:Location , vivo:GeographicLocation , obo:BFO_0000004 ; + owl:equivalentClass vivo:StateOrProvince . + +c4o:hasGlobalCountValue + rdfs:subPropertyOf c4o:hasGlobalCountValue , owl:topDataProperty . + +vivo:FacultyPosition rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:FacultyPosition . + +vivo:WorkingPaper rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:WorkingPaper . + +vivo:supportedInformationResource + rdfs:subPropertyOf vivo:supportedInformationResource , owl:topObjectProperty . + +vcard:language rdfs:subPropertyOf vcard:language , owl:topDataProperty . + +obo:ERO_0000007 rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:ERO_0000007 . + +ocresd:Phase_0 rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass ocresd:Phase_0 . + +vivo:hasSubjectArea rdfs:subPropertyOf + vivo:hasSubjectArea , owl:topObjectProperty . + +vivo:eRACommonsId rdfs:subPropertyOf vivo:eRACommonsId , owl:topDataProperty . + +vcard:category rdfs:subPropertyOf vcard:category , owl:topDataProperty . + +geo:nationalityZH rdfs:subPropertyOf geo:nationalityZH , owl:topDataProperty . + +vivo:middleName rdfs:subPropertyOf vivo:middleName , owl:topDataProperty . + +vivo:AdvisorRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:AdvisorRole . + +vivo:School rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:School . + +vivo:Consortium rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Consortium . + +vitro-public:mimeType + rdfs:subPropertyOf vitro-public:mimeType , owl:topDataProperty . + +obo:IAO_0000032 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:IAO_0000027 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000032 . + +vivo:Exhibit rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:Exhibit . + +obo:ARG_2000009 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , obo:IAO_0000109 , owl:Thing , obo:BFO_0000031 , obo:IAO_0000032 , obo:IAO_0000027 , obo:BFO_0000002 ; + owl:equivalentClass obo:ARG_2000009 . + +vitro-public:thumbnailImage + rdfs:subPropertyOf vitro-public:thumbnailImage , owl:topObjectProperty . + +vcard:Crush rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Crush . + +bibo:translator rdfs:subPropertyOf owl:topObjectProperty , bibo:translator . + +vivo:Museum rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Museum . + +vivo:Librarian rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Librarian . + +geo:area owl:equivalentClass geo:area . + +obo:ARG_0000197 rdfs:subPropertyOf obo:ARG_0000197 , owl:topDataProperty . + +vivo:EditorialArticle + rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:EditorialArticle . + +obo:IAO_0000221 rdfs:subPropertyOf obo:IAO_0000221 , owl:topObjectProperty ; + owl:inverseOf obo:IAO_0000417 . + +obo:BFO_0000019 rdfs:subClassOf obo:BFO_0000001 , obo:BFO_0000002 , owl:Thing ; + owl:disjointWith obo:ERO_0000779 , obo:ERO_0000780 , vivo:ReviewerRole , obo:ERO_0000790 , obo:ERO_0000778 , obo:BFO_0000017 , obo:OBI_0000017 , obo:ERO_0000777 , vivo:PresenterRole , vivo:AdvisorRole , obo:ERO_0000783 , vivo:TeacherRole , obo:ERO_0000787 , vivo:ClinicalRole , vivo:ResearcherRole , obo:ERO_0000914 , obo:ERO_0000225 , obo:BFO_0000034 , vivo:MemberRole , obo:ERO_0000786 , obo:ERO_0000776 , obo:BFO_0000023 , vivo:OrganizerRole , obo:ERO_0000012 , vivo:PeerReviewerRole , vivo:AttendeeRole , vivo:PrincipalInvestigatorRole , obo:ERO_0000595 , obo:ERO_0000224 , vivo:AdministratorRole , vivo:LeaderRole , obo:ERO_0000785 , obo:BFO_0000016 , vivo:EditorRole , obo:ERO_0000789 , obo:ERO_0000784 , vivo:CoPrincipalInvestigatorRole , vivo:OutreachProviderRole , vivo:AdviseeRole , obo:ERO_0000788 , vivo:InvestigatorRole ; + owl:equivalentClass obo:BFO_0000019 . + +bibo:pageEnd rdfs:subPropertyOf bibo:pageEnd , owl:topDataProperty . + +vcard:organizationName + rdfs:subPropertyOf vcard:organizationName , owl:topDataProperty . + +bibo:Workshop rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass bibo:Workshop . + +vivo:informationResourceSupportedBy + rdfs:subPropertyOf vivo:informationResourceSupportedBy , owl:topObjectProperty ; + owl:inverseOf vivo:supportedInformationResource . + + + a owl:ObjectProperty ; + rdfs:subPropertyOf , owl:topObjectProperty . + +obo:BFO_0000001 rdfs:subClassOf owl:Thing ; + owl:equivalentClass obo:BFO_0000001 . + +vivo:Campus rdfs:subClassOf obo:BFO_0000141 , vivo:Location , obo:BFO_0000001 , owl:Thing , obo:BFO_0000006 , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Campus . + +vitro:User rdfs:subClassOf owl:Thing ; + owl:equivalentClass vitro:User . + +vivo:GeographicRegion + rdfs:subClassOf obo:BFO_0000141 , vivo:Location , obo:BFO_0000001 , owl:Thing , obo:BFO_0000006 , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:GeographicRegion . + +vivo:GeopoliticalEntity + rdfs:subClassOf obo:BFO_0000141 , vivo:Location , obo:BFO_0000001 , owl:Thing , obo:BFO_0000006 , vivo:GeographicLocation , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:GeopoliticalEntity . + +vcard:Organization rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:ARG_2000379 , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vcard:Organization . + +vivo:relatedBy rdfs:subPropertyOf vivo:relatedBy , owl:topObjectProperty ; + owl:inverseOf vivo:relates . + +geo:populationNotes rdfs:subPropertyOf + geo:populationNotes , owl:topDataProperty . + +obo:ERO_0000785 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000023 , obo:BFO_0000002 , obo:BFO_0000017 , obo:BFO_0000001 , owl:Thing ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000785 . + +obo:ARG_2000377 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ARG_2000377 . + +obo:ERO_0001262 rdfs:subClassOf obo:ERO_0000005 , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001262 . + +obo:ERO_0000034 rdfs:subPropertyOf obo:ERO_0000034 , owl:topObjectProperty . + +vcard:Voice rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Voice . + +vcard:region rdfs:subPropertyOf vcard:region , owl:topDataProperty . + +vivo:preferredDisplayOrder + rdfs:subPropertyOf vivo:preferredDisplayOrder , owl:topDataProperty . + +obo:ARG_2000391 rdfs:subPropertyOf owl:topObjectProperty , obo:ARG_2000391 ; + owl:inverseOf obo:ARG_2000390 . + +geo:nameShortIT rdfs:subPropertyOf geo:nameShortIT , owl:topDataProperty . + +geo:countryAreaYear rdfs:subPropertyOf + geo:countryAreaYear , owl:topDataProperty . + +vivo:CoPrincipalInvestigatorRole + rdfs:subClassOf obo:BFO_0000017 , obo:BFO_0000001 , obo:BFO_0000002 , obo:BFO_0000020 , vivo:ResearcherRole , obo:BFO_0000023 , owl:Thing ; + owl:disjointWith obo:BFO_0000019 , obo:ARG_2000021 , obo:ARG_2000022 ; + owl:equivalentClass vivo:CoPrincipalInvestigatorRole . + +obo:IAO_0000013 rdfs:subClassOf bibo:Article , bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000013 . + +scires:irbNumber rdfs:subPropertyOf scires:irbNumber , owl:topDataProperty . + +vitro:copyrightAnchor + rdfs:subPropertyOf vitro:copyrightAnchor , owl:topDataProperty . + +bibo:Chapter rdfs:subClassOf bibo:DocumentPart , bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Chapter . + +vcard:hasMember rdfs:subPropertyOf vcard:hasMember , owl:topObjectProperty . + +geo:nameShortFR rdfs:subPropertyOf geo:nameShortFR , owl:topDataProperty . + +bibo:subsequentLegalDecision + rdfs:subPropertyOf owl:topObjectProperty , bibo:subsequentLegalDecision . + +bibo:chapter rdfs:subPropertyOf bibo:chapter , owl:topDataProperty . + +bibo:asin rdfs:subPropertyOf vivo:identifier , bibo:asin , owl:topDataProperty . + +bibo:edition rdfs:subPropertyOf bibo:edition , owl:topDataProperty . + +vivo:AcademicTerm rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000038 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000008 ; + owl:equivalentClass vivo:AcademicTerm . + +obo:OBI_0001554 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , obo:IAO_0000109 , owl:Thing , obo:BFO_0000031 , obo:IAO_0000027 , obo:BFO_0000002 ; + owl:equivalentClass obo:OBI_0001554 . + +vcard:Me rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Me . + +c4o:BibliographicInformationSource + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass c4o:BibliographicInformationSource . + +bibo:gtin14 rdfs:subPropertyOf vivo:identifier , bibo:gtin14 , owl:topDataProperty . + +vcard:Contact rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Contact . + +vivo:Catalog rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Catalog . + +vcard:Communication rdfs:subClassOf vcard:Security , vcard:TimeZone , vcard:Calendar , owl:Thing , vcard:Geographical , vcard:Geo ; + owl:equivalentClass vcard:Addressing , vcard:Communication , vcard:Explanatory , vcard:Organizational , vcard:Identification . + +bibo:BookSection rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:BookSection . + +vivo:LeaderRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:LeaderRole . + +geo:nameOfficialIT rdfs:subPropertyOf geo:nameOfficialIT , owl:topDataProperty . + +bibo:number rdfs:subPropertyOf bibo:number , owl:topDataProperty . + +bibo:Code rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , bibo:Collection , obo:BFO_0000002 ; + owl:equivalentClass bibo:Code . + +vcard:Note rdfs:subClassOf vcard:TimeZone , vcard:Security , vcard:Geographical , vcard:Identification , vcard:Addressing , vcard:Calendar , vcard:Geo , owl:Thing , vcard:Communication , vcard:Organizational ; + owl:equivalentClass vcard:Note . + +vcard:hasLanguage rdfs:subPropertyOf vcard:hasLanguage , owl:topObjectProperty . + +bibo:Map rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Map . + +geo:nameOfficialFR rdfs:subPropertyOf geo:nameOfficialFR , owl:topDataProperty . + +vcard:Name rdfs:subClassOf vcard:TimeZone , vcard:Addressing , owl:Thing , vcard:Security , vcard:Explanatory , vcard:Organizational , vcard:Calendar , vcard:Communication , vcard:Geographical , vcard:Geo ; + owl:equivalentClass vcard:Name . + +obo:OBI_0000017 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:OBI_0000017 . + +vivo:end rdfs:subPropertyOf vivo:end , owl:topObjectProperty . + +vcard:hasCategory rdfs:subPropertyOf vcard:hasCategory , owl:topObjectProperty . + +obo:ERO_0001520 rdfs:subPropertyOf obo:ERO_0001520 , owl:topObjectProperty . + +vivo:InvestigatorRole + rdfs:subClassOf obo:BFO_0000002 , obo:BFO_0000023 , obo:BFO_0000001 , obo:BFO_0000020 , owl:Thing , obo:BFO_0000017 ; + owl:disjointWith obo:ARG_2000021 , obo:BFO_0000019 , obo:ARG_2000022 ; + owl:equivalentClass vivo:InvestigatorRole . + +geo:territory rdfs:subClassOf obo:BFO_0000004 , vivo:GeographicRegion , obo:BFO_0000001 , obo:BFO_0000141 , vivo:GeographicLocation , owl:Thing , vivo:Location , obo:BFO_0000002 , obo:BFO_0000006 ; + owl:equivalentClass geo:territory . + +vcard:hasLogo rdfs:subPropertyOf vcard:hasLogo , owl:topObjectProperty . + +vcard:Location rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:ARG_2000379 , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vcard:Location . + +vivo:hasEquipment rdfs:subPropertyOf vivo:hasEquipment , owl:topObjectProperty . + +obo:ERO_0000015 rdfs:subClassOf obo:BFO_0000015 , vivo:Project , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing , obo:OBI_0000011 ; + owl:equivalentClass obo:ERO_0000015 . + +vitro:md5password rdfs:subPropertyOf vitro:md5password , owl:topDataProperty . + +geo:HDI rdfs:subPropertyOf geo:HDI , owl:topDataProperty . + +vcard:InstantMessage rdfs:subClassOf vcard:Explanatory , vcard:Security , vcard:Calendar , owl:Thing , vcard:Geo , vcard:Identification , vcard:Organizational , vcard:Geographical , vcard:Addressing , vcard:TimeZone ; + owl:equivalentClass vcard:InstantMessage . + +geo:nameShortRU rdfs:subPropertyOf geo:nameShortRU , owl:topDataProperty . + +obo:ERO_0000780 rdfs:subClassOf obo:BFO_0000017 , obo:BFO_0000001 , obo:BFO_0000020 , obo:BFO_0000002 , owl:Thing , obo:ERO_0000776 , obo:BFO_0000023 ; + owl:disjointWith obo:BFO_0000019 , obo:ARG_2000021 , obo:ARG_2000022 ; + owl:equivalentClass obo:ERO_0000780 . + +vitro:rootLogotypeImage + rdfs:subPropertyOf vitro:rootLogotypeImage , owl:topDataProperty . + +vcard:OrganizationName + rdfs:subClassOf vcard:Security , vcard:Calendar , owl:Thing , vcard:Identification , vcard:Explanatory , vcard:Addressing , vcard:TimeZone , vcard:Geo , vcard:Communication , vcard:Geographical ; + owl:equivalentClass vcard:OrganizationName . + +geo:nationalityAR rdfs:subPropertyOf geo:nationalityAR , owl:topDataProperty . + +obo:RO_0002350 rdfs:subPropertyOf obo:RO_0002350 , owl:topObjectProperty . + +vivo:Contract rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:Contract . + +vcard:hasOrganizationalUnitName + rdfs:subPropertyOf vcard:hasOrganizationalUnitName , owl:topObjectProperty . + +geo:codeAGROVOC rdfs:subPropertyOf geo:codeAGROVOC , owl:topDataProperty . + +bibo:ReferenceSource rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:ReferenceSource . + +geo:isInGroup rdfs:subPropertyOf owl:topObjectProperty , geo:isInGroup ; + owl:inverseOf geo:hasMember . + +vivo:Publisher rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Publisher . + +vivo:FundingOrganization + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:FundingOrganization . + +vcard:Organizational rdfs:subClassOf vcard:Security , owl:Thing , vcard:TimeZone , vcard:Geo , vcard:Calendar , vcard:Geographical ; + owl:equivalentClass vcard:Explanatory , vcard:Identification , vcard:Organizational , vcard:Addressing , vcard:Communication . + +geo:nameOfficialRU rdfs:subPropertyOf geo:nameOfficialRU , owl:topDataProperty . + +vivo:PrivateCompany rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , foaf:Organization , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:PrivateCompany . + +bibo:Book rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Book . + +vcard:hasTelephone rdfs:subPropertyOf vcard:hasTelephone , owl:topObjectProperty . + +bibo:EditedBook rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:EditedBook . + +vivo:EmeritusProfessor + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:EmeritusProfessor . + +vcard:nickName rdfs:subPropertyOf vcard:nickName , owl:topDataProperty . + +vitro:namespaceURI rdfs:subPropertyOf vitro:namespaceURI , owl:topDataProperty . + +vivo:placeOfPublication + rdfs:subPropertyOf vivo:placeOfPublication , owl:topDataProperty . + +obo:ERO_0000779 rdfs:subClassOf obo:BFO_0000017 , obo:BFO_0000001 , obo:BFO_0000023 , obo:BFO_0000002 , owl:Thing , obo:ERO_0000776 , obo:BFO_0000020 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000779 . + +vivo:identifier rdfs:subPropertyOf vivo:identifier , owl:topDataProperty . + +obo:ERO_0001256 rdfs:subClassOf obo:ERO_0000005 , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001256 . + +obo:ERO_0000572 rdfs:subPropertyOf owl:topObjectProperty , obo:ERO_0000572 . + +vivo:fundingVehicleFor + rdfs:subPropertyOf vivo:fundingVehicleFor , owl:topObjectProperty . + +vitro:imageThumbWidth + rdfs:subPropertyOf vitro:imageThumbWidth , owl:topDataProperty . + +obo:IAO_0000039 rdfs:subPropertyOf owl:topObjectProperty , obo:IAO_0000039 . + +geo:isSuccessorOf rdfs:subPropertyOf geo:isSuccessorOf , owl:topObjectProperty ; + owl:inverseOf geo:isPredecessorOf . + +scires:nctId rdfs:subPropertyOf scires:nctId , owl:topDataProperty . + +vivo:subjectAreaOf rdfs:subPropertyOf vivo:subjectAreaOf , owl:topObjectProperty ; + owl:inverseOf vivo:hasSubjectArea . + +obo:IAO_0000007 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000007 . + +vitro:PropertyGroup rdfs:subClassOf owl:Thing ; + owl:equivalentClass vitro:PropertyGroup . + +vivo:seatingCapacity rdfs:subPropertyOf + vivo:seatingCapacity , owl:topDataProperty . + +foaf:Agent rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass foaf:Agent . + +fabio:ClinicalGuideline + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass fabio:ClinicalGuideline . + +obo:OBI_0000643 rdfs:subPropertyOf obo:OBI_0000643 , owl:topObjectProperty . + +vivo:publisherOf rdfs:subPropertyOf vivo:publisherOf , owl:topObjectProperty ; + owl:inverseOf vivo:publisher . + +vivo:conceptAssociatedWith + rdfs:subPropertyOf vivo:conceptAssociatedWith , owl:topObjectProperty ; + owl:inverseOf vivo:hasAssociatedConcept . + +vitro:Namespace rdfs:subClassOf owl:Thing ; + owl:equivalentClass vitro:Namespace . + +vivo:Meeting rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:Meeting . + +obo:IAO_0000417 rdfs:subPropertyOf obo:IAO_0000417 , owl:topObjectProperty . + + + rdfs:subPropertyOf owl:topObjectProperty , . + +obo:ARG_2000012 rdfs:subPropertyOf obo:ARG_2000012 , owl:topDataProperty . + +geo:codeCurrency rdfs:subPropertyOf geo:codeCurrency , owl:topDataProperty . + +obo:BFO_0000008 rdfs:subClassOf obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:BFO_0000008 . + +vivo:dateTimePrecision + rdfs:subPropertyOf vivo:dateTimePrecision , owl:topObjectProperty . + +vivo:Company rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Company . + +obo:RO_0001015 rdfs:subPropertyOf obo:RO_0001015 , owl:topObjectProperty . + +obo:BFO_0000054 rdfs:subPropertyOf obo:BFO_0000054 , owl:topObjectProperty ; + owl:inverseOf obo:BFO_0000055 . + +obo:ERO_0000396 rdfs:subClassOf obo:ERO_0000005 , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000396 . + +vivo:NonFacultyAcademicPosition + rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:NonFacultyAcademicPosition . + +vitro:rootBreadCrumbAnchor + rdfs:subPropertyOf vitro:rootBreadCrumbAnchor , owl:topDataProperty . + +vitro-public:directDownloadUrl + rdfs:subPropertyOf vitro-public:directDownloadUrl , owl:topDataProperty . + +geo:agriculturalAreaYear + rdfs:subPropertyOf geo:agriculturalAreaYear , owl:topDataProperty . + +vivo:Laboratory rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Laboratory . + +vcard:Spouse rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Spouse . + +vivo:College rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:College . + +geo:hasBorderWith rdfs:subPropertyOf geo:hasBorderWith , owl:topObjectProperty . + +vivo:AttendingProcess + rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:AttendingProcess . + +geo:nameCurrencyIT rdfs:subPropertyOf geo:nameCurrencyIT , owl:topDataProperty . + +ocresd:Phase_2 rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass ocresd:Phase_2 . + +geo:nameCurrencyFR rdfs:subPropertyOf geo:nameCurrencyFR , owl:topDataProperty . + +bibo:citedBy rdfs:subPropertyOf bibo:citedBy , owl:topObjectProperty . + +obo:ERO_0000774 rdfs:subPropertyOf obo:ERO_0000774 , owl:topDataProperty . + +bibo:Document rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Document . + +vivo:supplementalInformation + rdfs:subPropertyOf vivo:supplementalInformation , owl:topDataProperty . + +geo:agriculturalAreaNotes + rdfs:subPropertyOf geo:agriculturalAreaNotes , owl:topDataProperty . + +geo:codeDBPediaID rdfs:subPropertyOf geo:codeDBPediaID , owl:topDataProperty . + +vivo:Video rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Video . + +vivo:PresentingProcess + rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:PresentingProcess . + +vcard:calendarLink rdfs:subPropertyOf vcard:calendarLink , owl:topDataProperty . + +vcard:hasInstantMessage + rdfs:subPropertyOf vcard:hasInstantMessage , owl:topObjectProperty . + +vivo:DateTimeValuePrecision + rdfs:subClassOf owl:Thing ; + owl:equivalentClass vivo:DateTimeValuePrecision . + +owl:backwardCompatibleWith + a owl:AnnotationProperty . + +vivo:AttendeeRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:AttendeeRole . + +vivo:distributesFundingFrom + rdfs:subPropertyOf vivo:distributesFundingFrom , owl:topObjectProperty . + +vcard:source rdfs:subPropertyOf vcard:source , owl:topDataProperty . + +bibo:numPages rdfs:subPropertyOf bibo:numPages , owl:topDataProperty . + +vcard:related rdfs:subPropertyOf vcard:related , owl:topDataProperty . + +vcard:Title rdfs:subClassOf vcard:TimeZone , vcard:Communication , vcard:Security , vcard:Explanatory , vcard:Geographical , vcard:Geo , vcard:Identification , vcard:Calendar , owl:Thing , vcard:Addressing ; + owl:equivalentClass vcard:Title . + +vivo:Center rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Center . + +owl:Thing a owl:Class ; + owl:equivalentClass owl:Thing . + +vivo:prerequisiteFor rdfs:subPropertyOf + vivo:prerequisiteFor , owl:topObjectProperty ; + owl:inverseOf vivo:hasPrerequisite . + +vcard:Child rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Child . + +vivo:dateIssued rdfs:subPropertyOf vivo:dateIssued , owl:topObjectProperty . + +bibo:Webpage rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Webpage . + +vivo:hasSuccessorOrganization + rdfs:subPropertyOf vivo:hasSuccessorOrganization , owl:topObjectProperty ; + owl:inverseOf vivo:hasPredecessorOrganization . + +vivo:License rdfs:subClassOf skos:Concept , owl:Thing ; + owl:equivalentClass vivo:License . + +vcard:locality rdfs:subPropertyOf vcard:locality , owl:topDataProperty . + +vivo:AdvisingRelationship + rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:AdvisingRelationship . + +vitro:themeDir rdfs:subPropertyOf vitro:themeDir , owl:topDataProperty . + +bibo:Periodical rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Periodical . + +bibo:cites rdfs:subPropertyOf bibo:cites , owl:topObjectProperty ; + owl:inverseOf bibo:citedBy . + +geo:hasCoordinate rdfs:subPropertyOf geo:hasCoordinate , owl:topDataProperty . + +geo:nameCurrencyRU rdfs:subPropertyOf geo:nameCurrencyRU , owl:topDataProperty . + +vcard:TextPhone rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:TextPhone . + +obo:BFO_0000003 rdfs:subClassOf owl:Thing ; + owl:equivalentClass obo:BFO_0000003 . + +vivo:Project rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:Project . + +vitro:rootTab rdfs:subPropertyOf vitro:rootTab , owl:topObjectProperty . + +obo:ERO_0000391 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000391 . + +vivo:GeographicLocation + rdfs:subClassOf obo:BFO_0000141 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000006 , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:GeographicLocation . + +vcard:Email rdfs:subClassOf vcard:Calendar , vcard:Security , vcard:Geo , vcard:Identification , vcard:Addressing , vcard:Explanatory , owl:Thing , vcard:TimeZone , vcard:Organizational , vcard:Geographical ; + owl:equivalentClass vcard:Email . + +scires:Phase3ClinicalTrial + rdfs:subClassOf ocrer:Interventional_study , owl:Thing ; + owl:equivalentClass scires:Phase3ClinicalTrial . + +vcard:Agent rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Agent . + +obo:ERO_0001716 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001716 . + +bibo:Conference rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass bibo:Conference . + +vivo:relates rdfs:subPropertyOf vivo:relates , owl:topObjectProperty . + +obo:ERO_0000787 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000787 . + +obo:ARG_2000379 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ARG_2000379 . + + + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:IAO_0000027 , obo:BFO_0000002 ; + owl:equivalentClass . + +geo:nameListIT rdfs:subPropertyOf geo:nameListIT , owl:topDataProperty . + +vivo:hrJobTitle rdfs:subPropertyOf vivo:hrJobTitle , owl:topDataProperty . + +obo:ARG_0000015 rdfs:subPropertyOf obo:ARG_0000015 , owl:topDataProperty . + +obo:ERO_0000004 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0000004 . + +geo:nameListFR rdfs:subPropertyOf geo:nameListFR , owl:topDataProperty . + +obo:ERO_0000050 rdfs:subPropertyOf obo:ERO_0000050 , owl:topDataProperty . + +obo:ERO_0000225 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000225 . + +vivo:AdvisingProcess rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:AdvisingProcess . + +geo:isPredecessorOf rdfs:subPropertyOf + geo:isPredecessorOf , owl:topObjectProperty . + +geo:codeISO3 rdfs:subPropertyOf geo:codeISO3 , owl:topDataProperty . + +vivo:Editorship rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:Editorship . + +vivo:Award rdfs:subClassOf owl:Thing ; + owl:equivalentClass vivo:Award . + +vcard:calendarRequest + rdfs:subPropertyOf vcard:calendarRequest , owl:topDataProperty . + +vcard:Parent rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Parent . + +scires:Phase2ClinicalTrial + rdfs:subClassOf ocrer:Interventional_study , owl:Thing ; + owl:equivalentClass scires:Phase2ClinicalTrial . + +vivo:assignee rdfs:subPropertyOf vivo:assignee , owl:topObjectProperty ; + owl:inverseOf vivo:assigneeFor . + +geo:hasCode rdfs:subPropertyOf geo:hasCode , owl:topDataProperty . + +obo:ERO_0000460 rdfs:subPropertyOf obo:ERO_0000460 , owl:topObjectProperty ; + owl:inverseOf scires:documentationFor . + +vitro:roleURI rdfs:subPropertyOf vitro:roleURI , owl:topDataProperty . + +bibo:coden rdfs:subPropertyOf vivo:identifier , bibo:coden , owl:topDataProperty . + +vivo:ConferencePoster + rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:ConferencePoster . + +vcard:Met rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Met . + +vivo:orcidId rdfs:subPropertyOf vivo:orcidId , owl:topObjectProperty . + +bibo:pageStart rdfs:subPropertyOf bibo:pageStart , owl:topDataProperty . + +obo:BFO_0000016 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:BFO_0000016 . + +vcard:photo rdfs:subPropertyOf vcard:photo , owl:topDataProperty . + +bibo:Note rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Note . + +vcard:key rdfs:subPropertyOf vcard:key , owl:topDataProperty . + +vivo:IssuedCredential + rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:IssuedCredential . + +vitro:contactMail rdfs:subPropertyOf vitro:contactMail , owl:topDataProperty . + +scires:Phase1ClinicalTrial + rdfs:subClassOf ocrer:Interventional_study , owl:Thing ; + owl:equivalentClass scires:Phase1ClinicalTrial . + +vivo:AcademicYear rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000038 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000008 ; + owl:equivalentClass vivo:AcademicYear . + +vcard:Telephone rdfs:subClassOf vcard:Explanatory , owl:Thing , vcard:Identification , vcard:Geo , vcard:Security , vcard:Organizational , vcard:Calendar , vcard:TimeZone , vcard:Geographical , vcard:Addressing ; + owl:equivalentClass vcard:Telephone . + +geo:nameListRU rdfs:subPropertyOf geo:nameListRU , owl:topDataProperty . + +vivo:localAwardId rdfs:subPropertyOf vivo:localAwardId , owl:topDataProperty . + +vivo:Abstract rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Abstract . + +vivo:hasPredecessorOrganization + rdfs:subPropertyOf vivo:hasPredecessorOrganization , owl:topObjectProperty . + +geo:landArea rdfs:subPropertyOf geo:landArea , owl:topDataProperty . + +obo:ERO_0001245 rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass obo:ERO_0001245 . + +vivo:teachingOverview + rdfs:subPropertyOf vivo:teachingOverview , owl:topDataProperty . + +vivo:Country rdfs:subClassOf vivo:Location , obo:BFO_0000141 , obo:BFO_0000001 , obo:BFO_0000006 , vivo:GeographicLocation , vivo:GeographicRegion , geo:area , owl:Thing , geo:territory , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass geo:self_governing , vivo:Country . + +vcard:hasTitle rdfs:subPropertyOf vcard:hasTitle , owl:topObjectProperty . + +vivo:departmentOrSchool + rdfs:subPropertyOf vivo:departmentOrSchool , owl:topDataProperty . + +vivo:AwardedDegree rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:AwardedDegree . + +bibo:Bill rdfs:subClassOf bibo:Document , obo:IAO_0000030 , bibo:LegalDocument , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Bill . + +vivo:InvitedTalk rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , event:Event , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:InvitedTalk . + +obo:ERO_0000031 rdfs:subPropertyOf owl:topObjectProperty , obo:ERO_0000031 . + +vivo:Committee rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Committee . + +bibo:shortDescription + rdfs:subPropertyOf bibo:shortDescription , owl:topDataProperty . + +vitro:oldpassword rdfs:subPropertyOf vitro:oldpassword , owl:topDataProperty . + +vivo:Location rdfs:subClassOf obo:BFO_0000141 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Location . + +obo:UO_0000280 rdfs:subClassOf obo:IAO_0000030 , obo:IAO_0000009 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:UO_0000280 . + +vivo:Postdoc rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , foaf:Person , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Postdoc . + +scires:Phase0ClinicalTrial + rdfs:subClassOf ocrer:Interventional_study , owl:Thing ; + owl:equivalentClass scires:Phase0ClinicalTrial . + +vivo:LibrarianPosition + rdfs:subClassOf vivo:Relationship , obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000002 ; + owl:equivalentClass vivo:LibrarianPosition . + +bibo:annotates rdfs:subPropertyOf bibo:annotates , owl:topObjectProperty . + +vcard:Type rdfs:subClassOf owl:Thing ; + owl:equivalentClass vcard:Type . + +vivo:Institute rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Institute . + +obo:BFO_0000029 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass obo:BFO_0000029 . + +vivo:Database rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass vivo:Database . + +bibo:draft a owl:Thing . + +vcard:title rdfs:subPropertyOf vcard:title , owl:topDataProperty . + +owl:sameAs rdfs:subPropertyOf owl:sameAs . + +vivo:Internship rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:Internship . + +vivo:totalAwardAmount + rdfs:subPropertyOf vivo:totalAwardAmount , owl:topDataProperty . + +obo:OBI_0000299 rdfs:subPropertyOf obo:OBI_0000299 , owl:topObjectProperty , obo:RO_0000057 . + +bibo:accepted a owl:Thing . + +geo:group rdfs:subClassOf owl:Thing ; + owl:equivalentClass geo:group . + +obo:ERO_0001258 rdfs:subClassOf obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:ERO_0001258 . + +vivo:WorkshopSeries rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:WorkshopSeries . + +skos:related rdfs:subPropertyOf skos:related , owl:topObjectProperty ; + owl:inverseOf skos:related . + +vivo:iclCode rdfs:subPropertyOf vivo:iclCode , owl:topDataProperty . + +geo:hasMaxLatitude rdfs:subPropertyOf geo:hasMaxLatitude , owl:topDataProperty . + +vivo:AdviseeRole rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass vivo:AdviseeRole . + +geo:hasMinLongitude rdfs:subPropertyOf + geo:hasMinLongitude , owl:topDataProperty . + +vcard:Male rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Male . + +vivo:StudentOrganization + rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:StudentOrganization . + +vivo:MedicalResidency + rdfs:subClassOf obo:BFO_0000015 , obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:MedicalResidency . + +vitro:Portal rdfs:subClassOf owl:Thing ; + owl:equivalentClass vitro:Portal . + +vcard:uid rdfs:subPropertyOf vcard:uid , owl:topDataProperty . + +obo:ERO_0000044 rdfs:subPropertyOf obo:ERO_0000044 , owl:topDataProperty . + +bibo:LegalDecision rdfs:subClassOf bibo:Document , obo:IAO_0000030 , bibo:LegalDocument , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:LegalDecision . + +vcard:Colleague rdfs:subClassOf vcard:Code , owl:Thing ; + owl:equivalentClass vcard:Colleague . + +bibo:Slide rdfs:subClassOf bibo:Document , obo:IAO_0000030 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass bibo:Slide . + +vivo:governingAuthorityFor + rdfs:subPropertyOf vivo:governingAuthorityFor , owl:topObjectProperty . + +obo:IAO_0000009 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000009 . + +obo:IAO_0000300 rdfs:subClassOf obo:BFO_0000001 , owl:Thing , obo:BFO_0000031 , obo:BFO_0000002 ; + owl:equivalentClass obo:IAO_0000300 . + +vcard:email rdfs:subPropertyOf vcard:email , owl:topDataProperty . + +obo:ERO_0000012 rdfs:subClassOf obo:BFO_0000020 , obo:BFO_0000001 , owl:Thing , obo:BFO_0000017 , obo:BFO_0000002 ; + owl:disjointWith obo:ARG_2000022 , obo:BFO_0000019 , obo:ARG_2000021 ; + owl:equivalentClass obo:ERO_0000012 . + +vivo:PeerReviewerRole + rdfs:subClassOf obo:BFO_0000001 , obo:BFO_0000017 , obo:BFO_0000020 , owl:Thing , obo:BFO_0000002 , obo:BFO_0000023 ; + owl:disjointWith obo:BFO_0000019 , obo:ARG_2000021 , obo:ARG_2000022 ; + owl:equivalentClass vivo:PeerReviewerRole . + +vivo:isCorrespondingAuthor + rdfs:subPropertyOf vivo:isCorrespondingAuthor , owl:topDataProperty . + +vitro:logotypeWidth rdfs:subPropertyOf + vitro:logotypeWidth , owl:topDataProperty . + +bibo:reproducedIn rdfs:subPropertyOf owl:topObjectProperty , bibo:reproducedIn ; + owl:inverseOf vivo:reproduces . + +vivo:EventSeries rdfs:subClassOf obo:BFO_0000003 , obo:BFO_0000001 , owl:Thing ; + owl:equivalentClass vivo:EventSeries . + +vcard:Key rdfs:subClassOf vcard:TimeZone , vcard:Calendar , owl:Thing , vcard:Geographical , vcard:Geo ; + owl:equivalentClass vcard:Key . + +vivo:hasMonetaryAmount + rdfs:subPropertyOf vivo:hasMonetaryAmount , owl:topDataProperty . + +vivo:researcherId rdfs:subPropertyOf vivo:researcherId , owl:topDataProperty . + +vivo:ExtensionUnit rdfs:subClassOf foaf:Agent , obo:BFO_0000001 , owl:Thing , obo:BFO_0000004 , obo:BFO_0000002 ; + owl:equivalentClass vivo:ExtensionUnit . + +geo:HDITotal rdfs:subPropertyOf geo:HDITotal , owl:topDataProperty . diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/TBoxReasonerSmokeTest.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/TBoxReasonerSmokeTest.java new file mode 100644 index 000000000..033fd0ef9 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/TBoxReasonerSmokeTest.java @@ -0,0 +1,73 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.servlet.setup; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.nio.file.Paths; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.ontology.OntModelSpec; +import com.hp.hpl.jena.rdf.model.ModelFactory; + +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; + +/** + * Safety Net: + * + * Insure that the inferred TBox is the same as it was before we started messing + * with things. + * + * KLUGE -- this shouldn't go into production. + * + * KLUGE -- in production, startup_listeners shouldn't mention this. + */ +public class TBoxReasonerSmokeTest implements ServletContextListener { + @Override + public void contextInitialized(ServletContextEvent sce) { + ServletContext ctx = sce.getServletContext(); + StartupStatus ss = StartupStatus.getBean(ctx); + + OntModel savedInferencesModel = ModelFactory + .createOntologyModel(OntModelSpec.OWL_MEM); + + try (InputStream in = new FileInputStream(locateSavedInferencesFile())) { + savedInferencesModel.read(in, null, "N3"); + } catch (IOException e) { + ss.fatal(this, "Can't read saved inferences", e); + } + + OntModel tboxInferencesModel = ModelAccess.on(sce.getServletContext()) + .getOntModel(ModelNames.TBOX_INFERENCES); + + if (savedInferencesModel.isIsomorphicWith(tboxInferencesModel)) { + ss.info(this, "TBox inferences matches saved."); + } else { + ss.fatal(this, "TBox inferences does not match saved."); + } + } + + private File locateSavedInferencesFile() { + String homeDirPath = ApplicationUtils.instance().getHomeDirectory() + .getPath().toString(); + Path savedInferencesPath = Paths.get(homeDirPath, "rdf", "tbox", + "savedInferences.n3"); + return savedInferencesPath.toFile(); + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + // Nothing to do + } + +} From 21727afd13210f7f0798433450f95289eefb3438 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Wed, 26 Nov 2014 16:29:59 -0500 Subject: [PATCH 04/10] VIVO-778 Extract ConfiguredReasonerListener from PelletListener. Separate the filtered listener from the reasoner driver. --- .../dao/jena/pellet/PelletListener.java | 366 ++++-------------- .../ConfiguredReasonerListener.java | 334 ++++++++++++++++ .../tboxreasoner/TBoxReasonerDriver.java | 21 + 3 files changed, 426 insertions(+), 295 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ConfiguredReasonerListener.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java 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 index d76547497..4cfc732a4 100644 --- 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 @@ -2,11 +2,8 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; -import java.util.List; -import java.util.Map; import java.util.Queue; import java.util.Set; @@ -19,28 +16,25 @@ import org.mindswap.pellet.jena.PelletReasonerFactory; import com.hp.hpl.jena.ontology.DatatypeProperty; import com.hp.hpl.jena.ontology.ObjectProperty; import com.hp.hpl.jena.ontology.OntModel; -import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; -import com.hp.hpl.jena.rdf.model.ModelChangedListener; import com.hp.hpl.jena.rdf.model.ModelFactory; -import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.rdf.model.Statement; -import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.util.iterator.ClosableIterator; import com.hp.hpl.jena.vocabulary.OWL; -import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; -import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener.Suspension; 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 ModelChangedListener { +public class PelletListener implements TBoxReasonerDriver { private static final Log log = LogFactory.getLog(PelletListener.class.getName()); private boolean isReasoning = false; @@ -56,7 +50,7 @@ public class PelletListener implements ModelChangedListener { private Set inferenceDrivingPatternDenySet; private Set inferenceReceivingPatternAllowSet; - private Map> inferenceDrivingPatternMap; + private final ConfiguredReasonerListener listener; private Model additionModel; private Model removalModel; @@ -64,8 +58,6 @@ public class PelletListener implements ModelChangedListener { private Model deletedObjectProperties; private Model deletedDataProperties; - private boolean pipeOpen; - private boolean isConsistent = true; private boolean inErrorState = false; private String explanation = ""; @@ -86,14 +78,6 @@ public class PelletListener implements ModelChangedListener { return this.isReasoning; } - public void closePipe() { - pipeOpen = false; - } - - public void openPipe() { - pipeOpen = true; - } - public synchronized boolean checkAndStartReasoning(){ if( this.isReasoning ) return false; @@ -143,45 +127,88 @@ public class PelletListener implements ModelChangedListener { this.inferenceDrivingPatternDenySet = reasonerConfiguration.getInferenceDrivingPatternDenySet(); this.inferenceReceivingPatternAllowSet = reasonerConfiguration.getInferenceReceivingPatternAllowSet(); - if (this.inferenceDrivingPatternAllowSet != null) { - this.inferenceDrivingPatternMap = new HashMap<>(); - for (Iterator i = inferenceDrivingPatternAllowSet.iterator(); i.hasNext();) { - ReasonerStatementPattern pat = i.next(); - Property p = pat.getPredicate(); - List patList = inferenceDrivingPatternMap.get(p); - if (patList == null) { - patList = new LinkedList<>(); - patList.add(pat); - inferenceDrivingPatternMap.put(p, patList); - } else { - patList.add(pat); - } - } - } - this.pipeOpen = true; this.additionModel = ModelFactory.createDefaultModel(); this.removalModel = ModelFactory.createDefaultModel(); this.deletedObjectProperties = ModelFactory.createDefaultModel(); this.deletedDataProperties = ModelFactory.createDefaultModel(); + + listener = new ConfiguredReasonerListener(reasonerConfiguration, this); + this.mainModel.enterCriticalSection(Lock.READ); try { for (ReasonerStatementPattern pat : this.inferenceDrivingPatternAllowSet) { - addedStatements(mainModel.listStatements((Resource) null, pat.getPredicate(), (RDFNode) null)); + listener.addedStatements(mainModel.listStatements((Resource) null, pat.getPredicate(), (RDFNode) null)); } if (!skipReasoningUponInitialization) { this.foreground = foreground; - notifyEvent(null,new EditEvent(null,false)); + listener.notifyEvent(null,new EditEvent(null,false)); } else if (inferenceModel.size() == 0){ foreground = true; - notifyEvent(null,new EditEvent(null,false)); + listener.notifyEvent(null,new EditEvent(null,false)); this.foreground = foreground; } } finally { this.mainModel.leaveCriticalSection(); } - this.fullModel.getBaseModel().register(this); - this.mainModel.getBaseModel().register(this); + 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 { @@ -333,12 +360,10 @@ public class PelletListener implements ModelChangedListener { if (!fullModelContainsStatement) { // in theory we should be able to lock only the inference model, but I'm not sure yet if Jena propagates the locking upward fullModel.enterCriticalSection(Lock.WRITE); - closePipe(); - try { + try (Suspension susp = listener.suspend()) { inferenceModel.add(stmt); addCount++; } finally { - openPipe(); fullModel.leaveCriticalSection(); } } @@ -360,12 +385,10 @@ public class PelletListener implements ModelChangedListener { } for (Iterator i = localRemovalQueue.iterator(); i.hasNext(); ) { fullModel.enterCriticalSection(Lock.WRITE); - closePipe(); - try { + try (Suspension susp = listener.suspend()) { retractCount++; inferenceModel.remove(i.next()); } finally { - openPipe(); fullModel.leaveCriticalSection(); } } @@ -412,208 +435,6 @@ public class PelletListener implements ModelChangedListener { } } - // TODO: These next two methods are really ugly; I need to refactor them to remove redundancy. - - private void tryAdd(Statement stmt) { - boolean sendToPellet = false; - if ( pipeOpen && reasonerConfiguration.getReasonOnAllDatatypePropertyStatements() && stmt.getObject().isLiteral() ) { - sendToPellet = true; - } else - if ( pipeOpen && hasCardinalityPredicate(stmt) ) { // see comment on this method - sendToPellet = true; - } else - if ( (stmt.getObject().isResource()) && !((stmt.getPredicate().getURI().indexOf(VitroVocabulary.vitroURI)==0)) ) { - if (pipeOpen) { - sendToPellet = false; - boolean denied = false; - ReasonerStatementPattern stPat = ReasonerStatementPattern.objectPattern(stmt); - if (inferenceDrivingPatternDenySet != null) { - for (Iterator i = inferenceDrivingPatternDenySet.iterator(); i.hasNext(); ){ - ReasonerStatementPattern pat = i.next(); - if (pat.matches(stPat)) { - denied = true; - break; - } - } - } - if (!denied) { - if (inferenceDrivingPatternAllowSet==null) { - sendToPellet = true; - } else { - // TODO: O(1) implementation of this - List patList = this.inferenceDrivingPatternMap.get(stmt.getPredicate()); - if (patList != null) { - for (Iterator i = patList.iterator(); i.hasNext(); ){ - ReasonerStatementPattern pat = i.next(); - if (pat.matches(stPat)) { - sendToPellet = true; - break; - } - } - } - } - } - - } - } - if (sendToPellet) { - //long startTime = System.currentTimeMillis(); - String valueStr = (stmt.getObject().isResource()) ? ((Resource)stmt.getObject()).getLocalName() : ((Literal)stmt.getObject()).getLexicalForm(); - if ( log.isDebugEnabled() ) { - log.debug( "Adding to Pellet: " + renderStatement( stmt ) ); - } - additionModel.enterCriticalSection(Lock.WRITE); - try { - additionModel.add(stmt); - } finally { - additionModel.leaveCriticalSection(); - } - } else { - if ( log.isDebugEnabled() ) { - log.debug( "Not adding to Pellet: " + renderStatement( stmt ) ); - } - } - } - - - private void tryRemove(Statement stmt) { - boolean removeFromPellet = false; - if ( pipeOpen && reasonerConfiguration.getReasonOnAllDatatypePropertyStatements() && stmt.getObject().isLiteral() ) { - removeFromPellet = true; - } else - if ( pipeOpen && hasCardinalityPredicate(stmt) ) { // see comment on this method - removeFromPellet = true; - } else - if ( stmt.getObject().isResource() ) { - if (pipeOpen) { - if (reasonerConfiguration.getQueryForAllObjectProperties() && stmt.getPredicate().equals(RDF.type) && stmt.getObject().equals(OWL.ObjectProperty)) { - deletedObjectProperties.enterCriticalSection(Lock.WRITE); - try { - deletedObjectProperties.add(stmt); - } finally { - deletedObjectProperties.leaveCriticalSection(); - } - } - if (reasonerConfiguration.getQueryForAllDatatypeProperties() && stmt.getPredicate().equals(RDF.type) && stmt.getObject().equals(OWL.DatatypeProperty)) { - deletedDataProperties.enterCriticalSection(Lock.WRITE); - try{ - deletedDataProperties.add(stmt); - } finally { - deletedDataProperties.leaveCriticalSection(); - } - } - removeFromPellet = false; - boolean denied = false; - ReasonerStatementPattern stPat = ReasonerStatementPattern.objectPattern(stmt); - if (inferenceDrivingPatternDenySet != null) { - for (Iterator i = inferenceDrivingPatternDenySet.iterator(); i.hasNext(); ){ - ReasonerStatementPattern pat = i.next(); - if (pat.matches(stPat)) { - denied = true; - break; - } - } - } - if (!denied) { - if (inferenceDrivingPatternAllowSet==null) { - removeFromPellet = true; - } else { - // TODO: O(1) implementation of this - List patList = this.inferenceDrivingPatternMap.get(stmt.getPredicate()); - if (patList != null) { - for (Iterator i = patList.iterator(); i.hasNext(); ){ - ReasonerStatementPattern pat = i.next(); - if (pat.matches(stPat)) { - removeFromPellet = true; - break; - } - } - } - } - } - } - } - if (removeFromPellet) { - String valueStr = (stmt.getObject().isResource()) ? ((Resource)stmt.getObject()).getLocalName() : ((Literal)stmt.getObject()).getLexicalForm(); - log.info("Removing from Pellet: "+stmt.getSubject().getLocalName()+" "+stmt.getPredicate().getLocalName()+" "+valueStr); - removalModel.enterCriticalSection(Lock.WRITE); - try { - removalModel.add(stmt); - } finally { - removalModel.leaveCriticalSection(); - } - } - } - - // The pattern matching stuff needs to get reworked. - // It originally assumed that only resources would be in object - // position, but cardinality axioms will have e.g. nonNegativeIntegers. - // This is a temporary workaround: all cardinality statements will - // be exposed to Pellet, regardless of configuration patterns. - private boolean hasCardinalityPredicate(Statement stmt) { - return ( - stmt.getPredicate().equals(OWL.cardinality) || - stmt.getPredicate().equals(OWL.minCardinality) || - stmt.getPredicate().equals(OWL.maxCardinality) - ) ; - } - - - public void addedStatement(Statement arg0) { - tryAdd(arg0); - } - - - public void addedStatements(Statement[] arg0) { - for (int i=0; i 0) || (removalModel.size()>0) ) { - if (!isSynchronizing) { - if (foreground) { - log.debug("Running Pellet in foreground."); - (new PelletSynchronizer()).run(); - } else { - log.debug("Running Pellet in background."); - new Thread(new PelletSynchronizer(), "PelletListener.PelletSynchronizer").start(); - } - } - } - } - } - } - private class PelletSynchronizer implements Runnable { public void run() { try { @@ -657,54 +478,9 @@ public class PelletListener implements ModelChangedListener { } } } - - public void removedStatement(Statement arg0) { - tryRemove(arg0); - } - - - public void removedStatements(Statement[] arg0) { - for (int i=0; i> { + + public DrivingPatternMap(Set patternSet) { + if (patternSet != null) { + for (ReasonerStatementPattern pat : patternSet) { + Property p = pat.getPredicate(); + if (!containsKey(p)) { + put(p, new LinkedList()); + } + get(p).add(pat); + } + } + } + } + + // ---------------------------------------------------------------------- + // Implement the ModelChangedListener methods. Delegate to the methods that + // check criteria. + // ---------------------------------------------------------------------- + + @Override + public void addedStatement(Statement s) { + tryAdd(s); + } + + @Override + public void addedStatements(Statement[] statements) { + for (Statement stmt : statements) { + tryAdd(stmt); + } + } + + @Override + public void addedStatements(List statements) { + for (Statement stmt : statements) { + tryAdd(stmt); + } + } + + @Override + public void addedStatements(StmtIterator statements) { + for (Statement stmt : statements.toList()) { + tryAdd(stmt); + } + } + + @Override + public void addedStatements(Model m) { + for (Statement stmt : m.listStatements().toList()) { + tryAdd(stmt); + } + } + + @Override + public void removedStatement(Statement s) { + tryRemove(s); + } + + @Override + public void removedStatements(Statement[] statements) { + for (Statement stmt : statements) { + tryRemove(stmt); + } + } + + @Override + public void removedStatements(List statements) { + for (Statement stmt : statements) { + tryRemove(stmt); + } + } + + @Override + public void removedStatements(StmtIterator statements) { + for (Statement stmt : statements.toList()) { + tryRemove(stmt); + } + } + + @Override + public void removedStatements(Model m) { + for (Statement stmt : m.listStatements().toList()) { + tryRemove(stmt); + } + } + + @Override + public void notifyEvent(Model m, Object event) { + if (event instanceof EditEvent) { + EditEvent ee = (EditEvent) event; + if (!ee.getBegin()) { + this.reasonerDriver.runSynchronizer(); + } + } + } + + // ---------------------------------------------------------------------- + // Check the criteria to determine whether each addition or removal should + // be passed to the reasoner. + // + // When the listener is suspended, nothing is passed on. + // ---------------------------------------------------------------------- + + public void tryAdd(Statement stmt) { + if (suspended.get()) { + return; + } + + if (isDataProperty(stmt)) { + if (reasonOnAllDataProperties() || hasCardinalityPredicate(stmt)) { + addIt(stmt); + return; + } else { + return; + } + } + + if (predicateIsInVitroNamespace(stmt) + || statementMatchesDenyPattern(stmt)) { + return; + } + + if (thereAreNoDrivingPatterns() || statementMatchesDrivingPattern(stmt)) { + addIt(stmt); + return; + } + } + + public void tryRemove(Statement stmt) { + if (suspended.get()) { + return; + } + + if (isDataProperty(stmt)) { + if (reasonOnAllDataProperties() || hasCardinalityPredicate(stmt)) { + removeIt(stmt); + return; + } else { + return; + } + } + + if (actOnObjectPropertyDeclarations() && declaresObjectProperty(stmt)) { + deleteObjectProperty(stmt); + return; + } + + if (actOnDataPropertyDeclarations() && declaresDataProperty(stmt)) { + deleteDataProperty(stmt); + return; + } + + if (statementMatchesDenyPattern(stmt)) { + return; + } + + if (thereAreNoDrivingPatterns() || statementMatchesDrivingPattern(stmt)) { + removeIt(stmt); + return; + } + } + + private boolean isDataProperty(Statement stmt) { + return stmt.getObject().isLiteral(); + } + + private boolean reasonOnAllDataProperties() { + return reasonerConfiguration.getReasonOnAllDatatypePropertyStatements(); + } + + private boolean predicateIsInVitroNamespace(Statement stmt) { + return stmt.getPredicate().getURI().indexOf(VitroVocabulary.vitroURI) == 0; + } + + private boolean statementMatchesDenyPattern(Statement stmt) { + Set denyPatterns = reasonerConfiguration.inferenceDrivingPatternDenySet; + if (denyPatterns == null) { + return false; + } + + ReasonerStatementPattern stPat = ReasonerStatementPattern + .objectPattern(stmt); + + for (ReasonerStatementPattern pat : denyPatterns) { + if (pat.matches(stPat)) { + return true; + } + } + + return false; + } + + private boolean thereAreNoDrivingPatterns() { + return reasonerConfiguration.inferenceDrivingPatternAllowSet == null; + } + + private boolean statementMatchesDrivingPattern(Statement stmt) { + List drivePatterns = drivingPatternMap + .get(stmt.getPredicate()); + if (drivePatterns == null) { + return false; + } + + ReasonerStatementPattern stPat = ReasonerStatementPattern + .objectPattern(stmt); + + for (ReasonerStatementPattern pat : drivePatterns) { + if (pat.matches(stPat)) { + return true; + } + } + + return false; + } + + private boolean actOnObjectPropertyDeclarations() { + return reasonerConfiguration.getQueryForAllObjectProperties(); + } + + private boolean declaresObjectProperty(Statement stmt) { + return stmt.getPredicate().equals(RDF.type) + && stmt.getObject().equals(OWL.ObjectProperty); + } + + private boolean actOnDataPropertyDeclarations() { + return reasonerConfiguration.getQueryForAllDatatypeProperties(); + } + + private boolean declaresDataProperty(Statement stmt) { + return stmt.getPredicate().equals(RDF.type) + && stmt.getObject().equals(OWL.DatatypeProperty); + } + + private void addIt(Statement stmt) { + this.reasonerDriver.addStatement(stmt); + } + + private void removeIt(Statement stmt) { + this.reasonerDriver.removeStatement(stmt); + } + + private void deleteObjectProperty(Statement stmt) { + this.reasonerDriver.deleteObjectProperty(stmt); + } + + private void deleteDataProperty(Statement stmt) { + this.reasonerDriver.deleteDataProperty(stmt); + } + + // The pattern matching stuff needs to get reworked. + // It originally assumed that only resources would be in object + // position, but cardinality axioms will have e.g. nonNegativeIntegers. + // This is a temporary workaround: all cardinality statements will + // be exposed to Pellet, regardless of configuration patterns. + private boolean hasCardinalityPredicate(Statement stmt) { + return (stmt.getPredicate().equals(OWL.cardinality) + || stmt.getPredicate().equals(OWL.minCardinality) || stmt + .getPredicate().equals(OWL.maxCardinality)); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java new file mode 100644 index 000000000..a52d8e06a --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java @@ -0,0 +1,21 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.tboxreasoner; + +import com.hp.hpl.jena.rdf.model.Statement; + +/** + * What calls can the ConfiguredReasonerListener make to drive the TBox reasoner? + */ +public interface TBoxReasonerDriver { + void runSynchronizer(); + + void addStatement(Statement stmt); + + void removeStatement(Statement stmt); + + void deleteDataProperty(Statement stmt); + + void deleteObjectProperty(Statement stmt); + +} From d513dcf9aeba7be12f53dcd016c4c03555d8995b Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Mon, 1 Dec 2014 16:52:07 -0500 Subject: [PATCH 05/10] VIVO-778 Break out just the task of syncing the inference model to the reasoner model. --- .../jena/pellet/InferenceModelUpdater.java | 139 ++++++++++++++++++ .../dao/jena/pellet/PelletListener.java | 94 +----------- .../servlet/setup/TBoxReasonerSmokeTest.java | 43 ++++++ 3 files changed, 189 insertions(+), 87 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/InferenceModelUpdater.java 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 new file mode 100644 index 000000000..36de3a795 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/InferenceModelUpdater.java @@ -0,0 +1,139 @@ +/* $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 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.utils.jena.criticalsection.LockableModel; +import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableOntModel; +import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedModel; +import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedOntModel; + +/** + * A tool that will adjust the inferences model to match the reasoner model, + * after applying the proper filters to both. + */ +public class InferenceModelUpdater { + private static final Log log = LogFactory + .getLog(InferenceModelUpdater.class); + + private final LockableOntModel lockableReasonerModel; + private final LockableModel lockableInferenceModel; + private final LockableOntModel lockableFullModel; + private final ConfiguredReasonerListener listener; + + private int addCount; + private int retractCount; + + public int getAddCount() { + return addCount; + } + + public int getRetractCount() { + return retractCount; + } + + public InferenceModelUpdater(OntModel reasonerModel, Model inferenceModel, + OntModel fullModel, ConfiguredReasonerListener listener) { + this.lockableReasonerModel = new LockableOntModel(reasonerModel); + this.lockableInferenceModel = new LockableModel(inferenceModel); + this.lockableFullModel = new LockableOntModel(fullModel); + 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. + * + * 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); + 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()) { + if (!fullModelContainsStatement(stmt)) { + try (LockedModel inferenceModel = lockableInferenceModel + .write(); Suspension susp = listener.suspend()) { + inferenceModel.add(stmt); + addCount++; + } + } + } + } + + private boolean fullModelContainsStatement(Statement stmt) { + try (LockedOntModel fullModel = lockableFullModel.read()) { + return fullModel.contains(stmt); + } + } + + private Model filterInferencesModel( + LinkedList patternList) { + Model filtered = ModelFactory.createDefaultModel(); + try (LockedOntModel reasonerModel = lockableReasonerModel.read()) { + for (ReasonerStatementPattern pattern : patternList) { + filtered.add(pattern.matchStatementsFromModel(reasonerModel)); + } + } + log.warn("Filtered inferences model: " + filtered.size()); + return filtered; + } + + private void removeOldInferences(Model filteredInferencesModel, + Model filteredReasonerModel) { + for (Statement stmt : filteredInferencesModel.listStatements().toList()) { + if (!filteredReasonerModel.contains(stmt)) { + try (LockedModel inferenceModel = lockableInferenceModel + .write(); Suspension susp = listener.suspend()) { + retractCount++; + inferenceModel.remove(stmt); + } + } + } + } + +} 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 index 4cfc732a4..fc44d2d14 100644 --- 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 @@ -4,7 +4,6 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet; import java.util.Iterator; import java.util.LinkedList; -import java.util.Queue; import java.util.Set; import org.apache.commons.logging.Log; @@ -24,12 +23,9 @@ import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.util.iterator.ClosableIterator; -import com.hp.hpl.jena.vocabulary.OWL; -import com.hp.hpl.jena.vocabulary.RDFS; 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.ConfiguredReasonerListener.Suspension; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver; @@ -303,10 +299,7 @@ public class PelletListener implements TBoxReasonerDriver { deletedDataProperties.leaveCriticalSection(); } } - - int addCount = 0; - int retractCount = 0; - + // force new reasoner (disabled) if (false && !reasonerConfiguration.isIncrementalReasoningEnabled()) { Model baseModel = pelletModel.getBaseModel(); @@ -323,88 +316,16 @@ public class PelletListener implements TBoxReasonerDriver { pelletModel.leaveCriticalSection(); } - for (Iterator patIt = irpl.iterator(); patIt.hasNext(); ) { - ReasonerStatementPattern pat = patIt.next(); - log.debug("Querying for "+pat); - - Model tempModel = ModelFactory.createDefaultModel(); - - pelletModel.enterCriticalSection(Lock.READ); - try { - for(Statement stmt : pat.matchStatementsFromModel(pelletModel)) { - - boolean reject = false; - - // this next part is only needed if we're using Jena's OWL reasoner instead of actually using Pellet - try { - if ( ( ((Resource)stmt.getObject()).equals(RDFS.Resource) ) ) { - reject = true; - } else if ( ( stmt.getSubject().equals(OWL.Nothing) ) ) { - reject = true; - } else if ( ( stmt.getObject().equals(OWL.Nothing) ) ) { - reject = true; - } - } catch (Exception e) {} - - if (!reject) { - tempModel.add(stmt); - - boolean fullModelContainsStatement = false; - fullModel.enterCriticalSection(Lock.READ); - try { - fullModelContainsStatement = fullModel.contains(stmt); - } finally { - fullModel.leaveCriticalSection(); - } - - if (!fullModelContainsStatement) { - // in theory we should be able to lock only the inference model, but I'm not sure yet if Jena propagates the locking upward - fullModel.enterCriticalSection(Lock.WRITE); - try (Suspension susp = listener.suspend()) { - inferenceModel.add(stmt); - addCount++; - } finally { - fullModel.leaveCriticalSection(); - } - } - - } - } - } finally { - pelletModel.leaveCriticalSection(); - } - - // now we see what's in the inference model that isn't in the temp model and remove it - - try { - Queue localRemovalQueue = new LinkedList(); - for (Statement stmt : pat.matchStatementsFromModel(inferenceModel)) { - if (!tempModel.contains(stmt)) { - localRemovalQueue.add(stmt); - } - } - for (Iterator i = localRemovalQueue.iterator(); i.hasNext(); ) { - fullModel.enterCriticalSection(Lock.WRITE); - try (Suspension susp = listener.suspend()) { - retractCount++; - inferenceModel.remove(i.next()); - } finally { - fullModel.leaveCriticalSection(); - } - } - - localRemovalQueue.clear(); - } catch (Exception e) { - log.error("Error getting inferences", e); - } - tempModel = null; - } + InferenceModelUpdater inferenceModelUpdater = new InferenceModelUpdater( + pelletModel, inferenceModel, fullModel, listener); + inferenceModelUpdater.update(irpl); + this.pelletListener.isConsistent = true; this.pelletListener.inErrorState = false; this.pelletListener.explanation = ""; if (log.isDebugEnabled()) { - log.info("Added "+addCount+" statements entailed by assertions"); - log.info("Retracted "+retractCount+" statements no longer entailed by assertions"); + log.info("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) { @@ -421,7 +342,6 @@ public class PelletListener implements TBoxReasonerDriver { } } } - } private void getInferences() { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/TBoxReasonerSmokeTest.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/TBoxReasonerSmokeTest.java index 033fd0ef9..1fe7109d0 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/TBoxReasonerSmokeTest.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/TBoxReasonerSmokeTest.java @@ -13,9 +13,14 @@ import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; +import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.Statement; import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; @@ -33,6 +38,9 @@ import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; * KLUGE -- in production, startup_listeners shouldn't mention this. */ public class TBoxReasonerSmokeTest implements ServletContextListener { + private static final Log log = LogFactory + .getLog(TBoxReasonerSmokeTest.class); + @Override public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); @@ -53,10 +61,45 @@ public class TBoxReasonerSmokeTest implements ServletContextListener { if (savedInferencesModel.isIsomorphicWith(tboxInferencesModel)) { ss.info(this, "TBox inferences matches saved."); } else { + dumpDifferences(savedInferencesModel, tboxInferencesModel); ss.fatal(this, "TBox inferences does not match saved."); } } + private void dumpDifferences(OntModel savedInferencesModel, + OntModel tboxInferencesModel) { + Model missingStatements = ModelFactory.createDefaultModel(); + for (Statement stmt : savedInferencesModel.listStatements().toList()) { + if (!tboxInferencesModel.contains(stmt)) { + missingStatements.add(stmt); + } + } + + Model extraStatements = ModelFactory.createDefaultModel(); + for (Statement stmt : tboxInferencesModel.listStatements().toList()) { + if (!savedInferencesModel.contains(stmt)) { + extraStatements.add(stmt); + } + } + + log.error("inferences: " + tboxInferencesModel.size() + ", saved: " + + savedInferencesModel.size() + ", missing: " + + missingStatements.size() + ", extra: " + + extraStatements.size()); + + String missing = ""; + for (Statement stmt : missingStatements.listStatements().toList()) { + missing += "\n " + stmt; + } + log.error("missing statements:" + missing); + + String extras = ""; + for (Statement stmt : extraStatements.listStatements().toList()) { + extras += "\n " + stmt; + } + log.error("extra statements:" + extras); + } + private File locateSavedInferencesFile() { String homeDirPath = ApplicationUtils.instance().getHomeDirectory() .getPath().toString(); From 4e156952814cdbc36b1fd2734c54514643bb83e1 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Tue, 2 Dec 2014 14:22:58 -0500 Subject: [PATCH 06/10] VIVO-778 Break out just the task of building the pattern list. --- .../dao/jena/pellet/PatternListBuilder.java | 110 ++++++++++++++++ .../dao/jena/pellet/PelletListener.java | 119 ++---------------- .../tboxreasoner/TBoxReasonerDriver.java | 35 +++++- 3 files changed, 157 insertions(+), 107 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PatternListBuilder.java 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 new file mode 100644 index 000000000..dbc5d0417 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PatternListBuilder.java @@ -0,0 +1,110 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet; + +import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty; + +import java.util.LinkedList; +import java.util.Set; + +import com.hp.hpl.jena.ontology.DatatypeProperty; +import com.hp.hpl.jena.ontology.ObjectProperty; +import 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; + +/** + * The list of patterns for filtering the models will include: + * + * All patterns specified by the ReasonerConfiguration, + * + * One pattern for each deleted property, to match the use of that property as a + * predicate. + */ +public class PatternListBuilder { + private static final String OWL_NS = "http://www.w3.org/2002/07/owl#"; + + private final ReasonerConfiguration reasonerConfiguration; + private final LockableOntModel lockableReasonerModel; + private final LockableModel lockableDeletedObjectProperties; + private final LockableModel lockableDeletedDataProperties; + + public PatternListBuilder(ReasonerConfiguration reasonerConfiguration, + OntModel reasonerModel, Model deletedObjectProperties, + Model deletedDataProperties) { + this.reasonerConfiguration = reasonerConfiguration; + this.lockableReasonerModel = new LockableOntModel(reasonerModel); + this.lockableDeletedObjectProperties = new LockableModel( + deletedObjectProperties); + this.lockableDeletedDataProperties = new LockableModel( + deletedDataProperties); + } + + /** + * @return + */ + public LinkedList build() { + LinkedList irpl = new LinkedList<>(); + + Set allowSet = reasonerConfiguration + .getInferenceReceivingPatternAllowSet(); + if (allowSet != null) { + irpl.addAll(allowSet); + } else { + irpl.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)); + } + } + } + + try (LockedModel deletedObjectProperties = lockableDeletedObjectProperties + .write()) { + for (Resource subj : deletedObjectProperties.listSubjects() + .toList()) { + irpl.add(ReasonerStatementPattern + .objectPattern(createProperty(subj.getURI()))); + } + deletedObjectProperties.removeAll(); + } + } + + 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)); + } + } + } + try (LockedModel deletedDataProperties = lockableDeletedDataProperties + .write()) { + for (Resource subj : deletedDataProperties.listSubjects() + .toList()) { + irpl.add(ReasonerStatementPattern + .objectPattern(createProperty(subj.getURI()))); + } + deletedDataProperties.removeAll(); + } + } + return irpl; + } +} 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 index fc44d2d14..0a706f13a 100644 --- 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 @@ -2,7 +2,6 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet; -import java.util.Iterator; import java.util.LinkedList; import java.util.Set; @@ -10,19 +9,14 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mindswap.pellet.exceptions.InconsistentOntologyException; import org.mindswap.pellet.jena.PelletInfGraph; -import org.mindswap.pellet.jena.PelletReasonerFactory; -import com.hp.hpl.jena.ontology.DatatypeProperty; -import com.hp.hpl.jena.ontology.ObjectProperty; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.rdf.model.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.shared.Lock; -import com.hp.hpl.jena.util.iterator.ClosableIterator; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener; @@ -54,20 +48,18 @@ public class PelletListener implements TBoxReasonerDriver { private Model deletedObjectProperties; private Model deletedDataProperties; - private boolean isConsistent = true; - private boolean inErrorState = false; - private String explanation = ""; + private Status status = Status.SUCCESS; public boolean isConsistent() { - return this.isConsistent; + return this.status.isConsistent(); } public String getExplanation() { - return this.explanation; + return this.status.getExplanation(); } public boolean isInErrorState() { - return this.inErrorState; + return this.status.isInErrorState(); } public boolean isReasoning() { @@ -95,8 +87,6 @@ public class PelletListener implements TBoxReasonerDriver { this.dirty = dirt; } - private int inferenceRounds = 0; - private boolean foreground = false; private static final boolean FOREGROUND = true; private static final boolean BACKGROUND = false; @@ -217,96 +207,16 @@ public class PelletListener implements TBoxReasonerDriver { public void run() { while (pelletListener.isDirty()) { - //pipeOpen = false; try { pelletListener.setDirty(false); - inferenceRounds++; log.info("Getting new inferences"); long startTime = System.currentTimeMillis(); - LinkedList irpl = new LinkedList<>(); - if (inferenceReceivingPatternAllowSet != null) { - irpl.addAll(inferenceReceivingPatternAllowSet); - } else { - irpl.add(ReasonerStatementPattern.ANY_OBJECT_PROPERTY); - } - - if (reasonerConfiguration.getQueryForAllObjectProperties()) { - pelletModel.enterCriticalSection(Lock.READ); - try { - ClosableIterator closeIt = pelletModel.listObjectProperties(); - try { - for (Iterator objPropIt = closeIt; objPropIt.hasNext();) { - ObjectProperty objProp = (ObjectProperty) objPropIt.next(); - if ( !("http://www.w3.org/2002/07/owl#".equals(objProp.getNameSpace())) ) { - irpl.add(ReasonerStatementPattern.objectPattern(objProp)); - } - } - } finally { - closeIt.close(); - } - } finally { - pelletModel.leaveCriticalSection(); - } - deletedObjectProperties.enterCriticalSection(Lock.WRITE); - try { - ClosableIterator sit = deletedObjectProperties.listSubjects(); - try { - while (sit.hasNext()) { - Resource subj = (Resource) sit.next(); - irpl.add(ReasonerStatementPattern.objectPattern(ResourceFactory.createProperty(subj.getURI()))); - } - } finally { - sit.close(); - } - deletedObjectProperties.removeAll(); - } finally { - deletedObjectProperties.leaveCriticalSection(); - } - } - - if (reasonerConfiguration.getQueryForAllDatatypeProperties()) { - pelletModel.enterCriticalSection(Lock.READ); - try { - ClosableIterator closeIt = pelletModel.listDatatypeProperties(); - try { - for (Iterator dataPropIt = closeIt; dataPropIt.hasNext();) { - DatatypeProperty dataProp = (DatatypeProperty) dataPropIt.next(); - if ( !("http://www.w3.org/2002/07/owl#".equals(dataProp.getNameSpace())) ) { - // TODO: THIS WILL WORK, BUT NEED TO GENERALIZE THE PATTERN CLASSES - irpl.add(ReasonerStatementPattern.objectPattern(dataProp)); - } - } - } finally { - closeIt.close(); - } - } finally { - pelletModel.leaveCriticalSection(); - } - deletedDataProperties.enterCriticalSection(Lock.WRITE); - try { - ClosableIterator sit = deletedDataProperties.listSubjects(); - try { - while (sit.hasNext()) { - Resource subj = (Resource) sit.next(); - irpl.add(ReasonerStatementPattern.objectPattern(ResourceFactory.createProperty(subj.getURI()))); - } - } finally { - sit.close(); - } - deletedDataProperties.removeAll(); - } finally { - deletedDataProperties.leaveCriticalSection(); - } - } - - // force new reasoner (disabled) - if (false && !reasonerConfiguration.isIncrementalReasoningEnabled()) { - Model baseModel = pelletModel.getBaseModel(); - pelletModel = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - pelletModel.getDocumentManager().setProcessImports(false); - pelletModel.add(baseModel); - } + PatternListBuilder patternListBuilder = new PatternListBuilder( + reasonerConfiguration, pelletModel, + deletedObjectProperties, deletedDataProperties); + LinkedList irpl = patternListBuilder + .build(); pelletModel.enterCriticalSection(Lock.WRITE); try { @@ -320,22 +230,19 @@ public class PelletListener implements TBoxReasonerDriver { pelletModel, inferenceModel, fullModel, listener); inferenceModelUpdater.update(irpl); - this.pelletListener.isConsistent = true; - this.pelletListener.inErrorState = false; - this.pelletListener.explanation = ""; - if (log.isDebugEnabled()) { + 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) { - this.pelletListener.isConsistent = false; String explanation = ((PelletInfGraph)pelletModel.getGraph()).getKB().getExplanation(); - this.pelletListener.explanation = explanation; + this.pelletListener.status = Status.inconsistent(explanation); log.error(ioe); log.error(explanation); } catch (Exception e) { - this.pelletListener.inErrorState = true; + this.pelletListener.status = Status.ERROR; log.error("Exception during inference", e); } finally { pelletListener.endReasoning(); 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 a52d8e06a..09c356adb 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java @@ -5,7 +5,8 @@ package edu.cornell.mannlib.vitro.webapp.tboxreasoner; import com.hp.hpl.jena.rdf.model.Statement; /** - * What calls can the ConfiguredReasonerListener make to drive the TBox reasoner? + * What calls can the ConfiguredReasonerListener make to drive the TBox + * reasoner? */ public interface TBoxReasonerDriver { void runSynchronizer(); @@ -18,4 +19,36 @@ public interface TBoxReasonerDriver { void deleteObjectProperty(Statement stmt); + public static class Status { + public static final Status SUCCESS = new Status(true, false, ""); + public static final Status ERROR = new Status(true, true, ""); + + public static final Status inconsistent(String explanation) { + return new Status(false, false, explanation); + } + + private final boolean consistent; + private final boolean inErrorState; + private final String explanation; + + private Status(boolean consistent, boolean inErrorState, + String explanation) { + this.consistent = consistent; + this.inErrorState = inErrorState; + this.explanation = explanation; + } + + public boolean isConsistent() { + return consistent; + } + + public boolean isInErrorState() { + return inErrorState; + } + + public String getExplanation() { + return explanation; + } + + } } From 24bce9ff670236d256fcb79bd7f4a9324405a404 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Wed, 3 Dec 2014 09:46:25 -0500 Subject: [PATCH 07/10] 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(); + } + } +} From 0c46f1d14ea4508ea516aaf8352eab4dc946b108 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Wed, 3 Dec 2014 10:18:03 -0500 Subject: [PATCH 08/10] VIVO-778 Let the listener hold the change set. --- .../tboxreasoner/BasicTBoxReasonerDriver.java | 35 +++---------------- .../ConfiguredReasonerListener.java | 26 +++++++++----- .../webapp/tboxreasoner/TBoxChanges.java | 5 +-- .../tboxreasoner/TBoxReasonerDriver.java | 11 +----- 4 files changed, 26 insertions(+), 51 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java index a38bf27b7..f02c54758 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java @@ -8,7 +8,6 @@ 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; @@ -17,11 +16,8 @@ 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; @@ -41,7 +37,6 @@ public class BasicTBoxReasonerDriver implements TBoxReasonerDriver { private final ConfiguredReasonerListener listener; - private final AtomicReference currentChangeSet; private final Set pendingChangeSets; private final ExecutorService executorService; @@ -62,7 +57,6 @@ public class BasicTBoxReasonerDriver implements TBoxReasonerDriver { this.listener = new ConfiguredReasonerListener(reasonerConfiguration, this); - this.currentChangeSet = new AtomicReference<>(new TBoxChanges()); this.pendingChangeSets = Collections.synchronizedSet(new HashSet()); this.executorService = Executors.newFixedThreadPool(1); @@ -97,32 +91,10 @@ public class BasicTBoxReasonerDriver implements TBoxReasonerDriver { } @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; + public void runSynchronizer(TBoxChanges changeSet) { + if (!changeSet.isEmpty()) { + executorService.execute(new ReasoningTask(changeSet)); } - executorService.execute(new ReasoningTask(changes)); } private class ReasoningTask implements Runnable { @@ -139,6 +111,7 @@ public class BasicTBoxReasonerDriver implements TBoxReasonerDriver { try { reasoner.updateReasonerModel(changes); status = reasoner.performReasoning(); + buildPatternList(); updateInferencesModel(); } finally { 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 cf7b90343..8ce096af4 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ConfiguredReasonerListener.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/ConfiguredReasonerListener.java @@ -7,6 +7,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -23,8 +24,11 @@ import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; /** - * Listens for changes on a model. When a change is announced, it is passed - * along to the reasoner driver, if the configuration says that it is worthy. + * Listens for changes on a model. When a change is announced, it is checked for + * worthiness. If worthy, it is added to a change set. + * + * When an ending EditEvent is received, the current change set is passed along + * to the reasoner driver, and a new change set is begun. * * Among the criteria for deciding on worthiness is the driving pattern set. In * the constructor, a map is made from this set, to reduce the number of tests @@ -41,9 +45,11 @@ public class ConfiguredReasonerListener implements ModelChangedListener { private final ReasonerConfiguration reasonerConfiguration; private final TBoxReasonerDriver reasonerDriver; + private final DrivingPatternMap drivingPatternMap; - private final AtomicBoolean suspended = new AtomicBoolean(); + private final AtomicReference changeSet; + private final AtomicBoolean suspended; public ConfiguredReasonerListener( ReasonerConfiguration reasonerConfiguration, @@ -53,6 +59,9 @@ public class ConfiguredReasonerListener implements ModelChangedListener { this.drivingPatternMap = new DrivingPatternMap( reasonerConfiguration.getInferenceDrivingPatternAllowSet()); + + this.changeSet = new AtomicReference<>(new TBoxChanges()); + this.suspended = new AtomicBoolean(); } public Suspension suspend() { @@ -167,7 +176,8 @@ public class ConfiguredReasonerListener implements ModelChangedListener { if (event instanceof EditEvent) { EditEvent ee = (EditEvent) event; if (!ee.getBegin()) { - this.reasonerDriver.runSynchronizer(); + TBoxChanges changes = changeSet.getAndSet(new TBoxChanges()); + this.reasonerDriver.runSynchronizer(changes); } } } @@ -310,19 +320,19 @@ public class ConfiguredReasonerListener implements ModelChangedListener { } private void addIt(Statement stmt) { - this.reasonerDriver.addStatement(stmt); + changeSet.get().addStatement(stmt); } private void removeIt(Statement stmt) { - this.reasonerDriver.removeStatement(stmt); + changeSet.get().removeStatement(stmt); } private void deleteObjectProperty(Statement stmt) { - this.reasonerDriver.deleteObjectProperty(stmt); + changeSet.get().deleteObjectProperty(stmt); } private void deleteDataProperty(Statement stmt) { - this.reasonerDriver.deleteDataProperty(stmt); + changeSet.get().deleteDataProperty(stmt); } // The pattern matching stuff needs to get reworked. diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxChanges.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxChanges.java index 11c6d1b87..efe79d917 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxChanges.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxChanges.java @@ -22,6 +22,7 @@ public class TBoxChanges { private final List deletedDataPropertyUris = Collections .synchronizedList(new ArrayList()); + private final List deletedObjectPropertyUris = Collections .synchronizedList(new ArrayList()); @@ -53,8 +54,8 @@ public class TBoxChanges { } // ---------------------------------------------------------------------- - // These methods are called when processing the changeSet. By then, it is - // owned and accessed by a single thread. + // These methods are called when processing the changeSet. By that time, it + // is owned and accessed by a single thread. // ---------------------------------------------------------------------- public boolean isEmpty() { 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 4ad552966..5412d0ed3 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java @@ -2,22 +2,14 @@ package edu.cornell.mannlib.vitro.webapp.tboxreasoner; -import com.hp.hpl.jena.rdf.model.Statement; /** * What calls can the ConfiguredReasonerListener make to drive the TBox * reasoner? */ public interface TBoxReasonerDriver { - void runSynchronizer(); - void addStatement(Statement stmt); - - void removeStatement(Statement stmt); - - void deleteDataProperty(Statement stmt); - - void deleteObjectProperty(Statement stmt); + void runSynchronizer(TBoxChanges changeSet); boolean isReasoning(); @@ -55,5 +47,4 @@ public interface TBoxReasonerDriver { } } - } From 3d65a708b77e0795b44aa59942b5686e7ce4cd62 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Wed, 3 Dec 2014 10:44:28 -0500 Subject: [PATCH 09/10] VIVO-778 Some renaming and moving. --- .../controller/jena/JenaAdminActions.java | 4 ++-- .../servlet/setup/PelletReasonerSetup.java | 6 +++--- .../tboxreasoner/BasicTBoxReasonerDriver.java | 4 ++-- .../InferenceModelUpdater.java | 8 ++++---- .../PatternListBuilder.java | 8 ++++---- ...ReasonerWrapper.java => TBoxReasoner.java} | 20 +++++++++++-------- ...nerDriver.java => PelletTBoxReasoner.java} | 8 ++++---- 7 files changed, 31 insertions(+), 27 deletions(-) rename webapp/src/edu/cornell/mannlib/vitro/webapp/{dao/jena/pellet => tboxreasoner}/InferenceModelUpdater.java (95%) rename webapp/src/edu/cornell/mannlib/vitro/webapp/{dao/jena/pellet => tboxreasoner}/PatternListBuilder.java (93%) rename webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/{TBoxReasonerWrapper.java => TBoxReasoner.java} (81%) rename webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/{PelletTBoxReasonerDriver.java => PelletTBoxReasoner.java} (94%) 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 7d3034394..a5eff2069 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,7 +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; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner; public class JenaAdminActions extends BaseEditController { @@ -191,7 +191,7 @@ public class JenaAdminActions extends BaseEditController { } private void printRestrictions() { - TBoxReasonerWrapper reasoner = (TBoxReasonerWrapper) getServletContext().getAttribute("tboxReasonerWrapper"); + TBoxReasoner reasoner = (TBoxReasoner) getServletContext().getAttribute("tboxReasonerWrapper"); for (Restriction rest : reasoner.listRestrictions() ) { //System.out.println(); if (rest.isAllValuesFromRestriction()) { 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 c434bb3e5..c3c7e6ce8 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 @@ -24,8 +24,8 @@ 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; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.pellet.PelletTBoxReasoner; /** * Start the Pellet reasoner on the TBox. @@ -46,7 +46,7 @@ public class PelletReasonerSetup implements ServletContextListener { OntModel tboxUnionModel = contextModels.getOntModel(TBOX_UNION); WebappDaoFactory wadf = contextModels.getWebappDaoFactory(); - TBoxReasonerWrapper reasoner = new PelletTBoxReasonerDriver( + TBoxReasoner reasoner = new PelletTBoxReasoner( ReasonerConfiguration.DEFAULT); TBoxReasonerDriver driver = new BasicTBoxReasonerDriver( tboxAssertionsModel, tboxInferencesModel, tboxUnionModel, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java index f02c54758..131670bbc 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java @@ -41,12 +41,12 @@ public class BasicTBoxReasonerDriver implements TBoxReasonerDriver { private final ExecutorService executorService; - private final TBoxReasonerWrapper reasoner; + private final TBoxReasoner reasoner; private TBoxReasonerDriver.Status status; public BasicTBoxReasonerDriver(OntModel assertionsModel, - Model inferencesModel, OntModel fullModel, TBoxReasonerWrapper reasoner, + Model inferencesModel, OntModel fullModel, TBoxReasoner reasoner, ReasonerConfiguration reasonerConfiguration) { this.lockableAssertionsModel = new LockableOntModel(assertionsModel); this.lockableInferencesModel = new LockableModel(inferencesModel); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/InferenceModelUpdater.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/InferenceModelUpdater.java similarity index 95% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/InferenceModelUpdater.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/InferenceModelUpdater.java index 095a1841c..9f54173fe 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/InferenceModelUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/InferenceModelUpdater.java @@ -1,6 +1,6 @@ /* $This file is distributed under the terms of the license in /doc/license.txt$ */ -package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet; +package edu.cornell.mannlib.vitro.webapp.tboxreasoner; import java.util.List; @@ -14,7 +14,7 @@ import com.hp.hpl.jena.rdf.model.Statement; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener.Suspension; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern; -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerWrapper; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner; import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableModel; import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableOntModel; import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedModel; @@ -28,7 +28,7 @@ public class InferenceModelUpdater { private static final Log log = LogFactory .getLog(InferenceModelUpdater.class); - private final TBoxReasonerWrapper reasoner; + private final TBoxReasoner reasoner; private final LockableModel lockableInferencesModel; private final LockableOntModel lockableFullModel; private final ConfiguredReasonerListener listener; @@ -44,7 +44,7 @@ public class InferenceModelUpdater { return retractCount; } - public InferenceModelUpdater(TBoxReasonerWrapper reasoner, + public InferenceModelUpdater(TBoxReasoner reasoner, LockableModel lockableInferencesModel, LockableOntModel lockableFullModel, ConfiguredReasonerListener listener) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PatternListBuilder.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/PatternListBuilder.java similarity index 93% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PatternListBuilder.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/PatternListBuilder.java index 544e16339..97574caaf 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PatternListBuilder.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/PatternListBuilder.java @@ -1,6 +1,6 @@ /* $This file is distributed under the terms of the license in /doc/license.txt$ */ -package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet; +package edu.cornell.mannlib.vitro.webapp.tboxreasoner; import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty; @@ -13,7 +13,7 @@ import com.hp.hpl.jena.ontology.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxChanges; -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerWrapper; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner; /** * The list of patterns for filtering the models will include: @@ -27,11 +27,11 @@ public class PatternListBuilder { private static final String OWL_NS = "http://www.w3.org/2002/07/owl#"; private final ReasonerConfiguration reasonerConfiguration; - private final TBoxReasonerWrapper reasoner; + private final TBoxReasoner reasoner; private final TBoxChanges changes; public PatternListBuilder(ReasonerConfiguration reasonerConfiguration, - TBoxReasonerWrapper reasoner, TBoxChanges changes) { + TBoxReasoner reasoner, TBoxChanges changes) { this.reasonerConfiguration = reasonerConfiguration; this.reasoner = reasoner; this.changes = changes; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerWrapper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasoner.java similarity index 81% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerWrapper.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasoner.java index 929937eaa..2c9de054f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerWrapper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasoner.java @@ -12,9 +12,13 @@ import com.hp.hpl.jena.rdf.model.Statement; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver.Status; /** - * TODO + * The functionality of a TBox reasoner. + * + * The reasoner will maintain its own TBox model. It will receive updates to + * that model and perform reasoning on it. It will answer queries about the + * contents of the model, when reasoning is complete. */ -public interface TBoxReasonerWrapper { +public interface TBoxReasoner { /** * Add the additions and remove the removals. @@ -38,16 +42,16 @@ public interface TBoxReasonerWrapper { */ List listDatatypeProperties(); + /** + * List all of the restrictions in the reasoner model, after updating and + * reasoning. + */ + List listRestrictions(); + /** * 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/PelletTBoxReasoner.java similarity index 94% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerDriver.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasoner.java index 7e235e763..e6167e199 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerDriver.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasoner.java @@ -23,20 +23,20 @@ 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.tboxreasoner.TBoxReasoner; import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableOntModel; import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedOntModel; /** * An implementation the TBoxReasonerWrapper for Pellet. */ -public class PelletTBoxReasonerDriver implements TBoxReasonerWrapper { +public class PelletTBoxReasoner implements TBoxReasoner { private static final Log log = LogFactory - .getLog(PelletTBoxReasonerDriver.class); + .getLog(PelletTBoxReasoner.class); private final LockableOntModel lockablePelletModel; - public PelletTBoxReasonerDriver(ReasonerConfiguration reasonerConfiguration) { + public PelletTBoxReasoner(ReasonerConfiguration reasonerConfiguration) { this.lockablePelletModel = new LockableOntModel( ModelFactory.createOntologyModel(reasonerConfiguration .getOntModelSpec())); From fb97bae6af8b9f8d7d9219cc9911157dde3bc176 Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Wed, 3 Dec 2014 16:35:56 -0500 Subject: [PATCH 10/10] VIVO-778 Connect the plumbing properly. Make TBoxReasonerModule a module on the Application. Make the reasoner status available through the module. Initialize it in startup_listeners.txt Create a concrete class for PelletTBoxReasonerModule, and configure it in applicationSetup.n3 Get rid of PelletReasonerSetup. Make it so the ExecutorService in BasicTBoxReasonerDriver uses a VitroBackgroundThread., --- .../webapp/application/ApplicationImpl.java | 48 ++++ .../freemarker/BaseSiteAdminController.java | 31 +-- .../controller/jena/JenaAdminActions.java | 6 +- .../webapp/dao/jena/DataPropertyDaoJena.java | 9 +- .../webapp/dao/jena/WebappDaoFactoryJena.java | 15 -- .../fields/IndividualsViaVClassOptions.java | 19 +- .../vitro/webapp/modules/Application.java | 3 + .../tboxreasoner/TBoxReasonerModule.java | 29 ++ .../tboxreasoner/TBoxReasonerStatus.java | 29 ++ .../servlet/setup/PelletReasonerSetup.java | 95 ------- .../servlet/setup/UpdateKnowledgeBase.java | 6 +- .../tboxreasoner/BasicTBoxReasonerDriver.java | 135 ---------- .../tboxreasoner/InferenceModelUpdater.java | 4 +- .../webapp/tboxreasoner/TBoxReasoner.java | 34 ++- .../tboxreasoner/TBoxReasonerDriver.java | 39 +-- .../impl/BasicTBoxReasonerDriver.java | 253 ++++++++++++++++++ .../impl/pellet/PelletTBoxReasoner.java | 1 - .../impl/pellet/PelletTBoxReasonerModule.java | 102 +++++++ .../utils/threads/VitroBackgroundThread.java | 23 ++ .../vitro/webapp/modules/ApplicationStub.java | 8 + .../WEB-INF/resources/startup_listeners.txt | 2 +- 21 files changed, 565 insertions(+), 326 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tboxreasoner/TBoxReasonerModule.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tboxreasoner/TBoxReasonerStatus.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/BasicTBoxReasonerDriver.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerModule.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java index 544340e00..45842830f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/application/ApplicationImpl.java @@ -16,6 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus; import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage; import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine; +import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule; import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource; import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; @@ -41,6 +42,7 @@ public class ApplicationImpl implements Application { private FileStorage fileStorage; private ContentTripleSource contentTripleSource; private ConfigurationTripleSource configurationTripleSource; + private TBoxReasonerModule tboxReasonerModule; public void setServletContext(ServletContext ctx) { this.ctx = ctx; @@ -140,6 +142,22 @@ public class ApplicationImpl implements Application { } } + @Override + public TBoxReasonerModule getTBoxReasonerModule() { + return tboxReasonerModule; + } + + @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTBoxReasonerModule") + public void setTBoxReasonerModule(TBoxReasonerModule module) { + if (tboxReasonerModule == null) { + tboxReasonerModule = module; + } else { + throw new IllegalStateException( + "Configuration includes multiple intances of TBoxReasonerModule: " + + tboxReasonerModule + ", and " + module); + } + } + @Validation public void validate() throws Exception { if (searchEngine == null) { @@ -162,6 +180,10 @@ public class ApplicationImpl implements Application { throw new IllegalStateException( "Configuration did not include a ConfigurationTripleSource."); } + if (tboxReasonerModule == null) { + throw new IllegalStateException( + "Configuration did not include a TBoxReasonerModule."); + } } @Override @@ -244,4 +266,30 @@ public class ApplicationImpl implements Application { } } + // ---------------------------------------------------------------------- + // Setup the reasoners. + // + // This must happen after the FileGraphSetup. + // ---------------------------------------------------------------------- + + public static class ReasonersSetup implements ServletContextListener { + @Override + public void contextInitialized(ServletContextEvent sce) { + ServletContext ctx = sce.getServletContext(); + Application app = ApplicationUtils.instance(); + StartupStatus ss = StartupStatus.getBean(ctx); + ComponentStartupStatus css = new ComponentStartupStatusImpl(this, + ss); + + TBoxReasonerModule tboxReasoner = app.getTBoxReasonerModule(); + tboxReasoner.startup(app, css); + ss.info(this, "Started the TBoxReasonerModule: " + tboxReasoner); + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + Application app = ApplicationUtils.instance(); + app.getTBoxReasonerModule().shutdown(app); + } + } } 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 09d423428..9ac27834c 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 @@ -15,6 +15,7 @@ import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vedit.beans.Option; import edu.cornell.mannlib.vedit.util.FormUtils; +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest; @@ -24,10 +25,9 @@ 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.modules.tboxreasoner.TBoxReasonerStatus; 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 { @@ -160,24 +160,21 @@ public class BaseSiteAdminController extends FreemarkerHttpServlet { if (PolicyHelper.isAuthorizedForActions(vreq, SimplePermission.EDIT_ONTOLOGY.ACTION)) { - String pelletError = null; - String pelletExplanation = null; - Object tbrObj = getServletContext().getAttribute("tboxReasoner"); - if ( tbrObj instanceof TBoxReasonerDriver) { - Status status = ((TBoxReasonerDriver) tbrObj).getStatus(); - if (!status.isConsistent()) { - pelletError = "INCONSISTENT ONTOLOGY: reasoning halted."; - pelletExplanation = status.getExplanation(); - } else if ( status.isInErrorState() ) { - pelletError = "An error occurred during reasoning. Reasoning has been halted. See error log for details."; - } + String error = null; + String explanation = null; + TBoxReasonerStatus status = ApplicationUtils.instance().getTBoxReasonerModule().getStatus(); + if (!status.isConsistent()) { + error = "INCONSISTENT ONTOLOGY: reasoning halted."; + explanation = status.getExplanation(); + } else if ( status.isInErrorState() ) { + error = "An error occurred during reasoning. Reasoning has been halted. See error log for details."; } - if (pelletError != null) { + if (error != null) { Map pellet = new HashMap(); - pellet.put("error", pelletError); - if (pelletExplanation != null) { - pellet.put("explanation", pelletExplanation); + pellet.put("error", error); + if (explanation != null) { + pellet.put("explanation", explanation); } map.put("pellet", pellet); } 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 a5eff2069..65e164714 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 @@ -44,11 +44,12 @@ import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; import edu.cornell.mannlib.vedit.controller.BaseEditController; +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner; +import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule; public class JenaAdminActions extends BaseEditController { @@ -191,9 +192,8 @@ public class JenaAdminActions extends BaseEditController { } private void printRestrictions() { - TBoxReasoner reasoner = (TBoxReasoner) getServletContext().getAttribute("tboxReasonerWrapper"); + TBoxReasonerModule reasoner = ApplicationUtils.instance().getTBoxReasonerModule(); for (Restriction rest : reasoner.listRestrictions() ) { - //System.out.println(); if (rest.isAllValuesFromRestriction()) { log.trace("All values from: "); AllValuesFromRestriction avfr = rest.asAllValuesFromRestriction(); 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 d2c185086..5afeca4d8 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 @@ -41,6 +41,7 @@ import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean; import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; @@ -51,8 +52,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.modules.tboxreasoner.TBoxReasonerStatus; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver; public class DataPropertyDaoJena extends PropertyDaoJena implements DataPropertyDao { @@ -357,10 +358,8 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements } protected boolean reasoningAvailable() { - TBoxReasonerDriver pl = getWebappDaoFactory().getTBoxReasonerDriver(); - return !( - ( pl == null || !pl.getStatus().isConsistent() || pl.getStatus().isInErrorState() ) - ); + TBoxReasonerStatus status = ApplicationUtils.instance().getTBoxReasonerModule().getStatus(); + return status.isConsistent() && !status.isInErrorState(); } private String getRequiredDatatypeURI(Individual individual, DataProperty dataprop, List vclassURIs) { 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 db38709e3..4114c7fbd 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 @@ -50,7 +50,6 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactoryConfig; 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,8 +69,6 @@ public class WebappDaoFactoryJena implements WebappDaoFactory { protected WebappDaoFactoryConfig config; - protected TBoxReasonerDriver tbrd; - protected String userURI; private Map properties = new HashMap(); @@ -238,18 +235,6 @@ public class WebappDaoFactoryJena implements WebappDaoFactory { return config.getNonUserNamespaces(); } - /** - * This enables the WebappDaoFactory to check the status of a reasoner. - * This will likely be refactored in future releases. - */ - public void setTBoxReasonerDriver(TBoxReasonerDriver tbrd) { - this.tbrd = tbrd; - } - - public TBoxReasonerDriver getTBoxReasonerDriver() { - return this.tbrd; - } - @Override public List getCommentsForResource(String resourceURI) { List commentList = new LinkedList(); 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 15ae28fa4..a245f9a59 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 @@ -8,12 +8,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; -import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver; +import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerStatus; public class IndividualsViaVClassOptions implements FieldOptions { @@ -101,20 +101,13 @@ public class IndividualsViaVClassOptions implements FieldOptions { return individualMap; } - protected boolean isReasoningAvailable( WebappDaoFactory wDaoFact){ - boolean inferenceAvailable = false; - if (wDaoFact instanceof WebappDaoFactoryJena) { - TBoxReasonerDriver pl = ((WebappDaoFactoryJena) wDaoFact).getTBoxReasonerDriver(); - if (pl != null && pl.getStatus().isConsistent() && !pl.getStatus().isInErrorState() - && !pl.isReasoning()) { - inferenceAvailable = true; - } - } - return inferenceAvailable; + protected boolean isReasoningAvailable(){ + TBoxReasonerStatus status = ApplicationUtils.instance().getTBoxReasonerModule().getStatus(); + return status.isConsistent() && !status.isInErrorState(); } protected Map addWhenMissingInference( String classUri , WebappDaoFactory wDaoFact ){ - boolean inferenceAvailable = isReasoningAvailable(wDaoFact); + boolean inferenceAvailable = isReasoningAvailable(); Map individualMap = new HashMap(); if ( !inferenceAvailable ) { for (String subclassURI : wDaoFact.getVClassDao().getAllSubClassURIs(classUri)) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/Application.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/Application.java index 2708634f3..7d875f707 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/Application.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/Application.java @@ -8,6 +8,7 @@ import edu.cornell.mannlib.vitro.webapp.application.VitroHomeDirectory; import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage; import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine; +import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule; import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource; import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource; @@ -29,6 +30,8 @@ public interface Application { ConfigurationTripleSource getConfigurationTripleSource(); + TBoxReasonerModule getTBoxReasonerModule(); + void shutdown(); public interface Component { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tboxreasoner/TBoxReasonerModule.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tboxreasoner/TBoxReasonerModule.java new file mode 100644 index 000000000..3110d9960 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tboxreasoner/TBoxReasonerModule.java @@ -0,0 +1,29 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner; + +import java.util.List; + +import com.hp.hpl.jena.ontology.Restriction; + +import edu.cornell.mannlib.vitro.webapp.modules.Application; + +/** + * A wrapper around the TBox reasoner + */ +public interface TBoxReasonerModule extends Application.Module { + /** + * What is the TBox reasoner doing now? + */ + TBoxReasonerStatus getStatus(); + + /** + * What restrictions are currently in the reasoner's internal model? + */ + List listRestrictions(); + + /** + * Wait until the TBox reasoner becomes quiet. + */ + void waitForTBoxReasoning(); +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tboxreasoner/TBoxReasonerStatus.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tboxreasoner/TBoxReasonerStatus.java new file mode 100644 index 000000000..d799ff8f9 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/modules/tboxreasoner/TBoxReasonerStatus.java @@ -0,0 +1,29 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner; + +/** + * What is the current state of the TBox reasoner? + */ +public interface TBoxReasonerStatus { + /** + * Is reasoning in progress based on changes to the TBox? + */ + boolean isReasoning(); + + /** + * Is the TBox free of inconsistency? + */ + boolean isConsistent(); + + /** + * Did the reasoner fail in its most recent attempt? + */ + boolean isInErrorState(); + + /** + * A description of the error state, or an empty string (never null). + */ + String getExplanation(); + +} 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 deleted file mode 100644 index c3c7e6ce8..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/PelletReasonerSetup.java +++ /dev/null @@ -1,95 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.servlet.setup; - -import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_ASSERTIONS; -import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_INFERENCES; -import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_UNION; - -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -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 edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; -import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena; -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.TBoxReasoner; -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.pellet.PelletTBoxReasoner; - -/** - * Start the Pellet reasoner on the TBox. - */ -public class PelletReasonerSetup implements ServletContextListener { - private static final Log log = LogFactory.getLog(PelletReasonerSetup.class); - - @Override - public void contextInitialized(ServletContextEvent sce) { - ServletContext ctx = sce.getServletContext(); - StartupStatus ss = StartupStatus.getBean(ctx); - - ContextModelAccess contextModels = ModelAccess.on(ctx); - OntModel tboxAssertionsModel = contextModels - .getOntModel(TBOX_ASSERTIONS); - Model tboxInferencesModel = contextModels - .getOntModel(TBOX_INFERENCES).getBaseModel(); - OntModel tboxUnionModel = contextModels.getOntModel(TBOX_UNION); - WebappDaoFactory wadf = contextModels.getWebappDaoFactory(); - - TBoxReasoner reasoner = new PelletTBoxReasoner( - ReasonerConfiguration.DEFAULT); - 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).setTBoxReasonerDriver(driver); - } - - ss.info(this, "Pellet reasoner connected for the TBox"); - - waitForTBoxReasoning(sce); - } - - public static void waitForTBoxReasoning(ServletContextEvent sce) { - 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) && driver.isReasoning())) { - if (((sleeps - 1) % 10) == 0) { // print message at 10 second - // intervals - log.info("Waiting for initial TBox reasoning to complete"); - } - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // This should never happen. - e.printStackTrace(); - } - sleeps++; - } - } - - @Override - public void contextDestroyed(ServletContextEvent sce) { - // Nothing to tear down - } - -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java index 92a4e81e5..3419300d6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java @@ -89,7 +89,11 @@ public class UpdateKnowledgeBase implements ServletContextListener { putReportingPathsIntoSettings(ctx, settings); putNonReportingPathsIntoSettings(ctx, settings); - PelletReasonerSetup.waitForTBoxReasoning(sce); + try { + ApplicationUtils.instance().getTBoxReasonerModule().waitForTBoxReasoning(); + } catch (Exception e) { + // Should mean that the reasoner is not even started yet. + } WebappDaoFactory wadf = ModelAccess.on(ctx).getWebappDaoFactory(); settings.setDefaultNamespace(wadf.getDefaultNamespace()); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java deleted file mode 100644 index 131670bbc..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/BasicTBoxReasonerDriver.java +++ /dev/null @@ -1,135 +0,0 @@ -/* $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 org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.hp.hpl.jena.ontology.OntModel; -import com.hp.hpl.jena.rdf.model.Model; -import com.hp.hpl.jena.rdf.model.RDFNode; -import com.hp.hpl.jena.rdf.model.Resource; - -import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; -import edu.cornell.mannlib.vitro.webapp.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 Set pendingChangeSets; - - private final ExecutorService executorService; - - private final TBoxReasoner reasoner; - - private TBoxReasonerDriver.Status status; - - public BasicTBoxReasonerDriver(OntModel assertionsModel, - Model inferencesModel, OntModel fullModel, TBoxReasoner reasoner, - ReasonerConfiguration reasonerConfiguration) { - this.lockableAssertionsModel = new LockableOntModel(assertionsModel); - this.lockableInferencesModel = new LockableModel(inferencesModel); - this.lockableFullModel = new LockableOntModel(fullModel); - this.reasoner = reasoner; - this.reasonerConfiguration = reasonerConfiguration; - - this.listener = new ConfiguredReasonerListener(reasonerConfiguration, - this); - - this.pendingChangeSets = Collections.synchronizedSet(new HashSet()); - - 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 runSynchronizer(TBoxChanges changeSet) { - if (!changeSet.isEmpty()) { - executorService.execute(new ReasoningTask(changeSet)); - } - } - - 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/InferenceModelUpdater.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/InferenceModelUpdater.java index 9f54173fe..1fcfaaabe 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/InferenceModelUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/InferenceModelUpdater.java @@ -67,7 +67,7 @@ public class InferenceModelUpdater { addNewInferences(filteredReasonerModel); removeOldInferences(filterInferencesModel(patternList), filteredReasonerModel); - log.warn("Added: " + addCount + ", Retracted: " + retractCount); + log.debug("Added: " + addCount + ", Retracted: " + retractCount); } private void addNewInferences(List filteredReasonerModel) { @@ -96,7 +96,7 @@ public class InferenceModelUpdater { filtered.add(pattern.matchStatementsFromModel(inferencesModel)); } } - log.warn("Filtered inferences model: " + filtered.size()); + log.debug("Filtered inferences model: " + filtered.size()); return filtered; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasoner.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasoner.java index 2c9de054f..5839193ca 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasoner.java @@ -9,8 +9,6 @@ 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; - /** * The functionality of a TBox reasoner. * @@ -53,5 +51,37 @@ public interface TBoxReasoner { * updating and reasoning. */ List filterResults(List patternList); + + public static class Status { + public static final Status SUCCESS = new Status(true, false, ""); + public static final Status ERROR = new Status(true, true, ""); + + public static final Status inconsistent(String explanation) { + return new Status(false, false, explanation); + } + + private final boolean consistent; + private final boolean inErrorState; + private final String explanation; + + private Status(boolean consistent, boolean inErrorState, + String explanation) { + this.consistent = consistent; + this.inErrorState = inErrorState; + this.explanation = explanation; + } + + public boolean isConsistent() { + return consistent; + } + + public boolean isInErrorState() { + return inErrorState; + } + + public String getExplanation() { + return explanation; + } + } } 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 5412d0ed3..edd3da3a9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/TBoxReasonerDriver.java @@ -2,6 +2,8 @@ package edu.cornell.mannlib.vitro.webapp.tboxreasoner; +import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerStatus; + /** * What calls can the ConfiguredReasonerListener make to drive the TBox @@ -11,40 +13,5 @@ public interface TBoxReasonerDriver { void runSynchronizer(TBoxChanges changeSet); - boolean isReasoning(); - - Status getStatus(); - - public static class Status { - public static final Status SUCCESS = new Status(true, false, ""); - public static final Status ERROR = new Status(true, true, ""); - - public static final Status inconsistent(String explanation) { - return new Status(false, false, explanation); - } - - private final boolean consistent; - private final boolean inErrorState; - private final String explanation; - - private Status(boolean consistent, boolean inErrorState, - String explanation) { - this.consistent = consistent; - this.inErrorState = inErrorState; - this.explanation = explanation; - } - - public boolean isConsistent() { - return consistent; - } - - public boolean isInErrorState() { - return inErrorState; - } - - public String getExplanation() { - return explanation; - } - - } + TBoxReasonerStatus getStatus(); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/BasicTBoxReasonerDriver.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/BasicTBoxReasonerDriver.java new file mode 100644 index 000000000..9ffe21cb5 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/BasicTBoxReasonerDriver.java @@ -0,0 +1,253 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl; + +import static edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread.WorkLevel.IDLE; +import static edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread.WorkLevel.WORKING; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.rdf.model.Resource; + +import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; +import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerStatus; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.InferenceModelUpdater; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.PatternListBuilder; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxChanges; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner.Status; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver; +import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableModel; +import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableOntModel; +import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedOntModel; +import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; + +/** + * The basic implementation of the TBoxReasonerDriver. It gets help from a + * listener, an executor, and a reasoner. + * + * Create a listener that listens for changes to the TBox, but filters them + * according to a ReasonerConfiguration object. The listener accumulates the + * changes it likes, until it detects an ending EditEvent. Then it passes the + * change set back to the driver. + * + * Each time a change set is received, a task is created and given to the + * executor to run. The executor is single-threaded, so the change sets are + * processed in sequence. + * + * Processing involves the following steps: + * + * 1. Telling the reasoner about the changes, so it can update its own internal + * ontology model. + * + * 2. Telling the reasoner to re-inference its model. A status is returned. + * + * 3. Asking the reasoner for the inferences from its model. As with the initial + * changes, these inferences are filtered according to the + * ReasonerConfiguration. + * + * 4. Synchronizing the applications TBox inferences model with the inferences + * obtained from the reasoner. + * + * ---------------------- + * + * Possible optimization: if change sets come in quickly enough that the third + * set is received while the first is still being processed, it would be + * reasonable to merge the second and third sets into one. + */ +public class BasicTBoxReasonerDriver implements TBoxReasonerDriver { + private static final Log log = LogFactory + .getLog(BasicTBoxReasonerDriver.class); + + private final LockableOntModel lockableAssertionsModel; + private final LockableModel lockableInferencesModel; + private final LockableOntModel lockableFullModel; + + private final ReasonerConfiguration reasonerConfiguration; + + private final ConfiguredReasonerListener listener; + + private final Set pendingChangeSets; + + private final ExecutorService executorService; + + private final TBoxReasoner reasoner; + + private TBoxReasoner.Status innerStatus; + + public BasicTBoxReasonerDriver(OntModel assertionsModel, + Model inferencesModel, OntModel fullModel, TBoxReasoner reasoner, + ReasonerConfiguration reasonerConfiguration) { + this.lockableAssertionsModel = new LockableOntModel(assertionsModel); + this.lockableInferencesModel = new LockableModel(inferencesModel); + this.lockableFullModel = new LockableOntModel(fullModel); + this.reasoner = reasoner; + this.reasonerConfiguration = reasonerConfiguration; + + this.listener = new ConfiguredReasonerListener(reasonerConfiguration, + this); + + this.pendingChangeSets = Collections + .synchronizedSet(new HashSet()); + + this.executorService = Executors.newFixedThreadPool(1, + new VitroBackgroundThread.Factory("TBoxReasoner")); + + assertionsModel.getBaseModel().register(listener); + fullModel.getBaseModel().register(listener); + + doInitialReasoning(); + } + + private void doInitialReasoning() { + try (LockedOntModel assertionsModel = lockableAssertionsModel.read()) { + for (ReasonerStatementPattern pat : reasonerConfiguration + .getInferenceDrivingPatternAllowSet()) { + listener.addedStatements(assertionsModel.listStatements( + (Resource) null, pat.getPredicate(), (RDFNode) null)); + } + } + listener.notifyEvent(null, new EditEvent(null, false)); + } + + @Override + public TBoxReasonerStatus getStatus() { + return new FullStatus(innerStatus, !pendingChangeSets.isEmpty()); + } + + @Override + public void runSynchronizer(TBoxChanges changeSet) { + if (!changeSet.isEmpty()) { + executorService.execute(new ReasoningTask(changeSet)); + } + } + + /** + * Shut down the thread that runs the reasoning tasks. Don't wait longer + * than 1 minute. + */ + public void shutdown() { + executorService.shutdown(); + int waited = 0; + while (waited < 60 && !executorService.isTerminated()) { + try { + log.info("Waiting for TBox reasoner to terminate."); + executorService.awaitTermination(5, TimeUnit.SECONDS); + waited += 5; + } catch (InterruptedException e) { + // Should never happen. + e.printStackTrace(); + break; + } + } + if (!executorService.isTerminated()) { + log.warn("Forcing TBox reasoner to terminate."); + executorService.shutdownNow(); + } + if (!executorService.isTerminated()) { + log.error("TBox reasoner did not terminate."); + } + } + + private class ReasoningTask implements Runnable { + private final TBoxChanges changes; + private List patternList; + + public ReasoningTask(TBoxChanges changes) { + this.changes = changes; + pendingChangeSets.add(changes); + } + + @Override + public void run() { + try { + setWorking(); + + reasoner.updateReasonerModel(changes); + innerStatus = reasoner.performReasoning(); + + buildPatternList(); + updateInferencesModel(); + + setIdle(); + } finally { + pendingChangeSets.remove(changes); + } + } + + private void setWorking() { + Thread current = Thread.currentThread(); + if (current instanceof VitroBackgroundThread) { + ((VitroBackgroundThread) current).setWorkLevel(WORKING); + } + } + + private void setIdle() { + Thread current = Thread.currentThread(); + if (current instanceof VitroBackgroundThread) { + ((VitroBackgroundThread) current).setWorkLevel(IDLE); + } + } + + private void buildPatternList() { + PatternListBuilder patternListBuilder = new PatternListBuilder( + reasonerConfiguration, reasoner, changes); + this.patternList = patternListBuilder.build(); + } + + private void updateInferencesModel() { + InferenceModelUpdater inferenceModelUpdater = new InferenceModelUpdater( + reasoner, lockableInferencesModel, lockableFullModel, + listener); + inferenceModelUpdater.update(patternList); + } + } + + private static class FullStatus implements TBoxReasonerStatus { + private final TBoxReasoner.Status reasonerStatus; + private final boolean reasoning; + + public FullStatus(Status reasonerStatus, boolean reasoning) { + this.reasonerStatus = reasonerStatus; + this.reasoning = reasoning; + } + + @Override + public boolean isReasoning() { + return reasoning; + } + + @Override + public boolean isConsistent() { + return reasonerStatus.isConsistent(); + } + + @Override + public boolean isInErrorState() { + return reasonerStatus.isInErrorState(); + } + + @Override + public String getExplanation() { + String explanation = reasonerStatus.getExplanation(); + return explanation == null ? "" : explanation; + } + + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasoner.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasoner.java index e6167e199..72b2ed49f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasoner.java @@ -22,7 +22,6 @@ 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.TBoxReasoner; import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableOntModel; import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedOntModel; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerModule.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerModule.java new file mode 100644 index 000000000..e04c7c54d --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerModule.java @@ -0,0 +1,102 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.pellet; + +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_ASSERTIONS; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_INFERENCES; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_UNION; + +import java.util.List; + +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.ontology.Restriction; +import com.hp.hpl.jena.rdf.model.Model; + +import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; +import edu.cornell.mannlib.vitro.webapp.modules.Application; +import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus; +import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule; +import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerStatus; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.BasicTBoxReasonerDriver; + +/** + * Configure a Pellet reasoner on the TBox. + */ +public class PelletTBoxReasonerModule implements TBoxReasonerModule { + private static final Log log = LogFactory + .getLog(PelletTBoxReasonerModule.class); + + private PelletTBoxReasoner reasoner; + private BasicTBoxReasonerDriver driver; + + @Override + public void startup(Application application, ComponentStartupStatus ss) { + ServletContext ctx = application.getServletContext(); + + ContextModelAccess contextModels = ModelAccess.on(ctx); + OntModel tboxAssertionsModel = contextModels + .getOntModel(TBOX_ASSERTIONS); + Model tboxInferencesModel = contextModels.getOntModel(TBOX_INFERENCES) + .getBaseModel(); + OntModel tboxUnionModel = contextModels.getOntModel(TBOX_UNION); + + reasoner = new PelletTBoxReasoner(ReasonerConfiguration.DEFAULT); + driver = new BasicTBoxReasonerDriver(tboxAssertionsModel, + tboxInferencesModel, tboxUnionModel, reasoner, + ReasonerConfiguration.DEFAULT); + + ss.info("Pellet reasoner connected for the TBox"); + + waitForTBoxReasoning(); + } + + @Override + public TBoxReasonerStatus getStatus() { + if (driver == null) { + throw new IllegalStateException( + "PelletTBoxReasonerModule has not been started."); + } + return driver.getStatus(); + } + + @Override + public List listRestrictions() { + if (reasoner == null) { + throw new IllegalStateException( + "PelletTBoxReasonerModule has not been started."); + } + return reasoner.listRestrictions(); + } + + @Override + public void shutdown(Application application) { + driver.shutdown(); + } + + @Override + public void waitForTBoxReasoning() { + int sleeps = 0; + // sleep at least once to make sure the TBox reasoning gets started + while ((0 == sleeps) + || ((sleeps < 1000) && getStatus().isReasoning())) { + if (((sleeps - 1) % 10) == 0) { // print message at 10 second + // intervals + log.info("Waiting for initial TBox reasoning to complete"); + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // This should never happen. + e.printStackTrace(); + } + sleeps++; + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/threads/VitroBackgroundThread.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/threads/VitroBackgroundThread.java index 47780558f..437b8d48d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/threads/VitroBackgroundThread.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/threads/VitroBackgroundThread.java @@ -10,6 +10,8 @@ import java.util.Collections; import java.util.Date; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -106,4 +108,25 @@ public class VitroBackgroundThread extends Thread { return flags; } } + + /** + * A factory class, for use in Executors, that creates threads with + * successive names. + */ + public static class Factory implements ThreadFactory{ + private final String threadName; + private final AtomicInteger index; + + public Factory(String threadName) { + this.threadName = threadName; + this.index = new AtomicInteger(); + } + + @Override + public Thread newThread(Runnable r) { + return new VitroBackgroundThread(r, threadName + "_" + index.getAndIncrement()); + } + + } + } diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/modules/ApplicationStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/modules/ApplicationStub.java index f5aeaf92f..b8534649c 100644 --- a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/modules/ApplicationStub.java +++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/modules/ApplicationStub.java @@ -12,6 +12,7 @@ import edu.cornell.mannlib.vitro.webapp.modules.Application; import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage; import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine; +import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule; import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource; import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource; @@ -101,4 +102,11 @@ public class ApplicationStub implements Application { "ApplicationStub.getConfigurationTripleSource() not implemented."); } + @Override + public TBoxReasonerModule getTBoxReasonerModule() { + // TODO Auto-generated method stub + throw new RuntimeException("ApplicationStub.getTBoxReasonerModule() not implemented."); + + } + } diff --git a/webapp/web/WEB-INF/resources/startup_listeners.txt b/webapp/web/WEB-INF/resources/startup_listeners.txt index 02a1f48fd..9c3fc7a42 100644 --- a/webapp/web/WEB-INF/resources/startup_listeners.txt +++ b/webapp/web/WEB-INF/resources/startup_listeners.txt @@ -34,7 +34,7 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.RemoveObsoletePermissions edu.cornell.mannlib.vitro.webapp.servlet.setup.FileGraphSetup -edu.cornell.mannlib.vitro.webapp.servlet.setup.PelletListenerSetup +edu.cornell.mannlib.vitro.webapp.application.ApplicationImpl$ReasonersSetup edu.cornell.mannlib.vitro.webapp.servlet.setup.SimpleReasonerSetup #edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdateKnowledgeBase