You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by wi...@apache.org on 2014/06/13 10:57:43 UTC
[023/100] [abbrv] [partial] Reverting the erroneous merge by
Sebastian according to the instructions in INFRA-6876
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/engine/ReasoningEngine.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/engine/ReasoningEngine.java b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/engine/ReasoningEngine.java
index dd42ae5..69d6cde 100644
--- a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/engine/ReasoningEngine.java
+++ b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/engine/ReasoningEngine.java
@@ -17,22 +17,22 @@
*/
package org.apache.marmotta.kiwi.reasoner.engine;
+import com.google.common.base.Equivalence;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
import info.aduna.iteration.CloseableIteration;
import info.aduna.iteration.EmptyIteration;
import info.aduna.iteration.Iterations;
import info.aduna.iteration.SingletonIteration;
+import org.apache.marmotta.commons.sesame.model.StatementCommons;
import org.apache.marmotta.kiwi.model.caching.TripleTable;
import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
import org.apache.marmotta.kiwi.model.rdf.KiWiResource;
import org.apache.marmotta.kiwi.model.rdf.KiWiTriple;
import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
-import org.apache.marmotta.kiwi.reasoner.model.program.Justification;
-import org.apache.marmotta.kiwi.reasoner.model.program.LiteralField;
-import org.apache.marmotta.kiwi.reasoner.model.program.Pattern;
-import org.apache.marmotta.kiwi.reasoner.model.program.Program;
-import org.apache.marmotta.kiwi.reasoner.model.program.ResourceField;
-import org.apache.marmotta.kiwi.reasoner.model.program.Rule;
-import org.apache.marmotta.kiwi.reasoner.model.program.VariableField;
+import org.apache.marmotta.kiwi.reasoner.model.exception.ReasoningException;
+import org.apache.marmotta.kiwi.reasoner.model.exception.UnjustifiedTripleException;
+import org.apache.marmotta.kiwi.reasoner.model.program.*;
import org.apache.marmotta.kiwi.reasoner.model.query.QueryResult;
import org.apache.marmotta.kiwi.reasoner.persistence.KiWiReasoningConnection;
import org.apache.marmotta.kiwi.reasoner.persistence.KiWiReasoningPersistence;
@@ -51,14 +51,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -121,24 +114,32 @@ public class ReasoningEngine implements TransactionListener {
* In-memory cache to store all patterns that are candidates for matching triples and accessing the rules
* they belong to.
*/
- private Map<Pattern,Rule> patternRuleMap;
+ private Multimap<Pattern,Rule> patternRuleMap;
/**
* Internal counter to count executions of the reasoner (informational purposes only)
*/
private static long taskCounter = 0;
+ private boolean isshutdown = false;
/**
* The worker thread for the reasoner.
*/
private SKWRLReasoner reasonerThread;
+ protected static Equivalence<Statement> equivalence = StatementCommons.quadrupleEquivalence();
+
/**
* A lock to ensure that only once thread at a time is carrying out persistence
*/
private Lock persistenceLock;
+ // for mocking
+ protected ReasoningEngine() {
+
+ }
+
public ReasoningEngine(KiWiReasoningPersistence persistence, TransactionalSail store, ReasoningConfiguration config) {
this.persistence = persistence;
this.store = store;
@@ -153,7 +154,7 @@ public class ReasoningEngine implements TransactionListener {
public void loadPrograms() {
log.info("program configuration changed, reloading ...");
- patternRuleMap = new HashMap<Pattern, Rule>();
+ patternRuleMap = HashMultimap.<Pattern,Rule>create();
try {
KiWiReasoningConnection connection = persistence.getConnection();
@@ -311,7 +312,6 @@ public class ReasoningEngine implements TransactionListener {
/**
* Stop the currently active reasoning task. Informational purposes only.
- * @param name
*/
protected void endTask() {
@@ -344,58 +344,59 @@ public class ReasoningEngine implements TransactionListener {
}
private void executeReasoner(TransactionData data) {
- updateTaskStatus("fetching worklist");
- Set<KiWiTriple> newTriples = new HashSet<KiWiTriple>();
- for(Statement stmt : data.getAddedTriples()) {
- KiWiTriple t = (KiWiTriple)stmt;
- if(t.isMarkedForReasoning()) {
- newTriples.add(t);
- t.setMarkedForReasoning(false);
+ try {
+ updateTaskStatus("fetching worklist");
+ Set<KiWiTriple> newTriples = StatementCommons.newQuadrupleSet();
+ for(Statement stmt : data.getAddedTriples()) {
+ KiWiTriple t = (KiWiTriple)stmt;
+ if(t.isMarkedForReasoning()) {
+ newTriples.add(t);
+ t.setMarkedForReasoning(false);
+ }
}
- }
- //taskManagerService.setTaskSteps(newTriples.size() + data.getRemovedTriples().size());
- // evaluate the rules for all added triples
- if(newTriples.size() > 0) {
- long start2 = System.currentTimeMillis();
- updateTaskStatus("reasoning over " + newTriples.size() + " new triples");
- processRules(newTriples);
- log.debug("REASONER: reasoning for {} new triples took {} ms overall",newTriples.size(),System.currentTimeMillis()-start2);
- }
+ //taskManagerService.setTaskSteps(newTriples.size() + data.getRemovedTriples().size());
+ // evaluate the rules for all added triples
+ if(newTriples.size() > 0) {
+ long start2 = System.currentTimeMillis();
+ updateTaskStatus("reasoning over " + newTriples.size() + " new triples");
+ processRules(newTriples);
+ log.debug("REASONER: reasoning for {} new triples took {} ms overall", newTriples.size(), System.currentTimeMillis() - start2);
+ }
- if(data.getRemovedTriples().size() > 0) {
- log.debug("cleaning up justifications and inferences for {} triples",data.getRemovedTriples().size());
- try {
- KiWiReasoningConnection connection = persistence.getConnection();
+ if(data.getRemovedTriples().size() > 0) {
+ log.debug("cleaning up justifications and inferences for {} triples",data.getRemovedTriples().size());
try {
- // first clean up justifications that are no longer supported
- cleanupJustifications(connection, data.getRemovedTriples());
-
-
- // then remove all inferred triples that are no longer supported
- cleanupUnsupported(connection);
-
- // and finally garbage collect those triples that are inferred and deleted
- // garbage collection is now carried out by a thread in the triple store
- //garbageCollectTriples();
- connection.commit();
- } catch (SQLException ex) {
- connection.rollback();
+ KiWiReasoningConnection connection = persistence.getConnection();
+ try {
+ // first clean up justifications that are no longer supported
+ cleanupJustifications(connection, data.getRemovedTriples());
+
+
+ // then remove all inferred triples that are no longer supported
+ cleanupUnsupported(connection);
+
+ // and finally garbage collect those triples that are inferred and deleted
+ // garbage collection is now carried out by a thread in the triple store
+ //garbageCollectTriples();
+ connection.commit();
+ } catch (SQLException ex) {
+ connection.rollback();
+ throw ex;
+ } finally {
+ connection.close();
+ }
+ } catch (SailException | SQLException ex) {
+ log.error("REASONING ERROR: could not clean up unsupported triples, database state will be inconsistent! Message: {}", ex.getMessage());
+ log.debug("Exception details:", ex);
throw ex;
- } finally {
- connection.close();
}
- } catch (SailException ex) {
- log.error("REPOSITORY ERROR: could not clean up unsupported triples, database state will be inconsistent! Message: {}", ex.getMessage());
- log.debug("Exception details:", ex);
- } catch (SQLException ex) {
- log.error("DATABASE ERROR: could not clean up justifications for triples, database state will be inconsistent! Message: {}", ex.getMessage());
- log.debug("Exception details:", ex);
- }
+ }
+ } catch (SQLException | SailException | ReasoningException ex) {
+ log.error("REASONER: processing of transaction data with ID {} aborted; reason: {}", data.getTransactionId(), ex.getMessage());
}
-
}
/**
@@ -483,40 +484,12 @@ public class ReasoningEngine implements TransactionListener {
}
- /**
- * Store new justifications in the database. The method performs a batched operation to avoid
- * excessive resource use.
- *
- * @param justifications
- */
- private void storeJustifications(Iterable<Justification> justifications) {
- // persist the justifications that have been created in the rule processing
- long counter = 0;
- updateTaskStatus("storing new justifications ...");
-
- try {
- KiWiReasoningConnection connection = persistence.getConnection();
- try {
- connection.storeJustifications(justifications);
- connection.commit();
- } catch (SQLException ex) {
- connection.rollback();
- throw ex;
- } finally {
- connection.close();
- }
- } catch (SQLException ex) {
- log.error("DATABASE ERROR: could not add new justifications for triples, database state will be inconsistent! Message: {}",ex.getMessage());
- log.debug("Exception details:",ex);
- }
- }
-
/**
* This method iterates over all triples that are passed as argument and
* checks whether they are used as supporting triples justifications. All
* such justifications are removed. Triples that are no longer supported
- * will later be cleaned up by {@link #cleanupUnsupported()}
+ * will later be cleaned up by {@link #cleanupUnsupported(org.apache.marmotta.kiwi.reasoner.persistence.KiWiReasoningConnection)}
*
* @param removedTriples
*/
@@ -541,24 +514,30 @@ public class ReasoningEngine implements TransactionListener {
updateTaskStatus("loading unsupported triples");
CloseableIteration<KiWiTriple,SQLException> tripleIterator = connection.listUnsupportedTriples();
-
- updateTaskStatus("deleting unsupported triples");
- SailConnection tc = store.getConnection();
- KiWiSailConnection ic = getWrappedConnection(tc);
try {
- tc.begin();
- while(tripleIterator.hasNext()) {
- ic.removeInferredStatement(tripleIterator.next());
- count++;
+ if(tripleIterator.hasNext()) {
+
+ updateTaskStatus("deleting unsupported triples");
+ SailConnection tc = store.getConnection();
+ KiWiSailConnection ic = getWrappedConnection(tc);
+ try {
+ tc.begin();
+ while(tripleIterator.hasNext()) {
+ ic.removeInferredStatement(tripleIterator.next());
+ count++;
+ }
+ log.debug("removed {} unsupported triples",count);
+ tc.commit();
+ } catch(SailException ex) {
+ ic.rollback();
+ throw ex;
+ } finally {
+ ic.close();
+ }
}
- log.debug("removed {} unsupported triples",count);
- tc.commit();
- } catch(SailException ex) {
- ic.rollback();
- throw ex;
} finally {
Iterations.closeCloseable(tripleIterator);
- ic.close();
+
}
}
@@ -567,43 +546,20 @@ public class ReasoningEngine implements TransactionListener {
*
* @param addedTriples
*/
- private void processRules(final Set<KiWiTriple> addedTriples) {
- try {
- updateTaskStatus("processing rules ...");
- // select the rules that have at least one matching pattern; the match method will
- // return a set of variable bindings that we will be used to prepopulate the bindings
-// Set<Callable<Boolean>> tasks = new HashSet<Callable<Boolean>>();
- for(final Pattern pattern : patternRuleMap.keySet()) {
- for(KiWiTriple triple : addedTriples) {
- QueryResult match = matches(pattern,triple);
- if(match != null) {
- log.debug("pattern {} matched with triple {}", pattern.toString(), triple.toString());
- processRule(patternRuleMap.get(pattern), match, pattern);
+ private void processRules(final Set<KiWiTriple> addedTriples) throws SQLException, SailException, ReasoningException {
+ updateTaskStatus("processing rules ...");
+ // select the rules that have at least one matching pattern; the match method will
+ // return a set of variable bindings that we will be used to prepopulate the bindings
+ for(final Pattern pattern : patternRuleMap.keySet()) {
+ for(KiWiTriple triple : addedTriples) {
+ QueryResult match = matches(pattern,triple);
+ if(match != null) {
+ for(Rule rule : patternRuleMap.get(pattern)) {
+ log.debug("REASONER(rule '{}'): pattern {} matched with triple {}", rule.getName(), pattern.toString(), triple.toString());
+ processRule(rule, match, pattern);
}
}
- // TODO: for parallel reasoning, the problem is that we should only create one thread per rule and not
- // one per pattern, otherwise we can get duplicates because the same rule is evaluated twice
-/*
- tasks.add(new Callable<Boolean>() {
- @Override
- public Boolean call() throws Exception {
- for(KiWiTriple triple : addedTriples) {
- QueryResult match = matches(pattern,triple);
- if(match != null) {
- log.debug("pattern {} matched with triple {}", pattern.toString(), triple.toString());
- processRule(patternRuleMap.get(pattern), match, pattern);
- }
- }
-
- return Boolean.TRUE;
- }
- });
-*/
}
- //workers.invokeAll(tasks);
-
- } catch(Exception ex) {
- log.error("error while processing rules",ex);
}
}
@@ -615,10 +571,10 @@ public class ReasoningEngine implements TransactionListener {
* @param rule
* @param match
*/
- private void processRule(Rule rule, QueryResult match, Pattern p) {
+ private void processRule(Rule rule, QueryResult match, Pattern p) throws SQLException, SailException, ReasoningException {
// get the variable bindings for the rule evaluation
- log.debug("REASONER: evaluating rule body for rule {} ...", rule);
+ log.debug("REASONER(rule '{}'): evaluating rule body {} ...", rule.getName() != null ? rule.getName() : rule.getId(), rule);
// create a collection consisting of the body minus the pattern that already matched
Set<Pattern> body = new HashSet<Pattern>(rule.getBody());
@@ -629,153 +585,143 @@ public class ReasoningEngine implements TransactionListener {
CloseableIteration<QueryResult, SQLException> bodyResult;
+ KiWiReasoningConnection connection = persistence.getConnection();
+ SailConnection sail = store.getConnection();
+ KiWiSailConnection isail = getWrappedConnection(sail);
try {
- KiWiReasoningConnection connection = persistence.getConnection();
- SailConnection sail = store.getConnection();
- KiWiSailConnection isail = getWrappedConnection(sail);
- try {
- // if there are further patterns, evaluate them; if the matched pattern was the only pattern, then
- // simply take the match as binding
- if(body.size() > 0) {
- bodyResult = connection.query(body,match,null,null,true);
- } else if(match != null) {
- bodyResult = new SingletonIteration<QueryResult, SQLException>(match);
- } else {
- bodyResult = new EmptyIteration<QueryResult, SQLException>();
- }
+ // if there are further patterns, evaluate them; if the matched pattern was the only pattern, then
+ // simply take the match as binding
+ if(body.size() > 0) {
+ bodyResult = connection.query(body,match,null,null,true);
+ } else if(match != null) {
+ bodyResult = new SingletonIteration<QueryResult, SQLException>(match);
+ } else {
+ bodyResult = new EmptyIteration<QueryResult, SQLException>();
+ }
- // construct triples out of the bindings and the rule heads
- long counter = 0;
+ // construct triples out of the bindings and the rule heads
+ long counter = 0;
- // initialise a new set of justifications
- Set<Justification> justifications = new HashSet<Justification>();
+ // initialise a new set of justifications
+ Set<Justification> justifications = new HashSet<Justification>();
- sail.begin();
- while(bodyResult.hasNext()) {
- QueryResult row = bodyResult.next();
- Map<VariableField,KiWiNode> binding = row.getBindings();
+ sail.begin();
+ while(bodyResult.hasNext()) {
+ QueryResult row = bodyResult.next();
+ Map<VariableField,KiWiNode> binding = row.getBindings();
- Resource subject = null;
- URI property = null;
- Value object;
+ Resource subject = null;
+ URI property = null;
+ Value object;
- if(rule.getHead().getSubject() != null && rule.getHead().getSubject().isVariableField()) {
- if(!binding.get(rule.getHead().getSubject()).isUriResource() && !binding.get(rule.getHead().getSubject()).isAnonymousResource()) {
- log.info("cannot use value {} as subject, because it is not a resource",binding.get(rule.getHead().getSubject()));
- continue;
- }
- subject = (KiWiResource)binding.get(rule.getHead().getSubject());
- } else if(rule.getHead().getSubject() != null && rule.getHead().getSubject().isResourceField()) {
- subject = ((ResourceField)rule.getHead().getSubject()).getResource();
- } else
- throw new IllegalArgumentException("Subject of rule head may only be a variable or a resource; rule: "+rule);
-
- if(rule.getHead().getProperty() != null && rule.getHead().getProperty().isVariableField()) {
- if(!binding.get(rule.getHead().getProperty()).isUriResource()) {
- log.info("cannot use value {} as property, because it is not a URI resource",binding.get(rule.getHead().getProperty()));
- continue;
+ if(rule.getHead().getSubject() != null && rule.getHead().getSubject().isVariableField()) {
+ if(!binding.get(rule.getHead().getSubject()).isUriResource() && !binding.get(rule.getHead().getSubject()).isAnonymousResource()) {
+ log.info("cannot use value {} as subject, because it is not a resource",binding.get(rule.getHead().getSubject()));
+ continue;
+ }
+ subject = (KiWiResource)binding.get(rule.getHead().getSubject());
+ } else if(rule.getHead().getSubject() != null && rule.getHead().getSubject().isResourceField()) {
+ subject = ((ResourceField)rule.getHead().getSubject()).getResource();
+ } else
+ throw new IllegalArgumentException("Subject of rule head may only be a variable or a resource; rule: "+rule);
+
+ if(rule.getHead().getProperty() != null && rule.getHead().getProperty().isVariableField()) {
+ if(!binding.get(rule.getHead().getProperty()).isUriResource()) {
+ log.info("cannot use value {} as property, because it is not a URI resource",binding.get(rule.getHead().getProperty()));
+ continue;
+ }
+ property = (KiWiUriResource)binding.get(rule.getHead().getProperty());
+ } else if(rule.getHead().getProperty() != null && rule.getHead().getProperty().isResourceField()) {
+ property = (KiWiUriResource)((ResourceField)rule.getHead().getProperty()).getResource();
+ } else
+ throw new IllegalArgumentException("Property of rule head may only be a variable or a resource; rule: "+rule);
+
+ if(rule.getHead().getObject() != null && rule.getHead().getObject().isVariableField()) {
+ object = binding.get(rule.getHead().getObject());
+ } else if(rule.getHead().getObject() != null && rule.getHead().getObject().isResourceField()) {
+ object = ((ResourceField)rule.getHead().getObject()).getResource();
+ } else if(rule.getHead().getObject() != null && rule.getHead().getObject().isLiteralField()) {
+ object = ((LiteralField)rule.getHead().getObject()).getLiteral();
+ } else
+ throw new IllegalArgumentException("Object of rule head may only be a variable, a literal, or a resource; rule: "+rule);
+
+
+ KiWiTriple triple = isail.addInferredStatement(subject, property, object);
+
+ Justification justification = new Justification();
+ justification.setTriple(triple);
+ justification.getSupportingRules().add(rule);
+ justification.getSupportingTriples().addAll(row.getJustifications());
+ justifications.add(justification);
+
+ // when the batch size is reached, commit the transaction, save the justifications, and start a new
+ // transaction and new justification set
+ if(++counter % config.getBatchSize() == 0) {
+ persistenceLock.lock();
+
+ try {
+
+ sail.commit();
+
+ log.debug("adding {} justifications",justifications.size());
+
+ updateTaskStatus("storing justifications ...");
+ Set<Justification> baseJustifications = getBaseJustifications(connection,justifications);
+
+ if(config.isRemoveDuplicateJustifications()) {
+ removeDuplicateJustifications(connection,baseJustifications);
}
- property = (KiWiUriResource)binding.get(rule.getHead().getProperty());
- } else if(rule.getHead().getProperty() != null && rule.getHead().getProperty().isResourceField()) {
- property = (KiWiUriResource)((ResourceField)rule.getHead().getProperty()).getResource();
- } else
- throw new IllegalArgumentException("Property of rule head may only be a variable or a resource; rule: "+rule);
-
- if(rule.getHead().getObject() != null && rule.getHead().getObject().isVariableField()) {
- object = binding.get(rule.getHead().getObject());
- } else if(rule.getHead().getObject() != null && rule.getHead().getObject().isResourceField()) {
- object = ((ResourceField)rule.getHead().getObject()).getResource();
- } else if(rule.getHead().getObject() != null && rule.getHead().getObject().isLiteralField()) {
- object = ((LiteralField)rule.getHead().getObject()).getLiteral();
- } else
- throw new IllegalArgumentException("Object of rule head may only be a variable, a literal, or a resource; rule: "+rule);
-
-
- KiWiTriple triple = isail.addInferredStatement(subject, property, object);
-
- Justification justification = new Justification();
- justification.setTriple(triple);
- justification.getSupportingRules().add(rule);
- justification.getSupportingTriples().addAll(row.getJustifications());
- justifications.add(justification);
-
- // when the batch size is reached, commit the transaction, save the justifications, and start a new
- // transaction and new justification set
- if(++counter % config.getBatchSize() == 0) {
- persistenceLock.lock();
-
- try {
-
- sail.commit();
-
- log.debug("adding {} justifications",justifications.size());
-
- updateTaskStatus("storing justifications ...");
- Set<Justification> baseJustifications = getBaseJustifications(connection,justifications);
-
- if(config.isRemoveDuplicateJustifications()) {
- removeDuplicateJustifications(connection,baseJustifications);
- }
-
- log.debug("{} justifications added after resolving inferred triples", baseJustifications.size());
-
- // persist the justifications that have been created in the rule processing
- if(baseJustifications.size() > 0) {
- connection.storeJustifications(baseJustifications);
- }
- connection.commit();
- sail.begin();
- } finally {
- persistenceLock.unlock();
+
+ log.debug("{} justifications added after resolving inferred triples", baseJustifications.size());
+
+ // persist the justifications that have been created in the rule processing
+ if(baseJustifications.size() > 0) {
+ connection.storeJustifications(baseJustifications);
}
- justifications.clear();
+ connection.commit();
+ sail.begin();
+ } finally {
+ persistenceLock.unlock();
}
+ justifications.clear();
}
+ }
- persistenceLock.lock();
- try {
- sail.commit();
+ persistenceLock.lock();
+ try {
+ sail.commit();
- log.debug("adding {} justifications",justifications.size());
- updateTaskStatus("storing justifications ...");
- Set<Justification> baseJustifications = getBaseJustifications(connection,justifications);
+ log.debug("adding {} justifications",justifications.size());
+ updateTaskStatus("storing justifications ...");
+ Set<Justification> baseJustifications = getBaseJustifications(connection,justifications);
- if(config.isRemoveDuplicateJustifications()) {
- removeDuplicateJustifications(connection,baseJustifications);
- }
+ if(config.isRemoveDuplicateJustifications()) {
+ removeDuplicateJustifications(connection,baseJustifications);
+ }
- // persist the justifications that have been created in the rule processing
- if(baseJustifications.size() > 0) {
- connection.storeJustifications(baseJustifications);
- }
+ // persist the justifications that have been created in the rule processing
+ if(baseJustifications.size() > 0) {
+ connection.storeJustifications(baseJustifications);
+ }
- log.debug("{} justifications added after resolving inferred triples", baseJustifications.size());
+ log.debug("{} justifications added after resolving inferred triples", baseJustifications.size());
- Iterations.closeCloseable(bodyResult);
- connection.commit();
- } finally {
- persistenceLock.unlock();
- }
- } catch(SailException ex) {
- connection.rollback();
- sail.rollback();
- throw ex;
- } catch(SQLException ex) {
- sail.rollback();
- connection.rollback();
- throw ex;
+ Iterations.closeCloseable(bodyResult);
+ connection.commit();
} finally {
- connection.close();
- sail.close();
+ persistenceLock.unlock();
}
-
- } catch(SQLException ex) {
- log.error("DATABASE ERROR: could not process rule, database state will be inconsistent! Message: {}",ex.getMessage());
+ } catch(SailException | SQLException | ReasoningException ex) {
+ log.error("REASONING ERROR: could not process rule, database state will be inconsistent! Message: {}",ex.getMessage());
log.debug("Exception details:",ex);
- } catch (SailException ex) {
- log.error("REPOSITORY ERROR: could not process rule, database state will be inconsistent! Message: {}",ex.getMessage());
- log.debug("Exception details:", ex);
+
+ connection.rollback();
+ sail.rollback();
+ throw ex;
+ } finally {
+ connection.close();
+ sail.close();
}
}
@@ -785,12 +731,11 @@ public class ReasoningEngine implements TransactionListener {
* @param t
* @return
*/
- private Collection<Justification> getJustifications(KiWiReasoningConnection connection, KiWiTriple t, Set<Justification> transactionJustifications) throws SQLException {
- // TODO: transactionJustifications are ignored
+ protected Collection<Justification> getJustifications(KiWiReasoningConnection connection, KiWiTriple t, Set<Justification> transactionJustifications) throws SQLException {
HashSet<Justification> justifications = new HashSet<Justification>();
Iterations.addAll(connection.listJustificationsForTriple(t), justifications);
for(Justification j : transactionJustifications) {
- if(j.getTriple().equals(t)) {
+ if(equivalence.equivalent(j.getTriple(), t)) {
justifications.add(j);
}
}
@@ -804,9 +749,9 @@ public class ReasoningEngine implements TransactionListener {
* @param justifications
* @return
*/
- private Set<Justification> getBaseJustifications(KiWiReasoningConnection connection, Set<Justification> justifications) throws SQLException {
+ protected Set<Justification> getBaseJustifications(KiWiReasoningConnection connection, Set<Justification> justifications) throws SQLException, ReasoningException {
Set<Justification> baseJustifications = new HashSet<Justification>();
- Map<KiWiTriple,Collection<Justification>> justificationCache = new HashMap<KiWiTriple, Collection<Justification>>();
+ Map<KiWiTriple,Collection<Justification>> justificationCache = StatementCommons.newQuadrupleMap();
for(Justification justification : justifications) {
KiWiTriple triple = justification.getTriple();
@@ -828,7 +773,7 @@ public class ReasoningEngine implements TransactionListener {
}
if(supportJustifications.size() == 0) {
- log.error("error: inferred triple {} is not justified!",support);
+ throw new UnjustifiedTripleException("error: inferred triple is not justified!", support);
}
// mix the two sets
@@ -864,7 +809,7 @@ public class ReasoningEngine implements TransactionListener {
*/
private void removeDuplicateJustifications(KiWiReasoningConnection connection, Set<Justification> justifications) throws SQLException {
// remove duplicate justifications
- HashMap<KiWiTriple,Collection<Justification>> justificationCache = new HashMap<KiWiTriple, Collection<Justification>>();
+ Map<KiWiTriple,Collection<Justification>> justificationCache = StatementCommons.newQuadrupleMap();
for(Iterator<Justification> it = justifications.iterator(); it.hasNext(); ) {
Justification j = it.next();
@@ -882,7 +827,7 @@ public class ReasoningEngine implements TransactionListener {
}
- private QueryResult matches(Pattern pattern, KiWiTriple triple) {
+ protected static QueryResult matches(Pattern pattern, KiWiTriple triple) {
boolean result = true;
QueryResult match = new QueryResult();
@@ -950,8 +895,45 @@ public class ReasoningEngine implements TransactionListener {
}
public void shutdown() {
- log.info("shutting down reasoning service ...");
- reasonerThread.shutdown();
+ shutdown(false);
+ }
+
+ public void shutdown(boolean force) {
+ if(isshutdown)
+ return;
+
+ if(force) {
+ log.warn("forced shutdown of reasoning service initiated, state will be inconsistent ...");
+
+ reasoningQueue.clear();
+ reasonerThread.shutdown(true);
+
+ for(int i = 0; i<5 && isRunning(); i++) {
+ log.warn("reasoner not yet finished, waiting for 100 ms (try={})", i+1);
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ // yes, I know it is unsafe; it is only used when forcefully shutting down on test ends before the database is deleted...
+ reasonerThread.stop();
+
+ } else {
+ log.info("graceful shutdown of reasoning service initiated ...");
+
+ for(int i = 0; i<20 && isRunning(); i++) {
+ log.warn("reasoner not yet finished, waiting for 1 seconds (try={})", i+1);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ reasonerThread.shutdown(false);
+ }
+
+ isshutdown = true;
}
/**
@@ -976,6 +958,7 @@ public class ReasoningEngine implements TransactionListener {
private class SKWRLReasoner extends Thread {
private boolean shutdown = false;
private boolean running = false;
+ private boolean forceshutdown = false;
private SKWRLReasoner() {
super("SKWRL Reasoner " + ++indexerCounter);
@@ -983,8 +966,10 @@ public class ReasoningEngine implements TransactionListener {
start();
}
- public void shutdown() {
+ public void shutdown(boolean force) {
+ log.info("REASONER: signalling shutdown to reasoner thread");
shutdown = true;
+ forceshutdown = force;
this.interrupt();
}
@@ -998,7 +983,7 @@ public class ReasoningEngine implements TransactionListener {
startTask(getName(), TASK_GROUP);
- while (!shutdown || reasoningQueue.size() > 0) {
+ while (!forceshutdown && (!shutdown || reasoningQueue.size() > 0)) {
running = false;
try {
updateTaskStatus("idle");
@@ -1011,10 +996,13 @@ public class ReasoningEngine implements TransactionListener {
executeReasoner(data);
} catch (InterruptedException ex) {
+ } catch (RuntimeException ex) {
+ // can happen on forced shutdown
} catch (Exception ex) {
log.warn("reasoning task threw an exception",ex);
}
}
+ running = false;
try {
endTask();
} catch (Exception ex) {
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/exception/ReasoningException.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/exception/ReasoningException.java b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/exception/ReasoningException.java
new file mode 100644
index 0000000..bc25d22
--- /dev/null
+++ b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/exception/ReasoningException.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.kiwi.reasoner.model.exception;
+
+/**
+ * Add file description here!
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class ReasoningException extends Exception {
+
+ /**
+ * Constructs a new exception with {@code null} as its detail message.
+ * The cause is not initialized, and may subsequently be initialized by a
+ * call to {@link #initCause}.
+ */
+ public ReasoningException() {
+ }
+
+ /**
+ * Constructs a new exception with the specified cause and a detail
+ * message of <tt>(cause==null ? null : cause.toString())</tt> (which
+ * typically contains the class and detail message of <tt>cause</tt>).
+ * This constructor is useful for exceptions that are little more than
+ * wrappers for other throwables (for example, {@link
+ * java.security.PrivilegedActionException}).
+ *
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A <tt>null</tt> value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.4
+ */
+ public ReasoningException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message. The
+ * cause is not initialized, and may subsequently be initialized by
+ * a call to {@link #initCause}.
+ *
+ * @param message the detail message. The detail message is saved for
+ * later retrieval by the {@link #getMessage()} method.
+ */
+ public ReasoningException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message and
+ * cause. <p>Note that the detail message associated with
+ * {@code cause} is <i>not</i> automatically incorporated in
+ * this exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A <tt>null</tt> value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.4
+ */
+ public ReasoningException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message,
+ * cause, suppression enabled or disabled, and writable stack
+ * trace enabled or disabled.
+ *
+ * @param message the detail message.
+ * @param cause the cause. (A {@code null} value is permitted,
+ * and indicates that the cause is nonexistent or unknown.)
+ * @param enableSuppression whether or not suppression is enabled
+ * or disabled
+ * @param writableStackTrace whether or not the stack trace should
+ * be writable
+ * @since 1.7
+ */
+ public ReasoningException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/exception/UnjustifiedTripleException.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/exception/UnjustifiedTripleException.java b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/exception/UnjustifiedTripleException.java
new file mode 100644
index 0000000..853db1c
--- /dev/null
+++ b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/exception/UnjustifiedTripleException.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.kiwi.reasoner.model.exception;
+
+import org.apache.marmotta.kiwi.model.rdf.KiWiTriple;
+
+/**
+ * Add file description here!
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class UnjustifiedTripleException extends ReasoningException {
+
+ private KiWiTriple triple;
+
+ /**
+ * Constructs a new exception with the specified detail message. The
+ * cause is not initialized, and may subsequently be initialized by
+ * a call to {@link #initCause}.
+ *
+ * @param message the detail message. The detail message is saved for
+ * later retrieval by the {@link #getMessage()} method.
+ */
+ public UnjustifiedTripleException(String message, KiWiTriple triple) {
+ super(message);
+
+ this.triple = triple;
+ }
+}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/program/Justification.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/program/Justification.java b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/program/Justification.java
index c338c86..5de904e 100644
--- a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/program/Justification.java
+++ b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/program/Justification.java
@@ -18,7 +18,10 @@
package org.apache.marmotta.kiwi.reasoner.model.program;
+import com.google.common.base.Equivalence;
+import org.apache.marmotta.commons.sesame.model.StatementCommons;
import org.apache.marmotta.kiwi.model.rdf.KiWiTriple;
+import org.openrdf.model.Statement;
import java.util.Date;
import java.util.HashSet;
@@ -63,8 +66,11 @@ public class Justification {
*/
private Date createdAt;
+
+ private static Equivalence<Statement> equivalence = StatementCommons.quadrupleEquivalence();
+
public Justification() {
- supportingTriples = new HashSet<KiWiTriple>();
+ supportingTriples = StatementCommons.newQuadrupleSet();
supportingRules = new HashSet<Rule>();
}
@@ -118,7 +124,7 @@ public class Justification {
//if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (!supportingRules.equals(that.supportingRules)) return false;
if (!supportingTriples.equals(that.supportingTriples)) return false;
- if (!triple.equals(that.triple)) return false;
+ if (!equivalence.equivalent(this.triple, that.triple)) return false;
return true;
}
@@ -126,7 +132,7 @@ public class Justification {
@Override
public int hashCode() {
int result = 0; // id != null ? id.hashCode() : 0;
- result = 31 * result + triple.hashCode();
+ result = 31 * result + equivalence.hash(triple);
result = 31 * result + supportingTriples.hashCode();
result = 31 * result + supportingRules.hashCode();
return result;
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/program/Pattern.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/program/Pattern.java b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/program/Pattern.java
index 91c9aa4..6fd96f9 100644
--- a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/program/Pattern.java
+++ b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/program/Pattern.java
@@ -17,6 +17,8 @@
*/
package org.apache.marmotta.kiwi.reasoner.model.program;
+import com.google.common.base.Objects;
+
import java.util.Map;
/**
@@ -93,28 +95,23 @@ public class Pattern {
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- if(context == null && object == null && subject == null && property == null) {
- return super.equals(o);
+ if(! (o instanceof Pattern)) {
+ return false;
}
Pattern pattern = (Pattern) o;
- if (context != null ? !context.equals(pattern.context) : pattern.context != null) return false;
- if (object != null ? !object.equals(pattern.object) : pattern.object != null) return false;
- if (property != null ? !property.equals(pattern.property) : pattern.property != null) return false;
- if (subject != null ? !subject.equals(pattern.subject) : pattern.subject != null) return false;
+ if(!Objects.equal(this.context, pattern.context)) return false;
+ if(!Objects.equal(this.object, pattern.object)) return false;
+ if(!Objects.equal(this.property, pattern.property)) return false;
+ if(!Objects.equal(this.subject, pattern.subject)) return false;
return true;
}
@Override
public int hashCode() {
- int result = subject != null ? subject.hashCode() : 0;
- result = 31 * result + (property != null ? property.hashCode() : 0);
- result = 31 * result + (object != null ? object.hashCode() : 0);
- result = 31 * result + (context != null ? context.hashCode() : 0);
- return result;
+ return Objects.hashCode(subject, property, object, context);
}
}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/query/QueryResult.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/query/QueryResult.java b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/query/QueryResult.java
index 94e73ed..5dbf0af 100644
--- a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/query/QueryResult.java
+++ b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/model/query/QueryResult.java
@@ -17,6 +17,7 @@
*/
package org.apache.marmotta.kiwi.reasoner.model.query;
+import org.apache.marmotta.commons.sesame.model.StatementCommons;
import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
import org.apache.marmotta.kiwi.model.rdf.KiWiTriple;
import org.apache.marmotta.kiwi.reasoner.model.program.VariableField;
@@ -27,7 +28,7 @@ import java.util.Map;
import java.util.Set;
/**
- * Add file description here!
+ * Represent the result of a pattern query of a rule body against the triple store.
* <p/>
* User: sschaffe
*/
@@ -39,7 +40,7 @@ public class QueryResult {
public QueryResult() {
bindings = new HashMap<VariableField, KiWiNode>();
- justifications = new HashSet<KiWiTriple>();
+ justifications = StatementCommons.newQuadrupleSet();
}
public QueryResult(Map<VariableField, KiWiNode> bindings, Set<KiWiTriple> justifications) {
@@ -51,15 +52,8 @@ public class QueryResult {
return bindings;
}
- public void setBindings(Map<VariableField, KiWiNode> bindings) {
- this.bindings = bindings;
- }
-
public Set<KiWiTriple> getJustifications() {
return justifications;
}
- public void setJustifications(Set<KiWiTriple> justifications) {
- this.justifications = justifications;
- }
}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/parser/KWRLProgramParserBase.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/parser/KWRLProgramParserBase.java b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/parser/KWRLProgramParserBase.java
index 550da32..0074b4c 100644
--- a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/parser/KWRLProgramParserBase.java
+++ b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/parser/KWRLProgramParserBase.java
@@ -128,14 +128,13 @@ public abstract class KWRLProgramParserBase {
return valueFactory.createURI(uri);
}
-
protected Literal resolveLiteral(Object content, Locale loc, String typeUri) {
if(typeUri != null) {
return valueFactory.createLiteral(content.toString(),valueFactory.createURI(typeUri));
} else if(loc != null) {
return valueFactory.createLiteral(content.toString(), loc.getLanguage());
} else {
- return valueFactory.createLiteral(content);
+ return valueFactory.createLiteral(content.toString());
}
}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/util/JustificationUtils.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/util/JustificationUtils.java b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/util/JustificationUtils.java
new file mode 100644
index 0000000..8503816
--- /dev/null
+++ b/libraries/kiwi/kiwi-reasoner/src/main/java/org/apache/marmotta/kiwi/reasoner/util/JustificationUtils.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.kiwi.reasoner.util;
+
+/**
+ * Add file description here!
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class JustificationUtils {
+}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/main/resources/org/apache/marmotta/kiwi/persistence/mysql/statements.properties
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/resources/org/apache/marmotta/kiwi/persistence/mysql/statements.properties b/libraries/kiwi/kiwi-reasoner/src/main/resources/org/apache/marmotta/kiwi/persistence/mysql/statements.properties
index 68e60f8..499b934 100644
--- a/libraries/kiwi/kiwi-reasoner/src/main/resources/org/apache/marmotta/kiwi/persistence/mysql/statements.properties
+++ b/libraries/kiwi/kiwi-reasoner/src/main/resources/org/apache/marmotta/kiwi/persistence/mysql/statements.properties
@@ -19,12 +19,15 @@
# get sequence numbers
seq.rules.prep = UPDATE seq_rules SET id=LAST_INSERT_ID(id+1);
seq.rules = SELECT LAST_INSERT_ID();
+seq.rules.set = UPDATE seq_rules SET id=?;
seq.programs.prep = UPDATE seq_programs SET id=LAST_INSERT_ID(id+1);
seq.programs = SELECT LAST_INSERT_ID();
+seq.programs.set = UPDATE seq_programs SET id=?;
seq.justifications.prep= UPDATE seq_justifications SET id=LAST_INSERT_ID(id+1);
seq.justifications = SELECT LAST_INSERT_ID();
+seq.justifications.set = UPDATE seq_justifications SET id=?;
# rules
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/statements.properties
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/statements.properties b/libraries/kiwi/kiwi-reasoner/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/statements.properties
index 2d7d788..2f3fa5c 100644
--- a/libraries/kiwi/kiwi-reasoner/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/statements.properties
+++ b/libraries/kiwi/kiwi-reasoner/src/main/resources/org/apache/marmotta/kiwi/persistence/pgsql/statements.properties
@@ -18,8 +18,11 @@
# get sequence numbers
seq.rules = SELECT nextval('seq_rules')
+seq.rules.set = SELECT setval('seq_rules',?);
seq.programs = SELECT nextval('seq_programs')
+seq.programs.set = SELECT setval('seq_programs',?);
seq.justifications = SELECT nextval('seq_justifications')
+seq.justifications.set= SELECT setval('seq_justifications',?);
# rules
rules.insert = INSERT INTO reasoner_rules (id,name,description,body,createdAt) VALUES (?,?,?,?,now())
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/engine/JustificationResolutionTest.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/engine/JustificationResolutionTest.java b/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/engine/JustificationResolutionTest.java
new file mode 100644
index 0000000..3f1aa48
--- /dev/null
+++ b/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/engine/JustificationResolutionTest.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.kiwi.reasoner.test.engine;
+
+import com.google.common.collect.Sets;
+import info.aduna.iteration.Iterations;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.marmotta.commons.sesame.model.Namespaces;
+import org.apache.marmotta.commons.sesame.model.StatementCommons;
+import org.apache.marmotta.kiwi.model.rdf.*;
+import org.apache.marmotta.kiwi.reasoner.engine.ReasoningEngine;
+import org.apache.marmotta.kiwi.reasoner.model.exception.ReasoningException;
+import org.apache.marmotta.kiwi.reasoner.model.program.Justification;
+import org.apache.marmotta.kiwi.reasoner.model.program.Rule;
+import org.apache.marmotta.kiwi.reasoner.persistence.KiWiReasoningConnection;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.openrdf.model.Statement;
+
+import java.sql.SQLException;
+import java.util.*;
+
+import static org.hamcrest.Matchers.*;
+
+/**
+ * Test if the ReasoningEngine's way of resolving base justifications works. Mocks the lookup for base justifications.
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class JustificationResolutionTest {
+
+ private MockReasoningEngine engine;
+
+ private Map<Statement,Set<Justification>> baseJustifications;
+
+
+ protected static Random rnd = new Random();
+
+
+ private KiWiTriple t1, t2, t3, t4, t5; // base
+ private KiWiTriple i1, i2, i3, i4, i5, i6; // inferred
+ private Justification j1, j2, j3, j4, j5, tj1, tj2, tj3;
+ private Rule r1, r2;
+
+ private KiWiUriResource ctx_inferred;
+
+ @Before
+ public void setup() {
+ engine = new MockReasoningEngine();
+
+ baseJustifications = StatementCommons.newQuadrupleMap();
+
+
+ KiWiUriResource s1 = randomURI();
+ KiWiUriResource s2 = randomURI();
+ KiWiUriResource s3 = randomURI();
+ KiWiUriResource s4 = randomURI();
+ KiWiUriResource p1 = randomURI();
+ KiWiUriResource p2 = randomURI();
+ KiWiNode o1 = randomObject();
+ KiWiNode o2 = randomObject();
+ KiWiNode o3 = randomObject();
+ KiWiNode o4 = randomObject();
+
+ ctx_inferred = randomURI();
+
+ t1 = new KiWiTriple(s1,p1,o1, null);
+ t2 = new KiWiTriple(s1,p1,o2, null);
+ t3 = new KiWiTriple(s2,p1,o3, null);
+ t4 = new KiWiTriple(s1,p1,o1, randomURI());
+ t5 = new KiWiTriple(s3,p1,o1, randomURI());
+
+
+ i1 = new KiWiTriple(s1,p2,o1, ctx_inferred); i1.setInferred(true);
+ i2 = new KiWiTriple(s1,p1,o2, ctx_inferred); i2.setInferred(true);
+ i3 = new KiWiTriple(s3,p1,o3, ctx_inferred); i3.setInferred(true);
+ i4 = new KiWiTriple(s1,p2,o1, ctx_inferred); i4.setInferred(true);
+ i5 = new KiWiTriple(s1,p2,o3, ctx_inferred); i5.setInferred(true);
+
+ // assume i1 is justified by t1 and t2;
+ j1 = new Justification();
+ j1.setTriple(i1);
+ j1.getSupportingTriples().add(t1);
+ j1.getSupportingTriples().add(t2);
+
+ baseJustifications.put(i1, Collections.singleton(j1));
+
+ // assume i2 is justified by t3 and t4, as well as by t2 and t4
+ j2 = new Justification();
+ j2.setTriple(i2);
+ j2.getSupportingTriples().add(t3);
+ j2.getSupportingTriples().add(t4);
+
+
+ j3 = new Justification();
+ j3.setTriple(i2);
+ j3.getSupportingTriples().add(t2);
+ j3.getSupportingTriples().add(t4);
+
+ baseJustifications.put(i2, Sets.newHashSet(j2,j3));
+
+ // assume that i5 as well is justified by two justifications
+ j4 = new Justification();
+ j4.setTriple(i5);
+ j4.getSupportingTriples().add(t1);
+ j4.getSupportingTriples().add(t4);
+
+
+ j5 = new Justification();
+ j5.setTriple(i5);
+ j5.getSupportingTriples().add(t2);
+ j5.getSupportingTriples().add(t5);
+
+
+ baseJustifications.put(i5, Sets.newHashSet(j4,j5));
+
+ // i3 justified by i1 and t3
+ tj1 = new Justification();
+ tj1.setTriple(i3);
+ tj1.getSupportingTriples().add(i1);
+ tj1.getSupportingTriples().add(t3);
+
+
+ // i4 justified by i1 and i2
+ tj2 = new Justification();
+ tj2.setTriple(i4);
+ tj2.getSupportingTriples().add(i1);
+ tj2.getSupportingTriples().add(i2);
+
+
+ // i6 is justified by i2 and i5 (so multiplexing needed)
+ tj3 = new Justification();
+ tj3.setTriple(i6);
+ tj3.getSupportingTriples().add(i2);
+ tj3.getSupportingTriples().add(i5);
+
+ }
+
+ /**
+ * Test substitution of a single inferred triple supporting the triple by a single justification, so
+ * the number of new justifications will be the same as before, but the new justification will only
+ * contain base triples.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testResolveBaseTriplesSingle() throws Exception {
+
+ Collection<Justification> r1 = engine.getBaseJustifications(null,Collections.singleton(tj1));
+ Assert.assertEquals(1, r1.size());
+
+ Justification tj1r = r1.iterator().next();
+ Assert.assertEquals(3,tj1r.getSupportingTriples().size());
+ Assert.assertTrue(tj1r.getSupportingTriples().contains(t1));
+ Assert.assertTrue(tj1r.getSupportingTriples().contains(t2));
+ Assert.assertTrue(tj1r.getSupportingTriples().contains(t3));
+
+
+
+ }
+
+ /**
+ * Test the substitution of an inferred triple that has several justifications itself; in this case the
+ * result will be split according to the number of justifications of the inferred triple
+ * @throws Exception
+ */
+ @Test
+ public void testResolveBaseTriplesMulti() throws Exception {
+ Collection<Justification> r2 = engine.getBaseJustifications(null,Collections.singleton(tj2));
+
+ // since i2 is justified by two justifications, the result for i4 also needs to have two
+ Assert.assertEquals(2, r2.size());
+
+ Assert.assertThat(r2,Matchers.<Justification>hasItem(hasProperty("supportingTriples", hasItems(t1,t2,t3,t4))));
+ Assert.assertThat(r2,Matchers.<Justification>hasItem(hasProperty("supportingTriples", hasItems(t1,t2,t4))));
+ }
+
+ /**
+ * Test the substitution of more than one justification, the result should include the new base justificatoins for
+ * all justifications in the set
+ * @throws Exception
+ */
+ @Test
+ public void testResolveBaseTriplesSet() throws Exception {
+ Collection<Justification> r3 = engine.getBaseJustifications(null,Sets.newHashSet(tj1, tj2));
+
+ // since i2 is justified by two justifications, the result for i4 also needs to have two
+ Assert.assertEquals(3, r3.size());
+
+ Assert.assertThat(r3,Matchers.<Justification>hasItem(allOf(hasProperty("triple", is(i3)),hasProperty("supportingTriples", hasItems(t1, t2, t3)))));
+ Assert.assertThat(r3,Matchers.<Justification>hasItem(allOf(hasProperty("triple", is(i4)),hasProperty("supportingTriples", hasItems(t1, t2, t3, t4)))));
+ Assert.assertThat(r3,Matchers.<Justification>hasItem(allOf(hasProperty("triple", is(i4)),hasProperty("supportingTriples", hasItems(t1,t2,t4)))));
+ }
+
+ /**
+ * Test the substitution of several inferred triple that have several justifications itself; the result needs to be
+ * multiplexed.
+ * @throws Exception
+ */
+ @Test
+ public void testResolveBaseTriplesMultiplex() throws Exception {
+ Collection<Justification> r4 = engine.getBaseJustifications(null,Collections.singleton(tj3));
+
+ // since i2 is justified by two justifications, the result for i4 also needs to have two
+ Assert.assertEquals(4, r4.size());
+
+ Assert.assertThat(r4,Matchers.<Justification>hasItem(hasProperty("supportingTriples", hasItems(t1,t3,t4))));
+ Assert.assertThat(r4,Matchers.<Justification>hasItem(hasProperty("supportingTriples", hasItems(t2,t3,t4,t5))));
+ Assert.assertThat(r4,Matchers.<Justification>hasItem(hasProperty("supportingTriples", hasItems(t1, t2, t4))));
+ Assert.assertThat(r4,Matchers.<Justification>hasItem(hasProperty("supportingTriples", allOf(hasItems(t2, t4, t5), not(hasItem(t3))))));
+ }
+
+
+ // TODO: a test taking into account transaction justifications
+
+ /**
+ * Test resolution against justifications that are not yet "persisted" but are taken from the current transaction
+ * @throws Exception
+ */
+ @Test
+ public void testTransactionJustifications() throws Exception {
+
+ }
+
+
+ /**
+ * Return a random URI, with a 10% chance of returning a URI that has already been used.
+ * @return
+ */
+ protected KiWiUriResource randomURI() {
+ KiWiUriResource resource = new KiWiUriResource("http://localhost/" + RandomStringUtils.randomAlphanumeric(8));
+ return resource;
+ }
+
+ /**
+ * Return a random RDF value, either a reused object (10% chance) or of any other kind.
+ * @return
+ */
+ protected KiWiNode randomObject() {
+ KiWiNode object;
+ switch(rnd.nextInt(6)) {
+ case 0: object = new KiWiUriResource("http://localhost/" + RandomStringUtils.randomAlphanumeric(8));
+ break;
+ case 1: object = new KiWiAnonResource(RandomStringUtils.randomAscii(8));
+ break;
+ case 2: object = new KiWiStringLiteral(RandomStringUtils.randomAscii(40));
+ break;
+ case 3: object = new KiWiIntLiteral(rnd.nextLong(), new KiWiUriResource(Namespaces.NS_XSD + "integer"));
+ break;
+ case 4: object = new KiWiDoubleLiteral(rnd.nextDouble(), new KiWiUriResource(Namespaces.NS_XSD + "double"));
+ break;
+ case 5: object = new KiWiBooleanLiteral(rnd.nextBoolean(), new KiWiUriResource(Namespaces.NS_XSD + "boolean"));
+ break;
+ default: object = new KiWiUriResource("http://localhost/" + RandomStringUtils.randomAlphanumeric(8));
+ break;
+
+ }
+ return object;
+ }
+
+
+
+ private class MockReasoningEngine extends ReasoningEngine {
+ private MockReasoningEngine() {
+ }
+
+
+ /**
+ * Return the justifications for the triple passed as argument.
+ *
+ * @param t
+ * @return
+ */
+ @Override
+ protected Collection<Justification> getJustifications(KiWiReasoningConnection connection, KiWiTriple t, Set<Justification> transactionJustifications) throws SQLException {
+ HashSet<Justification> justifications = new HashSet<Justification>();
+ justifications.addAll(baseJustifications.get(t));
+ for(Justification j : transactionJustifications) {
+ if(equivalence.equivalent(j.getTriple(), t)) {
+ justifications.add(j);
+ }
+ }
+ return justifications;
+ }
+
+ /**
+ * For all justifications contained in the set passed as argument, create corresponding base justifications,
+ * i.e. justifications that only contain base triples and no inferred triples.
+ *
+ * @param justifications
+ * @return
+ */
+ @Override
+ public Set<Justification> getBaseJustifications(KiWiReasoningConnection connection, Set<Justification> justifications) throws SQLException, ReasoningException {
+ return super.getBaseJustifications(connection, justifications);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/engine/ReasoningEngineTest.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/engine/ReasoningEngineTest.java b/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/engine/ReasoningEngineTest.java
index af6bc81..fb2c497 100644
--- a/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/engine/ReasoningEngineTest.java
+++ b/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/engine/ReasoningEngineTest.java
@@ -17,13 +17,18 @@
*/
package org.apache.marmotta.kiwi.reasoner.test.engine;
+import static org.hamcrest.Matchers.hasItem;
+import static org.junit.Assert.fail;
+import info.aduna.iteration.CloseableIteration;
import info.aduna.iteration.Iterations;
+
+import java.sql.SQLException;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.marmotta.kiwi.config.KiWiConfiguration;
import org.apache.marmotta.kiwi.model.rdf.KiWiTriple;
-import org.apache.marmotta.kiwi.persistence.KiWiDialect;
import org.apache.marmotta.kiwi.persistence.KiWiPersistence;
-import org.apache.marmotta.kiwi.persistence.h2.H2Dialect;
-import org.apache.marmotta.kiwi.persistence.mysql.MySQLDialect;
-import org.apache.marmotta.kiwi.persistence.pgsql.PostgreSQLDialect;
import org.apache.marmotta.kiwi.reasoner.engine.ReasoningConfiguration;
import org.apache.marmotta.kiwi.reasoner.engine.ReasoningEngine;
import org.apache.marmotta.kiwi.reasoner.model.program.Justification;
@@ -34,7 +39,7 @@ import org.apache.marmotta.kiwi.reasoner.parser.KWRLProgramParserBase;
import org.apache.marmotta.kiwi.reasoner.persistence.KiWiReasoningConnection;
import org.apache.marmotta.kiwi.reasoner.persistence.KiWiReasoningPersistence;
import org.apache.marmotta.kiwi.sail.KiWiStore;
-import org.apache.marmotta.kiwi.test.helper.DBConnectionChecker;
+import org.apache.marmotta.kiwi.test.junit.KiWiDatabaseRunner;
import org.apache.marmotta.kiwi.transactions.api.TransactionalSail;
import org.apache.marmotta.kiwi.transactions.model.TransactionData;
import org.apache.marmotta.kiwi.transactions.sail.KiWiTransactionalSail;
@@ -45,99 +50,34 @@ import org.junit.Test;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryResult;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import static org.hamcrest.Matchers.hasItem;
-
/**
* This test verifies the functionality of the KiWi Reasonong Engine. Based on a small sample program, it will test
* both incremental reasoning (by manually adding triples) and full reasoning. After reasoning completes, it will
* check if the expected inferred triples as well as their justifications are present.
- * <p/>
- * It will try running over all available databases. Except for in-memory databases like H2 or Derby, database
- * URLs must be passed as system property, or otherwise the test is skipped for this database. Available system properties:
- * <ul>
- * <li>PostgreSQL:
- * <ul>
- * <li>postgresql.url, e.g. jdbc:postgresql://localhost:5433/kiwitest?prepareThreshold=3</li>
- * <li>postgresql.user (default: lmf)</li>
- * <li>postgresql.pass (default: lmf)</li>
- * </ul>
- * </li>
- * <li>MySQL:
- * <ul>
- * <li>mysql.url, e.g. jdbc:mysql://localhost:3306/kiwitest?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull</li>
- * <li>mysql.user (default: lmf)</li>
- * <li>mysql.pass (default: lmf</li>
- * </ul>
- * </li>
- * <li>H2:
- * <ul>
- * <li>h2.url, e.g. jdbc:h2:mem;MVCC=true;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=10</li>
- * <li>h2.user (default: lmf)</li>
- * <li>h2.pass (default: lmf</li>
- * </ul>
- * </li>
- * </ul>
*
* @see org.apache.marmotta.kiwi.persistence.KiWiConnection
* @see org.apache.marmotta.kiwi.persistence.KiWiPersistence
- * <p/>
- * Author: Sebastian Schaffert
+ * @author Sebastian Schaffert (sschaffert@apache.org)
*/
-@RunWith(Parameterized.class)
+@RunWith(KiWiDatabaseRunner.class)
public class ReasoningEngineTest {
private static Logger log = LoggerFactory.getLogger(ReasoningEngineTest.class);
private static final String NS = "http://localhost/resource/";
- /**
- * Return database configurations if the appropriate parameters have been set.
- *
- * @return an array (database name, url, user, password)
- */
- @Parameterized.Parameters(name="Database Test {index}: {0} at {1}")
- public static Iterable<Object[]> databases() {
- String[] databases = {"H2", "PostgreSQL", "MySQL"};
-
- List<Object[]> result = new ArrayList<Object[]>(databases.length);
- for(String database : databases) {
- if(System.getProperty(database.toLowerCase()+".url") != null) {
- result.add(new Object[] {
- database,
- System.getProperty(database.toLowerCase()+".url"),
- System.getProperty(database.toLowerCase()+".user","lmf"),
- System.getProperty(database.toLowerCase()+".pass","lmf")
- });
- }
- }
- return result;
- }
-
-
- private KiWiDialect dialect;
-
- private String jdbcUrl;
-
- private String jdbcUser;
-
- private String jdbcPass;
-
- private KiWiStore store;
+ private KiWiStore store;
private TransactionalSail tsail;
private KiWiPersistence persistence;
private KiWiReasoningPersistence rpersistence;
@@ -145,36 +85,23 @@ public class ReasoningEngineTest {
private Repository repository;
+ private final KiWiConfiguration config;
- public ReasoningEngineTest(String database, String jdbcUrl, String jdbcUser, String jdbcPass) {
- this.jdbcPass = jdbcPass;
- this.jdbcUrl = jdbcUrl;
- this.jdbcUser = jdbcUser;
-
- if("H2".equals(database)) {
- this.dialect = new H2Dialect();
- } else if("MySQL".equals(database)) {
- this.dialect = new MySQLDialect();
- } else if("PostgreSQL".equals(database)) {
- this.dialect = new PostgreSQLDialect();
- }
- DBConnectionChecker.checkDatabaseAvailability(jdbcUrl, jdbcUser, jdbcPass, dialect);
+ public ReasoningEngineTest(KiWiConfiguration config) {
+ this.config = config;
}
@Before
public void initDatabase() throws Exception {
-
- persistence = new KiWiPersistence("test",jdbcUrl,jdbcUser,jdbcPass,dialect);
- persistence.initDatabase();
-
-
- store = new KiWiStore("test",jdbcUrl,jdbcUser,jdbcPass,dialect, "http://localhost/context/default", "http://localhost/context/inferred");
+ store = new KiWiStore(config);
tsail = new KiWiTransactionalSail(store);
repository = new SailRepository(tsail);
repository.initialize();
+ persistence = store.getPersistence();
+
rpersistence = new KiWiReasoningPersistence(persistence, repository.getValueFactory());
rpersistence.initDatabase();
@@ -202,26 +129,14 @@ public class ReasoningEngineTest {
@After
public void dropDatabase() throws Exception {
- engine.shutdown();
+ engine.shutdown(true);
rpersistence.dropDatabase();
-
persistence.dropDatabase();
- persistence.shutdown();
repository.shutDown();
}
- @org.junit.Rule
- public TestWatcher watchman = new TestWatcher() {
- /**
- * Invoked when a test is about to start
- */
- @Override
- protected void starting(Description description) {
- log.info("{} being run...", description.getMethodName());
- }
- };
/**
* Test the reasoning engine by incrementally adding and later removing triples through explicit calls to the
@@ -411,6 +326,9 @@ public class ReasoningEngineTest {
log.debug("sleeping for 100ms to let engine finish processing ... ");
Thread.sleep(100);
}
+
+ log.debug("reasoning finished, running tests");
+
con.begin();
List<Statement> inferred4 = Iterations.asList(con.getStatements(a,property,d, true));
@@ -469,6 +387,26 @@ public class ReasoningEngineTest {
Assert.assertTrue("expected inferred triple not found", con.hasStatement(b,t,d,true));
Assert.assertTrue("expected inferred triple not found", con.hasStatement(b,s,a,true));
+
+ // we also expect that there are justifications for all inferred triples
+ Resource[][] patterns = new Resource[][] {
+ new Resource[] { a, t, c },
+ new Resource[] { b, t, d },
+ new Resource[] { b, s, a }
+ };
+
+
+ RepositoryResult<Statement> result = con.getStatements(null,null,null,true, con.getValueFactory().createURI(store.getInferredContext()));
+ if(result.hasNext()) {
+ while (result.hasNext()) {
+ Statement stmt1 = result.next();
+
+ CloseableIteration<Justification, SQLException> justs1 = rcon.listJustificationsForTriple((KiWiTriple) stmt1);
+ Assert.assertTrue(justs1.hasNext());
+ }
+ } else {
+ fail("no inferred statements found");
+ }
con.commit();
} finally {
con.close();
http://git-wip-us.apache.org/repos/asf/marmotta/blob/582abb5b/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/model/JustificationTest.java
----------------------------------------------------------------------
diff --git a/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/model/JustificationTest.java b/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/model/JustificationTest.java
new file mode 100644
index 0000000..f3a1cb7
--- /dev/null
+++ b/libraries/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/model/JustificationTest.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.kiwi.reasoner.test.model;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.marmotta.commons.sesame.model.Namespaces;
+import org.apache.marmotta.kiwi.model.rdf.*;
+import org.apache.marmotta.kiwi.reasoner.model.program.Justification;
+import org.apache.marmotta.kiwi.reasoner.model.program.Rule;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+
+import java.util.*;
+
+/**
+ * Test critical functionality of justification objects, primarily equals and similar
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class JustificationTest {
+
+ protected static Random rnd = new Random();
+
+
+ private KiWiTriple t1, t2, t3, t4; // base
+ private KiWiTriple i1, i2, i3, i4; // inferred
+ private Rule r1, r2;
+
+ private KiWiUriResource ctx_inferred;
+
+ @Before
+ public void setup() {
+ KiWiUriResource s1 = randomURI();
+ KiWiUriResource s2 = randomURI();
+ KiWiUriResource s3 = randomURI();
+ KiWiUriResource s4 = randomURI();
+ KiWiUriResource p1 = randomURI();
+ KiWiUriResource p2 = randomURI();
+ KiWiNode o1 = randomObject();
+ KiWiNode o2 = randomObject();
+ KiWiNode o3 = randomObject();
+ KiWiNode o4 = randomObject();
+
+ ctx_inferred = randomURI();
+
+ t1 = new KiWiTriple(s1,p1,o1, null);
+ t2 = new KiWiTriple(s1,p1,o2, null);
+ t3 = new KiWiTriple(s2,p1,o3, null);
+ t4 = new KiWiTriple(s1,p1,o1, randomURI());
+
+
+ i1 = new KiWiTriple(s1,p2,o1, ctx_inferred); i1.setInferred(true);
+ i2 = new KiWiTriple(s1,p1,o2, ctx_inferred); i2.setInferred(true);
+ i3 = new KiWiTriple(s3,p1,o3, ctx_inferred); i3.setInferred(true);
+ i4 = new KiWiTriple(s1,p2,o1, ctx_inferred); i4.setInferred(true);
+
+
+ }
+
+
+ @Test
+ public void testJustificationEquals() {
+ Justification j1 = new Justification();
+ j1.setTriple(i1);
+ j1.getSupportingTriples().add(t1);
+ j1.getSupportingTriples().add(t4);
+
+ Justification j2 = new Justification();
+ j2.setTriple(i4);
+ j2.getSupportingTriples().add(t4);
+ j2.getSupportingTriples().add(t1);
+
+ Assert.assertEquals(j1,j2);
+
+ // j3 differs in the inferred triple
+ Justification j3 = new Justification();
+ j3.setTriple(i2);
+ j3.getSupportingTriples().add(t4);
+ j3.getSupportingTriples().add(t1);
+
+ Assert.assertNotEquals(j1, j3);
+
+ // j4 differs in the supporting triples
+ Justification j4 = new Justification();
+ j4.setTriple(i1);
+ j4.getSupportingTriples().add(t2);
+ j4.getSupportingTriples().add(t4);
+
+ Assert.assertNotEquals(j1, j4);
+ }
+
+
+ @Test
+ public void testJustificationSet() {
+ Set<Justification> set = new HashSet<>();
+
+ Justification j1 = new Justification();
+ j1.setTriple(i1);
+ j1.getSupportingTriples().add(t1);
+ j1.getSupportingTriples().add(t4);
+ set.add(j1);
+
+ Justification j2 = new Justification();
+ j2.setTriple(i4);
+ j2.getSupportingTriples().add(t4);
+ j2.getSupportingTriples().add(t1);
+
+ Assert.assertTrue(set.contains(j2));
+
+ set.add(j2);
+
+ Assert.assertEquals(1, set.size());
+
+
+ // j3 differs in the inferred triple
+ Justification j3 = new Justification();
+ j3.setTriple(i2);
+ j3.getSupportingTriples().add(t4);
+ j3.getSupportingTriples().add(t1);
+
+ Assert.assertFalse(set.contains(j3));
+
+ set.add(j3);
+
+ Assert.assertEquals(2, set.size());
+
+
+ // j4 differs in the supporting triples
+ Justification j4 = new Justification();
+ j4.setTriple(i1);
+ j4.getSupportingTriples().add(t2);
+ j4.getSupportingTriples().add(t4);
+
+ Assert.assertFalse(set.contains(j4));
+
+ set.add(j4);
+
+ Assert.assertEquals(3, set.size());
+ }
+
+
+
+ /**
+ * Return a random URI, with a 10% chance of returning a URI that has already been used.
+ * @return
+ */
+ protected KiWiUriResource randomURI() {
+ KiWiUriResource resource = new KiWiUriResource("http://localhost/" + RandomStringUtils.randomAlphanumeric(8));
+ return resource;
+ }
+
+ /**
+ * Return a random RDF value, either a reused object (10% chance) or of any other kind.
+ * @return
+ */
+ protected KiWiNode randomObject() {
+ KiWiNode object;
+ switch(rnd.nextInt(6)) {
+ case 0: object = new KiWiUriResource("http://localhost/" + RandomStringUtils.randomAlphanumeric(8));
+ break;
+ case 1: object = new KiWiAnonResource(RandomStringUtils.randomAscii(8));
+ break;
+ case 2: object = new KiWiStringLiteral(RandomStringUtils.randomAscii(40));
+ break;
+ case 3: object = new KiWiIntLiteral(rnd.nextLong(), new KiWiUriResource(Namespaces.NS_XSD + "integer"));
+ break;
+ case 4: object = new KiWiDoubleLiteral(rnd.nextDouble(), new KiWiUriResource(Namespaces.NS_XSD + "double"));
+ break;
+ case 5: object = new KiWiBooleanLiteral(rnd.nextBoolean(), new KiWiUriResource(Namespaces.NS_XSD + "boolean"));
+ break;
+ default: object = new KiWiUriResource("http://localhost/" + RandomStringUtils.randomAlphanumeric(8));
+ break;
+
+ }
+ return object;
+ }
+
+}