Add libSimpleDbus, libLogger, libConfig source code to Vasum. 59/38359/1
authorDariusz Michaluk <d.michaluk@samsung.com>
Tue, 14 Apr 2015 15:36:19 +0000 (17:36 +0200)
committerDariusz Michaluk <d.michaluk@samsung.com>
Fri, 17 Apr 2015 09:50:51 +0000 (11:50 +0200)
[Feature]       Add libSimpleDbus, libLogger, libConfig source code to Vasum.
[Cause]         N/A
[Solution]      N/A
[Verification]  Build, install, run tests, run server.

Change-Id: I2466604ee744874237fb989695d4104d399cdca1
Signed-off-by: Dariusz Michaluk <d.michaluk@samsung.com>
61 files changed:
CMakeLists.txt
client/CMakeLists.txt
client/dbus-connection.cpp
client/dbus-connection.hpp
common/api/method-result-builder.hpp
common/config/exception.hpp [new file with mode: 0644]
common/config/fdstore.cpp [new file with mode: 0644]
common/config/fdstore.hpp [new file with mode: 0644]
common/config/fields-union.hpp [new file with mode: 0644]
common/config/fields.hpp [new file with mode: 0644]
common/config/from-fdstore-visitor.hpp [new file with mode: 0644]
common/config/from-gvariant-visitor.hpp [new file with mode: 0644]
common/config/from-json-visitor.hpp [new file with mode: 0644]
common/config/from-kvjson-visitor.hpp [new file with mode: 0644]
common/config/from-kvstore-visitor.hpp [new file with mode: 0644]
common/config/fs-utils.cpp [new file with mode: 0644]
common/config/fs-utils.hpp [new file with mode: 0644]
common/config/is-union.hpp [new file with mode: 0644]
common/config/is-visitable.hpp [new file with mode: 0644]
common/config/kvstore.cpp [new file with mode: 0644]
common/config/kvstore.hpp [new file with mode: 0644]
common/config/manager.hpp [new file with mode: 0644]
common/config/sqlite3/connection.cpp [new file with mode: 0644]
common/config/sqlite3/connection.hpp [new file with mode: 0644]
common/config/sqlite3/statement.cpp [new file with mode: 0644]
common/config/sqlite3/statement.hpp [new file with mode: 0644]
common/config/to-fdstore-visitor.hpp [new file with mode: 0644]
common/config/to-gvariant-visitor.hpp [new file with mode: 0644]
common/config/to-json-visitor.hpp [new file with mode: 0644]
common/config/to-kvstore-visitor.hpp [new file with mode: 0644]
common/dbus/connection.cpp [new file with mode: 0644]
common/dbus/connection.hpp [new file with mode: 0644]
common/dbus/exception.hpp [new file with mode: 0644]
common/ipc/client.hpp
common/ipc/internals/processor.hpp
common/ipc/service.hpp
common/logger/backend-journal.cpp [new file with mode: 0644]
common/logger/backend-journal.hpp [new file with mode: 0644]
common/logger/backend-null.hpp [new file with mode: 0644]
common/logger/backend-stderr.cpp [new file with mode: 0644]
common/logger/backend-stderr.hpp [new file with mode: 0644]
common/logger/backend.hpp [new file with mode: 0644]
common/logger/ccolor.cpp [new file with mode: 0644]
common/logger/ccolor.hpp [new file with mode: 0644]
common/logger/formatter.cpp [new file with mode: 0644]
common/logger/formatter.hpp [new file with mode: 0644]
common/logger/level.cpp [new file with mode: 0644]
common/logger/level.hpp [new file with mode: 0644]
common/logger/logger-scope.cpp [new file with mode: 0644]
common/logger/logger-scope.hpp [new file with mode: 0644]
common/logger/logger.cpp [new file with mode: 0644]
common/logger/logger.hpp [new file with mode: 0644]
common/netlink/netlink-message.hpp
common/utils/glib-utils.cpp [new file with mode: 0644]
common/utils/glib-utils.hpp [new file with mode: 0644]
packaging/vasum.spec
server/CMakeLists.txt
server/netdev.hpp
tests/unit_tests/CMakeLists.txt
tests/unit_tests/socket_test_service/socket-test.cpp
zone-daemon/CMakeLists.txt

index e7f7aff..6a87b41 100644 (file)
@@ -86,6 +86,7 @@ ADD_DEFINITIONS("-pedantic-errors") # Make pedantic warnings into errors
 ADD_DEFINITIONS(-DPROGRAM_VERSION="${VERSION}")
 ADD_DEFINITIONS(-DPROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}")
 ADD_DEFINITIONS(-DUSE_EXEC)
+ADD_DEFINITIONS(-D__STDC_LIMIT_MACROS)
 
 IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
     # Warn about documentation problems
index 0ebbf75..296e638 100644 (file)
 MESSAGE(STATUS "")
 MESSAGE(STATUS "Generating makefile for the Client...")
 FILE(GLOB project_SRCS *.cpp *.hpp *.h)
-FILE(GLOB common_SRCS ${COMMON_FOLDER}/utils/callback-guard.hpp
-                      ${COMMON_FOLDER}/utils/callback-guard.cpp
-                      ${COMMON_FOLDER}/utils/glib-loop.cpp
-                      ${COMMON_FOLDER}/utils/glib-loop.hpp
-                      ${COMMON_FOLDER}/base-exception.hpp
-                      ${COMMON_FOLDER}/base-exception.cpp
-                      ${COMMON_FOLDER}/utils/eventfd.hpp
-                      ${COMMON_FOLDER}/utils/eventfd.cpp
-                      ${COMMON_FOLDER}/utils/fd-utils.hpp
-                      ${COMMON_FOLDER}/utils/fd-utils.cpp
-                      ${COMMON_FOLDER}/epoll/*.hpp
-                      ${COMMON_FOLDER}/epoll/*.cpp
-                      ${COMMON_FOLDER}/ipc/*.hpp
-                      ${COMMON_FOLDER}/ipc/*.cpp
-                      ${COMMON_FOLDER}/ipc/internals/*.hpp
-                      ${COMMON_FOLDER}/ipc/internals/*.cpp)
+FILE(GLOB common_SRCS ${COMMON_FOLDER}/config/*.hpp             ${COMMON_FOLDER}/config/*.cpp
+                      ${COMMON_FOLDER}/config/sqlite3/*.hpp     ${COMMON_FOLDER}/config/sqlite3/*.cpp
+                      ${COMMON_FOLDER}/dbus/*.hpp               ${COMMON_FOLDER}/dbus/*.cpp
+                      ${COMMON_FOLDER}/epoll/*.hpp              ${COMMON_FOLDER}/epoll/*.cpp
+                      ${COMMON_FOLDER}/ipc/*.hpp                ${COMMON_FOLDER}/ipc/*.cpp
+                      ${COMMON_FOLDER}/ipc/internals/*.hpp      ${COMMON_FOLDER}/ipc/internals/*.cpp
+                      ${COMMON_FOLDER}/logger/*.hpp             ${COMMON_FOLDER}/logger/*.cpp
+                      ${COMMON_FOLDER}/utils/*.hpp              ${COMMON_FOLDER}/utils/*.cpp
+                      ${COMMON_FOLDER}/*.hpp                    ${COMMON_FOLDER}/*.cpp)
 
 SET(_LIB_VERSION_ "0.0.1")
 SET(_LIB_SOVERSION_ "0")
@@ -55,7 +48,7 @@ SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY   VERSION ${_LIB_VERSION_})
 
 ## Link libraries ##############################################################
 FIND_PACKAGE(Boost COMPONENTS system filesystem)
-PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0 libSimpleDbus libLogger libConfig libsystemd-daemon)
+PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0 libsystemd-daemon libsystemd-journal libcap-ng sqlite3)
 INCLUDE_DIRECTORIES(SYSTEM ${LIB_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
 INCLUDE_DIRECTORIES(${COMMON_FOLDER})
 INCLUDE_DIRECTORIES(${SERVER_FOLDER})
index 7e364d7..b52bd71 100644 (file)
@@ -20,7 +20,7 @@
 /**
  * @file
  * @author  Mateusz Malicki (m.malicki2@samsung.com)
- * @brief   libSimpleDbus's wrapper
+ * @brief   SimpleDbus's wrapper
  */
 
 #include <config.hpp>
index a760bb6..3cb37ad 100644 (file)
@@ -20,7 +20,7 @@
 /**
  * @file
  * @author  Mateusz Malicki (m.malicki2@samsung.com)
- * @brief   libSimpleDbus's wrapper
+ * @brief   SimpleDbus's wrapper
  */
 
 #ifndef VASUM_CLIENT_DBUS_CONNECTION_HPP
@@ -37,9 +37,9 @@ namespace vasum {
 namespace client {
 
 /**
- * libSimpleDbus client definition.
+ * SimpleDbus client definition.
  *
- * DbusConnection uses libSimpleDbus API.
+ * DbusConnection uses SimpleDbus API.
  */
 class DbusConnection {
 public:
index 04ede40..89aa7a9 100644 (file)
@@ -47,7 +47,7 @@ public:
     template<typename Data>
     void set(const std::shared_ptr<Data>& data)
     {
-        static_assert(config::isVisitable<Data>::value, "Use only libConfig's structures");
+        static_assert(config::isVisitable<Data>::value, "Use only Config's structures");
         setImpl(data);
     }
 
diff --git a/common/config/exception.hpp b/common/config/exception.hpp
new file mode 100644 (file)
index 0000000..977ec32
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com)
+ * @brief   Exceptions for the configuration
+ */
+
+#ifndef COMMON_CONFIG_EXCEPTION_HPP
+#define COMMON_CONFIG_EXCEPTION_HPP
+
+#include <stdexcept>
+
+namespace config {
+
+/**
+ * Base class for exceptions in configuration.
+ * Error occured during a config file parsing,
+ * e.g. syntax error
+ */
+struct ConfigException: public std::runtime_error {
+
+    ConfigException(const std::string& error) : std::runtime_error(error) {}
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_EXCEPTION_HPP
diff --git a/common/config/fdstore.cpp b/common/config/fdstore.cpp
new file mode 100644 (file)
index 0000000..c1cedfe
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak <j.olszak@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief  Definition of a class for writing and reading data from a file descriptor
+ */
+
+#include "config.hpp"
+
+#include "config/fdstore.hpp"
+#include "config/exception.hpp"
+
+#include <cstring>
+#include <cerrno>
+#include <unistd.h>
+#include <chrono>
+#include <poll.h>
+
+namespace config {
+
+namespace {
+
+void waitForEvent(int fd,
+                  short event,
+                  const std::chrono::high_resolution_clock::time_point deadline)
+{
+    // Wait for the rest of the data
+    struct pollfd fds[1];
+    fds[0].fd = fd;
+    fds[0].events = event | POLLHUP;
+
+    for (;;) {
+        std::chrono::milliseconds timeoutMS =
+            std::chrono::duration_cast<std::chrono::milliseconds>(deadline - std::chrono::high_resolution_clock::now());
+        if (timeoutMS.count() < 0) {
+            throw ConfigException("Timeout");
+        }
+
+        int ret = ::poll(fds, 1 /*fds size*/, timeoutMS.count());
+
+        if (ret == -1) {
+            if (errno == EINTR) {
+                continue;
+            }
+            throw ConfigException("Error in poll: " + std::string(strerror(errno)));
+        }
+
+        if (ret == 0) {
+            throw ConfigException("Timeout");
+        }
+
+        if (fds[0].revents & POLLHUP) {
+            throw ConfigException("Peer disconnected");
+        }
+
+        // Here Comes the Sun
+        break;
+    }
+}
+
+} // namespace
+
+FDStore::FDStore(int fd)
+    : mFD(fd)
+{
+}
+
+FDStore::FDStore(const FDStore& store)
+    : mFD(store.mFD)
+{
+}
+
+FDStore::~FDStore()
+{
+}
+
+void FDStore::write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS)
+{
+    std::chrono::high_resolution_clock::time_point deadline = std::chrono::high_resolution_clock::now() +
+                                                              std::chrono::milliseconds(timeoutMS);
+
+    size_t nTotal = 0;
+    for (;;) {
+        int n  = ::write(mFD,
+                         reinterpret_cast<const char*>(bufferPtr) + nTotal,
+                         size - nTotal);
+        if (n >= 0) {
+            nTotal += n;
+            if (nTotal == size) {
+                // All data is written, break loop
+                break;
+            }
+        } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+            // Neglected errors
+        } else {
+            throw ConfigException("Error during writing: " + std::string(strerror(errno)));
+        }
+
+        waitForEvent(mFD, POLLOUT, deadline);
+    }
+}
+
+void FDStore::read(void* bufferPtr, const size_t size, const unsigned int timeoutMS)
+{
+    std::chrono::high_resolution_clock::time_point deadline = std::chrono::high_resolution_clock::now() +
+                                                              std::chrono::milliseconds(timeoutMS);
+
+    size_t nTotal = 0;
+    for (;;) {
+        int n  = ::read(mFD,
+                        reinterpret_cast<char*>(bufferPtr) + nTotal,
+                        size - nTotal);
+        if (n >= 0) {
+            nTotal += n;
+            if (nTotal == size) {
+                // All data is read, break loop
+                break;
+            }
+            if (n == 0) {
+                throw ConfigException("Peer disconnected");
+            }
+        } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+            // Neglected errors
+        } else {
+            throw ConfigException("Error during reading: " + std::string(strerror(errno)));
+        }
+
+        waitForEvent(mFD, POLLIN, deadline);
+    }
+}
+} // namespace config
diff --git a/common/config/fdstore.hpp b/common/config/fdstore.hpp
new file mode 100644 (file)
index 0000000..d34ea14
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak <j.olszak@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief  Declaration of a class for writing and reading data from a file descriptor
+ */
+
+#ifndef COMMON_CONFIG_FDSTORE_HPP
+#define COMMON_CONFIG_FDSTORE_HPP
+
+#include <cstddef>
+
+namespace config {
+
+class FDStore {
+
+public:
+    /**
+     * Constructor. One can pass any kind of file descriptor.
+     * Serialization is NOT written for network purposes,
+     * rather local communication.
+     *
+     * @param fd file descriptor
+     */
+    FDStore(int fd = -1);
+    FDStore(const FDStore& store);
+    ~FDStore();
+
+    /**
+     * Write data using the file descriptor
+     *
+     * @param bufferPtr buffer with the data
+     * @param size size of the buffer
+     * @param timeoutMS timeout in milliseconds
+     */
+    void write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS = 500);
+
+    /**
+     * Reads a value of the given type.
+     *
+     * @param bufferPtr buffer with the data
+     * @param size size of the buffer
+     * @param timeoutMS timeout in milliseconds
+     */
+    void read(void* bufferPtr, const size_t size, const unsigned int timeoutMS = 500);
+
+private:
+    int mFD;
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_FDSTORE_HPP
+
+
diff --git a/common/config/fields-union.hpp b/common/config/fields-union.hpp
new file mode 100644 (file)
index 0000000..67720e7
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki (m.malicki2@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   Macros for declare configuration fields
+ */
+
+#ifndef COMMON_CONFIG_FIELDS_UNION_HPP
+#define COMMON_CONFIG_FIELDS_UNION_HPP
+
+#include "config/fields.hpp"
+#include "config/exception.hpp"
+
+#include <utility>
+#include <boost/any.hpp>
+
+/**
+ * Use this macro to declare and register config fields
+ *
+ * Example:
+ *  struct Foo {
+ *      std::string bar;
+ *
+ *      CONFIG_REGISTER
+ *      (
+ *          bar,
+ *      )
+ *  };
+ *
+ *  struct Config
+ *  {
+ *      CONFIG_DECLARE_UNION
+ *      (
+ *          Foo,
+ *          int
+ *      )
+ *  };
+ *
+ *  Example of valid configuration:
+ *   1. {
+ *        "type": "Foo",
+ *        "value": { "bar": "some string" }
+ *      }
+ *   2. {
+ *        "type": "int",
+ *        "value": 1
+ *      }
+ *
+ *
+ *  Usage:
+ *   Config config;
+ *   // ...
+ *   if (config.isSet()) {
+ *      if (config.is<Foo>()) {
+ *          Foo& foo = config.as<Foo>();
+ *          // ...
+ *      }
+ *      if (config.is<int>())) {
+ *          int field = config.as<int>();
+ *          // ...
+ *      }
+ *   } else {
+ *     // Config is not set
+ *     Foo foo({"some string"});
+ *     config.set(foo);
+ *     config.set(std::move(foo));         //< copy sic!
+ *     config.set(Foo({"some string"}));
+ *   }
+ */
+
+class DisbaleMoveAnyWrapper : public boost::any
+{
+    public:
+        DisbaleMoveAnyWrapper() {}
+        DisbaleMoveAnyWrapper(const DisbaleMoveAnyWrapper& any)
+            : boost::any(static_cast<const boost::any&>(any)) {};
+        DisbaleMoveAnyWrapper& operator=(DisbaleMoveAnyWrapper&& any) = delete;
+        DisbaleMoveAnyWrapper& operator=(const DisbaleMoveAnyWrapper& any) {
+            static_cast<boost::any&>(*this) = static_cast<const boost::any&>(any);
+            return *this;
+        }
+};
+
+#define CONFIG_DECLARE_UNION(...)                                                               \
+private:                                                                                        \
+    DisbaleMoveAnyWrapper mConfigDeclareField;                                                  \
+                                                                                                \
+    template<typename Visitor>                                                                  \
+    void visitOption(Visitor& v, const std::string& name) {                                     \
+        GENERATE_CODE(GENERATE_UNION_VISIT__, __VA_ARGS__)                                      \
+        throw config::ConfigException("Union type error. Unsupported type");                    \
+    }                                                                                           \
+    template<typename Visitor>                                                                  \
+    void visitOption(Visitor& v, const std::string& name) const {                               \
+        GENERATE_CODE(GENERATE_UNION_VISIT_CONST__, __VA_ARGS__)                                \
+        throw config::ConfigException("Union type error. Unsupported type");                    \
+    }                                                                                           \
+    std::string getOptionName() const {                                                         \
+        GENERATE_CODE(GENERATE_UNION_NAME__, __VA_ARGS__)                                       \
+        return std::string();                                                                   \
+    }                                                                                           \
+    boost::any& getHolder() {                                                                   \
+        return static_cast<boost::any&>(mConfigDeclareField);                                   \
+    }                                                                                           \
+    const boost::any& getHolder() const {                                                       \
+        return static_cast<const boost::any&>(mConfigDeclareField);                             \
+    }                                                                                           \
+public:                                                                                         \
+                                                                                                \
+    template<typename Visitor>                                                                  \
+    void accept(Visitor v) {                                                                    \
+        std::string name;                                                                       \
+        v.visit("type", name);                                                                  \
+        visitOption(v, name);                                                                   \
+    }                                                                                           \
+                                                                                                \
+    template<typename Visitor>                                                                  \
+    void accept(Visitor v) const {                                                              \
+        const std::string name = getOptionName();                                               \
+        if (name.empty()) {                                                                     \
+           throw config::ConfigException("Type is not set");                                    \
+        }                                                                                       \
+        v.visit("type", name);                                                                  \
+        visitOption(v, name);                                                                   \
+    }                                                                                           \
+                                                                                                \
+    template<typename Type>                                                                     \
+    bool is() const {                                                                           \
+        return boost::any_cast<Type>(&getHolder()) != NULL;                                     \
+    }                                                                                           \
+    template<typename Type>                                                                     \
+    typename std::enable_if<!std::is_const<Type>::value, Type>::type& as() {                    \
+        if (getHolder().empty()) {                                                              \
+            throw config::ConfigException("Type is not set");                                   \
+        }                                                                                       \
+        return boost::any_cast<Type&>(getHolder());                                             \
+    }                                                                                           \
+    template<typename Type>                                                                     \
+    const Type& as() const {                                                                    \
+        if (getHolder().empty()) {                                                              \
+            throw config::ConfigException("Type is not set");                                   \
+        }                                                                                       \
+        return boost::any_cast<const Type&>(getHolder());                                       \
+    }                                                                                           \
+    bool isSet() {                                                                              \
+        return !getOptionName().empty();                                                        \
+    }                                                                                           \
+    template<typename Type>                                                                     \
+    Type& set(const Type& src) {                                                                \
+        getHolder() = std::forward<const Type>(src);                                            \
+        if (getOptionName().empty()) {                                                          \
+           throw config::ConfigException("Unsupported type");                                   \
+        }                                                                                       \
+        return as<Type>();                                                                      \
+    }                                                                                           \
+
+#define GENERATE_CODE(MACRO, ...)                                                               \
+    BOOST_PP_LIST_FOR_EACH(MACRO, _, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__))
+
+#define GENERATE_UNION_VISIT__(r, _, TYPE_)                                                     \
+    if (#TYPE_ == name) {                                                                       \
+        v.visit("value", set(std::move(TYPE_())));                                              \
+        return;                                                                                 \
+    }
+
+#define GENERATE_UNION_VISIT_CONST__(r, _, TYPE_)                                               \
+    if (#TYPE_ == name) {                                                                       \
+        v.visit("value", as<const TYPE_>());                                                    \
+        return;                                                                                 \
+    }
+
+#define GENERATE_UNION_NAME__(r, _, TYPE_)                                                      \
+    if (is<TYPE_>()) {                                                                          \
+        return #TYPE_;                                                                          \
+    }
+
+#endif // COMMON_CONFIG_FIELDS_UNION_HPP
diff --git a/common/config/fields.hpp b/common/config/fields.hpp
new file mode 100644 (file)
index 0000000..cba5a67
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   Macros for registering configuration fields
+ */
+
+#ifndef COMMON_CONFIG_FIELDS_HPP
+#define COMMON_CONFIG_FIELDS_HPP
+
+#include <boost/preprocessor/variadic/to_list.hpp>
+#include <boost/preprocessor/list/for_each.hpp>
+
+#if BOOST_PP_VARIADICS != 1
+#error variadic macros not supported
+#endif
+
+/**
+ * Use this macro to register config fields.
+ *
+ * Example:
+ *   struct Foo
+ *   {
+ *       std::string bar;
+ *       std::vector<int> tab;
+ *
+ *       // SubConfigA must also register config fields
+ *       SubConfigA sub_a;
+ *
+ *       // SubConfigB must also register config fields
+ *       std::vector<SubConfigB> tab_sub;
+ *
+ *       CONFIG_REGISTER
+ *       (
+ *           bar,
+ *           tab,
+ *           sub_a
+ *       )
+ *   };
+ */
+
+#define CONFIG_REGISTER_EMPTY                                      \
+    template<typename Visitor>                                     \
+    void accept(Visitor ) {                                        \
+    }                                                              \
+    template<typename Visitor>                                     \
+    void accept(Visitor ) const {                                  \
+    }                                                              \
+
+#define CONFIG_REGISTER(...)                                       \
+    template<typename Visitor>                                     \
+    void accept(Visitor v) {                                       \
+        GENERATE_ELEMENTS__(__VA_ARGS__)                           \
+    }                                                              \
+    template<typename Visitor>                                     \
+    void accept(Visitor v) const {                                 \
+        GENERATE_ELEMENTS__(__VA_ARGS__)                           \
+    }                                                              \
+
+#define GENERATE_ELEMENTS__(...)                                   \
+    BOOST_PP_LIST_FOR_EACH(GENERATE_ELEMENT__,                     \
+                           _,                                      \
+                           BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__)) \
+
+#define GENERATE_ELEMENT__(r, _, element)                          \
+    v.visit(#element, element);                                    \
+
+#endif // COMMON_CONFIG_FIELDS_HPP
diff --git a/common/config/from-fdstore-visitor.hpp b/common/config/from-fdstore-visitor.hpp
new file mode 100644 (file)
index 0000000..9b9df42
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak (j.olszak@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Jan Olszak (j.olszak@samsung.com)
+ * @brief   Visitor for loading from FDStore
+ */
+
+#ifndef COMMON_CONFIG_FROM_FDSTORE_VISITOR_HPP
+#define COMMON_CONFIG_FROM_FDSTORE_VISITOR_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/fdstore.hpp"
+
+#include <string>
+
+namespace config {
+
+class FromFDStoreVisitor {
+public:
+    explicit FromFDStoreVisitor(int fd)
+        : mStore(fd)
+    {
+    }
+
+    FromFDStoreVisitor(const FromFDStoreVisitor&) = default;
+
+    FromFDStoreVisitor& operator=(const FromFDStoreVisitor&) = delete;
+
+    template<typename T>
+    void visit(const std::string&, T& value)
+    {
+        readInternal(value);
+    }
+
+private:
+    FDStore mStore;
+
+    void readInternal(std::string& value)
+    {
+        size_t size;
+        readInternal(size);
+        value.resize(size);
+        mStore.read(&value.front(), size);
+    }
+
+    template<typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
+    void readInternal(T& value)
+    {
+        mStore.read(&value, sizeof(T));
+    }
+
+    template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
+    void readInternal(T& value)
+    {
+        FromFDStoreVisitor visitor(*this);
+        value.accept(visitor);
+    }
+
+    template<typename T>
+    void readInternal(std::vector<T>& values)
+    {
+        size_t vectorSize;
+        readInternal(vectorSize);
+        values.resize(vectorSize);
+
+        for (T& value : values) {
+            readInternal(value);
+        }
+    }
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_FROM_FDSTORE_VISITOR_HPP
diff --git a/common/config/from-gvariant-visitor.hpp b/common/config/from-gvariant-visitor.hpp
new file mode 100644 (file)
index 0000000..040dcae
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki (m.malicki2@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   GVariant visitor
+ */
+
+#ifndef COMMON_CONFIG_FROM_GVARIANT_VISITOR_HPP
+#define COMMON_CONFIG_FROM_GVARIANT_VISITOR_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/exception.hpp"
+#include "config/is-union.hpp"
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <cassert>
+#include <glib.h>
+
+namespace config {
+
+class FromGVariantVisitor {
+public:
+    explicit FromGVariantVisitor(GVariant* variant)
+    {
+        //Assume that the visited object is not a union
+        checkType(variant, G_VARIANT_TYPE_TUPLE);
+        mIter = g_variant_iter_new(variant);
+    }
+
+    FromGVariantVisitor(const FromGVariantVisitor& visitor)
+        : mIter(g_variant_iter_copy(visitor.mIter))
+    {
+    }
+
+    ~FromGVariantVisitor()
+    {
+        g_variant_iter_free(mIter);
+    }
+
+    FromGVariantVisitor& operator=(const FromGVariantVisitor&) = delete;
+
+    template<typename T>
+    void visit(const std::string& name, T& value)
+    {
+        auto child = makeUnique(g_variant_iter_next_value(mIter));
+        if (!child) {
+            throw config::ConfigException(
+                "GVariant doesn't match with config. Can't set  '" + name + "'");
+        }
+        fromGVariant(child.get(), value);
+    }
+
+private:
+    GVariantIter* mIter;
+
+    static std::unique_ptr<GVariant, decltype(&g_variant_unref)> makeUnique(GVariant* variant)
+    {
+        return std::unique_ptr<GVariant, decltype(&g_variant_unref)>(variant, g_variant_unref);
+    }
+
+    static void checkType(GVariant* object, const GVariantType* type)
+    {
+        if (!g_variant_is_of_type(object, type)) {
+            throw ConfigException("Invalid field type");
+        }
+    }
+
+    static void fromGVariant(GVariant* object, std::int32_t& value)
+    {
+        checkType(object, G_VARIANT_TYPE_INT32);
+        value = g_variant_get_int32(object);
+    }
+
+    static void fromGVariant(GVariant* object, std::int64_t& value)
+    {
+        checkType(object, G_VARIANT_TYPE_INT64);
+        value = g_variant_get_int64(object);
+    }
+
+    static void fromGVariant(GVariant* object, std::uint32_t& value)
+    {
+        checkType(object, G_VARIANT_TYPE_UINT32);
+        value = g_variant_get_uint32(object);
+    }
+
+    static void fromGVariant(GVariant* object, std::uint64_t& value)
+    {
+        checkType(object, G_VARIANT_TYPE_UINT64);
+        value = g_variant_get_uint64(object);
+    }
+
+    static void fromGVariant(GVariant* object, bool& value)
+    {
+        checkType(object, G_VARIANT_TYPE_BOOLEAN);
+        value = g_variant_get_boolean(object);
+    }
+
+    static void fromGVariant(GVariant* object, double& value)
+    {
+        checkType(object, G_VARIANT_TYPE_DOUBLE);
+        value = g_variant_get_double(object);
+    }
+
+    static void fromGVariant(GVariant* object, std::string& value)
+    {
+        checkType(object, G_VARIANT_TYPE_STRING);
+        value = g_variant_get_string(object, NULL);
+    }
+
+    template<typename T>
+    static void fromGVariant(GVariant* object, std::vector<T>& value)
+    {
+        checkType(object, G_VARIANT_TYPE_ARRAY);
+        GVariantIter iter;
+        g_variant_iter_init(&iter, object);
+        int length = g_variant_iter_n_children(&iter);
+        value.resize(static_cast<size_t>(length));
+        for (int i = 0; i < length; ++i) {
+            auto child = makeUnique(g_variant_iter_next_value(&iter));
+            assert(child);
+            fromGVariant(child.get(), value[static_cast<size_t>(i)]);
+        }
+    }
+
+    template<typename T>
+    static typename std::enable_if<isUnion<T>::value>::type
+    fromGVariant(GVariant* object, T& value)
+    {
+        checkType(object, G_VARIANT_TYPE_VARIANT);
+        auto inner = makeUnique(g_variant_get_variant(object));
+
+        FromGVariantVisitor visitor(inner.get());
+        value.accept(visitor);
+    }
+
+    template<typename T>
+    static typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value>::type
+    fromGVariant(GVariant* object, T& value)
+    {
+        FromGVariantVisitor visitor(object);
+        value.accept(visitor);
+    }
+
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_FROM_GVARIANT_VISITOR_HPP
diff --git a/common/config/from-json-visitor.hpp b/common/config/from-json-visitor.hpp
new file mode 100644 (file)
index 0000000..2934adf
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   JSON visitor
+ */
+
+#ifndef COMMON_CONFIG_FROM_JSON_VISITOR_HPP
+#define COMMON_CONFIG_FROM_JSON_VISITOR_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/exception.hpp"
+
+#include <json/json.h>
+#include <string>
+#include <vector>
+
+namespace config {
+
+class FromJsonVisitor {
+public:
+    explicit FromJsonVisitor(const std::string& jsonString)
+        : mObject(nullptr)
+    {
+        mObject = json_tokener_parse(jsonString.c_str());
+        if (mObject == nullptr) {
+            throw ConfigException("Json parsing error");
+        }
+    }
+
+    FromJsonVisitor(const FromJsonVisitor& visitor)
+        : mObject(json_object_get(visitor.mObject))
+    {
+    }
+
+    ~FromJsonVisitor()
+    {
+        json_object_put(mObject);
+    }
+
+    FromJsonVisitor& operator=(const FromJsonVisitor&) = delete;
+
+    template<typename T>
+    void visit(const std::string& name, T& value)
+    {
+        json_object* object = nullptr;
+        if (!json_object_object_get_ex(mObject, name.c_str(), &object)) {
+            throw ConfigException("Missing field '" + name + "'");
+        }
+        fromJsonObject(object, value);
+    }
+
+private:
+    json_object* mObject;
+
+
+    explicit FromJsonVisitor(json_object* object)
+        : mObject(json_object_get(object))
+    {
+    }
+
+    static void checkType(json_object* object, json_type type)
+    {
+        if (type != json_object_get_type(object)) {
+            throw ConfigException("Invalid field type");
+        }
+    }
+
+    static void fromJsonObject(json_object* object, std::int32_t& value)
+    {
+        checkType(object, json_type_int);
+        std::int64_t value64 = json_object_get_int64(object);
+        if (value64 > INT32_MAX || value64 < INT32_MIN) {
+            throw ConfigException("Value out of range");
+        }
+        value = static_cast<std::int32_t>(value64);
+    }
+
+    static void fromJsonObject(json_object* object, std::uint32_t& value)
+    {
+        checkType(object, json_type_int);
+        std::int64_t value64 = json_object_get_int64(object);
+        if (value64 > UINT32_MAX || value64 < 0) {
+            throw ConfigException("Value out of range");
+        }
+        value = static_cast<std::uint32_t>(value64);
+    }
+
+    static void fromJsonObject(json_object* object, std::int64_t& value)
+    {
+        checkType(object, json_type_int);
+        value = json_object_get_int64(object);
+    }
+
+    static void fromJsonObject(json_object* object, std::uint64_t& value)
+    {
+        checkType(object, json_type_int);
+        std::int64_t value64 = json_object_get_int64(object);
+        if (value64 < 0) {
+            throw ConfigException("Value out of range");
+        }
+        value = static_cast<std::uint64_t>(value64);
+    }
+
+    static void fromJsonObject(json_object* object, bool& value)
+    {
+        checkType(object, json_type_boolean);
+        value = json_object_get_boolean(object);
+    }
+
+    static void fromJsonObject(json_object* object, double& value)
+    {
+        checkType(object, json_type_double);
+        value = json_object_get_double(object);
+    }
+
+    static void fromJsonObject(json_object* object, std::string& value)
+    {
+        checkType(object, json_type_string);
+        value = json_object_get_string(object);
+    }
+
+    template<typename T>
+    static void fromJsonObject(json_object* object, std::vector<T>& value)
+    {
+        checkType(object, json_type_array);
+        int length = json_object_array_length(object);
+        value.resize(static_cast<size_t>(length));
+        for (int i = 0; i < length; ++i) {
+            fromJsonObject(json_object_array_get_idx(object, i), value[static_cast<size_t>(i)]);
+        }
+    }
+
+    template<typename T, class = typename std::enable_if<isVisitable<T>::value>::type>
+    static void fromJsonObject(json_object* object, T& value)
+    {
+        checkType(object, json_type_object);
+        FromJsonVisitor visitor(object);
+        value.accept(visitor);
+    }
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_FROM_JSON_VISITOR_HPP
diff --git a/common/config/from-kvjson-visitor.hpp b/common/config/from-kvjson-visitor.hpp
new file mode 100644 (file)
index 0000000..35e1bf7
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Krzysztof Dynowski (k.dynowski@samsumg.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+
+/**
+ * @file
+ * @author  Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief   KVStore visitor with defaults values from json
+ */
+
+#ifndef COMMON_CONFIG_FROM_KVJSON_VISITOR_HPP
+#define COMMON_CONFIG_FROM_KVJSON_VISITOR_HPP
+
+#include "config/from-kvstore-visitor.hpp"
+#include "config/is-union.hpp"
+#include <json/json.h>
+
+namespace config {
+
+class FromKVJsonVisitor {
+public:
+    FromKVJsonVisitor(KVStore& store, const std::string& json, const std::string& prefix)
+        : mStore(store)
+        , mKeyPrefix(prefix)
+        , mIsUnion(false)
+    {
+        mObject = json_tokener_parse(json.c_str());
+        if (mObject == nullptr) {
+            throw ConfigException("Json parsing error");
+        }
+    }
+
+
+    ~FromKVJsonVisitor() {
+        json_object_put(mObject);
+    }
+
+    FromKVJsonVisitor(const FromKVJsonVisitor& v) :
+        mStore(v.mStore),
+        mKeyPrefix(v.mKeyPrefix),
+        mObject(v.mObject ? json_object_get(v.mObject) : nullptr),
+        mIsUnion(v.mIsUnion)
+    {
+    }
+    FromKVJsonVisitor& operator=(const FromKVJsonVisitor&) = delete;
+
+    template<typename T>
+    void visit(const std::string& name, T& value) {
+        getValue(name, value);
+    }
+
+private:
+    KVStore& mStore;
+    std::string mKeyPrefix;
+    json_object* mObject;
+    bool mIsUnion;
+
+    // create visitor for field object (visitable object)
+    FromKVJsonVisitor(const FromKVJsonVisitor& v, const std::string& name, const bool isUnion) :
+        mStore(v.mStore),
+        mKeyPrefix(key(v.mKeyPrefix, name)),
+        mIsUnion(isUnion || v.mIsUnion)
+    {
+        json_object* object = nullptr;
+        if (v.mObject && !json_object_object_get_ex(v.mObject, name.c_str(), &object)) {
+            if (!mIsUnion)
+                throw ConfigException("Missing json field " + mKeyPrefix);
+        }
+        mObject = object ? json_object_get(object) : nullptr;
+    }
+
+    // create visitor for vector i-th element (visitable object)
+    FromKVJsonVisitor(const FromKVJsonVisitor& v, int i, const bool isUnion) :
+        mStore(v.mStore),
+        mKeyPrefix(key(v.mKeyPrefix, std::to_string(i))),
+        mIsUnion(isUnion || v.mIsUnion)
+    {
+        json_object* object = nullptr;
+        if (v.mObject) {
+            object = json_object_array_get_idx(v.mObject, i);
+            checkType(object, json_type_object);
+        }
+        mObject = object ? json_object_get(object) : nullptr;
+    }
+
+    template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
+    void getValue(const std::string& name, T& t)
+    {
+        std::string k = key(mKeyPrefix, name);
+        if (mStore.exists(k)) {
+            t = mStore.get<T>(k);
+        }
+        else {
+            json_object* object = nullptr;
+            if (mObject) {
+                json_object_object_get_ex(mObject, name.c_str(), &object);
+            }
+            if (!object) {
+                throw ConfigException("Missing json field " + key(mKeyPrefix, name));
+            }
+            fromJsonObject(object, t);
+        }
+    }
+
+    template<typename T, typename std::enable_if<isUnion<T>::value, int>::type = 0>
+    void getValue(const std::string& name, T& t)
+    {
+        FromKVJsonVisitor visitor(*this, name, true);
+        t.accept(visitor);
+    }
+
+    template<typename T, typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value, int>::type = 0>
+    void getValue(const std::string& name, T& t)
+    {
+        FromKVJsonVisitor visitor(*this, name, false);
+        t.accept(visitor);
+    }
+
+    int getArraySize(std::string& name, json_object* object)
+    {
+        if (mStore.exists(name)) {
+            return mStore.get<int>(name);
+        }
+        if (object) {
+            return json_object_array_length(object);
+        }
+        return -1;
+    }
+
+    template<typename T>
+    void getValue(const std::string& name, std::vector<T>& value)
+    {
+        json_object* object = nullptr;
+        if (mObject && json_object_object_get_ex(mObject, name.c_str(), &object)) {
+            checkType(object, json_type_array);
+        }
+
+        std::string k = key(mKeyPrefix, name);
+        int length = getArraySize(k, object);
+        if (length < 0) {
+            throw ConfigException("Missing array length " + k);
+        }
+        value.resize(static_cast<size_t>(length));
+        FromKVJsonVisitor visitor(*this, name, false);
+        if (mStore.exists(k)) {
+            json_object_put(visitor.mObject);
+            visitor.mObject = nullptr;
+        }
+        for (int i = 0; i < length; ++i) {
+            visitor.getValue(i, value[i]);
+        }
+    }
+
+    template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
+    void getValue(int i, T& t)
+    {
+        std::string k = key(mKeyPrefix, std::to_string(i));
+        if (mStore.exists(k)) {
+            t = mStore.get<T>(k);
+        }
+        else {
+            json_object* object = mObject ? json_object_array_get_idx(mObject, i) : nullptr;
+            if (!object) {
+                throw ConfigException("Missing json array elem " + k);
+            }
+            fromJsonObject(object, t);
+        }
+    }
+
+    template<typename T, typename std::enable_if<isUnion<T>::value, int>::type = 0>
+    void getValue(int i, T& t)
+    {
+        FromKVJsonVisitor visitor(*this, i, true);
+        t.accept(visitor);
+    }
+
+    template<typename T, typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value, int>::type = 0>
+    void getValue(int i, T& t)
+    {
+        FromKVJsonVisitor visitor(*this, i, false);
+        t.accept(visitor);
+    }
+
+    template<typename T>
+    void getValue(int i, std::vector<T>& value)
+    {
+        std::string k = key(mKeyPrefix, std::to_string(i));
+        int length = getArraySize(k, mObject);
+        value.resize(static_cast<size_t>(length));
+        FromKVJsonVisitor visitor(*this, i, false);
+        if (mStore.exists(k)) {
+            json_object_put(visitor.mObject);
+            visitor.mObject = nullptr;
+        }
+        for (int i = 0; i < length; ++i) {
+            visitor.getValue(i, value[i]);
+        }
+    }
+
+    static void checkType(json_object* object, json_type type)
+    {
+        if (type != json_object_get_type(object)) {
+            throw ConfigException("Invalid field type " + std::to_string(type));
+        }
+    }
+
+    static void fromJsonObject(json_object* object, int& value)
+    {
+        checkType(object, json_type_int);
+        std::int64_t value64 = json_object_get_int64(object);
+        if (value64 > INT32_MAX || value64 < INT32_MIN) {
+            throw ConfigException("Value out of range");
+        }
+        value = static_cast<int>(value64);
+    }
+
+    static void fromJsonObject(json_object* object, std::int64_t& value)
+    {
+        checkType(object, json_type_int);
+        value = json_object_get_int64(object);
+    }
+
+    static void fromJsonObject(json_object* object, std::uint32_t& value)
+    {
+        checkType(object, json_type_int);
+        std::int64_t value64 = json_object_get_int64(object);
+        if (value64 > UINT32_MAX || value64 < 0) {
+            throw ConfigException("Value out of range");
+        }
+        value = static_cast<std::uint32_t>(value64);
+    }
+
+    static void fromJsonObject(json_object* object, std::uint64_t& value)
+    {
+        checkType(object, json_type_int);
+        std::int64_t value64 = json_object_get_int64(object);
+        if (value64 < 0) {
+            throw ConfigException("Value out of range");
+        }
+        value = static_cast<std::uint64_t>(value64);
+    }
+
+    static void fromJsonObject(json_object* object, bool& value)
+    {
+        checkType(object, json_type_boolean);
+        value = json_object_get_boolean(object);
+    }
+
+    static void fromJsonObject(json_object* object, double& value)
+    {
+        checkType(object, json_type_double);
+        value = json_object_get_double(object);
+    }
+
+    static void fromJsonObject(json_object* object, std::string& value)
+    {
+        checkType(object, json_type_string);
+        value = json_object_get_string(object);
+    }
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_FROM_KVJSON_VISITOR_HPP
diff --git a/common/config/from-kvstore-visitor.hpp b/common/config/from-kvstore-visitor.hpp
new file mode 100644 (file)
index 0000000..56bcd14
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak (j.olszak@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Jan Olszak (j.olszak@samsung.com)
+ * @brief   Visitor for loading from KVStore
+ */
+
+#ifndef COMMON_CONFIG_FROM_KVSTORE_VISITOR_HPP
+#define COMMON_CONFIG_FROM_KVSTORE_VISITOR_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/kvstore.hpp"
+
+namespace config {
+
+class FromKVStoreVisitor {
+public:
+    FromKVStoreVisitor(KVStore& store, const std::string& prefix)
+        : mStore(store),
+          mKeyPrefix(prefix)
+    {
+    }
+
+    FromKVStoreVisitor& operator=(const FromKVStoreVisitor&) = delete;
+
+    template<typename T>
+    void visit(const std::string& name, T& value)
+    {
+        getInternal(key(mKeyPrefix, name), value);
+    }
+
+private:
+    KVStore& mStore;
+    std::string mKeyPrefix;
+
+    FromKVStoreVisitor(const FromKVStoreVisitor& visitor, const std::string& prefix)
+        : mStore(visitor.mStore),
+          mKeyPrefix(prefix)
+    {
+    }
+
+    template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
+    void getInternal(const std::string& name, T& value)
+    {
+        value = mStore.get<T>(name);
+    }
+
+    template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
+    void getInternal(const std::string& name, T& value)
+    {
+        FromKVStoreVisitor visitor(*this, name);
+        value.accept(visitor);
+    }
+
+    template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
+    void getInternal(const std::string& name, std::vector<T>& values)
+    {
+        values.clear();
+
+        size_t vectorSize = mStore.get<size_t>(name);
+        if (vectorSize == 0) {
+            return;
+        }
+
+        values.resize(vectorSize);
+        for (size_t i = 0; i < vectorSize; ++i) {
+            const std::string k = key(name, std::to_string(i));
+            getInternal(k, values[i]);
+        }
+    }
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_FROM_KVSTORE_VISITOR_HPP
diff --git a/common/config/fs-utils.cpp b/common/config/fs-utils.cpp
new file mode 100644 (file)
index 0000000..1b08dce
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   Filesystem helper functions
+ */
+
+#include "config/fs-utils.hpp"
+
+#include <fstream>
+#include <streambuf>
+
+
+namespace config {
+namespace fsutils {
+
+bool readFileContent(const std::string& path, std::string& result)
+{
+    std::ifstream file(path);
+
+    if (!file) {
+        return false;
+    }
+
+    file.seekg(0, std::ios::end);
+    std::streampos length = file.tellg();
+    if (length < 0) {
+        return false;
+    }
+    result.resize(static_cast<size_t>(length));
+    file.seekg(0, std::ios::beg);
+
+    file.read(&result[0], length);
+    if (!file) {
+        result.clear();
+        return false;
+    }
+
+    return true;
+}
+
+bool saveFileContent(const std::string& path, const std::string& content)
+{
+    std::ofstream file(path);
+    if (!file) {
+        return false;
+    }
+    file.write(content.data(), static_cast<std::streamsize>(content.size()));
+    if (!file) {
+        return false;
+    }
+    return true;
+}
+
+} // namespace fsutils
+} // namespace config
diff --git a/common/config/fs-utils.hpp b/common/config/fs-utils.hpp
new file mode 100644 (file)
index 0000000..a9dccec
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   src/config/manager.hpp
+ */
+
+#ifndef COMMON_CONFIG_FS_UTILS_HPP
+#define COMMON_CONFIG_FS_UTILS_HPP
+
+#include <string>
+
+namespace config {
+namespace fsutils {
+
+bool readFileContent(const std::string& path, std::string& result);
+bool saveFileContent(const std::string& path, const std::string& content);
+
+inline std::string readFileContent(const std::string& path) {
+    std::string content;
+    return readFileContent(path, content) ? content : std::string();
+}
+} // namespace fsutils
+} // namespace config
+
+#endif // COMMON_CONFIG_FS_UTILS_HPP
diff --git a/common/config/is-union.hpp b/common/config/is-union.hpp
new file mode 100644 (file)
index 0000000..63636ec
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief   Internal configuration helper
+ */
+
+#ifndef COMMON_CONFIG_IS_UNION_HPP
+#define COMMON_CONFIG_IS_UNION_HPP
+
+#include "config/is-visitable.hpp"
+
+namespace config {
+
+// generic member checker, start
+template <typename T, typename F>
+struct has_member_impl {
+    template <typename C>
+    static std::true_type check(typename F::template checker__<C>* =0);
+
+    template <typename C>
+    static std::false_type check(...);
+
+    static const bool value = std::is_same<decltype(check<T>(0)), std::true_type>::value;
+};
+
+template <typename T, typename F>
+struct has_member : public std::integral_constant<bool, has_member_impl<T, F>::value> {};
+// generic member checker, end
+
+
+template <typename X>
+struct check_union : isVisitable<X> {
+    template <typename T,
+         //list of function union must implement
+         const X& (T::*)() const = &T::as,
+         X& (T::*)(const X& src) = &T::set,
+         bool (T::*)() = &T::isSet
+    >
+    struct checker__ {};
+};
+template<typename T>
+struct isUnion : has_member<T, check_union<T>> {};
+
+//Note:
+// unfortunately, above generic has_member can't be used for isVisitable
+// because Vistable need 'accept' OR 'accept const', while has_member make exect match
+// e.g accept AND accept const
+
+} // namespace config
+
+#endif // COMMON_CONFIG_IS_UNION_HPP
+
diff --git a/common/config/is-visitable.hpp b/common/config/is-visitable.hpp
new file mode 100644 (file)
index 0000000..d63069f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   Internal configuration helper
+ */
+
+#ifndef COMMON_CONFIG_IS_VISITABLE_HPP
+#define COMMON_CONFIG_IS_VISITABLE_HPP
+
+#include <type_traits>
+
+namespace config {
+
+template <typename T>
+struct isVisitableHelper__ {
+    struct Visitor {};
+
+    template <typename C> static std::true_type
+    test(decltype(std::declval<C>().template accept(Visitor()))*);
+
+    template <typename C> static std::false_type
+    test(...);
+
+    static constexpr bool value = std::is_same<decltype(test<T>(0)), std::true_type>::value;
+};
+
+/**
+ * Helper for compile-time checking against existance of template method 'accept'.
+ */
+template <typename T>
+struct isVisitable : public std::integral_constant<bool, isVisitableHelper__<T>::value> {};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_IS_VISITABLE_HPP
diff --git a/common/config/kvstore.cpp b/common/config/kvstore.cpp
new file mode 100644 (file)
index 0000000..49656ae
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak <j.olszak@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief  Definition of a class for key-value storage in a sqlite3 database
+ */
+
+#include "config.hpp"
+
+#include "config/kvstore.hpp"
+#include "config/exception.hpp"
+
+#include <exception>
+#include <limits>
+#include <memory>
+#include <set>
+#include <cassert>
+
+namespace config {
+
+namespace {
+
+const int AUTO_DETERM_SIZE = -1;
+const int FIRST_COLUMN = 0;
+
+struct ScopedReset {
+    ScopedReset(std::unique_ptr<sqlite3::Statement>& stmtPtr)
+        : mStmtPtr(stmtPtr) {}
+    ~ScopedReset()
+    {
+        mStmtPtr->reset();
+    }
+private:
+    std::unique_ptr<sqlite3::Statement>& mStmtPtr;
+};
+
+/**
+ * Escape characters used by the GLOB function.
+ */
+void sqliteEscapeStr(::sqlite3_context* context, int argc, ::sqlite3_value** values)
+{
+    char* inBuff = (char*)sqlite3_value_text(values[0]);
+    if (argc != 1 || inBuff == NULL) {
+        sqlite3_result_error(context, "SQL function escapeSequence() called with invalid arguments.\n", -1);
+        return;
+    }
+
+    std::string in(inBuff);
+    static const std::set<char> toEscape({'?', '*', '[', ']'});
+
+    // Compute the out size
+    auto isEscapeChar = [&](char c) {
+        return toEscape.count(c) == 1;
+    };
+    size_t numEscape = std::count_if(in.begin(),
+                                     in.end(),
+                                     isEscapeChar);
+    if (numEscape == 0) {
+        sqlite3_result_text(context, in.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT);
+    }
+
+    // Escape characters
+    std::string out(in.size() + 2 * numEscape, 'x');
+    for (size_t i = 0, j = 0;
+            i < in.size();
+            ++i, ++j) {
+        if (isEscapeChar(in[i])) {
+            out[j] = '[';
+            ++j;
+            out[j] = in[i];
+            ++j;
+            out[j] = ']';
+        } else {
+            out[j] = in[i];
+        }
+    }
+    sqlite3_result_text(context, out.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT);
+}
+
+} // namespace
+
+KVStore::Transaction::Transaction(KVStore& kvStore)
+    : mLock(kvStore.mMutex)
+    , mKVStore(kvStore)
+    , mIsOuter(kvStore.mTransactionDepth == 0)
+{
+    if (mKVStore.mIsTransactionCommited) {
+        throw ConfigException("Previous transaction is not closed");
+    }
+    if (mIsOuter) {
+        mKVStore.mConn.exec("BEGIN EXCLUSIVE TRANSACTION");
+    }
+    ++mKVStore.mTransactionDepth;
+}
+
+KVStore::Transaction::~Transaction()
+{
+    --mKVStore.mTransactionDepth;
+    if (mIsOuter) {
+        if (mKVStore.mIsTransactionCommited) {
+            mKVStore.mIsTransactionCommited = false;
+        } else {
+            mKVStore.mConn.exec("ROLLBACK TRANSACTION");
+        }
+    }
+}
+
+void KVStore::Transaction::commit()
+{
+    if (mKVStore.mIsTransactionCommited) {
+        throw ConfigException("Transaction already commited");
+    }
+    if (mIsOuter) {
+        mKVStore.mConn.exec("COMMIT TRANSACTION");
+        mKVStore.mIsTransactionCommited = true;
+    }
+}
+
+KVStore::KVStore(const std::string& path)
+    : mTransactionDepth(0),
+      mIsTransactionCommited(false),
+      mPath(path),
+      mConn(path)
+{
+    setupDb();
+    createFunctions();
+    prepareStatements();
+}
+
+KVStore::~KVStore()
+{
+    assert(mTransactionDepth == 0);
+}
+
+void KVStore::setupDb()
+{
+    // called only from ctor, transaction is not needed
+    mConn.exec("CREATE TABLE IF NOT EXISTS data (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
+}
+
+void KVStore::prepareStatements()
+{
+    mGetValueStmt.reset(
+        new sqlite3::Statement(mConn, "SELECT value FROM data WHERE key = ? LIMIT 1"));
+    mGetKeyExistsStmt.reset(
+        // following line left in comment to have example of any subkey matching
+        //new sqlite3::Statement(mConn, "SELECT 1 FROM data WHERE key = ?1 OR key GLOB escapeStr(?1) || '.*' LIMIT 1"));
+        new sqlite3::Statement(mConn, "SELECT 1 FROM data WHERE key = ?1  LIMIT 1"));
+    mGetIsEmptyStmt.reset(
+        new sqlite3::Statement(mConn, "SELECT 1 FROM data LIMIT 1"));
+    mSetValueStmt.reset(
+        new sqlite3::Statement(mConn, "INSERT OR REPLACE INTO data (key, value) VALUES (?,?)"));
+    mRemoveValuesStmt.reset(
+        new sqlite3::Statement(mConn, "DELETE FROM data WHERE key = ?1  OR key GLOB escapeStr(?1) ||'.*' "));
+    mGetKeysStmt.reset(
+        new sqlite3::Statement(mConn, "SELECT key FROM data"));
+}
+
+void KVStore::createFunctions()
+{
+    int ret = sqlite3_create_function(mConn.get(), "escapeStr", 1, SQLITE_ANY, 0, &sqliteEscapeStr, 0, 0);
+    if (ret != SQLITE_OK) {
+        throw ConfigException("Error during creating functions: " + mConn.getErrorMessage());
+    }
+}
+
+void KVStore::clear()
+{
+    Transaction transaction(*this);
+    mConn.exec("DELETE FROM data");
+    transaction.commit();
+}
+
+bool KVStore::isEmpty()
+{
+    Transaction transaction(*this);
+    ScopedReset scopedReset(mGetIsEmptyStmt);
+
+    int ret = ::sqlite3_step(mGetIsEmptyStmt->get());
+    if (ret != SQLITE_DONE && ret != SQLITE_ROW) {
+        throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
+    }
+
+    transaction.commit();
+    return ret == SQLITE_DONE;
+}
+
+bool KVStore::exists(const std::string& key)
+{
+    Transaction transaction(*this);
+    ScopedReset scopedReset(mGetKeyExistsStmt);
+
+    ::sqlite3_bind_text(mGetKeyExistsStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT);
+
+    int ret = ::sqlite3_step(mGetKeyExistsStmt->get());
+    if (ret != SQLITE_DONE && ret != SQLITE_ROW) {
+        throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
+    }
+
+    transaction.commit();
+    return ret == SQLITE_ROW;
+}
+
+void KVStore::remove(const std::string& key)
+{
+    Transaction transaction(*this);
+    ScopedReset scopedReset(mRemoveValuesStmt);
+
+    ::sqlite3_bind_text(mRemoveValuesStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC);
+
+    if (::sqlite3_step(mRemoveValuesStmt->get()) != SQLITE_DONE) {
+        throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
+    }
+    transaction.commit();
+}
+
+void KVStore::setInternal(const std::string& key, const std::string& value)
+{
+    Transaction transaction(*this);
+    ScopedReset scopedReset(mSetValueStmt);
+
+    ::sqlite3_bind_text(mSetValueStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC);
+    ::sqlite3_bind_text(mSetValueStmt->get(), 2, value.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC);
+
+
+    if (::sqlite3_step(mSetValueStmt->get()) != SQLITE_DONE) {
+        throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
+    }
+    transaction.commit();
+}
+
+void KVStore::setInternal(const std::string& key, const std::initializer_list<std::string>& values)
+{
+    setInternal(key, std::vector<std::string>(values));
+}
+
+void KVStore::setInternal(const std::string& key, const std::vector<std::string>& values)
+{
+    if (values.size() > std::numeric_limits<unsigned int>::max()) {
+        throw ConfigException("Too many values to insert");
+    }
+
+    Transaction transaction(*this);
+
+    remove(key);
+
+    // Save vector's capacity
+    setInternal(key, values.size());
+
+    // Save vector's elements
+    for (unsigned int i = 0; i < values.size(); ++i) {
+        setInternal(config::key(key, std::to_string(i)),
+                    values[i]);
+    }
+    transaction.commit();
+}
+
+std::string KVStore::getInternal(const std::string& key, std::string*)
+{
+    Transaction transaction(*this);
+    ScopedReset scopedReset(mGetValueStmt);
+
+    ::sqlite3_bind_text(mGetValueStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT);
+
+    int ret = ::sqlite3_step(mGetValueStmt->get());
+    if (ret == SQLITE_DONE) {
+        throw ConfigException("No value corresponding to the key: " + key + "@" + mPath);
+    }
+    if (ret != SQLITE_ROW) {
+        throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
+    }
+
+    std::string value = reinterpret_cast<const char*>(
+            sqlite3_column_text(mGetValueStmt->get(), FIRST_COLUMN));
+
+    transaction.commit();
+    return value;
+}
+
+std::vector<std::string> KVStore::getInternal(const std::string& key, std::vector<std::string>*)
+{
+    Transaction transaction(*this);
+
+    unsigned int valuesSize = get<unsigned int>(key);
+    std::vector<std::string> values(valuesSize);
+    if (valuesSize == 0) {
+        transaction.commit();
+        return values;
+    }
+
+    for (unsigned int i = 0; i < values.size(); ++i) {
+        values[i] = getInternal(config::key(key, std::to_string(i)),
+                                static_cast<std::string*>(nullptr));
+
+    }
+
+    transaction.commit();
+    return values;
+}
+
+std::vector<std::string> KVStore::getKeys()
+{
+    Transaction transaction(*this);
+    ScopedReset scopedReset(mGetKeysStmt);
+
+    std::vector<std::string> result;
+
+    for (;;) {
+        int ret = ::sqlite3_step(mGetKeysStmt->get());
+        if (ret == SQLITE_DONE) {
+            break;
+        }
+        if (ret != SQLITE_ROW) {
+            throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
+        }
+        const char* key = reinterpret_cast<const char*>(sqlite3_column_text(mGetKeysStmt->get(),
+                                                                            FIRST_COLUMN));
+        result.push_back(key);
+    }
+
+    transaction.commit();
+    return result;
+}
+
+} // namespace config
diff --git a/common/config/kvstore.hpp b/common/config/kvstore.hpp
new file mode 100644 (file)
index 0000000..0717665
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak <j.olszak@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief  Declaration of a class for key-value storage in a sqlite3 database
+ */
+
+#ifndef COMMON_CONFIG_KVSTORE_HPP
+#define COMMON_CONFIG_KVSTORE_HPP
+
+#include "config/sqlite3/connection.hpp"
+#include "config/sqlite3/statement.hpp"
+
+#include <algorithm>
+#include <initializer_list>
+#include <memory>
+#include <mutex>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <atomic>
+
+namespace config {
+
+class KVStore {
+
+public:
+    /**
+     * A guard struct for thread synchronization and transaction management.
+     */
+    class Transaction {
+    public:
+        Transaction(KVStore& store);
+        ~Transaction();
+
+        Transaction(const Transaction&) = delete;
+        Transaction& operator=(const Transaction&) = delete;
+
+        void commit();
+    private:
+        std::unique_lock<std::recursive_mutex> mLock;
+        KVStore& mKVStore;
+        bool mIsOuter;
+    };
+
+    /**
+     * @param path configuration database file path
+     */
+    explicit KVStore(const std::string& path);
+    ~KVStore();
+
+    KVStore(const KVStore&) = delete;
+    KVStore& operator=(const KVStore&) = delete;
+
+    /**
+     * Clears all the stored data
+     */
+    void clear();
+
+    /**
+     * @return Is there any data stored
+     */
+    bool isEmpty();
+
+    /**
+     * @param key string regexp of the stored values
+     *
+     * @return Does this key exist in the database
+     */
+    bool exists(const std::string& key);
+
+    /**
+     * Removes values corresponding to the passed key.
+     * Many values may correspond to one key, so many values may
+     * need to be deleted
+     *
+     * @param key string regexp of the stored values
+     */
+    void remove(const std::string& key);
+
+    /**
+     * Stores a single value corresponding to the passed key
+     *
+     * @param key string key of the value
+     * @param value value corresponding to the key
+     */
+    template<typename T>
+    void set(const std::string& key, const T& value)
+    {
+        return setInternal(key, value);
+    }
+
+    /**
+     * Gets the value corresponding to the key.
+     * Uses stringstreams to parse.
+     *
+     * @param key string key of the value
+     * @tparam T = std::string desired type of the return value
+     * @return value corresponding to the key
+     */
+    template<typename T = std::string>
+    T get(const std::string& key)
+    {
+        return getInternal(key, static_cast<T*>(nullptr));
+    }
+
+    /**
+     * Returns all stored keys.
+     */
+    std::vector<std::string> getKeys();
+
+private:
+    typedef std::lock_guard<std::recursive_mutex> Lock;
+
+    std::recursive_mutex mMutex;
+    size_t mTransactionDepth;
+    bool mIsTransactionCommited;
+
+    void setInternal(const std::string& key, const std::string& value);
+    void setInternal(const std::string& key, const std::initializer_list<std::string>& values);
+    void setInternal(const std::string& key, const std::vector<std::string>& values);
+    template<typename T>
+    void setInternal(const std::string& key, const T& value);
+    template<typename T>
+    void setInternal(const std::string& key, const std::vector<T>& values);
+
+    std::string getInternal(const std::string& key, std::string*);
+    std::vector<std::string> getInternal(const std::string& key, std::vector<std::string>*);
+    template<typename T>
+    T getInternal(const std::string& key, T*);
+    template<typename T>
+    std::vector<T> getInternal(const std::string& key, std::vector<T>*);
+
+    std::string mPath;
+    sqlite3::Connection mConn;
+    std::unique_ptr<sqlite3::Statement> mGetValueStmt;
+    std::unique_ptr<sqlite3::Statement> mGetKeyExistsStmt;
+    std::unique_ptr<sqlite3::Statement> mGetIsEmptyStmt;
+    std::unique_ptr<sqlite3::Statement> mGetValueListStmt;
+    std::unique_ptr<sqlite3::Statement> mSetValueStmt;
+    std::unique_ptr<sqlite3::Statement> mRemoveValuesStmt;
+    std::unique_ptr<sqlite3::Statement> mGetKeysStmt;
+
+    void setupDb();
+    void prepareStatements();
+    void createFunctions();
+};
+
+namespace {
+template<typename T>
+std::string toString(const T& value)
+{
+    std::ostringstream oss;
+    oss << value;
+    return oss.str();
+}
+
+template<typename T>
+T fromString(const std::string& strValue)
+{
+    std::istringstream iss(strValue);
+    T value;
+    iss >> value;
+    return value;
+}
+
+} // namespace
+
+template<typename T>
+void KVStore::setInternal(const std::string& key, const T& value)
+{
+    setInternal(key, toString(value));
+}
+
+template<typename T>
+void KVStore::setInternal(const std::string& key, const std::vector<T>& values)
+{
+    std::vector<std::string> strValues(values.size());
+
+    std::transform(values.begin(),
+                   values.end(),
+                   strValues.begin(),
+                   toString<T>);
+
+    setInternal(key, strValues);
+}
+
+template<typename T>
+T KVStore::getInternal(const std::string& key, T*)
+{
+    return fromString<T>(getInternal(key, static_cast<std::string*>(nullptr)));
+}
+
+template<typename T>
+std::vector<T> KVStore::getInternal(const std::string& key, std::vector<T>*)
+{
+    std::vector<std::string> strValues = getInternal(key, static_cast<std::vector<std::string>*>(nullptr));
+    std::vector<T> values(strValues.size());
+
+    std::transform(strValues.begin(),
+                   strValues.end(),
+                   values.begin(),
+                   fromString<T>);
+
+    return values;
+}
+
+/**
+ * Concatenates all parameters into one std::string.
+ * Uses '.' to connect the terms.
+ * @param args components of the string
+ * @tparam delim optional delimiter
+ * @tparam typename ... Args any type implementing str
+ * @return string created from he args
+ */
+template<char delim = '.', typename Arg1, typename ... Args>
+std::string key(const Arg1& a1, const Args& ... args)
+{
+    std::string ret = toString(a1);
+    std::initializer_list<std::string> strings {toString(args)...};
+    for (const std::string& s : strings) {
+        ret += delim + s;
+    }
+
+    return ret;
+}
+
+/**
+ * Function added for key function completeness.
+ *
+ * @tparam delim = '.' parameter not used, added for consistency
+ * @return empty string
+ */
+template<char delim = '.'>
+std::string key()
+{
+    return std::string();
+}
+
+} // namespace config
+
+#endif // COMMON_CONFIG_KVSTORE_HPP
+
+
diff --git a/common/config/manager.hpp b/common/config/manager.hpp
new file mode 100644 (file)
index 0000000..0deb8d8
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   Configuration management functions
+ */
+
+#ifndef COMMON_CONFIG_MANAGER_HPP
+#define COMMON_CONFIG_MANAGER_HPP
+
+#include "config/to-gvariant-visitor.hpp"
+#include "config/to-json-visitor.hpp"
+#include "config/to-kvstore-visitor.hpp"
+#include "config/to-fdstore-visitor.hpp"
+#include "config/from-gvariant-visitor.hpp"
+#include "config/from-json-visitor.hpp"
+#include "config/from-kvstore-visitor.hpp"
+#include "config/from-fdstore-visitor.hpp"
+#include "config/from-kvjson-visitor.hpp"
+#include "config/fs-utils.hpp"
+#include "config/is-union.hpp"
+
+namespace config {
+
+/**
+ * Fills the configuration with data stored in the GVariant
+ *
+ * @param gvariant   configuration in GVariant type
+ * @param config     visitable structure to fill
+ */
+template <class Config>
+void loadFromGVariant(GVariant* gvariant, Config& config)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+    static_assert(!isUnion<Config>::value, "Don't use CONFIG_DECLARE_UNION in top level config");
+
+    FromGVariantVisitor visitor(gvariant);
+    config.accept(visitor);
+}
+
+/**
+ * Saves the config in a GVariant
+ *
+ * @param config   visitable structure to convert
+ */
+template <class Config>
+GVariant* saveToGVariant(const Config& config)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+    static_assert(!isUnion<Config>::value, "Don't use CONFIG_DECLARE_UNION in top level config");
+
+    ToGVariantVisitor visitor;
+    config.accept(visitor);
+    return visitor.toVariant();
+}
+
+/**
+ * Fills the configuration with data stored in the json string
+ *
+ * @param jsonString configuration in a json format
+ * @param config     visitable structure to fill
+ */
+template <class Config>
+void loadFromJsonString(const std::string& jsonString, Config& config)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+
+    FromJsonVisitor visitor(jsonString);
+    config.accept(visitor);
+}
+
+/**
+ * Creates a string representation of the configuration in json format
+ *
+ * @param config   visitable structure to convert
+ */
+template <class Config>
+std::string saveToJsonString(const Config& config)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+
+    ToJsonVisitor visitor;
+    config.accept(visitor);
+    return visitor.toString();
+}
+
+/**
+ * Loads the config from a json file
+ *
+ * @param filename path to the file
+ * @param config   visitable structure to load
+ */
+template <class Config>
+void loadFromJsonFile(const std::string& filename, Config& config)
+{
+    std::string content;
+    if (!fsutils::readFileContent(filename, content)) {
+        throw ConfigException("Could not load " + filename);
+    }
+    try {
+        loadFromJsonString(content, config);
+    } catch (ConfigException& e) {
+        throw ConfigException("Error in " + filename + ": " + e.what());
+    }
+}
+
+/**
+ * Saves the config in a json file
+ *
+ * @param filename path to the file
+ * @param config   visitable structure to save
+ */
+template <class Config>
+void saveToJsonFile(const std::string& filename, const Config& config)
+{
+    const std::string content = saveToJsonString(config);
+    if (!fsutils::saveFileContent(filename, content)) {
+        throw ConfigException("Could not save " + filename);
+    }
+}
+
+/**
+ * Loads a visitable configuration from KVStore.
+ *
+ * @param filename   path to the KVStore db
+ * @param config     visitable structure to load
+ * @param configName name of the configuration inside the KVStore db
+ */
+template <class Config>
+void loadFromKVStore(const std::string& filename, Config& config, const std::string& configName)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+
+    KVStore store(filename);
+    KVStore::Transaction transaction(store);
+    FromKVStoreVisitor visitor(store, configName);
+    config.accept(visitor);
+    transaction.commit();
+}
+
+/**
+ * Saves the config to a KVStore.
+ *
+ * @param filename   path to the KVStore db
+ * @param config     visitable structure to save
+ * @param configName name of the config inside the KVStore db
+ */
+template <class Config>
+void saveToKVStore(const std::string& filename, const Config& config, const std::string& configName)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+
+    KVStore store(filename);
+    KVStore::Transaction transaction(store);
+    ToKVStoreVisitor visitor(store, configName);
+    config.accept(visitor);
+    transaction.commit();
+}
+
+/**
+ * Load the config from KVStore with defaults given in json
+ *
+ * @param kvfile    path to the KVStore db
+ * @param jsonfile  path to json file with defaults
+ * @param config    visitable structure to save
+ * @param kvConfigName name of the config inside the KVStore db
+ */
+template <class Config>
+void loadFromKVStoreWithJson(const std::string& kvfile,
+                             const std::string& json,
+                             Config& config,
+                             const std::string& kvConfigName)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+
+    KVStore store(kvfile);
+    KVStore::Transaction transaction(store);
+    FromKVJsonVisitor visitor(store, json, kvConfigName);
+    config.accept(visitor);
+    transaction.commit();
+}
+
+/**
+ * Load the config from KVStore with defaults given in json file
+ *
+ * @param kvfile    path to the KVStore db
+ * @param jsonfile  path to json file with defaults
+ * @param config    visitable structure to save
+ * @param kvConfigName name of the config inside the KVStore db
+ */
+template <class Config>
+void loadFromKVStoreWithJsonFile(const std::string& kvfile,
+                                 const std::string& jsonfile,
+                                 Config& config,
+                                 const std::string& kvConfigName)
+{
+    std::string content;
+    if (!fsutils::readFileContent(jsonfile, content)) {
+        throw ConfigException("Could not load " + jsonfile);
+    }
+    try {
+        loadFromKVStoreWithJson(kvfile, content, config, kvConfigName);
+    } catch (ConfigException& e) {
+        throw ConfigException("Error in " + jsonfile + ": " + e.what());
+    }
+}
+
+/**
+ * Load binary data from a file/socket/pipe represented by the fd
+ *
+ * @param fd file descriptor
+ * @param config visitable structure to load
+ */
+template <class Config>
+void loadFromFD(const int fd, Config& config)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+
+    FromFDStoreVisitor visitor(fd);
+    config.accept(visitor);
+}
+
+/**
+ * Save binary data to a file/socket/pipe represented by the fd
+ *
+ * @param fd file descriptor
+ * @param config visitable structure to save
+ */
+template <class Config>
+void saveToFD(const int fd, const Config& config)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+
+    ToFDStoreVisitor visitor(fd);
+    config.accept(visitor);
+}
+
+} // namespace config
+
+#endif // COMMON_CONFIG_MANAGER_HPP
diff --git a/common/config/sqlite3/connection.cpp b/common/config/sqlite3/connection.cpp
new file mode 100644 (file)
index 0000000..cb25694
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak <j.olszak@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief  Definition of the class managing a sqlite3 database connection
+ */
+
+
+#include "config/sqlite3/connection.hpp"
+#include "config/exception.hpp"
+
+namespace config {
+namespace sqlite3 {
+
+Connection::Connection(const std::string& path)
+{
+    if (path.empty()) {
+        // Sqlite creates temporary database in case of empty path
+        // but we want to forbid this.
+        throw ConfigException("Error opening the database: empty path");
+    }
+    if (::sqlite3_open_v2(path.c_str(),
+                          &mDbPtr,
+                          SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
+                          NULL) != SQLITE_OK) {
+        throw ConfigException("Error opening the database: " + getErrorMessage());
+    }
+
+    if (mDbPtr == NULL) {
+        throw ConfigException("Error opening the database: Unable to allocate memory.");
+    }
+}
+
+Connection::~Connection()
+{
+    if (::sqlite3_close(mDbPtr) != SQLITE_OK) {
+        throw ConfigException("Error during closing the database. Error: " + getErrorMessage());
+    }
+}
+
+void Connection::exec(const std::string& query)
+{
+    char* mess;
+    if (::sqlite3_exec(mDbPtr, query.c_str(), 0, 0, &mess) != SQLITE_OK) {
+        throw ConfigException("Error during executing statement " + std::string(mess));
+    }
+}
+
+::sqlite3* Connection::get()
+{
+    return mDbPtr;
+}
+
+std::string Connection::getErrorMessage()
+{
+    return std::string(sqlite3_errmsg(mDbPtr));
+}
+
+} // namespace sqlite3
+} // namespace config
diff --git a/common/config/sqlite3/connection.hpp b/common/config/sqlite3/connection.hpp
new file mode 100644 (file)
index 0000000..850332a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak <j.olszak@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief  Declaration of the class managing a sqlite3 database connection
+ */
+
+#ifndef COMMON_CONFIG_SQLITE3_CONNECTION_HPP
+#define COMMON_CONFIG_SQLITE3_CONNECTION_HPP
+
+#include <sqlite3.h>
+#include <string>
+
+namespace config {
+namespace sqlite3 {
+
+struct Connection {
+    /**
+     * @param path database file path
+     */
+    Connection(const std::string& path);
+    Connection(const Connection&) = delete;
+    ~Connection();
+
+    /**
+     * @return pointer to the corresponding sqlite3 database object
+     */
+    ::sqlite3* get();
+
+    /**
+     * @return last error message in the database
+     */
+    std::string getErrorMessage();
+
+    /**
+     * Executes the query in the database.
+     *
+     * @param query query to be executed
+     */
+    void exec(const std::string& query);
+
+private:
+    ::sqlite3* mDbPtr;
+};
+
+} // namespace sqlite3
+} // namespace config
+
+#endif // COMMON_CONFIG_SQLITE3_CONNECTION_HPP
diff --git a/common/config/sqlite3/statement.cpp b/common/config/sqlite3/statement.cpp
new file mode 100644 (file)
index 0000000..287cb1c
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak <j.olszak@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief  Definition of the class managing a sqlite3 statement
+ */
+
+#include "config/sqlite3/statement.hpp"
+#include "config/exception.hpp"
+
+
+namespace config {
+namespace sqlite3 {
+
+Statement::Statement(sqlite3::Connection& connRef, const std::string& query)
+    : mConnRef(connRef)
+{
+    if (::sqlite3_prepare_v2(connRef.get(),
+                             query.c_str(),
+                             query.size(),
+                             &mStmtPtr,
+                             NULL)
+            != SQLITE_OK) {
+        throw ConfigException("Error during preparing statement " +
+                              mConnRef.getErrorMessage());
+    }
+
+    if (mStmtPtr == NULL) {
+        throw ConfigException("Wrong query: " + query);
+    }
+}
+
+Statement::Statement::~Statement()
+{
+    if (::sqlite3_finalize(mStmtPtr) != SQLITE_OK) {
+        throw ConfigException("Error during finalizing statement " +
+                              mConnRef.getErrorMessage());
+    }
+}
+
+sqlite3_stmt* Statement::get()
+{
+    return mStmtPtr;
+}
+
+void Statement::reset()
+{
+    if (::sqlite3_clear_bindings(mStmtPtr) != SQLITE_OK) {
+        throw ConfigException("Error unbinding statement: " +
+                              mConnRef.getErrorMessage());
+    }
+
+    if (::sqlite3_reset(mStmtPtr) != SQLITE_OK) {
+        throw ConfigException("Error reseting statement: " +
+                              mConnRef.getErrorMessage());
+    }
+}
+
+} // namespace sqlite3
+} // namespace config
diff --git a/common/config/sqlite3/statement.hpp b/common/config/sqlite3/statement.hpp
new file mode 100644 (file)
index 0000000..48a1fca
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak <j.olszak@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief  Declaration of the class managing a sqlite3 statement
+ */
+
+#ifndef COMMON_CONFIG_SQLITE3_STATEMENT_HPP
+#define COMMON_CONFIG_SQLITE3_STATEMENT_HPP
+
+#include "config/sqlite3/connection.hpp"
+
+#include <sqlite3.h>
+#include <string>
+
+namespace config {
+namespace sqlite3 {
+
+struct Statement {
+
+    /**
+     * @param connRef reference to the Connection object
+     * @param query query to be executed
+     */
+    Statement(sqlite3::Connection& connRef, const std::string& query);
+    ~Statement();
+
+    /**
+     * @return pointer to the sqlite3 statement
+     */
+    sqlite3_stmt* get();
+
+    /**
+     * Clears the bindings and resets the statement.
+     * After this the statement can be executed again
+     */
+    void reset();
+
+private:
+    ::sqlite3_stmt* mStmtPtr;
+    sqlite3::Connection& mConnRef;
+};
+
+} // namespace sqlite3
+} // namespace config
+
+#endif // COMMON_CONFIG_SQLITE3_STATEMENT_HPP
+
+
diff --git a/common/config/to-fdstore-visitor.hpp b/common/config/to-fdstore-visitor.hpp
new file mode 100644 (file)
index 0000000..50756c1
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak (j.olszak@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Jan Olszak (j.olszak@samsung.com)
+ * @brief   Visitor for saving to FDStore
+ */
+
+#ifndef COMMON_CONFIG_TO_FDSTORE_VISITOR_HPP
+#define COMMON_CONFIG_TO_FDSTORE_VISITOR_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/fdstore.hpp"
+
+#include <string>
+
+namespace config {
+
+class ToFDStoreVisitor {
+
+public:
+    ToFDStoreVisitor(int fd)
+        : mStore(fd)
+    {
+    }
+
+    ToFDStoreVisitor(const ToFDStoreVisitor&) = default;
+
+    ToFDStoreVisitor& operator=(const ToFDStoreVisitor&) = delete;
+
+    template<typename T>
+    void visit(const std::string&, const T& value)
+    {
+        writeInternal(value);
+    }
+
+private:
+    FDStore mStore;
+
+    void writeInternal(const std::string& value)
+    {
+        writeInternal(value.size());
+        mStore.write(value.c_str(), value.size());
+    }
+
+    template<typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
+    void writeInternal(const T& value)
+    {
+        mStore.write(&value, sizeof(T));
+    }
+
+    template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
+    void writeInternal(const T& value)
+    {
+        ToFDStoreVisitor visitor(*this);
+        value.accept(visitor);
+    }
+
+    template<typename T>
+    void writeInternal(const std::vector<T>& values)
+    {
+        writeInternal(values.size());
+        for (const T& value : values) {
+            writeInternal(value);
+        }
+    }
+
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_TO_FDSTORE_VISITOR_HPP
diff --git a/common/config/to-gvariant-visitor.hpp b/common/config/to-gvariant-visitor.hpp
new file mode 100644 (file)
index 0000000..bb94e49
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki (m.malicki2@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   GVariant visitor
+ */
+
+#ifndef COMMON_CONFIG_TO_GVARIANT_VISITOR_HPP
+#define COMMON_CONFIG_TO_GVARIANT_VISITOR_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/is-union.hpp"
+
+#include <string>
+#include <vector>
+#include <glib.h>
+
+namespace config {
+
+class ToGVariantVisitor {
+
+public:
+    ToGVariantVisitor()
+        : mBuilder(g_variant_builder_new(G_VARIANT_TYPE_TUPLE))
+    {
+    }
+
+    ToGVariantVisitor(const ToGVariantVisitor& visitor)
+        : mBuilder(visitor.mBuilder ? g_variant_builder_ref(visitor.mBuilder) : nullptr)
+    {
+    }
+
+    ~ToGVariantVisitor()
+    {
+        if (mBuilder) {
+            g_variant_builder_unref(mBuilder);
+        }
+    }
+
+    ToGVariantVisitor& operator=(const ToGVariantVisitor&) = delete;
+
+    GVariant* toVariant()
+    {
+        if (mBuilder) {
+            GVariant* ret = g_variant_builder_end(mBuilder);
+            g_variant_builder_unref(mBuilder);
+            mBuilder = nullptr;
+            return ret;
+        }
+        return nullptr;
+    }
+
+    template<typename T>
+    void visit(const std::string& /* name */, const T& value)
+    {
+        writeInternal(value);
+    }
+private:
+    GVariantBuilder* mBuilder;
+
+    void writeInternal(std::int32_t value) { add("i", value); };
+    void writeInternal(std::int64_t value) { add("x", value); };
+    void writeInternal(std::uint32_t value) { add("u", value); };
+    void writeInternal(std::uint64_t value) { add("t", value); };
+    void writeInternal(bool value) { add("b", value); };
+    void writeInternal(double value) { add("d", value); };
+    void writeInternal(const std::string& value) { add("s", value.c_str()); };
+
+    template<typename T>
+    void writeInternal(const std::vector<T>& value)
+    {
+        if (!value.empty()) {
+            g_variant_builder_open(mBuilder, G_VARIANT_TYPE_ARRAY);
+            for (const T& v : value) {
+                writeInternal(v);
+            }
+            g_variant_builder_close(mBuilder);
+        } else {
+            g_variant_builder_add(mBuilder, "as", NULL);
+        }
+    }
+
+    template<typename T>
+    typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value>::type
+    writeInternal(const T& value)
+    {
+        ToGVariantVisitor visitor;
+        value.accept(visitor);
+        g_variant_builder_add_value(mBuilder, visitor.toVariant());
+    }
+
+    template<typename T>
+    typename std::enable_if<isVisitable<T>::value && isUnion<T>::value>::type
+    writeInternal(const T& value)
+    {
+        ToGVariantVisitor visitor;
+        value.accept(visitor);
+        add("v", visitor.toVariant());
+    }
+
+    template<typename Value>
+    void add(const char* type, Value value) {
+        g_variant_builder_add(mBuilder, type, value);
+    }
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_TO_GVARIANT_VISITOR_HPP
diff --git a/common/config/to-json-visitor.hpp b/common/config/to-json-visitor.hpp
new file mode 100644 (file)
index 0000000..f524900
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   JSON visitor
+ */
+
+#ifndef COMMON_CONFIG_TO_JSON_VISITOR_HPP
+#define COMMON_CONFIG_TO_JSON_VISITOR_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/exception.hpp"
+
+#include <json/json.h>
+#include <string>
+#include <vector>
+
+namespace config {
+
+class ToJsonVisitor {
+
+public:
+    ToJsonVisitor()
+        : mObject(json_object_new_object())
+    {
+    }
+
+    ToJsonVisitor(const ToJsonVisitor& visitor)
+        : mObject(json_object_get(visitor.mObject))
+    {
+    }
+
+    ~ToJsonVisitor()
+    {
+        json_object_put(mObject);
+    }
+
+    ToJsonVisitor& operator=(const ToJsonVisitor&) = delete;
+
+    std::string toString() const
+    {
+        return json_object_to_json_string(mObject);
+    }
+
+    template<typename T>
+    void visit(const std::string& name, const T& value)
+    {
+        json_object_object_add(mObject, name.c_str(), toJsonObject(value));
+    }
+private:
+    json_object* mObject;
+
+
+    json_object* detach()
+    {
+        json_object* ret = mObject;
+        mObject = nullptr;
+        return ret;
+    }
+
+    static json_object* toJsonObject(std::int32_t value)
+    {
+        return json_object_new_int(value);
+    }
+
+    static json_object* toJsonObject(std::int64_t value)
+    {
+        return json_object_new_int64(value);
+    }
+
+    static json_object* toJsonObject(std::uint32_t value)
+    {
+        if (value > INT32_MAX) {
+            throw ConfigException("Value out of range");
+        }
+        return json_object_new_int(value);
+    }
+
+    static json_object* toJsonObject(std::uint64_t value)
+    {
+        if (value > INT64_MAX) {
+            throw ConfigException("Value out of range");
+        }
+        return json_object_new_int64(value);
+    }
+
+    static json_object* toJsonObject(bool value)
+    {
+        return json_object_new_boolean(value);
+    }
+
+    static json_object* toJsonObject(double value)
+    {
+        return json_object_new_double(value);
+    }
+
+    static json_object* toJsonObject(const std::string& value)
+    {
+        return json_object_new_string(value.c_str());
+    }
+
+    template<typename T>
+    static json_object* toJsonObject(const std::vector<T>& value)
+    {
+        json_object* array = json_object_new_array();
+        for (const T& v : value) {
+            json_object_array_add(array, toJsonObject(v));
+        }
+        return array;
+    }
+
+    template<typename T, class = typename std::enable_if<isVisitable<T>::value>::type>
+    static json_object* toJsonObject(const T& value)
+    {
+        ToJsonVisitor visitor;
+        value.accept(visitor);
+        return visitor.detach();
+    }
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_TO_JSON_VISITOR_HPP
diff --git a/common/config/to-kvstore-visitor.hpp b/common/config/to-kvstore-visitor.hpp
new file mode 100644 (file)
index 0000000..14944dc
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak (j.olszak@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Jan Olszak (j.olszak@samsung.com)
+ * @brief   Visitor for saving to KVStore
+ */
+
+#ifndef COMMON_CONFIG_TO_KVSTORE_VISITOR_HPP
+#define COMMON_CONFIG_TO_KVSTORE_VISITOR_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/kvstore.hpp"
+
+namespace config {
+
+class ToKVStoreVisitor {
+
+public:
+    ToKVStoreVisitor(KVStore& store, const std::string& prefix)
+        : mStore(store),
+          mKeyPrefix(prefix)
+    {
+    }
+
+    ToKVStoreVisitor& operator=(const ToKVStoreVisitor&) = delete;
+
+    template<typename T>
+    void visit(const std::string& name, const T& value)
+    {
+        setInternal(key(mKeyPrefix, name), value);
+    }
+
+private:
+    KVStore& mStore;
+    std::string mKeyPrefix;
+
+    ToKVStoreVisitor(const ToKVStoreVisitor& visitor, const std::string& prefix)
+        : mStore(visitor.mStore),
+          mKeyPrefix(prefix)
+    {
+    }
+
+    template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
+    void setInternal(const std::string& name, const T& value)
+    {
+        mStore.set(name, value);
+    }
+
+    template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
+    void setInternal(const std::string& name, const T& value)
+    {
+        ToKVStoreVisitor visitor(*this, name);
+        value.accept(visitor);
+    }
+
+    template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
+    void setInternal(const std::string& name, const std::vector<T>& values)
+    {
+        mStore.remove(name);
+        mStore.set(name, values.size());
+        for (size_t i = 0; i < values.size(); ++i) {
+            setInternal(key(name, std::to_string(i)), values[i]);
+        }
+    }
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_TO_KVSTORE_VISITOR_HPP
diff --git a/common/dbus/connection.cpp b/common/dbus/connection.cpp
new file mode 100644 (file)
index 0000000..12544be
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   Dbus connection class
+ */
+
+#include "config.hpp"
+#include "dbus/connection.hpp"
+#include "dbus/exception.hpp"
+#include "utils/callback-wrapper.hpp"
+#include "utils/scoped-gerror.hpp"
+#include "utils/glib-utils.hpp"
+#include "logger/logger.hpp"
+
+using namespace vasum::utils;
+
+namespace dbus {
+
+
+namespace {
+
+const std::string SYSTEM_BUS_ADDRESS = "unix:path=/var/run/dbus/system_bus_socket";
+const std::string INTROSPECT_INTERFACE = "org.freedesktop.DBus.Introspectable";
+const std::string INTROSPECT_METHOD = "Introspect";
+
+class MethodResultBuilderImpl : public MethodResultBuilder {
+public:
+    MethodResultBuilderImpl(GDBusMethodInvocation* invocation)
+        : mInvocation(invocation), mResultSet(false) {}
+    ~MethodResultBuilderImpl()
+    {
+        if (!mResultSet) {
+            setError("org.freedesktop.DBus.Error.UnknownMethod", "Not implemented");
+        }
+    }
+    void set(GVariant* parameters)
+    {
+        g_dbus_method_invocation_return_value(mInvocation, parameters);
+        mResultSet = true;
+    }
+    void setVoid()
+    {
+        set(NULL);
+    }
+    void setError(const std::string& name, const std::string& message)
+    {
+        g_dbus_method_invocation_return_dbus_error(mInvocation, name.c_str(), message.c_str());
+        mResultSet = true;
+    }
+private:
+    GDBusMethodInvocation* mInvocation;
+    bool mResultSet;
+};
+
+void throwDbusException(const ScopedGError& e)
+{
+    if (e->domain == g_io_error_quark()) {
+        if (e->code == G_IO_ERROR_DBUS_ERROR) {
+            throw DbusCustomException(e->message);
+        } else {
+            throw DbusIOException(e->message);
+        }
+    } else if (e->domain == g_dbus_error_quark()) {
+        throw DbusOperationException(e->message);
+    } else if (e->domain == g_markup_error_quark()) {
+        throw DbusInvalidArgumentException(e->message);
+    } else {
+        throw DbusException(e->message);
+    }
+}
+
+class AsyncMethodCallResultImpl : public AsyncMethodCallResult {
+public:
+    AsyncMethodCallResultImpl(GVariant* result, const ScopedGError& error)
+        : mResult(result), mError(error) {}
+    ~AsyncMethodCallResultImpl()
+    {
+        if (mResult) {
+            g_variant_unref(mResult);
+        }
+    }
+    GVariant* get()
+    {
+        if (mError) {
+            throwDbusException(mError);
+        }
+        return mResult;
+    }
+private:
+    GVariant* mResult;
+    const ScopedGError& mError;
+};
+
+} // namespace
+
+DbusConnection::Pointer DbusConnection::create(const std::string& address)
+{
+    return Pointer(new DbusConnection(address));
+}
+
+DbusConnection::Pointer DbusConnection::createSystem()
+{
+    return create(SYSTEM_BUS_ADDRESS);
+}
+
+DbusConnection::DbusConnection(const std::string& address)
+    : mConnection(NULL)
+    , mNameId(0)
+{
+    ScopedGError error;
+    const GDBusConnectionFlags flags =
+        static_cast<GDBusConnectionFlags>(G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+                                          G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION);
+    // TODO: this is possible deadlock if the dbus
+    // socket exists but there is no dbus-daemon
+    mConnection = g_dbus_connection_new_for_address_sync(address.c_str(),
+                                                         flags,
+                                                         NULL,
+                                                         NULL,
+                                                         &error);
+    if (error) {
+        error.strip();
+        LOGE("Could not connect to " << address << "; " << error);
+        throwDbusException(error);
+    }
+}
+
+DbusConnection::~DbusConnection()
+{
+    // Close connection in a glib thread (because of a bug in glib)
+    GDBusConnection* connection = mConnection;
+    guint nameId = mNameId;
+
+    auto closeConnection = [=]() {
+        if (nameId) {
+            g_bus_unown_name(nameId);
+        }
+        g_object_unref(connection);
+        LOGT("Connection deleted");
+    };
+    executeInGlibThread(closeConnection, mGuard);
+}
+
+void DbusConnection::setName(const std::string& name,
+                             const VoidCallback& onNameAcquired,
+                             const VoidCallback& onNameLost)
+{
+    mNameId = g_bus_own_name_on_connection(mConnection,
+                                           name.c_str(),
+                                           G_BUS_NAME_OWNER_FLAGS_NONE,
+                                           &DbusConnection::onNameAcquired,
+                                           &DbusConnection::onNameLost,
+                                           createCallbackWrapper(
+                                               NameCallbacks(onNameAcquired, onNameLost),
+                                               mGuard.spawn()),
+                                           &deleteCallbackWrapper<NameCallbacks>);
+}
+
+void DbusConnection::onNameAcquired(GDBusConnection*, const gchar* name, gpointer userData)
+{
+    LOGD("Name acquired " << name);
+    const NameCallbacks& callbacks = getCallbackFromPointer<NameCallbacks>(userData);
+    if (callbacks.nameAcquired) {
+        callbacks.nameAcquired();
+    }
+}
+
+void DbusConnection::onNameLost(GDBusConnection*, const gchar* name, gpointer userData)
+{
+    LOGD("Name lost " << name);
+    const NameCallbacks& callbacks = getCallbackFromPointer<NameCallbacks>(userData);
+    if (callbacks.nameLost) {
+        callbacks.nameLost();
+    }
+}
+
+void DbusConnection::emitSignal(const std::string& objectPath,
+                                const std::string& interface,
+                                const std::string& name,
+                                GVariant* parameters)
+{
+    ScopedGError error;
+    g_dbus_connection_emit_signal(mConnection,
+                                  NULL,
+                                  objectPath.c_str(),
+                                  interface.c_str(),
+                                  name.c_str(),
+                                  parameters,
+                                  &error);
+    if (error) {
+        error.strip();
+        LOGE("Emit signal failed; " << error);
+        throwDbusException(error);
+    }
+}
+
+DbusConnection::SubscriptionId DbusConnection::signalSubscribe(const SignalCallback& callback,
+                                                               const std::string& senderBusName)
+{
+    return g_dbus_connection_signal_subscribe(mConnection,
+                                              senderBusName.empty() ? NULL : senderBusName.c_str(),
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              G_DBUS_SIGNAL_FLAGS_NONE,
+                                              &DbusConnection::onSignal,
+                                              createCallbackWrapper(callback,
+                                                                                mGuard.spawn()),
+                                              &deleteCallbackWrapper<SignalCallback>);
+}
+
+void DbusConnection::signalUnsubscribe(DbusConnection::SubscriptionId subscriptionId)
+{
+    g_dbus_connection_signal_unsubscribe(mConnection, subscriptionId);
+}
+
+void DbusConnection::onSignal(GDBusConnection*,
+                              const gchar* sender,
+                              const gchar* object,
+                              const gchar* interface,
+                              const gchar* name,
+                              GVariant* parameters,
+                              gpointer userData)
+{
+    const SignalCallback& callback = getCallbackFromPointer<SignalCallback>(userData);
+
+    LOGD("Signal: " << sender << "; " << object << "; " << interface << "; " << name);
+
+    if (callback) {
+        callback(sender, object, interface, name, parameters);
+    }
+}
+
+std::string DbusConnection::introspect(const std::string& busName, const std::string& objectPath)
+{
+    GVariantPtr result = DbusConnection::callMethod(busName,
+                                                    objectPath,
+                                                    INTROSPECT_INTERFACE,
+                                                    INTROSPECT_METHOD,
+                                                    NULL,
+                                                    "(s)");
+    const gchar* xml;
+    g_variant_get(result.get(), "(&s)", &xml);
+    return xml;
+}
+
+void DbusConnection::registerObject(const std::string& objectPath,
+                                    const std::string& objectDefinitionXml,
+                                    const MethodCallCallback& callback)
+{
+    ScopedGError error;
+    GDBusNodeInfo* nodeInfo = g_dbus_node_info_new_for_xml(objectDefinitionXml.c_str(), &error);
+    if (nodeInfo != NULL && (nodeInfo->interfaces == NULL ||
+                             nodeInfo->interfaces[0] == NULL ||
+                             nodeInfo->interfaces[1] != NULL)) {
+        g_dbus_node_info_unref(nodeInfo);
+        g_set_error(&error,
+                    G_MARKUP_ERROR,
+                    G_MARKUP_ERROR_INVALID_CONTENT,
+                    "Expected exactly one interface");
+    }
+    if (error) {
+        error.strip();
+        LOGE("Invalid xml; " << error);
+        throwDbusException(error);
+    }
+    GDBusInterfaceInfo* interfaceInfo = nodeInfo->interfaces[0];
+
+    GDBusInterfaceVTable vtable;
+    vtable.method_call = &DbusConnection::onMethodCall;
+    vtable.get_property = NULL;
+    vtable.set_property = NULL;
+
+    g_dbus_connection_register_object(mConnection,
+                                      objectPath.c_str(),
+                                      interfaceInfo,
+                                      &vtable,
+                                      createCallbackWrapper(callback, mGuard.spawn()),
+                                      &deleteCallbackWrapper<MethodCallCallback>,
+                                      &error);
+    g_dbus_node_info_unref(nodeInfo);
+    if (error) {
+        error.strip();
+        LOGE("Register object failed; " << error);
+        throwDbusException(error);
+    }
+}
+
+void DbusConnection::onMethodCall(GDBusConnection*,
+                                  const gchar*,
+                                  const gchar* objectPath,
+                                  const gchar* interface,
+                                  const gchar* method,
+                                  GVariant* parameters,
+                                  GDBusMethodInvocation* invocation,
+                                  gpointer userData)
+{
+    const MethodCallCallback& callback = getCallbackFromPointer<MethodCallCallback>(userData);
+
+    LOGD("MethodCall: " << objectPath << "; " << interface << "; " << method);
+
+    MethodResultBuilder::Pointer resultBuilder(new MethodResultBuilderImpl(invocation));
+    if (callback) {
+        callback(objectPath, interface, method, parameters, resultBuilder);
+    }
+}
+
+GVariantPtr DbusConnection::callMethod(const std::string& busName,
+                                       const std::string& objectPath,
+                                       const std::string& interface,
+                                       const std::string& method,
+                                       GVariant* parameters,
+                                       const std::string& replyType,
+                                       int timeoutMs)
+{
+    ScopedGError error;
+    GVariant* result = g_dbus_connection_call_sync(mConnection,
+                                                   busName.c_str(),
+                                                   objectPath.c_str(),
+                                                   interface.c_str(),
+                                                   method.c_str(),
+                                                   parameters,
+                                                   replyType.empty() ? NULL
+                                                       : G_VARIANT_TYPE(replyType.c_str()),
+                                                   G_DBUS_CALL_FLAGS_NONE,
+                                                   timeoutMs,
+                                                   NULL,
+                                                   &error);
+    if (error) {
+        error.strip();
+        LOGE("Call method failed; " << error);
+        throwDbusException(error);
+    }
+    return GVariantPtr(result, g_variant_unref);
+}
+
+void DbusConnection::callMethodAsync(const std::string& busName,
+                                     const std::string& objectPath,
+                                     const std::string& interface,
+                                     const std::string& method,
+                                     GVariant* parameters,
+                                     const std::string& replyType,
+                                     const AsyncMethodCallCallback& callback,
+                                     int timeoutMs)
+{
+    g_dbus_connection_call(mConnection,
+                           busName.c_str(),
+                           objectPath.c_str(),
+                           interface.c_str(),
+                           method.c_str(),
+                           parameters,
+                           replyType.empty() ? NULL
+                               : G_VARIANT_TYPE(replyType.c_str()),
+                           G_DBUS_CALL_FLAGS_NONE,
+                           timeoutMs,
+                           NULL,
+                           &DbusConnection::onAsyncReady,
+                           createCallbackWrapper(callback, mGuard.spawn()));
+}
+
+void DbusConnection::onAsyncReady(GObject* source,
+                                  GAsyncResult* asyncResult,
+                                  gpointer userData)
+{
+    std::unique_ptr<void, void(*)(void*)>
+        autoDeleteCallback(userData, &deleteCallbackWrapper<AsyncMethodCallCallback>);
+    GDBusConnection* connection = reinterpret_cast<GDBusConnection*>(source);
+    const AsyncMethodCallCallback& callback =
+        getCallbackFromPointer<AsyncMethodCallCallback>(userData);
+
+    ScopedGError error;
+    GVariant* result = g_dbus_connection_call_finish(connection, asyncResult, &error);
+    if (error) {
+        error.strip();
+        LOGE("Call method failed; " << error);
+    }
+    AsyncMethodCallResultImpl asyncMethodCallResult(result, error);
+    if (callback) {
+        try {
+            callback(asyncMethodCallResult);
+        } catch (DbusException& e) {
+            // Drop dbus exceptions (thrown from asyncMethodCallResult.get()).
+            // We can not ignore other exceptions - they must be catched inside callback,
+            // otherwise std::terminate will be called.
+            LOGW("Uncaugth dbus exception: " << e.what());
+        }
+    }
+}
+
+} // namespace dbus
diff --git a/common/dbus/connection.hpp b/common/dbus/connection.hpp
new file mode 100644 (file)
index 0000000..6603c9d
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   Dbus connection class
+ */
+
+#ifndef COMMON_DBUS_CONNECTION_HPP
+#define COMMON_DBUS_CONNECTION_HPP
+
+#include "utils/callback-guard.hpp"
+
+#include <memory>
+#include <string>
+#include <functional>
+#include <gio/gio.h>
+
+
+namespace dbus {
+
+
+typedef std::unique_ptr<GVariant, void(*)(GVariant*)> GVariantPtr;
+
+/**
+ * An interface used to set a result to a method call.
+ */
+class MethodResultBuilder {
+public:
+    typedef std::shared_ptr<MethodResultBuilder> Pointer;
+
+    virtual ~MethodResultBuilder() {}
+    virtual void set(GVariant* parameters) = 0;
+    virtual void setVoid() = 0;
+    virtual void setError(const std::string& name, const std::string& message) = 0;
+};
+
+/**
+ * An interface used to get result from async response.
+ */
+class AsyncMethodCallResult {
+public:
+    virtual ~AsyncMethodCallResult() {}
+    virtual GVariant* get() = 0; // throws DbusException on error
+};
+
+/**
+ * Dbus connection.
+ * Provides a functionality that allows to call dbus methods,
+ * register dbus interfaces, etc.
+ *
+ * TODO divide to interface and implementation header
+ */
+class DbusConnection {
+public:
+    typedef std::unique_ptr<DbusConnection> Pointer;
+
+    typedef std::function<void()> VoidCallback;
+
+    typedef std::function<void(const std::string& objectPath,
+                               const std::string& interface,
+                               const std::string& methodName,
+                               GVariant* parameters,
+                               MethodResultBuilder::Pointer result
+                              )> MethodCallCallback;
+
+    typedef std::function<void(const std::string& senderBusName,
+                               const std::string& objectPath,
+                               const std::string& interface,
+                               const std::string& signalName,
+                               GVariant* parameters
+                              )> SignalCallback;
+
+    typedef std::function<void(AsyncMethodCallResult& asyncMethodCallResult
+                              )> AsyncMethodCallCallback;
+
+    typedef unsigned int SubscriptionId;
+
+    /**
+     * Creates a connection to the dbus with given address.
+     */
+    static Pointer create(const std::string& address);
+
+    /**
+     * Creates a connection to the system dbus.
+     */
+    static Pointer createSystem();
+
+    ~DbusConnection();
+
+    /**
+     * Sets a name to the dbus connection.
+     * It allows other client to call methods using this name.
+     */
+    void setName(const std::string& name,
+                 const VoidCallback& onNameAcquired,
+                 const VoidCallback& onNameLost);
+
+    /**
+     * Emits dbus signal.
+     */
+    void emitSignal(const std::string& objectPath,
+                    const std::string& interface,
+                    const std::string& name,
+                    GVariant* parameters);
+
+    /**
+     * Subscribes to a signal.
+     * Empty sender means subscribe to all signals
+     * Returns a subscription identifier that can be used to unsubscribe signal
+     */
+    SubscriptionId signalSubscribe(const SignalCallback& callback, const std::string& senderBusName);
+
+    /**
+     * Unsubscribes from a signal.
+     */
+    void signalUnsubscribe(SubscriptionId subscriptionId);
+
+    /**
+     * Registers an object with given definition.
+     * Api calls will be handled by given callback.
+     */
+    void registerObject(const std::string& objectPath,
+                        const std::string& objectDefinitionXml,
+                        const MethodCallCallback& callback);
+
+    /**
+     * Call a dbus method
+     */
+    GVariantPtr callMethod(const std::string& busName,
+                           const std::string& objectPath,
+                           const std::string& interface,
+                           const std::string& method,
+                           GVariant* parameters,
+                           const std::string& replyType,
+                           int timeoutMs = -1);
+
+    /**
+     * Async call a dbus method
+     */
+    void callMethodAsync(const std::string& busName,
+                         const std::string& objectPath,
+                         const std::string& interface,
+                         const std::string& method,
+                         GVariant* parameters,
+                         const std::string& replyType,
+                         const AsyncMethodCallCallback& callback,
+                         int timeoutMs = -1);
+
+    /**
+     * Returns an xml with meta description of specified dbus object.
+     */
+    std::string introspect(const std::string& busName, const std::string& objectPath);
+
+private:
+    struct NameCallbacks {
+        VoidCallback nameAcquired;
+        VoidCallback nameLost;
+
+        NameCallbacks(const VoidCallback& acquired, const VoidCallback& lost)
+            : nameAcquired(acquired), nameLost(lost) {}
+    };
+
+    vasum::utils::CallbackGuard mGuard;
+    GDBusConnection* mConnection;
+    guint mNameId;
+
+    DbusConnection(const std::string& address);
+
+    static void onNameAcquired(GDBusConnection* connection, const gchar* name, gpointer userData);
+    static void onNameLost(GDBusConnection* connection, const gchar* name, gpointer userData);
+    static void onSignal(GDBusConnection* connection,
+                         const gchar* sender,
+                         const gchar* object,
+                         const gchar* interface,
+                         const gchar* name,
+                         GVariant* parameters,
+                         gpointer userData);
+    static void onMethodCall(GDBusConnection* connection,
+                             const gchar* sender,
+                             const gchar* objectPath,
+                             const gchar* interface,
+                             const gchar* method,
+                             GVariant* parameters,
+                             GDBusMethodInvocation* invocation,
+                             gpointer userData);
+    static void onAsyncReady(GObject* source,
+                             GAsyncResult* asyncResult,
+                             gpointer userData);
+};
+
+
+} // namespace dbus
+
+#endif // COMMON_DBUS_CONNECTION_HPP
diff --git a/common/dbus/exception.hpp b/common/dbus/exception.hpp
new file mode 100644 (file)
index 0000000..a09bdbc
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   Dbus exceptions
+ */
+
+#ifndef COMMON_DBUS_EXCEPTION_HPP
+#define COMMON_DBUS_EXCEPTION_HPP
+
+#include <stdexcept>
+
+namespace dbus {
+
+/**
+ * Base class for dbus exceptions
+ */
+struct DbusException: public std::runtime_error {
+
+    DbusException(const std::string& error = "") : std::runtime_error(error) {}
+};
+
+/**
+ * Dbus IO exception (connection failed, connection lost, etc)
+ */
+struct DbusIOException: public DbusException {
+
+    DbusIOException(const std::string& error = "") : DbusException(error) {}
+};
+
+/**
+ * Dbus operation failed exception
+ */
+struct DbusOperationException: public DbusException {
+
+    DbusOperationException(const std::string& error = "") : DbusException(error) {}
+};
+
+/**
+ * Dbus custom exception triggered by user logic
+ */
+struct DbusCustomException: public DbusException {
+
+    DbusCustomException(const std::string& error = "") : DbusException(error) {}
+};
+
+/**
+ * Dbus invalid argument exception
+ */
+struct DbusInvalidArgumentException: public DbusException {
+
+    DbusInvalidArgumentException(const std::string& error = "") : DbusException(error) {}
+};
+
+} // namespace dbus
+
+#endif // COMMON_DBUS_EXCEPTION_HPP
index a3342b6..db15a4a 100644 (file)
@@ -38,7 +38,7 @@ namespace ipc {
 
 /**
  * This class wraps communication via UX sockets for client applications.
- * It uses serialization mechanism from libConfig.
+ * It uses serialization mechanism from Config.
  *
  * For message format @see ipc::Processor
  */
index dec16e8..84aaa5c 100644 (file)
@@ -62,7 +62,7 @@ const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500;
 * This class wraps communication via UX sockets
 *
 * It's intended to be used both in Client and Service classes.
-* It uses a serialization mechanism from libConfig.
+* It uses a serialization mechanism from Config.
 * Library user will only have to pass the types that each call will send and receive
 *
 * Message format:
index 880c137..32b604f 100644 (file)
@@ -40,7 +40,7 @@ namespace ipc {
 
 /**
  * This class wraps communication via UX sockets.
- * It uses serialization mechanism from libConfig.
+ * It uses serialization mechanism from Config.
  *
  * For message format @see ipc::Processor
  */
diff --git a/common/logger/backend-journal.cpp b/common/logger/backend-journal.cpp
new file mode 100644 (file)
index 0000000..12c4eff
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Dariusz Michaluk <d.michaluk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Dariusz Michaluk (d.michaluk@samsung.com)
+ * @brief   Systemd journal backend for logger
+ */
+
+#include "config.hpp"
+#include "logger/backend-journal.hpp"
+
+#define SD_JOURNAL_SUPPRESS_LOCATION
+#include <systemd/sd-journal.h>
+
+namespace logger {
+
+namespace {
+
+inline int toJournalPriority(LogLevel logLevel)
+{
+    switch (logLevel) {
+    case LogLevel::ERROR:
+        return LOG_ERR;     // 3
+    case LogLevel::WARN:
+        return LOG_WARNING; // 4
+    case LogLevel::INFO:
+        return LOG_INFO;    // 6
+    case LogLevel::DEBUG:
+        return LOG_DEBUG;   // 7
+    case LogLevel::TRACE:
+        return LOG_DEBUG;   // 7
+    case LogLevel::HELP:
+        return LOG_DEBUG;   // 7
+    default:
+        return LOG_DEBUG;   // 7
+    }
+}
+
+} // namespace
+
+void SystemdJournalBackend::log(LogLevel logLevel,
+                                const std::string& file,
+                                const unsigned int& line,
+                                const std::string& func,
+                                const std::string& message)
+{
+    sd_journal_send("PRIORITY=%d", toJournalPriority(logLevel),
+                    "CODE_FILE=%s", file.c_str(),
+                    "CODE_LINE=%d", line,
+                    "CODE_FUNC=%s", func.c_str(),
+                    "MESSAGE=%s", message.c_str(),
+                    NULL);
+}
+
+} // namespace logger
diff --git a/common/logger/backend-journal.hpp b/common/logger/backend-journal.hpp
new file mode 100644 (file)
index 0000000..e566ed1
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Dariusz Michaluk <d.michaluk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Dariusz Michaluk (d.michaluk@samsung.com)
+ * @brief   Systemd journal backend for logger
+ */
+
+#ifndef COMMON_LOGGER_BACKEND_JOURNAL_HPP
+#define COMMON_LOGGER_BACKEND_JOURNAL_HPP
+
+#include "logger/backend.hpp"
+
+namespace logger {
+
+/**
+ * systemd journal logging backend
+ */
+class SystemdJournalBackend : public LogBackend {
+public:
+    void log(LogLevel logLevel,
+             const std::string& file,
+             const unsigned int& line,
+             const std::string& func,
+             const std::string& message) override;
+};
+
+} // namespace logger
+
+#endif // COMMON_LOGGER_BACKEND_JOURNAL_HPP
diff --git a/common/logger/backend-null.hpp b/common/logger/backend-null.hpp
new file mode 100644 (file)
index 0000000..4a7e8a9
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Pawel Broda <p.broda@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Pawel Broda (p.broda@partner.samsung.com)
+ * @brief   Null backend for logger
+ */
+
+#ifndef COMMON_LOGGER_BACKEND_NULL_HPP
+#define COMMON_LOGGER_BACKEND_NULL_HPP
+
+#include "logger/backend.hpp"
+
+namespace logger {
+
+/**
+ * Null logging backend
+ */
+class NullLogger : public LogBackend {
+public:
+    void log(LogLevel            /*logLevel*/,
+             const std::string&  /*file*/,
+             const unsigned int& /*line*/,
+             const std::string&  /*func*/,
+             const std::string&  /*message*/) override {}
+};
+
+} // namespace logger
+
+#endif // COMMON_LOGGER_BACKEND_NULL_HPP
diff --git a/common/logger/backend-stderr.cpp b/common/logger/backend-stderr.cpp
new file mode 100644 (file)
index 0000000..d4e36b1
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Pawel Broda <p.broda@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Pawel Broda (p.broda@partner.samsung.com)
+ * @brief   Stderr backend for logger
+ */
+
+#include "config.hpp"
+#include "logger/backend-stderr.hpp"
+#include "logger/formatter.hpp"
+
+#include <boost/tokenizer.hpp>
+
+namespace logger {
+
+void StderrBackend::log(LogLevel logLevel,
+                        const std::string& file,
+                        const unsigned int& line,
+                        const std::string& func,
+                        const std::string& message)
+{
+    typedef boost::char_separator<char> charSeparator;
+    typedef boost::tokenizer<charSeparator> tokenizer;
+
+    // example log string
+    // 06:52:35.123 [ERROR] src/util/fs.cpp:43 readFileContent: /file/file.txt is missing
+
+    const std::string logColor = LogFormatter::getConsoleColor(logLevel);
+    const std::string defaultColor = LogFormatter::getDefaultConsoleColor();
+    const std::string header = LogFormatter::getHeader(logLevel, file, line, func);
+    tokenizer tokens(message, charSeparator("\n"));
+    for (const auto& messageLine : tokens) {
+        if (!messageLine.empty()) {
+            fprintf(stderr,
+                    "%s%s%s%s\n",
+                    logColor.c_str(),
+                    header.c_str(),
+                    messageLine.c_str(),
+                    defaultColor.c_str());
+        }
+    }
+}
+
+} // namespace logger
diff --git a/common/logger/backend-stderr.hpp b/common/logger/backend-stderr.hpp
new file mode 100644 (file)
index 0000000..4cdd0ec
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Pawel Broda <p.broda@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Pawel Broda (p.broda@partner.samsung.com)
+ * @brief   Stderr backend for logger
+ */
+
+#ifndef COMMON_LOGGER_BACKEND_STDERR_HPP
+#define COMMON_LOGGER_BACKEND_STDERR_HPP
+
+#include "logger/backend.hpp"
+
+namespace logger {
+
+/**
+ * Stderr logging backend
+ */
+class StderrBackend : public LogBackend {
+public:
+    void log(LogLevel logLevel,
+             const std::string& file,
+             const unsigned int& line,
+             const std::string& func,
+             const std::string& message) override;
+};
+
+} // namespace logger
+
+#endif // COMMON_LOGGER_BACKEND_STDERR_HPP
diff --git a/common/logger/backend.hpp b/common/logger/backend.hpp
new file mode 100644 (file)
index 0000000..99b0c49
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Pawel Broda <p.broda@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Pawel Broda (p.broda@partner.samsung.com)
+ * @brief   Logging backend
+ */
+
+#ifndef COMMON_LOGGER_BACKEND_HPP
+#define COMMON_LOGGER_BACKEND_HPP
+
+#include "logger/level.hpp"
+
+#include <string>
+
+namespace logger {
+
+/**
+ * Abstract class for logger
+ */
+class LogBackend {
+public:
+    virtual void log(LogLevel logLevel,
+                     const std::string& file,
+                     const unsigned int& line,
+                     const std::string& func,
+                     const std::string& message) = 0;
+    virtual ~LogBackend() {}
+};
+
+} // namespace logger
+
+#endif // COMMON_LOGGER_BACKEND_HPP
diff --git a/common/logger/ccolor.cpp b/common/logger/ccolor.cpp
new file mode 100644 (file)
index 0000000..e5e71b0
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Dariusz Michaluk <d.michaluk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Dariusz Michaluk (d.michaluk@samsung.com)
+ * @brief   Console color for StderrBackend logger
+ */
+
+#include "config.hpp"
+#include "logger/ccolor.hpp"
+
+#include <stdio.h>
+
+namespace logger {
+
+std::string getConsoleEscapeSequence(Attributes attr, Color color)
+{
+    char command[10];
+
+    // Command is the control command to the terminal
+    snprintf(command, sizeof(command), "%c[%d;%dm", 0x1B, attr, color);
+    return std::string(command);
+}
+
+} // namespace logger
diff --git a/common/logger/ccolor.hpp b/common/logger/ccolor.hpp
new file mode 100644 (file)
index 0000000..47cc25e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Dariusz Michaluk <d.michaluk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Dariusz Michaluk (d.michaluk@samsung.com)
+ * @brief   Console color for StderrBackend logger
+ */
+
+#ifndef COMMON_LOGGER_CCOLOR_HPP
+#define COMMON_LOGGER_CCOLOR_HPP
+
+#include <string>
+
+namespace logger {
+
+enum class Color : unsigned int {
+    DEFAULT     = 0,
+    BLACK       = 90,
+    RED         = 91,
+    GREEN       = 92,
+    YELLOW      = 93,
+    BLUE        = 94,
+    MAGENTA     = 95,
+    CYAN        = 96,
+    WHITE       = 97
+};
+
+enum class Attributes : unsigned int {
+    DEFAULT     = 0,
+    BOLD        = 1
+};
+
+std::string getConsoleEscapeSequence(Attributes attr, Color color);
+
+} // namespace logger
+
+#endif // COMMON_LOGGER_CCOLOR_HPP
diff --git a/common/logger/formatter.cpp b/common/logger/formatter.cpp
new file mode 100644 (file)
index 0000000..529cd14
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Dariusz Michaluk <d.michaluk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Dariusz Michaluk (d.michaluk@samsung.com)
+ * @brief   Helper formatter for logger
+ */
+
+#include "config.hpp"
+#include "logger/formatter.hpp"
+#include "logger/ccolor.hpp"
+
+#include <sys/time.h>
+#include <cassert>
+#include <sstream>
+#include <iomanip>
+#include <thread>
+#include <atomic>
+
+namespace logger {
+
+namespace {
+
+const int TIME_COLUMN_LENGTH = 12;
+const int SEVERITY_COLUMN_LENGTH = 8;
+const int THREAD_COLUMN_LENGTH = 3;
+const int FILE_COLUMN_LENGTH = 60;
+
+std::atomic<unsigned int> gNextThreadId(1);
+thread_local unsigned int gThisThreadId(0);
+
+} // namespace
+
+unsigned int LogFormatter::getCurrentThread(void)
+{
+    unsigned int id = gThisThreadId;
+    if (id == 0) {
+        gThisThreadId = id = gNextThreadId++;
+    }
+
+    return id;
+}
+
+std::string LogFormatter::getCurrentTime(void)
+{
+    char time[TIME_COLUMN_LENGTH + 1];
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    struct tm* tm = localtime(&tv.tv_sec);
+    snprintf(time,
+             sizeof(time),
+             "%02d:%02d:%02d.%03d",
+             tm->tm_hour,
+             tm->tm_min,
+             tm->tm_sec,
+             int(tv.tv_usec / 1000));
+
+    return std::string(time);
+}
+
+std::string LogFormatter::getConsoleColor(LogLevel logLevel)
+{
+    switch (logLevel) {
+    case LogLevel::ERROR:
+        return getConsoleEscapeSequence(Attributes::BOLD, Color::RED);
+    case LogLevel::WARN:
+        return getConsoleEscapeSequence(Attributes::BOLD, Color::YELLOW);
+    case LogLevel::INFO:
+        return getConsoleEscapeSequence(Attributes::BOLD, Color::BLUE);
+    case LogLevel::DEBUG:
+        return getConsoleEscapeSequence(Attributes::DEFAULT, Color::GREEN);
+    case LogLevel::TRACE:
+        return getConsoleEscapeSequence(Attributes::DEFAULT, Color::BLACK);
+    case LogLevel::HELP:
+        return getConsoleEscapeSequence(Attributes::BOLD, Color::MAGENTA);
+    default:
+        return getConsoleEscapeSequence(Attributes::DEFAULT, Color::DEFAULT);
+    }
+}
+
+std::string LogFormatter::getDefaultConsoleColor(void)
+{
+    return getConsoleEscapeSequence(Attributes::DEFAULT, Color::DEFAULT);
+}
+
+std::string LogFormatter::stripProjectDir(const std::string& file,
+                                          const std::string& rootDir)
+{
+    // If rootdir is empty then return full name
+    if (rootDir.empty()) {
+        return file;
+    }
+    const std::string sourceDir = rootDir + "/";
+    // If file does not belong to rootDir then also return full name
+    if (0 != file.compare(0, sourceDir.size(), sourceDir)) {
+        return file;
+    }
+    return file.substr(sourceDir.size());
+}
+
+std::string LogFormatter::getHeader(LogLevel logLevel,
+                                    const std::string& file,
+                                    const unsigned int& line,
+                                    const std::string& func)
+{
+    std::ostringstream logLine;
+    logLine << getCurrentTime() << ' '
+            << std::left << std::setw(SEVERITY_COLUMN_LENGTH) << '[' + toString(logLevel) + ']'
+            << std::right << std::setw(THREAD_COLUMN_LENGTH) << getCurrentThread() << ": "
+            << std::left << std::setw(FILE_COLUMN_LENGTH)
+            << file + ':' + std::to_string(line) + ' ' + func + ':';
+    return logLine.str();
+}
+
+} // namespace logger
diff --git a/common/logger/formatter.hpp b/common/logger/formatter.hpp
new file mode 100644 (file)
index 0000000..3af0763
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Dariusz Michaluk <d.michaluk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Dariusz Michaluk (d.michaluk@samsung.com)
+ * @brief   Helper formatter for logger
+ */
+
+#ifndef COMMON_LOGGER_FORMATTER_HPP
+#define COMMON_LOGGER_FORMATTER_HPP
+
+#include "logger/level.hpp"
+
+#include <string>
+
+namespace logger {
+
+class LogFormatter {
+public:
+    static unsigned int getCurrentThread(void);
+    static std::string getCurrentTime(void);
+    static std::string getConsoleColor(LogLevel logLevel);
+    static std::string getDefaultConsoleColor(void);
+    static std::string stripProjectDir(const std::string& file,
+                                       const std::string& rootDir);
+    static std::string getHeader(LogLevel logLevel,
+                                 const std::string& file,
+                                 const unsigned int& line,
+                                 const std::string& func);
+};
+
+} // namespace logger
+
+#endif // COMMON_LOGGER_FORMATTER_HPP
diff --git a/common/logger/level.cpp b/common/logger/level.cpp
new file mode 100644 (file)
index 0000000..bf46561
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak <j.olszak@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Jan Olszak (j.olszak@samsung.com)
+ * @brief   Functions to handle LogLevel
+ */
+
+#include "config.hpp"
+#include "logger/level.hpp"
+
+#include <stdexcept>
+#include <boost/algorithm/string.hpp>
+
+namespace logger {
+
+LogLevel parseLogLevel(const std::string& level)
+{
+    if (boost::iequals(level, "ERROR")) {
+        return LogLevel::ERROR;
+    } else if (boost::iequals(level, "WARN")) {
+        return LogLevel::WARN;
+    } else if (boost::iequals(level, "INFO")) {
+        return LogLevel::INFO;
+    } else if (boost::iequals(level, "DEBUG")) {
+        return LogLevel::DEBUG;
+    } else if (boost::iequals(level, "TRACE")) {
+        return LogLevel::TRACE;
+    } else if (boost::iequals(level, "HELP")) {
+        return LogLevel::HELP;
+    } else {
+        throw std::runtime_error("Invalid LogLevel to parse");
+    }
+}
+
+std::string toString(const LogLevel logLevel)
+{
+    switch (logLevel) {
+    case LogLevel::ERROR:
+        return "ERROR";
+    case LogLevel::WARN:
+        return "WARN";
+    case LogLevel::INFO:
+        return "INFO";
+    case LogLevel::DEBUG:
+        return "DEBUG";
+    case LogLevel::TRACE:
+        return "TRACE";
+    case LogLevel::HELP:
+        return "HELP";
+    default:
+        return "UNKNOWN";
+    }
+}
+} // namespace logger
diff --git a/common/logger/level.hpp b/common/logger/level.hpp
new file mode 100644 (file)
index 0000000..7902301
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Dariusz Michaluk (d.michaluk@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Dariusz Michaluk (d.michaluk@samsung.com)
+ * @brief   LogLevel
+ */
+
+#ifndef COMMON_LOGGER_LEVEL_HPP
+#define COMMON_LOGGER_LEVEL_HPP
+
+#include <string>
+
+namespace logger {
+
+enum class LogLevel {
+    TRACE,
+    DEBUG,
+    INFO,
+    WARN,
+    ERROR,
+    HELP
+};
+
+/**
+ * @param logLevel LogLevel
+ * @return std::sting representation of the LogLevel value
+ */
+std::string toString(const LogLevel logLevel);
+
+/**
+ * @param level string representation of log level
+ * @return parsed LogLevel value
+ */
+LogLevel parseLogLevel(const std::string& level);
+
+} // namespace logger
+
+#endif // COMMON_LOGGER_LEVEL_HPP
diff --git a/common/logger/logger-scope.cpp b/common/logger/logger-scope.cpp
new file mode 100644 (file)
index 0000000..e790bab
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Kostyra <l.kostyra@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Lukasz Kostyra (l.kostyra@samsung.com)
+ * @brief   Scope logger class implementation
+ */
+
+#include "logger/logger-scope.hpp"
+#include "logger/logger.hpp"
+
+namespace logger {
+
+SStreamWrapper::operator std::string() const
+{
+    return mSStream.str();
+}
+
+LoggerScope::LoggerScope(const std::string& file,
+                         const unsigned int line,
+                         const std::string& func,
+                         const std::string& message,
+                         const std::string& rootDir):
+        mFile(file),
+        mLine(line),
+        mFunc(func),
+        mMessage(message),
+        mRootDir(rootDir)
+{
+    logger::Logger::logMessage(logger::LogLevel::TRACE, "Entering: " + mMessage, mFile,
+                               mLine, mFunc, mRootDir);
+}
+
+LoggerScope::~LoggerScope()
+{
+    logger::Logger::logMessage(logger::LogLevel::TRACE, "Leaving:  " + mMessage, mFile,
+                               mLine, mFunc, mRootDir);
+}
+
+} // namespace logger
diff --git a/common/logger/logger-scope.hpp b/common/logger/logger-scope.hpp
new file mode 100644 (file)
index 0000000..cefd912
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Kostyra <l.kostyra@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Lukasz Kostyra (l.kostyra@samsung.com)
+ * @brief   Scope logger class declaration
+ */
+
+#ifndef COMMON_LOGGER_LOGGER_SCOPE_HPP
+#define COMMON_LOGGER_LOGGER_SCOPE_HPP
+
+#include <string>
+#include <sstream>
+
+namespace logger {
+
+class SStreamWrapper
+{
+public:
+    operator std::string() const;
+
+    template <typename T>
+    SStreamWrapper& operator<<(const T& b)
+    {
+        this->mSStream << b;
+        return *this;
+    }
+
+private:
+    std::ostringstream mSStream;
+};
+
+/**
+ * Class specifically for scope debug logging. Should be used at the beggining of a scope.
+ * Constructor marks scope enterance, destructor marks scope leave.
+ */
+class LoggerScope
+{
+public:
+    LoggerScope(const std::string& file,
+                const unsigned int line,
+                const std::string& func,
+                const std::string& message,
+                const std::string& rootDir);
+    ~LoggerScope();
+
+private:
+    const std::string mFile;
+    const unsigned int mLine;
+    const std::string mFunc;
+    const std::string mMessage;
+    const std::string mRootDir;
+};
+
+} // namespace logger
+
+// macro to automatically create LoggerScope object
+#define LOGS(MSG)   logger::LoggerScope logScopeObj(__FILE__, __LINE__, __func__,    \
+                                                    logger::SStreamWrapper() << MSG, \
+                                                    PROJECT_SOURCE_DIR)
+
+#endif // COMMON_LOGGER_LOGGER_SCOPE_HPP
diff --git a/common/logger/logger.cpp b/common/logger/logger.cpp
new file mode 100644 (file)
index 0000000..aa2dccd
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Pawel Broda <p.broda@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Pawel Broda (p.broda@partner.samsung.com)
+ * @brief   Logger
+ */
+
+#include "config.hpp"
+#include "logger/logger.hpp"
+#include "logger/formatter.hpp"
+#include "logger/backend-null.hpp"
+
+#include <memory>
+#include <mutex>
+
+namespace logger {
+
+namespace {
+
+volatile LogLevel gLogLevel = LogLevel::DEBUG;
+std::unique_ptr<LogBackend> gLogBackendPtr(new NullLogger());
+std::mutex gLogMutex;
+
+} // namespace
+
+void Logger::logMessage(LogLevel logLevel,
+                        const std::string& message,
+                        const std::string& file,
+                        const unsigned int line,
+                        const std::string& func,
+                        const std::string& rootDir)
+{
+    std::string sfile = LogFormatter::stripProjectDir(file, rootDir);
+    std::unique_lock<std::mutex> lock(gLogMutex);
+    gLogBackendPtr->log(logLevel, sfile, line, func, message);
+}
+
+void Logger::setLogLevel(const LogLevel level)
+{
+    gLogLevel = level;
+}
+
+void Logger::setLogLevel(const std::string& level)
+{
+    gLogLevel = parseLogLevel(level);
+}
+
+LogLevel Logger::getLogLevel(void)
+{
+    return gLogLevel;
+}
+
+void Logger::setLogBackend(LogBackend* pBackend)
+{
+    std::unique_lock<std::mutex> lock(gLogMutex);
+    gLogBackendPtr.reset(pBackend);
+}
+
+} // namespace logger
diff --git a/common/logger/logger.hpp b/common/logger/logger.hpp
new file mode 100644 (file)
index 0000000..8d8d433
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jan Olszak <j.olszak@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Jan Olszak (j.olszak@samsung.com)
+ * @brief   Logger
+ */
+
+#ifndef COMMON_LOGGER_LOGGER_HPP
+#define COMMON_LOGGER_LOGGER_HPP
+
+#include "logger/level.hpp"
+
+#include <sstream>
+#include <string>
+
+#ifndef PROJECT_SOURCE_DIR
+#define PROJECT_SOURCE_DIR ""
+#endif
+
+namespace logger {
+
+class LogBackend;
+
+class Logger {
+public:
+    static void logMessage(LogLevel logLevel,
+                           const std::string& message,
+                           const std::string& file,
+                           const unsigned int line,
+                           const std::string& func,
+                           const std::string& rootDir);
+
+    static void setLogLevel(const LogLevel level);
+    static void setLogLevel(const std::string& level);
+    static LogLevel getLogLevel(void);
+    static void setLogBackend(LogBackend* pBackend);
+};
+
+} // namespace logger
+
+#define LOG(SEVERITY, MESSAGE)                                             \
+    do {                                                                   \
+        if (logger::Logger::getLogLevel() <= logger::LogLevel::SEVERITY) { \
+            std::ostringstream messageStream__;                            \
+            messageStream__ << MESSAGE;                                    \
+            logger::Logger::logMessage(logger::LogLevel::SEVERITY,         \
+                                       messageStream__.str(),              \
+                                       __FILE__,                           \
+                                       __LINE__,                           \
+                                       __func__,                           \
+                                       PROJECT_SOURCE_DIR);                \
+        }                                                                  \
+    } while (0)
+
+#define LOGE(MESSAGE) LOG(ERROR, MESSAGE)
+#define LOGW(MESSAGE) LOG(WARN, MESSAGE)
+#define LOGI(MESSAGE) LOG(INFO, MESSAGE)
+#define LOGD(MESSAGE) LOG(DEBUG, MESSAGE)
+#define LOGH(MESSAGE) LOG(HELP, MESSAGE)
+#define LOGT(MESSAGE) LOG(TRACE, MESSAGE)
+
+#endif // COMMON_LOGGER_LOGGER_HPP
index 971e6ad..3379009 100644 (file)
@@ -31,6 +31,7 @@
 #include <stack>
 #include <type_traits>
 #include <cstdlib>
+#include <sys/socket.h>
 #include <linux/netlink.h>
 
 namespace vasum {
diff --git a/common/utils/glib-utils.cpp b/common/utils/glib-utils.cpp
new file mode 100644 (file)
index 0000000..93cbff9
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   C++ wrapper of glib main loop
+ */
+
+#include "config.hpp"
+#include "utils/glib-utils.hpp"
+#include "utils/callback-wrapper.hpp"
+
+#include <glib-object.h>
+
+namespace vasum {
+namespace utils {
+
+namespace {
+
+gboolean onIddle(gpointer data)
+{
+    const VoidCallback& callback = getCallbackFromPointer<VoidCallback>(data);
+    callback();
+    return FALSE;
+}
+
+} // namespace
+
+void executeInGlibThread(const VoidCallback& callback, const CallbackGuard& guard)
+{
+    if (!callback) {
+        return;
+    }
+    g_idle_add_full(G_PRIORITY_DEFAULT,
+                    &onIddle,
+                    utils::createCallbackWrapper(callback, guard.spawn()),
+                    &utils::deleteCallbackWrapper<VoidCallback>);
+
+}
+
+
+} // namespace utils
+} // namespace vasum
diff --git a/common/utils/glib-utils.hpp b/common/utils/glib-utils.hpp
new file mode 100644 (file)
index 0000000..eaeeee8
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   Miscellaneous helpers for the Glib library
+ */
+
+#ifndef COMMON_UTILS_GLIB_UTILS_HPP
+#define COMMON_UTILS_GLIB_UTILS_HPP
+
+#include "utils/callback-guard.hpp"
+
+namespace vasum {
+namespace utils {
+
+typedef std::function<void()> VoidCallback;
+
+/**
+ * Executes a callback in glib thread (adds an iddle event to glib)
+ */
+void executeInGlibThread(const VoidCallback& callback, const CallbackGuard& guard);
+
+
+} // namespace utils
+} // namespace vasum
+
+#endif // COMMON_UTILS_GLIB_UTILS_HPP
index 6cea869..bd31d68 100644 (file)
@@ -21,9 +21,6 @@ BuildRequires:  boost-devel
 BuildRequires:  libjson-devel >= 0.10
 BuildRequires:  libcap-ng-devel
 BuildRequires:  lxc-devel
-BuildRequires:  pkgconfig(libConfig)
-BuildRequires:  pkgconfig(libLogger)
-BuildRequires:  pkgconfig(libSimpleDbus)
 BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(libsystemd-journal)
 BuildRequires:  pkgconfig(libsystemd-daemon)
index 79ced75..9470754 100644 (file)
@@ -31,7 +31,7 @@ ADD_EXECUTABLE(${SERVER_CODENAME} ${project_SRCS} ${common_SRCS})
 ## Link libraries ##############################################################
 FIND_PACKAGE(Boost COMPONENTS program_options system filesystem regex)
 PKG_CHECK_MODULES(SERVER_DEPS REQUIRED lxc json gio-2.0 libsystemd-journal libsystemd-daemon
-                  libcap-ng libLogger libSimpleDbus libConfig)
+                  libcap-ng sqlite3)
 
 INCLUDE_DIRECTORIES(${COMMON_FOLDER})
 INCLUDE_DIRECTORIES(${CLIENT_FOLDER})
index b3c574d..eba9a01 100644 (file)
@@ -28,6 +28,7 @@
 #include <string>
 #include <vector>
 #include <tuple>
+#include <sys/socket.h>
 #include <linux/if_link.h>
 #include <sys/types.h>
 
index 2a561ed..692ec4b 100644 (file)
@@ -48,7 +48,7 @@ ADD_EXECUTABLE(${SOCKET_TEST_CODENAME} ${socket_test_SRCS} ${common_SRCS})
 FIND_PACKAGE (Boost COMPONENTS unit_test_framework system filesystem regex)
 
 PKG_CHECK_MODULES(UT_SERVER_DEPS REQUIRED lxc json gio-2.0 libsystemd-daemon
-                  libsystemd-journal libcap-ng libLogger libSimpleDbus libConfig)
+                  libsystemd-journal libcap-ng sqlite3)
 INCLUDE_DIRECTORIES(${COMMON_FOLDER} ${SERVER_FOLDER} ${UNIT_TESTS_FOLDER} ${CLIENT_FOLDER}
                     ${SOCKET_TEST_FOLDER})
 INCLUDE_DIRECTORIES(SYSTEM ${UT_SERVER_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
index 609bf87..2f163af 100644 (file)
@@ -25,7 +25,7 @@
 #include <config.hpp>
 #include "socket-test.hpp"
 
-#include <logger/config.hpp>
+#include <config.hpp>
 #include <logger/logger.hpp>
 #include <logger/backend-journal.hpp>
 
index 7baf37f..7e7bfba 100644 (file)
@@ -20,9 +20,9 @@
 MESSAGE(STATUS "")
 MESSAGE(STATUS "Generating makefile for the Zone Daemon...")
 FILE(GLOB project_SRCS *.cpp *.hpp)
-FILE(GLOB common_SRCS ${COMMON_FOLDER}/dbus/*.cpp  ${COMMON_FOLDER}/dbus/*.hpp
-                      ${COMMON_FOLDER}/log/*.cpp   ${COMMON_FOLDER}/log/*.hpp
-                      ${COMMON_FOLDER}/utils/*.cpp ${COMMON_FOLDER}/utils/*.hpp
+FILE(GLOB common_SRCS ${COMMON_FOLDER}/dbus/*.cpp   ${COMMON_FOLDER}/dbus/*.hpp
+                      ${COMMON_FOLDER}/logger/*.cpp ${COMMON_FOLDER}/logger/*.hpp
+                      ${COMMON_FOLDER}/utils/*.cpp  ${COMMON_FOLDER}/utils/*.hpp
                       ${COMMON_FOLDER}/*.cpp)
 
 ## Setup target ################################################################
@@ -33,8 +33,8 @@ ADD_EXECUTABLE(${ZONE_DAEMON_CODENAME} ${project_SRCS} ${common_SRCS})
 ## Link libraries ##############################################################
 FIND_PACKAGE (Boost COMPONENTS program_options system filesystem)
 
-PKG_CHECK_MODULES(ZONE_DAEMON_DEPS REQUIRED gio-2.0 libsystemd-journal libcap-ng
-                                                 libLogger libSimpleDbus libConfig)
+PKG_CHECK_MODULES(ZONE_DAEMON_DEPS REQUIRED gio-2.0 libsystemd-journal libcap-ng)
+
 INCLUDE_DIRECTORIES(${COMMON_FOLDER})
 INCLUDE_DIRECTORIES(SYSTEM ${ZONE_DAEMON_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})