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

[33/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/ldcache/ldcache-sail-kiwi/pom.xml
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/pom.xml b/ldcache/ldcache-sail-kiwi/pom.xml
new file mode 100644
index 0000000..8d728fd
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/pom.xml
@@ -0,0 +1,198 @@
+<?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-sail-kiwi</artifactId>
+    <name>LDCache: Sesame SAIL (KiWi)</name>
+
+    <description>
+        Stacked Sail that allows transparent access to resources through the Linked Data Cache, retrieving them
+        on demand when needed. Can be wrapped around other Sesame SAILs.
+    </description>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <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>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>ldcache-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>ldcache-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>ldcache-backend-kiwi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>kiwi-triplestore</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>at.newmedialab.sesame</groupId>
+            <artifactId>sesame-commons</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>at.newmedialab.sesame</groupId>
+            <artifactId>sesame-filter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+        </dependency>
+
+        <!-- LDClient -->
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>ldclient-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>ldclient-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>ldclient-provider-rdf</artifactId>
+        </dependency>
+
+
+        <!-- logging -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-ext</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>log4j-over-slf4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jul-to-slf4j</artifactId>
+        </dependency>
+
+
+        <!-- Testing -->
+        <dependency>
+            <artifactId>junit</artifactId>
+            <groupId>junit</groupId>
+            <scope>test</scope>
+        </dependency>
+        <dependency> <!-- see http://www.dbunit.org/howto.html -->
+            <artifactId>dbunit</artifactId>
+            <groupId>org.dbunit</groupId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <artifactId>hamcrest-core</artifactId>
+            <groupId>org.hamcrest</groupId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <artifactId>hamcrest-library</artifactId>
+            <groupId>org.hamcrest</groupId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-rio-turtle</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail-kiwi/src/main/java/org/apache/marmotta/ldcache/sail/KiWiLinkedDataSail.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/src/main/java/org/apache/marmotta/ldcache/sail/KiWiLinkedDataSail.java b/ldcache/ldcache-sail-kiwi/src/main/java/org/apache/marmotta/ldcache/sail/KiWiLinkedDataSail.java
new file mode 100644
index 0000000..5d29659
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/src/main/java/org/apache/marmotta/ldcache/sail/KiWiLinkedDataSail.java
@@ -0,0 +1,134 @@
+/**
+ * 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.kiwi.sail.KiWiStore;
+import org.apache.marmotta.ldcache.backend.kiwi.LDCachingKiWiBackend;
+import org.apache.marmotta.ldcache.model.CacheConfiguration;
+import org.apache.marmotta.ldcache.services.LDCache;
+import org.apache.marmotta.ldclient.model.ClientConfiguration;
+import org.apache.marmotta.sesame.filter.SesameFilter;
+import org.openrdf.model.Resource;
+import org.openrdf.sail.NotifyingSail;
+import org.openrdf.sail.NotifyingSailConnection;
+import org.openrdf.sail.SailException;
+import org.openrdf.sail.StackableSail;
+import org.openrdf.sail.helpers.NotifyingSailWrapper;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class KiWiLinkedDataSail extends NotifyingSailWrapper {
+
+    private KiWiStore store;
+
+    private LDCachingKiWiBackend backend;
+
+    private LDCache ldcache;
+
+    private SesameFilter<Resource> acceptor;
+
+    private String cache_context;
+
+    private CacheConfiguration config;
+
+    /**
+     * Creates a new SAIL with transparent Linked Data access. Caching information is stored in the underlying
+     * KiWi triple store.
+     *
+     * @param baseSail the wrapped SAIL; at the parent level must be a KiWiStore
+     * @param acceptor a filter that selects which resources are considered as external Linked Data resources,
+     *                 e.g. all resources not matching http://localhost and file:
+     * @param cacheContextUri the URI of the context to use for storing cached triples
+     */
+    public KiWiLinkedDataSail(NotifyingSail baseSail, SesameFilter<Resource> acceptor, String cacheContextUri) {
+        this(baseSail, acceptor, cacheContextUri,null);
+    }
+
+    /**
+     * Creates a new SAIL with transparent Linked Data access. Caching information is stored in the underlying
+     * KiWi triple store.
+     *
+     * @param baseSail the wrapped SAIL; at the parent level must be a KiWiStore
+     * @param acceptor a filter that selects which resources are considered as external Linked Data resources,
+     *                 e.g. all resources not matching http://localhost and file:
+     * @param cacheContextUri the URI of the context to use for storing cached triples
+     */
+    public KiWiLinkedDataSail(NotifyingSail baseSail, SesameFilter<Resource> acceptor, String cacheContextUri, ClientConfiguration clientConfiguration) {
+        super(baseSail);
+
+        this.store = getBaseStore();
+        this.cache_context = cacheContextUri;
+        this.acceptor = acceptor;
+        this.config = new CacheConfiguration();
+        if(clientConfiguration != null) {
+            config.setClientConfiguration(clientConfiguration);
+        }
+    }
+
+
+    @Override
+    public void initialize() throws SailException {
+        super.initialize();
+
+        backend = new LDCachingKiWiBackend(store, cache_context);
+        backend.initialize();
+
+        ldcache = new LDCache(config,backend);
+
+    }
+
+    @Override
+    public void shutDown() throws SailException {
+        ldcache.shutdown();
+        backend.shutdown();
+
+        super.shutDown();
+    }
+
+    @Override
+    public NotifyingSailConnection getConnection() throws SailException {
+        return new KiWiLinkedDataSailConnection(super.getConnection(),ldcache,acceptor);
+    }
+
+    /**
+     * Return the KiWi store that is at the base of the SAIL stack. Throws an IllegalArgumentException in case the base
+     * store is not a KiWi store.
+     *
+     * @return
+     */
+    public KiWiStore getBaseStore() {
+        StackableSail current = this;
+        while(current != null && current.getBaseSail() instanceof StackableSail) {
+            current = (StackableSail) current.getBaseSail();
+        }
+        if(current != null && current.getBaseSail() instanceof KiWiStore) {
+            return (KiWiStore) current.getBaseSail();
+        } else {
+            throw new IllegalStateException("the base store is not a KiWiStore (type: "+current.getBaseSail().getClass().getCanonicalName()+")!");
+        }
+    }
+
+    public LDCachingKiWiBackend getBackend() {
+        return backend;
+    }
+
+    public LDCache getLDCache() {
+        return ldcache;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail-kiwi/src/main/java/org/apache/marmotta/ldcache/sail/KiWiLinkedDataSailConnection.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/src/main/java/org/apache/marmotta/ldcache/sail/KiWiLinkedDataSailConnection.java b/ldcache/ldcache-sail-kiwi/src/main/java/org/apache/marmotta/ldcache/sail/KiWiLinkedDataSailConnection.java
new file mode 100644
index 0000000..07e0c3c
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/src/main/java/org/apache/marmotta/ldcache/sail/KiWiLinkedDataSailConnection.java
@@ -0,0 +1,75 @@
+/**
+ * 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 info.aduna.iteration.CloseableIteration;
+import org.apache.marmotta.ldcache.services.LDCache;
+import org.apache.marmotta.sesame.filter.SesameFilter;
+import org.openrdf.model.BNode;
+import org.openrdf.model.Resource;
+import org.openrdf.model.Statement;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.sail.NotifyingSailConnection;
+import org.openrdf.sail.SailException;
+import org.openrdf.sail.helpers.NotifyingSailConnectionWrapper;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class KiWiLinkedDataSailConnection extends NotifyingSailConnectionWrapper {
+
+    private LDCache ldcache;
+
+    private SesameFilter<Resource> acceptor;
+
+    public KiWiLinkedDataSailConnection(NotifyingSailConnection wrappedCon, LDCache ldcache, SesameFilter<Resource> acceptor) {
+        super(wrappedCon);
+
+        this.ldcache = ldcache;
+        this.acceptor = acceptor;
+    }
+
+
+    /**
+     * Handle a triple store query event. This method carries out the following steps:
+     * 1. if the subject of the query is local, return immediately without doing anything
+     * 2. if the subject of the query is a remote resource, call refreshResource on it; refreshed triples will
+     *    be part of the currently active transaction and thus be available to the listTriples method execution
+     * 3, if the subject of the query is null, refresh all non-local resources in the triple store
+     */
+    @Override
+    public CloseableIteration<? extends Statement, SailException> getStatements(Resource subj, URI pred, Value obj, boolean includeInferred, Resource... contexts) throws SailException {
+        if(subj != null && isAcceptable(subj)) {
+            ldcache.refreshResource((URI)subj,false);
+        }
+
+        // the refreshed resources will anyways be stored in the same triple store, so we can simply delegate the query
+        // to the wrapped repository
+
+        return super.getStatements(subj, pred, obj, includeInferred, contexts);
+    }
+
+
+    private boolean isAcceptable(Resource resource) {
+        if(resource instanceof BNode) {
+            return false;
+        }
+        return acceptor.accept(resource);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/KiWiLinkedDataSailOfflineTest.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/KiWiLinkedDataSailOfflineTest.java b/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/KiWiLinkedDataSailOfflineTest.java
new file mode 100644
index 0000000..72b73b0
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/KiWiLinkedDataSailOfflineTest.java
@@ -0,0 +1,244 @@
+/*
+ * 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.ldcache.sail.test;
+
+import info.aduna.iteration.CloseableIteration;
+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.ldcache.sail.KiWiLinkedDataSail;
+import org.apache.marmotta.ldcache.sail.test.dummy.DummyEndpoint;
+import org.apache.marmotta.ldclient.model.ClientConfiguration;
+import org.apache.marmotta.sesame.filter.resource.ResourceFilter;
+import org.apache.marmotta.sesame.filter.resource.UriPrefixFilter;
+import org.hamcrest.CoreMatchers;
+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.repository.Repository;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.sail.SailRepository;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.Matchers.hasProperty;
+import static org.hamcrest.Matchers.hasToString;
+
+
+/**
+ * This test checks if the transparent linked data caching works, based on an ldclient offline provider. 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 KiWiLinkedDataSailOfflineTest {
+
+    private static final String CACHE_CONTEXT = "http://localhost/context/cache";
+
+    /**
+     * 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 KiWiLinkedDataSail lsail;
+
+    private ResourceFilter cacheFilter;
+
+    private Repository repository;
+
+    public KiWiLinkedDataSailOfflineTest(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();
+        }
+    }
+
+
+    @Before
+    public void initDatabase() throws RepositoryException {
+        cacheFilter = new UriPrefixFilter("http://remote/");
+
+        ClientConfiguration config = new ClientConfiguration();
+        config.addEndpoint(new DummyEndpoint());
+
+        store = new KiWiStore("test",jdbcUrl,jdbcUser,jdbcPass,dialect, "http://localhost/context/default", "http://localhost/context/inferred");
+        lsail = new KiWiLinkedDataSail(store,cacheFilter,CACHE_CONTEXT, config);
+        repository = new SailRepository(lsail);
+        repository.initialize();
+    }
+
+    @After
+    public void dropDatabase() throws RepositoryException, SQLException {
+        store.closeValueFactory();
+        lsail.getBackend().getPersistence().dropDatabase();
+        store.getPersistence().dropDatabase();
+        repository.shutDown();
+    }
+
+    /**
+     * This test verifies whether the transparent caching works for the three resources provided by our
+     * dummy provider.
+     * @throws Exception
+     */
+    @Test
+    public void testCachedResources() throws Exception {
+        String uri1 = "http://remote/resource1";
+        String uri2 = "http://remote/resource2";
+        String uri3 = "http://remote/resource3";
+
+        RepositoryConnection con = repository.getConnection();
+        try {
+            con.begin();
+
+            List<Statement> list1 = asList(con.getStatements(con.getValueFactory().createURI(uri1), null, null, true));
+
+            Assert.assertEquals(3,list1.size());
+            Assert.assertThat(list1, allOf(
+                    CoreMatchers.<Statement>hasItem(hasProperty("object", hasToString("\"Value 1\"^^xsd:string"))),
+                    CoreMatchers.<Statement>hasItem(hasProperty("object", hasToString("\"Value X\"^^xsd:string")))
+            ));
+
+
+            con.commit();
+
+            con.begin();
+
+            List<Statement> list2 = asList(con.getStatements(con.getValueFactory().createURI(uri2), null, null, true));
+
+            Assert.assertEquals(2, list2.size());
+            Assert.assertThat(list2, allOf(
+                    CoreMatchers.<Statement>hasItem(hasProperty("object", hasToString("\"Value 2\"^^xsd:string")))
+            ));
+
+
+            con.commit();
+
+            con.begin();
+
+            List<Statement> list3 = asList(con.getStatements(con.getValueFactory().createURI(uri3), null, null, true));
+
+            Assert.assertEquals(2, list3.size());
+            Assert.assertThat(list3, allOf(
+                    CoreMatchers.<Statement>hasItem(hasProperty("object", hasToString("\"Value 3\"^^xsd:string"))),
+                    CoreMatchers.<Statement>hasItem(hasProperty("object", hasToString("\"Value 4\"^^xsd:string")))
+            ));
+
+
+            con.commit();
+        } catch(RepositoryException ex) {
+            con.rollback();
+        } finally {
+            con.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 RepositoryException {
+        ArrayList<E> collection = new ArrayList<E>();
+        try {
+            try {
+                while (result.hasNext()) {
+                    collection.add(result.next());
+                }
+
+                return collection;
+            } finally {
+                result.close();
+            }
+        } catch(Throwable ex) {
+            throw new RepositoryException(ex);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyEndpoint.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyEndpoint.java b/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyEndpoint.java
new file mode 100644
index 0000000..d4c758e
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyEndpoint.java
@@ -0,0 +1,28 @@
+/*
+ * 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.ldcache.sail.test.dummy;
+
+import org.apache.marmotta.ldclient.api.endpoint.Endpoint;
+
+public class DummyEndpoint extends Endpoint {
+	
+	public DummyEndpoint() {
+		super("Dummy", "Dummy", "^http://remote", null, 86400l);
+		setPriority(PRIORITY_HIGH);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyProvider.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyProvider.java b/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyProvider.java
new file mode 100644
index 0000000..4a0bcd3
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyProvider.java
@@ -0,0 +1,81 @@
+/*
+ * 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.ldcache.sail.test.dummy;
+
+import org.apache.marmotta.ldclient.api.endpoint.Endpoint;
+import org.apache.marmotta.ldclient.api.ldclient.LDClientService;
+import org.apache.marmotta.ldclient.api.provider.DataProvider;
+import org.apache.marmotta.ldclient.exception.DataRetrievalException;
+import org.apache.marmotta.ldclient.model.ClientResponse;
+import org.openrdf.repository.Repository;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.sail.SailRepository;
+import org.openrdf.rio.RDFFormat;
+import org.openrdf.rio.RDFParseException;
+import org.openrdf.sail.memory.MemoryStore;
+
+import java.io.IOException;
+
+public class DummyProvider implements DataProvider {
+
+	@Override
+	public String getName() {
+		return "Dummy";
+	}
+
+	@Override
+	public String[] listMimeTypes() {
+		return new String[] {"application/dummy"};
+	}
+
+	@Override
+	public ClientResponse retrieveResource(String resource, LDClientService client, Endpoint endpoint) throws DataRetrievalException {
+        String filename = resource.substring("http://remote/".length()) + ".ttl";
+
+        try {
+            Repository triples = new SailRepository(new MemoryStore());
+            triples.initialize();
+
+            RepositoryConnection con = triples.getConnection();
+            try {
+                con.begin();
+
+                con.add(DummyProvider.class.getResourceAsStream(filename), resource, RDFFormat.TURTLE);
+
+                con.commit();
+            } catch(RepositoryException ex) {
+                con.rollback();
+            } catch (RDFParseException e) {
+                throw new DataRetrievalException("could not parse resource data for file "+filename);
+            } catch (IOException e) {
+                throw new DataRetrievalException("could not load resource data for file "+filename);
+            } finally {
+                con.close();
+            }
+
+            ClientResponse response = new ClientResponse(triples);
+
+            return response;
+        } catch (RepositoryException e) {
+            throw new DataRetrievalException("could not load resource data for file "+filename);
+        }
+
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyTest.java
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyTest.java b/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyTest.java
new file mode 100644
index 0000000..ab5ea29
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/src/test/java/org/apache/marmotta/ldcache/sail/test/dummy/DummyTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.ldcache.sail.test.dummy;
+
+import org.apache.marmotta.ldclient.api.ldclient.LDClientService;
+import org.apache.marmotta.ldclient.model.ClientConfiguration;
+import org.apache.marmotta.ldclient.model.ClientResponse;
+import org.apache.marmotta.ldclient.services.ldclient.LDClient;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.openrdf.repository.RepositoryConnection;
+
+/**
+ * Test if the dummy components work.
+ * <p/>
+ * Author: Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class DummyTest {
+
+    private LDClientService ldclient;
+
+
+    @Before
+    public void setupClient() {
+        ClientConfiguration config = new ClientConfiguration();
+        config.addEndpoint(new DummyEndpoint());
+
+        ldclient = new LDClient(config);
+    }
+
+    @After
+    public void shutdownClient() {
+        ldclient.shutdown();
+    }
+
+    @Test
+    public void testDummyProvider() throws Exception {
+        ClientResponse resp1 = ldclient.retrieveResource("http://remote/resource1");
+        RepositoryConnection con1 = resp1.getTriples().getConnection();
+        try {
+            con1.begin();
+            Assert.assertEquals(3, con1.size());
+            con1.commit();
+        } finally {
+            con1.close();
+        }
+
+        ClientResponse resp2 = ldclient.retrieveResource("http://remote/resource2");
+        RepositoryConnection con2 = resp2.getTriples().getConnection();
+        try {
+            con2.begin();
+            Assert.assertEquals(2, con2.size());
+            con2.commit();
+        } finally {
+            con2.close();
+        }
+
+        ClientResponse resp3 = ldclient.retrieveResource("http://remote/resource3");
+        RepositoryConnection con3 = resp3.getTriples().getConnection();
+        try {
+            con3.begin();
+            Assert.assertEquals(2, con3.size());
+            con3.commit();
+        } finally {
+            con3.close();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail-kiwi/src/test/resources/META-INF/services/org.apache.marmotta.ldclient.api.provider.DataProvider
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/src/test/resources/META-INF/services/org.apache.marmotta.ldclient.api.provider.DataProvider b/ldcache/ldcache-sail-kiwi/src/test/resources/META-INF/services/org.apache.marmotta.ldclient.api.provider.DataProvider
new file mode 100644
index 0000000..d9367d2
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/src/test/resources/META-INF/services/org.apache.marmotta.ldclient.api.provider.DataProvider
@@ -0,0 +1 @@
+org.apache.marmotta.ldcache.sail.test.dummy.DummyProvider
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource1.ttl
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource1.ttl b/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource1.ttl
new file mode 100644
index 0000000..bc34cc1
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource1.ttl
@@ -0,0 +1,4 @@
+@prefix ex: <http://remote/> .
+ex:resource1 ex:property1 "Value 1" ;
+             ex:property2 ex:resource2 ;
+             ex:property3 "Value X" .
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource2.ttl
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource2.ttl b/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource2.ttl
new file mode 100644
index 0000000..1e02b0b
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource2.ttl
@@ -0,0 +1,3 @@
+@prefix ex: <http://remote/> .
+ex:resource2 ex:property1 "Value 2" ;
+             ex:property2 ex:resource3 .
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource3.ttl
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource3.ttl b/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource3.ttl
new file mode 100644
index 0000000..0964311
--- /dev/null
+++ b/ldcache/ldcache-sail-kiwi/src/test/resources/org/apache/marmotta/ldcache/sail/test/dummy/resource3.ttl
@@ -0,0 +1,3 @@
+@prefix ex: <http://remote/> .
+ex:resource3 ex:property1 "Value 3" ;
+             ex:property3 "Value 4" .
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail/.classpath
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail/.classpath b/ldcache/ldcache-sail/.classpath
new file mode 100644
index 0000000..90df7da
--- /dev/null
+++ b/ldcache/ldcache-sail/.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-sail/.project
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail/.project b/ldcache/ldcache-sail/.project
new file mode 100644
index 0000000..09d5094
--- /dev/null
+++ b/ldcache/ldcache-sail/.project
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>ldcache-sail</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>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+	</natures>
+</projectDescription>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldcache/ldcache-sail/.settings/org.eclipse.jdt.core.prefs
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail/.settings/org.eclipse.jdt.core.prefs b/ldcache/ldcache-sail/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..60105c1
--- /dev/null
+++ b/ldcache/ldcache-sail/.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-sail/.settings/org.eclipse.m2e.core.prefs
----------------------------------------------------------------------
diff --git a/ldcache/ldcache-sail/.settings/org.eclipse.m2e.core.prefs b/ldcache/ldcache-sail/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/ldcache/ldcache-sail/.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/pom.xml
----------------------------------------------------------------------
diff --git a/ldcache/pom.xml b/ldcache/pom.xml
new file mode 100644
index 0000000..6e1b3e9
--- /dev/null
+++ b/ldcache/pom.xml
@@ -0,0 +1,75 @@
+<?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>lmf-parent</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>at.newmedialab.lmf</groupId>
+    <artifactId>ldcache-parent</artifactId>
+    <name>LDCache: Parent</name>
+    <packaging>pom</packaging>
+
+    <description>
+        Linked Data Caching: Parent POM
+    </description>
+
+    <developers>
+        <developer>
+            <name>Sebastian Schaffert</name>
+            <email>sschaffert@apache.org</email>
+            <organization>Apache Software Foundation</organization>
+        </developer>
+        <developer>
+            <name>Jakob Frank</name>
+            <email>jfrank@apache.org</email>
+            <organization>Apache Software Foundation</organization>
+        </developer>
+    </developers>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin> <!-- generate JRebel Configuration -->
+                    <groupId>org.zeroturnaround</groupId>
+                    <artifactId>jrebel-maven-plugin</artifactId>
+                    <configuration>
+                        <relativePath>../../</relativePath>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <modules>
+        <module>ldcache-api</module>
+        <module>ldcache-core</module>
+        <module>ldcache-sail-kiwi</module>
+        <module>ldcache-sail-generic</module>
+        <module>ldcache-backend-ehcache</module>
+        <module>ldcache-backend-kiwi</module>
+        <!--
+        <module>ldcache-backend-ehcache</module>
+        <module>ldcache-backend-kiwi</module>
+        -->
+    </modules>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/.project
----------------------------------------------------------------------
diff --git a/ldclient/.project b/ldclient/.project
new file mode 100644
index 0000000..72be855
--- /dev/null
+++ b/ldclient/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>ldclient-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/ldclient/.settings/org.eclipse.m2e.core.prefs
----------------------------------------------------------------------
diff --git a/ldclient/.settings/org.eclipse.m2e.core.prefs b/ldclient/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/ldclient/.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/ldclient/README.txt
----------------------------------------------------------------------
diff --git a/ldclient/README.txt b/ldclient/README.txt
new file mode 100644
index 0000000..2cc03a5
--- /dev/null
+++ b/ldclient/README.txt
@@ -0,0 +1,12 @@
+This component will contain all the code necessary for accessing linked data resources. It will be split into the
+following modules:
+
+- ldclient-api: defines the API for accessing LD resources, as well as the model for data providers that wrap
+  legacy sources
+- ldclient-core: implements the core functionality for accessing LD resources via HTTP and other protocols; offers
+  access to the API through a factory
+- ldclient-provider-rdf: implements providers for accessing LD resources that already offer data as RDF
+- ldclient-provider-xml: implements (abstract) providers for accessing LD resources that offer some form of XML;
+  these providers can be subclassed for mapping XPath expressions to RDF properties
+
+In addition, a number of custom providers can be defined.

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/.classpath
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/.classpath b/ldclient/ldclient-api/.classpath
new file mode 100644
index 0000000..1b28ee5
--- /dev/null
+++ b/ldclient/ldclient-api/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java"/>
+	<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">
+		<attributes>
+			<attribute name="org.eclipse.jst.component.nondependency" value=""/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/.project
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/.project b/ldclient/ldclient-api/.project
new file mode 100644
index 0000000..57ebe04
--- /dev/null
+++ b/ldclient/ldclient-api/.project
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>ldclient-api</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<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.eclipse.wst.validation.validationbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+	</natures>
+</projectDescription>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/.settings/org.eclipse.core.resources.prefs
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/.settings/org.eclipse.core.resources.prefs b/ldclient/ldclient-api/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..2b76340
--- /dev/null
+++ b/ldclient/ldclient-api/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/.settings/org.eclipse.jdt.core.prefs
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/.settings/org.eclipse.jdt.core.prefs b/ldclient/ldclient-api/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..69c31cd
--- /dev/null
+++ b/ldclient/ldclient-api/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+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/ldclient/ldclient-api/.settings/org.eclipse.m2e.core.prefs
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/.settings/org.eclipse.m2e.core.prefs b/ldclient/ldclient-api/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/ldclient/ldclient-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/ldclient/ldclient-api/.settings/org.eclipse.wst.common.component
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/.settings/org.eclipse.wst.common.component b/ldclient/ldclient-api/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..56ef980
--- /dev/null
+++ b/ldclient/ldclient-api/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+    <wb-module deploy-name="ldclient-api">
+        <wb-resource deploy-path="/" source-path="/src/main/java"/>
+    </wb-module>
+</project-modules>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/.settings/org.eclipse.wst.common.project.facet.core.xml
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/.settings/org.eclipse.wst.common.project.facet.core.xml b/ldclient/ldclient-api/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..c78d932
--- /dev/null
+++ b/ldclient/ldclient-api/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <installed facet="java" version="1.6"/>
+  <installed facet="jst.utility" version="1.0"/>
+</faceted-project>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/pom.xml
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/pom.xml b/ldclient/ldclient-api/pom.xml
new file mode 100644
index 0000000..7a42fc4
--- /dev/null
+++ b/ldclient/ldclient-api/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<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>ldclient-parent</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <artifactId>ldclient-api</artifactId>
+    <name>LDClient: API</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>at.newmedialab.lmf</groupId>
+            <artifactId>marmotta-commons</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-repository-sail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-repository-event</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-sail-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-sail-memory</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/endpoint/Endpoint.java
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/endpoint/Endpoint.java b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/endpoint/Endpoint.java
new file mode 100644
index 0000000..21ddb93
--- /dev/null
+++ b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/endpoint/Endpoint.java
@@ -0,0 +1,311 @@
+/**
+ * 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.ldclient.api.endpoint;
+
+import org.apache.marmotta.commons.http.ContentType;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import static org.apache.marmotta.commons.http.LMFHttpUtils.parseAcceptHeader;
+
+/**
+ * Definition of a Linked Data Endpoint. Contains information how to query the
+ * endpoint, what format to expect, and when to expire data from this endpoint.
+ * <p/>
+ * <ul>
+ * <li> LinkedDataProvider endpoints will be accessed by directly
+ * retrieving the URI with appropriate Accept headers following the Linked Data
+ * recommendations
+ * <li> CacheProvider endpoints will be accessed by passing the URI
+ * as request parameter to the cache and parsing the response according to the
+ * content type defined for this endpoint (Content-Type header is too
+ * unspecific)
+ * <li> SPARQLProvider endpoints will be accessed by issuing a query
+ * of <code>SELECT ?p ?o WHERE { {url} ?p ?o }</code> to retrieve all triples
+ * for the requested resource
+ * <li> NONE act as blacklist. Resources matching handled by this endpoint are not fetched.
+ * </ul>
+ * <p/>
+ * Note: this class has a natural ordering that is inconsistent with equals.
+ * <p/>
+ * User: sschaffe
+ */
+public class Endpoint implements Comparable<Endpoint> {
+
+    /**
+     * constant indicating high priority of this endpoint definition
+     */
+    public final static int PRIORITY_HIGH = 3;
+
+    /**
+     * constant indicating medium priority of this endpoint definition
+     */
+    public final static int PRIORITY_MEDIUM = 2;
+
+    /**
+     * constant indicating low priority of this endpoint definition
+     */
+    public final static int PRIORITY_LOW = 1;
+
+    /**
+     * A human-readable name for this endpoint.
+     */
+    private String name;
+
+    /**
+     * The type of the endpoint. Either the name of a data provider, or the special name "NONE" to indicate that
+     * the data for these URIs should not be retrieved.
+     */
+    private String type;
+
+
+    public static final String REGEX_INDICATOR = "~";
+
+    /**
+     * A regular expression describing for which URIs the endpoint applies. The endpoint will be applied to all
+     * resource requests matching with this pattern.
+     * 
+     * @see Pattern
+     */
+    private String uriPattern;
+
+    private Pattern uriPatternCompiled = null;
+
+    /**
+     * Flag to temporarily enable/disable the endpoint configuration at runtime.
+     */
+    private boolean            active;
+
+    /**
+     * The priority of this endpoint configuration; endpoints with higher priority take precedence over
+     * endpoints with lower priority in case both would be applicable.
+     */
+    private int priority = PRIORITY_MEDIUM;
+
+    /**
+     * The HTTP URL to access the endpoint. Occurrences of the string {uri} will
+     * be replaced by the resource URI of the queried resource for CACHE
+     * endpoints. Occurrences of the string {query} will be replaced by the
+     * SPARQL query for the requested resource for SPARQL endpoints.
+     * 
+     * Requried for SPARQL and CACHE endpoints, ignored for LINKEDDATA endpoints
+     * 
+     * <pre>
+     * Examples:
+     * - Sindice: http://api.sindice.com/v2/live?url={uri}
+     *        or  http://api.sindice.com/v2/cache?url={uri}
+     *        or  http://sparql.sindice.com/sparql?default-graph-uri=&query={query}&format=text%2Fhtml&debug=on
+     * - Stanbol: http://dev.iks-project.eu:8080/entityhub/lookup/?id={uri}&create=false
+     * </pre>
+     */
+    private String endpointUrl;
+
+
+    /**
+     * The content type (MIME) returned by this endpoint. Used to determine how to parse the result.
+     */
+    private Set<ContentType> contentTypes;
+
+    /**
+     * The default expiry time in seconds to use for this endpoint if the HTTP request does not explicitly return an
+     * expiry time.
+     */
+    private Long defaultExpiry;
+
+
+    /**
+     * Additional configuration options used by this endpoint. Can be accessed in the different providers.
+     */
+    private Map<String,String> properties;
+
+    public Endpoint() {
+    }
+
+    public Endpoint(String name, String type, String uriPattern, String endpointUrl, Long defaultExpiry) {
+        this.name = name;
+        this.type = type;
+        this.uriPattern = uriPattern;
+        this.endpointUrl = endpointUrl;
+        this.contentTypes = new HashSet<ContentType>();
+        this.defaultExpiry = defaultExpiry;
+        this.active = true;
+        this.properties = new HashMap<String, String>();
+    }
+
+    public Endpoint(String name, String type, String uriPattern, String endpointUrl, String contentType, Long defaultExpiry) {
+        this(name,type,uriPattern,endpointUrl,defaultExpiry);
+        this.contentTypes = new HashSet<ContentType>(parseAcceptHeader(contentType));
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getUriPattern() {
+        return uriPattern;
+    }
+
+    public void setUriPattern(String uriPattern) {
+        this.uriPattern = uriPattern;
+        this.uriPatternCompiled = null;
+    }
+
+    public String getEndpointUrl() {
+        return endpointUrl;
+    }
+
+    public void setEndpointUrl(String endpointUrl) {
+        this.endpointUrl = endpointUrl;
+    }
+
+    public Set<ContentType> getContentTypes() {
+        return contentTypes;
+    }
+
+    public void addContentType(ContentType type) {
+        contentTypes.add(type);
+    }
+
+    public void setContentTypes(Set<ContentType> contentTypes) {
+        this.contentTypes = contentTypes;
+    }
+
+    public Long getDefaultExpiry() {
+        return defaultExpiry;
+    }
+
+    public void setDefaultExpiry(Long defaultExpiry) {
+        this.defaultExpiry = defaultExpiry;
+    }
+
+    public boolean isActive() {
+        return active;
+    }
+
+    public void setActive(boolean active) {
+        this.active = active;
+    }
+
+    public int getPriority() {
+        return priority;
+    }
+
+    public void setPriority(int priority) {
+        this.priority = priority;
+    }
+
+
+    public String getProperty(String key) {
+        return properties.get(key);
+    }
+
+    public void setProperty(String key, String value) {
+        properties.put(key,value);
+    }
+
+
+    public Pattern getUriPatternCompiled() {
+        if (uriPatternCompiled == null) {
+            try {
+                if (uriPattern.startsWith(REGEX_INDICATOR)) {
+                    // backwards compatibility
+                    uriPatternCompiled = Pattern.compile(uriPattern.substring(REGEX_INDICATOR.length()));
+                } else {
+                    uriPatternCompiled = Pattern.compile(uriPattern);
+                }
+            } catch (PatternSyntaxException pse) {
+            }
+        }
+        return uriPatternCompiled;
+    }
+
+    /**
+     * Check if this {@link Endpoint} handles (is responsible) for this URI.
+     * 
+     * @param uri the URI to check
+     * @return <code>true</code> if the uri matches the endpoint's {@link #uriPattern}
+     * 
+     * @see #uriPattern
+     */
+    public boolean handles(String uri) {
+        if (isActive() && getUriPatternCompiled() != null) return getUriPatternCompiled().matcher(uri).find();
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Endpoint endpoint = (Endpoint) o;
+
+        if (name != null ? !name.equals(endpoint.name) : endpoint.name != null) return false;
+        if (type != null ? !type.equals(endpoint.type) : endpoint.type != null) return false;
+        if (uriPattern != null ? !uriPattern.equals(endpoint.uriPattern) : endpoint.uriPattern != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (type != null ? type.hashCode() : 0);
+        result = 31 * result + (uriPattern != null ? uriPattern.hashCode() : 0);
+        return result;
+    }
+
+
+    /**
+     * Compares this object with the specified object for order according to priority.
+     * Returns a negative integer, zero, or a positive integer as this object is less
+     * than, equal to, or greater than the specified object.
+     *
+     * @see #getPriority()
+     * @param o the object to be compared.
+     * @return a negative integer, zero, or a positive integer as this object
+     *         is less than, equal to, or greater than the specified object.
+     * @throws NullPointerException if the specified object is null
+     * @throws ClassCastException   if the specified object's type prevents it
+     *                              from being compared to this object.
+     */
+    @Override
+    public int compareTo(Endpoint o) {
+        if(getPriority() > o.getPriority()) {
+            return -1;
+        } else if(getPriority() < o.getPriority()) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/ldclient/LDClientService.java
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/ldclient/LDClientService.java b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/ldclient/LDClientService.java
new file mode 100644
index 0000000..64572ac
--- /dev/null
+++ b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/ldclient/LDClientService.java
@@ -0,0 +1,96 @@
+/**
+ * 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.ldclient.api.ldclient;
+
+import org.apache.http.client.HttpClient;
+import org.apache.marmotta.ldclient.api.endpoint.Endpoint;
+import org.apache.marmotta.ldclient.api.provider.DataProvider;
+import org.apache.marmotta.ldclient.exception.DataRetrievalException;
+import org.apache.marmotta.ldclient.model.ClientConfiguration;
+import org.apache.marmotta.ldclient.model.ClientResponse;
+
+import java.util.Set;
+
+/**
+ * A service offering Linked Data client functionality for retrieving Linked Data resources from the cloud.
+ * Implements retrieval of triples from the cloud depending on the Endpoint definitions available for a resource.
+ *
+ * <p/>
+ * User: Sebastian Schaffert
+ */
+public interface LDClientService {
+
+    /**
+     * Perform a ping (HTTP HEAD) to the resource
+     * 
+     * @param resource
+     * @return
+     */
+    public boolean ping(String resource);
+
+    /**
+     * Retrieve all triples for this resource from the Linked Data Cloud. Retrieval will be carried out according
+     * to the endpoint definition that matches this resource. In case no endpoint definition is found, the method
+     * will try an "default" Linked Data retrieval if the configuration option "ldcache.fallback" is set to true
+     *
+     *
+     *
+     * @param resource  the URI resource for which to retrieve the triples
+     * @return a Sesame in-memory repository containing the triples for this resource
+     */
+    public ClientResponse retrieveResource(String resource) throws DataRetrievalException;
+
+    /**
+     * Get access to the Apache HTTP Client managed by the connection handler to execute
+     * a request.
+     *
+     * @return
+     */
+    public HttpClient getClient();
+
+
+    /**
+     * Get the client configuration used by the connection handler
+     * @return
+     */
+    public ClientConfiguration getClientConfiguration();
+
+    /**
+     * Retrieve the endpoint matching the KiWiUriResource passed as argument. The endpoint is determined by
+     * matching the endpoint's URI prefix with the resource URI. If no matching endpoint exists, returns null.
+     * The LinkedDataClientService can then decide (based on configuration) whether to try with a standard
+     * LinkedDataRequest or ignore the request.
+     *
+     * @param resource the KiWiUriResource to check.
+     */
+    Endpoint getEndpoint(String resource);
+
+    /**
+     * Test whether an endpoint definition for the given url pattern already exists.
+     *
+     * @param urlPattern
+     * @return
+     */
+    boolean hasEndpoint(String urlPattern);
+
+    void shutdown();
+
+    /**
+     * Return a collection of all available data providers (i.e. registered through the service loader).
+     * @return
+     */
+    Set<DataProvider> getDataProviders();
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/provider/DataProvider.java
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/provider/DataProvider.java b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/provider/DataProvider.java
new file mode 100644
index 0000000..6359961
--- /dev/null
+++ b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/provider/DataProvider.java
@@ -0,0 +1,62 @@
+/**
+ * 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.ldclient.api.provider;
+
+import org.apache.marmotta.ldclient.api.endpoint.Endpoint;
+import org.apache.marmotta.ldclient.api.ldclient.LDClientService;
+import org.apache.marmotta.ldclient.exception.DataRetrievalException;
+import org.apache.marmotta.ldclient.model.ClientResponse;
+
+/**
+ * Abstract interface for defining different implementations of data providers. Standard data
+ * providers are Linked Data and SPARQL, but in principle any data source can be wrapped as RDF
+ * (e.g. Google Data API)
+ * <p/>
+ * Data provider should be implemented as CDI service beans and can make use of @PostConstruct
+ * methods for registering themselves for specific URIs or carrying out maintenance work.
+ * 
+ * @author Sebastian Schaffert
+ */
+public interface DataProvider {
+
+    /**
+     * Return the name of this data provider. To be used e.g. in the configuration and in log messages.
+     * @return
+     */
+    public String getName();
+
+
+    /**
+     * Return the list of mime types accepted by this data provider.
+     * 
+     * @return
+     */
+    public String[] listMimeTypes();
+
+    /**
+     * Retrieve the data for a resource using the given http client and endpoint definition. The service is
+     * supposed to manage the connection handling itself. See AbstractHttpProvider
+     * for a generic implementation of this method.
+     *
+     *
+     *
+     * @param resource the resource to be retrieved
+     * @param endpoint the endpoint definition
+     * @return a completely specified client response, including expiry information and the set of triples
+     */
+    public ClientResponse retrieveResource(String resource, LDClientService client, Endpoint endpoint) throws DataRetrievalException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/provider/ValueMapper.java
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/provider/ValueMapper.java b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/provider/ValueMapper.java
new file mode 100644
index 0000000..6ac35e1
--- /dev/null
+++ b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/api/provider/ValueMapper.java
@@ -0,0 +1,43 @@
+/**
+ * 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.ldclient.api.provider;
+
+import org.openrdf.model.Value;
+import org.openrdf.model.ValueFactory;
+
+import java.util.List;
+
+/**
+ * Map the value returned by a selection in a different data format (e.g. an XPath expression( into a list of Sesame
+ * values, using the ValueFactory passed as argument.
+ *
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public interface ValueMapper {
+
+    /**
+     * Take the selected value, process it according to the mapping definition, and create Sesame Values using the
+     * factory passed as argument.
+     *
+     *
+     * @param resourceUri
+     * @param selectedValue
+     * @param factory
+     * @return
+     */
+    public List<Value> map(String resourceUri, String selectedValue, ValueFactory factory);
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/exception/DataRetrievalException.java
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/exception/DataRetrievalException.java b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/exception/DataRetrievalException.java
new file mode 100644
index 0000000..1753854
--- /dev/null
+++ b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/exception/DataRetrievalException.java
@@ -0,0 +1,82 @@
+/**
+ * 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.ldclient.exception;
+
+/**
+ * Thrown in case an error occurs during data import or retrieval.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class DataRetrievalException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Constructs a new exception with <code>null</code> as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public DataRetrievalException() {
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public DataRetrievalException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * <code>cause</code> is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *                by the {@link #getMessage()} method).
+     * @param cause   the cause (which is saved for later retrieval by the
+     *                {@link #getCause()} method).  (A <tt>null</tt> value is
+     *                permitted, and indicates that the cause is nonexistent or
+     *                unknown.)
+     * @since 1.4
+     */
+    public DataRetrievalException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
+     * typically contains the class and detail message of <tt>cause</tt>).
+     * This constructor is useful for exceptions that are little more than
+     * wrappers for other throwables (for example, {@link
+     * java.security.PrivilegedActionException}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *              {@link #getCause()} method).  (A <tt>null</tt> value is
+     *              permitted, and indicates that the cause is nonexistent or
+     *              unknown.)
+     * @since 1.4
+     */
+    public DataRetrievalException(Throwable cause) {
+        super(cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/model/ClientConfiguration.java
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/model/ClientConfiguration.java b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/model/ClientConfiguration.java
new file mode 100644
index 0000000..52b7819
--- /dev/null
+++ b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/model/ClientConfiguration.java
@@ -0,0 +1,169 @@
+/**
+ * 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.ldclient.model;
+
+import org.apache.http.client.HttpClient;
+import org.apache.marmotta.ldclient.api.endpoint.Endpoint;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Configuration options for the Linked Data Client.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class ClientConfiguration {
+
+    /**
+     * Socket timeout in milliseconds; maximum time a socket may be idle; default 60 seconds
+     */
+    private int socketTimeout = 60000;
+
+    /**
+     * HTTP connection timeout in milliseconds; default 10 seconds, because we don't want slow servers to slow down
+     * batch retrievals
+     */
+    private int connectionTimeout = 10000;
+
+    /**
+     * Maximum number of HTTP requests to run in parallel
+     */
+    private int maxParallelRequests = 10;
+
+
+    /**
+     * Default expiry time in seconds if not given by the server.
+     */
+    private long defaultExpiry = 86400;
+
+    /**
+     * Minimum expiry time in seconds in case the server returns a lower expiry time
+     */
+    private long minimumExpiry = 30;
+
+    /**
+     * The URI prefixes to exclude from retrieval; this is typically used for resources that are
+     * considered "local", i.e. managed by the local triple store
+     */
+    private Set<String> excludeUris;
+
+    /**
+     * A collection of endpoint definitions to use by this Linked Data Client.
+     */
+    private Set<Endpoint> endpoints;
+    
+    /**
+     * A HttpClient used for retrieving the resource data.
+     */
+    private HttpClient httpClient;
+
+    public ClientConfiguration() {
+        excludeUris = new HashSet<String>();
+        endpoints   = new HashSet<Endpoint>();
+        httpClient = null;
+    }
+
+    public int getConnectionTimeout() {
+        return connectionTimeout;
+    }
+
+    public void setConnectionTimeout(int connectionTimeout) {
+        this.connectionTimeout = connectionTimeout;
+    }
+
+    public int getSocketTimeout() {
+        return socketTimeout;
+    }
+
+    public void setSocketTimeout(int socketTimeout) {
+        this.socketTimeout = socketTimeout;
+    }
+
+    public int getMaxParallelRequests() {
+        return maxParallelRequests;
+    }
+
+    public void setMaxParallelRequests(int maxParallelRequests) {
+        this.maxParallelRequests = maxParallelRequests;
+    }
+
+
+    public long getDefaultExpiry() {
+        return defaultExpiry;
+    }
+
+    public void setDefaultExpiry(long defaultExpiry) {
+        this.defaultExpiry = defaultExpiry;
+    }
+
+    public long getMinimumExpiry() {
+        return minimumExpiry;
+    }
+
+    public void setMinimumExpiry(long minimumExpiry) {
+        this.minimumExpiry = minimumExpiry;
+    }
+
+    public void addExcludeUri(String uriPrefix) {
+        excludeUris.add(uriPrefix);
+    }
+
+    public Set<String> getExcludeUris() {
+        return excludeUris;
+    }
+
+    public void setExcludeUris(Set<String> excludeUris) {
+        this.excludeUris = excludeUris;
+    }
+
+    /**
+     * Return true in case the URI passed as argument is considered to be excluded.
+     *
+     * @param uri
+     * @return
+     */
+    public boolean isExcludedUri(String uri) {
+        for(String prefix : excludeUris) {
+            if(uri.startsWith(prefix)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    public void addEndpoint(Endpoint endpoint) {
+        endpoints.add(endpoint);
+    }
+
+    public Set<Endpoint> getEndpoints() {
+        return endpoints;
+    }
+
+    public void setEndpoints(Set<Endpoint> endpoints) {
+        this.endpoints = endpoints;
+    }
+
+	public HttpClient getHttpClient() {
+		return httpClient;
+	}
+
+	public void setHttpClient(HttpClient httpClient) {
+		this.httpClient = httpClient;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/model/ClientResponse.java
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/model/ClientResponse.java b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/model/ClientResponse.java
new file mode 100644
index 0000000..4811ade
--- /dev/null
+++ b/ldclient/ldclient-api/src/main/java/org/apache/marmotta/ldclient/model/ClientResponse.java
@@ -0,0 +1,58 @@
+/**
+ * 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.ldclient.model;
+
+import org.apache.commons.lang.time.DateUtils;
+import org.openrdf.repository.Repository;
+
+import java.util.Date;
+
+/**
+ * LDCache Client Response
+ * 
+ * @author Sebastian Schaffert
+ * @author Sergio Fernández
+ */
+public class ClientResponse {
+
+    private static final int DEFAULT_EXPIRATION_IN_DAYS = 7;
+
+    private Repository triples;
+
+    private Date expires;
+
+    public ClientResponse(Repository triples) {
+        this.triples = triples;
+        this.expires = DateUtils.addDays(new Date(), DEFAULT_EXPIRATION_IN_DAYS);
+    }
+
+    public Repository getTriples() {
+        return triples;
+    }
+
+    public void setTriples(Repository triples) {
+        this.triples = triples;
+    }
+
+    public Date getExpires() {
+        return expires;
+    }
+
+    public void setExpires(Date expires) {
+        this.expires = new Date(expires.getTime());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-core/.classpath
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-core/.classpath b/ldclient/ldclient-core/.classpath
new file mode 100644
index 0000000..bf96ac0
--- /dev/null
+++ b/ldclient/ldclient-core/.classpath
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java"/>
+	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
+	<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+	<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
+	<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">
+		<attributes>
+			<attribute name="org.eclipse.jst.component.nondependency" value=""/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-core/.project
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-core/.project b/ldclient/ldclient-core/.project
new file mode 100644
index 0000000..50a702b
--- /dev/null
+++ b/ldclient/ldclient-core/.project
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>ldclient-core</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.zeroturnaround.eclipse.rebelXmlBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.wst.validation.validationbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>org.zeroturnaround.eclipse.jrebelNature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+	</natures>
+</projectDescription>

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/ldclient/ldclient-core/.settings/org.eclipse.core.resources.prefs
----------------------------------------------------------------------
diff --git a/ldclient/ldclient-core/.settings/org.eclipse.core.resources.prefs b/ldclient/ldclient-core/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..dc1b414
--- /dev/null
+++ b/ldclient/ldclient-core/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8