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 2013/02/19 13:51:59 UTC
[47/52] [partial] code contribution,
initial import of relevant modules of LMF-3.0.0-SNAPSHOT based on
revision 4bf944319368 of the default branch at https://code.google.com/p/lmf/
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/JustificationPersistenceTest.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/JustificationPersistenceTest.java b/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/JustificationPersistenceTest.java
new file mode 100644
index 0000000..5c23332
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/JustificationPersistenceTest.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2013 The Apache Software Foundation
+ *
+ * Licensed 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.persistence;
+
+import info.aduna.iteration.CloseableIteration;
+import org.apache.commons.lang.RandomStringUtils;
+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.model.program.Justification;
+import org.apache.marmotta.kiwi.reasoner.model.program.Program;
+import org.apache.marmotta.kiwi.reasoner.parser.KWRLProgramParser;
+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.sail.KiWiValueFactory;
+import org.apache.marmotta.kiwi.test.helper.DBConnectionChecker;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.openrdf.model.Statement;
+import org.openrdf.model.URI;
+import org.openrdf.repository.Repository;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.sail.SailRepository;
+
+import java.sql.BatchUpdateException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.hamcrest.Matchers.*;
+
+/**
+ * This test verifies the persistence functionality of the reasoning component regarding storing, loading and deleting
+ * reasoning programs.
+ *
+ * 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
+ */
+@RunWith(Parameterized.class)
+public class JustificationPersistenceTest {
+
+ /**
+ * 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 KiWiPersistence persistence;
+ private KiWiReasoningPersistence rpersistence;
+
+ private Repository repository;
+
+
+ public JustificationPersistenceTest(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);
+ }
+
+
+ @Before
+ public void initDatabase() throws Exception {
+
+ persistence = new KiWiPersistence("test",jdbcUrl,jdbcUser,jdbcPass,dialect);
+ persistence.initDatabase();
+
+ repository = new SailRepository(new KiWiStore("test",jdbcUrl,jdbcUser,jdbcPass,dialect, "http://localhost/context/default", "http://localhost/context/inferred"));
+ repository.initialize();
+
+ rpersistence = new KiWiReasoningPersistence(persistence, repository.getValueFactory());
+ rpersistence.initDatabase();
+
+ }
+
+ @After
+ public void dropDatabase() throws Exception {
+ rpersistence.dropDatabase();
+
+ persistence.dropDatabase();
+ persistence.shutdown();
+
+ repository.shutDown();
+ }
+
+
+ /**
+ * Test 1: create some triples through a repository connection (some inferred, some base), load a program, and
+ * store justifications for the inferred triples based on rules and base triples. Test the different listing
+ * functions.
+ *
+ */
+ @Test
+ public void testStoreJustifications() throws Exception {
+ KiWiValueFactory v = (KiWiValueFactory) repository.getValueFactory();
+
+ URI ctxb = v.createURI("http://localhost/context/default");
+ URI ctxi = v.createURI("http://localhost/context/inferred");
+
+ URI s1 = v.createURI("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+ URI s2 = v.createURI("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+ URI s3 = v.createURI("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+ URI p1 = v.createURI("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+ URI p2 = v.createURI("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+ URI o1 = v.createURI("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+ URI o2 = v.createURI("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+ URI o3 = v.createURI("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+
+
+ // first, load a sample program (it does not really matter what it actually contains, since we are not really
+ // running the reasoner)
+ KWRLProgramParserBase parser = new KWRLProgramParser(v, this.getClass().getResourceAsStream("test-001.kwrl"));
+ Program p = parser.parseProgram();
+ p.setName("test-001");
+
+ KiWiReasoningConnection connection = rpersistence.getConnection();
+ try {
+ // should not throw an exception and the program should have a database ID afterwards
+ connection.storeProgram(p);
+ connection.commit();
+ } finally {
+ connection.close();
+ }
+
+ // then get a connection to the repository and create a number of triples, some inferred and some base
+ RepositoryConnection con = repository.getConnection();
+ try {
+ con.add(s1,p1,o1);
+ con.add(s2,p1,o2);
+ con.add(s3,p1,o3);
+
+ con.add(s1,p2,o1,ctxi);
+ con.add(s2,p2,o2,ctxi);
+ con.add(s3,p2,o3,ctxi);
+
+ con.commit();
+ } finally {
+ con.close();
+ }
+
+ connection = rpersistence.getConnection();
+ try {
+ // retrieve the persisted triples and put them into two sets to build justifications
+ List<Statement> baseTriples = asList(connection.listTriples(null,null,null,v.convert(ctxb),false));
+ List<Statement> infTriples = asList(connection.listTriples(null,null,null,v.convert(ctxi),true));
+
+ Assert.assertEquals("number of base triples was not 3", 3, baseTriples.size());
+ Assert.assertEquals("number of inferred triples was not 3", 3, infTriples.size());
+
+ // we manually update the "inferred" flag for all inferred triples, since this is not possible through the
+ // repository API
+ PreparedStatement updateInferred = connection.getJDBCConnection().prepareStatement("UPDATE triples SET inferred = true WHERE id = ?");
+ for(Statement stmt : infTriples) {
+ KiWiTriple triple = (KiWiTriple)stmt;
+ updateInferred.setLong(1,triple.getId());
+ updateInferred.addBatch();
+ }
+ updateInferred.executeBatch();
+ updateInferred.close();
+
+ // now we create some justifications for the inferred triples and store them
+ Set<Justification> justifications = new HashSet<Justification>();
+ Justification j1 = new Justification();
+ j1.getSupportingRules().add(p.getRules().get(0));
+ j1.getSupportingRules().add(p.getRules().get(1));
+ j1.getSupportingTriples().add((KiWiTriple) baseTriples.get(0));
+ j1.getSupportingTriples().add((KiWiTriple) baseTriples.get(1));
+ j1.setTriple((KiWiTriple) infTriples.get(0));
+ justifications.add(j1);
+
+ Justification j2 = new Justification();
+ j2.getSupportingRules().add(p.getRules().get(1));
+ j2.getSupportingTriples().add((KiWiTriple) baseTriples.get(1));
+ j2.getSupportingTriples().add((KiWiTriple) baseTriples.get(2));
+ j2.setTriple((KiWiTriple) infTriples.get(1));
+ justifications.add(j2);
+
+ connection.storeJustifications(justifications);
+ connection.commit();
+
+ // we should now have two justifications in the database
+ PreparedStatement listJustifications = connection.getJDBCConnection().prepareStatement("SELECT count(*) AS count FROM reasoner_justifications");
+ ResultSet resultListJustifications = listJustifications.executeQuery();
+
+ Assert.assertTrue(resultListJustifications.next());
+ Assert.assertEquals(2, resultListJustifications.getInt("count"));
+ resultListJustifications.close();
+ connection.commit();
+
+ PreparedStatement listSupportingTriples = connection.getJDBCConnection().prepareStatement("SELECT count(*) AS count FROM reasoner_just_supp_triples");
+ ResultSet resultListSupportingTriples = listSupportingTriples.executeQuery();
+
+ Assert.assertTrue(resultListSupportingTriples.next());
+ Assert.assertEquals(4, resultListSupportingTriples.getInt("count"));
+ resultListSupportingTriples.close();
+ connection.commit();
+
+ PreparedStatement listSupportingRules = connection.getJDBCConnection().prepareStatement("SELECT count(*) AS count FROM reasoner_just_supp_rules");
+ ResultSet resultListSupportingRules = listSupportingRules.executeQuery();
+
+ Assert.assertTrue(resultListSupportingRules.next());
+ Assert.assertEquals(3, resultListSupportingRules.getInt("count"));
+ resultListSupportingRules.close();
+ connection.commit();
+
+
+
+ // *** check listing justifications by base triple (supporting triple)
+
+ // there should now be two justifications based on triple baseTriples.get(1))
+ List<Justification> supported1 = asList(connection.listJustificationsBySupporting((KiWiTriple) baseTriples.get(1)));
+ Assert.assertEquals("number of justifications is wrong",2,supported1.size());
+ Assert.assertThat("justifications differ", supported1, hasItems(j1,j2));
+
+ // only j1 should be supported by triple baseTriples.get(0))
+ List<Justification> supported2 = asList(connection.listJustificationsBySupporting((KiWiTriple) baseTriples.get(0)));
+ Assert.assertEquals("number of justifications is wrong", 1, supported2.size());
+ Assert.assertThat("justifications differ", supported2, allOf(hasItem(j1), not(hasItem(j2))));
+
+ // only j2 should be supported by triple baseTriples.get(2))
+ List<Justification> supported3 = asList(connection.listJustificationsBySupporting((KiWiTriple) baseTriples.get(2)));
+ Assert.assertEquals("number of justifications is wrong", 1, supported3.size());
+ Assert.assertThat("justifications differ", supported3, allOf(hasItem(j2), not(hasItem(j1))));
+
+ // *** check listing justificatoins by supporting rule
+
+ // there should now be two justifications based on triple p.getRules().get(1)
+ List<Justification> supported4 = asList(connection.listJustificationsBySupporting(p.getRules().get(1)));
+ Assert.assertEquals("number of justifications is wrong", 2, supported4.size());
+ Assert.assertThat("justifications differ", supported4, hasItems(j1,j2));
+
+ // only j1 should be supported by triple p.getRules().get(0)
+ List<Justification> supported5 = asList(connection.listJustificationsBySupporting(p.getRules().get(0)));
+ Assert.assertEquals("number of justifications is wrong", 1, supported5.size());
+ Assert.assertThat("justifications differ", supported5, allOf(hasItem(j1), not(hasItem(j2))));
+
+
+ // *** check listing justifications by supported (inferred) triple
+
+ // there should now be one justification supporting infTriples.get(0)
+ List<Justification> supported6 = asList(connection.listJustificationsForTriple((KiWiTriple) infTriples.get(0)));
+ Assert.assertEquals("number of justifications is wrong", 1, supported6.size());
+ Assert.assertThat("justifications differ", supported6, allOf(hasItem(j1), not(hasItem(j2))));
+
+ // there should now be one justification supporting infTriples.get(1)
+ List<Justification> supported7 = asList(connection.listJustificationsForTriple((KiWiTriple) infTriples.get(1)));
+ Assert.assertEquals("number of justifications is wrong", 1, supported7.size());
+ Assert.assertThat("justifications differ", supported7, allOf(hasItem(j2), not(hasItem(j1))));
+
+ // there should now be no justification supporting infTriples.get(2)
+ List<Justification> supported8 = asList(connection.listJustificationsForTriple((KiWiTriple) infTriples.get(2)));
+ Assert.assertEquals("number of justifications is wrong", 0, supported8.size());
+
+
+ // *** check listing unsupported triples
+ List<KiWiTriple> unsupported = asList(connection.listUnsupportedTriples());
+ Assert.assertEquals("number of unsupported triples is wrong",1,unsupported.size());
+ Assert.assertThat("unsupported triples differ", unsupported, hasItem((KiWiTriple)infTriples.get(2)));
+
+
+ // now we delete justification 2; as a consequence,
+ // - there should be only once justification left
+ // - there should be two unsupported triples
+ connection.deleteJustifications(Collections.singleton(j2));
+
+
+ // we should now have one justifications in the database
+ resultListJustifications = listJustifications.executeQuery();
+
+ Assert.assertTrue(resultListJustifications.next());
+ Assert.assertEquals(1, resultListJustifications.getInt("count"));
+ resultListJustifications.close();
+ connection.commit();
+
+ resultListSupportingTriples = listSupportingTriples.executeQuery();
+
+ Assert.assertTrue(resultListSupportingTriples.next());
+ Assert.assertEquals(2, resultListSupportingTriples.getInt("count"));
+ resultListSupportingTriples.close();
+ connection.commit();
+
+ resultListSupportingRules = listSupportingRules.executeQuery();
+
+ Assert.assertTrue(resultListSupportingRules.next());
+ Assert.assertEquals(2, resultListSupportingRules.getInt("count"));
+ resultListSupportingRules.close();
+ connection.commit();
+
+ List<KiWiTriple> unsupported2 = asList(connection.listUnsupportedTriples());
+ Assert.assertEquals("number of unsupported triples is wrong",2,unsupported2.size());
+ Assert.assertThat("unsupported triples differ", unsupported2, hasItem((KiWiTriple)infTriples.get(1)));
+
+
+ } catch(BatchUpdateException ex) {
+ if(ex.getNextException() != null) {
+ ex.printStackTrace();
+ throw ex.getNextException();
+ } else {
+ throw ex;
+ }
+ } finally {
+ connection.close();
+ }
+
+ }
+
+
+
+ /**
+ * Workaround for https://openrdf.atlassian.net/browse/SES-1702 in Sesame 2.7.0-beta1
+ * @param <E>
+ * @return
+ */
+ public static <E,X extends Exception> List<E> asList(CloseableIteration<E,X> result) throws Exception {
+ ArrayList<E> collection = new ArrayList<E>();
+ try {
+ while (result.hasNext()) {
+ collection.add(result.next());
+ }
+
+ return collection;
+ } finally {
+ result.close();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/KWRLProgramPersistenceTest.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/KWRLProgramPersistenceTest.java b/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/KWRLProgramPersistenceTest.java
new file mode 100644
index 0000000..388c8f1
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/KWRLProgramPersistenceTest.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2013 The Apache Software Foundation
+ *
+ * Licensed 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.persistence;
+
+import info.aduna.iteration.CloseableIteration;
+import org.apache.marmotta.kiwi.persistence.KiWiConnection;
+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.model.program.Program;
+import org.apache.marmotta.kiwi.reasoner.parser.KWRLProgramParser;
+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.test.helper.DBConnectionChecker;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.openrdf.repository.Repository;
+import org.openrdf.repository.sail.SailRepository;
+import org.openrdf.sail.memory.MemoryStore;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.hamcrest.Matchers.hasItems;
+
+/**
+ * This test verifies the persistence functionality of the reasoning component regarding storing, loading and deleting
+ * reasoning programs.
+ *
+ * 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
+ */
+@RunWith(Parameterized.class)
+public class KWRLProgramPersistenceTest {
+
+ /**
+ * 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 KiWiPersistence persistence;
+ private KiWiReasoningPersistence rpersistence;
+
+ private Repository repository;
+
+
+ public KWRLProgramPersistenceTest(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);
+ }
+
+
+ @Before
+ public void initDatabase() throws Exception {
+ repository = new SailRepository(new MemoryStore());
+ repository.initialize();
+
+ persistence = new KiWiPersistence("test",jdbcUrl,jdbcUser,jdbcPass,dialect);
+ persistence.initDatabase();
+
+ rpersistence = new KiWiReasoningPersistence(persistence, repository.getValueFactory());
+ rpersistence.initDatabase();
+
+ }
+
+ @After
+ public void dropDatabase() throws Exception {
+ rpersistence.dropDatabase();
+
+ persistence.dropDatabase();
+ persistence.shutdown();
+
+ repository.shutDown();
+ }
+
+
+ @Test
+ public void testTablesCreateDrop() throws Exception {
+ // test if database exists and has a version
+ KiWiConnection connection = rpersistence.getConnection();
+ try {
+ Assert.assertThat(connection.getDatabaseTables(), hasItems(
+ "reasoner_programs", "reasoner_program_namespaces", "reasoner_program_rules",
+ "reasoner_rules", "reasoner_justifications", "reasoner_just_supp_triples", "reasoner_just_supp_rules"));
+ Assert.assertEquals(1, connection.getDatabaseVersion());
+
+ connection.commit();
+ } finally {
+ connection.close();
+ }
+ }
+
+ @Test
+ public void testStoreLoadProgram() throws Exception {
+ KWRLProgramParserBase parser = new KWRLProgramParser(repository.getValueFactory(), this.getClass().getResourceAsStream("test-001.kwrl"));
+ Program p = parser.parseProgram();
+ p.setName("test-001");
+
+ KiWiReasoningConnection connection = rpersistence.getConnection();
+ try {
+ // should not throw an exception and the program should have a database ID afterwards
+ connection.storeProgram(p);
+ connection.commit();
+
+ Assert.assertNotNull("program did not get a database ID",p.getId());
+
+ // load the program by name and check if it is equal to the original program
+ Program p1 = connection.loadProgram("test-001");
+ connection.commit();
+
+ Assert.assertNotNull("load program by name: loaded program is null",p1);
+ Assert.assertEquals("load program by name: loaded program differs from original",p,p1);
+
+ // load the program by name and check if it is equal to the original program
+ Program p2 = connection.loadProgram(p.getId());
+ connection.commit();
+
+ Assert.assertNotNull("load program by ID: loaded program is null",p2);
+ Assert.assertEquals("load program by ID: loaded program differs from original",p,p2);
+
+ } finally {
+ connection.close();
+ }
+ }
+
+ /**
+ * Test storing and then updating a program (by removing two rules)
+ */
+ @Test
+ public void testUpdateProgram() throws Exception {
+ KWRLProgramParserBase parser = new KWRLProgramParser(repository.getValueFactory(), this.getClass().getResourceAsStream("test-001.kwrl"));
+ Program p = parser.parseProgram();
+ p.setName("test-001");
+
+ KiWiReasoningConnection connection = rpersistence.getConnection();
+ try {
+ // should not throw an exception and the program should have a database ID afterwards
+ connection.storeProgram(p);
+ connection.commit();
+
+ Assert.assertNotNull("program did not get a database ID",p.getId());
+
+
+ // load the program by name and check if it is equal to the original program
+ Program p1 = connection.loadProgram("test-001");
+ connection.commit();
+
+ Assert.assertNotNull("load program by name: loaded program is null",p1);
+ Assert.assertEquals("load program by name: loaded program differs from original",p,p1);
+
+
+ PreparedStatement listRules1 = connection.getJDBCConnection().prepareStatement("SELECT count(*) AS count FROM reasoner_rules");
+ ResultSet resultListRules1 = listRules1.executeQuery();
+
+ Assert.assertTrue(resultListRules1.next());
+ Assert.assertEquals(5, resultListRules1.getInt("count"));
+ resultListRules1.close();
+ connection.commit();
+
+
+
+ // now remove two rules from the original and update the existing program
+ p.getRules().remove(p.getRules().size()-1);
+ p.getRules().remove(p.getRules().size()-1);
+ p.addNamespace("myns","http://example.com/myns");
+
+ connection.updateProgram(p);
+
+ // load the program by name and check if it is equal to the original program
+ Program p2 = connection.loadProgram(p.getName());
+ connection.commit();
+
+ Assert.assertNotNull("load program by name: loaded program is null",p2);
+ Assert.assertEquals("load program by name: loaded program differs from original",p,p2);
+
+ PreparedStatement listRules2 = connection.getJDBCConnection().prepareStatement("SELECT count(*) AS count FROM reasoner_rules");
+ ResultSet resultListRules2 = listRules2.executeQuery();
+
+ Assert.assertTrue(resultListRules2.next());
+ Assert.assertEquals(3, resultListRules2.getInt("count"));
+ resultListRules2.close();
+ connection.commit();
+
+
+
+ } finally {
+ connection.close();
+ }
+ }
+
+ /**
+ * Add a bunch of reasoner programs to the database and check if listing the programs works
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testListDeletePrograms() throws Exception {
+ KiWiReasoningConnection connection = rpersistence.getConnection();
+ try {
+ List<Program> programs = new ArrayList<Program>();
+ for(String name : new String[] {"test-001", "test-002", "test-003", "test-004"}) {
+ KWRLProgramParserBase parser = new KWRLProgramParser(repository.getValueFactory(), this.getClass().getResourceAsStream(name+".kwrl"));
+ Program p = parser.parseProgram();
+ p.setName(name);
+ connection.storeProgram(p);
+ connection.commit();
+
+ programs.add(p);
+ }
+
+ // now we should have a collection of 4 programs in the database
+ PreparedStatement checkNodeStmt = connection.getJDBCConnection().prepareStatement("SELECT count(*) AS count FROM reasoner_programs");
+ ResultSet result = checkNodeStmt.executeQuery();
+
+ Assert.assertTrue(result.next());
+ Assert.assertEquals(4, result.getInt("count"));
+ result.close();
+ connection.commit();
+
+ // list programs should return the same number and equal programs
+ List<Program> dbPrograms1 = asList(connection.listPrograms());
+ Assert.assertEquals(4, dbPrograms1.size());
+ Assert.assertEquals("list of original programs differs from list of database",programs,dbPrograms1);
+
+ // delete all programs and check if the database does not contain any remaining entries in the different tables
+ for(Program p : programs) {
+ connection.deleteProgram(p);
+ connection.commit();
+ }
+ List<Program> dbPrograms2 = asList(connection.listPrograms());
+ Assert.assertEquals(0, dbPrograms2.size());
+
+ PreparedStatement listPrograms = connection.getJDBCConnection().prepareStatement("SELECT count(*) AS count FROM reasoner_programs");
+ ResultSet resultListPrograms = listPrograms.executeQuery();
+
+ Assert.assertTrue(resultListPrograms.next());
+ Assert.assertEquals(0, resultListPrograms.getInt("count"));
+ resultListPrograms.close();
+ connection.commit();
+
+ PreparedStatement listRules = connection.getJDBCConnection().prepareStatement("SELECT count(*) AS count FROM reasoner_rules");
+ ResultSet resultListRules = listRules.executeQuery();
+
+ Assert.assertTrue(resultListRules.next());
+ Assert.assertEquals(0, resultListRules.getInt("count"));
+ resultListRules.close();
+ connection.commit();
+
+ PreparedStatement listNamespaces = connection.getJDBCConnection().prepareStatement("SELECT count(*) AS count FROM reasoner_program_namespaces");
+ ResultSet resultListNamespaces = listNamespaces.executeQuery();
+
+ Assert.assertTrue(resultListNamespaces.next());
+ Assert.assertEquals(0, resultListNamespaces.getInt("count"));
+ resultListNamespaces.close();
+ connection.commit();
+
+ PreparedStatement listProgramRules = connection.getJDBCConnection().prepareStatement("SELECT count(*) AS count FROM reasoner_program_rules");
+ ResultSet resultListProgramRules = listProgramRules.executeQuery();
+
+ Assert.assertTrue(resultListProgramRules.next());
+ Assert.assertEquals(0, resultListProgramRules.getInt("count"));
+ resultListProgramRules.close();
+ connection.commit();
+
+ } finally {
+ connection.close();
+ }
+ }
+
+
+ /**
+ * Workaround for https://openrdf.atlassian.net/browse/SES-1702 in Sesame 2.7.0-beta1
+ * @param <E>
+ * @return
+ */
+ public static <E,X extends Exception> List<E> asList(CloseableIteration<E,X> result) throws Exception {
+ ArrayList<E> collection = new ArrayList<E>();
+ try {
+ while (result.hasNext()) {
+ collection.add(result.next());
+ }
+
+ return collection;
+ } finally {
+ result.close();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/PatternQueryTest.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/PatternQueryTest.java b/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/PatternQueryTest.java
new file mode 100644
index 0000000..2627d17
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/persistence/PatternQueryTest.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2013 The Apache Software Foundation
+ *
+ * Licensed 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.persistence;
+
+import com.google.common.collect.ImmutableSet;
+import info.aduna.iteration.CloseableIteration;
+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.model.program.LiteralField;
+import org.apache.marmotta.kiwi.reasoner.model.program.Pattern;
+import org.apache.marmotta.kiwi.reasoner.model.program.ResourceField;
+import org.apache.marmotta.kiwi.reasoner.model.program.VariableField;
+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;
+import org.apache.marmotta.kiwi.sail.KiWiStore;
+import org.apache.marmotta.kiwi.test.helper.DBConnectionChecker;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.openrdf.model.Literal;
+import org.openrdf.model.URI;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.repository.Repository;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.sail.SailRepository;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This test verifies the persistence functionality of the reasoning component regarding storing, loading and deleting
+ * reasoning programs.
+ *
+ * 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
+ */
+@RunWith(Parameterized.class)
+public class PatternQueryTest {
+
+ // string constants for RDF values
+ private static final String SUBJECT1 = "http://localhost/resource/S1";
+ private static final String SUBJECT2 = "http://localhost/resource/S2";
+ private static final String SUBJECT3 = "http://localhost/resource/S3";
+ private static final String PREDICATE1 = "http://localhost/resource/P1";
+ private static final String PREDICATE2 = "http://localhost/resource/P2";
+ private static final String OBJECT1 = "http://localhost/resource/O1";
+ private static final String OBJECT2 = "http://localhost/resource/O2";
+ private static final String OBJECT3 = "Literal Value 1";
+ private static final String OBJECT4 = "Literal Value 2";
+ private static final String OBJECT5 = "Literal Value 3";
+
+
+
+ /**
+ * 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 KiWiPersistence persistence;
+ private KiWiReasoningPersistence rpersistence;
+
+ private Repository repository;
+
+
+ public PatternQueryTest(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);
+ }
+
+
+ @Before
+ public void initDatabase() throws Exception {
+
+ persistence = new KiWiPersistence("test",jdbcUrl,jdbcUser,jdbcPass,dialect);
+ persistence.initDatabase();
+
+ repository = new SailRepository(new KiWiStore("test",jdbcUrl,jdbcUser,jdbcPass,dialect, "http://localhost/context/default", "http://localhost/context/inferred"));
+ repository.initialize();
+
+ rpersistence = new KiWiReasoningPersistence(persistence, repository.getValueFactory());
+ rpersistence.initDatabase();
+
+ // add some triples
+ RepositoryConnection con = repository.getConnection();
+ try {
+ ValueFactory v = con.getValueFactory();
+
+ con.add(v.createURI(SUBJECT1), v.createURI(PREDICATE1), v.createURI(SUBJECT2));
+ con.add(v.createURI(SUBJECT1), v.createURI(PREDICATE2), v.createLiteral(OBJECT3));
+ con.add(v.createURI(SUBJECT2), v.createURI(PREDICATE1), v.createURI(OBJECT2));
+ con.add(v.createURI(SUBJECT2), v.createURI(PREDICATE2), v.createLiteral(OBJECT4));
+ con.add(v.createURI(SUBJECT3), v.createURI(PREDICATE2), v.createLiteral(OBJECT5));
+
+ con.commit();
+ } finally {
+ con.close();
+ }
+
+ }
+
+ @After
+ public void dropDatabase() throws Exception {
+ rpersistence.dropDatabase();
+
+ persistence.dropDatabase();
+ persistence.shutdown();
+
+ repository.shutDown();
+ }
+
+
+ // test the method for querying patterns by:
+ // - evaluating a single pattern without variables (no bindings but justifications non-empty)
+ // - evaluating a single pattern with variables (bindings and justifications non-empty)
+ // - evaluating a collection of patterns (more complex SQL query)
+
+ /**
+ * Test a single pattern with constant fields
+ */
+ @Test
+ public void testSingleConstantPattern() throws Exception {
+ ValueFactory v = repository.getValueFactory();
+ URI subject = v.createURI(SUBJECT1);
+ URI predicate = v.createURI(PREDICATE2);
+ Literal object = v.createLiteral(OBJECT3);
+
+ Pattern p = new Pattern(new ResourceField(subject), new ResourceField(predicate), new LiteralField(object));
+ KiWiReasoningConnection connection = rpersistence.getConnection();
+ try {
+ List<QueryResult> results = asList(connection.query(Collections.singleton(p), null, null, null, true));
+ Assert.assertEquals(1, results.size());
+ Assert.assertEquals(1,results.get(0).getJustifications().size());
+
+ KiWiTriple justification = results.get(0).getJustifications().iterator().next();
+ Assert.assertEquals(subject, justification.getSubject());
+ Assert.assertEquals(predicate, justification.getPredicate());
+ Assert.assertEquals(object, justification.getObject());
+
+ connection.commit();
+ } finally {
+ connection.close();
+ }
+ }
+
+ /**
+ * Test a single pattern with constant fields and variables
+ */
+ @Test
+ public void testSingleVariablePattern() throws Exception {
+ ValueFactory v = repository.getValueFactory();
+ URI predicate = v.createURI(PREDICATE2);
+
+ Pattern p = new Pattern(new VariableField("X"), new ResourceField(predicate), new VariableField("Y"));
+ KiWiReasoningConnection connection = rpersistence.getConnection();
+ try {
+ List<QueryResult> results = asList(connection.query(Collections.singleton(p), null, null, null, true));
+ Assert.assertEquals(3, results.size());
+
+ for(int i=0; i<3; i++) {
+ Assert.assertEquals(1,results.get(i).getJustifications().size());
+
+ KiWiTriple justification = results.get(i).getJustifications().iterator().next();
+ Assert.assertEquals(predicate, justification.getPredicate());
+ }
+
+ connection.commit();
+ } finally {
+ connection.close();
+ }
+ }
+
+ /**
+ * Test a conjunction of two patterns with variables and constants
+ */
+ @Test
+ public void testMultipleVariablePattern() throws Exception {
+ ValueFactory v = repository.getValueFactory();
+ URI predicate1 = v.createURI(PREDICATE1);
+ URI predicate2 = v.createURI(PREDICATE2);
+
+ VariableField x = new VariableField("X");
+ VariableField y = new VariableField("Y");
+ VariableField z = new VariableField("Z");
+
+ Pattern p1 = new Pattern(x, new ResourceField(predicate1), y);
+ Pattern p2 = new Pattern(y, new ResourceField(predicate1), z);
+ KiWiReasoningConnection connection = rpersistence.getConnection();
+ try {
+ List<QueryResult> results = asList(connection.query(ImmutableSet.of(p1,p2), null, null, null, true));
+ Assert.assertEquals(1, results.size());
+ Assert.assertEquals(2, results.get(0).getJustifications().size());
+
+
+ Assert.assertEquals(SUBJECT1, results.get(0).getBindings().get(x).stringValue());
+ Assert.assertEquals(SUBJECT2, results.get(0).getBindings().get(y).stringValue());
+ Assert.assertEquals(OBJECT2, results.get(0).getBindings().get(z).stringValue());
+
+ KiWiTriple justification1 = results.get(0).getJustifications().iterator().next();
+ Assert.assertEquals(predicate1, justification1.getPredicate());
+
+ connection.commit();
+ } finally {
+ connection.close();
+ }
+
+
+ }
+
+
+
+ /**
+ * Workaround for https://openrdf.atlassian.net/browse/SES-1702 in Sesame 2.7.0-beta1
+ * @param <E>
+ * @return
+ */
+ public static <E,X extends Exception> List<E> asList(CloseableIteration<E,X> result) throws Exception {
+ ArrayList<E> collection = new ArrayList<E>();
+ try {
+ while (result.hasNext()) {
+ collection.add(result.next());
+ }
+
+ return collection;
+ } finally {
+ result.close();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/sail/ReasoningLargeTest.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/sail/ReasoningLargeTest.java b/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/sail/ReasoningLargeTest.java
new file mode 100644
index 0000000..2a85e72
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/sail/ReasoningLargeTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013 The Apache Software Foundation
+ *
+ * Licensed 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.sail;
+
+/**
+ * This test verifies reasoning with larger datasets and more complex programs. It loads an initial large dataset and
+ * program, runs full reasoning over the triple store, and then adds a second large dataset.
+ * <p/>
+ * Author: Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class ReasoningLargeTest {
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/sail/ReasoningSailTest.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/sail/ReasoningSailTest.java b/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/sail/ReasoningSailTest.java
new file mode 100644
index 0000000..6e771a6
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/java/org/apache/marmotta/kiwi/reasoner/test/sail/ReasoningSailTest.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2013 The Apache Software Foundation
+ *
+ * Licensed 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.sail;
+
+import org.apache.marmotta.kiwi.persistence.KiWiDialect;
+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.sail.KiWiReasoningSail;
+import org.apache.marmotta.kiwi.sail.KiWiStore;
+import org.apache.marmotta.kiwi.test.helper.DBConnectionChecker;
+import org.apache.marmotta.kiwi.transactions.sail.KiWiTransactionalSail;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.openrdf.model.URI;
+import org.openrdf.repository.Repository;
+import org.openrdf.repository.RepositoryConnection;
+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.List;
+
+/**
+ * Test the reasoning sail with small sample datasets. It will test both full and incremental reasoning.
+ * <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
+ */
+@RunWith(Parameterized.class)
+public class ReasoningSailTest {
+
+ private static Logger log = LoggerFactory.getLogger(ReasoningSailTest.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 KiWiTransactionalSail tsail;
+ private KiWiReasoningSail rsail;
+
+ private Repository repository;
+
+
+ public ReasoningSailTest(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);
+ }
+
+
+ @Before
+ public void initDatabase() throws Exception {
+ store = new KiWiStore("test",jdbcUrl,jdbcUser,jdbcPass,dialect, "http://localhost/context/default", "http://localhost/context/inferred");
+ tsail = new KiWiTransactionalSail(store);
+ rsail = new KiWiReasoningSail(tsail, new ReasoningConfiguration());
+ repository = new SailRepository(rsail);
+ repository.initialize();
+ }
+
+ @After
+ public void dropDatabase() throws Exception {
+ rsail.getPersistence().dropDatabase();
+ store.getPersistence().dropDatabase();
+ repository.shutDown();
+ }
+
+
+ /**
+ * Test incremental reasoning with a small sample program. This test will carry out the following steps in order:
+ * - load the program "simple.kwrl" into the reasoning engine
+ * - import the turtle file "simple.ttl" into the repository
+ * - wait for the reasoner to finish
+ * - check if all expected inferred triples exist
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testIncrementalReasoning() throws Exception {
+
+ // load the program "simple.kwrl" into the reasoning engine
+ rsail.addProgram("simple", this.getClass().getResourceAsStream("simple.kwrl"));
+
+ // import the turtle file "simple.ttl" into the repository
+ RepositoryConnection importCon = repository.getConnection();
+ try {
+ importCon.begin();
+ importCon.add(this.getClass().getResourceAsStream("simple.ttl"),NS, RDFFormat.TURTLE);
+ importCon.commit();
+ } finally {
+ importCon.close();
+ }
+
+ // wait for the reasoner to finish
+ while(rsail.getEngine().isRunning()) {
+ log.debug("sleeping for 100ms to let engine finish processing ... ");
+ Thread.sleep(100);
+ }
+
+ // check if all expected inferred triples exist
+ RepositoryConnection testCon = repository.getConnection();
+ try {
+ testCon.begin();
+ URI a = testCon.getValueFactory().createURI(NS + "a");
+ URI b = testCon.getValueFactory().createURI(NS + "b");
+ URI c = testCon.getValueFactory().createURI(NS + "c");
+ URI d = testCon.getValueFactory().createURI(NS + "d");
+ URI s = testCon.getValueFactory().createURI(NS + "symmetric");
+ URI t = testCon.getValueFactory().createURI(NS + "transitive");
+
+ // first reasoning round
+ Assert.assertTrue("expected inferred triple does not exist", testCon.hasStatement(b,s,a,true));
+ Assert.assertTrue("expected inferred triple does not exist", testCon.hasStatement(a,t,c,true));
+ Assert.assertTrue("expected inferred triple does not exist", testCon.hasStatement(b,t,d,true));
+
+ // second reasoning round
+ Assert.assertTrue("expected inferred triple does not exist", testCon.hasStatement(a,t,d,true));
+
+ testCon.commit();
+ } finally {
+ testCon.close();
+ }
+ }
+
+ /**
+ * Test full reasoning with a small sample program. This test will carry out the following steps in order:
+ * - import the turtle file "simple.ttl" into the repository
+ * - load the program "simple.kwrl" into the reasoning engine
+ * - wait for the reasoner to finish
+ * - check if all expected inferred triples exist
+ * - rerun reasoner
+ * - check if all expected inferred triples exist
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFullReasoning() throws Exception {
+
+ // import the turtle file "simple.ttl" into the repository
+ RepositoryConnection importCon = repository.getConnection();
+ try {
+ importCon.begin();
+ importCon.add(this.getClass().getResourceAsStream("simple.ttl"),NS, RDFFormat.TURTLE);
+ importCon.commit();
+ } finally {
+ importCon.close();
+ }
+
+ // load the program "simple.kwrl" into the reasoning engine
+ rsail.addProgram("simple", this.getClass().getResourceAsStream("simple.kwrl"));
+
+ // wait for the reasoner to finish
+ while(rsail.getEngine().isRunning()) {
+ log.debug("sleeping for 100ms to let engine finish processing ... ");
+ Thread.sleep(100);
+ }
+
+ // check if all expected inferred triples exist
+ RepositoryConnection testCon1 = repository.getConnection();
+ try {
+ testCon1.begin();
+ URI a = testCon1.getValueFactory().createURI(NS + "a");
+ URI b = testCon1.getValueFactory().createURI(NS + "b");
+ URI c = testCon1.getValueFactory().createURI(NS + "c");
+ URI d = testCon1.getValueFactory().createURI(NS + "d");
+ URI s = testCon1.getValueFactory().createURI(NS + "symmetric");
+ URI t = testCon1.getValueFactory().createURI(NS + "transitive");
+
+ // first reasoning round
+ Assert.assertTrue("expected inferred triple does not exist", testCon1.hasStatement(b,s,a,true));
+ Assert.assertTrue("expected inferred triple does not exist", testCon1.hasStatement(a,t,c,true));
+ Assert.assertTrue("expected inferred triple does not exist", testCon1.hasStatement(b,t,d,true));
+
+ // second reasoning round
+ Assert.assertTrue("expected inferred triple does not exist", testCon1.hasStatement(a,t,d,true));
+
+ testCon1.commit();
+ } finally {
+ testCon1.close();
+ }
+
+ // rerun reasoner
+ rsail.reRunPrograms();
+
+ // wait for the reasoner to finish
+ while(rsail.getEngine().isRunning()) {
+ log.debug("sleeping for 100ms to let engine finish processing ... ");
+ Thread.sleep(100);
+ }
+
+ // check if all expected inferred triples exist
+ RepositoryConnection testCon2 = repository.getConnection();
+ try {
+ testCon2.begin();
+ URI a = testCon2.getValueFactory().createURI(NS + "a");
+ URI b = testCon2.getValueFactory().createURI(NS + "b");
+ URI c = testCon2.getValueFactory().createURI(NS + "c");
+ URI d = testCon2.getValueFactory().createURI(NS + "d");
+ URI s = testCon2.getValueFactory().createURI(NS + "symmetric");
+ URI t = testCon2.getValueFactory().createURI(NS + "transitive");
+
+ // first reasoning round
+ Assert.assertTrue("expected inferred triple does not exist", testCon2.hasStatement(b,s,a,true));
+ Assert.assertTrue("expected inferred triple does not exist", testCon2.hasStatement(a,t,c,true));
+ Assert.assertTrue("expected inferred triple does not exist", testCon2.hasStatement(b,t,d,true));
+
+ // second reasoning round
+ Assert.assertTrue("expected inferred triple does not exist", testCon2.hasStatement(a,t,d,true));
+
+ testCon2.commit();
+ } finally {
+ testCon2.close();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/engine/simple.kwrl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/engine/simple.kwrl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/engine/simple.kwrl
new file mode 100644
index 0000000..76f662b
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/engine/simple.kwrl
@@ -0,0 +1,3 @@
+@prefix ex: <http://localhost/resource/>
+rule1 : ($1 ex:transitive $2), ($2 ex:transitive $3) -> ($1 ex:transitive $3)
+rule2 : ($1 ex:symmetric $2) -> ($2 ex:symmetric $1)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/engine/simple.ttl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/engine/simple.ttl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/engine/simple.ttl
new file mode 100644
index 0000000..1478ee9
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/engine/simple.ttl
@@ -0,0 +1,5 @@
+@prefix ex: <http://localhost/resource/> .
+ex:a ex:transitive ex:b .
+ex:b ex:transitive ex:c .
+ex:c ex:transitive ex:d .
+ex:a ex:symmetric ex:b .
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-001.kwrl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-001.kwrl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-001.kwrl
new file mode 100644
index 0000000..e944c88
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-001.kwrl
@@ -0,0 +1,8 @@
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+($1 rdfs:subClassOf $2), ($2 rdfs:subClassOf $3) -> ($1 rdfs:subClassOf $3)
+($1 rdfs:subPropertyOf $2), ($2 rdfs:subPropertyOf $3) -> ($1 rdfs:subPropertyOf $3)
+($1 rdf:type $2), ($2 rdfs:subClassOf $3) -> ($1 rdf:type $3)
+($p rdfs:range $r), ($1 $p $2) -> ($2 rdf:type $r)
+($p rdfs:domain $d), ($1 $p $2) -> ($1 rdf:type $d)
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-002.kwrl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-002.kwrl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-002.kwrl
new file mode 100644
index 0000000..fc96549
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-002.kwrl
@@ -0,0 +1,3 @@
+($1 http://www.w3.org/2000/01/rdf-schema#subClassOf $2), ($2 http://www.w3.org/2000/01/rdf-schema#subClassOf $3) -> ($1 http://www.w3.org/2000/01/rdf-schema#subClassOf $3)
+($1 http://www.w3.org/2000/01/rdf-schema#subPropertyOf $2), ($2 http://www.w3.org/2000/01/rdf-schema#subPropertyOf $3) -> ($1 http://www.w3.org/2000/01/rdf-schema#subPropertyOf $3)
+($1 http://www.w3.org/1999/02/22-rdf-syntax-ns#type $2), ($2 http://www.w3.org/2000/01/rdf-schema#subClassOf $3) -> ($1 http://www.w3.org/1999/02/22-rdf-syntax-ns#type $3)
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-003.kwrl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-003.kwrl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-003.kwrl
new file mode 100644
index 0000000..fd2856e
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-003.kwrl
@@ -0,0 +1,14 @@
+@prefix skos: <http://www.w3.org/2004/02/skos/core#>
+
+($1 skos:broader $2) -> ($1 skos:broaderTransitive $2)
+($1 skos:narrower $2) -> ($1 skos:narrowerTransitive $2)
+
+($1 skos:broaderTransitive $2), ($2 skos:broaderTransitive $3) -> ($1 skos:broaderTransitive $3)
+($1 skos:narrowerTransitive $2), ($2 skos:narrowerTransitive $3) -> ($1 skos:narrowerTransitive $3)
+
+($1 skos:broader $2) -> ($2 skos:narrower $1)
+($1 skos:narrower $2) -> ($2 skos:broader $1)
+
+($1 skos:broader $2) -> ($1 skos:related $2)
+($1 skos:narrower $2) -> ($1 skos:related $2)
+($1 skos:related $2) -> ($2 skos:related $1)
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-004.kwrl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-004.kwrl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-004.kwrl
new file mode 100644
index 0000000..d387fe7
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/parser/test-004.kwrl
@@ -0,0 +1,5 @@
+@prefix owl: <http://www.w3.org/2002/07/owl#>
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+inverseProp: ($p owl:inverseOf $q), ($1 $p $2) -> ($2 $q $1)
+symmetricProp: ($p rdf:type owl:SymmetricProperty), ($1 $p $2) -> ($2 $p $1)
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-001.kwrl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-001.kwrl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-001.kwrl
new file mode 100644
index 0000000..e944c88
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-001.kwrl
@@ -0,0 +1,8 @@
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+($1 rdfs:subClassOf $2), ($2 rdfs:subClassOf $3) -> ($1 rdfs:subClassOf $3)
+($1 rdfs:subPropertyOf $2), ($2 rdfs:subPropertyOf $3) -> ($1 rdfs:subPropertyOf $3)
+($1 rdf:type $2), ($2 rdfs:subClassOf $3) -> ($1 rdf:type $3)
+($p rdfs:range $r), ($1 $p $2) -> ($2 rdf:type $r)
+($p rdfs:domain $d), ($1 $p $2) -> ($1 rdf:type $d)
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-002.kwrl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-002.kwrl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-002.kwrl
new file mode 100644
index 0000000..fc96549
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-002.kwrl
@@ -0,0 +1,3 @@
+($1 http://www.w3.org/2000/01/rdf-schema#subClassOf $2), ($2 http://www.w3.org/2000/01/rdf-schema#subClassOf $3) -> ($1 http://www.w3.org/2000/01/rdf-schema#subClassOf $3)
+($1 http://www.w3.org/2000/01/rdf-schema#subPropertyOf $2), ($2 http://www.w3.org/2000/01/rdf-schema#subPropertyOf $3) -> ($1 http://www.w3.org/2000/01/rdf-schema#subPropertyOf $3)
+($1 http://www.w3.org/1999/02/22-rdf-syntax-ns#type $2), ($2 http://www.w3.org/2000/01/rdf-schema#subClassOf $3) -> ($1 http://www.w3.org/1999/02/22-rdf-syntax-ns#type $3)
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-003.kwrl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-003.kwrl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-003.kwrl
new file mode 100644
index 0000000..fd2856e
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-003.kwrl
@@ -0,0 +1,14 @@
+@prefix skos: <http://www.w3.org/2004/02/skos/core#>
+
+($1 skos:broader $2) -> ($1 skos:broaderTransitive $2)
+($1 skos:narrower $2) -> ($1 skos:narrowerTransitive $2)
+
+($1 skos:broaderTransitive $2), ($2 skos:broaderTransitive $3) -> ($1 skos:broaderTransitive $3)
+($1 skos:narrowerTransitive $2), ($2 skos:narrowerTransitive $3) -> ($1 skos:narrowerTransitive $3)
+
+($1 skos:broader $2) -> ($2 skos:narrower $1)
+($1 skos:narrower $2) -> ($2 skos:broader $1)
+
+($1 skos:broader $2) -> ($1 skos:related $2)
+($1 skos:narrower $2) -> ($1 skos:related $2)
+($1 skos:related $2) -> ($2 skos:related $1)
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-004.kwrl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-004.kwrl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-004.kwrl
new file mode 100644
index 0000000..d387fe7
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/persistence/test-004.kwrl
@@ -0,0 +1,5 @@
+@prefix owl: <http://www.w3.org/2002/07/owl#>
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+inverseProp: ($p owl:inverseOf $q), ($1 $p $2) -> ($2 $q $1)
+symmetricProp: ($p rdf:type owl:SymmetricProperty), ($1 $p $2) -> ($2 $p $1)
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/sail/simple.kwrl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/sail/simple.kwrl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/sail/simple.kwrl
new file mode 100644
index 0000000..76f662b
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/sail/simple.kwrl
@@ -0,0 +1,3 @@
+@prefix ex: <http://localhost/resource/>
+rule1 : ($1 ex:transitive $2), ($2 ex:transitive $3) -> ($1 ex:transitive $3)
+rule2 : ($1 ex:symmetric $2) -> ($2 ex:symmetric $1)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/sail/simple.ttl
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/sail/simple.ttl b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/sail/simple.ttl
new file mode 100644
index 0000000..1478ee9
--- /dev/null
+++ b/kiwi/kiwi-reasoner/src/test/resources/org/apache/marmotta/kiwi/reasoner/test/sail/simple.ttl
@@ -0,0 +1,5 @@
+@prefix ex: <http://localhost/resource/> .
+ex:a ex:transitive ex:b .
+ex:b ex:transitive ex:c .
+ex:c ex:transitive ex:d .
+ex:a ex:symmetric ex:b .
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sqlmapper/JoinTable.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sqlmapper/JoinTable.java b/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sqlmapper/JoinTable.java
new file mode 100644
index 0000000..54035d5
--- /dev/null
+++ b/kiwi/kiwi-sparql/src/main/java/org/apache/marmotta/kiwi/sparql/sqlmapper/JoinTable.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.sparql.services.evaluation.sql;
+
+import org.jooq.Condition;
+import org.jooq.Table;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Wrapper for representing information about a table to join with. Holds a reference to the table and a
+ * list of conditions to be used as join conditions.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class JoinTable {
+
+ private Table table;
+
+ private Set<Condition> conditions;
+
+ // remember conditions referring to tables not created in the current statement; they will also be contained
+ // in conditions, this set is just for checking in special cases
+ private Set<Condition> backConditions;
+
+
+ public JoinTable(Table table) {
+ this.table = table;
+
+ conditions = new HashSet<Condition>();
+ backConditions = new HashSet<Condition>();
+ }
+
+ public void setTable(Table table) {
+ this.table = table;
+ }
+
+ public Table getTable() {
+ return table;
+ }
+
+ public Set<Condition> getConditions() {
+ return conditions;
+ }
+
+ public void addCondition(Condition condition) {
+ conditions.add(condition);
+ }
+
+ public Set<Condition> getBackConditions() {
+ return backConditions;
+ }
+
+ public void addBackCondition(Condition condition) {
+ backConditions.add(condition);
+ }
+}