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 <[email protected]> +#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 ([email protected]) + */ +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 ([email protected]) + */ +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 ([email protected]) + */ +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 ([email protected]) + */ +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 ([email protected]) + */ +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 ([email protected]) + */ +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 ([email protected]) + */ +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(); + } +}
