You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ss...@apache.org on 2015/12/12 17:06:43 UTC

[2/7] marmotta git commit: move experimental C++ LevelDB backend into Apache Marmotta main, and named the new module "ostrich" as an analogy to "kiwi"

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/test/main.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/test/main.cc b/libraries/ostrich/backend/test/main.cc
new file mode 100644
index 0000000..40755a6
--- /dev/null
+++ b/libraries/ostrich/backend/test/main.cc
@@ -0,0 +1,11 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+// Author: Sebastian Schaffert <sc...@google.com>
+#include <glog/logging.h>
+#include "gtest.h"
+
+// run all tests in the current binary
+int main(int argc, char **argv) {
+    ::google::InitGoogleLogging(argv[0]);
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/util/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/util/CMakeLists.txt b/libraries/ostrich/backend/util/CMakeLists.txt
new file mode 100644
index 0000000..f573c3c
--- /dev/null
+++ b/libraries/ostrich/backend/util/CMakeLists.txt
@@ -0,0 +1,3 @@
+include_directories(.. ${CMAKE_CURRENT_BINARY_DIR}/..)
+
+add_library(marmotta_util murmur3.cc murmur3.h split.cc split.h iterator.h)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/util/iterator.h
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/util/iterator.h b/libraries/ostrich/backend/util/iterator.h
new file mode 100644
index 0000000..cb95d8b
--- /dev/null
+++ b/libraries/ostrich/backend/util/iterator.h
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A collection of iterators used by different components.
+//
+
+#ifndef MARMOTTA_ITERATOR_H
+#define MARMOTTA_ITERATOR_H
+
+namespace marmotta {
+namespace util {
+
+/**
+ * A common iterator class for iterators binding resources.
+ */
+template<typename T>
+class CloseableIterator {
+ public:
+
+    /**
+     * Close the iterator, freeing any wrapped resources
+     */
+    virtual ~CloseableIterator() {}
+
+    /**
+     * Increment iterator to next element.
+    */
+    virtual CloseableIterator<T>& operator++() = 0;
+
+    /**
+     * Dereference iterator, returning a reference to the current element.
+     */
+    virtual T& operator*() = 0;
+
+    /**
+     * Dereference iterator, returning a pointer to the current element.
+     */
+    virtual T* operator->() = 0;
+
+    /**
+     * Return true in case the iterator has more elements.
+     */
+    virtual bool hasNext() = 0;
+
+};
+
+/**
+ * An empty iterator.
+ */
+template<typename T>
+class EmptyIterator : public CloseableIterator<T> {
+ public:
+    EmptyIterator() { }
+
+    CloseableIterator<T> &operator++() override {
+        return *this;
+    }
+
+    T &operator*() override {
+        throw std::out_of_range("No more elements");
+    };
+
+    T *operator->() override {
+        throw std::out_of_range("No more elements");
+    };
+
+    bool hasNext() override {
+        return false;
+    };
+};
+
+
+
+/**
+ * An iterator wrapping a single element.
+ */
+template<typename T>
+class SingletonIterator : public CloseableIterator<T> {
+ public:
+    SingletonIterator(T& value) : value(value), incremented(false) { }
+
+    CloseableIterator<T> &operator++() override {
+        incremented = true;
+        return *this;
+    };
+
+    T &operator*() override {
+        if (!incremented)
+            return value;
+        else
+            throw std::out_of_range("No more elements");
+    };
+
+    T *operator->() override {
+        if (!incremented)
+            return &value;
+        else
+            throw std::out_of_range("No more elements");
+    };
+
+    bool hasNext() override {
+        return !incremented;
+    };
+
+ private:
+    T value;
+    bool incremented;
+
+};
+
+}
+}
+
+
+#endif //MARMOTTA_ITERATOR_H

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/util/murmur3.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/util/murmur3.cc b/libraries/ostrich/backend/util/murmur3.cc
new file mode 100644
index 0000000..27bd6c1
--- /dev/null
+++ b/libraries/ostrich/backend/util/murmur3.cc
@@ -0,0 +1,313 @@
+//-----------------------------------------------------------------------------
+// MurmurHash3 was written by Austin Appleby, and is placed in the public
+// domain. The author hereby disclaims copyright to this source code.
+
+// Note - The x86 and x64 versions do _not_ produce the same results, as the
+// algorithms are optimized for their respective platforms. You can still
+// compile and run any of them on any platform, but your performance with the
+// non-native version will be less than optimal.
+
+#include "murmur3.h"
+
+#define FORCE_INLINE inline __attribute__((always_inline))
+
+inline uint32_t rotl32 ( uint32_t x, int8_t r )
+{
+    return (x << r) | (x >> (32 - r));
+}
+
+inline uint64_t rotl64 ( uint64_t x, int8_t r )
+{
+    return (x << r) | (x >> (64 - r));
+}
+
+#define ROTL32(x,y)     rotl32(x,y)
+#define ROTL64(x,y)     rotl64(x,y)
+
+#define BIG_CONSTANT(x) (x##LLU)
+
+//-----------------------------------------------------------------------------
+// Block read - if your platform needs to do endian-swapping or can only
+// handle aligned reads, do the conversion here
+
+FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i )
+{
+    return p[i];
+}
+
+FORCE_INLINE uint64_t getblock64 ( const uint64_t * p, int i )
+{
+    return p[i];
+}
+
+//-----------------------------------------------------------------------------
+// Finalization mix - force all bits of a hash block to avalanche
+
+FORCE_INLINE uint32_t fmix32 ( uint32_t h )
+{
+    h ^= h >> 16;
+    h *= 0x85ebca6b;
+    h ^= h >> 13;
+    h *= 0xc2b2ae35;
+    h ^= h >> 16;
+
+    return h;
+}
+
+//----------
+
+FORCE_INLINE uint64_t fmix64 ( uint64_t k )
+{
+    k ^= k >> 33;
+    k *= BIG_CONSTANT(0xff51afd7ed558ccd);
+    k ^= k >> 33;
+    k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
+    k ^= k >> 33;
+
+    return k;
+}
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x86_32 ( const void * key, int len,
+                          uint32_t seed, void * out )
+{
+    const uint8_t * data = (const uint8_t*)key;
+    const int nblocks = len / 4;
+
+    uint32_t h1 = seed;
+
+    const uint32_t c1 = 0xcc9e2d51;
+    const uint32_t c2 = 0x1b873593;
+
+    //----------
+    // body
+
+    const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
+
+    for(int i = -nblocks; i; i++)
+    {
+        uint32_t k1 = getblock32(blocks,i);
+
+        k1 *= c1;
+        k1 = ROTL32(k1,15);
+        k1 *= c2;
+
+        h1 ^= k1;
+        h1 = ROTL32(h1,13);
+        h1 = h1*5+0xe6546b64;
+    }
+
+    //----------
+    // tail
+
+    const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
+
+    uint32_t k1 = 0;
+
+    switch(len & 3)
+    {
+        case 3: k1 ^= tail[2] << 16;
+        case 2: k1 ^= tail[1] << 8;
+        case 1: k1 ^= tail[0];
+            k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+    };
+
+    //----------
+    // finalization
+
+    h1 ^= len;
+
+    h1 = fmix32(h1);
+
+    *(uint32_t*)out = h1;
+}
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x86_128 ( const void * key, const int len,
+                           uint32_t seed, void * out )
+{
+    const uint8_t * data = (const uint8_t*)key;
+    const int nblocks = len / 16;
+
+    uint32_t h1 = seed;
+    uint32_t h2 = seed;
+    uint32_t h3 = seed;
+    uint32_t h4 = seed;
+
+    const uint32_t c1 = 0x239b961b;
+    const uint32_t c2 = 0xab0e9789;
+    const uint32_t c3 = 0x38b34ae5;
+    const uint32_t c4 = 0xa1e38b93;
+
+    //----------
+    // body
+
+    const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
+
+    for(int i = -nblocks; i; i++)
+    {
+        uint32_t k1 = getblock32(blocks,i*4+0);
+        uint32_t k2 = getblock32(blocks,i*4+1);
+        uint32_t k3 = getblock32(blocks,i*4+2);
+        uint32_t k4 = getblock32(blocks,i*4+3);
+
+        k1 *= c1; k1  = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+
+        h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
+
+        k2 *= c2; k2  = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
+
+        h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
+
+        k3 *= c3; k3  = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
+
+        h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
+
+        k4 *= c4; k4  = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
+
+        h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
+    }
+
+    //----------
+    // tail
+
+    const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
+
+    uint32_t k1 = 0;
+    uint32_t k2 = 0;
+    uint32_t k3 = 0;
+    uint32_t k4 = 0;
+
+    switch(len & 15)
+    {
+        case 15: k4 ^= tail[14] << 16;
+        case 14: k4 ^= tail[13] << 8;
+        case 13: k4 ^= tail[12] << 0;
+            k4 *= c4; k4  = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
+
+        case 12: k3 ^= tail[11] << 24;
+        case 11: k3 ^= tail[10] << 16;
+        case 10: k3 ^= tail[ 9] << 8;
+        case  9: k3 ^= tail[ 8] << 0;
+            k3 *= c3; k3  = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
+
+        case  8: k2 ^= tail[ 7] << 24;
+        case  7: k2 ^= tail[ 6] << 16;
+        case  6: k2 ^= tail[ 5] << 8;
+        case  5: k2 ^= tail[ 4] << 0;
+            k2 *= c2; k2  = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
+
+        case  4: k1 ^= tail[ 3] << 24;
+        case  3: k1 ^= tail[ 2] << 16;
+        case  2: k1 ^= tail[ 1] << 8;
+        case  1: k1 ^= tail[ 0] << 0;
+            k1 *= c1; k1  = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+    };
+
+    //----------
+    // finalization
+
+    h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
+
+    h1 += h2; h1 += h3; h1 += h4;
+    h2 += h1; h3 += h1; h4 += h1;
+
+    h1 = fmix32(h1);
+    h2 = fmix32(h2);
+    h3 = fmix32(h3);
+    h4 = fmix32(h4);
+
+    h1 += h2; h1 += h3; h1 += h4;
+    h2 += h1; h3 += h1; h4 += h1;
+
+    ((uint32_t*)out)[0] = h1;
+    ((uint32_t*)out)[1] = h2;
+    ((uint32_t*)out)[2] = h3;
+    ((uint32_t*)out)[3] = h4;
+}
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x64_128 ( const void * key, const int len,
+                           const uint32_t seed, void * out )
+{
+    const uint8_t * data = (const uint8_t*)key;
+    const int nblocks = len / 16;
+
+    uint64_t h1 = seed;
+    uint64_t h2 = seed;
+
+    const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
+    const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
+
+    //----------
+    // body
+
+    const uint64_t * blocks = (const uint64_t *)(data);
+
+    for(int i = 0; i < nblocks; i++)
+    {
+        uint64_t k1 = getblock64(blocks,i*2+0);
+        uint64_t k2 = getblock64(blocks,i*2+1);
+
+        k1 *= c1; k1  = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
+
+        h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
+
+        k2 *= c2; k2  = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
+
+        h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
+    }
+
+    //----------
+    // tail
+
+    const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
+
+    uint64_t k1 = 0;
+    uint64_t k2 = 0;
+
+    switch(len & 15)
+    {
+        case 15: k2 ^= ((uint64_t)tail[14]) << 48;
+        case 14: k2 ^= ((uint64_t)tail[13]) << 40;
+        case 13: k2 ^= ((uint64_t)tail[12]) << 32;
+        case 12: k2 ^= ((uint64_t)tail[11]) << 24;
+        case 11: k2 ^= ((uint64_t)tail[10]) << 16;
+        case 10: k2 ^= ((uint64_t)tail[ 9]) << 8;
+        case  9: k2 ^= ((uint64_t)tail[ 8]) << 0;
+            k2 *= c2; k2  = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
+
+        case  8: k1 ^= ((uint64_t)tail[ 7]) << 56;
+        case  7: k1 ^= ((uint64_t)tail[ 6]) << 48;
+        case  6: k1 ^= ((uint64_t)tail[ 5]) << 40;
+        case  5: k1 ^= ((uint64_t)tail[ 4]) << 32;
+        case  4: k1 ^= ((uint64_t)tail[ 3]) << 24;
+        case  3: k1 ^= ((uint64_t)tail[ 2]) << 16;
+        case  2: k1 ^= ((uint64_t)tail[ 1]) << 8;
+        case  1: k1 ^= ((uint64_t)tail[ 0]) << 0;
+            k1 *= c1; k1  = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
+    };
+
+    //----------
+    // finalization
+
+    h1 ^= len; h2 ^= len;
+
+    h1 += h2;
+    h2 += h1;
+
+    h1 = fmix64(h1);
+    h2 = fmix64(h2);
+
+    h1 += h2;
+    h2 += h1;
+
+    ((uint64_t*)out)[0] = h1;
+    ((uint64_t*)out)[1] = h2;
+}
+
+//-----------------------------------------------------------------------------
+

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/util/murmur3.h
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/util/murmur3.h b/libraries/ostrich/backend/util/murmur3.h
new file mode 100644
index 0000000..69019a9
--- /dev/null
+++ b/libraries/ostrich/backend/util/murmur3.h
@@ -0,0 +1,18 @@
+//
+// Implementation of Murmur3 hashing using the C++ reference implementation.
+// See https://code.google.com/p/smhasher/wiki/MurmurHash
+//
+
+#ifndef MARMOTTA_MURMUR3_H
+#define MARMOTTA_MURMUR3_H
+
+#include <stdint.h>
+
+void MurmurHash3_x86_32  ( const void * key, int len, uint32_t seed, void * out );
+
+void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out );
+
+void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out );
+
+
+#endif //MARMOTTA_MURMUR3_H

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/util/split.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/util/split.cc b/libraries/ostrich/backend/util/split.cc
new file mode 100644
index 0000000..aa8ce7d
--- /dev/null
+++ b/libraries/ostrich/backend/util/split.cc
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "split.h"
+
+namespace marmotta {
+namespace util {
+
+std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
+    std::stringstream ss(s);
+    std::string item;
+    while (std::getline(ss, item, delim)) {
+        elems.push_back(item);
+    }
+    return elems;
+}
+
+
+std::vector<std::string> split(const std::string &s, char delim) {
+    std::vector<std::string> elems;
+    split(s, delim, elems);
+    return elems;
+}
+
+}
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/util/split.h
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/util/split.h b/libraries/ostrich/backend/util/split.h
new file mode 100644
index 0000000..49f796e
--- /dev/null
+++ b/libraries/ostrich/backend/util/split.h
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef MARMOTTA_SPLIT_H
+#define MARMOTTA_SPLIT_H
+
+#include <string>
+#include <sstream>
+#include <vector>
+
+namespace marmotta {
+namespace util {
+
+// Split a string at a certain delimiter and add the parts to the vector elems.
+std::vector<std::string> &split(const std::string &s, char delim,
+                                std::vector<std::string> &elems);
+
+// Split a string, returning a new vector containing the parts.
+std::vector<std::string> split(const std::string &s, char delim);
+
+}
+}
+
+#endif //MARMOTTA_SPLIT_H

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/client/pom.xml
----------------------------------------------------------------------
diff --git a/libraries/ostrich/client/pom.xml b/libraries/ostrich/client/pom.xml
new file mode 100644
index 0000000..b0a39b8
--- /dev/null
+++ b/libraries/ostrich/client/pom.xml
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<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>org.apache.marmotta</groupId>
+        <artifactId>ostrich-parent</artifactId>
+        <version>3.4.0-SNAPSHOT</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <artifactId>ostrich-client</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Ostrich Triplestore: Persistence Client</name>
+    <description>Sesame Sail wrapper around C++ Marmotta Services</description>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <releases>
+                <updatePolicy>never</updatePolicy>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <id>central</id>
+            <name>Central Repository</name>
+            <url>https://repo.maven.apache.org/maven2</url>
+        </pluginRepository>
+        <pluginRepository>
+            <id>protoc-plugin</id>
+            <url>https://dl.bintray.com/sergei-ivanov/maven/</url>
+        </pluginRepository>
+    </pluginRepositories>
+    <build>
+        <extensions>
+            <extension>
+                <groupId>kr.motd.maven</groupId>
+                <artifactId>os-maven-plugin</artifactId>
+                <version>1.3.0.Final</version>
+            </extension>
+        </extensions>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.google.protobuf.tools</groupId>
+                <artifactId>maven-protoc-plugin</artifactId>
+                <version>0.4.2</version>
+                <configuration>
+                    <!--
+                      The version of protoc must match protobuf-java. If you don't depend on
+                      protobuf-java directly, you will be transitively depending on the
+                      protobuf-java version that grpc depends on.
+                    -->
+                    <protocArtifact>com.google.protobuf:protoc:3.0.0-beta-1:exe:${os.detected.classifier}</protocArtifact>
+                    <pluginId>grpc-java</pluginId>
+                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:0.9.0:exe:${os.detected.classifier}</pluginArtifact>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>compile</goal>
+                            <goal>compile-custom</goal>
+                        </goals>
+                        <configuration>
+                            <protoSourceRoot>${basedir}/../backend/service</protoSourceRoot>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.marmotta</groupId>
+            <artifactId>ostrich-model</artifactId>
+            <version>3.4.0-SNAPSHOT</version>
+        </dependency>
+
+        <!-- Logging -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>log4j-over-slf4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jul-to-slf4j</artifactId>
+        </dependency>
+
+
+        <!-- gRPC -->
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-all</artifactId>
+            <version>0.10.0-SNAPSHOT</version>
+        </dependency>
+
+        <!-- Sesame dependencies -->
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-model</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-sail-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-sail-inferencer</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-queryalgebra-model</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-queryalgebra-evaluation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.marmotta</groupId>
+            <artifactId>marmotta-commons</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.marmotta</groupId>
+            <artifactId>marmotta-model-vocabs</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+
+        <!-- Testing -->
+        <dependency>
+            <artifactId>junit</artifactId>
+            <groupId>junit</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>org.openrdf.sesame</groupId>
+            <artifactId>sesame-rio-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-rio-rdfxml</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-repository-sail</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-store-testsuite</artifactId>
+            <scope>test</scope>
+        </dependency>
+        
+        <dependency>
+            <groupId>com.google.code.tempus-fugit</groupId>
+            <artifactId>tempus-fugit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+
+    </dependencies>
+    
+</project>

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/ClosableResponseStream.java
----------------------------------------------------------------------
diff --git a/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/ClosableResponseStream.java b/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/ClosableResponseStream.java
new file mode 100644
index 0000000..35d8ada
--- /dev/null
+++ b/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/ClosableResponseStream.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.ostrich.sail;
+
+import com.google.common.base.Preconditions;
+import info.aduna.iteration.CloseableIteration;
+import io.grpc.ClientCall;
+import io.grpc.Metadata;
+import io.grpc.MethodDescriptor;
+import io.grpc.Status;
+import io.grpc.stub.AbstractStub;
+import org.openrdf.sail.SailException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.NoSuchElementException;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+/**
+ * A modified version of ClientCalls.BlockingResponseStream that allows closing the stream early.
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class ClosableResponseStream<Svc extends AbstractStub<Svc>, ReqT, T> implements CloseableIteration<T, SailException> {
+
+    private static Logger log = LoggerFactory.getLogger(ClosableResponseStream.class);
+
+    // Due to flow control, only needs to hold up to 2 items: 1 for value, 1 for close.
+    private final BlockingQueue<Object> buffer = new ArrayBlockingQueue<Object>(2);
+    private final ClientCall.Listener<T> listener = new QueuingListener();
+    private final ClientCall<ReqT, T> call;
+    // Only accessed when iterating.
+    private Object last;
+
+    ClosableResponseStream(AbstractStub<Svc> stub, MethodDescriptor<ReqT, T> method, ReqT req) throws SailException {
+        call = stub.getChannel().newCall(method, stub.getCallOptions());
+
+        call.start(listener(), new Metadata());
+        call.request(1);
+        try {
+            call.sendMessage(req);
+            call.halfClose();
+        } catch (Throwable t) {
+            call.cancel();
+            throw new SailException(t);
+        }
+    }
+
+    ClientCall.Listener<T> listener() {
+        return listener;
+    }
+
+    /**
+     * Closes this iteration, freeing any resources that it is holding. If the
+     * iteration has already been closed then invoking this method has no effect.
+     */
+    @Override
+    public void close() throws SailException {
+        call.cancel();
+    }
+
+    /**
+     * Returns <tt>true</tt> if the iteration has more elements. (In other
+     * words, returns <tt>true</tt> if {@link #next} would return an element
+     * rather than throwing a <tt>NoSuchElementException</tt>.)
+     *
+     * @return <tt>true</tt> if the iteration has more elements.
+     * @throws SailException
+     */
+    @Override
+    public boolean hasNext() throws SailException {
+        try {
+            // Will block here indefinitely waiting for content. RPC timeouts defend against permanent
+            // hangs here as the call will become closed.
+            last = (last == null) ? buffer.take() : last;
+        } catch (InterruptedException ie) {
+            Thread.interrupted();
+            throw new SailException(ie);
+        }
+        if (last instanceof Status) {
+            throw new SailException(((Status) last).asRuntimeException());
+        }
+        return last != this;
+    }
+
+    /**
+     * Returns the next element in the iteration.
+     *
+     * @return the next element in the iteration.
+     * @throws NoSuchElementException if the iteration has no more elements or if it has been closed.
+     */
+    @Override
+    public T next() throws SailException {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        try {
+            call.request(1);
+            @SuppressWarnings("unchecked")
+            T tmp = (T) last;
+            return tmp;
+        } finally {
+            last = null;
+        }
+    }
+
+    /**
+     * Removes from the underlying collection the last element returned by the
+     * iteration (optional operation). This method can be called only once per
+     * call to next.
+     *
+     * @throws UnsupportedOperationException if the remove operation is not supported by this Iteration.
+     * @throws IllegalStateException         If the Iteration has been closed, or if <tt>next()</tt> has not
+     *                                       yet been called, or <tt>remove()</tt> has already been called
+     *                                       after the last call to <tt>next()</tt>.
+     */
+    @Override
+    public void remove() throws SailException {
+
+    }
+
+    private class QueuingListener extends ClientCall.Listener<T> {
+        private boolean done = false;
+
+        @Override
+        public void onHeaders(Metadata headers) {
+        }
+
+        @Override
+        public void onMessage(T value) {
+            Preconditions.checkState(!done, "ClientCall already closed");
+            buffer.add(value);
+        }
+
+        @Override
+        public void onClose(Status status, Metadata trailers) {
+            Preconditions.checkState(!done, "ClientCall already closed");
+            if (status.isOk()) {
+                buffer.add(ClosableResponseStream.this);
+            } else {
+                buffer.add(status);
+            }
+            done = true;
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichSail.java
----------------------------------------------------------------------
diff --git a/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichSail.java b/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichSail.java
new file mode 100644
index 0000000..84d8c2e
--- /dev/null
+++ b/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichSail.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.ostrich.sail;
+
+import org.openrdf.model.ValueFactory;
+import org.openrdf.sail.NotifyingSailConnection;
+import org.openrdf.sail.Sail;
+import org.openrdf.sail.SailException;
+import org.openrdf.sail.helpers.NotifyingSailBase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Add file description here!
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class OstrichSail extends NotifyingSailBase implements Sail {
+    private static Logger log = LoggerFactory.getLogger(OstrichSail.class);
+
+    private OstrichValueFactory valueFactory = new OstrichValueFactory();
+
+    private String host;
+    private int port;
+
+    public OstrichSail(String host, int port) {
+        this.host = host;
+        this.port = port;
+    }
+
+    /**
+     * Do store-specific operations to initialize the store. The default
+     * implementation of this method does nothing.
+     */
+    @Override
+    protected void initializeInternal() throws SailException {
+        log.info("Initialising CMarmotta Sail (host={}, port={})", host, port);
+    }
+
+    @Override
+    protected NotifyingSailConnection getConnectionInternal() throws SailException {
+        return new OstrichSailConnection(this, host, port);
+    }
+
+    /**
+     * Do store-specific operations to ensure proper shutdown of the store.
+     */
+    @Override
+    protected void shutDownInternal() throws SailException {
+
+    }
+
+    /**
+     * Checks whether this Sail object is writable, i.e. if the data contained in
+     * this Sail object can be changed.
+     */
+    @Override
+    public boolean isWritable() throws SailException {
+        return true;
+    }
+
+    /**
+     * Gets a ValueFactory object that can be used to create URI-, blank node-,
+     * literal- and statement objects.
+     *
+     * @return a ValueFactory object for this Sail object.
+     */
+    @Override
+    public ValueFactory getValueFactory() {
+        return valueFactory;
+    }
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichSailConnection.java
----------------------------------------------------------------------
diff --git a/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichSailConnection.java b/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichSailConnection.java
new file mode 100644
index 0000000..bb80665
--- /dev/null
+++ b/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichSailConnection.java
@@ -0,0 +1,529 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.ostrich.sail;
+
+import com.google.common.util.concurrent.SettableFuture;
+import com.google.protobuf.Empty;
+import com.google.protobuf.Int64Value;
+import info.aduna.iteration.*;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.Status;
+import io.grpc.stub.StreamObserver;
+import org.apache.marmotta.ostrich.client.proto.Sail;
+import org.apache.marmotta.ostrich.client.proto.SailServiceGrpc;
+import org.apache.marmotta.ostrich.client.proto.Sparql;
+import org.apache.marmotta.ostrich.client.proto.SparqlServiceGrpc;
+import org.apache.marmotta.ostrich.model.*;
+import org.apache.marmotta.ostrich.model.proto.Model;
+import org.openrdf.model.*;
+import org.openrdf.query.BindingSet;
+import org.openrdf.query.Dataset;
+import org.openrdf.query.QueryEvaluationException;
+import org.openrdf.query.QueryInterruptedException;
+import org.openrdf.query.algebra.QueryRoot;
+import org.openrdf.query.algebra.StatementPattern;
+import org.openrdf.query.algebra.TupleExpr;
+import org.openrdf.query.algebra.Var;
+import org.openrdf.query.algebra.evaluation.EvaluationStrategy;
+import org.openrdf.query.algebra.evaluation.TripleSource;
+import org.openrdf.query.algebra.evaluation.impl.*;
+import org.openrdf.query.impl.EmptyBindingSet;
+import org.openrdf.query.impl.MapBindingSet;
+import org.openrdf.sail.SailException;
+import org.openrdf.sail.helpers.NotifyingSailConnectionBase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.channels.ClosedByInterruptException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Add file description here!
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class OstrichSailConnection extends NotifyingSailConnectionBase {
+
+    private static Logger log = LoggerFactory.getLogger(OstrichSailConnection.class);
+
+    private final ManagedChannel channel;
+    private final SailServiceGrpc.SailServiceBlockingStub stub;
+    private final SailServiceGrpc.SailServiceStub sailServiceStub;
+    private final SparqlServiceGrpc.SparqlServiceStub sparqlServiceStub;
+
+    private SettableFuture<Void> finishFuture;
+    private StreamObserver<Sail.UpdateResponse> updateResponseObserver;
+    private StreamObserver<Sail.UpdateRequest> updateRequestObserver;
+
+    public OstrichSailConnection(OstrichSail parent, String host, int port) {
+        super(parent);
+        channel = ManagedChannelBuilder.forAddress(host, port)
+                .usePlaintext(true)
+                .build();
+        stub = SailServiceGrpc.newBlockingStub(channel);
+        sailServiceStub = SailServiceGrpc.newStub(channel);
+        sparqlServiceStub = SparqlServiceGrpc.newStub(channel);
+
+        updateResponseObserver = new StreamObserver<Sail.UpdateResponse>() {
+            @Override
+            public void onNext(Sail.UpdateResponse updateResponse) {
+                log.info(
+                        "Committed transaction (added statements={}, removed statements={}, added namespaces={}, removed namespaces={})",
+                        updateResponse.getAddedStatements(), updateResponse.getRemovedStatements(),
+                        updateResponse.getAddedNamespaces(), updateResponse.getRemovedNamespaces());
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+                finishFuture.setException(throwable);
+            }
+
+            @Override
+            public void onCompleted() {
+                finishFuture.set(null);
+            }
+        };
+    }
+
+    @Override
+    protected void addStatementInternal(Resource subj, URI pred, Value obj, Resource... contexts) throws SailException {
+        log.info("Adding statements.");
+        ensureTransaction();
+
+        if (contexts.length > 0) {
+            for (Resource ctx : contexts) {
+                ProtoStatement stmt = new ProtoStatement(subj, pred, obj, ctx);
+                Sail.UpdateRequest u = Sail.UpdateRequest.newBuilder().setStmtAdded(stmt.getMessage()).build();
+                updateRequestObserver.onNext(u);
+            }
+        } else {
+            ProtoStatement stmt = new ProtoStatement(subj, pred, obj, null);
+            Sail.UpdateRequest u = Sail.UpdateRequest.newBuilder().setStmtAdded(stmt.getMessage()).build();
+            updateRequestObserver.onNext(u);
+        }
+    }
+
+    @Override
+    protected void closeInternal() throws SailException {
+        log.info("Closing connection.");
+        commit();
+
+        try {
+            channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            new SailException("Shutdown interrupted", e);
+        }
+    }
+
+    @Override
+    protected CloseableIteration<? extends BindingSet, QueryEvaluationException> evaluateInternal(TupleExpr tupleExpr, Dataset dataset, BindingSet bindings, boolean includeInferred) throws SailException {
+        // Clone the tuple expression to allow for more aggressive optimizations
+        tupleExpr = tupleExpr.clone();
+
+        if (!(tupleExpr instanceof QueryRoot)) {
+            // Add a dummy root node to the tuple expressions to allow the
+            // optimizers to modify the actual root node
+            tupleExpr = new QueryRoot(tupleExpr);
+        }
+
+        try {
+            CMarmottaTripleSource tripleSource = new CMarmottaTripleSource(this,includeInferred);
+            EvaluationStrategy strategy = new EvaluationStrategyImpl(tripleSource, dataset);
+
+            new BindingAssigner().optimize(tupleExpr, dataset, bindings);
+            new ConstantOptimizer(strategy).optimize(tupleExpr, dataset, bindings);
+            new CompareOptimizer().optimize(tupleExpr, dataset, bindings);
+            new ConjunctiveConstraintSplitter().optimize(tupleExpr, dataset, bindings);
+            new DisjunctiveConstraintOptimizer().optimize(tupleExpr, dataset, bindings);
+            new SameTermFilterOptimizer().optimize(tupleExpr, dataset, bindings);
+            new QueryModelNormalizer().optimize(tupleExpr, dataset, bindings);
+            new QueryJoinOptimizer(new InternalEvaluationStatistics()).optimize(tupleExpr, dataset, bindings);
+            new IterativeEvaluationOptimizer().optimize(tupleExpr, dataset, bindings);
+            new FilterOptimizer().optimize(tupleExpr, dataset, bindings);
+            new OrderLimitOptimizer().optimize(tupleExpr, dataset, bindings);
+
+            return strategy.evaluate(tupleExpr, EmptyBindingSet.getInstance());
+
+        } catch (QueryEvaluationException e) {
+            throw new SailException(e);
+        }
+    }
+
+
+    /**
+     * Send a SPARQL query to a backend supporting direct SPARQL evaluation.
+     *
+     * @param query
+     * @return
+     * @throws SailException
+     */
+    public CloseableIteration<? extends BindingSet, QueryEvaluationException> directTupleQuery(String query) throws SailException {
+        log.info("Committing transaction before querying ...");
+        commitForQuery();
+
+        Sparql.SparqlRequest request = Sparql.SparqlRequest.newBuilder().setQuery(query).build();
+
+        return new ExceptionConvertingIteration<BindingSet, QueryEvaluationException>(
+                new ConvertingIteration<Sparql.SparqlResponse, BindingSet, SailException>(
+                        new ClosableResponseStream<>(sparqlServiceStub, SparqlServiceGrpc.METHOD_TUPLE_QUERY, request)) {
+                    @Override
+                    protected BindingSet convert(Sparql.SparqlResponse sourceObject) throws SailException {
+                        MapBindingSet result = new MapBindingSet();
+                        for (Sparql.SparqlResponse.Binding b :sourceObject.getBindingList()) {
+
+                            Value v = null;
+                            switch (b.getValue().getValuesCase()) {
+                                case RESOURCE:
+                                    switch(b.getValue().getResource().getResourcesCase()) {
+                                        case URI:
+                                            v = new ProtoURI(b.getValue().getResource().getUri());
+                                        case BNODE:
+                                            v = new ProtoBNode(b.getValue().getResource().getBnode());
+                                    }
+                                case LITERAL:
+                                    switch(b.getValue().getLiteral().getLiteralsCase()) {
+                                        case STRINGLITERAL:
+                                            v = new ProtoStringLiteral(b.getValue().getLiteral().getStringliteral());
+                                        case DATALITERAL:
+                                            v = new ProtoDatatypeLiteral(b.getValue().getLiteral().getDataliteral());
+                                    }
+                            }
+                            result.addBinding(b.getVariable(), v);
+                        }
+                        return result;
+                    }
+                }) {
+            @Override
+            protected QueryEvaluationException convert(Exception e) {
+                return new QueryEvaluationException(e);
+            }
+        };
+    }
+
+    @Override
+    protected CloseableIteration<? extends Resource, SailException> getContextIDsInternal() throws SailException {
+        log.info("Committing transaction before querying ...");
+        commitForQuery();
+
+        return wrapResourceIterator(stub.getContexts(Empty.getDefaultInstance()));
+    }
+
+    @Override
+    protected CloseableIteration<? extends Statement, SailException> getStatementsInternal(Resource subj, URI pred, Value obj, boolean includeInferred, Resource... contexts) throws SailException {
+        log.info("Committing transaction before querying ...");
+        commitForQuery();
+
+        if (contexts.length > 0) {
+            ArrayList<CloseableIteration<? extends Statement, SailException>> iterators = new ArrayList<>(contexts.length);
+            for (Resource ctx : contexts) {
+                final ProtoStatement pattern = new ProtoStatement(subj, pred, obj, ctx);
+                iterators.add(new DelayedIteration<Statement, SailException>() {
+                    @Override
+                    protected Iteration<? extends Statement, ? extends SailException> createIteration() throws SailException {
+                        return wrapStatementIterator(new ClosableResponseStream<>(sailServiceStub, SailServiceGrpc.METHOD_GET_STATEMENTS, pattern.getMessage()));
+                    }
+                });
+            }
+            return new UnionIteration<>(iterators);
+        }
+
+        ProtoStatement pattern = new ProtoStatement(subj, pred, obj, null);
+
+        return wrapStatementIterator(new ClosableResponseStream<>(sailServiceStub, SailServiceGrpc.METHOD_GET_STATEMENTS, pattern.getMessage()));
+    }
+
+    @Override
+    protected long sizeInternal(Resource... contexts) throws SailException {
+        log.info("Committing transaction before querying ...");
+        commitForQuery();
+
+        Sail.ContextRequest.Builder builder = Sail.ContextRequest.newBuilder();
+        for (Resource ctx : contexts) {
+            if (ctx instanceof URI) {
+                builder.addContextBuilder().getUriBuilder().setUri(ctx.stringValue());
+            } else if(ctx instanceof BNode) {
+                builder.addContextBuilder().getBnodeBuilder().setId(ctx.stringValue());
+            }
+        }
+
+        Int64Value v = stub.size(builder.build());
+        return v.getValue();
+    }
+
+    @Override
+    protected void startTransactionInternal() throws SailException {
+    }
+
+    protected void ensureTransaction() {
+        if (updateRequestObserver == null) {
+            finishFuture = SettableFuture.create();
+            updateRequestObserver = sailServiceStub.update(updateResponseObserver);
+        }
+    }
+
+    protected void commitForQuery() throws SailException {
+        if (isActive()) {
+            commitInternal();
+            startTransactionInternal();
+        }
+    }
+
+    @Override
+    protected void commitInternal() throws SailException {
+        if (updateRequestObserver != null) {
+            log.info("Start transaction commit");
+            updateRequestObserver.onCompleted();
+            try {
+                finishFuture.get();
+            } catch (InterruptedException | ExecutionException e) {
+                throw new SailException("Error while writing to server", e);
+            }
+            updateRequestObserver = null;
+            log.info("Transaction committed.");
+        }
+    }
+
+    @Override
+    protected void rollbackInternal() throws SailException {
+        updateRequestObserver.onError(new Exception("transaction rollback"));
+        updateRequestObserver = null;
+    }
+
+    @Override
+    protected void removeStatementsInternal(Resource subj, URI pred, Value obj, Resource... contexts) throws SailException {
+        log.info("Removing statements.");
+        commitForQuery();
+        ensureTransaction();
+
+        if (contexts.length > 0) {
+            for (Resource ctx : contexts) {
+                ProtoStatement stmt = new ProtoStatement(subj, pred, obj, ctx);
+                Sail.UpdateRequest u = Sail.UpdateRequest.newBuilder().setStmtRemoved(stmt.getMessage()).build();
+                updateRequestObserver.onNext(u);
+            }
+        } else {
+            ProtoStatement stmt = new ProtoStatement(subj, pred, obj, null);
+            Sail.UpdateRequest u = Sail.UpdateRequest.newBuilder().setStmtRemoved(stmt.getMessage()).build();
+            updateRequestObserver.onNext(u);
+        }
+    }
+
+    @Override
+    protected void clearInternal(Resource... contexts) throws SailException {
+        log.info("Clearing statements.");
+        commitForQuery();
+        ensureTransaction();
+
+        if (contexts.length > 0) {
+            for (Resource ctx : contexts) {
+                ProtoStatement stmt = new ProtoStatement(null, null, null, ctx);
+                Sail.UpdateRequest u = Sail.UpdateRequest.newBuilder().setStmtRemoved(stmt.getMessage()).build();
+                updateRequestObserver.onNext(u);
+            }
+        } else {
+            ProtoStatement stmt = new ProtoStatement(null, null, null, null);
+            Sail.UpdateRequest u = Sail.UpdateRequest.newBuilder().setStmtRemoved(stmt.getMessage()).build();
+            updateRequestObserver.onNext(u);
+        }
+    }
+
+    @Override
+    protected CloseableIteration<? extends Namespace, SailException> getNamespacesInternal() throws SailException {
+        log.info("Getting namespaces.");
+        commitForQuery();
+
+        Empty pattern = Empty.getDefaultInstance();
+        return wrapNamespaceIterator(stub.getNamespaces(pattern));
+    }
+
+    @Override
+    protected String getNamespaceInternal(String prefix) throws SailException {
+        log.info("Committing transaction before querying ...");
+        commitForQuery();
+
+        Model.Namespace pattern = Model.Namespace.newBuilder().setPrefix(prefix).build();
+        try {
+            return stub.getNamespace(pattern).getUri();
+        } catch (io.grpc.StatusRuntimeException ex) {
+            if (ex.getStatus().getCode() == Status.Code.NOT_FOUND) {
+                return null;
+            }
+            throw new SailException(ex);
+        }
+    }
+
+    @Override
+    protected void setNamespaceInternal(String prefix, String name) throws SailException {
+        log.info("Setting namespace {} = {}.", prefix, name);
+        ensureTransaction();
+
+        ProtoNamespace ns = new ProtoNamespace(prefix, name);
+        Sail.UpdateRequest u = Sail.UpdateRequest.newBuilder().setNsAdded(ns.getMessage()).build();
+        updateRequestObserver.onNext(u);
+
+    }
+
+    @Override
+    protected void removeNamespaceInternal(String prefix) throws SailException {
+        log.info("Removing namespace {}.", prefix);
+        commitForQuery();
+        ensureTransaction();
+
+        Sail.UpdateRequest.Builder builder = Sail.UpdateRequest.newBuilder();
+        builder.getNsRemovedBuilder().setPrefix(prefix);
+        updateRequestObserver.onNext(builder.build());
+    }
+
+    @Override
+    protected void clearNamespacesInternal() throws SailException {
+        log.info("Clearing namespaces.");
+        commitForQuery();
+        ensureTransaction();
+
+        Sail.UpdateRequest.Builder builder = Sail.UpdateRequest.newBuilder();
+        builder.setNsRemoved(Model.Namespace.getDefaultInstance());
+        updateRequestObserver.onNext(builder.build());
+    }
+
+    private static CloseableIteration<Statement, SailException> wrapStatementIterator(CloseableIteration<Model.Statement, SailException> it) {
+        return new ConvertingIteration<Model.Statement, Statement, SailException>(it) {
+            @Override
+            protected Statement convert(Model.Statement sourceObject) throws SailException {
+                return new ProtoStatement(sourceObject);
+            }
+        };
+    }
+
+
+    private static CloseableIteration<Statement, SailException> wrapStatementIterator(Iterator<Model.Statement> it) {
+        return new ConvertingIteration<Model.Statement, Statement, SailException>(
+                new IteratorIteration<Model.Statement, SailException>(it)) {
+            @Override
+            protected Statement convert(Model.Statement sourceObject) throws SailException {
+                return new ProtoStatement(sourceObject);
+            }
+        };
+    }
+
+    private static CloseableIteration<Namespace, SailException> wrapNamespaceIterator(Iterator<Model.Namespace> it) {
+        return new ConvertingIteration<Model.Namespace, Namespace, SailException>(
+                new IteratorIteration<Model.Namespace, SailException>(it)) {
+            @Override
+            protected Namespace convert(Model.Namespace sourceObject) throws SailException {
+                return new ProtoNamespace(sourceObject);
+            }
+        };
+    }
+
+    private static CloseableIteration<Resource, SailException> wrapResourceIterator(Iterator<Model.Resource> it) {
+        return new ConvertingIteration<Model.Resource, Resource, SailException>(
+                new IteratorIteration<Model.Resource, SailException>(it)) {
+            @Override
+            protected Resource convert(Model.Resource sourceObject) throws SailException {
+                switch (sourceObject.getResourcesCase()) {
+                    case URI:
+                        return new ProtoURI(sourceObject.getUri());
+                    case BNODE:
+                        return new ProtoBNode(sourceObject.getBnode());
+                }
+                return null;
+            }
+        };
+    }
+
+    protected static class InternalEvaluationStatistics extends EvaluationStatistics {
+
+        public InternalEvaluationStatistics() {
+        }
+
+        @Override
+        protected CardinalityCalculator createCardinalityCalculator() {
+            return new InternalCardinalityCalculator();
+        }
+
+        protected class InternalCardinalityCalculator extends CardinalityCalculator {
+
+            @Override
+            protected double getCardinality(StatementPattern sp) {
+                return super.getCardinality(sp);
+            }
+
+            protected Value getConstantValue(Var var) {
+                return (var != null) ? var.getValue() : null;
+            }
+        }
+    }
+
+    /**
+     * A helper class using a CMarmottaSailConnection as triple source for SPARQL queries.
+     */
+    private static class CMarmottaTripleSource implements TripleSource {
+
+        private boolean inferred;
+        private OstrichSailConnection connection;
+
+        private CMarmottaTripleSource(OstrichSailConnection connection, boolean inferred) {
+            this.inferred   = inferred;
+            this.connection = connection;
+        }
+
+        @Override
+        public CloseableIteration<? extends Statement, QueryEvaluationException> getStatements(Resource subj, URI pred, Value obj, Resource... contexts) throws QueryEvaluationException {
+            try {
+                return new ExceptionConvertingIteration<Statement, QueryEvaluationException>(
+                        connection.getStatements(subj, pred, obj, inferred, contexts)
+                ) {
+                    @Override
+                    protected QueryEvaluationException convert(Exception e) {
+                        if (e instanceof ClosedByInterruptException) {
+                            return new QueryInterruptedException(e);
+                        }
+                        else if (e instanceof IOException) {
+                            return new QueryEvaluationException(e);
+                        }
+                        else if (e instanceof SailException) {
+                            return new QueryEvaluationException(e);
+                        }
+                        else if (e instanceof RuntimeException) {
+                            throw (RuntimeException)e;
+                        }
+                        else if (e == null) {
+                            throw new IllegalArgumentException("e must not be null");
+                        }
+                        else {
+                            throw new IllegalArgumentException("Unexpected exception type: " + e.getClass(),e);
+                        }
+                    }
+                };
+            } catch (SailException ex) {
+                throw new QueryEvaluationException(ex);
+            }
+        }
+
+        @Override
+        public ValueFactory getValueFactory() {
+            return new OstrichValueFactory();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichValueFactory.java
----------------------------------------------------------------------
diff --git a/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichValueFactory.java b/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichValueFactory.java
new file mode 100644
index 0000000..054492d
--- /dev/null
+++ b/libraries/ostrich/client/src/main/java/org/apache/marmotta/ostrich/sail/OstrichValueFactory.java
@@ -0,0 +1,260 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.ostrich.sail;
+
+import org.apache.marmotta.commons.sesame.model.LiteralCommons;
+import org.apache.marmotta.commons.util.DateUtils;
+import org.apache.marmotta.ostrich.model.*;
+import org.openrdf.model.*;
+
+import javax.xml.datatype.XMLGregorianCalendar;
+import java.util.Date;
+import java.util.Random;
+
+/**
+ * Add file description here!
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class OstrichValueFactory implements ValueFactory {
+
+    private Random anonIdGenerator;
+
+    public OstrichValueFactory() {
+        this.anonIdGenerator = new Random();
+    }
+
+    /**
+     * Creates a new bNode.
+     *
+     * @return An object representing the bNode.
+     */
+    @Override
+    public BNode createBNode() {
+        return new ProtoBNode(Long.toHexString(System.currentTimeMillis())+Integer.toHexString(anonIdGenerator.nextInt(1000)));
+    }
+
+    /**
+     * Creates a new URI from the supplied string-representation.
+     *
+     * @param uri A string-representation of a URI.
+     * @return An object representing the URI.
+     */
+    @Override
+    public URI createURI(String uri) {
+        return new ProtoURI(uri);
+    }
+
+    /**
+     * Creates a new URI from the supplied namespace and local name. Calling this
+     * method is funtionally equivalent to calling {@link #createURI(String)
+     * createURI(namespace+localName)}, but allows the ValueFactory to reuse
+     * supplied namespace and local name strings whenever possible. Note that the
+     * values returned by {@link URI#getNamespace()} and
+     * {@link URI#getLocalName()} are not necessarily the same as the values that
+     * are supplied to this method.
+     *
+     * @param namespace The URI's namespace.
+     * @param localName The URI's local name.
+     * @throws IllegalArgumentException If the supplied namespace and localname do not resolve to a legal
+     *                                  (absolute) URI.
+     */
+    @Override
+    public URI createURI(String namespace, String localName) {
+        return new ProtoURI(namespace+localName);
+    }
+
+    /**
+     * Creates a new blank node with the given node identifier.
+     *
+     * @param nodeID The blank node identifier.
+     * @return An object representing the blank node.
+     */
+    @Override
+    public BNode createBNode(String nodeID) {
+        return new ProtoBNode(nodeID);
+    }
+
+    /**
+     * Creates a new literal with the supplied label.
+     *
+     * @param label The literal's label.
+     */
+    @Override
+    public Literal createLiteral(String label) {
+        return new ProtoStringLiteral(label);
+    }
+
+    /**
+     * Creates a new literal with the supplied label and language attribute.
+     *
+     * @param label    The literal's label.
+     * @param language The literal's language attribute, or <tt>null</tt> if the literal
+     */
+    @Override
+    public Literal createLiteral(String label, String language) {
+        return new ProtoStringLiteral(label, language);
+    }
+
+    /**
+     * Creates a new literal with the supplied label and datatype.
+     *
+     * @param label    The literal's label.
+     * @param datatype The literal's datatype, or <tt>null</tt> if the literal doesn't
+     */
+    @Override
+    public Literal createLiteral(String label, URI datatype) {
+        return new ProtoDatatypeLiteral(label, datatype);
+    }
+
+    /**
+     * Creates a new <tt>xsd:boolean</tt>-typed literal representing the
+     * specified value.
+     *
+     * @param value The value for the literal.
+     * @return An <tt>xsd:boolean</tt>-typed literal for the specified value.
+     */
+    @Override
+    public Literal createLiteral(boolean value) {
+        return new ProtoDatatypeLiteral(Boolean.toString(value), LiteralCommons.getXSDType(Boolean.class));
+    }
+
+    /**
+     * Creates a new <tt>xsd:byte</tt>-typed literal representing the specified
+     * value.
+     *
+     * @param value The value for the literal.
+     * @return An <tt>xsd:byte</tt>-typed literal for the specified value.
+     */
+    @Override
+    public Literal createLiteral(byte value) {
+        return new ProtoDatatypeLiteral(Byte.toString(value), LiteralCommons.getXSDType(Byte.class));
+    }
+
+    /**
+     * Creates a new <tt>xsd:short</tt>-typed literal representing the specified
+     * value.
+     *
+     * @param value The value for the literal.
+     * @return An <tt>xsd:short</tt>-typed literal for the specified value.
+     */
+    @Override
+    public Literal createLiteral(short value) {
+        return new ProtoDatatypeLiteral(Short.toString(value), LiteralCommons.getXSDType(Short.class));
+    }
+
+    /**
+     * Creates a new <tt>xsd:int</tt>-typed literal representing the specified
+     * value.
+     *
+     * @param value The value for the literal.
+     * @return An <tt>xsd:int</tt>-typed literal for the specified value.
+     */
+    @Override
+    public Literal createLiteral(int value) {
+        return new ProtoDatatypeLiteral(Integer.toString(value), LiteralCommons.getXSDType(Integer.class));
+    }
+
+    /**
+     * Creates a new <tt>xsd:long</tt>-typed literal representing the specified
+     * value.
+     *
+     * @param value The value for the literal.
+     * @return An <tt>xsd:long</tt>-typed literal for the specified value.
+     */
+    @Override
+    public Literal createLiteral(long value) {
+        return new ProtoDatatypeLiteral(Long.toString(value), LiteralCommons.getXSDType(Long.class));
+    }
+
+    /**
+     * Creates a new <tt>xsd:float</tt>-typed literal representing the specified
+     * value.
+     *
+     * @param value The value for the literal.
+     * @return An <tt>xsd:float</tt>-typed literal for the specified value.
+     */
+    @Override
+    public Literal createLiteral(float value) {
+        return new ProtoDatatypeLiteral(Float.toString(value), LiteralCommons.getXSDType(Float.class));
+    }
+
+    /**
+     * Creates a new <tt>xsd:double</tt>-typed literal representing the specified
+     * value.
+     *
+     * @param value The value for the literal.
+     * @return An <tt>xsd:double</tt>-typed literal for the specified value.
+     */
+    @Override
+    public Literal createLiteral(double value) {
+        return new ProtoDatatypeLiteral(Double.toString(value), LiteralCommons.getXSDType(Double.class));
+    }
+
+    /**
+     * Creates a new literal representing the specified calendar that is typed
+     * using the appropriate XML Schema date/time datatype.
+     *
+     * @param calendar The value for the literal.
+     * @return An typed literal for the specified calendar.
+     */
+    @Override
+    public Literal createLiteral(XMLGregorianCalendar calendar) {
+        return new ProtoDatatypeLiteral(calendar.toXMLFormat(), LiteralCommons.getXSDType(Date.class));
+    }
+
+    /**
+     * Creates a new literal representing the specified date that is typed using
+     * the appropriate XML Schema date/time datatype.
+     *
+     * @param date
+     * @since 2.7.0
+     */
+    @Override
+    public Literal createLiteral(Date date) {
+        return new ProtoDatatypeLiteral(DateUtils.getXMLCalendar(date).toXMLFormat(), LiteralCommons.getXSDType(Date.class));
+    }
+
+    /**
+     * Creates a new statement with the supplied subject, predicate and object.
+     *
+     * @param subject   The statement's subject.
+     * @param predicate The statement's predicate.
+     * @param object    The statement's object.
+     * @return The created statement.
+     */
+    @Override
+    public Statement createStatement(Resource subject, URI predicate, Value object) {
+        return new ProtoStatement(subject, predicate, object, null);
+    }
+
+    /**
+     * Creates a new statement with the supplied subject, predicate and object
+     * and associated context.
+     *
+     * @param subject   The statement's subject.
+     * @param predicate The statement's predicate.
+     * @param object    The statement's object.
+     * @param context   The statement's context.
+     * @return The created statement.
+     */
+    @Override
+    public Statement createStatement(Resource subject, URI predicate, Value object, Resource context) {
+        return new ProtoStatement(subject, predicate, object, context);
+    }
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/client/src/test/java/org/apache/marmotta/ostrich/sail/test/CMarmottaSailTest.java
----------------------------------------------------------------------
diff --git a/libraries/ostrich/client/src/test/java/org/apache/marmotta/ostrich/sail/test/CMarmottaSailTest.java b/libraries/ostrich/client/src/test/java/org/apache/marmotta/ostrich/sail/test/CMarmottaSailTest.java
new file mode 100644
index 0000000..f60cc4e
--- /dev/null
+++ b/libraries/ostrich/client/src/test/java/org/apache/marmotta/ostrich/sail/test/CMarmottaSailTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.ostrich.sail.test;
+
+import org.apache.marmotta.ostrich.sail.OstrichSail;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.openrdf.sail.RDFStoreTest;
+import org.openrdf.sail.Sail;
+import org.openrdf.sail.SailConnection;
+import org.openrdf.sail.SailException;
+
+/**
+ * Add file description here!
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class CMarmottaSailTest extends RDFStoreTest {
+
+    private static Sail repository;
+
+    @BeforeClass
+    public static void setupClass() throws SailException {
+        repository = new OstrichSail("localhost", 10000) {
+            @Override
+            public void shutDown() throws SailException {
+                // Clear repository on shutdown, but otherwise reuse it.
+                SailConnection con = getConnection();
+                con.begin();
+                try {
+                    con.clear();
+                    con.clearNamespaces();
+                } finally {
+                    con.commit();
+                    con.close();
+                }
+            }
+        };
+        repository.initialize();
+    }
+
+    @AfterClass
+    public static void teardownClass() throws SailException {
+        repository.shutDown();
+    }
+
+
+    /**
+     * Gets an instance of the Sail that should be tested. The returned
+     * repository should already have been initialized.
+     *
+     * @return an initialized Sail.
+     * @throws SailException If the initialization of the repository failed.
+     */
+    @Override
+    protected Sail createSail() throws SailException {
+        return repository;
+    }
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/client/src/test/java/org/apache/marmotta/ostrich/sail/test/TestSailConnection.java
----------------------------------------------------------------------
diff --git a/libraries/ostrich/client/src/test/java/org/apache/marmotta/ostrich/sail/test/TestSailConnection.java b/libraries/ostrich/client/src/test/java/org/apache/marmotta/ostrich/sail/test/TestSailConnection.java
new file mode 100644
index 0000000..b904b3c
--- /dev/null
+++ b/libraries/ostrich/client/src/test/java/org/apache/marmotta/ostrich/sail/test/TestSailConnection.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.ostrich.sail.test;
+
+import org.apache.marmotta.ostrich.sail.OstrichSail;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openrdf.model.Statement;
+import org.openrdf.model.URI;
+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 org.openrdf.rio.RDFHandlerException;
+import org.openrdf.rio.RDFWriter;
+import org.openrdf.rio.Rio;
+
+/**
+ * Add file description here!
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class TestSailConnection {
+
+    private static Repository repository;
+
+    @BeforeClass
+    public static void setup() throws RepositoryException {
+        repository = new SailRepository(new OstrichSail("localhost", 10000));
+        repository.initialize();
+    }
+
+    @AfterClass
+    public static void teardown() throws RepositoryException {
+        repository.shutDown();
+    }
+
+    @Test
+    public void testQuery() throws RepositoryException, RDFHandlerException {
+        RDFWriter writer = Rio.createWriter(RDFFormat.TURTLE, System.out);
+        URI s = repository.getValueFactory().createURI("http://umbel.org/umbel/rc/Zyban");
+
+        RepositoryConnection con = repository.getConnection();
+        try {
+            con.begin();
+            writer.startRDF();
+
+            RepositoryResult<Statement> it = con.getStatements(s, null, null, true);
+            while (it.hasNext()) {
+                writer.handleStatement(it.next());
+            }
+
+            writer.endRDF();
+
+            con.commit();
+        } catch(RepositoryException ex) {
+            con.rollback();
+        } finally {
+            con.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/model/pom.xml
----------------------------------------------------------------------
diff --git a/libraries/ostrich/model/pom.xml b/libraries/ostrich/model/pom.xml
new file mode 100644
index 0000000..893346c
--- /dev/null
+++ b/libraries/ostrich/model/pom.xml
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<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>org.apache.marmotta</groupId>
+        <artifactId>cmarmotta-parent</artifactId>
+        <version>3.4.0-SNAPSHOT</version>
+        <relativePath>../</relativePath>
+    </parent>
+
+    <artifactId>ostrich-model</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Ostrich Triplestore: Model</name>
+    <description>Sesame Model wrapper around C++ Marmotta Proto Model</description>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <releases>
+                <updatePolicy>never</updatePolicy>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <id>central</id>
+            <name>Central Repository</name>
+            <url>https://repo.maven.apache.org/maven2</url>
+        </pluginRepository>
+        <pluginRepository>
+            <id>protoc-plugin</id>
+            <url>https://dl.bintray.com/sergei-ivanov/maven/</url>
+        </pluginRepository>
+    </pluginRepositories>
+    <build>
+        <extensions>
+            <extension>
+                <groupId>kr.motd.maven</groupId>
+                <artifactId>os-maven-plugin</artifactId>
+                <version>1.3.0.Final</version>
+            </extension>
+        </extensions>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.google.protobuf.tools</groupId>
+                <artifactId>maven-protoc-plugin</artifactId>
+                <version>0.4.2</version>
+                <configuration>
+                    <!--
+                      The version of protoc must match protobuf-java. If you don't depend on
+                      protobuf-java directly, you will be transitively depending on the
+                      protobuf-java version that grpc depends on.
+                    -->
+                    <protocArtifact>com.google.protobuf:protoc:3.0.0-beta-1:exe:${os.detected.classifier}</protocArtifact>
+                    <protoSourceRoot>${basedir}/../backend/model</protoSourceRoot>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>compile</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <!-- Logging -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>log4j-over-slf4j</artifactId>
+        </dependency>
+
+
+        <!-- Protobuf -->
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java</artifactId>
+            <version>3.0.0-beta-1</version>
+        </dependency>
+
+        <!-- Sesame dependencies -->
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-model</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-sail-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-sail-inferencer</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-queryalgebra-model</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-queryalgebra-evaluation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.marmotta</groupId>
+            <artifactId>marmotta-commons</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.marmotta</groupId>
+            <artifactId>marmotta-model-vocabs</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+
+        <!-- Testing -->
+        <dependency>
+            <artifactId>junit</artifactId>
+            <groupId>junit</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>org.openrdf.sesame</groupId>
+            <artifactId>sesame-rio-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-rio-rdfxml</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-repository-sail</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openrdf.sesame</groupId>
+            <artifactId>sesame-store-testsuite</artifactId>
+            <scope>test</scope>
+        </dependency>
+        
+        <dependency>
+            <groupId>com.google.code.tempus-fugit</groupId>
+            <artifactId>tempus-fugit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+
+    </dependencies>
+    
+</project>

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/model/src/main/java/org/apache/marmotta/ostrich/model/ProtoBNode.java
----------------------------------------------------------------------
diff --git a/libraries/ostrich/model/src/main/java/org/apache/marmotta/ostrich/model/ProtoBNode.java b/libraries/ostrich/model/src/main/java/org/apache/marmotta/ostrich/model/ProtoBNode.java
new file mode 100644
index 0000000..3b6a750
--- /dev/null
+++ b/libraries/ostrich/model/src/main/java/org/apache/marmotta/ostrich/model/ProtoBNode.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.marmotta.ostrich.model;
+
+import org.apache.marmotta.ostrich.model.proto.Model;
+import org.openrdf.model.BNode;
+import org.openrdf.model.Literal;
+import org.openrdf.model.URI;
+
+/**
+ * An implementation of a Sesame BNode backed by a protocol buffer.
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+public class ProtoBNode implements BNode {
+
+    private Model.BNode message;
+
+    public ProtoBNode(String id) {
+        message = Model.BNode.newBuilder().setId(id).build();
+    }
+
+    public ProtoBNode(Model.BNode message) {
+        this.message = message;
+    }
+
+    public Model.BNode getMessage() {
+        return message;
+    }
+
+    /**
+     * retrieves this blank node's identifier.
+     *
+     * @return A blank node identifier.
+     */
+    @Override
+    public String getID() {
+        return message.getId();
+    }
+
+    /**
+     * Returns the String-value of a <tt>Value</tt> object. This returns either
+     * a {@link Literal}'s label, a {@link URI}'s URI or a {@link BNode}'s ID.
+     */
+    @Override
+    public String stringValue() {
+        return message.getId();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if(o instanceof BNode) {
+            return this.stringValue().equals(((BNode)o).stringValue());
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return stringValue().hashCode();
+    }
+}