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