diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerPluginTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerPluginTest.java new file mode 100644 index 000000000..82c1fdf97 --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerPluginTest.java @@ -0,0 +1,145 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.reasoner; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Level; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mindswap.pellet.jena.PelletReasonerFactory; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.ontology.OntModelSpec; +import com.hp.hpl.jena.ontology.OntProperty; +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.Property; +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.RDFS; + +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; + +public class SimpleReasonerPluginTest extends AbstractTestClass { + long delay = 50; + + private final static String DEFAULT_NS = "http://vivoweb.org/individual/"; + + private final static String DCTERMS_NS = "http://purl.org/dc/terms/"; + private final static String VIVOCORE_NS = "http://vivoweb.org/ontology/core#"; + + private final static String creator_URI = DCTERMS_NS + "creator"; + private final static String authorInAuthorship_URI = VIVOCORE_NS + "authorInAuthorship"; + private final static String linkedAuthor_URI = VIVOCORE_NS + "linkedAuthor"; + private final static String informationResourceInAuthorship_URI = VIVOCORE_NS + "informationResourceInAuthorship"; + private final static String linkedInformationResource_URI = VIVOCORE_NS + "linkedInformationResource"; + + @Before + public void suppressErrorOutput() { + //suppressSyserr(); + //Turn off log messages to console + setLoggerLevel(SimpleReasoner.class, Level.DEBUG); + setLoggerLevel(SimpleReasonerTBoxListener.class, Level.DEBUG); + } + + /* + * testing samplePlugin - based on dcterms:creator plugin + * + */ + @Test + public void test1() { + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + + OntProperty authorInAuthorship = tBox.createObjectProperty(authorInAuthorship_URI); + OntProperty linkedAuthor = tBox.createObjectProperty(linkedAuthor_URI); + OntProperty informationResourceInAuthorship = tBox.createObjectProperty(informationResourceInAuthorship_URI); + OntProperty linkedInformationResource = tBox.createObjectProperty(linkedInformationResource_URI); + + authorInAuthorship.addInverseOf(linkedAuthor); + informationResourceInAuthorship.addInverseOf(linkedInformationResource); + + Literal title1 = tBox.createLiteral("My Findings"); + Literal name1 = tBox.createLiteral("Priscilla Powers"); + + // 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); + SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); + aBox.register(simpleReasoner); + + // register plugin with SimpleReasoner + List pluginList = new ArrayList(); + String pluginClassName = "edu.cornell.mannlib.vitro.webapp.reasoner.plugin.SamplePlugin"; + + try { + ReasonerPlugin plugin = (ReasonerPlugin) Class.forName(pluginClassName).getConstructors()[0].newInstance(); + plugin.setSimpleReasoner(simpleReasoner); + pluginList.add(plugin); + simpleReasoner.setPluginList(pluginList); + } catch (Exception e) { + System.out.println("Exception trying to instantiate plugin: " + e.getMessage()); + e.printStackTrace(); + return; + } + + Property dctermsCreator = ResourceFactory.createProperty(creator_URI); + + // add abox data for person, authorship and article. + // note, they aren't actually typed in this test tbox + Resource prissy = aBox.createResource(DEFAULT_NS + "prissy"); + + // assert same as + + Resource authorship1 = aBox.createResource(DEFAULT_NS + "authorship1"); + Resource article1 = aBox.createResource(DEFAULT_NS + "article1"); + Resource article100 = aBox.createResource(DEFAULT_NS + "article100"); + + aBox.add(prissy,RDFS.label,name1); + aBox.add(prissy,authorInAuthorship,authorship1); + + aBox.add(authorship1,linkedAuthor,prissy); + aBox.add(authorship1,linkedInformationResource,article1); + + aBox.add(article1,RDFS.label,title1); + aBox.add(article1,informationResourceInAuthorship,authorship1); + aBox.add(article1, OWL.sameAs, article100); + + Assert.assertTrue(inf.contains(article1,dctermsCreator,prissy)); + Assert.assertTrue(inf.contains(article100,dctermsCreator,prissy)); + + aBox.remove(authorship1,linkedAuthor,prissy); + + Assert.assertFalse(inf.contains(article1,dctermsCreator,prissy)); + Assert.assertFalse(inf.contains(article100,dctermsCreator,prissy)); + } + + + //==================================== Utility methods ==================== + SimpleReasonerTBoxListener getTBoxListener(SimpleReasoner simpleReasoner) { + return new SimpleReasonerTBoxListener(simpleReasoner, new Exception().getStackTrace()[1].getMethodName()); + } + + // To help in debugging the unit test + void printModel(Model model, String modelName) { + + System.out.println("\nThe " + modelName + " model has " + model.size() + " statements:"); + System.out.println("---------------------------------------------------------------------"); + model.write(System.out); + } + + // To help in debugging the unit test + void printModel(OntModel ontModel, String modelName) { + + System.out.println("\nThe " + modelName + " model has " + ontModel.size() + " statements:"); + System.out.println("---------------------------------------------------------------------"); + ontModel.writeAll(System.out,"N3",null); + + } +} \ No newline at end of file diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SamplePlugin.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SamplePlugin.java new file mode 100644 index 000000000..e49d9bd2d --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SamplePlugin.java @@ -0,0 +1,18 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + + +package edu.cornell.mannlib.vitro.webapp.reasoner.plugin; + +import edu.cornell.mannlib.vitro.webapp.reasoner.ReasonerPlugin; + +public class SamplePlugin extends SimpleBridgingRule implements ReasonerPlugin { + + private final static String DCTERMS = "http://purl.org/dc/terms/"; + private final static String VIVOCORE = "http://vivoweb.org/ontology/core#"; + + public SamplePlugin() { + super(VIVOCORE + "informationResourceInAuthorship", + VIVOCORE + "linkedAuthor", + DCTERMS + "creator"); + } +} diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimpleBridgingRule.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimpleBridgingRule.java new file mode 100644 index 000000000..5528d6ecd --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimpleBridgingRule.java @@ -0,0 +1,136 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.reasoner.plugin; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.QueryExecution; +import com.hp.hpl.jena.query.QueryExecutionFactory; +import com.hp.hpl.jena.query.QueryFactory; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.ResourceFactory; +import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.rdf.model.StmtIterator; + +import edu.cornell.mannlib.vitro.webapp.reasoner.ReasonerPlugin; +import edu.cornell.mannlib.vitro.webapp.reasoner.SimpleReasoner; + +/** + * handles rules of the form + * assertedProp1(?x, ?y) ^ assertedProp2(?y, ?z) -> inferredProp(?x, ?z) + * + */ +public abstract class SimpleBridgingRule implements ReasonerPlugin { + + private Property assertedProp1; + private Property assertedProp2; + private String queryStr; + private SimpleReasoner simpleReasoner; + + protected SimpleBridgingRule(String assertedProp1, String assertedProp2, String inferredProp) { + this.assertedProp1 = ResourceFactory.createProperty(assertedProp1); + this.assertedProp2 = ResourceFactory.createProperty(assertedProp2); + + this.queryStr = "CONSTRUCT { \n" + + " ?x <" + inferredProp + "> ?z \n" + + "} WHERE { \n" + + " ?x <" + assertedProp1 + "> ?y . \n" + + " ?y <" + assertedProp2 + "> ?z \n" + + "}"; + } + + public boolean isInterestedInAddedStatement(Statement stmt) { + return isRelevantPredicate(stmt); + } + + public boolean isInterestedInRemovedStatement(Statement stmt) { + return isRelevantPredicate(stmt); + } + + public void addedABoxStatement(Statement stmt, + Model aboxAssertionsModel, + Model aboxInferencesModel, + OntModel TBoxInferencesModel) { + if (ignore(stmt)) { + return; + } + Model inf = constructInferences(stmt, aboxAssertionsModel); + StmtIterator sit = inf.listStatements(); + while(sit.hasNext()) { + Statement s = sit.nextStatement(); + if (simpleReasoner != null) simpleReasoner.addInference(s,aboxInferencesModel); + } + } + + private boolean ignore(Statement stmt) { + return ( + (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) + // can't deal with blank nodes + || + (!stmt.getObject().isResource()) + // don't deal with literal values + ); + } + + private Model constructInferences(Statement stmt, Model aboxAssertionsModel) { + String queryStr = new String(this.queryStr); + if (stmt.getPredicate().equals(assertedProp1)) { + queryStr = queryStr.replace( + "?x", "<" + stmt.getSubject().getURI() + ">"); + queryStr = queryStr.replace( + "?y", "<" + ((Resource) stmt.getObject()).getURI() + ">"); + } else if (stmt.getPredicate().equals(assertedProp2)) { + queryStr = queryStr.replace( + "?y", "<" + stmt.getSubject().getURI() + ">"); + queryStr = queryStr.replace( + "?z", "<" + ((Resource) stmt.getObject()).getURI() + ">"); + } else { + // should never be here + return ModelFactory.createDefaultModel(); + } + Query query = QueryFactory.create(queryStr); + QueryExecution qe = QueryExecutionFactory.create(query, aboxAssertionsModel); + try { + return qe.execConstruct(); + } finally { + qe.close(); + } + + } + + public void removedABoxStatement(Statement stmt, + Model aboxAssertionsModel, + Model aboxInferencesModel, + OntModel TBoxInferencesModel) { + if (ignore(stmt)) { + return; + } + Model m = ModelFactory.createDefaultModel(); + m.add(stmt); + Model union = ModelFactory.createUnion(m, aboxAssertionsModel); + + Model inf = constructInferences(stmt, union); + StmtIterator sit = inf.listStatements(); + while(sit.hasNext()) { + Statement s = sit.nextStatement(); + if (simpleReasoner != null) simpleReasoner.removeInference(s,aboxInferencesModel); + } + } + + private boolean isRelevantPredicate(Statement stmt) { + return (assertedProp1.equals(stmt.getPredicate()) + || assertedProp2.equals(stmt.getPredicate())); + } + + public void setSimpleReasoner(SimpleReasoner simpleReasoner) { + this.simpleReasoner = simpleReasoner; + } + + public SimpleReasoner getSimpleReasoner() { + return this.simpleReasoner; + } +} +