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);
+    }
+}