From 6e8a4dfff16662ad3de88f67662f55af53855311 Mon Sep 17 00:00:00 2001 From: brianjlowe Date: Wed, 13 Jun 2012 17:19:46 +0000 Subject: [PATCH] merge changes from trunk to rdf api branch and fix issue with listeners notifying before triples are actually added/removed --- .../dao/jena/ABoxJenaChangeListener.java | 2 + .../webapp/dao/jena/DifferenceGraph.java | 2 + .../vitro/webapp/dao/jena/EmptyReifier.java | 2 + .../webapp/dao/jena/JenaChangeListener.java | 2 + .../webapp/dao/jena/RDFServiceDataset.java | 2 + .../dao/jena/RDFServiceDatasetGraph.java | 2 + .../webapp/dao/jena/RDFServiceGraph.java | 2 + .../dao/jena/RDFServiceGraphBulkUpdater.java | 4 +- .../vitro/webapp/dao/jena/SparqlDataset.java | 2 + .../webapp/dao/jena/SparqlDatasetGraph.java | 2 + .../vitro/webapp/dao/jena/SparqlGraph.java | 2 + .../dao/jena/SparqlGraphBulkUpdater.java | 2 + .../dao/jena/SparqlGraphMultilingual.java | 2 + .../filters/WebappDaoFactorySDBPrep.java | 6 +- .../webapp/rdfservice/RDFServiceFactory.java | 2 + .../impl/RDFServiceFactorySingle.java | 2 + .../rdfservice/impl/RDFServiceUtils.java | 2 + .../rdfservice/impl/sdb/ListeningGraph.java | 217 +++ .../impl/sdb/RDFServiceFactorySDB.java | 2 + .../rdfservice/impl/sdb/RDFServiceSDB.java | 74 +- .../vitro/webapp/reasoner/ReasonerPlugin.java | 3 + .../vitro/webapp/reasoner/SimpleReasoner.java | 1430 ++++++++--------- .../reasoner/SimpleReasonerTBoxListener.java | 2 + .../servlet/setup/SimpleReasonerSetup.java | 1 + .../SimpleReasonerInversePropertyTest.java | 201 ++- .../reasoner/SimpleReasonerSameAsTest.java | 353 +++- .../webapp/reasoner/SimpleReasonerTest.java | 422 +---- 27 files changed, 1429 insertions(+), 1316 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/ListeningGraph.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ABoxJenaChangeListener.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ABoxJenaChangeListener.java index 72042f39c..0d374f030 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ABoxJenaChangeListener.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ABoxJenaChangeListener.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.util.HashSet; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DifferenceGraph.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DifferenceGraph.java index 1eb6cd0b3..cd45a9795 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DifferenceGraph.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DifferenceGraph.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.util.Set; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/EmptyReifier.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/EmptyReifier.java index 089358914..064dce350 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/EmptyReifier.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/EmptyReifier.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.util.ArrayList; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaChangeListener.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaChangeListener.java index 0a4a69ac1..aaa1af321 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaChangeListener.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaChangeListener.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.io.ByteArrayInputStream; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDataset.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDataset.java index 2564a7822..61cd2b58c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDataset.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDataset.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.util.ArrayList; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDatasetGraph.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDatasetGraph.java index 49c68b934..ca0dfa80f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDatasetGraph.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceDatasetGraph.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.util.ArrayList; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java index 106da87e7..766b1bbf4 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.io.InputStream; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraphBulkUpdater.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraphBulkUpdater.java index 0b8f80622..9b6300fe4 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraphBulkUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraphBulkUpdater.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.io.ByteArrayInputStream; @@ -30,7 +32,7 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; public class RDFServiceGraphBulkUpdater extends SimpleBulkUpdateHandler { - private static final Log log = LogFactory.getLog(SparqlGraphBulkUpdater.class); + private static final Log log = LogFactory.getLog(RDFServiceGraphBulkUpdater.class); private RDFServiceGraph graph; public RDFServiceGraphBulkUpdater(RDFServiceGraph graph) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlDataset.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlDataset.java index 3fd3043c3..16ce9b326 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlDataset.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlDataset.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.util.ArrayList; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlDatasetGraph.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlDatasetGraph.java index ab6bedb88..7cd6f8822 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlDatasetGraph.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlDatasetGraph.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.util.ArrayList; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraph.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraph.java index 33dbd0fb2..d3988bc66 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraph.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraph.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.util.ArrayList; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraphBulkUpdater.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraphBulkUpdater.java index e4bd83c02..4c2e4c39a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraphBulkUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraphBulkUpdater.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.io.StringWriter; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraphMultilingual.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraphMultilingual.java index bd35548cb..1e6aeb9de 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraphMultilingual.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SparqlGraphMultilingual.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.util.ArrayList; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/WebappDaoFactorySDBPrep.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/WebappDaoFactorySDBPrep.java index 95cab9ee5..eafe98550 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/WebappDaoFactorySDBPrep.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/WebappDaoFactorySDBPrep.java @@ -35,6 +35,7 @@ import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactoryConfig; +import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext; import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector; import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset; import edu.cornell.mannlib.vitro.webapp.dao.jena.SparqlDataset; @@ -90,7 +91,8 @@ public class WebappDaoFactorySDBPrep implements Filter { } } - OntModelSelector oms = (OntModelSelector) _ctx.getAttribute("unionOntModelSelector"); + OntModelSelector oms = ModelContext.getUnionOntModelSelector(_ctx); + OntModelSelector baseOms = ModelContext.getBaseOntModelSelector(_ctx); String defaultNamespace = (String) _ctx.getAttribute("defaultNamespace"); WebappDaoFactory wadf = null; VitroRequest vreq = new VitroRequest((HttpServletRequest) request); @@ -112,7 +114,7 @@ public class WebappDaoFactorySDBPrep implements Filter { Dataset dataset = new RDFServiceDataset(rdfService); wadf = new WebappDaoFactorySDB(rdfService, oms, config); WebappDaoFactory assertions = new WebappDaoFactorySDB( - rdfService, oms, config, SDBDatasetMode.ASSERTIONS_ONLY); + rdfService, baseOms, config, SDBDatasetMode.ASSERTIONS_ONLY); vreq.setWebappDaoFactory(wadf); vreq.setAssertionsWebappDaoFactory(assertions); vreq.setFullWebappDaoFactory(wadf); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFServiceFactory.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFServiceFactory.java index dc2cca163..770b60a48 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFServiceFactory.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFServiceFactory.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.rdfservice; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceFactorySingle.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceFactorySingle.java index 2580100c9..f9f801f5a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceFactorySingle.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceFactorySingle.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.rdfservice.impl; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java index 71d0e79cc..10b6313f7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.rdfservice.impl; import java.io.ByteArrayInputStream; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/ListeningGraph.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/ListeningGraph.java new file mode 100644 index 000000000..2db8d1e64 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/ListeningGraph.java @@ -0,0 +1,217 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sdb; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.graph.BulkUpdateHandler; +import com.hp.hpl.jena.graph.Capabilities; +import com.hp.hpl.jena.graph.Graph; +import com.hp.hpl.jena.graph.GraphEventManager; +import com.hp.hpl.jena.graph.GraphStatisticsHandler; +import com.hp.hpl.jena.graph.Node; +import com.hp.hpl.jena.graph.Reifier; +import com.hp.hpl.jena.graph.TransactionHandler; +import com.hp.hpl.jena.graph.Triple; +import com.hp.hpl.jena.graph.TripleMatch; +import com.hp.hpl.jena.graph.impl.GraphWithPerform; +import com.hp.hpl.jena.graph.impl.SimpleBulkUpdateHandler; +import com.hp.hpl.jena.graph.impl.SimpleEventManager; +import com.hp.hpl.jena.graph.query.QueryHandler; +import com.hp.hpl.jena.graph.query.SimpleQueryHandler; +import com.hp.hpl.jena.shared.AddDeniedException; +import com.hp.hpl.jena.shared.DeleteDeniedException; +import com.hp.hpl.jena.shared.PrefixMapping; +import com.hp.hpl.jena.shared.impl.PrefixMappingImpl; +import com.hp.hpl.jena.util.iterator.ExtendedIterator; +import com.hp.hpl.jena.util.iterator.WrappedIterator; + +import edu.cornell.mannlib.vitro.webapp.dao.jena.EmptyReifier; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange; + +public class ListeningGraph implements GraphWithPerform { + + private static final Log log = LogFactory.getLog(ListeningGraph.class); + + private RDFServiceSDB rdfServiceSDB; + private String graphURI; + + private BulkUpdateHandler bulkUpdateHandler; + private GraphEventManager eventManager; + private PrefixMapping prefixMapping = new PrefixMappingImpl(); + private Reifier reifier = new EmptyReifier(this); + private QueryHandler queryHandler; + + public ListeningGraph(String graphURI, RDFServiceSDB rdfServiceSDB) { + this.graphURI = graphURI; + this.rdfServiceSDB = rdfServiceSDB; + } + + @Override + public void add(Triple triple) throws AddDeniedException { + performAdd(triple); + } + + @Override + public void performAdd(Triple triple) throws AddDeniedException { + this.rdfServiceSDB.notifyListeners(triple, ModelChange.Operation.ADD, graphURI); + } + + @Override + public void delete(Triple triple) throws DeleteDeniedException { + performDelete(triple); + } + + @Override + public void performDelete(Triple triple) throws DeleteDeniedException { + this.rdfServiceSDB.notifyListeners(triple, ModelChange.Operation.REMOVE, graphURI); + } + + @Override + public void close() { + } + + @Override + public boolean contains(Triple arg0) { + return contains(arg0.getSubject(), arg0.getPredicate(), arg0.getObject()); + } + + @Override + public boolean contains(Node subject, Node predicate, Node object) { + return false; + } + + @Override + public boolean dependsOn(Graph arg0) { + return false; // who knows? + } + + @Override + public ExtendedIterator find(TripleMatch arg0) { + Triple t = arg0.asTriple(); + return find(t.getSubject(), t.getPredicate(), t.getObject()); + } + + @Override + public ExtendedIterator find(Node subject, Node predicate, Node object) { + List triplist = new ArrayList(); + return WrappedIterator.create(triplist.iterator()); + } + + @Override + public BulkUpdateHandler getBulkUpdateHandler() { + if (this.bulkUpdateHandler == null) { + this.bulkUpdateHandler = new SimpleBulkUpdateHandler(this); + } + return this.bulkUpdateHandler; + } + + @Override + public Capabilities getCapabilities() { + return capabilities; + } + + @Override + public GraphEventManager getEventManager() { + if (eventManager == null) { + eventManager = new SimpleEventManager(this); + } + return eventManager; + } + + @Override + public PrefixMapping getPrefixMapping() { + return prefixMapping; + } + + @Override + public Reifier getReifier() { + return reifier; + } + + @Override + public GraphStatisticsHandler getStatisticsHandler() { + return null; + } + + @Override + public TransactionHandler getTransactionHandler() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isClosed() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isEmpty() { + return (size() == 0); + } + + @Override + public boolean isIsomorphicWith(Graph arg0) { + throw new UnsupportedOperationException("isIsomorphicWith() not supported " + + "by SPARQL graphs"); + } + + @Override + public QueryHandler queryHandler() { + if (queryHandler == null) { + queryHandler = new SimpleQueryHandler(this); + } + return queryHandler; + } + + @Override + public int size() { + int size = find(null, null, null).toList().size(); + return size; + } + + private final static Capabilities capabilities = new Capabilities() { + + public boolean addAllowed() { + return false; + } + + public boolean addAllowed(boolean everyTriple) { + return false; + } + + public boolean canBeEmpty() { + return true; + } + + public boolean deleteAllowed() { + return false; + } + + public boolean deleteAllowed(boolean everyTriple) { + return false; + } + + public boolean findContractSafe() { + return true; + } + + public boolean handlesLiteralTyping() { + return true; + } + + public boolean iteratorRemoveAllowed() { + return false; + } + + public boolean sizeAccurate() { + return true; + } + }; + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceFactorySDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceFactorySDB.java index 7c87359d9..c48fdcea1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceFactorySDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceFactorySDB.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sdb; import org.apache.commons.dbcp.BasicDataSource; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceSDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceSDB.java index 1c60855ee..c6042e809 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceSDB.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sdb/RDFServiceSDB.java @@ -1,3 +1,5 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sdb; import java.io.ByteArrayInputStream; @@ -35,6 +37,7 @@ import com.hp.hpl.jena.sdb.Store; import com.hp.hpl.jena.sdb.StoreDesc; import com.hp.hpl.jena.sdb.sql.SDBConnection; import com.hp.hpl.jena.shared.Lock; +import com.hp.hpl.jena.vocabulary.OWL; import edu.cornell.mannlib.vitro.webapp.dao.jena.DatasetWrapper; import edu.cornell.mannlib.vitro.webapp.dao.jena.SparqlGraph; @@ -82,9 +85,7 @@ public class RDFServiceSDB extends RDFServiceImpl implements RDFService { changeSet.getPreconditionQueryType())) { return false; } - - Iterator csIt = changeSet.getModelChanges().iterator(); - + SDBConnection conn = null; try { conn = new SDBConnection(bds.getConnection()); @@ -96,47 +97,47 @@ public class RDFServiceSDB extends RDFServiceImpl implements RDFService { Dataset dataset = getDataset(conn); boolean transaction = conn.getTransactionHandler().transactionsSupported(); - try { + try { + if (transaction) { conn.getTransactionHandler().begin(); - } else { - for (Object o : changeSet.getPreChangeEvents()) { - this.notifyListenersOfEvent(o); - } } + + for (Object o : changeSet.getPreChangeEvents()) { + this.notifyListenersOfEvent(o); + } + + Iterator csIt = changeSet.getModelChanges().iterator(); while (csIt.hasNext()) { ModelChange modelChange = csIt.next(); + modelChange.getSerializedModel().mark(Integer.MAX_VALUE); dataset.getLock().enterCriticalSection(Lock.WRITE); try { Model model = dataset.getNamedModel(modelChange.getGraphURI()); - model.enterCriticalSection(Lock.WRITE); - try { - model.register(new ModelListener(modelChange.getGraphURI(), this)); - if (modelChange.getOperation() == ModelChange.Operation.ADD) { - model.read(modelChange.getSerializedModel(), null, - getSerializationFormatString(modelChange.getSerializationFormat())); - } else if (modelChange.getOperation() == ModelChange.Operation.REMOVE) { - model.remove(parseModel(modelChange)); - removeBlankNodesWithSparqlUpdate(dataset, model, modelChange.getGraphURI()); - } else { - log.error("unrecognized operation type"); - } - } finally { - model.leaveCriticalSection(); - } + operateOnModel(model, modelChange, dataset); } finally { dataset.getLock().leaveCriticalSection(); } } + if (transaction) { - for (Object o : changeSet.getPreChangeEvents()) { - this.notifyListenersOfEvent(o); - } conn.getTransactionHandler().commit(); } + + // notify listeners of triple changes + csIt = changeSet.getModelChanges().iterator(); + while (csIt.hasNext()) { + ModelChange modelChange = csIt.next(); + modelChange.getSerializedModel().reset(); + Model model = ModelFactory.createModelForGraph( + new ListeningGraph(modelChange.getGraphURI(), this)); + operateOnModel(model, modelChange, null); + } + for (Object o : changeSet.getPostChangeEvents()) { this.notifyListenersOfEvent(o); } + } catch (Exception e) { log.error(e, e); if (transaction) { @@ -150,6 +151,25 @@ public class RDFServiceSDB extends RDFServiceImpl implements RDFService { return true; } + private void operateOnModel(Model model, ModelChange modelChange, Dataset dataset) { + model.enterCriticalSection(Lock.WRITE); + try { + if (modelChange.getOperation() == ModelChange.Operation.ADD) { + model.read(modelChange.getSerializedModel(), null, + getSerializationFormatString(modelChange.getSerializationFormat())); + } else if (modelChange.getOperation() == ModelChange.Operation.REMOVE) { + model.remove(parseModel(modelChange)); + if (dataset != null) { + removeBlankNodesWithSparqlUpdate(dataset, model, modelChange.getGraphURI()); + } + } else { + log.error("unrecognized operation type"); + } + } finally { + model.leaveCriticalSection(); + } + } + private void removeBlankNodesWithSparqlUpdate(Dataset dataset, Model model, String graphURI) { Model blankNodeModel = ModelFactory.createDefaultModel(); @@ -414,12 +434,10 @@ public class RDFServiceSDB extends RDFServiceImpl implements RDFService { } public void addedStatement(Statement stmt) { - log.debug("adding " + stmt + " to " + graphURI); s.notifyListeners(stmt.asTriple(), ModelChange.Operation.ADD, graphURI); } public void removedStatement(Statement stmt) { - log.debug("removing " + stmt + " from " + graphURI); s.notifyListeners(stmt.asTriple(), ModelChange.Operation.REMOVE, graphURI); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ReasonerPlugin.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ReasonerPlugin.java index 075b50d14..aa3ce9689 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ReasonerPlugin.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ReasonerPlugin.java @@ -22,4 +22,7 @@ public interface ReasonerPlugin { Model aboxInferencesModel, OntModel TBoxInferencesModel); + public void setSimpleReasoner(SimpleReasoner simpleReasoner); + + public SimpleReasoner getSimpleReasoner(); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java index 272e8c0bd..5df4d7271 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java @@ -65,16 +65,17 @@ public class SimpleReasoner extends StatementListener { private Model inferenceRebuildModel; // work area for re-computing all ABox inferences private Model scratchpadModel; // work area for re-computing all ABox inferences - private static final String mostSpecificTypePropertyURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType"; - - private AnnotationProperty mostSpecificType = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createAnnotationProperty(mostSpecificTypePropertyURI); + private static final String mostSpecificTypePropertyURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType"; + private static final AnnotationProperty mostSpecificType = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createAnnotationProperty(mostSpecificTypePropertyURI); + //TODO check this for thread safety private CumulativeDeltaModeler aBoxDeltaModeler1 = null; private CumulativeDeltaModeler aBoxDeltaModeler2 = null; private volatile boolean batchMode1 = false; private volatile boolean batchMode2 = false; private boolean stopRequested = false; + //TODO check this for thread safety private List pluginList = new ArrayList(); /** @@ -161,6 +162,7 @@ public class SimpleReasoner extends StatementListener { } catch (Exception e) { // don't stop the edit if there's an exception log.error("Exception while computing inferences: " + e.getMessage()); + e.printStackTrace(); //TODO remove this for release } } @@ -181,6 +183,7 @@ public class SimpleReasoner extends StatementListener { } catch (Exception e) { // don't stop the edit if there's an exception log.error("Exception while retracting inferences: ", e); + e.printStackTrace(); } } @@ -218,7 +221,7 @@ public class SimpleReasoner extends StatementListener { return; } - log.debug("added TBox assertion = " + stmt.toString()); + //log.debug("added TBox assertion = " + stmt.toString()); if ( stmt.getObject().isResource() && (stmt.getObject().asResource()).getURI() == null ) { log.warn("The object of this assertion has a null URI: " + stmtString(stmt)); @@ -288,7 +291,7 @@ public class SimpleReasoner extends StatementListener { return; } - log.debug("removed TBox assertion = " + stmt.toString()); + //log.debug("removed TBox assertion = " + stmt.toString()); if ( stmt.getObject().isResource() && (stmt.getObject().asResource()).getURI() == null ) { log.warn("The object of this assertion has a null URI: " + stmtString(stmt)); @@ -355,7 +358,6 @@ public class SimpleReasoner extends StatementListener { StmtIterator iter = null; aboxModel.enterCriticalSection(Lock.READ); - try { iter = aboxModel.listStatements(individual, RDF.type, (RDFNode) null); @@ -379,20 +381,18 @@ public class SimpleReasoner extends StatementListener { */ protected void addedABoxTypeAssertion(Statement stmt, Model inferenceModel, HashSet unknownTypes) { - tboxModel.enterCriticalSection(Lock.READ); + tboxModel.enterCriticalSection(Lock.READ); try { OntClass cls = null; if ( (stmt.getObject().asResource()).getURI() != null ) { cls = tboxModel.getOntClass(stmt.getObject().asResource().getURI()); if (cls != null) { - List parents = (cls.listSuperClasses(false)).toList(); parents.addAll((cls.listEquivalentClasses()).toList()); Iterator parentIt = parents.iterator(); if (parentIt.hasNext()) { - List sameIndividuals = getSameIndividuals(stmt.getSubject().asResource(), inferenceModel); while (parentIt.hasNext()) { OntClass parentClass = parentIt.next(); @@ -403,28 +403,7 @@ public class SimpleReasoner extends StatementListener { if (parentClass.isAnon()) continue; Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), RDF.type, parentClass); - aboxModel.enterCriticalSection(Lock.READ); - try { - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt)) { - inferenceModel.add(infStmt); - } - - Iterator sameIter = sameIndividuals.iterator(); - while (sameIter.hasNext()) { - Resource subject = sameIter.next(); - if (!inferenceModel.contains(subject,infStmt.getPredicate(),infStmt.getObject()) && !aboxModel.contains(subject,infStmt.getPredicate(),infStmt.getObject())) { - inferenceModel.add(subject,infStmt.getPredicate(),infStmt.getObject()); - } - } - - } finally { - inferenceModel.leaveCriticalSection(); - } - } finally { - aboxModel.leaveCriticalSection(); - } + addInference(infStmt,inferenceModel,true); } } } else { @@ -443,8 +422,75 @@ public class SimpleReasoner extends StatementListener { } finally { tboxModel.leaveCriticalSection(); } + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if (inferenceModel.contains(stmt)) { + inferenceModel.remove(stmt); + } + } finally { + inferenceModel.leaveCriticalSection(); + } } - + + /* + * If it is removed that B is of type A, then for each superclass of A remove + * the inferred statement that B is of that type UNLESS it is otherwise entailed + * that B is of that type. + * + */ + protected void removedABoxTypeAssertion(Statement stmt, Model inferenceModel) { + tboxModel.enterCriticalSection(Lock.READ); + try { + OntClass cls = null; + + if ( (stmt.getObject().asResource()).getURI() != null ) { + cls = tboxModel.getOntClass(stmt.getObject().asResource().getURI()); + + if (cls != null) { + if (entailedType(stmt.getSubject(),cls)) { + addInference(stmt,inferenceModel,true); + } + + List parents = null; + parents = (cls.listSuperClasses(false)).toList(); + parents.addAll((cls.listEquivalentClasses()).toList()); + + Iterator parentIt = parents.iterator(); + + while (parentIt.hasNext()) { + + OntClass parentClass = parentIt.next(); + + // VIVO doesn't materialize statements that assert anonymous types + // for individuals. Also, sharing an identical anonymous node is + // not allowed in owl-dl. picklist population code looks at qualities + // of classes not individuals. + if (parentClass.isAnon()) continue; + + if (entailedType(stmt.getSubject(),parentClass)) { + continue; // if a type is still entailed without the + } + // removed statement, then don't remove it + // from the inferences + + Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), RDF.type, parentClass); + removeInference(infStmt,inferenceModel,true,false); + } + } else { + log.warn("Didn't find target class (the object of the removed rdf:type statement) in the TBox: " + + ((Resource)stmt.getObject()).getURI() + ". No class subsumption reasoning will be performed based on the removal of this assertion."); + } + } else { + log.warn("The object of this rdf:type assertion has a null URI: " + stmtString(stmt)); + } + } catch (Exception e) { + log.warn("exception while removing abox type assertions: " + e.getMessage()); + } finally { + tboxModel.leaveCriticalSection(); + } + } + /* * Materializes inferences based on the owl:sameAs relationship. * @@ -452,7 +498,7 @@ public class SimpleReasoner extends StatementListener { * statements about x will become inferred about y if they are not already * asserted about y, and vice versa. */ - public void addedABoxSameAsAssertion(Statement stmt, Model inferenceModel) { + protected void addedABoxSameAsAssertion(Statement stmt, Model inferenceModel) { Resource subject = null; Resource object = null; @@ -478,91 +524,21 @@ public class SimpleReasoner extends StatementListener { return; } - Model inferences = ModelFactory.createDefaultModel(); - inferences.add(generateSameAsInferences(subject, object, inferenceModel)); - inferences.add(generateSameAsInferences(object, subject, inferenceModel)); - inferences.add(object, OWL.sameAs, subject); - - Iterator infIter = inferences.listStatements(); - - while (infIter.hasNext()) { - Statement infStmt = infIter.next(); - aboxModel.enterCriticalSection(Lock.READ); - try { - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (inferenceModel.contains(stmt)) { - inferenceModel.remove(stmt); - } - - if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt) ) { - inferenceModel.add(infStmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - } finally { - aboxModel.leaveCriticalSection(); - } - } - } - - /* - * Create a model that contains every assertion about indB as exists for - * indA in the Abox assertions or inference model - */ - public Model generateSameAsInferences(Resource indA, Resource indB, Model inferenceModel) { - - Model inferences = ModelFactory.createDefaultModel(); - - OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - unionModel.addSubModel(aboxModel); - unionModel.addSubModel(inferenceModel); - - aboxModel.enterCriticalSection(Lock.READ); + inferenceModel.enterCriticalSection(Lock.WRITE); try { - Iterator iter = unionModel.listStatements(indA, (Property) null, (RDFNode) null); - - while (iter.hasNext()) { - Statement stmt = iter.next(); - if (stmt.getObject() == null) continue; - if (OWL.sameAs.equals(stmt.getPredicate()) && indB.equals(stmt.getObject())) continue; - inferences.add(indB, stmt.getPredicate(), stmt.getObject()); - } - } finally { - aboxModel.leaveCriticalSection(); - } - - return inferences; - } - - /* - * Get a list of individuals the same as the given individual - */ - public List getSameIndividuals(Resource ind, Model inferenceModel) { - - OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - unionModel.addSubModel(aboxModel); - unionModel.addSubModel(inferenceModel); - - ArrayList sameIndividuals = new ArrayList(); - aboxModel.enterCriticalSection(Lock.READ); - inferenceModel.enterCriticalSection(Lock.READ); - try { - Iterator iter = unionModel.listStatements(ind, OWL.sameAs, (RDFNode) null); - - while (iter.hasNext()) { - Statement stmt = iter.next(); - if (stmt.getObject() == null || !stmt.getObject().isResource() || stmt.getObject().asResource().getURI() == null) continue; - sameIndividuals.add(stmt.getObject().asResource()); + if (inferenceModel.contains(stmt)) { + inferenceModel.remove(stmt); } } finally { inferenceModel.leaveCriticalSection(); - aboxModel.leaveCriticalSection(); } - return sameIndividuals; - } + Statement opposite = ResourceFactory.createStatement(object, OWL.sameAs, subject); + addInference(opposite,inferenceModel,true); + + generateSameAsInferences(subject, object, inferenceModel); + generateSameAsInferences(object, subject, inferenceModel); + } /* * Materializes inferences based on the owl:sameAs relationship. @@ -571,8 +547,7 @@ public class SimpleReasoner extends StatementListener { * the inference graph and then recompute the inferences for x and * y based on their respective assertions. that x owl:sameAs y, then all asserted and inferred */ - public void removedABoxSameAsAssertion(Statement stmt, Model inferenceModel) { - + protected void removedABoxSameAsAssertion(Statement stmt, Model inferenceModel) { Resource subject = null; Resource object = null; @@ -597,199 +572,60 @@ public class SimpleReasoner extends StatementListener { log.warn("the object of this removed sameAs statement is not a resource, no reasoning will be done: " + stmtString(stmt)); return; } - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (inferenceModel.contains(stmt)) { - inferenceModel.remove(stmt); - } - - if (!inferenceModel.contains(object, OWL.sameAs, subject) && !aboxModel.contains(object, OWL.sameAs, subject) ) { - inferenceModel.add(object, OWL.sameAs, subject); - } - } finally { - inferenceModel.leaveCriticalSection(); + + List sameIndividuals = getSameIndividuals(subject,inferenceModel); + sameIndividuals.addAll(getSameIndividuals(object, inferenceModel)); + + Iterator sIter1 = sameIndividuals.iterator(); + while (sIter1.hasNext()) { + removeInferencesForIndividual(sIter1.next(), inferenceModel); } - recomputeInferencesForIndividual(subject, inferenceModel); - recomputeInferencesForIndividual(object, inferenceModel); + Iterator sIter2 = sameIndividuals.iterator(); + while (sIter2.hasNext()) { + computeInferencesForIndividual(sIter2.next(), inferenceModel); + } } - + /* - * Recompute inferences for individual - */ - public void recomputeInferencesForIndividual(Resource ind, Model inferenceModel) { - - Model inferencesToRemove = ModelFactory.createDefaultModel(); - - inferenceModel.enterCriticalSection(Lock.READ); - try { - Iterator iter = inferenceModel.listStatements(ind, (Property) null, (RDFNode) null); - - while (iter.hasNext()) { - inferencesToRemove.add(iter.next()); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - inferenceModel.remove(inferencesToRemove); - } finally { - inferenceModel.leaveCriticalSection(); - } - - Iterator iter = null; - aboxModel.enterCriticalSection(Lock.WRITE); - try { - iter = aboxModel.listStatements(ind, (Property) null, (RDFNode) null); - } finally { - aboxModel.leaveCriticalSection(); - } - - while (iter.hasNext()) { - addedStatement(iter.next()); - } - - return; - } - - /* - * Performs incremental property-based reasoning. * * Materializes inferences based on the owl:inverseOf relationship. + * and owl:sameAs * * If it is added that x prop1 y, and prop2 is an inverseOf prop1 * then add y prop2 x to the inference graph, if it is not already in * the assertions graph. + * */ - public void addedABoxAssertion(Statement stmt, Model inferenceModel) { - List sameIndividuals = getSameIndividuals(stmt.getSubject().asResource(), inferenceModel); + protected void addedABoxAssertion(Statement stmt, Model inferenceModel) { + List inverseProperties = getInverseProperties(stmt); Iterator inverseIter = inverseProperties.iterator(); while (inverseIter.hasNext()) { Property inverseProp = inverseIter.next(); - Statement infStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), inverseProp, stmt.getSubject()); - - aboxModel.enterCriticalSection(Lock.READ); - try { - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt) ) { - inferenceModel.add(infStmt); - } - - Iterator sameIter = sameIndividuals.iterator(); - while (sameIter.hasNext()) { - Resource subject = sameIter.next(); - if (!inferenceModel.contains(subject,infStmt.getPredicate(),infStmt.getObject()) && !aboxModel.contains(subject,infStmt.getPredicate(),infStmt.getObject())) { - inferenceModel.add(subject,infStmt.getPredicate(),infStmt.getObject()); - } - } - } finally { - inferenceModel.leaveCriticalSection(); - } - } finally { - aboxModel.leaveCriticalSection(); - } + addInference(infStmt,inferenceModel,true); } + List sameIndividuals = getSameIndividuals(stmt.getSubject().asResource(), inferenceModel); + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Resource subject = sameIter.next(); + Statement sameStmt = ResourceFactory.createStatement(subject,stmt.getPredicate(),stmt.getObject()); + addInference(sameStmt,inferenceModel,false); + } + inferenceModel.enterCriticalSection(Lock.WRITE); try { if (inferenceModel.contains(stmt)) { inferenceModel.remove(stmt); } - - Iterator sameIter = sameIndividuals.iterator(); - while (sameIter.hasNext()) { - Resource subject = sameIter.next(); - if (!inferenceModel.contains(subject,stmt.getPredicate(),stmt.getObject()) && !aboxModel.contains(subject,stmt.getPredicate(),stmt.getObject())) { - inferenceModel.add(subject,stmt.getPredicate(),stmt.getObject()); - } - } } finally { inferenceModel.leaveCriticalSection(); } } - /* - * If it is removed that B is of type A, then for each superclass of A remove - * the inferred statement that B is of that type UNLESS it is otherwise entailed - * that B is of that type. - * - */ - protected void removedABoxTypeAssertion(Statement stmt, Model inferenceModel) { - - tboxModel.enterCriticalSection(Lock.READ); - - try { - OntClass cls = null; - - if ( (stmt.getObject().asResource()).getURI() != null ) { - cls = tboxModel.getOntClass(stmt.getObject().asResource().getURI()); - - if (cls != null) { - if (entailedType(stmt.getSubject(),cls)) { - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - //don't have to check aboxmodel here because this is the - //statement being removed. - if (!inferenceModel.contains(stmt)) { - inferenceModel.add(stmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - return; - } - - List parents = null; - parents = (cls.listSuperClasses(false)).toList(); - parents.addAll((cls.listEquivalentClasses()).toList()); - - Iterator parentIt = parents.iterator(); - - while (parentIt.hasNext()) { - OntClass parentClass = parentIt.next(); - - // VIVO doesn't materialize statements that assert anonymous types - // for individuals. Also, sharing an identical anonymous node is - // not allowed in owl-dl. picklist population code looks at qualities - // of classes not individuals. - if (parentClass.isAnon()) continue; - - if (entailedType(stmt.getSubject(),parentClass)) continue; // if a type is still entailed without the - // removed statement, then don't remove it - // from the inferences - - Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), RDF.type, parentClass); - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (inferenceModel.contains(infStmt)) { - inferenceModel.remove(infStmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - } - } else { - log.warn("Didn't find target class (the object of the removed rdf:type statement) in the TBox: " - + ((Resource)stmt.getObject()).getURI() + ". No class subsumption reasoning will be performed based on the removal of this assertion."); - } - } else { - log.warn("The object of this rdf:type assertion has a null URI: " + stmtString(stmt)); - } - } catch (Exception e) { - log.warn("exception while removing abox type assertions: " + e.getMessage()); - } finally { - tboxModel.leaveCriticalSection(); - } - } - /* * Performs incremental property-based reasoning. * @@ -800,114 +636,325 @@ public class SimpleReasoner extends StatementListener { * otherwise entailed by the assertions graph independently of * this removed statement. */ - public void removedABoxAssertion(Statement stmt, Model inferenceModel) { + protected void removedABoxAssertion(Statement stmt, Model inferenceModel) { - List sameIndividuals = getSameIndividuals(stmt.getSubject().asResource(), inferenceModel); List inverseProperties = getInverseProperties(stmt); - Iterator inverseIter = inverseProperties.iterator(); + Iterator inverseIter = inverseProperties.iterator(); while (inverseIter.hasNext()) { OntProperty inverseProp = inverseIter.next(); - Statement infStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), inverseProp, stmt.getSubject()); - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (!entailedStatement(infStmt) && inferenceModel.contains(infStmt)) { - inferenceModel.remove(infStmt); - } - - Iterator sameIter = sameIndividuals.iterator(); - while (sameIter.hasNext()) { - Statement infStmtSame = ResourceFactory.createStatement(sameIter.next(), infStmt.getPredicate(), infStmt.getObject()); - if (!entailedStatement(infStmtSame) && inferenceModel.contains(infStmtSame)) { - inferenceModel.remove(infStmtSame); - } - } - } finally { - inferenceModel.leaveCriticalSection(); - } + removeInference(infStmt,inferenceModel); } - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - // if a statement has been removed that is otherwise entailed, - // add it to the inference graph. + + List sameIndividuals = getSameIndividuals(stmt.getSubject().asResource(), inferenceModel); + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Statement stmtSame = ResourceFactory.createStatement(sameIter.next(), stmt.getPredicate(), stmt.getObject()); + removeInference(stmtSame,inferenceModel,false,true); + } + + // if a statement has been removed that is otherwise entailed, + // add it to the inference graph. + inferenceModel.enterCriticalSection(Lock.WRITE); + try { if (entailedStatement(stmt) && !inferenceModel.contains(stmt)) { inferenceModel.add(stmt); - } - - Iterator sameIter = sameIndividuals.iterator(); - while (sameIter.hasNext()) { - Statement stmtSame = ResourceFactory.createStatement(sameIter.next(), stmt.getPredicate(), stmt.getObject()); - if (!entailedStatement(stmtSame) && inferenceModel.contains(stmtSame)) { - inferenceModel.remove(stmtSame); - } - } - } finally { - inferenceModel.leaveCriticalSection(); - } + } + } finally { + inferenceModel.leaveCriticalSection(); + } } + + /* + * If it is added that B is a subClass of A, then for each + * individual that is typed as B, either in the ABox or in the + * inferred model, infer that it is of type A. + */ + protected void addedSubClass(OntClass subClass, OntClass superClass, Model inferenceModel) { + //log.debug("subClass = " + subClass.getURI() + " superClass = " + superClass.getURI()); + OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + unionModel.addSubModel(aboxModel); + unionModel.addSubModel(inferenceModel); + List subjectList = new ArrayList(); + aboxModel.enterCriticalSection(Lock.READ); + try { + StmtIterator iter = unionModel.listStatements((Resource) null, RDF.type, subClass); + while (iter.hasNext()) { + Statement stmt = iter.next(); + subjectList.add(stmt.getSubject()); + } + } finally { + aboxModel.leaveCriticalSection(); + } + + for (Resource subject : subjectList) { + Statement infStmt = ResourceFactory.createStatement(subject, RDF.type, superClass); + addInference(infStmt, inferenceModel, true); + setMostSpecificTypes(infStmt.getSubject(), inferenceModel, new HashSet()); + } + } + + /* + * If removed that B is a subclass of A, then for each individual + * that is of type B, either inferred or in the ABox, remove the + * assertion that it is of type A from the inferred model, + * UNLESS the individual is of some type C that is a subClass + * of A (including A itself) + */ + protected void removedSubClass(OntClass subClass, OntClass superClass, Model inferenceModel) { + OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + unionModel.addSubModel(aboxModel); + unionModel.addSubModel(inferenceModel); + List subjectList = new ArrayList(); + aboxModel.enterCriticalSection(Lock.READ); + try { + StmtIterator iter = unionModel.listStatements((Resource) null, RDF.type, subClass); + while (iter.hasNext()) { + Statement stmt = iter.next(); + subjectList.add(stmt.getSubject()); + } + } finally { + aboxModel.leaveCriticalSection(); + } + + for (Resource ind : subjectList) { + if (entailedType(ind,superClass)) { + continue; + } + Statement infStmt = ResourceFactory.createStatement(ind, RDF.type, superClass); + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if (inferenceModel.contains(infStmt)) { + inferenceModel.remove(infStmt); + } + + } finally { + inferenceModel.leaveCriticalSection(); + } + + setMostSpecificTypes(ind, inferenceModel, new HashSet()); + } + } + + /* + * If it is added that P is an inverse of Q, then: + * 1. For each statement involving predicate P in + * the assertions model add the inverse statement + * to the inference model if that inverse is + * in the assertions model. + * + * 2. Repeat the same for predicate Q. + * + */ + protected void addedInverseProperty(OntProperty prop1, OntProperty prop2, Model inferenceModel) { + + if ( !prop1.isObjectProperty() || !prop2.isObjectProperty() ) { + log.warn("The subject and object of the inverseOf statement are not both object properties. No inferencing will be performed. property 1: " + prop1.getURI() + " property 2:" + prop2.getURI()); + return; + } + + Model inferences = ModelFactory.createDefaultModel(); + inferences.add(generateInverseInferences(prop1, prop2)); + inferences.add(generateInverseInferences(prop2, prop1)); + + if (inferences.isEmpty()) return; + + StmtIterator iter = inferences.listStatements(); + + while (iter.hasNext()) { + Statement infStmt = iter.next(); + addInference(infStmt, inferenceModel, true); + } + } + + /* + * If it is removed that P is an inverse of Q, then: + * 1. For each statement involving predicate P in + * the abox assertions model remove the inverse + * statement from the inference model unless + * that statement is otherwise entailed. + * + * 2. Repeat the same for predicate Q. + */ + protected void removedInverseProperty(OntProperty prop1, OntProperty prop2, Model inferenceModel) { + + if ( !prop1.isObjectProperty() || !prop2.isObjectProperty() ) { + log.warn("The subject and object of the inverseOf statement are not both object properties. No inferencing will be performed. property 1: " + prop1.getURI() + " property 2:" + prop2.getURI()); + return; + } + + Model inferences = ModelFactory.createDefaultModel(); + inferences.add(generateInverseInferences(prop1, prop2)); + inferences.add(generateInverseInferences(prop2, prop1)); + + if (inferences.isEmpty()) return; + + StmtIterator iter = inferences.listStatements(); + + while (iter.hasNext()) { + Statement infStmt = iter.next(); + + if (entailedStatement(infStmt)) { + continue; + } + + removeInference(infStmt,inferenceModel); + } + } + + /* + * Get a list of individuals the same as the given individual + */ + protected List getSameIndividuals(Resource ind, Model inferenceModel) { + + OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + unionModel.addSubModel(aboxModel); + unionModel.addSubModel(inferenceModel); + ArrayList sameIndividuals = new ArrayList(); + aboxModel.enterCriticalSection(Lock.READ); + try { + inferenceModel.enterCriticalSection(Lock.READ); + try { + Iterator iter = unionModel.listStatements(ind, OWL.sameAs, (RDFNode) null); + + while (iter.hasNext()) { + Statement stmt = iter.next(); + if (stmt.getObject() == null || !stmt.getObject().isResource() || stmt.getObject().asResource().getURI() == null) continue; + sameIndividuals.add(stmt.getObject().asResource()); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + } finally { + aboxModel.leaveCriticalSection(); + } + + return sameIndividuals; + } + + protected void generateSameAsInferences(Resource ind1, Resource ind2, Model inferenceModel) { + + OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + unionModel.addSubModel(aboxModel); + unionModel.addSubModel(inferenceModel); + + aboxModel.enterCriticalSection(Lock.READ); + try { + Iterator iter = unionModel.listStatements(ind1, (Property) null, (RDFNode) null); + while (iter.hasNext()) { + Statement stmt = iter.next(); + if (stmt.getObject() == null) continue; + Statement infStmt = ResourceFactory.createStatement(ind2,stmt.getPredicate(),stmt.getObject()); + addInference(infStmt, inferenceModel,true); + } + } finally { + aboxModel.leaveCriticalSection(); + } + + return; + } + + /* + * Remove inferences for individual + */ + protected void removeInferencesForIndividual(Resource ind, Model inferenceModel) { + + Model individualInferences = ModelFactory.createDefaultModel(); + + inferenceModel.enterCriticalSection(Lock.READ); + try { + Iterator iter = inferenceModel.listStatements(ind, (Property) null, (RDFNode) null); + + while (iter.hasNext()) { + individualInferences.add(iter.next()); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + inferenceModel.remove(individualInferences); + } finally { + inferenceModel.leaveCriticalSection(); + } + + return; + } + + /* + * compute inferences for individual + */ + protected void computeInferencesForIndividual(Resource ind, Model inferenceModel) { + + Iterator iter = null; + aboxModel.enterCriticalSection(Lock.WRITE); + try { + iter = aboxModel.listStatements(ind, (Property) null, (RDFNode) null); + } finally { + aboxModel.leaveCriticalSection(); + } + + while (iter.hasNext()) { + Statement stmt = iter.next(); + addedStatement(stmt); + } + + return; + } + // Returns true if it is entailed by class subsumption that // subject is of type cls; otherwise returns false. protected boolean entailedType(Resource subject, OntClass cls) { + List sameIndividuals = getSameIndividuals(subject,inferenceModel); + sameIndividuals.add(subject); + tboxModel.enterCriticalSection(Lock.READ); - aboxModel.enterCriticalSection(Lock.READ); - - try { - List subclasses = null; - subclasses = (cls.listSubClasses(false)).toList(); - subclasses.addAll((cls.listEquivalentClasses()).toList()); - - Iterator iter = subclasses.iterator(); - - while (iter.hasNext()) { - OntClass childClass = iter.next(); - if (childClass.equals(cls)) continue; - Statement stmt = ResourceFactory.createStatement(subject, RDF.type, childClass); - if (aboxModel.contains(stmt)) return true; - } - - return false; - } catch (Exception e) { - log.debug("exception in method entailedType: " + e.getMessage()); - return false; - } finally { - aboxModel.leaveCriticalSection(); - tboxModel.leaveCriticalSection(); - } + try { + aboxModel.enterCriticalSection(Lock.READ); + try { + List subclasses = null; + subclasses = (cls.listSubClasses(false)).toList(); + subclasses.addAll((cls.listEquivalentClasses()).toList()); + Iterator iter = subclasses.iterator(); + while (iter.hasNext()) { + OntClass childClass = iter.next(); + if (childClass.equals(cls)) continue; // TODO - determine whether this is needed + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Statement stmt = ResourceFactory.createStatement(sameIter.next(), RDF.type, childClass); + if (aboxModel.contains(stmt)) { + return true; + } + } + } + return false; + } finally { + aboxModel.leaveCriticalSection(); + } + } finally { + tboxModel.leaveCriticalSection(); + } } // Returns true if the triple is entailed by inverse property // reasoning or sameAs reasoning; otherwise returns false. protected boolean entailedStatement(Statement stmt) { - - List inverses = new ArrayList(); - - tboxModel.enterCriticalSection(Lock.READ); - try { - OntProperty prop = tboxModel.getOntProperty(stmt.getPredicate().asResource().getURI()); - inverses.addAll(prop.listInverse().toList()); - } finally { - tboxModel.leaveCriticalSection(); - } - - Iterator oIter = inverses.iterator(); - if (oIter.hasNext()) { + + //TODO think about checking class subsumption here + + // Inverse properties + List inverses = getInverseProperties(stmt); + Iterator iIter = inverses.iterator(); + if (iIter.hasNext()) { aboxModel.enterCriticalSection(Lock.READ); try { - while (oIter.hasNext()) { - Property invProp = oIter.next(); - - // not reasoning on properties in the OWL, RDF or RDFS namespace - if ((invProp.getNameSpace()).equals(OWL.NS) || - (invProp.getNameSpace()).equals(RDFS.getURI()) || - (invProp.getNameSpace()).equals(RDF.getURI())) { - continue; - } - + while (iIter.hasNext()) { + Property invProp = iIter.next(); + Statement invStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), invProp, stmt.getSubject()); if (aboxModel.contains(invStmt)) { return true; @@ -918,6 +965,7 @@ public class SimpleReasoner extends StatementListener { } } + // individuals sameAs each other List sameIndividuals = getSameIndividuals(stmt.getSubject().asResource(),inferenceModel); Iterator rIter = sameIndividuals.iterator(); if (rIter.hasNext()) { @@ -938,6 +986,9 @@ public class SimpleReasoner extends StatementListener { return false; } + + + /* * Returns a list of properties that are inverses of the property * in the given statement. @@ -991,143 +1042,7 @@ public class SimpleReasoner extends StatementListener { return inverses; } - /* - * If it is added that B is a subClass of A, then for each - * individual that is typed as B, either in the ABox or in the - * inferred model, infer that it is of type A. - */ - protected void addedSubClass(OntClass subClass, OntClass superClass, Model inferenceModel) { - log.debug("subClass = " + subClass.getURI() + " superClass = " + superClass.getURI()); - OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - unionModel.addSubModel(aboxModel); - unionModel.addSubModel(inferenceModel); - List subjectList = new ArrayList(); - aboxModel.enterCriticalSection(Lock.READ); - try { - StmtIterator iter = unionModel.listStatements((Resource) null, RDF.type, subClass); - while (iter.hasNext()) { - Statement stmt = iter.next(); - subjectList.add(stmt.getSubject()); - } - } finally { - aboxModel.leaveCriticalSection(); - } - - for (Resource subject : subjectList) { - Statement infStmt = ResourceFactory.createStatement(subject, RDF.type, superClass); - - inferenceModel.enterCriticalSection(Lock.WRITE); - aboxModel.enterCriticalSection(Lock.READ); - try { - if (!inferenceModel.contains(infStmt) ) { - if (!aboxModel.contains(infStmt)) { - inferenceModel.add(infStmt); - } - setMostSpecificTypes(infStmt.getSubject(), inferenceModel, new HashSet()); - } - } finally { - inferenceModel.leaveCriticalSection(); - aboxModel.leaveCriticalSection(); - } - } - } - - /* - * If removed that B is a subclass of A, then for each individual - * that is of type B, either inferred or in the ABox, remove the - * assertion that it is of type A from the inferred model, - * UNLESS the individual is of some type C that is a subClass - * of A (including A itself) - */ - protected void removedSubClass(OntClass subClass, OntClass superClass, Model inferenceModel) { - OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - unionModel.addSubModel(aboxModel); - unionModel.addSubModel(inferenceModel); - List subjectList = new ArrayList(); - aboxModel.enterCriticalSection(Lock.READ); - try { - StmtIterator iter = unionModel.listStatements((Resource) null, RDF.type, subClass); - while (iter.hasNext()) { - Statement stmt = iter.next(); - subjectList.add(stmt.getSubject()); - } - } finally { - aboxModel.leaveCriticalSection(); - } - - for (Resource ind : subjectList) { - if (entailedType(ind,superClass)) { - continue; - } - Statement infStmt = ResourceFactory.createStatement(ind, RDF.type, superClass); - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (inferenceModel.contains(infStmt)) { - inferenceModel.remove(infStmt); - } - - } finally { - inferenceModel.leaveCriticalSection(); - } - - setMostSpecificTypes(ind, inferenceModel, new HashSet()); - } - } - - /* - * If it is added that P is an inverse of Q, then: - * 1. For each statement involving predicate P in - * the assertions model add the inverse statement - * to the inference model if that inverse is - * in the assertions model. - * - * 2. Repeat the same for predicate Q. - * - */ - public void addedInverseProperty(OntProperty prop1, OntProperty prop2, Model inferenceModel) { - - if ( !prop1.isObjectProperty() || !prop2.isObjectProperty() ) { - log.warn("The subject and object of the inverseOf statement are not both object properties. No inferencing will be performed. property 1: " + prop1.getURI() + " property 2:" + prop2.getURI()); - return; - } - - Model inferences = ModelFactory.createDefaultModel(); - inferences.add(generateInverseInferences(prop1, prop2)); - inferences.add(generateInverseInferences(prop2, prop1)); - - if (inferences.isEmpty()) return; - - aboxModel.enterCriticalSection(Lock.READ); - try { - StmtIterator iter = inferences.listStatements(); - - while (iter.hasNext()) { - Statement infStmt = iter.next(); - List sameIndividuals = getSameIndividuals(infStmt.getSubject().asResource(), inferenceModel); - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt)) { - inferenceModel.add(infStmt); - } - - Iterator sameIter = sameIndividuals.iterator(); - while (sameIter.hasNext()) { - Resource subject = sameIter.next(); - if (!inferenceModel.contains(subject,infStmt.getPredicate(),infStmt.getObject()) && !aboxModel.contains(subject,infStmt.getPredicate(),infStmt.getObject())) { - inferenceModel.add(subject,infStmt.getPredicate(),infStmt.getObject()); - } - } - } finally { - inferenceModel.leaveCriticalSection(); - } - } - } finally { - aboxModel.leaveCriticalSection(); - } - } - - public Model generateInverseInferences(OntProperty prop, OntProperty inverseProp) { + protected Model generateInverseInferences(OntProperty prop, OntProperty inverseProp) { Model inferences = ModelFactory.createDefaultModel(); aboxModel.enterCriticalSection(Lock.READ); @@ -1148,50 +1063,95 @@ public class SimpleReasoner extends StatementListener { } /* - * If it is removed that P is an inverse of Q, then: - * 1. For each statement involving predicate P in - * the abox assertions model remove the inverse - * statement from the inference model unless - * that statement is otherwise entailed. - * - * 2. Repeat the same for predicate Q. + * Add an inference from the inference model + * + * Adds the inference to the inference model if it is not already in + * the inference model and not in the abox model. */ - public void removedInverseProperty(OntProperty prop1, OntProperty prop2, Model inferenceModel) { - - if ( !prop1.isObjectProperty() || !prop2.isObjectProperty() ) { - log.warn("The subject and object of the inverseOf statement are not both object properties. No inferencing will be performed. property 1: " + prop1.getURI() + " property 2:" + prop2.getURI()); - return; - } - - Model inferences = ModelFactory.createDefaultModel(); - inferences.add(generateInverseInferences(prop1, prop2)); - inferences.add(generateInverseInferences(prop2, prop1)); - - if (inferences.isEmpty()) return; - - StmtIterator iter = inferences.listStatements(); - - while (iter.hasNext()) { - Statement infStmt = iter.next(); - - if (entailedStatement(infStmt)) { - continue; - } - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (inferenceModel.contains(infStmt)) { - inferenceModel.remove(infStmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - } + + public void addInference(Statement infStmt, Model inferenceModel) { + addInference(infStmt,inferenceModel,true); } + protected void addInference(Statement infStmt, Model inferenceModel, boolean handleSameAs) { + + aboxModel.enterCriticalSection(Lock.READ); + try { + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt)) { + inferenceModel.add(infStmt); + } + + if (handleSameAs) { + List sameIndividuals = getSameIndividuals(infStmt.getSubject().asResource(), inferenceModel); + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Resource subject = sameIter.next(); + + Statement sameStmt = ResourceFactory.createStatement(subject,infStmt.getPredicate(),infStmt.getObject()); + if (subject.equals(infStmt.getObject()) && OWL.sameAs.equals(infStmt.getPredicate())) { + continue; + } + + if (!inferenceModel.contains(sameStmt) && !aboxModel.contains(sameStmt)) { + inferenceModel.add(sameStmt); + } + } + } + } finally { + inferenceModel.leaveCriticalSection(); + } + } finally { + aboxModel.leaveCriticalSection(); + } + } + + /* + * Remove an inference from the inference model + * + * Removes the inference if it is not entailed by the abox model + * and if the inference model contains it. + * + * Removes the corresponding inference for each same individual + * if that inference is not entailed by the abox model. + */ + public void removeInference(Statement infStmt, Model inferenceModel) { + removeInference(infStmt,inferenceModel,true,true); + } + + protected void removeInference(Statement infStmt, Model inferenceModel, boolean handleSameAs, boolean checkEntailment) { + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if ( (!checkEntailment || !entailedStatement(infStmt)) && inferenceModel.contains(infStmt)) { + inferenceModel.remove(infStmt); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + + if (handleSameAs) { + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + List sameIndividuals = getSameIndividuals(infStmt.getSubject().asResource(), inferenceModel); + + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Statement infStmtSame = ResourceFactory.createStatement(sameIter.next(), infStmt.getPredicate(), infStmt.getObject()); + if ((!checkEntailment || !entailedStatement(infStmtSame)) && inferenceModel.contains(infStmtSame)) { + inferenceModel.remove(infStmtSame); + } + } + } finally { + inferenceModel.leaveCriticalSection(); + } + } + } + /* * Find the most specific types (classes) of an individual and - * indicate them for the individual with the mostSpecificType + * infer them for the individual with the mostSpecificType * annotation. */ protected void setMostSpecificTypes(Resource individual, Model inferenceModel, HashSet unknownTypes) { @@ -1291,10 +1251,10 @@ public class SimpleReasoner extends StatementListener { protected void setMostSpecificTypes(Resource individual, HashSet typeURIs, Model inferenceModel) { - inferenceModel.enterCriticalSection(Lock.WRITE); - + Model retractions = ModelFactory.createDefaultModel(); + + inferenceModel.enterCriticalSection(Lock.READ); try { - Model retractions = ModelFactory.createDefaultModel(); // remove obsolete mostSpecificType assertions StmtIterator iter = inferenceModel.listStatements(individual, mostSpecificType, (RDFNode) null); @@ -1310,27 +1270,60 @@ public class SimpleReasoner extends StatementListener { retractions.add(stmt); } } - - inferenceModel.remove(retractions); - - // add new mostSpecificType assertions - Iterator typeIter = typeURIs.iterator(); - - while (typeIter.hasNext()) { - String typeURI = typeIter.next(); - Resource mstResource = ResourceFactory.createResource(typeURI); - - if (!inferenceModel.contains(individual, mostSpecificType, mstResource)) { - inferenceModel.add(individual, mostSpecificType, mstResource); - } - } } finally { inferenceModel.leaveCriticalSection(); - } - - return; + } + + Iterator rIter = retractions.listStatements(); + while (rIter.hasNext()) { + removeInference(rIter.next(), inferenceModel, true, false); + } + + Iterator typeIter = typeURIs.iterator(); + while (typeIter.hasNext()) { + String typeURI = typeIter.next(); + Statement mstStmt = ResourceFactory.createStatement(individual,mostSpecificType,ResourceFactory.createResource(typeURI)); + addInference(mstStmt,inferenceModel,true); + } + + return; } + // system-configured reasoning modules (plugins) + protected boolean isInterestedInRemovedStatement(Statement stmt) { + + if (stmt.getPredicate().equals(RDF.type)) return true; + + for (ReasonerPlugin plugin : getPluginList()) { + if (plugin.isInterestedInRemovedStatement(stmt)) return true; + } + + return false; + } + + protected void doPlugins(ModelUpdate.Operation op, Statement stmt) { + + for (ReasonerPlugin plugin : getPluginList()) { + try { + switch (op) { + case ADD: + if (plugin.isInterestedInAddedStatement(stmt)) { + plugin.addedABoxStatement(stmt, aboxModel, inferenceModel, tboxModel); + } + break; + case RETRACT: + if (plugin.isInterestedInRemovedStatement(stmt)) { + plugin.removedABoxStatement(stmt, aboxModel, inferenceModel, tboxModel); + } + break; + } + } catch (Exception e) { + log.error("Exception while processing " + (op == ModelUpdate.Operation.ADD ? "an added" : "a removed") + + " statement in SimpleReasoner plugin:" + plugin.getClass().getName() + " -- " + e.getMessage()); + } + } + } + /** * Returns true if the reasoner is in the process of recomputing all * inferences. @@ -1370,7 +1363,7 @@ public class SimpleReasoner extends StatementListener { HashSet unknownTypes = new HashSet(); inferenceRebuildModel.removeAll(); - log.info("Computing class subsumtion ABox inferences."); + log.info("Computing class subsumption ABox inferences."); int numStmts = 0; ArrayList individuals = this.getAllIndividualURIs(); @@ -1412,122 +1405,158 @@ public class SimpleReasoner extends StatementListener { } log.info("Finished computing class subsumption ABox inferences"); - log.info("Computing inverse property ABox inferences"); - Iterator invStatements = null; - tboxModel.enterCriticalSection(Lock.READ); + + Iterator invStatements = null; + tboxModel.enterCriticalSection(Lock.READ); + try { + invStatements = tboxModel.listStatements((Resource) null, OWL.inverseOf, (Resource) null); + } finally { + tboxModel.leaveCriticalSection(); + } + + numStmts = 0; + while (invStatements.hasNext()) { + Statement stmt = invStatements.next(); + try { - invStatements = tboxModel.listStatements((Resource) null, OWL.inverseOf, (Resource) null); - } finally { - tboxModel.leaveCriticalSection(); - } - - numStmts = 0; - while (invStatements.hasNext()) { - Statement stmt = invStatements.next(); - - try { - OntProperty prop1 = tboxModel.getOntProperty((stmt.getSubject()).getURI()); - if (prop1 == null) { - //TODO make sure not to print out a million of these for the same property - log.debug("didn't find subject property in the tbox: " + (stmt.getSubject()).getURI()); - continue; - } - - OntProperty prop2 = tboxModel.getOntProperty(((Resource)stmt.getObject()).getURI()); - if (prop2 == null) { - //TODO make sure not to print out a million of these for the same property - log.debug("didn't find object property in the tbox: " + ((Resource)stmt.getObject()).getURI()); - continue; - } - - addedInverseProperty(prop1, prop2, inferenceRebuildModel); - } catch (NullPointerException npe) { - log.error("a NullPointerException was received while recomputing the ABox inferences. Halting inference computation."); - return; - } catch (JenaException je) { - if (je.getMessage().equals("Statement models must no be null")) { - log.error("Exception while recomputing ABox inference model. Halting inference computation.", je); - return; - } - log.error("Exception while recomputing ABox inference model: ", je); - } catch (Exception e) { - log.error("Exception while recomputing ABox inference model: ", e); + OntProperty prop1 = tboxModel.getOntProperty((stmt.getSubject()).getURI()); + if (prop1 == null) { + //TODO make sure not to print out a million of these for the same property + log.debug("didn't find subject property in the tbox: " + (stmt.getSubject()).getURI()); + continue; } - numStmts++; - if ((numStmts % 10000) == 0) { - log.info("Still computing inverse property ABox inferences..."); - } - - if (stopRequested) { - log.info("a stopRequested signal was received during recomputeABox. Halting Processing."); - return; - } + OntProperty prop2 = tboxModel.getOntProperty(((Resource)stmt.getObject()).getURI()); + if (prop2 == null) { + //TODO make sure not to print out a million of these for the same property + log.debug("didn't find object property in the tbox: " + ((Resource)stmt.getObject()).getURI()); + continue; + } + + addedInverseProperty(prop1, prop2, inferenceRebuildModel); + } catch (NullPointerException npe) { + log.error("a NullPointerException was received while recomputing the ABox inferences. Halting inference computation."); + return; + } catch (JenaException je) { + if (je.getMessage().equals("Statement models must no be null")) { + log.error("Exception while recomputing ABox inference model. Halting inference computation.", je); + return; + } + log.error("Exception while recomputing ABox inference model: ", je); + } catch (Exception e) { + log.error("Exception while recomputing ABox inference model: ", e); } - log.info("Finished computing inverse property ABox inferences"); + numStmts++; + if ((numStmts % 10000) == 0) { + log.info("Still computing inverse property ABox inferences..."); + } + + if (stopRequested) { + log.info("a stopRequested signal was received during recomputeABox. Halting Processing."); + return; + } + } + log.info("Finished computing inverse property ABox inferences"); log.info("Computing sameAs ABox inferences"); - Iterator sameAsStatements = null; - aboxModel.enterCriticalSection(Lock.READ); + Iterator sameAsStatements = null; + aboxModel.enterCriticalSection(Lock.READ); + try { + sameAsStatements = aboxModel.listStatements((Resource) null, OWL.sameAs, (Resource) null); + } finally { + aboxModel.leaveCriticalSection(); + } + + numStmts = 0; + while (sameAsStatements.hasNext()) { + Statement stmt = sameAsStatements.next(); + try { - sameAsStatements = aboxModel.listStatements((Resource) null, OWL.sameAs, (Resource) null); - } finally { - aboxModel.leaveCriticalSection(); - } - - numStmts = 0; - while (sameAsStatements.hasNext()) { - Statement stmt = sameAsStatements.next(); - - try { - addedABoxSameAsAssertion(stmt, inferenceRebuildModel); - } catch (NullPointerException npe) { - log.error("a NullPointerException was received while recomputing the ABox inferences. Halting inference computation."); - return; - } catch (JenaException je) { - if (je.getMessage().equals("Statement models must no be null")) { - log.error("Exception while recomputing ABox inference model. Halting inference computation.", je); - return; - } - log.error("Exception while recomputing ABox inference model: ", je); - } catch (Exception e) { - log.error("Exception while recomputing ABox inference model: ", e); - } - - numStmts++; - if ((numStmts % 10000) == 0) { - log.info("Still computing sameAs ABox inferences..."); - } - - if (stopRequested) { - log.info("a stopRequested signal was received during recomputeABox. Halting Processing."); - return; - } - } - log.info("Finished computing sameAs ABox inferences"); - - try { - if (updateInferenceModel(inferenceRebuildModel)) { - log.info("a stopRequested signal was received during updateInferenceModel. Halting Processing."); - return; - } + addedABoxSameAsAssertion(stmt, inferenceRebuildModel); + } catch (NullPointerException npe) { + log.error("a NullPointerException was received while recomputing the ABox inferences. Halting inference computation."); + return; + } catch (JenaException je) { + if (je.getMessage().equals("Statement models must no be null")) { + log.error("Exception while recomputing ABox inference model. Halting inference computation.", je); + return; + } + log.error("Exception while recomputing ABox inference model: ", je); } catch (Exception e) { - log.error("Exception while reconciling the current and recomputed ABox inference model for class subsumption inferences. Halting processing." , e); - inferenceRebuildModel.removeAll(); - return; - } + log.error("Exception while recomputing ABox inference model: ", e); + } + + numStmts++; + if ((numStmts % 10000) == 0) { + log.info("Still computing sameAs ABox inferences..."); + } + + if (stopRequested) { + log.info("a stopRequested signal was received during recomputeABox. Halting Processing."); + return; + } + } + log.info("Finished computing sameAs ABox inferences"); + + try { + if (updateInferenceModel(inferenceRebuildModel)) { + log.info("a stopRequested signal was received during updateInferenceModel. Halting Processing."); + return; + } + } catch (Exception e) { + log.error("Exception while reconciling the current and recomputed ABox inference model for class subsumption inferences. Halting processing." , e); + } } catch (Exception e) { - log.error("Exception while recomputing ABox inferences. Halting processing.", e); - inferenceRebuildModel.removeAll(); - return; + log.error("Exception while recomputing ABox inferences. Halting processing.", e); } finally { - inferenceRebuildModel.leaveCriticalSection(); + inferenceRebuildModel.removeAll(); + inferenceRebuildModel.leaveCriticalSection(); } } + /* + * Get the URIs for all individuals in the system + */ + protected ArrayList getAllIndividualURIs() { + + String queryString = "select distinct ?subject where {?subject ?type}"; + return getIndividualURIs(queryString); + } + + protected ArrayList getIndividualURIs(String queryString) { + + ArrayList individuals = new ArrayList(); + aboxModel.enterCriticalSection(Lock.READ); + + try { + try { + Query query = QueryFactory.create(queryString, Syntax.syntaxARQ); + QueryExecution qe = QueryExecutionFactory.create(query, aboxModel); + + ResultSet results = qe.execSelect(); + + while (results.hasNext()) { + QuerySolution solution = results.next(); + Resource resource = solution.getResource("subject"); + + if ((resource != null) && !resource.isAnon()) { + individuals.add(resource.getURI()); + } + } + + } catch (Exception e) { + log.error("exception while retrieving list of individuals ",e); + } + } finally { + aboxModel.leaveCriticalSection(); + } + + return individuals; + } + /* * reconcile a set of inferences into the application inference model */ @@ -1633,82 +1662,7 @@ public class SimpleReasoner extends StatementListener { log.info("ABox inference model updated"); return false; } - /* - * Get the URIs for all individuals in the system - */ - protected ArrayList getAllIndividualURIs() { - - String queryString = "select distinct ?subject where {?subject ?type}"; - return getIndividualURIs(queryString); - } - - protected ArrayList getIndividualURIs(String queryString) { - - ArrayList individuals = new ArrayList(); - aboxModel.enterCriticalSection(Lock.READ); - - try { - try { - Query query = QueryFactory.create(queryString, Syntax.syntaxARQ); - QueryExecution qe = QueryExecutionFactory.create(query, aboxModel); - - ResultSet results = qe.execSelect(); - - while (results.hasNext()) { - QuerySolution solution = results.next(); - Resource resource = solution.getResource("subject"); - - if ((resource != null) && !resource.isAnon()) { - individuals.add(resource.getURI()); - } - } - - } catch (Exception e) { - log.error("exception while retrieving list of individuals ",e); - } - } finally { - aboxModel.leaveCriticalSection(); - } - - return individuals; - } - - // system-configured reasoning modules (plugins) - public boolean isInterestedInRemovedStatement(Statement stmt) { - - if (stmt.getPredicate().equals(RDF.type)) return true; - - for (ReasonerPlugin plugin : getPluginList()) { - if (plugin.isInterestedInRemovedStatement(stmt)) return true; - } - - return false; - } - - protected void doPlugins(ModelUpdate.Operation op, Statement stmt) { - - for (ReasonerPlugin plugin : getPluginList()) { - try { - switch (op) { - case ADD: - if (plugin.isInterestedInAddedStatement(stmt)) { - plugin.addedABoxStatement(stmt, aboxModel, inferenceModel, tboxModel); - } - break; - case RETRACT: - if (plugin.isInterestedInRemovedStatement(stmt)) { - plugin.removedABoxStatement(stmt, aboxModel, inferenceModel, tboxModel); - } - break; - } - } catch (Exception e) { - log.error("Exception while processing " + (op == ModelUpdate.Operation.ADD ? "an added" : "a removed") + - " statement in SimpleReasoner plugin:" + plugin.getClass().getName() + " -- " + e.getMessage()); - } - } - } - /** * This is called when the application shuts down. */ @@ -1725,10 +1679,8 @@ public class SimpleReasoner extends StatementListener { "] [object = " + (statement.getObject().isLiteral() ? ((Literal)statement.getObject()).getLexicalForm() + " (Literal)" : ((Resource)statement.getObject()).getURI() + " (Resource)") + "]"; } - - - // DeltaComputer - + + // DeltaComputer /* * Asynchronous reasoning mode (DeltaComputer) is used in the case of batch removals. */ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTBoxListener.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTBoxListener.java index f3ab12423..840572d51 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTBoxListener.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTBoxListener.java @@ -49,12 +49,14 @@ public class SimpleReasonerTBoxListener extends StatementListener { @Override public void addedStatement(Statement statement) { + ModelUpdate mu = new ModelUpdate(statement, ModelUpdate.Operation.ADD, JenaDataSourceSetupBase.JENA_TBOX_ASSERTIONS_MODEL); processUpdate(mu); } @Override public void removedStatement(Statement statement) { + ModelUpdate mu = new ModelUpdate(statement, ModelUpdate.Operation.RETRACT, JenaDataSourceSetupBase.JENA_TBOX_ASSERTIONS_MODEL); processUpdate(mu); } 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 ff5bb35df..60a6ee5d8 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 @@ -115,6 +115,7 @@ public class SimpleReasonerSetup implements ServletContextListener { try { ReasonerPlugin plugin = (ReasonerPlugin) Class.forName( classname).getConstructors()[0].newInstance(); + plugin.setSimpleReasoner(simpleReasoner); pluginList.add(plugin); } catch(Throwable t) { ss.info(this, "Could not instantiate reasoner plugin " + classname); diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java index 4c61fcb73..b96b33f64 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java @@ -42,44 +42,42 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { @Test public void addABoxAssertion1() { + // set up the tbox OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - OntProperty P = tBox.createOntProperty("http://test.vivo/P"); P.setLabel("property P", "en-US"); - OntProperty Q = tBox.createOntProperty("http://test.vivo/Q"); Q.setLabel("property Q", "en-US"); P.addInverseOf(Q); - // this is the model to receive inferences + // this is the model to receive abox inferences Model inf = ModelFactory.createDefaultModel(); - // create an ABox and register the SimpleReasoner listener with it + // create an abox and register the SimpleReasoner listener with it OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); aBox.register(new SimpleReasoner(tBox, aBox, inf)); - // Individuals a, b, c and d + // add assertions to the abox and verify inferences Resource a = aBox.createResource("http://test.vivo/a"); Resource b = aBox.createResource("http://test.vivo/b"); Resource c = aBox.createResource("http://test.vivo/c"); Resource d = aBox.createResource("http://test.vivo/d"); - // b Q a is inferred from a P b aBox.add(a,P,b); - Assert.assertTrue(inf.contains(b,Q,a)); - - // d P c is inferred from c Q d. + Assert.assertTrue(inf.contains(b,Q,a)); aBox.add(c,Q,d); Assert.assertTrue(inf.contains(d,P,c)); } /* - * don't infer if it's already in the abox + * don't infer statements already in the abox + * (never infer because it's in the abox already) */ @Test public void addABoxAssertion2() { + // set up the tbox OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); OntProperty P = tBox.createOntProperty("http://test.vivo/P"); @@ -88,10 +86,10 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { Q.setLabel("property Q", "en-US"); P.addInverseOf(Q); - // this is the model to receive inferences + // this is the model to receive abox inferences Model inf = ModelFactory.createDefaultModel(); - // create an ABox and add statement b Q a + // create an ABox and add data (no inferencing happening yet) OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); // Individuals a, b, c and d Resource a = aBox.createResource("http://test.vivo/a"); @@ -101,38 +99,42 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { // register SimpleReasoner aBox.register(new SimpleReasoner(tBox, aBox, inf)); - // b Q a is inferred from a P b, but it is already in the abox + Assert.assertFalse(inf.contains(b,Q,a)); + + // add data and verify inferences aBox.add(a,P,b); Assert.assertFalse(inf.contains(b,Q,a)); } /* - * don't infer if it's already in the abox + * don't infer statements already in the abox + * (remove the inference when it is asserted) */ @Test public void addABoxAssertion3() { - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + // set up the tbox + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); OntProperty P = tBox.createOntProperty("http://test.vivo/P"); P.setLabel("property P", "en-US"); OntProperty Q = tBox.createOntProperty("http://test.vivo/Q"); Q.setLabel("property Q", "en-US"); P.addInverseOf(Q); - // this is the model to receive inferences + // this is the model to receive abox inferences Model inf = ModelFactory.createDefaultModel(); - // create an ABox and register SimpleReasoner + // create abox and register SimpleReasoner OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); aBox.register(new SimpleReasoner(tBox, aBox, inf)); - // Individuals a, b, c and d + // add statements to the abox and verify inferences Resource a = aBox.createResource("http://test.vivo/a"); Resource b = aBox.createResource("http://test.vivo/b"); - // b Q a is inferred from a P b, but it is already in the abox aBox.add(a,P,b); - aBox.add(b,Q,a); + Assert.assertTrue(inf.contains(b,Q,a)); + aBox.add(b,Q,a); // this should cause the inference to be removed Assert.assertFalse(inf.contains(b,Q,a)); } @@ -143,8 +145,8 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { @Test public void addABoxAssertion4() { + // set up the tbox OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - OntProperty P = tBox.createOntProperty("http://test.vivo/P"); P.setLabel("property P", "en-US"); OntProperty R = tBox.createOntProperty("http://test.vivo/R"); @@ -153,27 +155,24 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { Q.setLabel("property Q", "en-US"); R.addEquivalentProperty(P); - P.addEquivalentProperty(R); P.addInverseOf(Q); - // this is the model to receive inferences + // this is the model to receive abox inferences Model inf = ModelFactory.createDefaultModel(); - // create an ABox and register the SimpleReasoner listener with it + // create an ABox and register the SimpleReasoner with it OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); aBox.register(new SimpleReasoner(tBox, aBox, inf)); - // a, b, c and d + // add abox statements and verify inferences Resource a = aBox.createResource("http://test.vivo/a"); Resource b = aBox.createResource("http://test.vivo/b"); Resource c = aBox.createResource("http://test.vivo/c"); Resource d = aBox.createResource("http://test.vivo/d"); - // b Q a is inferred from a R b. aBox.add(a,R,b); Assert.assertTrue(inf.contains(b,Q,a)); - - // d P c is inferred from c Q d. + aBox.add(c,Q,d); Assert.assertTrue(inf.contains(d,P,c)); Assert.assertTrue(inf.contains(d,R,c)); @@ -181,11 +180,14 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { /* * basic scenarios around removing abox data + * don't remove an inference if it's still + * entailed by something else in the abox. */ @Test public void removedABoxAssertion1() { - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + // set up the tbox + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); OntProperty P = tBox.createOntProperty("http://test.vivo/P"); P.setLabel("property P", "en-US"); OntProperty Q = tBox.createOntProperty("http://test.vivo/Q"); @@ -195,24 +197,23 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { P.addInverseOf(Q); P.addInverseOf(T); - // this is the model to receive inferences + // this is the model to receive abox inferences Model inf = ModelFactory.createDefaultModel(); - // create an ABox and register the SimpleReasoner listener with it + // create an ABox and register the SimpleReasoner with it OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); aBox.register(new SimpleReasoner(tBox, aBox, inf)); - // Individuals a, b, c and d + // add statements to the abox and verify inferences Resource a = aBox.createResource("http://test.vivo/a"); Resource b = aBox.createResource("http://test.vivo/b"); Resource c = aBox.createResource("http://test.vivo/c"); Resource d = aBox.createResource("http://test.vivo/d"); - // b Q a is inferred from a P b. aBox.add(a,P,b); Assert.assertTrue(inf.contains(b,Q,a)); - // d P c is inferred from c Q d and from c T d + // d P c is inferred from c Q d and also from c T d aBox.add(c,Q,d); aBox.add(c,T,d); Assert.assertTrue(inf.contains(d,P,c)); @@ -220,17 +221,19 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { aBox.remove(a,P,b); Assert.assertFalse(inf.contains(b,Q,a)); - aBox.remove(c,Q,d); - Assert.assertTrue(inf.contains(d,P,c)); + aBox.remove(c,Q,d); + Assert.assertTrue(inf.contains(d,P,c)); // still inferred from c T d } /* * removing abox data with equivalent and inverse properties + * don't remove inference if it's still inferred. */ @Test public void removedABoxAssertion2() { - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + // set up the tbox + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); OntProperty P = tBox.createOntProperty("http://test.vivo/P"); P.setLabel("property P", "en-US"); OntProperty Q = tBox.createOntProperty("http://test.vivo/Q"); @@ -238,26 +241,29 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { OntProperty T = tBox.createOntProperty("http://test.vivo/T"); Q.setLabel("property T", "en-US"); P.addInverseOf(Q); - Q.addInverseOf(P); P.addEquivalentProperty(T); - T.addEquivalentProperty(P); + + // not clear what these will do + tBox.rebind(); + tBox.prepare(); - // this is the model to receive inferences + // this is the model to receive abox inferences Model inf = ModelFactory.createDefaultModel(); - // create an ABox and register the SimpleReasoner listener with it + // create an abox and register the SimpleReasoner listener with it OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); aBox.register(new SimpleReasoner(tBox, aBox, inf)); - // Individuals a, b, c and d + // add abox data and verify inferences Resource a = aBox.createResource("http://test.vivo/a"); Resource b = aBox.createResource("http://test.vivo/b"); - // b Q a is inferred from a P b and a T b. + // b Q a is inferred from a P b and also from a T b. aBox.add(a,P,b); aBox.add(a,T,b); Assert.assertTrue(inf.contains(b,Q,a)); Assert.assertFalse(inf.contains(a,P,b)); + Assert.assertFalse(inf.contains(a,T,b)); aBox.remove(a,P,b); Assert.assertTrue(inf.contains(b,Q,a)); @@ -268,80 +274,81 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { */ @Test public void removedABoxAssertion3() { - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + //set up the tbox + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); OntProperty P = tBox.createOntProperty("http://test.vivo/P"); P.setLabel("property P", "en-US"); OntProperty Q = tBox.createOntProperty("http://test.vivo/Q"); Q.setLabel("property Q", "en-US"); P.addInverseOf(Q); - // this is the model to receive inferences + tBox.rebind(); // not sure what effect this has + + // this is the model to receive abox inferences Model inf = ModelFactory.createDefaultModel(); - // create an ABox and register the SimpleReasoner listener with it - OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + // create the abox and add some data - no reasoning is happening yet + OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + Resource a = aBox.createResource("http://test.vivo/a"); Resource b = aBox.createResource("http://test.vivo/b"); aBox.add(a,P,b); + // register the SimpleReasoner aBox.register(new SimpleReasoner(tBox, aBox, inf)); + // add abox statements and verify inferences aBox.add(b,Q,a); - Assert.assertFalse(inf.contains(b,Q,a)); - Assert.assertFalse(inf.contains(a,P,b)); - + Assert.assertFalse(inf.contains(a,P,b)); // this could be inferred from b Q a, but + // it's already in the abox aBox.remove(a,P,b); - Assert.assertTrue(inf.contains(a,P,b)); + Assert.assertTrue(inf.contains(a,P,b)); // now it gets added to inference model + // when it's removed from the abox } /* - * Basic scenario around adding an inverseOf assertion to the - * TBox + * adding an inverseOf assertion to the tbox */ @Test public void addTBoxInverseAssertion1() throws InterruptedException { - - // Create TBox, ABox and Inference models and register - // the ABox reasoner listeners with the ABox and TBox - // Pellet will compute TBox inferences - + + // Set up the TBox. OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - OntProperty P = tBox.createOntProperty("http://test.vivo/P"); P.setLabel("property P", "en-US"); - OntProperty Q = tBox.createOntProperty("http://test.vivo/Q"); Q.setLabel("property Q", "en-US"); - OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + // this is the model to receive abox inferences Model inf = ModelFactory.createDefaultModel(); - - SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); + + // abox + OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + + // set up SimpleReasoner and register it with abox. register + // SimpleReasonerTBoxListener with the tbox. + SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); tBox.register(simpleReasonerTBoxListener); - // Individuals a, b, c and d + // add abox data Resource a = aBox.createResource("http://test.vivo/a"); Resource b = aBox.createResource("http://test.vivo/b"); Resource c = aBox.createResource("http://test.vivo/c"); Resource d = aBox.createResource("http://test.vivo/d"); - - // abox statements + aBox.add(a,P,b); aBox.add(c,P,d); aBox.add(b,Q,a); - // Assert P and Q as inverses and wait for SimpleReasoner TBox - // thread to end + // Assert P and Q as inverses and wait for + // SimpleReasonerTBoxListener thread to end Q.addInverseOf(P); - - tBox.rebind(); - tBox.prepare(); - + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { Thread.sleep(delay); } @@ -349,47 +356,43 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { // Verify inferences Assert.assertTrue(inf.contains(d,Q,c)); Assert.assertFalse(inf.contains(b,Q,a)); + Assert.assertFalse(inf.contains(a,P,b)); simpleReasonerTBoxListener.setStopRequested(); } /* - * Basic scenario around removing an inverseOf assertion to the - * TBox + * removing an inverseOf assertion from the tbox */ @Test public void removeTBoxInverseAssertion1() throws InterruptedException { - // Create TBox, ABox and Inference models and register - // the ABox reasoner listeners with the ABox and TBox - // Pellet will compute TBox inferences - + // set up the tbox. OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - // set up TBox and Abox - OntProperty P = tBox.createOntProperty("http://test.vivo/propP"); P.setLabel("property P", "en-US"); - OntProperty Q = tBox.createOntProperty("http://test.vivo/propQ"); Q.setLabel("property Q", "en-US"); - Q.addInverseOf(P); + // this is the model to receive abox inferences + Model inf = ModelFactory.createDefaultModel(); + + // abox OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - Model inf = ModelFactory.createDefaultModel(); - - SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); + + // set up SimpleReasoner and SimpleReasonerTBox listener, + // register them with abox and tbox + SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); tBox.register(simpleReasonerTBoxListener); - // Individuals a, b, c and d + + // add statements to the abox and verify inference Resource c = aBox.createResource("http://test.vivo/c"); Resource d = aBox.createResource("http://test.vivo/d"); - - // abox statements aBox.add(c,P,d); - Assert.assertTrue(inf.contains(d,Q,c)); // Remove P and Q inverse relationship and wait for @@ -397,14 +400,11 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { Q.removeInverseProperty(P); - tBox.rebind(); - tBox.prepare(); - while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { Thread.sleep(delay); } - // Verify inferences + // Verify inference has been removed Assert.assertFalse(inf.contains(d,Q,c)); simpleReasonerTBoxListener.setStopRequested(); @@ -416,12 +416,9 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { @Test public void recomputeABox1() throws InterruptedException { - // Create TBox, ABox and Inference models and register - // the ABox reasoner listeners with the ABox and TBox - // Pellet will compute TBox inferences + // set up tbox OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - // set up TBox and Abox OntProperty P = tBox.createOntProperty("http://test.vivo/propP"); P.setLabel("property P", "en-US"); OntProperty Q = tBox.createOntProperty("http://test.vivo/propQ"); @@ -434,21 +431,23 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { Q.setLabel("property Y", "en-US"); X.addInverseOf(Y); + // create abox and abox inf model and register simplereasoner + // with abox. OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - Model inf = ModelFactory.createDefaultModel(); - + Model inf = ModelFactory.createDefaultModel(); SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - // Individuals a, b, c and d + + // abox statements Resource a = aBox.createResource("http://test.vivo/a"); Resource b = aBox.createResource("http://test.vivo/b"); Resource c = aBox.createResource("http://test.vivo/c"); Resource d = aBox.createResource("http://test.vivo/d"); - // abox statements aBox.add(a,P,b); aBox.add(c,X,d); + //recompute whole abox simpleReasoner.recompute(); while (simpleReasoner.isRecomputing()) { diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java index 41ceffee7..7f1b083c0 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java @@ -8,6 +8,7 @@ import org.junit.Before; import org.junit.Test; import org.mindswap.pellet.jena.PelletReasonerFactory; +import com.hp.hpl.jena.ontology.AnnotationProperty; import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; @@ -16,6 +17,7 @@ import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; @@ -25,7 +27,8 @@ import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; public class SimpleReasonerSameAsTest extends AbstractTestClass { long delay = 50; - + private static final String mostSpecificTypePropertyURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType"; + @Before public void suppressErrorOutput() { suppressSyserr(); @@ -90,7 +93,7 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { } /* - * basic scenario of removing an abox sameAs assertion + * basic scenario of removing an abox sameAs assertion */ @Test public void removeSameAsABoxAssertion1() { @@ -103,10 +106,10 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { OntProperty Q = tBox.createObjectProperty("http://test.vivo/Q"); Q.setLabel("property Q", "en-US"); - OntProperty S = tBox.createDatatypeProperty("http://test.vivo/"); + OntProperty S = tBox.createDatatypeProperty("http://test.vivo/data1"); S.setLabel("property S", "en-US"); - OntProperty T = tBox.createDatatypeProperty("http://test.vivo/"); + OntProperty T = tBox.createDatatypeProperty("http://test.vivo/data2"); T.setLabel("property T", "en-US"); Literal literal1 = tBox.createLiteral("Literal value 1"); @@ -138,7 +141,7 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { Assert.assertTrue(inf.contains(a,T,literal2)); aBox.remove(a,OWL.sameAs,b); - + Assert.assertFalse(inf.contains(b,OWL.sameAs,a)); Assert.assertFalse(inf.contains(b,P,c)); Assert.assertFalse(inf.contains(b,S,literal1)); @@ -147,8 +150,7 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { } /* - * basic scenario of adding an abox assertion for - * an individual is sameAs another. + * adding abox assertion for individual in sameAs chain. */ @Test public void addABoxAssertion1() { @@ -182,10 +184,23 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { Resource b = aBox.createResource("http://test.vivo/b"); Resource c = aBox.createResource("http://test.vivo/c"); Resource d = aBox.createResource("http://test.vivo/d"); + Resource e = aBox.createResource("http://test.vivo/e"); + Resource f = aBox.createResource("http://test.vivo/f"); aBox.add(a,OWL.sameAs,b); + aBox.add(b,OWL.sameAs,e); + aBox.add(e,OWL.sameAs,f); Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(e,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(e,OWL.sameAs,b)); + Assert.assertTrue(inf.contains(a,OWL.sameAs,e)); + Assert.assertTrue(inf.contains(f,OWL.sameAs,e)); + Assert.assertTrue(inf.contains(f,OWL.sameAs,b)); + Assert.assertTrue(inf.contains(f,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(b,OWL.sameAs,f)); + Assert.assertTrue(inf.contains(a,OWL.sameAs,f)); + aBox.add(a,P,c); aBox.add(a,S,literal1); @@ -196,24 +211,48 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { Assert.assertTrue(inf.contains(b,S,literal1)); Assert.assertTrue(inf.contains(a,Q,d)); Assert.assertTrue(inf.contains(a,T,literal2)); + Assert.assertTrue(inf.contains(e,P,c)); + Assert.assertTrue(inf.contains(e,S,literal1)); + Assert.assertTrue(inf.contains(e,Q,d)); + Assert.assertTrue(inf.contains(e,T,literal2)); + Assert.assertTrue(inf.contains(f,P,c)); + Assert.assertTrue(inf.contains(f,S,literal1)); + Assert.assertTrue(inf.contains(f,Q,d)); + Assert.assertTrue(inf.contains(f,T,literal2)); + + aBox.remove(b,OWL.sameAs,e); + + Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + Assert.assertFalse(inf.contains(e,OWL.sameAs,a)); + Assert.assertFalse(inf.contains(e,OWL.sameAs,b)); + Assert.assertFalse(inf.contains(a,OWL.sameAs,e)); + Assert.assertTrue(inf.contains(f,OWL.sameAs,e)); + Assert.assertFalse(inf.contains(f,OWL.sameAs,b)); + Assert.assertFalse(inf.contains(f,OWL.sameAs,a)); + Assert.assertFalse(inf.contains(b,OWL.sameAs,f)); + Assert.assertFalse(inf.contains(a,OWL.sameAs,f)); + + Assert.assertTrue(inf.contains(b,P,c)); + Assert.assertTrue(inf.contains(b,S,literal1)); + Assert.assertTrue(inf.contains(a,Q,d)); + Assert.assertTrue(inf.contains(a,T,literal2)); + Assert.assertFalse(inf.contains(e,P,c)); + Assert.assertFalse(inf.contains(e,S,literal1)); + Assert.assertFalse(inf.contains(e,Q,d)); + Assert.assertFalse(inf.contains(e,T,literal2)); + Assert.assertFalse(inf.contains(f,P,c)); + Assert.assertFalse(inf.contains(f,S,literal1)); + Assert.assertFalse(inf.contains(f,Q,d)); + Assert.assertFalse(inf.contains(f,T,literal2)); } /* - * adding abox assertion for individuals that are sameAs - * each other. + * sameAs with datatype properties */ @Test public void addABoxAssertion2() { OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - - OntClass classA = tBox.createClass("http://test.vivo/A"); - classA.setLabel("class A", "en-US"); - - OntClass classB = tBox.createClass("http://test.vivo/B"); - classB.setLabel("class B", "en-US"); - - classA.addSubClass(classB); - + OntProperty desc = tBox.createDatatypeProperty("http://test.vivo/desc"); desc.setLabel("property desc", "en-US"); @@ -230,18 +269,14 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { // Individuals a and b Resource a = aBox.createResource("http://test.vivo/a"); Resource b = aBox.createResource("http://test.vivo/b"); - + aBox.add(a,desc,desc1); aBox.add(b,desc,desc2); aBox.add(a,OWL.sameAs,b); - aBox.add(a, RDF.type, classB); Assert.assertTrue(inf.contains(a,desc,desc2)); - Assert.assertTrue(inf.contains(a,RDF.type,classA)); Assert.assertTrue(inf.contains(b,desc,desc1)); Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); - Assert.assertTrue(inf.contains(b,RDF.type,classB)); - Assert.assertTrue(inf.contains(b,RDF.type,classA)); } /* @@ -295,11 +330,11 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { } /* - * adding an inverseOf assertion for individuals who are sameAs - * each other. + * adding and removing an inverseOf assertion for individuals who + * are sameAs each other. */ @Test - public void addTBoxInverseAssertion1() throws InterruptedException { + public void tBoxInverseAssertion1() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox @@ -328,27 +363,275 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { // abox statements aBox.add(a,P,b); aBox.add(a, OWL.sameAs,b); - - // Assert P and Q as inverses and wait for SimpleReasoner TBox - // thread to end - + Q.addInverseOf(P); - tBox.rebind(); - tBox.prepare(); - while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { Thread.sleep(delay); } - - // Verify inferences + Assert.assertTrue(inf.contains(b,Q,a)); Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); Assert.assertTrue(inf.contains(b,P,b)); Assert.assertTrue(inf.contains(a,Q,a)); + + Q.removeInverseProperty(P); + + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + + Assert.assertFalse(inf.contains(b,Q,a)); + Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(b,P,b)); + Assert.assertFalse(inf.contains(a,Q,a)); + simpleReasonerTBoxListener.setStopRequested(); } + + /* + * adding and removing a type assertion for an individual who has + * a sameAs individual. + */ + //@Test + public void tBoxTypeAssertion1() throws InterruptedException { + + // Create a Tbox with a simple class hierarchy. B is a subclass of A. + // Pellet will compute TBox inferences + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + + OntClass classA = tBox.createClass("http://test.vivo/A"); + classA.setLabel("class A", "en-US"); + + OntClass classB = tBox.createClass("http://test.vivo/B"); + classB.setLabel("class B", "en-US"); + + classA.addSubClass(classB); + + // this is the model to receive inferences + Model inf = ModelFactory.createDefaultModel(); + + // create an ABox and register the SimpleReasoner listener with it + OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + aBox.register(new SimpleReasoner(tBox, aBox, inf)); + + Resource x = aBox.createResource("http://test.vivo/x"); + Resource y = aBox.createResource("http://test.vivo/y"); + Resource z = aBox.createResource("http://test.vivo/z"); + + aBox.add(x,OWL.sameAs,y); + aBox.add(y,OWL.sameAs,z); + aBox.add(x,RDF.type,classB); + + Assert.assertTrue(inf.contains(y,RDF.type,classB)); + Assert.assertTrue(inf.contains(y,RDF.type,classA)); + Assert.assertTrue(inf.contains(z,RDF.type,classB)); + Assert.assertTrue(inf.contains(z,RDF.type,classA)); + + aBox.remove(x,RDF.type,classB); + Assert.assertFalse(inf.contains(y,RDF.type,classB)); + Assert.assertFalse(inf.contains(y,RDF.type,classA)); + Assert.assertFalse(inf.contains(z,RDF.type,classB)); + Assert.assertFalse(inf.contains(z,RDF.type,classA)); + } + + /* + * adding and removing subclass assertion when there is an + * individual member who has a sameAs individual. + */ + @Test + public void tBoxSubclassAssertion1() throws InterruptedException { + + //create aBox and tBox, and SimpleReasoner to listen to them + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + Model inf = ModelFactory.createDefaultModel(); + + SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); + aBox.register(simpleReasoner); + SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); + tBox.register(simpleReasonerTBoxListener); + + // set up TBox + OntClass classA = tBox.createClass("http://test.vivo/A"); + classA.setLabel("class A", "en-US"); + OntClass classB = tBox.createClass("http://test.vivo/B"); + classB.setLabel("class B", "en-US"); + OntClass classC = tBox.createClass("http://test.vivo/C"); + classC.setLabel("class C", "en-US"); + + // set up ABox + Resource a = aBox.createResource("http://test.vivo/a"); + Resource b = aBox.createResource("http://test.vivo/b"); + Resource c = aBox.createResource("http://test.vivo/c"); + + aBox.add(a, RDF.type, classC); + aBox.add(a, OWL.sameAs, b); + aBox.add(c, OWL.sameAs, a); + + // update TBox + classA.addSubClass(classB); + + // wait for SimpleReasonerTBoxListener thread to end + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + + classB.addSubClass(classC); + classA.addSubClass(classC); // simulate what Pellet would infer, and + // thus what the SimpleReasonerTBoxListener + // would be notified of. + + // wait for SimpleReasonerTBoxListener thread to end + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + + // Verify inferences + Assert.assertFalse(inf.contains(a, RDF.type, classC)); + Assert.assertTrue(inf.contains(a, RDF.type, classB)); + Assert.assertTrue(inf.contains(a, RDF.type, classA)); + + Assert.assertTrue(inf.contains(b, RDF.type, classC)); + Assert.assertTrue(inf.contains(b, RDF.type, classB)); + Assert.assertTrue(inf.contains(b, RDF.type, classA)); + + Assert.assertTrue(inf.contains(c, RDF.type, classC)); + Assert.assertTrue(inf.contains(c, RDF.type, classB)); + Assert.assertTrue(inf.contains(c, RDF.type, classA)); + + // update TBox + classA.removeSubClass(classB); + classA.removeSubClass(classC); // simulate what Pellet would infer, and + // thus what the SimpleReasonerTBoxListener + // would be notified of. + + // wait for SimpleReasonerTBoxListener thread to end + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + + // Verify inferences + Assert.assertFalse(inf.contains(a, RDF.type, classC)); + Assert.assertTrue(inf.contains(a, RDF.type, classB)); + Assert.assertFalse(inf.contains(a, RDF.type, classA)); + + Assert.assertTrue(inf.contains(b, RDF.type, classC)); + Assert.assertTrue(inf.contains(b, RDF.type, classB)); + Assert.assertFalse(inf.contains(b, RDF.type, classA)); + + Assert.assertTrue(inf.contains(c, RDF.type, classC)); + Assert.assertTrue(inf.contains(c, RDF.type, classB)); + Assert.assertFalse(inf.contains(c, RDF.type, classA)); + + // update TBox + classB.removeSubClass(classC); + + // wait for SimpleReasonerTBoxListener thread to end + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + + // Verify inferences + Assert.assertFalse(inf.contains(a, RDF.type, classC)); + Assert.assertFalse(inf.contains(a, RDF.type, classB)); + Assert.assertFalse(inf.contains(a, RDF.type, classA)); + + Assert.assertTrue(inf.contains(b, RDF.type, classC)); + Assert.assertFalse(inf.contains(b, RDF.type, classB)); + Assert.assertFalse(inf.contains(b, RDF.type, classA)); + + Assert.assertTrue(inf.contains(c, RDF.type, classC)); + Assert.assertFalse(inf.contains(c, RDF.type, classB)); + Assert.assertFalse(inf.contains(c, RDF.type, classA)); + + simpleReasonerTBoxListener.setStopRequested(); + } + + /* + * test that mostSpecificType inferences propagate to sameAs + * individuals + */ + //@Test + public void mostSpecificTypeTest1() throws InterruptedException { + + // set up tbox. Pellet is reasoning; SimpleReasonerTBoxListener is not being used. + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); + + OntClass classA = tBox.createClass("http://test.vivo/A"); + classA.setLabel("class A", "en-US"); + OntClass classC = tBox.createClass("http://test.vivo/C"); + classC.setLabel("class C", "en-US"); + OntClass classD = tBox.createClass("http://test.vivo/D"); + classD.setLabel("class D", "en-US"); + OntClass classE = tBox.createClass("http://test.vivo/E"); + classE.setLabel("class E", "en-US"); + + classA.addSubClass(classC); + classC.addSubClass(classD); + classC.addSubClass(classE); + + // this will receive the abox inferences + Model inf = ModelFactory.createDefaultModel(); + + // abox + OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + + // set up SimpleReasoner and register it with abox + SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); + aBox.register(simpleReasoner); + + // add & remove ABox type statements and verify inferences + Resource a = aBox.createResource("http://test.vivo/a"); + Resource b = aBox.createResource("http://test.vivo/b"); + Resource c = aBox.createResource("http://test.vivo/c"); + Resource d = aBox.createResource("http://test.vivo/d"); + + aBox.add(a, OWL.sameAs, b); + aBox.add(c, OWL.sameAs, b); + aBox.add(d, OWL.sameAs, a); + + aBox.add(a, RDF.type, classD); + aBox.add(d, RDF.type, classC); + Assert.assertFalse(inf.contains(a,RDF.type,classD)); + Assert.assertTrue(inf.contains(a,RDF.type,classC)); + Assert.assertTrue(inf.contains(b,RDF.type, classD)); + Assert.assertTrue(inf.contains(b,RDF.type, classC)); + Assert.assertTrue(inf.contains(c,RDF.type, classD)); + Assert.assertTrue(inf.contains(c,RDF.type, classC)); + Assert.assertTrue(inf.contains(d,RDF.type, classD)); + Assert.assertFalse(inf.contains(d,RDF.type, classC)); + + Assert.assertTrue(inf.contains(a, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + Assert.assertTrue(inf.contains(b, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + Assert.assertTrue(inf.contains(c, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + Assert.assertTrue(inf.contains(d, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + Assert.assertFalse(inf.contains(a, mostSpecificType, ResourceFactory.createResource(classC.getURI()))); + Assert.assertFalse(inf.contains(b, mostSpecificType, ResourceFactory.createResource(classC.getURI()))); + Assert.assertFalse(inf.contains(c, mostSpecificType, ResourceFactory.createResource(classC.getURI()))); + Assert.assertFalse(inf.contains(d, mostSpecificType, ResourceFactory.createResource(classC.getURI()))); + + aBox.remove(a, RDF.type, classD); + Assert.assertFalse(inf.contains(a,RDF.type,classD)); + Assert.assertTrue(inf.contains(a,RDF.type,classC)); + Assert.assertFalse(inf.contains(b,RDF.type, classD)); + Assert.assertTrue(inf.contains(b,RDF.type, classC)); + Assert.assertFalse(inf.contains(c,RDF.type, classD)); + Assert.assertTrue(inf.contains(c,RDF.type, classC)); + Assert.assertFalse(inf.contains(d,RDF.type, classD)); + Assert.assertFalse(inf.contains(d,RDF.type, classC)); + Assert.assertTrue(inf.contains(a, mostSpecificType, ResourceFactory.createResource(classC.getURI()))); + Assert.assertTrue(inf.contains(b, mostSpecificType, ResourceFactory.createResource(classC.getURI()))); + Assert.assertTrue(inf.contains(c, mostSpecificType, ResourceFactory.createResource(classC.getURI()))); + Assert.assertTrue(inf.contains(d, mostSpecificType, ResourceFactory.createResource(classC.getURI()))); + Assert.assertFalse(inf.contains(a, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + Assert.assertFalse(inf.contains(b, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + Assert.assertFalse(inf.contains(c, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + Assert.assertFalse(inf.contains(d, mostSpecificType, ResourceFactory.createResource(classD.getURI()))); + } + /* * Basic scenario around recomputing the ABox inferences */ diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java index c36dd37f9..0c6427377 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java @@ -13,7 +13,6 @@ import com.hp.hpl.jena.ontology.AnnotationProperty; import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; -import com.hp.hpl.jena.ontology.OntProperty; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Resource; @@ -28,7 +27,6 @@ import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; public class SimpleReasonerTest extends AbstractTestClass { - private Resource objectProperty = ResourceFactory.createResource("http://www.w3.org/2002/07/owl#ObjectProperty"); private static final String mostSpecificTypePropertyURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#mostSpecificType"; long delay = 50; @@ -591,8 +589,12 @@ public class SimpleReasonerTest extends AbstractTestClass { * inference graph. * */ - //@Test - enable this in 1.5 - will need to add in PelletListener infrastructure - public void removeTBoxSubClassAssertion2() throws InterruptedException { + //@Test - this test would need PelletListener infrastructure, which we're not + // testing in this suite. The reason it doesn't work as it is because + // the SimpleReasonerTBoxListener is not listening to the tBox inference + // model as Pellet is updating it. I could simulate it by adding to the + // tBox assertions what we can count on Pellet to infer. + public void bcdTest() throws InterruptedException { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences @@ -621,6 +623,9 @@ public class SimpleReasonerTest extends AbstractTestClass { LivingThing.addSubClass(Flora); Flora.addSubClass(Brassica); + tBox.rebind(); + tBox.prepare(); + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { Thread.sleep(delay); } @@ -631,7 +636,9 @@ public class SimpleReasonerTest extends AbstractTestClass { // Remove the statement that Brassica is a subclass of Flora from the TBox Flora.removeSubClass(Brassica); - + + tBox.rebind(); + tBox.prepare(); while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { Thread.sleep(delay); } @@ -647,411 +654,6 @@ public class SimpleReasonerTest extends AbstractTestClass { simpleReasonerTBoxListener.setStopRequested(); } - /* - * tests rdfs:subPropertyOf materialization for object properties. - */ - // @Test uncomment when sub/equiv property inferencing is enabled. sjm222 5/13/2011 - public void addABoxAssertion1() throws InterruptedException { - - // Create TBox, ABox and Inference models and register - // the ABox reasoner listeners with the ABox and TBox - // Pellet will compute TBox inferences - - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - Model inf = ModelFactory.createDefaultModel(); - - SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); - aBox.register(simpleReasoner); - SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); - tBox.register(simpleReasonerTBoxListener); - - // Add object properties propA and propB to the TBox. - // propB is a sub-property of propA. - - OntProperty propA = tBox.createOntProperty("http://test.vivo/propA"); - tBox.add(propA, RDF.type, objectProperty); - propA.setLabel("propA", "en-US"); - - OntProperty propB = tBox.createOntProperty("http://test.vivo/propB"); - tBox.add(propB, RDF.type, objectProperty); - propB.setLabel("propB", "en-US"); - - propA.addSubProperty(propB); - - // Add the assertion that x propB y to the ABox - Resource ind_x = aBox.createResource("http://test.vivo/x"); - Resource ind_y = aBox.createResource("http://test.vivo/y"); - aBox.add(ind_x, propB, ind_y); - - // Verify that x propA y was inferred - Statement xay = ResourceFactory.createStatement(ind_x, propA, ind_y); - Assert.assertTrue(inf.contains(xay)); - } - - /* - * Test that when a statement is asserted, that it not - * added to the inference graph. - */ - // @Test uncomment when sub/equiv property inferencing is enabled. sjm222 5/13/2011 - public void addABoxAssertion2(){ - - // Create TBox, ABox and Inference models and register - // the ABox reasoner listeners with the ABox and TBox - // Pellet will compute TBox inferences - - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - Model inf = ModelFactory.createDefaultModel(); - - SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); - aBox.register(simpleReasoner); - SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); - tBox.register(simpleReasonerTBoxListener); - - // Add object properties propA and propB to the TBox. - // propB is a sub-property of propA. - - OntProperty propA = tBox.createOntProperty("http://test.vivo/propA"); - tBox.add(propA, RDF.type, objectProperty); - propA.setLabel("propA", "en-US"); - - OntProperty propB = tBox.createOntProperty("http://test.vivo/propB"); - tBox.add(propB, RDF.type, objectProperty); - propB.setLabel("propB", "en-US"); - - propA.addSubProperty(propB); - - // Add the assertion that x propB y to the ABox - Resource ind_x = aBox.createResource("http://test.vivo/x"); - Resource ind_y = aBox.createResource("http://test.vivo/y"); - aBox.add(ind_x, propB, ind_y); - - // Verify that x propA y was inferred - Statement xby = ResourceFactory.createStatement(ind_x, propB, ind_y); - Assert.assertFalse(inf.contains(xby)); - } - - /* - * Test inference based on property equivalence - */ - // @Test uncomment when sub/equiv property inferencing is enabled. sjm222 5/13/2011 - public void addABoxAssertion4(){ - - // Create TBox, ABox and Inference models and register - // the ABox reasoner listeners with the ABox and TBox - // Pellet will compute TBox inferences - - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - Model inf = ModelFactory.createDefaultModel(); - - SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); - aBox.register(simpleReasoner); - SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); - tBox.register(simpleReasonerTBoxListener); - - // Add properties A, B and C to the TBox - // A is equivalent to B - // C is a subclass of A - - OntProperty propA = tBox.createOntProperty("http://test.vivo/A"); - tBox.add(propA, RDF.type, objectProperty); - propA.setLabel("property A", "en-US"); - - OntProperty propB = tBox.createOntProperty("http://test.vivo/B"); - tBox.add(propB, RDF.type, objectProperty); - propB.setLabel("property B", "en-US"); - - OntProperty propC = tBox.createOntProperty("http://test.vivo/C"); - tBox.add(propC, RDF.type, objectProperty); - propC.setLabel("property C", "en-US"); - - propA.addEquivalentProperty(propB); - propA.addSubProperty(propC); - - // Add a statement that individual x is of type C to the ABox - Resource ind_x = aBox.createResource("http://test.vivo/x"); - Resource ind_y = aBox.createResource("http://test.vivo/y"); - - aBox.add(ind_x, propC, ind_y); - - // Verify that "x A y" was inferred - Statement xAy = ResourceFactory.createStatement(ind_x, propA, ind_y); - Assert.assertTrue(inf.contains(xAy)); - - // Verify that "x B y" was inferred - Statement xBy = ResourceFactory.createStatement(ind_x, propB, ind_y); - Assert.assertTrue(inf.contains(xBy)); - } - - /* - * The sub-property is not of the same type as the super - * property so no inference should be materialized. - */ - - // @Test uncomment when sub/equiv property inferencing is enabled. sjm222 5/13/2011 - public void addABoxAssertion5(){ - - // Create TBox, ABox and Inference models and register - // the ABox reasoner listeners with the ABox and TBox - // Pellet will compute TBox inferences - - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - Model inf = ModelFactory.createDefaultModel(); - - SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); - aBox.register(simpleReasoner); - SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); - tBox.register(simpleReasonerTBoxListener); - - // Add object properties propA and propB to the TBox. - // propB is a sub-property of propA. - - OntProperty propA = tBox.createOntProperty("http://test.vivo/propA"); - tBox.add(propA, RDF.type, objectProperty); - propA.setLabel("propA", "en-US"); - - OntProperty propB = tBox.createOntProperty("http://test.vivo/propB"); - Resource datatypeProperty = ResourceFactory.createResource("http://www.w3.org/2002/07/owl#DatatypeProperty"); - tBox.add(propB, RDF.type, datatypeProperty); - propB.setLabel("propB", "en-US"); - - propA.addSubProperty(propB); - - // Add the assertion that x propB y to the ABox - Resource ind_x = aBox.createResource("http://test.vivo/x"); - Resource ind_y = aBox.createResource("http://test.vivo/y"); - aBox.add(ind_x, propB, ind_y); - - // Verify that x propA y was not inferred - Statement xay = ResourceFactory.createStatement(ind_x, propA, ind_y); - Assert.assertFalse(inf.contains(xay)); - } - - /* - * Test inference based on property equivalence - */ - // @Test uncomment when sub/equiv property inferencing is enabled. sjm222 5/13/2011 - public void addABoxAssertion6() { - - // Create TBox, ABox and Inference models and register - // the ABox reasoner listeners with the ABox and TBox - // Pellet will compute TBox inferences - - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - Model inf = ModelFactory.createDefaultModel(); - - SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); - aBox.register(simpleReasoner); - SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); - tBox.register(simpleReasonerTBoxListener); - - // Add properties A and B to the TBox - // A is equivalent to B - - OntProperty propA = tBox.createOntProperty("http://test.vivo/A"); - tBox.add(propA, RDF.type, objectProperty); - propA.setLabel("property A", "en-US"); - - OntProperty propB = tBox.createOntProperty("http://test.vivo/B"); - tBox.add(propB, RDF.type, objectProperty); - propB.setLabel("property B", "en-US"); - - propA.addEquivalentProperty(propB); - - // Add the statement x B y to the ABox - Resource ind_x = aBox.createResource("http://test.vivo/x"); - Resource ind_y = aBox.createResource("http://test.vivo/y"); - aBox.add(ind_x, propB, ind_y); - - // Verify that "x A y" was inferred - Statement xAy = ResourceFactory.createStatement(ind_x, propA, ind_y); - Assert.assertTrue(inf.contains(xAy)); - - // Remove the statement that x B y from the ABox - aBox.remove(ind_x, propB, ind_y); - - // Verify that "x is of type A" was removed from the inference graph - Assert.assertFalse(inf.contains(xAy)); - } - - - /* - * Test the addition of a subPropertyOf statement to - * the TBox. The instance data that is the basis - * for the inference is in the ABox. - * - * Since the addition of an owl:equivalentProperty - * statement is implemented as two calls to the - * method that handles the addition of an - * rdfs:subPropetyOf statement, this test serves - * as a test of equivalentProperty assertions also. - */ - // @Test uncomment when sub/equiv property inferencing is enabled. sjm222 5/13/2011 - public void addTBoxSubPropertyAssertion1(){ - - // Create TBox, ABox and Inference models and register - // the ABox reasoner listeners with the ABox and TBox - // Pellet will compute TBox inferences - - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - Model inf = ModelFactory.createDefaultModel(); - - SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); - aBox.register(simpleReasoner); - SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); - tBox.register(simpleReasonerTBoxListener); - - // Add properties A, B, C and D to the TBox - OntProperty propA = tBox.createOntProperty("http://test.vivo/A"); - tBox.add(propA, RDF.type, objectProperty); - propA.setLabel("property A", "en-US"); - - OntProperty propB = tBox.createOntProperty("http://test.vivo/B"); - tBox.add(propB, RDF.type, objectProperty); - propB.setLabel("property B", "en-US"); - - OntProperty propC = tBox.createOntProperty("http://test.vivo/C"); - tBox.add(propC, RDF.type, objectProperty); - propB.setLabel("property C", "en-US"); - - OntProperty propD = tBox.createOntProperty("http://test.vivo/D"); - tBox.add(propD, RDF.type, objectProperty); - propB.setLabel("property D", "en-US"); - - // Add the statement "x C y" to the ABox - Resource ind_x = aBox.createResource("http://test.vivo/x"); - Resource ind_y = aBox.createResource("http://test.vivo/y"); - aBox.add(ind_x, propC, ind_y); - - // Add a statement that C is a sub-property of A to the TBox - - propA.addSubProperty(propC); - - // Verify that "x A y" was inferred - Statement xAy = ResourceFactory.createStatement(ind_x, propA, ind_y); - Assert.assertTrue(inf.contains(xAy)); - - // Verify that "x B y" was not inferred - Statement xBy = ResourceFactory.createStatement(ind_x, propB, ind_y); - Assert.assertFalse(inf.contains(xBy)); - - // Verify that "x D y" was not inferred - Statement xDy = ResourceFactory.createStatement(ind_x, propD, ind_y); - Assert.assertFalse(inf.contains(xDy)); - - } - - /* - * Test the removal of a subPropertyOf statement from - * the TBox. The instance data that is the basis - * for the inference is in the ABox graph and the - * inference graph. - * - * Since the addition of an owl:equivalentProperty - * statement is implemented as two calls to the - * method that handles the addition of an - * rdfs:subPropertyOf statement, this test serves - * as a test of equivalentProperty assertions also. - * - */ - // @Test uncomment when sub/equiv property inferencing is enabled. sjm222 5/13/2011 - public void removeTBoxSubPropertyAssertion1(){ - // Create TBox, ABox and Inference models and register - // the ABox reasoner listeners with the ABox and TBox - // Pellet will compute TBox inferences - - OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); - OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - Model inf = ModelFactory.createDefaultModel(); - - SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); - aBox.register(simpleReasoner); - SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); - tBox.register(simpleReasonerTBoxListener); - - // Add properties A, B, C, D, E, F, G and H to the TBox. - // B, C and D are subproperties of A. - // E is a subproperty of B. - // F and G are subproperties of C. - // H is a subproperty of D. - - OntProperty propA = tBox.createOntProperty("http://test.vivo/A"); - tBox.add(propA, RDF.type, objectProperty); - propA.setLabel("property A", "en-US"); - - OntProperty propB = tBox.createOntProperty("http://test.vivo/B"); - tBox.add(propB, RDF.type, objectProperty); - propB.setLabel("property B", "en-US"); - - OntProperty propC = tBox.createOntProperty("http://test.vivo/C"); - tBox.add(propC, RDF.type, objectProperty); - propB.setLabel("property C", "en-US"); - - OntProperty propD = tBox.createOntProperty("http://test.vivo/D"); - tBox.add(propD, RDF.type, objectProperty); - propB.setLabel("property D", "en-US"); - - OntProperty propE = tBox.createOntProperty("http://test.vivo/E"); - tBox.add(propE, RDF.type, objectProperty); - propB.setLabel("property E", "en-US"); - - OntProperty propF = tBox.createOntProperty("http://test.vivo/F"); - tBox.add(propF, RDF.type, objectProperty); - propB.setLabel("property F", "en-US"); - - OntProperty propG = tBox.createOntProperty("http://test.vivo/G"); - tBox.add(propG, RDF.type, objectProperty); - propB.setLabel("property G", "en-US"); - - OntProperty propH = tBox.createOntProperty("http://test.vivo/H"); - tBox.add(propH, RDF.type, objectProperty); - propB.setLabel("property H", "en-US"); - - propA.addSubProperty(propB); - propA.addSubProperty(propC); - propA.addSubProperty(propD); - propB.addSubProperty(propE); - propC.addSubProperty(propF); - propC.addSubProperty(propG); - propD.addSubProperty(propH); - - // Add the statement "x E y" to the ABox - Resource ind_x = aBox.createResource("http://test.vivo/x"); - Resource ind_y = aBox.createResource("http://test.vivo/y"); - aBox.add(ind_x, propE, ind_y); - - // Remove the statement that B is a subproperty of A from the TBox - propA.removeSubProperty(propB); - - // Verify that "x A y" is not in the inference graph - Statement xAy = ResourceFactory.createStatement(ind_x, propA, ind_y); - Assert.assertFalse(inf.contains(xAy)); - - // Verify that "x B y" is in the inference graph - Statement xBy = ResourceFactory.createStatement(ind_x, propB, ind_y); - Assert.assertTrue(inf.contains(xBy)); - - // Add statements "w F z" and "w H z" to the ABox - Resource ind_z = aBox.createResource("http://test.vivo/z"); - Resource ind_w = aBox.createResource("http://test.vivo/w"); - aBox.add(ind_w, propF, ind_z); - aBox.add(ind_w, propH, ind_z); - - // Remove the statement that C is a subproperty of A from the TBox - propA.removeSubProperty(propC); - - // Verify that "w A z" is in the inference graph - Statement wAz = ResourceFactory.createStatement(ind_w, propA, ind_z); - Assert.assertTrue(inf.contains(wAz)); - } - - - /* * Test computation of mostSpecificType annotations in response * to an added/removed ABox type assertion.