diff --git a/webapp/config/log4j.properties b/webapp/config/log4j.properties index 241df5716..82c16fea8 100644 --- a/webapp/config/log4j.properties +++ b/webapp/config/log4j.properties @@ -35,7 +35,8 @@ log4j.rootLogger=INFO, AllAppender # These classes are too chatty to display INFO messages. log4j.logger.edu.cornell.mannlib.vitro.webapp.startup.StartupStatus=WARN -log4j.logger.edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdateKnowledgeBase=DEBUG +log4j.logger.edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdateKnowledgeBase=WARN +log4j.logger.org.semanticweb.owlapi.rdf.rdfxml.parser.OWLRDFConsumer=WARN # Spring as a whole is too chatty to display INFO messages. log4j.logger.org.springframework=WARN diff --git a/webapp/lib/commons-io-2.0.1.jar b/webapp/lib/commons-io-2.0.1.jar deleted file mode 100644 index 5b64b7d6c..000000000 Binary files a/webapp/lib/commons-io-2.0.1.jar and /dev/null differ diff --git a/webapp/lib/commons-io-2.4.jar b/webapp/lib/commons-io-2.4.jar new file mode 100644 index 000000000..90035a4fe Binary files /dev/null and b/webapp/lib/commons-io-2.4.jar differ diff --git a/webapp/lib/jfact-4.0.0.jar b/webapp/lib/jfact-4.0.0.jar new file mode 100644 index 000000000..331b02bf6 Binary files /dev/null and b/webapp/lib/jfact-4.0.0.jar differ diff --git a/webapp/lib/owlapi-distribution-4.0.1.jar b/webapp/lib/owlapi-distribution-4.0.1.jar new file mode 100644 index 000000000..a3f9c2882 Binary files /dev/null and b/webapp/lib/owlapi-distribution-4.0.1.jar differ 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 1fcfaaabe..04fda0a6e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/InferenceModelUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/InferenceModelUpdater.java @@ -62,11 +62,11 @@ public class InferenceModelUpdater { * to the inferences model. */ public void update(List patternList) { - List filteredReasonerModel = reasoner + List filteredReasonerStatements = reasoner .filterResults(patternList); - addNewInferences(filteredReasonerModel); + addNewInferences(filteredReasonerStatements); removeOldInferences(filterInferencesModel(patternList), - filteredReasonerModel); + filteredReasonerStatements); log.debug("Added: " + addCount + ", Retracted: " + retractCount); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/TBoxInferencesAccumulator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/TBoxInferencesAccumulator.java new file mode 100644 index 000000000..d2009280e --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/TBoxInferencesAccumulator.java @@ -0,0 +1,340 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl; + +import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty; +import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.semanticweb.owlapi.model.OWLClass; +import org.semanticweb.owlapi.model.OWLDataProperty; +import org.semanticweb.owlapi.model.OWLNamedObject; +import org.semanticweb.owlapi.model.OWLObjectProperty; +import org.semanticweb.owlapi.model.OWLObjectPropertyExpression; +import org.semanticweb.owlapi.reasoner.OWLReasoner; + +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.Resource; + +/** + * Build a model of inferred statements by walking through the ontology as + * represented in the reasoner. + * + * TODO Get rid of the kluges. Either decide that they are not necessary, or + * give them full status. + */ +public class TBoxInferencesAccumulator { + private static final Log log = LogFactory + .getLog(TBoxInferencesAccumulator.class); + + private static final Property RDFS_TYPE = createProperty("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); + private static final Resource OWL_CLASS = createResource("http://www.w3.org/2002/07/owl#Class"); + private static final Property OWL_EQUIVALENT_CLASS = createProperty("http://www.w3.org/2002/07/owl#equivalentClass"); + private static final Property OWL_DISJOINT_WITH = createProperty("http://www.w3.org/2002/07/owl#disjointWith"); + private static final Property OWL_SUBCLASS_OF = createProperty("http://www.w3.org/2000/01/rdf-schema#subClassOf"); + private static final Property OWL_SUBPROPERTY_OF = createProperty("http://www.w3.org/2000/01/rdf-schema#subPropertyOf"); + private static final Property OWL_INVERSE_OF = createProperty("http://www.w3.org/2002/07/owl#inverseOf"); + + public Model populateModelFromReasonerQueries(OWLReasoner reasoner) { + Model m = ModelFactory.createDefaultModel(); + populateClasses(reasoner, m); + populateObjectProperties(reasoner, m); + populateDataProperties(reasoner, m); + klugeOwlInvariants(m); + klugeMistakes(m); + return m; + } + + private void populateClasses(OWLReasoner r, Model m) { + OWLClass bottom = r.getBottomClassNode().getRepresentativeElement(); + for (OWLClass c : r.getSuperClasses(bottom, false).getFlattened()) { + populateClass(c, r, m); + } + } + + private void populateClass(OWLClass c, OWLReasoner r, Model m) { + log.debug("Owl class: " + c); + populateClassType(c, m); + populateEquivalentClasses(c, r, m); + populateDisjointClasses(c, r, m); + populateSubClasses(c, r, m); + } + + private void populateClassType(OWLClass c, Model m) { + log.debug(c + " is a class."); + m.add(toResource(c), RDFS_TYPE, OWL_CLASS); + } + + private void populateEquivalentClasses(OWLClass c, OWLReasoner r, Model m) { + for (OWLClass equiv : r.getEquivalentClasses(c).getEntities()) { + log.debug("Equivalent class: " + c + ", " + equiv); + m.add(toResource(c), OWL_EQUIVALENT_CLASS, toResource(equiv)); + } + } + + private void populateDisjointClasses(OWLClass c, OWLReasoner r, Model m) { + for (OWLClass d : r.getDisjointClasses(c).getFlattened()) { + if (!d.isOWLNothing()) { + log.debug("Disjoint class: " + c + ", " + d); + m.add(toResource(c), OWL_DISJOINT_WITH, toResource(d)); + } + } + } + + private void populateSubClasses(OWLClass c, OWLReasoner r, Model m) { + for (OWLClass sub : r.getSubClasses(c, false).getFlattened()) { + log.debug(sub + " is subclass of " + c); + if (!sub.isOWLNothing()) { + m.add(toResource(sub), OWL_SUBCLASS_OF, toResource(c)); + } + } + } + + private void populateObjectProperties(OWLReasoner r, Model m) { + OWLObjectPropertyExpression bottom = r.getBottomObjectPropertyNode() + .getRepresentativeElement(); + populateObjectProperty(bottom, r, m); + for (OWLObjectPropertyExpression op : r.getSuperObjectProperties( + bottom, false).getFlattened()) { + populateObjectProperty(op, r, m); + } + } + + private void populateObjectProperty(OWLObjectPropertyExpression ope, + OWLReasoner r, Model m) { + if (!ope.isAnonymous()) { + OWLObjectProperty op = ope.asOWLObjectProperty(); + log.debug("object property: " + op); + populateObjectSubProperties(op, r, m); + populateObjectInverseProperties(op, r, m); + } + } + + private void populateObjectSubProperties(OWLObjectProperty op, + OWLReasoner r, Model m) { + for (OWLObjectPropertyExpression subOPE : r.getSubObjectProperties(op, + false).getFlattened()) { + if (!subOPE.isAnonymous()) { + OWLObjectProperty subOP = subOPE.asOWLObjectProperty(); + log.debug(subOP + " object sub-property of " + op); + m.add(toResource(subOP), OWL_SUBPROPERTY_OF, toResource(op)); + } + } + // getSubObjectProperties is strict, so add the reflexive statement. + log.debug(op + " object sub-property of " + op); + m.add(toResource(op), OWL_SUBPROPERTY_OF, toResource(op)); + } + + private void populateObjectInverseProperties(OWLObjectProperty op, + OWLReasoner r, Model m) { + for (OWLObjectPropertyExpression inverseE : r + .getInverseObjectProperties(op)) { + if (!inverseE.isAnonymous() + && !inverseE.isOWLBottomObjectProperty() + && !inverseE.isOWLTopObjectProperty()) { + OWLObjectProperty inverse = inverseE.asOWLObjectProperty(); + log.debug(inverse + " object inverse of " + op); + m.add(toResource(inverse), OWL_INVERSE_OF, toResource(op)); + } + } + } + + private void populateDataProperties(OWLReasoner r, Model m) { + OWLDataProperty bottom = r.getBottomDataPropertyNode() + .getRepresentativeElement(); + populateDataProperty(bottom, r, m); + for (OWLDataProperty dp : r.getSuperDataProperties(bottom, false) + .getFlattened()) { + populateDataProperty(dp, r, m); + } + } + + private void populateDataProperty(OWLDataProperty dp, OWLReasoner r, Model m) { + log.debug("data property: " + dp); + populateDataSubProperties(dp, r, m); + } + + private void populateDataSubProperties(OWLDataProperty dp, OWLReasoner r, + Model m) { + for (OWLDataProperty subDP : r.getSubDataProperties(dp, false) + .getFlattened()) { + log.debug(subDP + " data sub-property of " + dp); + m.add(toResource(subDP), OWL_SUBPROPERTY_OF, toResource(dp)); + } + // getSubDataProperties is strict, so add the reflexive statement. + log.debug(dp + " data sub-property of " + dp); + m.add(toResource(dp), OWL_SUBPROPERTY_OF, toResource(dp)); + } + + private Resource toResource(OWLNamedObject owlObject) { + return createResource(owlObject.getIRI().toString()); + } + + private static final Resource OWL_THING = createResource("http://www.w3.org/2002/07/owl#Thing"); + + private static final Resource OWL_OBJECT_PROPERTY = createResource("http://www.w3.org/2002/07/owl#ObjectProperty"); + private static final Resource OWL_TOP_OBJECT_PROPERTY = createResource("http://www.w3.org/2002/07/owl#topObjectProperty"); + private static final Resource OWL_BOTTOM_OBJECT_PROPERTY = createResource("http://www.w3.org/2002/07/owl#bottomObjectProperty"); + private static final Resource OWL_DATA_PROPERTY = createResource("http://www.w3.org/2002/07/owl#DatatypeProperty"); + private static final Resource OWL_TOP_DATA_PROPERTY = createResource("http://www.w3.org/2002/07/owl#topDataProperty"); + private static final Resource OWL_BOTTOM_DATA_PROPERTY = createResource("http://www.w3.org/2002/07/owl#bottomDataProperty"); + private static final Resource OWL_FUNCTIONAL_PROPERTY = createResource("http://www.w3.org/2002/07/owl#FunctionalProperty"); + private static final Resource OWL_INVERSE_FUNCTIONAL_PROPERTY = createResource("http://www.w3.org/2002/07/owl#InverseFunctionalProperty"); + private static final Resource OWL_TRANSITIVE_PROPERTY = createResource("http://www.w3.org/2002/07/owl#TransitiveProperty"); + private static final Resource OWL_SYMMETRIC_PROPERTY = createResource("http://www.w3.org/2002/07/owl#SymmetricProperty"); + private static final Resource OWL_ASYMMETRIC_PROPERTY = createResource("http://www.w3.org/2002/07/owl#AsymmetricProperty"); + private static final Resource OWL_REFLEXIVE_PROPERTY = createResource("http://www.w3.org/2002/07/owl#ReflexiveProperty"); + private static final Resource OWL_IRREFLEXIVE_PROPERTY = createResource("http://www.w3.org/2002/07/owl#IrreflexiveProperty"); + private static final Resource OWL_ANNOTATION_PROPERTY = createResource("http://www.w3.org/2002/07/owl#AnnotationProperty"); + + private static final Resource OWL_VERSION_INFO = createResource("http://www.w3.org/2002/07/owl#versionInfo"); + private static final Resource OWL_BACKWARD_COMPATIBLE_WITH = createResource("http://www.w3.org/2002/07/owl#backwardCompatibleWith"); + private static final Resource OWL_INCOMPATIBLE_WITH = createResource("http://www.w3.org/2002/07/owl#incompatibleWith"); + private static final Resource OWL_PRIOR_VERSION = createResource("http://www.w3.org/2002/07/owl#priorVersion"); + + private static final Resource RDFS_SEE_ALSO = createResource("http://www.w3.org/2000/01/rdf-schema#seeAlso"); + private static final Resource RDFS_COMMENT = createResource("http://www.w3.org/2000/01/rdf-schema#comment"); + private static final Resource RDFS_IS_DEFINED_BY = createResource("http://www.w3.org/2000/01/rdf-schema#isDefinedBy"); + private static final Resource RDFS_LABEL = createResource("http://www.w3.org/2000/01/rdf-schema#label"); + + private void klugeOwlInvariants(Model m) { + m.add(OWL_BOTTOM_DATA_PROPERTY, RDFS_TYPE, OWL_DATA_PROPERTY); + m.add(OWL_BOTTOM_DATA_PROPERTY, RDFS_TYPE, OWL_FUNCTIONAL_PROPERTY); + + m.add(OWL_TOP_DATA_PROPERTY, RDFS_TYPE, OWL_DATA_PROPERTY); + + m.add(OWL_BOTTOM_OBJECT_PROPERTY, RDFS_TYPE, OWL_OBJECT_PROPERTY); + m.add(OWL_BOTTOM_OBJECT_PROPERTY, RDFS_TYPE, OWL_FUNCTIONAL_PROPERTY); + m.add(OWL_BOTTOM_OBJECT_PROPERTY, RDFS_TYPE, + OWL_INVERSE_FUNCTIONAL_PROPERTY); + m.add(OWL_BOTTOM_OBJECT_PROPERTY, RDFS_TYPE, OWL_TRANSITIVE_PROPERTY); + m.add(OWL_BOTTOM_OBJECT_PROPERTY, RDFS_TYPE, OWL_SYMMETRIC_PROPERTY); + m.add(OWL_BOTTOM_OBJECT_PROPERTY, RDFS_TYPE, OWL_ASYMMETRIC_PROPERTY); + m.add(OWL_BOTTOM_OBJECT_PROPERTY, RDFS_TYPE, OWL_IRREFLEXIVE_PROPERTY); + + m.add(OWL_TOP_OBJECT_PROPERTY, RDFS_TYPE, OWL_OBJECT_PROPERTY); + m.add(OWL_TOP_OBJECT_PROPERTY, RDFS_TYPE, OWL_TRANSITIVE_PROPERTY); + m.add(OWL_TOP_OBJECT_PROPERTY, RDFS_TYPE, OWL_REFLEXIVE_PROPERTY); + m.add(OWL_TOP_OBJECT_PROPERTY, RDFS_TYPE, OWL_SYMMETRIC_PROPERTY); + + m.add(OWL_THING, RDFS_TYPE, OWL_CLASS); + + m.add(OWL_VERSION_INFO, RDFS_TYPE, OWL_ANNOTATION_PROPERTY); + m.add(OWL_BACKWARD_COMPATIBLE_WITH, RDFS_TYPE, OWL_ANNOTATION_PROPERTY); + m.add(OWL_PRIOR_VERSION, RDFS_TYPE, OWL_ANNOTATION_PROPERTY); + m.add(OWL_INCOMPATIBLE_WITH, RDFS_TYPE, OWL_ANNOTATION_PROPERTY); + m.add(RDFS_SEE_ALSO, RDFS_TYPE, OWL_ANNOTATION_PROPERTY); + m.add(RDFS_COMMENT, RDFS_TYPE, OWL_ANNOTATION_PROPERTY); + m.add(RDFS_IS_DEFINED_BY, RDFS_TYPE, OWL_ANNOTATION_PROPERTY); + m.add(RDFS_LABEL, RDFS_TYPE, OWL_ANNOTATION_PROPERTY); + } + + private void klugeMistakes(Model m) { + Property ISF_DEPRECATED = createProperty("http://isf/deprecated_op"); + m.add(ISF_DEPRECATED, RDFS_TYPE, OWL_OBJECT_PROPERTY); + m.add(ISF_DEPRECATED, OWL_SUBPROPERTY_OF, ISF_DEPRECATED); + m.add(ISF_DEPRECATED, OWL_SUBPROPERTY_OF, OWL_TOP_OBJECT_PROPERTY); + m.add(OWL_BOTTOM_OBJECT_PROPERTY, OWL_SUBPROPERTY_OF, ISF_DEPRECATED); + + Resource OWL_DEPRECATED = createResource("http://www.w3.org/2002/07/owl#DeprecatedProperty"); + m.add(OWL_DEPRECATED, RDFS_TYPE, OWL_OBJECT_PROPERTY); + m.add(OWL_DEPRECATED, OWL_SUBPROPERTY_OF, OWL_DEPRECATED); + m.add(OWL_DEPRECATED, OWL_SUBPROPERTY_OF, OWL_TOP_OBJECT_PROPERTY); + m.add(OWL_BOTTOM_OBJECT_PROPERTY, OWL_SUBPROPERTY_OF, OWL_DEPRECATED); + + Property DCT_CONTRIBUTOR = createProperty("http://purl.org/dc/terms/contributor"); + m.add(DCT_CONTRIBUTOR, RDFS_TYPE, OWL_OBJECT_PROPERTY); + m.add(DCT_CONTRIBUTOR, OWL_SUBPROPERTY_OF, DCT_CONTRIBUTOR); + m.add(DCT_CONTRIBUTOR, OWL_SUBPROPERTY_OF, OWL_TOP_OBJECT_PROPERTY); + m.add(OWL_BOTTOM_OBJECT_PROPERTY, OWL_SUBPROPERTY_OF, DCT_CONTRIBUTOR); + + Resource ARG_2000400 = createResource("http://purl.obolibrary.org/obo/ARG_2000400"); + Resource BFO_0000001 = createResource("http://purl.obolibrary.org/obo/BFO_0000001"); + Resource BFO_0000002 = createResource("http://purl.obolibrary.org/obo/BFO_0000002"); + Resource BFO_0000031 = createResource("http://purl.obolibrary.org/obo/BFO_0000031"); + Resource IAO_0000003 = createResource("http://purl.obolibrary.org/obo/IAO_0000003"); + Resource IAO_0000009 = createResource("http://purl.obolibrary.org/obo/IAO_0000009"); + Resource IAO_0000030 = createResource("http://purl.obolibrary.org/obo/IAO_0000030"); + m.add(ARG_2000400, RDFS_TYPE, BFO_0000001); + m.add(ARG_2000400, RDFS_TYPE, BFO_0000002); + m.add(ARG_2000400, RDFS_TYPE, BFO_0000031); + m.add(ARG_2000400, RDFS_TYPE, IAO_0000003); + m.add(ARG_2000400, RDFS_TYPE, IAO_0000009); + m.add(ARG_2000400, RDFS_TYPE, IAO_0000030); + m.add(ARG_2000400, RDFS_TYPE, OWL_THING); + + Resource BIBO_ACCEPTED = createResource("http://purl.org/ontology/bibo/accepted"); + Resource BIBO_DRAFT = createResource("http://purl.org/ontology/bibo/draft"); + Resource BIBO_PEER_REVIEWED = createResource("http://purl.org/ontology/bibo/peerReviewed"); + Resource BIBO_PUBLISHED = createResource("http://purl.org/ontology/bibo/published"); + Resource BIBO_REJECTED = createResource("http://purl.org/ontology/bibo/rejected"); + Resource BIBO_UNPUBLISHED = createResource("http://purl.org/ontology/bibo/unpublished"); + m.add(BIBO_ACCEPTED, RDFS_TYPE, OWL_THING); + m.add(BIBO_DRAFT, RDFS_TYPE, OWL_THING); + m.add(BIBO_PEER_REVIEWED, RDFS_TYPE, OWL_THING); + m.add(BIBO_PUBLISHED, RDFS_TYPE, OWL_THING); + m.add(BIBO_REJECTED, RDFS_TYPE, OWL_THING); + m.add(BIBO_UNPUBLISHED, RDFS_TYPE, OWL_THING); + + Resource CORE_YMDT_PRECISION = createResource("http://vivoweb.org/ontology/core#yearMonthDayTimePrecision"); + Resource CORE_YMD_PRECISION = createResource("http://vivoweb.org/ontology/core#yearMonthDayPrecision"); + Resource CORE_YM_PRECISION = createResource("http://vivoweb.org/ontology/core#yearMonthPrecision"); + Resource CORE_Y_PRECISION = createResource("http://vivoweb.org/ontology/core#yearPrecision"); + Resource SKOS_CONCEPT = createResource("http://www.w3.org/2004/02/skos/core#Concept"); + m.add(CORE_YMDT_PRECISION, RDFS_TYPE, OWL_THING); + m.add(CORE_YMDT_PRECISION, RDFS_TYPE, SKOS_CONCEPT); + m.add(CORE_YMD_PRECISION, RDFS_TYPE, OWL_THING); + m.add(CORE_YMD_PRECISION, RDFS_TYPE, SKOS_CONCEPT); + m.add(CORE_YM_PRECISION, RDFS_TYPE, OWL_THING); + m.add(CORE_YM_PRECISION, RDFS_TYPE, SKOS_CONCEPT); + m.add(CORE_Y_PRECISION, RDFS_TYPE, OWL_THING); + m.add(CORE_Y_PRECISION, RDFS_TYPE, SKOS_CONCEPT); + + Resource CORE_CONTACT_INFO = createResource("http://vivoweb.org/ontology/core#contactInformation"); + m.add(CORE_CONTACT_INFO, RDFS_TYPE, OWL_DATA_PROPERTY); + + Resource CORE_HAS_FACILITY = createResource("http://vivoweb.org/ontology/core#hasFacility"); + m.add(CORE_HAS_FACILITY, RDFS_TYPE, OWL_OBJECT_PROPERTY); + + Resource CORE_HAS_FUNDING = createResource("http://vivoweb.org/ontology/core#hasFundingVehicle"); + m.add(CORE_HAS_FUNDING, RDFS_TYPE, OWL_OBJECT_PROPERTY); + + Resource CORE_HAS_GOV_AUTH = createResource("http://vivoweb.org/ontology/core#hasGoverningAuthority"); + m.add(CORE_HAS_GOV_AUTH, RDFS_TYPE, OWL_OBJECT_PROPERTY); + + Resource CORE_IN_PRESS = createResource("http://vivoweb.org/ontology/core#inPress"); + m.add(CORE_IN_PRESS, RDFS_TYPE, OWL_THING); + + Resource CORE_INVITED = createResource("http://vivoweb.org/ontology/core#invited"); + m.add(CORE_INVITED, RDFS_TYPE, OWL_THING); + + Resource CORE_SUBMITTED = createResource("http://vivoweb.org/ontology/core#submitted"); + m.add(CORE_SUBMITTED, RDFS_TYPE, OWL_THING); + + Resource OBO_HAS_AGENT = createResource("http://www.obofoundry.org/ro/ro.owl#has_agent"); + m.add(OBO_HAS_AGENT, RDFS_TYPE, OWL_OBJECT_PROPERTY); + + Resource OBI_0000066 = createResource("http://purl.obolibrary.org/obo/OBI_0000066"); + m.remove(OBI_0000066, RDFS_TYPE, OWL_CLASS); + m.remove(OBI_0000066, OWL_SUBCLASS_OF, OWL_THING); + m.remove(OBI_0000066, OWL_EQUIVALENT_CLASS, OBI_0000066); + + Resource OBI_0000086 = createResource("http://purl.obolibrary.org/obo/OBI_0000086"); + m.remove(OBI_0000086, RDFS_TYPE, OWL_CLASS); + m.remove(OBI_0000086, OWL_SUBCLASS_OF, OWL_THING); + m.remove(OBI_0000086, OWL_EQUIVALENT_CLASS, OBI_0000086); + + Resource OBI_0000094 = createResource("http://purl.obolibrary.org/obo/OBI_0000094"); + m.remove(OBI_0000094, RDFS_TYPE, OWL_CLASS); + m.remove(OBI_0000094, OWL_SUBCLASS_OF, OWL_THING); + m.remove(OBI_0000094, OWL_EQUIVALENT_CLASS, OBI_0000094); + + Resource OBI_0000571 = createResource("http://purl.obolibrary.org/obo/OBI_0000571"); + m.remove(OBI_0000571, RDFS_TYPE, OWL_CLASS); + m.remove(OBI_0000571, OWL_SUBCLASS_OF, OWL_THING); + m.remove(OBI_0000571, OWL_EQUIVALENT_CLASS, OBI_0000571); + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/jfact/JFactTBoxReasoner.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/jfact/JFactTBoxReasoner.java new file mode 100644 index 000000000..9940e7c33 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/jfact/JFactTBoxReasoner.java @@ -0,0 +1,159 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.jfact; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.semanticweb.owlapi.apibinding.OWLManager; +import org.semanticweb.owlapi.model.OWLOntology; +import org.semanticweb.owlapi.model.OWLOntologyCreationException; +import org.semanticweb.owlapi.reasoner.InferenceType; +import org.semanticweb.owlapi.reasoner.OWLReasoner; +import org.semanticweb.owlapi.reasoner.OWLReasonerConfiguration; +import org.semanticweb.owlapi.reasoner.OWLReasonerFactory; +import org.semanticweb.owlapi.reasoner.SimpleConfiguration; + +import uk.ac.manchester.cs.jfact.JFactFactory; + +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.ontology.OntModelSpec; +import com.hp.hpl.jena.ontology.Restriction; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.Statement; + +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxChanges; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner; +import edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.TBoxInferencesAccumulator; + +/** + * An implementation of the JFact reasoner for the TBox. + * + * It maintains a model of all the assertions it has been given, adding or + * removing statements as change sets are received. + * + * Each time a change is received, it will create a fresh ontology from the + * assertions model, and apply a reasoner to that ontology. A model of + * inferences is built by querying the reasoner. + * + * The assertions and inferences are combined into an OntModel, which is kept to + * answer queries. + * + * ----------------- + * + * This class it not thread-safe. + */ +public class JFactTBoxReasoner implements + TBoxReasoner { + private static final Log log = LogFactory.getLog(JFactTBoxReasoner.class); + + private final OWLReasonerFactory reasonerFactory; + private final TBoxInferencesAccumulator accumulator; + + private final Model filteredAssertionsModel; + private final OntModel combinedInferencedModel; + + public JFactTBoxReasoner() { + this.filteredAssertionsModel = ModelFactory.createDefaultModel(); + this.combinedInferencedModel = ModelFactory + .createOntologyModel(OntModelSpec.OWL_MEM); + + this.reasonerFactory = new JFactFactory(); + this.accumulator = new TBoxInferencesAccumulator(); + } + + @Override + public void updateReasonerModel(TBoxChanges changes) { + log.debug("Adding " + changes.getAddedStatements().size() + + ", removing " + changes.getRemovedStatements().size()); + filteredAssertionsModel.add(changes.getAddedStatements()); + filteredAssertionsModel.remove(changes.getRemovedStatements()); + } + + @Override + public Status performReasoning() { + try { + OWLOntology ont = copyModelToOntology(filteredAssertionsModel); + + OWLReasoner reasoner = createReasoner(ont); + reasoner.precomputeInferences(InferenceType.values()); + + try { + if (!reasoner.isConsistent()) { + return Status.inconsistent("Reasoner axioms are not " + + "consistent"); + } + } catch (Exception e) { + log.error(e); + return Status.ERROR; + } + + Model inferences = accumulator.populateModelFromReasonerQueries(reasoner); + mergeModels(filteredAssertionsModel, inferences); + return Status.SUCCESS; + } catch (Exception e) { + log.error(e); + return Status.ERROR; + } + } + + private OWLOntology copyModelToOntology(Model m) + throws OWLOntologyCreationException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + m.write(out, "RDF/XML"); + + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + return OWLManager.createOWLOntologyManager() + .loadOntologyFromOntologyDocument(in); + } + + private OWLReasoner createReasoner(OWLOntology ont) { + OWLReasonerConfiguration config = new SimpleConfiguration(50000); + OWLReasoner reasoner = this.reasonerFactory.createReasoner(ont, config); + return reasoner; + } + + private void mergeModels(Model assertions, Model inferences) { + combinedInferencedModel.removeAll(); + combinedInferencedModel.add(assertions); + combinedInferencedModel.add(inferences); + log.debug("Assertions: " + assertions.size() + ", inferences: " + + inferences.size() + ", combined: " + + combinedInferencedModel.size()); + } + + @Override + public List listObjectProperties() { + return combinedInferencedModel.listObjectProperties().toList(); + } + + @Override + public List listDatatypeProperties() { + return combinedInferencedModel.listDatatypeProperties().toList(); + } + + @Override + public List listRestrictions() { + return combinedInferencedModel.listRestrictions().toList(); + } + + @Override + public List filterResults( + List patternList) { + List filtered = new ArrayList<>(); + for (ReasonerStatementPattern pattern : patternList) { + filtered.addAll(pattern + .matchStatementsFromModel(combinedInferencedModel)); + } + return filtered; + } + +} 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/jfact/JFactTBoxReasonerModule.java similarity index 68% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerModule.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/jfact/JFactTBoxReasonerModule.java index e04c7c54d..b69ca0095 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasonerModule.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/jfact/JFactTBoxReasonerModule.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.tboxreasoner.impl.pellet; +package edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.jfact; import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_ASSERTIONS; import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_INFERENCES; @@ -13,9 +13,7 @@ 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; @@ -27,13 +25,16 @@ import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration; import edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.BasicTBoxReasonerDriver; /** - * Configure a Pellet reasoner on the TBox. + * Configure a JFact reasoner on the TBox. + * + * Create a JFactTBoxReasoner and pass it as the strategy to a + * BasicTBoxReasonerDriver. */ -public class PelletTBoxReasonerModule implements TBoxReasonerModule { +public class JFactTBoxReasonerModule implements TBoxReasonerModule { private static final Log log = LogFactory - .getLog(PelletTBoxReasonerModule.class); + .getLog(JFactTBoxReasonerModule.class); - private PelletTBoxReasoner reasoner; + private JFactTBoxReasoner reasoner; private BasicTBoxReasonerDriver driver; @Override @@ -41,18 +42,14 @@ public class PelletTBoxReasonerModule implements TBoxReasonerModule { 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, + reasoner = new JFactTBoxReasoner(); + driver = new BasicTBoxReasonerDriver( + contextModels.getOntModel(TBOX_ASSERTIONS), contextModels + .getOntModel(TBOX_INFERENCES).getBaseModel(), + contextModels.getOntModel(TBOX_UNION), reasoner, ReasonerConfiguration.DEFAULT); - ss.info("Pellet reasoner connected for the TBox"); + ss.info("JFact reasoner connected for the TBox"); waitForTBoxReasoning(); } @@ -61,7 +58,7 @@ public class PelletTBoxReasonerModule implements TBoxReasonerModule { public TBoxReasonerStatus getStatus() { if (driver == null) { throw new IllegalStateException( - "PelletTBoxReasonerModule has not been started."); + "JFactTBoxReasonerModule has not been started."); } return driver.getStatus(); } @@ -70,22 +67,16 @@ public class PelletTBoxReasonerModule implements TBoxReasonerModule { public List listRestrictions() { if (reasoner == null) { throw new IllegalStateException( - "PelletTBoxReasonerModule has not been started."); + "JFactTBoxReasonerModule has not been started."); } return reasoner.listRestrictions(); } @Override - public void shutdown(Application application) { - driver.shutdown(); - } - - @Override - public void waitForTBoxReasoning() { + 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())) { + 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"); @@ -99,4 +90,9 @@ public class PelletTBoxReasonerModule implements TBoxReasonerModule { sleeps++; } } + + @Override + public void shutdown(Application application) { + driver.shutdown(); + } } 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 deleted file mode 100644 index 72b2ed49f..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/tboxreasoner/impl/pellet/PelletTBoxReasoner.java +++ /dev/null @@ -1,114 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.tboxreasoner.impl.pellet; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.mindswap.pellet.exceptions.InconsistentOntologyException; -import org.mindswap.pellet.jena.PelletInfGraph; - -import com.hp.hpl.jena.ontology.DatatypeProperty; -import com.hp.hpl.jena.ontology.ObjectProperty; -import com.hp.hpl.jena.ontology.Restriction; -import com.hp.hpl.jena.rdf.model.ModelFactory; -import com.hp.hpl.jena.rdf.model.Statement; -import com.hp.hpl.jena.vocabulary.OWL; -import com.hp.hpl.jena.vocabulary.RDFS; - -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration; -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern; -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxChanges; -import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasoner; -import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableOntModel; -import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedOntModel; - -/** - * An implementation the TBoxReasonerWrapper for Pellet. - */ -public class PelletTBoxReasoner implements TBoxReasoner { - private static final Log log = LogFactory - .getLog(PelletTBoxReasoner.class); - - private final LockableOntModel lockablePelletModel; - - public PelletTBoxReasoner(ReasonerConfiguration reasonerConfiguration) { - this.lockablePelletModel = new LockableOntModel( - ModelFactory.createOntologyModel(reasonerConfiguration - .getOntModelSpec())); - } - - @Override - public void updateReasonerModel(TBoxChanges changes) { - try (LockedOntModel pelletModel = lockablePelletModel.write()) { - pelletModel.remove(changes.getRemovedStatements()); - pelletModel.add(changes.getAddedStatements()); - } - } - - @Override - public Status performReasoning() { - try (LockedOntModel pelletModel = lockablePelletModel.write()) { - try { - pelletModel.rebind(); - pelletModel.prepare(); - return Status.SUCCESS; - } catch (InconsistentOntologyException ioe) { - String explanation = ((PelletInfGraph) pelletModel.getGraph()) - .getKB().getExplanation(); - log.error(ioe); - log.error(explanation); - return Status.inconsistent(explanation); - } catch (Exception e) { - log.error("Exception during inference", e); - return Status.ERROR; - } - } - } - - @Override - public List 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(); - } - } -}