move experimental C++ LevelDB backend into Apache Marmotta main, and named the new module "ostrich" as an analogy to "kiwi"
Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/0ff22a0c Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/0ff22a0c Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/0ff22a0c Branch: refs/heads/develop Commit: 0ff22a0c3e086efdae4f25aa11aa27ff987c99bc Parents: ed387b9 Author: Sebastian Schaffert <[email protected]> Authored: Sat Dec 12 17:07:51 2015 +0100 Committer: Sebastian Schaffert <[email protected]> Committed: Sat Dec 12 17:07:51 2015 +0100 ---------------------------------------------------------------------- launchers/marmotta-webapp/pom.xml | 22 + libraries/ostrich/backend/CMakeLists.txt | 31 + libraries/ostrich/backend/README.md | 87 + libraries/ostrich/backend/client/CMakeLists.txt | 8 + libraries/ostrich/backend/client/client.cc | 275 + .../ostrich/backend/cmake/FindGFlags.cmake | 48 + libraries/ostrich/backend/cmake/FindGLog.cmake | 18 + libraries/ostrich/backend/cmake/FindGRPC.cmake | 67 + .../ostrich/backend/cmake/FindLevelDB.cmake | 18 + .../ostrich/backend/cmake/FindRAPTOR.cmake | 103 + .../ostrich/backend/cmake/FindRasqal.cmake | 99 + .../ostrich/backend/cmake/FindTcmalloc.cmake | 39 + libraries/ostrich/backend/model/CMakeLists.txt | 6 + libraries/ostrich/backend/model/model.proto | 77 + libraries/ostrich/backend/model/rdf_model.cc | 348 + libraries/ostrich/backend/model/rdf_model.h | 709 + .../ostrich/backend/model/rdf_operators.cc | 61 + libraries/ostrich/backend/model/rdf_operators.h | 240 + libraries/ostrich/backend/parser/CMakeLists.txt | 4 + libraries/ostrich/backend/parser/rdf_parser.cc | 175 + libraries/ostrich/backend/parser/rdf_parser.h | 87 + .../ostrich/backend/persistence/CMakeLists.txt | 10 + .../backend/persistence/leveldb_persistence.cc | 685 + .../backend/persistence/leveldb_persistence.h | 185 + .../backend/persistence/leveldb_server.cc | 73 + .../backend/persistence/leveldb_service.cc | 254 + .../backend/persistence/leveldb_service.h | 120 + .../backend/persistence/leveldb_sparql.cc | 114 + .../backend/persistence/leveldb_sparql.h | 52 + .../ostrich/backend/serializer/CMakeLists.txt | 4 + .../ostrich/backend/serializer/serializer.cc | 49 + .../ostrich/backend/serializer/serializer.h | 54 + .../backend/serializer/serializer_base.cc | 64 + .../backend/serializer/serializer_base.h | 104 + .../backend/serializer/serializer_proto.cc | 54 + .../backend/serializer/serializer_proto.h | 50 + .../backend/serializer/serializer_raptor.cc | 266 + .../backend/serializer/serializer_raptor.h | 55 + .../ostrich/backend/service/CMakeLists.txt | 9 + libraries/ostrich/backend/service/sail.proto | 102 + libraries/ostrich/backend/service/sparql.proto | 45 + .../ostrich/backend/sharding/CMakeLists.txt | 10 + libraries/ostrich/backend/sharding/server.cc | 66 + libraries/ostrich/backend/sharding/sharding.cc | 335 + libraries/ostrich/backend/sharding/sharding.h | 174 + libraries/ostrich/backend/sparql/CMakeLists.txt | 7 + .../ostrich/backend/sparql/rasqal_adapter.cc | 299 + .../ostrich/backend/sparql/rasqal_adapter.h | 107 + .../ostrich/backend/sparql/rasqal_model.cc | 193 + libraries/ostrich/backend/sparql/rasqal_model.h | 74 + libraries/ostrich/backend/test/CMakeLists.txt | 12 + libraries/ostrich/backend/test/SparqlTest.cc | 266 + libraries/ostrich/backend/test/StatementTest.cc | 135 + libraries/ostrich/backend/test/gtest-all.cc | 9592 ++++++++ libraries/ostrich/backend/test/gtest.h | 20061 +++++++++++++++++ libraries/ostrich/backend/test/main.cc | 11 + libraries/ostrich/backend/util/CMakeLists.txt | 3 + libraries/ostrich/backend/util/iterator.h | 131 + libraries/ostrich/backend/util/murmur3.cc | 313 + libraries/ostrich/backend/util/murmur3.h | 18 + libraries/ostrich/backend/util/split.cc | 40 + libraries/ostrich/backend/util/split.h | 38 + libraries/ostrich/client/pom.xml | 234 + .../ostrich/sail/ClosableResponseStream.java | 163 + .../marmotta/ostrich/sail/OstrichSail.java | 87 + .../ostrich/sail/OstrichSailConnection.java | 529 + .../ostrich/sail/OstrichValueFactory.java | 260 + .../ostrich/sail/test/CMarmottaSailTest.java | 74 + .../ostrich/sail/test/TestSailConnection.java | 80 + libraries/ostrich/model/pom.xml | 219 + .../marmotta/ostrich/model/ProtoBNode.java | 79 + .../ostrich/model/ProtoDatatypeLiteral.java | 106 + .../ostrich/model/ProtoLiteralBase.java | 187 + .../marmotta/ostrich/model/ProtoNamespace.java | 86 + .../marmotta/ostrich/model/ProtoStatement.java | 221 + .../ostrich/model/ProtoStringLiteral.java | 101 + .../apache/marmotta/ostrich/model/ProtoURI.java | 113 + .../ostrich/model/test/StatementTest.java | 68 + .../marmotta/ostrich/model/test/URITest.java | 57 + .../model/src/test/resources/logback.xml | 28 + libraries/ostrich/pom.xml | 50 + libraries/pom.xml | 9 + .../backends/marmotta-backend-ostrich/pom.xml | 175 + .../backend/ostrich/OstrichProvider.java | 94 + .../src/main/resources/META-INF/beans.xml | 28 + .../main/resources/config-defaults.properties | 24 + .../resources/config-descriptions.properties | 26 + .../src/main/resources/kiwi-module.properties | 38 + .../src/main/resources/web/admin/about.html | 36 + .../main/resources/web/admin/configuration.html | 52 + platform/backends/pom.xml | 6 + 91 files changed, 39986 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/launchers/marmotta-webapp/pom.xml ---------------------------------------------------------------------- diff --git a/launchers/marmotta-webapp/pom.xml b/launchers/marmotta-webapp/pom.xml index c9d0cd6..e02e44a 100644 --- a/launchers/marmotta-webapp/pom.xml +++ b/launchers/marmotta-webapp/pom.xml @@ -415,6 +415,28 @@ </dependencies> </profile> + <profile> + <id>ostrich</id> + <activation> + <property> + <name>marmotta.backend</name> + <value>ostrich</value> + </property> + </activation> + <dependencies> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>marmotta-backend-ostrich</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>marmotta-ldcache-file</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </profile> + <!-- Caching Backends for KiWi --> http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/CMakeLists.txt b/libraries/ostrich/backend/CMakeLists.txt new file mode 100644 index 0000000..d8232b7 --- /dev/null +++ b/libraries/ostrich/backend/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.0) +project(Marmotta) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g") +set(PROTOBUF_IMPORT_DIRS "${CMAKE_SOURCE_DIR}/model") +set(USE_TCMALLOC TRUE) + +find_package (Threads REQUIRED) +find_package (RAPTOR REQUIRED) +find_package (Rasqal REQUIRED) +find_package (GFlags REQUIRED) +find_package (Protobuf REQUIRED) +find_package (GRPC REQUIRED) +find_package (LevelDB REQUIRED) +find_package (GLog REQUIRED) +find_package (Tcmalloc) + +add_definitions(-DNDEBUG) + +add_subdirectory(util) +add_subdirectory(model) +add_subdirectory(sparql) +add_subdirectory(service) +add_subdirectory(parser) +add_subdirectory(serializer) +add_subdirectory(persistence) +add_subdirectory(sharding) +add_subdirectory(client) +add_subdirectory(test) + http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/README.md ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/README.md b/libraries/ostrich/backend/README.md new file mode 100644 index 0000000..047a968 --- /dev/null +++ b/libraries/ostrich/backend/README.md @@ -0,0 +1,87 @@ +# Apache Marmotta LevelDB/C++ Backend + +This repository implements an experimental high-performance backend for Apache Marmotta +using LevelDB as storage and gRPC as communication channel between the Java frontend +and the C++ backend. + +If it proves to be useful, the repository will eventually be merged into the main +development branch of Apache Marmotta + +## Dependencies (C++) + +To compile the C++ backend, you need to have the following dependencies installed: + + * libraptor (used for parsing/serializing in C++) + * librasqal (used for server-side SPARQL evaluation) + * libglog (logging) + * libgflags (command line arguments) + * libleveldb (database backend) + * libgrpc (gRPC runtime) + * libprotobuf (messaging, data model) + +With the exception of libgrpc and libprotobuf, all libraries are available in Linux repositories. +Debian: + + apt-get install libraptor2-dev librasqal3-dev libgoogle-glog-dev libgflags-dev libleveldb-dev + +The backend uses the new Proto 3 format and the gRPC SDK. These need to be installed separately, +please follow the instructions at [https://github.com/grpc/grpc](https://github.com/grpc/grpc/blob/master/INSTALL). + + +## Compilation (C++) + +The backend uses cmake to compile the modules. Create a new directory `build`, run cmake, and run make: + + mkdir build && cd build + cmake .. + make + +## Compilation (Java) + +The frontend is compiled with Maven and depends on many Apache Marmotta modules to work. Build it with + + cd java + mvn clean install + +## Running C++ Backend + +Start the backend from the cmake build directory as follows: + + ./service/marmotta_persistence -db /path/to/database -port 10000 + +The binary accepts many different options. Please see `--help` for details. + +## Running Sharding + +The repository contains an experimental implementation of a sharding server that proxies and +distributes requests based on a hash calculation over statements. In heavy load environments, +this is potentially much faster than running a single persistence backend. The setup requires +several persistence backends (shards) and a sharding proxy. To experiment, you can start these +on the same machine as follows: + + ./service/marmotta_persistence -db /path/to/shard1 -port 10001 + ./service/marmotta_persistence -db /path/to/shard2 -port 10002 + ./sharding/marmotta_sharding --port 10000 --backends localhost:10001,localhost:10002 + +You can then access the sharding server through Marmotta like the persistence server. Running all instances +on the same host is only useful for testing. In production environments, you would of course run all three +(or more) instances on different hosts. Note that the number and order of backends should not change once +data has been imported, because otherwise the hashing algorithm will do the wrong thing. + +## Running Apache Marmotta + +A preconfigured version of Apache Marmotta is available in `java/webapp`. It connects to +`localhost:10000` by default and can be started with: + + mvn tomcat7:run + +Afterwards, point your browser to `localhost:8080`. + +## Command Line Client + +A C++ command line client is available for very fast bulk imports and simple queries. To import +a large turtle file, run: + + ./client/marmotta_client --format=turtle import file.ttl + +The client connects by default to `localhost:10000` (change with `--host` and `--port` flags). http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/client/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/client/CMakeLists.txt b/libraries/ostrich/backend/client/CMakeLists.txt new file mode 100644 index 0000000..88ad11a --- /dev/null +++ b/libraries/ostrich/backend/client/CMakeLists.txt @@ -0,0 +1,8 @@ +include_directories(.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/../model) + +add_executable(marmotta_client client.cc) +target_link_libraries(marmotta_client + marmotta_model marmotta_service marmotta_parser marmotta_serializer + ${GFLAGS_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} ${PROTOBUF_LIBRARIES} ${GRPC_LIBRARIES}) + http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/client/client.cc ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/client/client.cc b/libraries/ostrich/backend/client/client.cc new file mode 100644 index 0000000..16c9022 --- /dev/null +++ b/libraries/ostrich/backend/client/client.cc @@ -0,0 +1,275 @@ +/* + * 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 <fstream> + +#include <grpc/grpc.h> +#include <grpc++/channel.h> +#include <grpc++/client_context.h> +#include <grpc++/create_channel.h> +#include <grpc++/security/credentials.h> +#include <grpc++/support/sync_stream.h> + +#include <google/protobuf/text_format.h> +#include <google/protobuf/empty.pb.h> +#include <google/protobuf/wrappers.pb.h> + +#include <gflags/gflags.h> + +#include "model/rdf_model.h" +#include "parser/rdf_parser.h" +#include "serializer/serializer.h" +#include "service/sail.pb.h" +#include "service/sail.grpc.pb.h" +#include "service/sparql.pb.h" +#include "service/sparql.grpc.pb.h" + + +using grpc::Channel; +using grpc::ClientContext; +using grpc::ClientReader; +using grpc::ClientReaderWriter; +using grpc::ClientWriter; +using grpc::Status; +using google::protobuf::TextFormat; + +using namespace marmotta; +namespace svc = marmotta::service::proto; +namespace spq = marmotta::sparql::proto; + +// A STL iterator wrapper around a client reader. +template <class T, class Proto> +class ClientReaderIterator : public util::CloseableIterator<T> { + public: + ClientReaderIterator() : finished(true) { } + + ClientReaderIterator(ClientReader<Proto>* r) : reader(r), finished(false) { + // Immediately move to first element. + operator++(); + } + + ClientReaderIterator& operator++() override { + if (!finished) { + finished = !reader->Read(&buffer); + current = T(buffer); + if (finished) { + reader->Finish(); + } + } + return *this; + } + + T& operator*() override { + return current; + } + + T* operator->() override { + return ¤t; + } + + bool hasNext() override { + return !finished; + } + + private: + ClientReader<Proto>* reader; + Proto buffer; + T current; + bool finished; +}; + +typedef ClientReaderIterator<rdf::Statement, rdf::proto::Statement> StatementReader; +typedef ClientReaderIterator<rdf::Namespace, rdf::proto::Namespace> NamespaceReader; + +class MarmottaClient { + public: + MarmottaClient(const std::string& server) + : stub_(svc::SailService::NewStub( + grpc::CreateChannel(server, grpc::InsecureChannelCredentials()))), + sparql_(spq::SparqlService::NewStub( + grpc::CreateChannel(server, grpc::InsecureChannelCredentials()))){} + + void importDataset(std::istream& in, parser::Format format) { + ClientContext nscontext, stmtcontext; + + google::protobuf::Int64Value nsstats; + google::protobuf::Int64Value stmtstats; + + std::unique_ptr<ClientWriter<rdf::proto::Namespace> > nswriter( + stub_->AddNamespaces(&nscontext, &nsstats)); + std::unique_ptr<ClientWriter<rdf::proto::Statement> > stmtwriter( + stub_->AddStatements(&stmtcontext, &stmtstats)); + + parser::Parser p("http://www.example.com", format); + p.setStatementHandler([&stmtwriter](const rdf::Statement& stmt) { + stmtwriter->Write(stmt.getMessage()); + }); + p.setNamespaceHandler([&nswriter](const rdf::Namespace& ns) { + nswriter->Write(ns.getMessage()); + }); + p.parse(in); + + stmtwriter->WritesDone(); + nswriter->WritesDone(); + + Status nsst = nswriter->Finish(); + Status stmtst = stmtwriter->Finish(); + + if (nsst.ok() && stmtst.ok()) { + std::cout << "Added " << nsstats.value() << " namespaces and " + << stmtstats.value() << " statements" << std::endl; + } else { + std::cout << "Failed writing data to server: " << stmtst.error_message() << std::endl; + } + } + + + void patternQuery(const rdf::Statement &pattern, std::ostream &out, serializer::Format format) { + ClientContext context; + + std::unique_ptr<ClientReader<rdf::proto::Statement> > reader( + stub_->GetStatements(&context, pattern.getMessage())); + + serializer::Serializer serializer("http://www.example.com", format); + serializer.serialize(StatementReader(reader.get()), out); + } + + void patternDelete(const rdf::Statement &pattern) { + ClientContext context; + google::protobuf::Int64Value result; + + Status status = stub_->RemoveStatements(&context, pattern.getMessage(), &result); + if (status.ok()) { + std::cout << "Deleted " << result.value() << " statements." << std::endl; + } else { + std::cerr << "Failed deleting statements: " << status.error_message() << std::endl; + } + } + + void tupleQuery(const std::string& query, std::ostream &out) { + ClientContext context; + spq::SparqlRequest request; + request.set_query(query); + + std::unique_ptr<ClientReader<spq::SparqlResponse>> reader( + sparql_->TupleQuery(&context, request)); + + auto out_ = new google::protobuf::io::OstreamOutputStream(&out); + spq::SparqlResponse result; + while (reader->Read(&result)) { + TextFormat::Print(result, dynamic_cast<google::protobuf::io::ZeroCopyOutputStream*>(out_)); + } + delete out_; + } + + void listNamespaces(std::ostream &out) { + ClientContext context; + + google::protobuf::Empty pattern; + + std::unique_ptr<ClientReader<rdf::proto::Namespace> > reader( + stub_->GetNamespaces(&context, pattern)); + + NamespaceReader it(reader.get()); + for (; it.hasNext(); ++it) { + out << (*it).getPrefix() << " = " << (*it).getUri() << std::endl; + } + } + + int64_t size(const svc::ContextRequest& r) { + ClientContext context; + google::protobuf::Int64Value result; + + Status status = stub_->Size(&context, r, &result); + if (status.ok()) { + return result.value(); + } else { + return -1; + } + } + private: + std::unique_ptr<svc::SailService::Stub> stub_; + std::unique_ptr<spq::SparqlService::Stub> sparql_; +}; + + +DEFINE_string(format, "rdfxml", "RDF format to use for parsing/serializing."); +DEFINE_string(host, "localhost", "Address/name of server to access."); +DEFINE_string(port, "10000", "Port of server to access."); +DEFINE_string(output, "", "File to write result to."); + +int main(int argc, char** argv) { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + google::ParseCommandLineFlags(&argc, &argv, true); + + MarmottaClient client(FLAGS_host + ":" + FLAGS_port); + + if ("import" == std::string(argv[1])) { + std::ifstream in(argv[2]); + std::cout << "Importing " << argv[2] << " ... " << std::endl; + client.importDataset(in, parser::FormatFromString(FLAGS_format)); + std::cout << "Finished!" << std::endl; + } + + if ("select" == std::string(argv[1])) { + rdf::proto::Statement query; + TextFormat::ParseFromString(argv[2], &query); + if (FLAGS_output != "") { + std::ofstream out(FLAGS_output); + client.patternQuery(rdf::Statement(query), out, serializer::FormatFromString(FLAGS_format)); + } else { + client.patternQuery(rdf::Statement(query), std::cout, serializer::FormatFromString(FLAGS_format)); + } + } + + if ("sparql" == std::string(argv[1])) { + std::string query = argv[2]; + if (FLAGS_output != "") { + std::ofstream out(FLAGS_output); + client.tupleQuery(query, out); + } else { + client.tupleQuery(query, std::cout); + } + } + + if ("delete" == std::string(argv[1])) { + rdf::proto::Statement query; + TextFormat::ParseFromString(argv[2], &query); + client.patternDelete(rdf::Statement(query)); + } + + if ("size" == std::string(argv[1])) { + svc::ContextRequest query; + TextFormat::ParseFromString(argv[2], &query); + std::cout << "Size: " << client.size(query) << std::endl; + } + + + if ("namespaces" == std::string(argv[1])) { + if (FLAGS_output != "") { + std::ofstream out(FLAGS_output); + client.listNamespaces(out); + } else { + client.listNamespaces(std::cout); + } + } + + google::protobuf::ShutdownProtobufLibrary(); + + return 0; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/cmake/FindGFlags.cmake ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/cmake/FindGFlags.cmake b/libraries/ostrich/backend/cmake/FindGFlags.cmake new file mode 100644 index 0000000..2d44a8c --- /dev/null +++ b/libraries/ostrich/backend/cmake/FindGFlags.cmake @@ -0,0 +1,48 @@ +# - Try to find GFLAGS +# +# The following variables are optionally searched for defaults +# GFLAGS_ROOT_DIR: Base directory where all GFLAGS components are found +# +# The following are set after configuration is done: +# GFLAGS_FOUND +# GFLAGS_INCLUDE_DIRS +# GFLAGS_LIBRARIES +# GFLAGS_LIBRARYRARY_DIRS + +include(FindPackageHandleStandardArgs) + +set(GFLAGS_ROOT_DIR "" CACHE PATH "Folder contains Gflags") + +# We are testing only a couple of files in the include directories +if(WIN32) + find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h + PATHS ${GFLAGS_ROOT_DIR}/src/windows) +else() + find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h + PATHS ${GFLAGS_ROOT_DIR}) +endif() + +if(MSVC) + find_library(GFLAGS_LIBRARY_RELEASE + NAMES libgflags + PATHS ${GFLAGS_ROOT_DIR} + PATH_SUFFIXES Release) + + find_library(GFLAGS_LIBRARY_DEBUG + NAMES libgflags-debug + PATHS ${GFLAGS_ROOT_DIR} + PATH_SUFFIXES Debug) + + set(GFLAGS_LIBRARY optimized ${GFLAGS_LIBRARY_RELEASE} debug ${GFLAGS_LIBRARY_DEBUG}) +else() + find_library(GFLAGS_LIBRARY gflags) +endif() + +find_package_handle_standard_args(GFLAGS DEFAULT_MSG + GFLAGS_INCLUDE_DIR GFLAGS_LIBRARY) + + +if(GFLAGS_FOUND) + set(GFLAGS_INCLUDE_DIRS ${GFLAGS_INCLUDE_DIR}) + set(GFLAGS_LIBRARIES ${GFLAGS_LIBRARY}) +endif() \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/cmake/FindGLog.cmake ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/cmake/FindGLog.cmake b/libraries/ostrich/backend/cmake/FindGLog.cmake new file mode 100644 index 0000000..3d09d06 --- /dev/null +++ b/libraries/ostrich/backend/cmake/FindGLog.cmake @@ -0,0 +1,18 @@ +# Find Google Logging + +find_path(GLOG_INCLUDE_PATH NAMES glog/logging.h) +find_library(GLOG_LIBRARY NAMES glog) + +if(GLOG_INCLUDE_PATH AND GLOG_LIBRARY) + set(GLOG_FOUND TRUE) +endif(GLOG_INCLUDE_PATH AND GLOG_LIBRARY) + +if(GLOG_FOUND) + if(NOT GLOG_FIND_QUIETLY) + message(STATUS "Found GLOG: ${GLOG_LIBRARY}; includes - ${GLOG_INCLUDE_PATH}") + endif(NOT GLOG_FIND_QUIETLY) +else(GLOG_FOUND) + if(GLOG_FIND_REQUIRED) + message(FATAL_ERROR "Could not find GLOG library.") + endif(GLOG_FIND_REQUIRED) +endif(GLOG_FOUND) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/cmake/FindGRPC.cmake ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/cmake/FindGRPC.cmake b/libraries/ostrich/backend/cmake/FindGRPC.cmake new file mode 100644 index 0000000..d5aa718 --- /dev/null +++ b/libraries/ostrich/backend/cmake/FindGRPC.cmake @@ -0,0 +1,67 @@ +find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin) # Get full path to plugin + +find_library(GRPC_LIBRARY NAMES grpc) +find_library(GRPCPP_LIBRARY NAMES grpc++) +find_library(GPR_LIBRARY NAMES gpr) +set(GRPC_LIBRARIES ${GRPCPP_LIBRARY} ${GRPC_LIBRARY} ${GPR_LIBRARY}) +if(GRPC_LIBRARIES) + message(STATUS "Found GRPC: ${GRPC_LIBRARIES}; plugin - ${GRPC_CPP_PLUGIN}") +endif() + + +function(PROTOBUF_GENERATE_GRPC_CPP SRCS HDRS) + if(NOT ARGN) + message(SEND_ERROR "Error: PROTOBUF_GENERATE_GRPC_CPP() called without any proto files") + return() + endif() + + if(PROTOBUF_GENERATE_CPP_APPEND_PATH) # This variable is common for all types of output. + # Create an include path for each file specified + foreach(FIL ${ARGN}) + get_filename_component(ABS_FIL ${FIL} ABSOLUTE) + get_filename_component(ABS_PATH ${ABS_FIL} PATH) + list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) + if(${_contains_already} EQUAL -1) + list(APPEND _protobuf_include_path -I ${ABS_PATH}) + endif() + endforeach() + else() + set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + + if(DEFINED PROTOBUF_IMPORT_DIRS) + foreach(DIR ${PROTOBUF_IMPORT_DIRS}) + get_filename_component(ABS_PATH ${DIR} ABSOLUTE) + list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) + if(${_contains_already} EQUAL -1) + list(APPEND _protobuf_include_path -I ${ABS_PATH}) + endif() + endforeach() + endif() + + set(${SRCS}) + set(${HDRS}) + foreach(FIL ${ARGN}) + get_filename_component(ABS_FIL ${FIL} ABSOLUTE) + get_filename_component(FIL_WE ${FIL} NAME_WE) + + list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.cc") + list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.h") + + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.cc" + "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.h" + COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} + ARGS --grpc_out=${CMAKE_CURRENT_BINARY_DIR} + --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} + ${_protobuf_include_path} ${ABS_FIL} + DEPENDS ${ABS_FIL} ${PROTOBUF_PROTOC_EXECUTABLE} + COMMENT "Running gRPC C++ protocol buffer compiler on ${FIL}" + VERBATIM) + endforeach() + + set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE) + set(${SRCS} ${${SRCS}} PARENT_SCOPE) + set(${HDRS} ${${HDRS}} PARENT_SCOPE) +endfunction() + http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/cmake/FindLevelDB.cmake ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/cmake/FindLevelDB.cmake b/libraries/ostrich/backend/cmake/FindLevelDB.cmake new file mode 100644 index 0000000..db99bf9 --- /dev/null +++ b/libraries/ostrich/backend/cmake/FindLevelDB.cmake @@ -0,0 +1,18 @@ +# Find libleveldb.a - key/value storage system + +find_path(LevelDB_INCLUDE_PATH NAMES leveldb/db.h) +find_library(LevelDB_LIBRARY NAMES leveldb) + +if(LevelDB_INCLUDE_PATH AND LevelDB_LIBRARY) + set(LevelDB_FOUND TRUE) +endif(LevelDB_INCLUDE_PATH AND LevelDB_LIBRARY) + +if(LevelDB_FOUND) + if(NOT LevelDB_FIND_QUIETLY) + message(STATUS "Found LevelDB: ${LevelDB_LIBRARY}; includes - ${LevelDB_INCLUDE_PATH}") + endif(NOT LevelDB_FIND_QUIETLY) +else(LevelDB_FOUND) + if(LevelDB_FIND_REQUIRED) + message(FATAL_ERROR "Could not find leveldb library.") + endif(LevelDB_FIND_REQUIRED) +endif(LevelDB_FOUND) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/cmake/FindRAPTOR.cmake ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/cmake/FindRAPTOR.cmake b/libraries/ostrich/backend/cmake/FindRAPTOR.cmake new file mode 100644 index 0000000..ef12f1b --- /dev/null +++ b/libraries/ostrich/backend/cmake/FindRAPTOR.cmake @@ -0,0 +1,103 @@ +# - Try to find the Raptor RDF parsing library (http://librdf.org/raptor/) +# Once done this will define +# +# RAPTOR_FOUND - system has Raptor +# RAPTOR_LIBRARIES - Link these to use Raptor +# RAPTOR_INCLUDE_DIR - Include directory for using Raptor +# RAPTOR_DEFINITIONS - Compiler switches required for using Raptor +# +# Capabilities +# RAPTOR_HAVE_TRIG - Set if raptor has TRIG + +# (c) 2007-2011 Sebastian Trueg <[email protected]> +# (c) 2011 Artem Serebriyskiy <[email protected]> +# (c) 2011 Michael Jansen <[email protected]> +# +# Based on FindFontconfig Copyright (c) 2006,2007 Laurent Montel, <[email protected]> +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +MACRO ( FIND_RAPTOR ) + +ENDMACRO () + + + +# Check if we have cached results in case the last round was successful. +if ( NOT( RAPTOR_INCLUDE_DIR AND RAPTOR_LIBRARIES ) OR NOT RAPTOR_FOUND ) + + set( RAPTOR_LDFLAGS ) + + find_package(PkgConfig) + + if ( NOT WIN32 ) + pkg_check_modules(PC_RAPTOR QUIET raptor) + if ( PC_RAPTOR_FOUND ) + set(RAPTOR_DEFINITIONS ${PC_RAPTOR_CFLAGS_OTHER}) + set(RAPTOR_VERSION ${PC_RAPTOR_VERSION} CACHE STRING "Raptor Version found" ) + string( REGEX REPLACE "^.*-lraptor;" "" RAPTOR_LDFLAGS "${PC_RAPTOR_STATIC_LDFLAGS}") + endif () + endif () + + find_path(RAPTOR_INCLUDE_DIR + NAMES raptor2.h raptor2/raptor2.h raptor.h raptor/raptor.h + PATHS $ENV{RAPTOR_DIR}/include + $ENV{RAPTOR_DIR} + ~/Library/Frameworks + /Library/Frameworks + /usr/local/include + /usr/include/ + /sw/include # Fink + /opt/local/include # MacPorts + /opt/csw/include # Blastwave + /usr/local/opt/raptor/include # brew + /opt/include + /usr/freeware/include + + ) + + + find_library(RAPTOR_LIBRARY + NAMES raptor raptor2 + PATHS $ENV{RAPTOR_DIR}/lib + $ENV{RAPTOR_DIR}/lib-dbg + $ENV{RAPTOR_DIR} + ~/Library/Frameworks + /Library/Frameworks + /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 + /sw/lib # Fink + /opt/local/lib # MacPorts + /opt/csw/lib # Blastwave + /usr/local/opt/raptor/lib # brew + /opt/lib + /usr/freeware/lib64 + ) + + if ( RAPTOR_LDFLAGS ) + set( RAPTOR_LIBRARY ${RAPTOR_LIBRARY} ${RAPTOR_LDFLAGS} ) + endif () + + mark_as_advanced(RAPTOR_INCLUDE_DIR RAPTOR_LIBRARY) + +endif () # Check for cached values + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args( + Raptor + VERSION_VAR RAPTOR_VERSION + REQUIRED_VARS RAPTOR_LIBRARY RAPTOR_INCLUDE_DIR) + +mark_as_advanced(RAPTOR_VERSION) + +if (NOT RAPTOR_FOUND AND Raptor_FIND_VERSION_MAJOR EQUAL "2" AND NOT Raptor_FIND_QUIET ) + pkg_check_modules(PC_RAPTOR QUIET raptor) + if (PC_RAPTOR_FOUND) + message( STATUS "You have raptor1 version ${PC_RAPTOR_VERSION} installed. Please update." ) + endif () +endif () \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/cmake/FindRasqal.cmake ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/cmake/FindRasqal.cmake b/libraries/ostrich/backend/cmake/FindRasqal.cmake new file mode 100644 index 0000000..e80ab34 --- /dev/null +++ b/libraries/ostrich/backend/cmake/FindRasqal.cmake @@ -0,0 +1,99 @@ +# - Try to find the Rasqal rdf query library (http://librdf.org/rasqal/) +# Once done this will define +# +# RASQAL_FOUND - system has Rasqal +# RASQAL_LIBRARIES - Link these to use RASQAL +# RASQAL_INCLUDE_DIR - The include directory for using rasqal +# RASQAL_DEFINITIONS - Compiler switches required for using RASQAL +# RASQAL_VERSION - The rasqal version string + +# (c) 2007-2009 Sebastian Trueg <[email protected]> +# +# Based on FindFontconfig Copyright (c) 2006,2007 Laurent Montel, <[email protected]> +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +if(WINCE) + FIND_PROGRAM( + RASQAL_CONFIG + NAMES rasqal-config + PATHS ${HOST_BINDIR} NO_DEFAULT_PATH + ) +else(WINCE) + FIND_PROGRAM( + RASQAL_CONFIG + NAMES rasqal-config + ) +endif(WINCE) + + if(RASQAL_CONFIG) + EXECUTE_PROCESS( + COMMAND ${RASQAL_CONFIG} --version + OUTPUT_VARIABLE RASQAL_VERSION + ) + if(RASQAL_VERSION) + STRING(REPLACE "\n" "" RASQAL_VERSION ${RASQAL_VERSION}) + + # extract include paths from rasqal-config + EXECUTE_PROCESS( + COMMAND ${RASQAL_CONFIG} --cflags + OUTPUT_VARIABLE rasqal_CFLAGS_ARGS) + STRING( REPLACE " " ";" rasqal_CFLAGS_ARGS ${rasqal_CFLAGS_ARGS} ) + FOREACH( _ARG ${rasqal_CFLAGS_ARGS} ) + IF(${_ARG} MATCHES "^-I") + STRING(REGEX REPLACE "^-I" "" _ARG ${_ARG}) + STRING( REPLACE "\n" "" _ARG ${_ARG} ) + LIST(APPEND rasqal_INCLUDE_DIRS ${_ARG}) + ENDIF(${_ARG} MATCHES "^-I") + ENDFOREACH(_ARG) + + # extract lib paths from rasqal-config + EXECUTE_PROCESS( + COMMAND ${RASQAL_CONFIG} --libs + OUTPUT_VARIABLE rasqal_CFLAGS_ARGS) + STRING( REPLACE " " ";" rasqal_CFLAGS_ARGS ${rasqal_CFLAGS_ARGS} ) + FOREACH( _ARG ${rasqal_CFLAGS_ARGS} ) + IF(${_ARG} MATCHES "^-L") + STRING(REGEX REPLACE "^-L" "" _ARG ${_ARG}) + LIST(APPEND rasqal_LIBRARY_DIRS ${_ARG}) + ENDIF(${_ARG} MATCHES "^-L") + ENDFOREACH(_ARG) + endif(RASQAL_VERSION) + endif(RASQAL_CONFIG) + + find_path(RASQAL_INCLUDE_DIR rasqal.h + PATHS + ${redland_INCLUDE_DIRS} + ${rasqal_INCLUDE_DIRS} + /usr/X11/include + PATH_SUFFIXES redland rasqal + ) + + find_library(RASQAL_LIBRARIES NAMES rasqal librasqal + PATHS + ${rasqal_LIBRARY_DIRS} + ) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args( + Rasqal + VERSION_VAR RASQAL_VERSION + REQUIRED_VARS RASQAL_LIBRARIES RASQAL_INCLUDE_DIR) + + if (RASQAL_FOUND) + set(RASQAL_DEFINITIONS ${rasqal_CFLAGS}) + if (NOT Rasqal_FIND_QUIETLY) + message(STATUS "Found Rasqal ${RASQAL_VERSION}: libs - ${RASQAL_LIBRARIES}; includes - ${RASQAL_INCLUDE_DIR}") + endif (NOT Rasqal_FIND_QUIETLY) + else (RASQAL_FOUND) + if (Rasqal_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find Rasqal") + endif (Rasqal_FIND_REQUIRED) + endif (RASQAL_FOUND) + + +mark_as_advanced(RASQAL_INCLUDE_DIR_TMP + RASQAL_INCLUDE_DIR + RASQAL_LIBRARIES) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/cmake/FindTcmalloc.cmake ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/cmake/FindTcmalloc.cmake b/libraries/ostrich/backend/cmake/FindTcmalloc.cmake new file mode 100644 index 0000000..eb89d61 --- /dev/null +++ b/libraries/ostrich/backend/cmake/FindTcmalloc.cmake @@ -0,0 +1,39 @@ +# - Find Tcmalloc +# Find the native Tcmalloc includes and library +# +# Tcmalloc_INCLUDE_DIR - where to find Tcmalloc.h, etc. +# Tcmalloc_LIBRARIES - List of libraries when using Tcmalloc. +# Tcmalloc_FOUND - True if Tcmalloc found. + +find_path(Tcmalloc_INCLUDE_DIR google/tcmalloc.h) + +if (USE_TCMALLOC) + set(Tcmalloc_NAMES tcmalloc_and_profiler) +else () + set(Tcmalloc_NAMES tcmalloc_minimal tcmalloc) +endif () + +find_library(Tcmalloc_LIBRARY NAMES ${Tcmalloc_NAMES}) + +if (Tcmalloc_INCLUDE_DIR AND Tcmalloc_LIBRARY) + set(Tcmalloc_FOUND TRUE) + set( Tcmalloc_LIBRARIES ${Tcmalloc_LIBRARY} ) +else () + set(Tcmalloc_FOUND FALSE) + set( Tcmalloc_LIBRARIES ) +endif () + +if (Tcmalloc_FOUND) + message(STATUS "Found Tcmalloc: ${Tcmalloc_LIBRARY}") +else () + message(STATUS "Not Found Tcmalloc") + if (Tcmalloc_FIND_REQUIRED) + message(STATUS "Looked for Tcmalloc libraries named ${Tcmalloc_NAMES}.") + message(FATAL_ERROR "Could NOT find Tcmalloc library") + endif () +endif () + +mark_as_advanced( + Tcmalloc_LIBRARY + Tcmalloc_INCLUDE_DIR + ) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/model/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/model/CMakeLists.txt b/libraries/ostrich/backend/model/CMakeLists.txt new file mode 100644 index 0000000..473e6c8 --- /dev/null +++ b/libraries/ostrich/backend/model/CMakeLists.txt @@ -0,0 +1,6 @@ +file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.proto") +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${ProtoFiles}) +include_directories(.. ${CMAKE_CURRENT_BINARY_DIR}/..) + +add_library(marmotta_model rdf_model.cc rdf_model.h ${PROTO_SRCS} ${PROTO_HDRS} rdf_operators.h rdf_operators.cc) +target_link_libraries(marmotta_model ${CMAKE_THREAD_LIBS_INIT} ${PROTOBUF_LIBRARIES}) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/model/model.proto ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/model/model.proto b/libraries/ostrich/backend/model/model.proto new file mode 100644 index 0000000..2076303 --- /dev/null +++ b/libraries/ostrich/backend/model/model.proto @@ -0,0 +1,77 @@ +syntax = "proto3"; + +package marmotta.rdf.proto; + +option java_package = "org.apache.marmotta.ostrich.model.proto"; + +// Namespaces consist of a prefix (short string used as replacement of a +// URI prefix) and a uri (the URI to replace by a prefix) +message Namespace { + string prefix = 1; + string uri = 2; +} + +// URI resources have a single required field, the uri they are pointing to. +message URI { + string uri = 1; +} + +// BNodes/anonymous nodes have a single required field, the node ID. +message BNode { + string id = 1; +} + +// Resources are either URIs or BNodes. +message Resource { + oneof Resources { + URI uri = 1; + BNode bnode = 2; + } +} + +// A string literal has string content and an optional language specification. +// At least content is required. +message StringLiteral { + string content = 1; + string language = 2; +} + +// A datatype literal has string content of a specific datatype and a URI +// identifying that datatype (typically in XSD namespace). Both fields are +// required. +message DatatypeLiteral { + string content = 1; + URI datatype = 2; +} + +// A literal is either a string literal with optional language or a +// datatype literal with required content and datatype. +message Literal { + oneof Literals { + StringLiteral stringliteral = 1; + DatatypeLiteral dataliteral = 2; + } +} + +// Values can be resources or literals +message Value { + oneof Values { + Resource resource = 1; + Literal literal = 2; + } +} + +// A statement has subject, predicate and object, and an optional context. +// The Statement message is also used for pattern queries, in which case +// non-existing fields are interpreted as wildcards. +message Statement { + Resource subject = 1; + URI predicate = 2; + Value object = 3; + Resource context = 4; +} + +// A collection of statements. +message Statements { + repeated Statement statement = 1; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/model/rdf_model.cc ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/model/rdf_model.cc b/libraries/ostrich/backend/model/rdf_model.cc new file mode 100644 index 0000000..bd7d76d --- /dev/null +++ b/libraries/ostrich/backend/model/rdf_model.cc @@ -0,0 +1,348 @@ +/* + * 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 <new> + +#include "rdf_model.h" + +namespace marmotta { +namespace rdf { + +static std::string as_turtle_(const proto::URI& uri) { + return "<" + uri.uri() + ">"; +} + +static std::string as_turtle_(const proto::BNode& bnode) { + return "_:" + bnode.id(); +} + +static std::string as_turtle_(const proto::StringLiteral& literal) { + if (literal.language() == "") { + return "\"" + literal.content() + "\""; + } else { + return "\"" + literal.content() + "\"@" + literal.language(); + } +} + +static std::string as_turtle_(const proto::DatatypeLiteral& literal) { + return "\"" + literal.content() + "\"^^" + as_turtle_(literal.datatype()); +} + +static std::string as_turtle_(const proto::Resource& resource) { + if (resource.has_uri()) { + return as_turtle_(resource.uri()); + } + if (resource.has_bnode()) { + return as_turtle_(resource.bnode()); + } + return ""; +} + +static std::string as_turtle_(const proto::Value& value) { + if (value.has_resource()) { + if (value.resource().has_uri()) { + return as_turtle_(value.resource().uri()); + } + if (value.resource().has_bnode()) { + return as_turtle_(value.resource().bnode()); + } + } + if (value.has_literal()) { + if (value.literal().has_stringliteral()) { + return as_turtle_(value.literal().stringliteral()); + } + if (value.literal().has_dataliteral()) { + return as_turtle_(value.literal().dataliteral()); + } + } + return ""; +} + +std::string URI::as_turtle() const { + return as_turtle_(internal_); +} + +std::string BNode::as_turtle() const { + return as_turtle_(internal_); +} + +std::string StringLiteral::as_turtle() const { + return as_turtle_(internal_); +} + +std::string DatatypeLiteral::as_turtle() const { + return as_turtle_(internal_); +} + + + +std::string Resource::stringValue() const { + switch (type) { + case URI: + return internal_.uri().uri(); + case BNODE: + return internal_.bnode().id(); + default: + return ""; + } +} + +std::string Resource::as_turtle() const { + return as_turtle_(internal_); +} + + +Value &Value::operator=(const marmotta::rdf::URI &_uri) { + type = URI; + internal_.mutable_resource()->mutable_uri()->MergeFrom(_uri.getMessage()); + return *this; +} + + +Value &Value::operator=(const BNode &_bnode) { + type = BNODE; + internal_.mutable_resource()->mutable_bnode()->MergeFrom(_bnode.getMessage()); + return *this; +} + +Value &Value::operator=(const StringLiteral &literal) { + type = STRING_LITERAL; + internal_.mutable_literal()->mutable_stringliteral()->MergeFrom(literal.getMessage()); + return *this; +} + +Value &Value::operator=(const DatatypeLiteral &literal) { + type = DATATYPE_LITERAL; + internal_.mutable_literal()->mutable_dataliteral()->MergeFrom(literal.getMessage()); + return *this; +} + +Value &Value::operator=(marmotta::rdf::URI &&_uri) { + type = URI; + internal_.mutable_resource()->mutable_uri()->Swap(&_uri.internal_); + return *this; +} + + +Value &Value::operator=(BNode &&_bnode) { + type = BNODE; + internal_.mutable_resource()->mutable_bnode()->Swap(&_bnode.internal_); + return *this; +} + +Value &Value::operator=(StringLiteral &&literal) { + type = STRING_LITERAL; + internal_.mutable_literal()->mutable_stringliteral()->Swap(&literal.internal_); + return *this; +} + +Value &Value::operator=(DatatypeLiteral &&literal) { + type = DATATYPE_LITERAL; + internal_.mutable_literal()->mutable_dataliteral()->Swap(&literal.internal_); + return *this; +} + +std::string Value::stringValue() const { + switch (type) { + case URI: + return internal_.resource().uri().uri(); + case BNODE: + return internal_.resource().bnode().id(); + case STRING_LITERAL: + return internal_.literal().stringliteral().content(); + case DATATYPE_LITERAL: + return internal_.literal().dataliteral().content(); + default: + return ""; + } +} + +std::string Value::as_turtle() const { + return as_turtle_(internal_); +} + + +std::string Statement::as_turtle() const { + if (hasContext()) { + return as_turtle_(internal_.context()) + " { " + + as_turtle_(internal_.subject()) + " " + + as_turtle_(internal_.predicate()) + " " + + as_turtle_(internal_.object()) + ". }"; + } else { + return as_turtle_(internal_.subject()) + " " + + as_turtle_(internal_.predicate()) + " " + + as_turtle_(internal_.object()) + "."; + } +} + +Value::Value(const proto::Value& v) : internal_(v) { + if (v.has_resource()) { + if (v.resource().has_uri()) + type = URI; + else + type = BNODE; + } else if (v.has_literal()) { + if (v.literal().has_stringliteral()) + type = STRING_LITERAL; + else + type = DATATYPE_LITERAL; + } else { + type = NONE; + } +} + +Value::Value(proto::Value&& v) { + if (v.has_resource()) { + if (v.resource().has_uri()) + type = URI; + else + type = BNODE; + } else if (v.has_literal()) { + if (v.literal().has_stringliteral()) + type = STRING_LITERAL; + else + type = DATATYPE_LITERAL; + } else { + type = NONE; + } + internal_.Swap(&v); +} + +Resource::Resource(const proto::Resource& v) : internal_(v) { + if (v.has_uri()) + type = URI; + else if (v.has_bnode()) + type = BNODE; + else + type = NONE; +} + +Resource::Resource(proto::Resource&& v) { + if (v.has_uri()) + type = URI; + else if (v.has_bnode()) + type = BNODE; + else + type = NONE; + internal_.Swap(&v); +} + +Resource &Resource::operator=(const rdf::URI &uri) { + type = URI; + internal_.mutable_uri()->MergeFrom(uri.getMessage()); + return *this; +} + +Resource &Resource::operator=(const rdf::BNode &bnode) { + type = BNODE; + internal_.mutable_bnode()->MergeFrom(bnode.getMessage()); + return *this; +} + +Resource &Resource::operator=(rdf::URI &&uri) { + type = URI; + internal_.mutable_uri()->Swap(&uri.internal_); + return *this; +} + +Resource &Resource::operator=(rdf::BNode &&bnode) { + type = BNODE; + internal_.mutable_bnode()->Swap(&bnode.internal_); + return *this; +} + +URI &URI::operator=(proto::URI &&other) { + internal_.Swap(&other); + return *this; +} + +URI &URI::operator=(const URI &other) { + internal_.MergeFrom(other.internal_); + return *this; +} + +URI &URI::operator=(URI &&other) { + internal_.Swap(&other.internal_); + return *this; +} + +BNode &BNode::operator=(proto::BNode &&other) { + internal_.Swap(&other); + return *this; +} + +BNode &BNode::operator=(const BNode &other) { + internal_.MergeFrom(other.internal_); + return *this; +} + +BNode &BNode::operator=(BNode &&other) { + internal_.Swap(&other.internal_); + return *this; +} + +StringLiteral &StringLiteral::operator=(proto::StringLiteral &&other) { + internal_.Swap(&other); + return *this; +} + +StringLiteral &StringLiteral::operator=(const StringLiteral &other) { + internal_.MergeFrom(other.internal_); + return *this; +} + +StringLiteral &StringLiteral::operator=(StringLiteral &&other) { + internal_.Swap(&other.internal_); + return *this; +} + +DatatypeLiteral &DatatypeLiteral::operator=(proto::DatatypeLiteral &&other) { + internal_.Swap(&other); + return *this; +} + +DatatypeLiteral &DatatypeLiteral::operator=(const DatatypeLiteral &other) { + internal_.MergeFrom(other.internal_); + return *this; +} + +DatatypeLiteral &DatatypeLiteral::operator=(DatatypeLiteral &&other) { + internal_.Swap(&other.internal_); + return *this; +} + +Statement &Statement::operator=(const proto::Statement &other) { + internal_.MergeFrom(other); + return *this; +} + +Statement &Statement::operator=(proto::Statement &&other) { + internal_.Swap(&other); + return *this; +} + +Statement &Statement::operator=(const Statement &other) { + internal_.MergeFrom(other.internal_); + return *this; +} + +Statement &Statement::operator=(Statement &&other) { + internal_.Swap(&other.internal_); + return *this; +} +} // namespace rdf +} // namespace marmotta http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/model/rdf_model.h ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/model/rdf_model.h b/libraries/ostrich/backend/model/rdf_model.h new file mode 100644 index 0000000..ee5c5bb --- /dev/null +++ b/libraries/ostrich/backend/model/rdf_model.h @@ -0,0 +1,709 @@ +/* + * 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_RDF_MODEL_H +#define MARMOTTA_RDF_MODEL_H + +#include <string> +#include <iostream> + +#include "model/model.pb.h" + +/* + * This namespace contains the model definition for the C++ version of + * Marmotta. + * + * All objects are backed by proto messages, but offer more convenient + * high-level constructs. + * + * All objects implement copy as well as efficient move operations for + * constructors and assignment operators. Converting back and forth between + * a proto message and a model object is therefore very cheap. + */ +namespace marmotta { +namespace rdf { + +/** + * RDF namespace, consisting of a prefix and a URI. + */ +class Namespace { + public: + /* + * default constructor, creates empty namespace. + */ + Namespace() {} + + /** + * Create a new namespace from the given prefix and uri (0-terminated + * C-style strings). + */ + Namespace(const char* prefix, const char* uri) { + // Raptor sends us a nullptr for the base NS. + if (prefix != nullptr) { + internal_.set_prefix(prefix); + } + internal_.set_uri(uri); + } + + /** + * Create a new namespace from the given prefix and uri. + */ + Namespace(const std::string &prefix, const std::string &uri) { + internal_.set_prefix(prefix); + internal_.set_uri(uri); + } + + /** + * Create a new namespace from a namespace proto message. + */ + Namespace(const proto::Namespace &ns) : internal_(ns) { }; + + /** + * Create a new namespace from a namespace proto message (move constructor). + */ + Namespace(proto::Namespace &&ns) { + internal_.Swap(&ns); + }; + + /** + * Get the prefix used to identify this namespace. + */ + const std::string &getPrefix() const { + return internal_.prefix(); + } + + /** + * Set the prefix used to identify this namespace. + */ + void setPrefix(std::string &prefix) { + internal_.set_prefix(prefix); + } + + /** + * Get the URI identified by this namespace. + */ + const std::string &getUri() const { + return internal_.uri(); + } + + /** + * Set the URI identified by this namespace. + */ + void setUri(std::string &uri) { + internal_.set_uri(uri); + } + + /** + * Get a reference to the proto message wrapped by the Namespace object. + */ + const proto::Namespace& getMessage() const { + return internal_; + } + + private: + proto::Namespace internal_; +}; + +/** + * RDF URI implementation, backed by a URI proto message. + */ +class URI { + public: + /** + * Default constructor, creates an empty URI. + */ + URI() { } + + /** + * Create an URI object from the URI string passed as argument. + */ + URI(const std::string &uri) { + internal_.set_uri(uri); + } + + /** + * Create an URI object from the URI string passed as argument. + */ + URI(const char* uri) { + internal_.set_uri(uri); + } + + /** + * Create an URI object from the proto message passed as argument (copy + * constructor). + */ + URI(const proto::URI &uri) : internal_(uri) { } + + /** + * Create an URI object from the proto message passed as argument (move + * constructor, the original proto message is invalidated). + */ + URI(proto::URI &&uri) { + internal_.Swap(&uri); + } + + /** + * Copy constructor, create an URI from another URI. + */ + URI(const URI &other) : internal_(other.internal_) {}; + + /** + * Move constructor, create an URI from another URI, invalidating the + * original URI. + */ + URI(URI&& uri) { + internal_.Swap(&uri.internal_); + } + + URI & operator=(proto::URI &&other); + URI & operator=(const URI &other); + URI & operator=(URI &&other); + + /** + * Get the string representation of the URI. + */ + const std::string &getUri() const { + return internal_.uri(); + } + + /** + * Set the string representation of the URI. + */ + void setUri(std::string &uri) { + internal_.set_uri(uri); + } + + /** + * Get a canonical string representation of the URI. + */ + const std::string &stringValue() const { + return internal_.uri(); + } + + /** + * Get a Turtle representation of the URI. + */ + std::string as_turtle() const; + + /** + * Get a reference to the proto message wrapped by the URI object. + */ + const proto::URI& getMessage() const { + return internal_; + } + + private: + proto::URI internal_; + + friend class Value; + friend class Resource; + friend class Statement; +}; + +/** + * RDF Blank node implementation, backed by a BNode proto message. + */ +class BNode { + public: + /** + * Default constructor, creates empty BNode. + */ + BNode() { } + + /** + * Create a new BNode using the ID passed as argument. + */ + BNode(const std::string &id) { + internal_.set_id(id); + } + + /** + * Create a new BNode using the ID passed as argument. + */ + BNode(const char* id) { + internal_.set_id(id); + } + + /** + * Create a new BNode from the proto message passed as argument (copy + * constructor). + */ + BNode(const proto::BNode &n) : internal_(n) { } + + /** + * Create a new BNode from the proto message passed as argument (move + * constructor, original message is invalidated). + */ + BNode(proto::BNode &&n) { + internal_.Swap(&n); + }; + + /** + * Copy constructor, create a BNode from another BNode. + */ + BNode(const BNode &n) : internal_(n.internal_) {}; + + /** + * Move constructor, create a BNode from another BNode. The other BNode + * is invalidated. + */ + BNode(BNode &&n) { + internal_.Swap(&n.internal_); + }; + + BNode & operator=(proto::BNode &&other);; + BNode & operator=(const BNode &other);; + BNode & operator=(BNode &&other);; + + /** + * Return the id of this blank node. + */ + const std::string &getId() const { + return internal_.id(); + } + + /** + * Set the id of this blank node. + */ + void setId(std::string &id) { + internal_.set_id(id); + } + + /** + * Get a canonical string representation of the URI. + */ + const std::string &stringValue() const { + return internal_.id(); + } + + /** + * Get a Turtle representation of the URI. + */ + std::string as_turtle() const; + + /** + * Get a reference to the proto message wrapped by the BNode object. + */ + const proto::BNode& getMessage() const { + return internal_; + } + + private: + proto::BNode internal_; + + friend class Value; + friend class Resource; +}; + + +class StringLiteral { + public: + StringLiteral() { } + + StringLiteral(const std::string &content) { + internal_.set_content(content); + } + + StringLiteral(const std::string &content, const std::string &language) { + internal_.set_content(content); + internal_.set_language(language); + } + + StringLiteral(const proto::StringLiteral &other) : internal_(other) { }; + + StringLiteral(proto::StringLiteral &&other) { + internal_.Swap(&other); + } + + StringLiteral(const StringLiteral &other) : internal_(other.internal_) {}; + + StringLiteral(StringLiteral &&other) { + internal_.Swap(&other.internal_); + } + + StringLiteral & operator=(proto::StringLiteral &&other);; + StringLiteral & operator=(const StringLiteral &other);; + StringLiteral & operator=(StringLiteral &&other);; + + const std::string &getContent() const { + return internal_.content(); + } + + void setContent(std::string &content) { + internal_.set_content(content); + } + + const std::string &getLanguage() const { + return internal_.language(); + } + + void setLanguage(std::string &language) { + internal_.set_language(language); + } + + const std::string &stringValue() const { + return internal_.content(); + } + + const proto::StringLiteral& getMessage() const { + return internal_; + } + + std::string as_turtle() const; + + private: + proto::StringLiteral internal_; + + friend class Value; +}; + + +class DatatypeLiteral { + public: + DatatypeLiteral() { } + + DatatypeLiteral(const std::string &content, URI const &datatype) { + internal_.set_content(content); + internal_.mutable_datatype()->MergeFrom(datatype.getMessage()); + } + + DatatypeLiteral(const proto::DatatypeLiteral &other) : internal_(other) { }; + + DatatypeLiteral(proto::DatatypeLiteral &&other) { + internal_.Swap(&other); + } + + DatatypeLiteral(const DatatypeLiteral &other) : internal_(other.internal_) { }; + + DatatypeLiteral(DatatypeLiteral &&other) { + internal_.Swap(&other.internal_); + } + + DatatypeLiteral & operator=(proto::DatatypeLiteral &&other);; + DatatypeLiteral & operator=(const DatatypeLiteral &other);; + DatatypeLiteral & operator=(DatatypeLiteral &&other);; + + const std::string &getContent() const { + return internal_.content(); + } + + void setContent(std::string &content) { + internal_.set_content(content); + } + + URI getDatatype() const { + return URI(internal_.datatype()); + } + + void setDatatype(const URI &datatype) { + internal_.mutable_datatype()->MergeFrom(datatype.getMessage()); + } + + const std::string &stringValue() const { + return internal_.content(); + } + + int intValue() const { + return std::stoi(getContent()); + } + + operator int() const { + return std::stoi(getContent()); + } + + long long longValue() const { + return std::stoll(getContent()); + } + + operator long long() const { + return std::stoll(getContent()); + } + + float floatValue() const { + return std::stof(getContent()); + } + + operator float() const { + return std::stof(getContent()); + } + + double doubleValue() const { + return std::stod(getContent()); + } + + operator double() const { + return std::stod(getContent()); + } + + const proto::DatatypeLiteral& getMessage() const { + return internal_; + } + + std::string as_turtle() const; + + private: + proto::DatatypeLiteral internal_; + + friend class Value; +}; + +/** + * Value is a polymorphic, but strictly typed generic implementation for URI, + * BNode and Literal. Copy/move constructors and assignment operators allow + * using URI, BNode and Literal wherever a Value is required. + */ +class Value { + public: + enum { + URI = 1, BNODE, STRING_LITERAL, DATATYPE_LITERAL, NONE + } type; + + Value() : type(NONE) { } + + Value(const proto::Value& v); + + Value(proto::Value&& v); + + Value(const marmotta::rdf::URI &uri) : type(URI) { + internal_.mutable_resource()->mutable_uri()->MergeFrom(uri.getMessage()); + } + + Value(marmotta::rdf::URI &&uri) : type(URI) { + internal_.mutable_resource()->mutable_uri()->Swap(&uri.internal_); + } + + Value(const BNode &bnode) : type(BNODE) { + internal_.mutable_resource()->mutable_bnode()->MergeFrom(bnode.getMessage()); + } + + Value(BNode &&bnode) : type(BNODE) { + internal_.mutable_resource()->mutable_bnode()->Swap(&bnode.internal_); + } + + Value(const StringLiteral &sliteral) : type(STRING_LITERAL) { + internal_.mutable_literal()->mutable_stringliteral()->MergeFrom(sliteral.getMessage()); + }; + + Value(StringLiteral &&sliteral) : type(STRING_LITERAL) { + internal_.mutable_literal()->mutable_stringliteral()->Swap(&sliteral.internal_); + }; + + Value(const DatatypeLiteral &dliteral) : type(DATATYPE_LITERAL) { + internal_.mutable_literal()->mutable_dataliteral()->MergeFrom(dliteral.getMessage()); + }; + + Value(DatatypeLiteral &&dliteral) : type(DATATYPE_LITERAL) { + internal_.mutable_literal()->mutable_dataliteral()->Swap(&dliteral.internal_); + }; + + Value(const std::string &literal) : type(STRING_LITERAL) { + internal_.mutable_literal()->mutable_stringliteral()->set_content(literal); + }; + + Value(const char* literal) : type(STRING_LITERAL) { + internal_.mutable_literal()->mutable_stringliteral()->set_content(literal); + }; + + + Value &operator=(const rdf::URI &uri); + + Value &operator=(const rdf::BNode &bnode); + + Value &operator=(const rdf::StringLiteral &literal); + + Value &operator=(const rdf::DatatypeLiteral &literal); + + Value &operator=(rdf::URI &&uri); + + Value &operator=(rdf::BNode &&bnode); + + Value &operator=(rdf::StringLiteral &&literal); + + Value &operator=(rdf::DatatypeLiteral &&literal); + + std::string stringValue() const; + + std::string as_turtle() const; + + const proto::Value& getMessage() const { + return internal_; + } + private: + proto::Value internal_; + + friend class Statement; +}; + + +class Resource { + public: + enum { + URI, BNODE, NONE + } type; + + Resource() : type(NONE) { }; + + Resource(const proto::Resource& v); + + Resource(proto::Resource&& v); + + Resource(const std::string &uri) : type(URI) { + internal_.mutable_uri()->set_uri(uri); + }; + + Resource(const char* uri) : type(URI) { + internal_.mutable_uri()->set_uri(uri); + }; + + Resource(const rdf::URI &uri) : type(URI) { + internal_.mutable_uri()->MergeFrom(uri.getMessage()); + } + + Resource(const rdf::BNode &bnode) : type(BNODE) { + internal_.mutable_bnode()->MergeFrom(bnode.getMessage()); + } + + Resource(rdf::URI &&uri) : type(URI) { + internal_.mutable_uri()->Swap(&uri.internal_); + } + + Resource(rdf::BNode &&bnode) : type(BNODE) { + internal_.mutable_bnode()->Swap(&bnode.internal_); + } + + Resource & operator=(const rdf::URI &uri); + + Resource & operator=(const rdf::BNode &bnode); + + Resource & operator=(rdf::URI &&uri); + + Resource & operator=(rdf::BNode &&bnode); + + std::string stringValue() const; + + std::string as_turtle() const; + + const proto::Resource& getMessage() const { + return internal_; + } + private: + proto::Resource internal_; + + friend class Statement; +}; + + +class Statement { + public: + Statement() {} + + Statement(const Statement& other) : internal_(other.internal_) {} + Statement(Statement&& other) { + internal_.Swap(&other.internal_); + } + + Statement(const proto::Statement& other) : internal_(other) {} + Statement(proto::Statement&& other) { + internal_.Swap(&other); + } + + Statement & operator=(const proto::Statement &other); + Statement & operator=(proto::Statement &&other); + Statement & operator=(const Statement &other); + Statement & operator=(Statement &&other); + + + Statement(Resource const &subject, URI const &predicate, Value const &object) { + internal_.mutable_subject()->MergeFrom(subject.getMessage()); + internal_.mutable_predicate()->MergeFrom(predicate.getMessage()); + internal_.mutable_object()->MergeFrom(object.getMessage()); + } + + + Statement(Resource const &subject, URI const &predicate, Value const &object, Resource const &context) { + internal_.mutable_subject()->MergeFrom(subject.getMessage()); + internal_.mutable_predicate()->MergeFrom(predicate.getMessage()); + internal_.mutable_object()->MergeFrom(object.getMessage()); + internal_.mutable_context()->MergeFrom(context.getMessage()); + } + + Statement(Resource &&subject, URI &&predicate, Value &&object) { + internal_.mutable_subject()->Swap(&subject.internal_); + internal_.mutable_predicate()->Swap(&predicate.internal_); + internal_.mutable_object()->Swap(&object.internal_); + } + + + Statement(Resource &&subject, URI &&predicate, Value &&object, Resource &&context) { + internal_.mutable_subject()->Swap(&subject.internal_); + internal_.mutable_predicate()->Swap(&predicate.internal_); + internal_.mutable_object()->Swap(&object.internal_); + internal_.mutable_context()->Swap(&context.internal_); + } + + + Resource getSubject() const { + return Resource(internal_.subject()); + } + + void setSubject(Resource const &subject) { + internal_.mutable_subject()->MergeFrom(subject.getMessage()); + } + + URI getPredicate() const { + return URI(internal_.predicate()); + } + + void setPredicate(URI const &predicate) { + internal_.mutable_predicate()->MergeFrom(predicate.getMessage()); + } + + Value getObject() const { + return Value(internal_.object()); + } + + void setObject(Value const &object) { + internal_.mutable_object()->MergeFrom(object.getMessage()); + } + + Resource getContext() const { + return Resource(internal_.context()); + } + + void setContext(Resource const &context) { + internal_.mutable_context()->MergeFrom(context.getMessage()); + } + + bool hasContext() const { + return internal_.has_context(); + } + + std::string as_turtle() const; + + const proto::Statement& getMessage() const { + return internal_; + } + private: + proto::Statement internal_; +}; + + +} // namespace rdf +} // namespace marmotta + + +#endif //MARMOTTA_RDF_MODEL_H http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/model/rdf_operators.cc ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/model/rdf_operators.cc b/libraries/ostrich/backend/model/rdf_operators.cc new file mode 100644 index 0000000..b9e49ad --- /dev/null +++ b/libraries/ostrich/backend/model/rdf_operators.cc @@ -0,0 +1,61 @@ +/* + * 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 "rdf_operators.h" + +namespace marmotta { +namespace rdf { +namespace proto { + +bool operator==(const Value &lhs, const Value &rhs) { + if (lhs.has_resource() && rhs.has_resource()) { + if (lhs.resource().has_uri() && rhs.resource().has_uri()) { + return lhs.resource().uri() == rhs.resource().uri(); + } else if (lhs.resource().has_bnode() && rhs.resource().has_bnode()) { + return lhs.resource().bnode() == rhs.resource().bnode(); + } + } else if(lhs.has_literal() && rhs.has_literal()) { + if (lhs.literal().has_stringliteral() && rhs.literal().has_stringliteral()) { + return lhs.literal().stringliteral() == rhs.literal().stringliteral(); + } else if (lhs.literal().has_dataliteral() && rhs.literal().has_dataliteral()) { + return lhs.literal().dataliteral() == rhs.literal().dataliteral(); + } + } + return false; +} + +bool operator==(const Resource &lhs, const Resource &rhs) { + if (lhs.has_uri() && rhs.has_uri()) { + return lhs.uri() == rhs.uri(); + } else if (lhs.has_bnode() && rhs.has_bnode()) { + return lhs.bnode() == rhs.bnode(); + } + return false; +} + +bool operator==(const Statement &lhs, const Statement &rhs) { + return operator==(lhs.subject(), rhs.subject()) && + operator==(lhs.predicate(), rhs.predicate()) && + operator==(lhs.object(), rhs.object()) && + operator==(lhs.context(), rhs.context()); + +} + + +} // namespace proto +} // namespace rdf +} // namespace marmotta http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/model/rdf_operators.h ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/model/rdf_operators.h b/libraries/ostrich/backend/model/rdf_operators.h new file mode 100644 index 0000000..2cf8183 --- /dev/null +++ b/libraries/ostrich/backend/model/rdf_operators.h @@ -0,0 +1,240 @@ +/* + * 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_RDF_OPERATORS_H +#define MARMOTTA_RDF_OPERATORS_H + +#include "model/rdf_model.h" + +namespace marmotta { +namespace rdf { +namespace proto { + +inline bool operator==(const Namespace &lhs, const Namespace &rhs) { + return lhs.uri() == rhs.uri(); +} + +inline bool operator!=(const Namespace &lhs, const Namespace &rhs) { + return lhs.uri() != rhs.uri(); +} + +inline bool operator==(const URI &lhs, const URI &rhs) { + return lhs.uri() == rhs.uri(); +} + +inline bool operator!=(const URI &lhs, const URI &rhs) { + return lhs.uri() != rhs.uri(); +} + +inline bool operator==(const BNode &lhs, const BNode &rhs) { + return lhs.id() == rhs.id(); +} + +inline bool operator!=(const BNode &lhs, const BNode &rhs) { + return lhs.id() != rhs.id(); +} + + +inline bool operator==(const StringLiteral &lhs, const StringLiteral &rhs) { + return lhs.content() == rhs.content() && lhs.language() == rhs.language(); +} + +inline bool operator!=(const StringLiteral &lhs, const StringLiteral &rhs) { + return lhs.content() != rhs.content() || lhs.language() != rhs.language(); +} + +inline bool operator==(const DatatypeLiteral &lhs, const DatatypeLiteral &rhs) { + return lhs.content() == rhs.content() && lhs.datatype().uri() == rhs.datatype().uri(); +} + +inline bool operator!=(const DatatypeLiteral &lhs, const DatatypeLiteral &rhs) { + return lhs.content() != rhs.content() || lhs.datatype().uri() != rhs.datatype().uri(); +} + +bool operator==(const Value &lhs, const Value &rhs); + +inline bool operator!=(const Value &lhs, const Value &rhs) { + return !operator==(lhs,rhs); +}; + + +bool operator==(const Resource &lhs, const Resource &rhs); + +inline bool operator!=(const Resource &lhs, const Resource &rhs) { + return !operator==(lhs,rhs); +}; + +bool operator==(const Statement &lhs, const Statement &rhs); + +inline bool operator!=(const Statement &lhs, const Statement &rhs) { + return !operator==(lhs,rhs); +}; + + +} // namespace proto + + +inline bool operator==(const Namespace &lhs, const Namespace &rhs) { + return lhs.getMessage() == rhs.getMessage(); +} + +inline bool operator!=(const Namespace &lhs, const Namespace &rhs) { + return !operator==(lhs,rhs); +} + +inline bool operator==(const URI &lhs, const URI &rhs) { + return lhs.getMessage() == rhs.getMessage(); +} + +inline bool operator!=(const URI &lhs, const URI &rhs) { + return !operator==(lhs,rhs); +} + +inline bool operator==(const BNode &lhs, const BNode &rhs) { + return lhs.getMessage() == rhs.getMessage(); +} + +inline bool operator!=(const BNode &lhs, const BNode &rhs) { + return !operator==(lhs,rhs); +} + +inline bool operator==(const StringLiteral &lhs, const StringLiteral &rhs) { + return lhs.getMessage() == rhs.getMessage(); +} + +inline bool operator!=(const StringLiteral &lhs, const StringLiteral &rhs) { + return !operator==(lhs,rhs); +} + +inline bool operator==(const DatatypeLiteral &lhs, const DatatypeLiteral &rhs) { + return lhs.getMessage() == rhs.getMessage(); +} + +inline bool operator!=(const DatatypeLiteral &lhs, const DatatypeLiteral &rhs) { + return !operator==(lhs,rhs); +} + +inline bool operator==(const Value &lhs, const Value &rhs) { + return lhs.getMessage() == rhs.getMessage(); +} + +inline bool operator!=(const Value &lhs, const Value &rhs) { + return !operator==(lhs,rhs); +} + +inline bool operator==(const Resource &lhs, const Resource &rhs) { + return lhs.getMessage() == rhs.getMessage(); +} + +inline bool operator!=(const Resource &lhs, const Resource &rhs) { + return !operator==(lhs,rhs); +} + +inline bool operator==(const Statement &lhs, const Statement &rhs) { + return lhs.getMessage() == rhs.getMessage(); +} + +inline bool operator!=(const Statement &lhs, const Statement &rhs) { + return !operator==(lhs,rhs); +} + +} // namespace rdf +} // namespace marmotta + +namespace std { + +// Define std::hash specializations for our proto messages. Note that this generic +// computation serializes the message and is therefore expensive. Consider using +// specialised implementations instead. +template<> +struct hash<google::protobuf::Message> { + std::size_t operator()(const google::protobuf::Message &k) const { + std::string content; + k.SerializeToString(&content); + return std::hash<string>()(content); + } +}; + +// Hash implementation for URIs. Uses a faster implementation than the generic +// proto message version. +template<> +struct hash<marmotta::rdf::proto::URI> { + std::size_t operator()(const marmotta::rdf::proto::URI &k) const { + return std::hash<std::string>()(k.uri()); + } +}; + +// Hash implementation for BNodes. Uses a faster implementation than the generic +// proto message version. +template<> +struct hash<marmotta::rdf::proto::BNode> { + std::size_t operator()(const marmotta::rdf::proto::BNode &k) const { + return std::hash<std::string>()(k.id()); + } +}; + +// Hash implementation for Resources. Uses a faster implementation than the generic +// proto message version. +template<> +struct hash<marmotta::rdf::proto::Resource> { + std::size_t operator()(const marmotta::rdf::proto::Resource &k) const { + if (k.has_uri()) { + return std::hash<marmotta::rdf::proto::URI>()(k.uri()); + } else if (k.has_bnode()) { + return std::hash<marmotta::rdf::proto::BNode>()(k.bnode()); + } + return std::hash<google::protobuf::Message>()(k); + } +}; + +template<> +struct hash<marmotta::rdf::proto::Value> { + std::size_t operator()(const marmotta::rdf::proto::Value &k) const { + return std::hash<google::protobuf::Message>()(k); + } +}; + +template<> +struct hash<marmotta::rdf::proto::StringLiteral> { + std::size_t operator()(const marmotta::rdf::proto::StringLiteral &k) const { + return std::hash<google::protobuf::Message>()(k); + } +}; + +template<> +struct hash<marmotta::rdf::proto::DatatypeLiteral> { + std::size_t operator()(const marmotta::rdf::proto::DatatypeLiteral &k) const { + return std::hash<google::protobuf::Message>()(k); + } +}; + +template<> +struct hash<marmotta::rdf::proto::Statement> { + std::size_t operator()(const marmotta::rdf::proto::Statement &k) const { + return std::hash<google::protobuf::Message>()(k); + } +}; + +template<> +struct hash<marmotta::rdf::proto::Namespace> { + std::size_t operator()(const marmotta::rdf::proto::Namespace &k) const { + return std::hash<google::protobuf::Message>()(k); + } +}; +} // namespace std + +#endif //MARMOTTA_RDF_OPERATORS_H http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/parser/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/parser/CMakeLists.txt b/libraries/ostrich/backend/parser/CMakeLists.txt new file mode 100644 index 0000000..3ed5634 --- /dev/null +++ b/libraries/ostrich/backend/parser/CMakeLists.txt @@ -0,0 +1,4 @@ +include_directories(.. ${CMAKE_CURRENT_BINARY_DIR}/..) + +add_library(marmotta_parser rdf_parser.h rdf_parser.cc) +target_link_libraries(marmotta_parser marmotta_model ${CMAKE_THREAD_LIBS_INIT} ${RAPTOR_LIBRARY}) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/0ff22a0c/libraries/ostrich/backend/parser/rdf_parser.cc ---------------------------------------------------------------------- diff --git a/libraries/ostrich/backend/parser/rdf_parser.cc b/libraries/ostrich/backend/parser/rdf_parser.cc new file mode 100644 index 0000000..9a1fea3 --- /dev/null +++ b/libraries/ostrich/backend/parser/rdf_parser.cc @@ -0,0 +1,175 @@ +/* + * 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 <raptor2/raptor2.h> +#include "rdf_parser.h" + +namespace marmotta { +namespace parser { +Parser::Parser(const rdf::URI& baseUri, Format format) + : stmt_handler([](const rdf::Statement& stmt) { }) + , ns_handler([](const rdf::Namespace& ns) { }) +{ + world = raptor_new_world(); + base = raptor_new_uri(world, (unsigned char const *) baseUri.getUri().c_str()); + + switch (format) { + case RDFXML: + parser = raptor_new_parser(world, "rdfxml"); + break; + case TURTLE: + parser = raptor_new_parser(world, "turtle"); + break; + case NTRIPLES: + parser = raptor_new_parser(world, "ntriples"); + break; + case RDFA: + parser = raptor_new_parser(world, "rdfa"); + break; + case RDFJSON: + parser = raptor_new_parser(world, "json"); + break; + case GUESS: + parser = raptor_new_parser(world, "guess"); + break; + } + + raptor_parser_set_statement_handler(parser, this, raptor_stmt_handler); + raptor_parser_set_namespace_handler(parser, this, raptor_ns_handler); +} + +Parser::~Parser() { + raptor_free_parser(parser); + raptor_free_uri(base); + raptor_free_world(world); +} + + +void Parser::raptor_stmt_handler(void *user_data, raptor_statement *statement) { + Parser* p = static_cast<Parser*>(user_data); + + rdf::Resource subject; rdf::URI predicate; rdf::Value object; rdf::Resource context; + switch (statement->subject->type) { + case RAPTOR_TERM_TYPE_URI: + subject = rdf::URI((const char*)raptor_uri_as_string(statement->subject->value.uri)); + break; + case RAPTOR_TERM_TYPE_BLANK: + subject = rdf::BNode(std::string((const char*)statement->subject->value.blank.string, statement->subject->value.blank.string_len)); + break; + default: + raptor_parser_parse_abort(p->parser); + throw ParseError("invalid subject term type"); + } + + switch (statement->predicate->type) { + case RAPTOR_TERM_TYPE_URI: + predicate = rdf::URI((const char*)raptor_uri_as_string(statement->predicate->value.uri)); + break; + default: + raptor_parser_parse_abort(p->parser); + throw ParseError("invalid predicate term type"); + } + + switch (statement->object->type) { + case RAPTOR_TERM_TYPE_URI: + object = rdf::URI((const char*)raptor_uri_as_string(statement->object->value.uri)); + break; + case RAPTOR_TERM_TYPE_BLANK: + object = rdf::BNode(std::string((const char*)statement->object->value.blank.string, statement->object->value.blank.string_len)); + break; + case RAPTOR_TERM_TYPE_LITERAL: + if(statement->object->value.literal.language != NULL) { + object = rdf::StringLiteral( + std::string((const char*)statement->object->value.literal.string, statement->object->value.literal.string_len), + std::string((const char*)statement->object->value.literal.language, statement->object->value.literal.language_len) + ); + } else if(statement->object->value.literal.datatype != NULL) { + object = rdf::DatatypeLiteral( + std::string((const char*)statement->object->value.literal.string, statement->object->value.literal.string_len), + rdf::URI((const char*)raptor_uri_as_string(statement->object->value.literal.datatype)) + ); + } else { + object = rdf::StringLiteral( + std::string((const char*)statement->object->value.literal.string, statement->object->value.literal.string_len) + ); + } + break; + default: + raptor_parser_parse_abort(p->parser); + throw ParseError("invalid object term type"); + } + + if (statement->graph != NULL) { + switch (statement->graph->type) { + case RAPTOR_TERM_TYPE_URI: + context = rdf::URI((const char*)raptor_uri_as_string(statement->graph->value.uri)); + break; + case RAPTOR_TERM_TYPE_BLANK: + context = rdf::BNode(std::string((const char*)statement->graph->value.blank.string, statement->graph->value.blank.string_len)); + break; + default: + raptor_parser_parse_abort(p->parser); + throw ParseError("invalid graph term type"); + } + } else { + context = rdf::URI(); + } + + p->stmt_handler(rdf::Statement(subject, predicate, object, context)); +} + + +void Parser::raptor_ns_handler(void *user_data, raptor_namespace *nspace) { + Parser* p = static_cast<Parser*>(user_data); + p->ns_handler(rdf::Namespace( + (const char*)raptor_namespace_get_prefix(nspace), + (const char*)raptor_uri_as_string(raptor_namespace_get_uri(nspace)))); +} + +void Parser::parse(std::istream &in) { + if(in) { + raptor_parser_parse_start(parser, base); + + char buffer[8192]; + while (in.read(buffer, 8192)) { + raptor_parser_parse_chunk(parser, (unsigned char const *) buffer, in.gcount(), 0); + } + raptor_parser_parse_chunk(parser, (unsigned char const *) buffer, in.gcount(), 1); + } +} + +Format FormatFromString(const std::string &name) { + if (name == "rdfxml" || name == "rdf/xml" || name == "xml") { + return RDFXML; + } + if (name == "n3" || name == "ntriples" || name == "text/n3") { + return NTRIPLES; + } + if (name == "turtle" || name == "text/turtle") { + return TURTLE; + } + if (name == "json" || name == "application/json" || name == "application/rdf+json") { + return RDFJSON; + } + if (name == "auto" || name == "guess") { + return GUESS; + } + return RDFXML; +} + +} +}
