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:52:00 UTC

[36/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-versioning/src/test/java/org/apache/marmotta/kiwi/versioning/test/VersioningPersistenceTest.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/test/java/org/apache/marmotta/kiwi/versioning/test/VersioningPersistenceTest.java b/kiwi/kiwi-versioning/src/test/java/org/apache/marmotta/kiwi/versioning/test/VersioningPersistenceTest.java
new file mode 100644
index 0000000..6005697
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/test/java/org/apache/marmotta/kiwi/versioning/test/VersioningPersistenceTest.java
@@ -0,0 +1,354 @@
+/*
+ * 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.versioning.test;
+
+import org.apache.commons.lang.RandomStringUtils;
+import org.apache.marmotta.kiwi.model.rdf.KiWiStringLiteral;
+import org.apache.marmotta.kiwi.model.rdf.KiWiTriple;
+import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
+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.test.helper.DBConnectionChecker;
+import org.apache.marmotta.kiwi.versioning.model.Version;
+import org.apache.marmotta.kiwi.versioning.persistence.KiWiVersioningConnection;
+import org.apache.marmotta.kiwi.versioning.persistence.KiWiVersioningPersistence;
+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 java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import static org.hamcrest.Matchers.hasItems;
+
+/**
+ * This test checks if the database persistence for the versioning functionality works properly.
+ * 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>
+ *
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@RunWith(Parameterized.class)
+public class VersioningPersistenceTest {
+
+
+    /**
+     * 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 KiWiVersioningPersistence vpersistence;
+
+    public VersioningPersistenceTest(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 SQLException {
+        persistence = new KiWiPersistence("test",jdbcUrl,jdbcUser,jdbcPass,dialect);
+        persistence.initDatabase();
+
+        vpersistence = new KiWiVersioningPersistence(persistence);
+        vpersistence.initDatabase();
+    }
+
+    @After
+    public void dropDatabase() throws SQLException {
+        vpersistence.dropDatabase();
+
+        persistence.dropDatabase();
+        persistence.shutdown();
+    }
+
+
+    @Test
+    public void testTablesCreateDrop() throws Exception {
+        // test if database exists and has a version
+        KiWiConnection connection = vpersistence.getConnection();
+        try {
+            Assert.assertThat(connection.getDatabaseTables(), hasItems("versions", "versions_added", "versions_removed"));
+            Assert.assertEquals(1, connection.getDatabaseVersion());
+
+            connection.commit();
+        } finally {
+            connection.close();
+        }
+    }
+
+    @Test
+    public void testCreateListVersions() throws Exception {
+        KiWiVersioningConnection connection = vpersistence.getConnection();
+        try {
+            KiWiUriResource subject1  = new KiWiUriResource("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+            KiWiUriResource subject2  = new KiWiUriResource("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+            KiWiUriResource pred_1   = new KiWiUriResource("http://localhost/predicate/P1");
+            KiWiUriResource pred_2   = new KiWiUriResource("http://localhost/predicate/P2");
+            KiWiUriResource object_1 = new KiWiUriResource("http://localhost/resource/"+RandomStringUtils.randomAlphanumeric(8));
+            KiWiStringLiteral object_2 = new KiWiStringLiteral(RandomStringUtils.randomAlphanumeric(32));
+            KiWiUriResource context  = new KiWiUriResource("http://localhost/context/"+RandomStringUtils.randomAlphanumeric(8));
+
+            connection.storeNode(subject1);
+            connection.storeNode(subject2);
+            connection.storeNode(pred_1);
+            connection.storeNode(pred_2);
+            connection.storeNode(object_1);
+            connection.storeNode(object_2);
+            connection.storeNode(context);
+
+            KiWiTriple triple1 = new KiWiTriple(subject1,pred_1,object_1,context);
+            KiWiTriple triple2 = new KiWiTriple(subject2,pred_2,object_2,context);
+
+            connection.storeTriple(triple1);
+            connection.storeTriple(triple2);
+            connection.commit();
+
+            Version version1 = new Version();
+            version1.setCommitTime(new Date());
+            version1.addTriple(triple1);
+            connection.storeVersion(version1);
+            connection.commit();
+
+            // check if listVersions now gives exactly one version
+            List<Version> list1 = connection.listVersions().asList();
+            Assert.assertEquals("there should be exactly one version",1,list1.size());
+            Assert.assertEquals("contents of version differ", version1, list1.get(0));
+            Assert.assertEquals("version id is not 1", 1L, (long)list1.get(0).getId());
+
+            // check if listVersions with subject1 now gives exactly one version
+            List<Version> listr1 = connection.listVersions(subject1).asList();
+            Assert.assertEquals("there should be exactly one version", 1, listr1.size());
+            Assert.assertEquals("contents of version differ", version1, listr1.get(0));
+            Assert.assertEquals("version id is not 1", 1L, (long)listr1.get(0).getId());
+
+
+            Version version2 = new Version();
+            version2.setCommitTime(new Date());
+            version2.addTriple(triple2);
+            version2.removeTriple(triple1);
+            connection.storeVersion(version2);
+            connection.commit();
+
+            // check if listVersions now gives exactly two versions
+            List<Version> list2 = connection.listVersions().asList();
+            Assert.assertEquals("there should be exactly two version",2,list2.size());
+            Assert.assertEquals("contents of version differ", version2, list2.get(1));
+
+
+            // check if listVersions with subject1 still gives exactly one version
+            List<Version> listr2 = connection.listVersions(subject1).asList();
+            Assert.assertEquals("there should be exactly one version", 2, listr2.size());
+            Assert.assertEquals("contents of version differ", version1, listr2.get(0));
+            Assert.assertEquals("version id is not 1", 1L, (long)listr2.get(0).getId());
+
+            connection.commit();
+        } finally {
+            connection.close();
+        }
+
+    }
+
+    /**
+     * Test listing versions between two dates
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testCreateListVersionsBetween() throws Exception {
+        KiWiVersioningConnection connection = vpersistence.getConnection();
+        try {
+            KiWiUriResource subject  = new KiWiUriResource("http://localhost/resource/"+ RandomStringUtils.randomAlphanumeric(8));
+            KiWiUriResource pred_1   = new KiWiUriResource("http://localhost/predicate/P1");
+            KiWiUriResource pred_2   = new KiWiUriResource("http://localhost/predicate/P2");
+            KiWiUriResource object_1 = new KiWiUriResource("http://localhost/resource/"+RandomStringUtils.randomAlphanumeric(8));
+            KiWiStringLiteral object_2 = new KiWiStringLiteral(RandomStringUtils.randomAlphanumeric(32));
+            KiWiUriResource context  = new KiWiUriResource("http://localhost/context/"+RandomStringUtils.randomAlphanumeric(8));
+
+            connection.storeNode(subject);
+            connection.storeNode(pred_1);
+            connection.storeNode(pred_2);
+            connection.storeNode(object_1);
+            connection.storeNode(object_2);
+            connection.storeNode(context);
+
+            KiWiTriple triple1 = new KiWiTriple(subject,pred_1,object_1,context);
+            KiWiTriple triple2 = new KiWiTriple(subject,pred_2,object_2,context);
+
+            connection.storeTriple(triple1);
+            connection.storeTriple(triple2);
+            connection.commit();
+
+            Date date1 = new Date();
+
+            // wait for one second to be sure to capture MySQL cutting milliseconds
+            mysqlSleep();
+
+
+            Version version1 = new Version();
+            version1.setCommitTime(new Date());
+            version1.addTriple(triple1);
+            connection.storeVersion(version1);
+            connection.commit();
+
+            // wait for one second to be sure to capture MySQL cutting milliseconds
+            mysqlSleep();
+
+            Date date2 = new Date();
+
+            // wait for one second to be sure to capture MySQL cutting milliseconds
+            mysqlSleep();
+
+
+            Version version2 = new Version();
+            version2.setCommitTime(new Date());
+            version2.addTriple(triple2);
+            version2.removeTriple(triple1);
+            connection.storeVersion(version2);
+            connection.commit();
+
+            // wait for one second to be sure to capture MySQL cutting milliseconds
+            mysqlSleep();
+
+            Date date3 = new Date();
+
+
+            // now we test different ways of listing versions between dates
+            List<Version> list1 = connection.listVersions(date1,date2).asList();
+            Assert.assertEquals("there should be exactly one version from "+date1+" to "+date2,1,list1.size());
+            Assert.assertEquals("contents of version differ", version1, list1.get(0));
+            Assert.assertEquals("version id is not 1", 1L, (long)list1.get(0).getId());
+
+            // check if getLatestVersion at date2 works
+            Version latest2 = connection.getLatestVersion(subject,date2);
+            Assert.assertNotNull("latest version for subject was not found",latest2);
+            Assert.assertEquals("latest version is not the expected version", version1,latest2);
+
+            // check if listVersions with subject1 now gives exactly one version
+            List<Version> listr1 = connection.listVersions(subject,date1,date2).asList();
+            Assert.assertEquals("there should be exactly one version", 1, listr1.size());
+            Assert.assertEquals("contents of version differ", version1, listr1.get(0));
+            Assert.assertEquals("version id is not 1", 1L, (long)listr1.get(0).getId());
+
+
+            List<Version> list2 = connection.listVersions(date2,date3).asList();
+            Assert.assertEquals("there should be exactly one version from "+date2+" to "+date3,1,list2.size());
+            Assert.assertEquals("contents of version differ", version2, list2.get(0));
+            Assert.assertEquals("version id is not 2", 2L, (long)list2.get(0).getId());
+
+            List<Version> list3 = connection.listVersions(date3,new Date()).asList();
+            Assert.assertEquals("there should be no version from "+date3+" to now",0,list3.size());
+
+            List<Version> list4 = connection.listVersions(date1,date3).asList();
+            Assert.assertEquals("there should be exactly two versions from "+date1+" to "+date3,2,list4.size());
+            Assert.assertEquals("contents of version1 differ", version1, list4.get(0));
+            Assert.assertEquals("contents of version2 differ", version2, list4.get(1));
+
+
+            connection.commit();
+        } finally {
+            connection.close();
+        }
+
+
+    }
+
+    /**
+     * MYSQL rounds timestamps to the second, so it is sometimes necessary to sleep before doing a test
+     */
+    private  void mysqlSleep() {
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/src/test/java/org/apache/marmotta/kiwi/versioning/test/VersioningRepositoryTest.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/test/java/org/apache/marmotta/kiwi/versioning/test/VersioningRepositoryTest.java b/kiwi/kiwi-versioning/src/test/java/org/apache/marmotta/kiwi/versioning/test/VersioningRepositoryTest.java
new file mode 100644
index 0000000..a6531d4
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/test/java/org/apache/marmotta/kiwi/versioning/test/VersioningRepositoryTest.java
@@ -0,0 +1,261 @@
+/*
+ * 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.versioning.test;
+
+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.sail.KiWiStore;
+import org.apache.marmotta.kiwi.test.helper.DBConnectionChecker;
+import org.apache.marmotta.kiwi.transactions.sail.KiWiTransactionalSail;
+import org.apache.marmotta.kiwi.versioning.model.Version;
+import org.apache.marmotta.kiwi.versioning.sail.KiWiVersioningSail;
+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.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.RepositoryResult;
+import org.openrdf.repository.sail.SailRepository;
+import org.openrdf.rio.RDFFormat;
+
+import java.io.InputStream;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assume.assumeThat;
+
+/**
+ * This test checks if the versioning functionality itself works, i.e. the system properly creates versions on
+ * transaction commits. 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>
+ *
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@RunWith(Parameterized.class)
+public class VersioningRepositoryTest {
+
+    /**
+     * 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 KiWiVersioningSail    vsail;
+
+    private Repository repository;
+
+    public VersioningRepositoryTest(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 RepositoryException {
+        store = new KiWiStore("test",jdbcUrl,jdbcUser,jdbcPass,dialect, "http://localhost/context/default", "http://localhost/context/inferred");
+        tsail = new KiWiTransactionalSail(store);
+        vsail = new KiWiVersioningSail(tsail);
+        repository = new SailRepository(vsail);
+        repository.initialize();
+    }
+
+    @After
+    public void dropDatabase() throws RepositoryException, SQLException {
+        vsail.getPersistence().dropDatabase();
+        store.getPersistence().dropDatabase();
+        repository.shutDown();
+    }
+
+    /**
+     * This test imports three small RDF files in sequence and checks afterwards that the number of versions
+     * is correct and they contain the correct information
+     * @throws Exception
+     */
+    @Test
+    public void testCreateVersions() throws Exception {
+        // import three files in sequence and check if the versions are created properly
+
+        Date date1 = new Date();
+
+        mysqlSleep();
+
+        // base data
+        InputStream baseData = this.getClass().getResourceAsStream("version-base.rdf");
+        assumeThat("Could not load test-data: version-base.rdf", baseData, notNullValue(InputStream.class));
+
+        RepositoryConnection connectionBase = repository.getConnection();
+        try {
+            connectionBase.add(baseData, "http://marmotta.incubator.apache.org/testing/ns1/", RDFFormat.RDFXML);
+            connectionBase.commit();
+        } finally {
+            connectionBase.close();
+        }
+
+        mysqlSleep();
+
+        Date date2 = new Date();
+
+        mysqlSleep();
+
+        // update 1
+        InputStream update1Data = this.getClass().getResourceAsStream("version-update1.rdf");
+        assumeThat("Could not load test-data: version-update1.rdf", update1Data, notNullValue(InputStream.class));
+
+        RepositoryConnection connectionUpdate1 = repository.getConnection();
+        try {
+            connectionUpdate1.add(update1Data, "http://marmotta.incubator.apache.org/testing/ns1/", RDFFormat.RDFXML);
+            connectionUpdate1.commit();
+        } finally {
+            connectionUpdate1.close();
+        }
+
+        // update 2
+        InputStream update2Data = this.getClass().getResourceAsStream("version-update2.rdf");
+        assumeThat("Could not load test-data: version-update2.rdf", update2Data, notNullValue(InputStream.class));
+
+        RepositoryConnection connectionUpdate2 = repository.getConnection();
+        try {
+            connectionUpdate2.add(update2Data, "http://marmotta.incubator.apache.org/testing/ns1/", RDFFormat.RDFXML);
+            connectionUpdate2.commit();
+        } finally {
+            connectionUpdate2.close();
+        }
+
+        // list all versions
+        List<Version> versions = asList(vsail.listVersions());
+        Assert.assertEquals("expected 3 versions!", 3, versions.size());
+        Assert.assertEquals(1, (long)versions.get(0).getId());
+        Assert.assertEquals(2, (long)versions.get(1).getId());
+        Assert.assertEquals(3, (long)versions.get(2).getId());
+        Assert.assertEquals(3, (long)versions.get(0).getAddedTriples().size());
+        Assert.assertEquals(3, (long)versions.get(1).getAddedTriples().size());
+        Assert.assertEquals(1, (long)versions.get(2).getAddedTriples().size());
+
+        List<Version> versions1 = asList(vsail.listVersions(date1,date2));
+        Assert.assertEquals("expected 1 version!", 1, versions1.size());
+        Assert.assertEquals(1, (long)versions1.get(0).getId());
+        Assert.assertEquals(3, (long)versions1.get(0).getAddedTriples().size());
+    }
+
+
+    /**
+     * MYSQL rounds timestamps to the second, so it is sometimes necessary to sleep before doing a test
+     */
+    private  void mysqlSleep() {
+        if(this.dialect instanceof MySQLDialect) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+
+    /**
+     * Workaround for https://openrdf.atlassian.net/browse/SES-1702 in Sesame 2.7.0-beta1
+     * @param <E>
+     * @return
+     */
+    public static <E> List<E> asList(RepositoryResult<E> result) throws RepositoryException {
+        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-versioning/src/test/resources/logback.xml
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/test/resources/logback.xml b/kiwi/kiwi-versioning/src/test/resources/logback.xml
new file mode 100644
index 0000000..08c9e0a
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/test/resources/logback.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ 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.
+  -->
+
+<configuration>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <!-- encoders are assigned the type
+     ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+        <encoder>
+<!--            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>  -->
+            <pattern>%d{HH:mm:ss.SSS} %-5level - %msg%n</pattern>
+<!--            <pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern> -->
+        </encoder>
+    </appender>
+
+    <logger name="com.mchange" level="INFO" />
+
+
+    <root level="debug">
+        <appender-ref ref="STDOUT" />
+    </root>
+</configuration>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-base.rdf
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-base.rdf b/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-base.rdf
new file mode 100644
index 0000000..f15e108
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-base.rdf
@@ -0,0 +1,25 @@
+<!--
+  ~ 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.
+  -->
+
+<rdf:RDF
+        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+        xmlns:ns1="http://marmotta.incubator.apache.org/testing/ns1/">
+    <ns1:C rdf:about="http://marmotta.incubator.apache.org/testing/ns1/R1">
+        <ns1:P1>property 1 value 1</ns1:P1>
+        <ns1:P2>property 2 value 1</ns1:P2>
+    </ns1:C>
+
+</rdf:RDF>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-update1.rdf
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-update1.rdf b/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-update1.rdf
new file mode 100644
index 0000000..1f94210
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-update1.rdf
@@ -0,0 +1,25 @@
+<!--
+  ~ 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.
+  -->
+
+<rdf:RDF
+        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+        xmlns:ns1="http://marmotta.incubator.apache.org/testing/ns1/">
+    <ns1:C rdf:about="http://marmotta.incubator.apache.org/testing/ns1/R2">
+        <ns1:P1>property 1 value 2</ns1:P1>
+        <ns1:P3>property 3 value 2</ns1:P3>
+    </ns1:C>
+
+</rdf:RDF>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-update2.rdf
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-update2.rdf b/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-update2.rdf
new file mode 100644
index 0000000..ab083fb
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/test/resources/org/apache/marmotta/kiwi/versioning/test/version-update2.rdf
@@ -0,0 +1,24 @@
+<!--
+  ~ 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.
+  -->
+
+<rdf:RDF
+        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+        xmlns:ns1="http://marmotta.incubator.apache.org/testing/ns1/">
+    <ns1:C rdf:about="http://marmotta.incubator.apache.org/testing/ns1/R1">
+        <ns1:P3>property 3 value 1</ns1:P3>
+    </ns1:C>
+
+</rdf:RDF>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/pom.xml
----------------------------------------------------------------------
diff --git a/kiwi/pom.xml b/kiwi/pom.xml
new file mode 100644
index 0000000..2c2baca
--- /dev/null
+++ b/kiwi/pom.xml
@@ -0,0 +1,179 @@
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>at.newmedialab.lmf</groupId>
+        <artifactId>lmf-parent</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <artifactId>kiwi-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <name>KiWi Triplestore: Parent</name>
+    <description>A Sesame Triple Store based on a relational database. Supports reasoning and versioning.</description>
+    <url>https://code.google.com/p/ldpath/</url>
+
+    <inceptionYear>2008</inceptionYear>
+    <licenses>
+        <license>
+            <name>Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+            <comments>A business-friendly OSS license</comments>
+        </license>
+    </licenses>
+
+    <developers>
+        <developer>
+            <name>Sebastian Schaffert</name>
+            <email>sebastian.schaffert@salzburgresearch.at</email>
+            <organization>Salzburg Research</organization>
+        </developer>
+    </developers>
+
+    <organization>
+        <name>Salzburg Research</name>
+        <url>http://www.salzburgresearch.at</url>
+    </organization>
+
+    <properties>
+        <sesameVersion>2.6.10</sesameVersion>
+        <sl4jVersion>1.7.2</sl4jVersion>
+        <logbackVersion>1.0.7</logbackVersion>
+    </properties>
+
+
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>2.13</version>
+                    <configuration>
+                        <systemPropertyVariables>
+                            <h2.url>jdbc:h2:mem:test;MVCC=true;DB_CLOSE_ON_EXIT=TRUE</h2.url>
+                            <h2.user>sa</h2.user>
+                            <h2.pass />
+
+                            <!-- enable or pass on command line for testing local PostgreSQL -->
+                            <postgresql.url>jdbc:postgresql://localhost:5433/kiwitest?prepareThreshold=3</postgresql.url>
+                            <postgresql.user>lmf</postgresql.user>
+                            <postgresql.pass>lmf</postgresql.pass>
+
+                            <!-- enable or pass on command line for testing local MySQL -->
+                            <mysql.url>jdbc:mysql://localhost:3306/kiwitest</mysql.url>
+                            <mysql.user>lmf</mysql.user>
+                            <mysql.pass>lmf</mysql.pass>
+                        </systemPropertyVariables>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>surefire-booter</artifactId>
+                    <version>2.13</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-gpg-plugin</artifactId>
+                    <version>1.4</version>
+                    <!-- uncomment for release deployment -->
+                                        <executions>
+                                            <execution>
+                                                <id>sign-artifacts</id>
+                                                <phase>verify</phase>
+                                                <goals>
+                                                    <goal>sign</goal>
+                                                </goals>
+                                            </execution>
+                                        </executions>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>maven-bundle-plugin</artifactId>
+                    <version>2.3.7</version>
+                    <inherited>true</inherited>
+                    <configuration>
+                        <instructions>
+                            <Bundle-DocURL>http://code.google.com/p/ldpath/</Bundle-DocURL>
+                            <Bundle-Vendor>Salzburg Research</Bundle-Vendor>
+                            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                            <_versionpolicy>$${version;===;${@}}</_versionpolicy>
+                        </instructions>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>maven-scr-plugin</artifactId>
+                    <version>1.7.4</version>
+                    <executions>
+                        <execution>
+                            <id>generate-scr-scrdescriptor</id>
+                            <goals>
+                                <goal>scr</goal>
+                            </goals>
+                            <configuration>
+                                <properties>
+                                    <service.vendor>Salzburg Research</service.vendor>
+                                </properties>
+                            </configuration>
+                        </execution>
+                    </executions>
+                </plugin>
+                <plugin> <!-- generate JRebel Configuration -->
+                    <groupId>org.zeroturnaround</groupId>
+                    <artifactId>jrebel-maven-plugin</artifactId>
+                    <configuration>
+                        <relativePath>../../</relativePath>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>at.newmedialab.lmf</groupId>
+                <artifactId>kiwi-triplestore</artifactId>
+                <version>${project.version}</version>
+                <type>test-jar</type>
+                <scope>test</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <modules>
+        <module>kiwi-contextaware</module>
+        <module>kiwi-triplestore</module>
+        <module>kiwi-transactions</module>
+        <module>kiwi-tripletable</module>
+        <module>kiwi-versioning</module>
+        <module>kiwi-reasoner</module>
+    </modules>
+
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/.project
----------------------------------------------------------------------
diff --git a/ldcache/.project b/ldcache/.project
new file mode 100644
index 0000000..6de81ee
--- /dev/null
+++ b/ldcache/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>ldcache-parent</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+	</natures>
+</projectDescription>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/.settings/org.eclipse.m2e.core.prefs
----------------------------------------------------------------------
diff --git a/ldcache/.settings/org.eclipse.m2e.core.prefs b/ldcache/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/ldcache/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/README.txt
----------------------------------------------------------------------
diff --git a/ldcache/README.txt b/ldcache/README.txt
new file mode 100644
index 0000000..a593d58
--- /dev/null
+++ b/ldcache/README.txt
@@ -0,0 +1,10 @@
+This components implements Linked Data Caching support in conjunction with the Linked Data Client Library.
+It provides the following modules:
+- ldcache-api: interfaces and data model for Linked Data Caching
+- ldcache-core: core library implementation, manages the caching functionality
+- ldcache-sail: Sesame StackedSail that can be used for transparently retrieving Linked Data Resources when
+  requested through the Sesame API
+- ldcache-backend-kiwi: caching backend based on the KiWi triplestore; allows persisting caching information
+  in the JDBC database used by KiWi
+
+Other backends can be implemented as needed.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/.classpath
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/.classpath b/ldcache/ldcache-api/.classpath
new file mode 100644
index 0000000..90df7da
--- /dev/null
+++ b/ldcache/ldcache-api/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/.project
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/.project b/ldcache/ldcache-api/.project
new file mode 100644
index 0000000..d5d1332
--- /dev/null
+++ b/ldcache/ldcache-api/.project
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>ldcache-api</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.zeroturnaround.eclipse.rebelXmlBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>org.zeroturnaround.eclipse.jrebelNature</nature>
+	</natures>
+</projectDescription>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/.settings/org.eclipse.jdt.core.prefs
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/.settings/org.eclipse.jdt.core.prefs b/ldcache/ldcache-api/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..60105c1
--- /dev/null
+++ b/ldcache/ldcache-api/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/.settings/org.eclipse.m2e.core.prefs
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/.settings/org.eclipse.m2e.core.prefs b/ldcache/ldcache-api/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/ldcache/ldcache-api/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/pom.xml
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/pom.xml b/ldcache/ldcache-api/pom.xml
new file mode 100644
index 0000000..4bf13f8
--- /dev/null
+++ b/ldcache/ldcache-api/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>at.newmedialab.lmf</groupId>
+        <artifactId>ldcache-parent</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <artifactId>ldcache-api</artifactId>
+    <name>LDCache: API</name>
+
+    <description>
+        Interfaces and Data Model for the Linked Data Caching component.
+    </description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>ldclient-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-model</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-repository-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-query</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingBackend.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingBackend.java b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingBackend.java
new file mode 100644
index 0000000..e6fdc90
--- /dev/null
+++ b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingBackend.java
@@ -0,0 +1,69 @@
+/**
+ * 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 org.apache.marmotta.ldcache.api;
+
+import info.aduna.iteration.CloseableIteration;
+import org.apache.marmotta.ldcache.model.CacheEntry;
+import org.openrdf.repository.RepositoryException;
+
+/**
+ * This interface defines the API for different backends for storing the caching results.
+ * <p/>
+ * Author: Sebastian Schaffert (sschaffert@apache.org)
+ */
+public interface LDCachingBackend {
+
+    /**
+     * Return a repository connection that can be used for caching. The LDCache will first remove all statements for
+     * the newly cached resources and then add retrieved statements as-is to this connection and properly commit and
+     * close it after use.
+     * <p/>
+     * Note that in case the statements should be rewritten this method must take care of providing the proper
+     * connection, e.g. by using a ContextAwareRepositoryConnection to add a context to all statements when adding them.
+     *
+     *
+     * @param  resource the resource that will be cached
+     * @return a repository connection that can be used for storing retrieved triples for caching
+     */
+    public LDCachingConnection getCacheConnection(String resource) throws RepositoryException;
+
+
+    /**
+     * Return an iterator over all expired cache entries (can e.g. be used for refreshing).
+     *
+     * @return
+     */
+    public CloseableIteration<CacheEntry,RepositoryException> listExpiredEntries() throws RepositoryException;
+
+
+    /**
+     * Return an iterator over all cache entries (can e.g. be used for refreshing or expiring).
+     *
+     * @return
+     */
+    public CloseableIteration<CacheEntry,RepositoryException> listCacheEntries() throws RepositoryException;
+
+
+    /**
+     * Carry out any initialization tasks that might be necessary
+     */
+    public void initialize();
+
+    /**
+     * Shutdown the backend and free all runtime resources.
+     */
+    public void shutdown();
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingConnection.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingConnection.java b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingConnection.java
new file mode 100644
index 0000000..6a284d0
--- /dev/null
+++ b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingConnection.java
@@ -0,0 +1,57 @@
+/**
+ * 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 org.apache.marmotta.ldcache.api;
+
+import org.apache.marmotta.ldcache.model.CacheEntry;
+import org.openrdf.model.URI;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert (sschaffert@apache.org)
+ */
+public interface LDCachingConnection extends RepositoryConnection {
+
+
+    /**
+     * Get the cache entry for the passed resource, if any. Returns null in case there is no cache entry.
+     *
+     *
+     * @param resource the resource to look for
+     * @return the cache entry for the resource, or null if the resource has never been cached or is expired
+     */
+    public CacheEntry getCacheEntry(URI resource) throws RepositoryException;
+
+    /**
+     * Store a cache entry for the passed resource in the backend. Depending on the backend, this can be a
+     * persistent storage or an in-memory storage.
+     *
+     * @param resource
+     * @param entry
+     */
+    public void addCacheEntry(URI resource, CacheEntry entry) throws RepositoryException;
+
+
+    /**
+     * Remove the currently stored cache entry for the passed resource from the backend.
+     * @param resource
+     */
+    public void removeCacheEntry(URI resource) throws RepositoryException;
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingService.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingService.java b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingService.java
new file mode 100644
index 0000000..54a3f6a
--- /dev/null
+++ b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/api/LDCachingService.java
@@ -0,0 +1,101 @@
+/**
+ * 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 org.apache.marmotta.ldcache.api;
+
+import info.aduna.iteration.CloseableIteration;
+import org.apache.marmotta.ldcache.model.CacheEntry;
+import org.openrdf.model.URI;
+import org.openrdf.repository.RepositoryException;
+
+/**
+ * Add file description here!
+ * <p/>
+ * User: sschaffe
+ */
+public interface LDCachingService {
+
+
+    /**
+     * Refresh the cached resource passed as argument. The method will do nothing for local
+     * resources.
+     * Calling the method will carry out the following tasks:
+     * 1. check whether the resource is a remote resource; if no, returns immediately
+     * 2. check whether the resource has a cache entry; if no, goto 4
+     * 3. check whether the expiry time of the cache entry has passed; if no, returns immediately
+     * 4. retrieve the triples for the resource from the Linked Data Cloud using the methods offered
+     * by the
+     * LinkedDataClientService (registered endpoints etc); returns immediately if the result is null
+     * or
+     * an exception is thrown
+     * 5. remove all old triples for the resource and add all new triples for the resource
+     * 6. create new expiry information of the cache entry and persist it in the transaction
+     * 
+     *
+     * @param resource
+     * @param forceRefresh if <code>true</code> the resource will be refreshed despite the
+     */
+    public void refreshResource(URI resource, boolean forceRefresh);
+
+    /**
+     * Refresh all expired resources by listing the cache entries that have expired and calling refreshResource on
+     * them. This method can e.g. be called by a scheduled task to regularly update cache entries to always have
+     * the latest version available in the Search Index and elsewhere.
+     */
+    public void refreshExpired();
+
+    /**
+     * Manually expire the caching information for the given resource. The resource will be
+     * re-retrieved upon the next access.
+     *
+     * @param resource the Resource to expire.
+     */
+    public void expire(URI resource);
+
+    /**
+     * Manually expire all cached resources.
+     * 
+     * @see #expire(org.openrdf.model.URI)
+     */
+    public void expireAll();
+
+
+    /**
+     * Shutdown the caching service and free all occupied runtime resources.
+     */
+    public void shutdown();
+
+    /**
+     * Return a repository connection that can be used for accessing cached resources.
+     *
+     * @param  resource the resource that will be cached
+     * @return a repository connection that can be used for storing retrieved triples for caching
+     */
+    LDCachingConnection getCacheConnection(String resource) throws RepositoryException;
+
+    /**
+     * Return an iterator over all cache entries (can e.g. be used for refreshing or expiring).
+     *
+     * @return
+     */
+    CloseableIteration<CacheEntry, RepositoryException> listCacheEntries() throws RepositoryException;
+
+    /**
+     * Return an iterator over all expired cache entries (can e.g. be used for refreshing).
+     *
+     * @return
+     */
+    CloseableIteration<CacheEntry, RepositoryException> listExpiredEntries() throws RepositoryException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/model/CacheConfiguration.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/model/CacheConfiguration.java b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/model/CacheConfiguration.java
new file mode 100644
index 0000000..4302735
--- /dev/null
+++ b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/model/CacheConfiguration.java
@@ -0,0 +1,56 @@
+/**
+ * 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 org.apache.marmotta.ldcache.model;
+
+import org.apache.marmotta.ldclient.model.ClientConfiguration;
+
+/**
+ * Configuration options for LDCache instances. Can be subclassed by backends as needed.
+ * <p/>
+ * Author: Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class CacheConfiguration {
+
+    /** the LDClient configuration to use for configuring the Linked Data Client */
+    private ClientConfiguration clientConfiguration;
+
+
+    private long defaultExpiry = 86400L;
+
+    public CacheConfiguration() {
+        this(new ClientConfiguration());
+    }
+
+    public CacheConfiguration(ClientConfiguration clientConfiguration) {
+        this.clientConfiguration = clientConfiguration;
+    }
+
+    public ClientConfiguration getClientConfiguration() {
+        return clientConfiguration;
+    }
+
+    public void setClientConfiguration(ClientConfiguration clientConfiguration) {
+        this.clientConfiguration = clientConfiguration;
+    }
+
+    public long getDefaultExpiry() {
+        return defaultExpiry;
+    }
+
+    public void setDefaultExpiry(long defaultExpiry) {
+        this.defaultExpiry = defaultExpiry;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/model/CacheEntry.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/model/CacheEntry.java b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/model/CacheEntry.java
new file mode 100644
index 0000000..72a1775
--- /dev/null
+++ b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/model/CacheEntry.java
@@ -0,0 +1,90 @@
+/**
+ * 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 org.apache.marmotta.ldcache.model;
+
+import org.openrdf.model.URI;
+
+import java.util.Date;
+
+/**
+ * The cache entry for a URI resource managed by the Linked Data Cache. Contains maintenance information about
+ * the resource, i.e. when it has been retrieved last, when to retrieve it next, etc.
+ * <p/>
+ * User: Sebastian Schaffert
+ */
+public class CacheEntry {
+
+    /**
+     * The URI resource managed by this cache entry.
+     */
+    private URI resource;
+
+    /**
+     * The date when this resource has been retrieved the last time.
+     */
+    private Date lastRetrieved;
+
+
+    /**
+     * The date when this resource needs to be retrieved again according to expiry configuration.
+     */
+    private Date expiryDate;
+
+
+    /**
+     * The number of times this resource has already been updated.
+     */
+    private Integer updateCount;
+
+
+
+    public CacheEntry() {
+    }
+
+
+    public URI getResource() {
+        return resource;
+    }
+
+    public void setResource(URI resource) {
+        this.resource = resource;
+    }
+
+    public Date getLastRetrieved() {
+        return lastRetrieved;
+    }
+
+    public void setLastRetrieved(Date lastRetrieved) {
+        this.lastRetrieved = new Date(lastRetrieved.getTime());
+    }
+
+    public Date getExpiryDate() {
+        return expiryDate;
+    }
+
+    public void setExpiryDate(Date expiryDate) {
+        this.expiryDate = new Date(expiryDate.getTime());
+    }
+
+    public Integer getUpdateCount() {
+        return updateCount;
+    }
+
+    public void setUpdateCount(Integer updateCount) {
+        this.updateCount = updateCount;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/sail/LDCachingSail.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/sail/LDCachingSail.java b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/sail/LDCachingSail.java
new file mode 100644
index 0000000..43a1015
--- /dev/null
+++ b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/sail/LDCachingSail.java
@@ -0,0 +1,32 @@
+/**
+ * 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 org.apache.marmotta.ldcache.sail;
+
+import org.openrdf.sail.Sail;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert (sschaffert@apache.org)
+ */
+public interface LDCachingSail extends Sail {
+
+    /**
+     * Return a caching connection.
+     * @return
+     */
+    public LDCachingSailConnection getConnection();
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/sail/LDCachingSailConnection.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/sail/LDCachingSailConnection.java b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/sail/LDCachingSailConnection.java
new file mode 100644
index 0000000..d91d24d
--- /dev/null
+++ b/ldcache/ldcache-api/src/main/java/org/apache/marmotta/ldcache/sail/LDCachingSailConnection.java
@@ -0,0 +1,55 @@
+/**
+ * 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 org.apache.marmotta.ldcache.sail;
+
+import org.apache.marmotta.ldcache.model.CacheEntry;
+import org.openrdf.model.URI;
+import org.openrdf.sail.SailConnection;
+import org.openrdf.sail.SailException;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert (sschaffert@apache.org)
+ */
+public interface LDCachingSailConnection extends SailConnection {
+
+    /**
+     * Get the cache entry for the passed resource, if any. Returns null in case there is no cache entry.
+     *
+     *
+     * @param resource the resource to look for
+     * @return the cache entry for the resource, or null if the resource has never been cached or is expired
+     */
+    public CacheEntry getCacheEntry(URI resource) throws SailException;
+
+    /**
+     * Store a cache entry for the passed resource in the backend. Depending on the backend, this can be a
+     * persistent storage or an in-memory storage.
+     *
+     * @param resource
+     * @param entry
+     */
+    public void addCacheEntry(URI resource, CacheEntry entry) throws SailException;
+
+
+    /**
+     * Remove the currently stored cache entry for the passed resource from the backend.
+     * @param resource
+     */
+    public void removeCacheEntry(URI resource) throws SailException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-backend-ehcache/pom.xml
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-backend-ehcache/pom.xml b/ldcache/ldcache-backend-ehcache/pom.xml
new file mode 100644
index 0000000..b1b6453
--- /dev/null
+++ b/ldcache/ldcache-backend-ehcache/pom.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>at.newmedialab.lmf</groupId>
+        <artifactId>ldcache-parent</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>ldcache-backend-ehcache</artifactId>
+    <name>LDCache Backend: EHCache</name>
+
+    <description>
+        This module offers a backend that allows storing cache entries in an EHCache instance. The backend class is
+        abstract and needs to be subclassed to provide the repository connection for the triples.
+    </description>
+
+
+    <dependencies>
+
+
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>ldcache-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>kiwi-tripletable</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.sf.ehcache</groupId>
+            <artifactId>ehcache-core</artifactId>
+        </dependency>
+    </dependencies>
+    
+</project>
\ No newline at end of file