You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2019/07/23 20:08:46 UTC

[celix] branch feature/cxx updated (807b88b -> 41cb4b5)

This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a change to branch feature/cxx
in repository https://gitbox.apache.org/repos/asf/celix.git.


    from 807b88b  CELIX-458: Updates travis config to install libzip
     new 2d6327e  CELIX-370: Initial commit for CompnentManager (DM) for C++ Celix
     new 41cb4b5  CELIX-370: Update ServiceDependency implementation

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../topology_manager/CMakeLists.txt                |   2 +-
 libs/framework_cxx/CMakeLists.txt                  |   1 +
 libs/framework_cxx/gtest/CMakeLists.txt            |   1 +
 .../gtest/src/ComponentManager_tests.cc            |  68 ++++
 .../framework_cxx/include/celix/ComponentManager.h | 353 +++++++++++++++++++++
 libs/framework_cxx/include/celix/Framework.h       |   2 +-
 libs/framework_cxx/src/ComponentManager.cc         | 119 +++++++
 libs/framework_cxx/src/Framework.cc                |   6 +-
 libs/registry/include/celix/Properties.h           |  54 +++-
 libs/registry/include/celix/ServiceRegistry.h      |   2 +-
 libs/registry/src/ServiceRegistry.cc               |   2 +-
 11 files changed, 586 insertions(+), 24 deletions(-)
 create mode 100644 libs/framework_cxx/gtest/src/ComponentManager_tests.cc
 create mode 100644 libs/framework_cxx/include/celix/ComponentManager.h
 create mode 100644 libs/framework_cxx/src/ComponentManager.cc


[celix] 01/02: CELIX-370: Initial commit for CompnentManager (DM) for C++ Celix

Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/cxx
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 2d6327e6918723bfd082830b6ddcc5fa2cd60798
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Sun Jun 16 12:50:27 2019 +0200

    CELIX-370: Initial commit for CompnentManager (DM) for C++ Celix
---
 .../topology_manager/CMakeLists.txt                |   2 +-
 libs/framework_cxx/CMakeLists.txt                  |   1 +
 libs/framework_cxx/gtest/CMakeLists.txt            |   1 +
 .../gtest/src/ComponentManager_tests.cc            |  61 +++++
 .../framework_cxx/include/celix/ComponentManager.h | 288 +++++++++++++++++++++
 libs/framework_cxx/include/celix/Framework.h       |   2 +-
 libs/framework_cxx/src/ComponentManager.cc         | 102 ++++++++
 libs/framework_cxx/src/Framework.cc                |   6 +-
 libs/registry/include/celix/Properties.h           |  54 ++--
 libs/registry/src/ServiceRegistry.cc               |   2 +-
 10 files changed, 496 insertions(+), 23 deletions(-)

diff --git a/bundles/remote_services/topology_manager/CMakeLists.txt b/bundles/remote_services/topology_manager/CMakeLists.txt
index 9ee218f..211a31e 100644
--- a/bundles/remote_services/topology_manager/CMakeLists.txt
+++ b/bundles/remote_services/topology_manager/CMakeLists.txt
@@ -41,7 +41,7 @@ if (RSA_TOPOLOGY_MANAGER)
         include_directories(${CPPUTEST_INCLUDE_DIR})
         include_directories(${CPPUTEST_EXT_INCLUDE_DIR})
         add_subdirectory(tms_tst)
-   endif (ENABLE_TESTING)
+   endif ()
 
     install_celix_bundle(rsa_topology_manager EXPORT celix COMPONENT rsa)
     #Setup target aliases to match external usage
diff --git a/libs/framework_cxx/CMakeLists.txt b/libs/framework_cxx/CMakeLists.txt
index c4604ac..f5c3164 100644
--- a/libs/framework_cxx/CMakeLists.txt
+++ b/libs/framework_cxx/CMakeLists.txt
@@ -27,6 +27,7 @@ add_library(celix_framework_cxx SHARED
         src/Framework.cc
         src/BundleContext.cc
         src/Bundle.cc
+        src/ComponentManager.cc
 )
 target_include_directories(celix_framework_cxx PRIVATE src)
 target_include_directories(celix_framework_cxx PUBLIC include)
diff --git a/libs/framework_cxx/gtest/CMakeLists.txt b/libs/framework_cxx/gtest/CMakeLists.txt
index 4e76ed2..e12c856 100644
--- a/libs/framework_cxx/gtest/CMakeLists.txt
+++ b/libs/framework_cxx/gtest/CMakeLists.txt
@@ -18,6 +18,7 @@
 set(SOURCES
         src/main.cc
         src/Framework_tests.cc
+        src/ComponentManager_tests.cc
 )
 add_executable(celix_framework_cxx_tests ${SOURCES})
 target_link_libraries(celix_framework_cxx_tests PRIVATE gtest celix_framework_cxx glog::glog)
diff --git a/libs/framework_cxx/gtest/src/ComponentManager_tests.cc b/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
new file mode 100644
index 0000000..f9a42ad
--- /dev/null
+++ b/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
@@ -0,0 +1,61 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include <atomic>
+
+#include "gtest/gtest.h"
+
+#include "celix/Framework.h"
+#include "celix/ComponentManager.h"
+
+class ComponentManagerTest : public ::testing::Test {
+public:
+    celix::Framework& framework() { return fw; }
+private:
+    celix::Framework fw{};
+};
+
+
+TEST_F(ComponentManagerTest, CreateDestroy) {
+    auto ctx = framework().context();
+
+    class Cmp {};
+
+    celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
+    EXPECT_FALSE(cmpMng.isEnabled());
+    EXPECT_TRUE(cmpMng.isResolved()); //no deps -> resolved
+    EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Disabled);
+
+    cmpMng.enable();
+    EXPECT_TRUE(cmpMng.isEnabled());
+}
+
+TEST_F(ComponentManagerTest, AddSvcDep) {
+    auto ctx = framework().context();
+
+    class Cmp {};
+    class ISvc {};
+
+    celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
+    cmpMng.addServiceDependency(); //TODO
+    cmpMng.enable();
+    EXPECT_TRUE(cmpMng.isEnabled());
+
+
+}
\ No newline at end of file
diff --git a/libs/framework_cxx/include/celix/ComponentManager.h b/libs/framework_cxx/include/celix/ComponentManager.h
new file mode 100644
index 0000000..431b784
--- /dev/null
+++ b/libs/framework_cxx/include/celix/ComponentManager.h
@@ -0,0 +1,288 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#ifndef CXX_CELIX_COMPONENT_MANAGER_H
+#define CXX_CELIX_COMPONENT_MANAGER_H
+
+#include <memory>
+#include <unordered_map>
+
+#include "celix/BundleContext.h"
+
+namespace celix {
+
+    enum class ComponentState {
+        Disabled,
+        Uninitialized,
+        Initialized,
+        Started
+    };
+
+    template<typename T, typename I>
+    class ServiceDependency; //forward declaration
+    class GenericServiceDependency; //forward declaration
+
+    class GenericComponentManager {
+    public:
+        virtual ~GenericComponentManager() = default;
+
+        ComponentState getState() const;
+        bool isEnabled() const;
+        bool isResolved() const;
+
+        //TODO make friend of SvcDep
+        void updateState();
+    protected:
+        GenericComponentManager(std::shared_ptr<BundleContext> _ctx, std::shared_ptr<void> cmpInstance) : ctx{std::move(_ctx)}, instance{std::move(cmpInstance)} {};
+
+        void removeServiceDependency(long serviceDependencyId);
+        void setEnabled(bool enable);
+
+
+        /**** Fields ****/
+        mutable std::mutex mutex{}; //protects below
+        ComponentState state = ComponentState::Disabled;
+        bool enabled = false;
+        std::function<void()> init{};
+        std::function<void()> start{};
+        std::function<void()> stop{};
+        std::function<void()> deinit{};
+
+        std::shared_ptr<BundleContext> ctx;
+        std::shared_ptr<void> instance;
+
+        long nextServiceDependencyId = 1L;
+        std::unordered_map<long,GenericServiceDependency> serviceDependencies{};
+    };
+
+    template<typename T>
+    class ComponentManager : public GenericComponentManager {
+    public:
+        using ComponentType = T;
+
+        ComponentManager(std::shared_ptr<BundleContext> ctx, std::shared_ptr<T> cmpInstance);
+        ~ComponentManager() override = default;
+
+        ComponentManager<T>& enable();
+        ComponentManager<T>& disable();
+
+        ComponentManager<T>& setCallbacks(
+                void (T::*init)(),
+                void (T::*start)(),
+                void (T::*stop)(),
+                void (T::*deinit)());
+
+//        template<typename I>
+//        ServiceDependency<T,I>& addServiceDependency();
+//
+//        template<typename F>
+//        ServiceDependency<T,F>& addFunctionServiceDependency(const std::string &functionName);
+
+    };
+
+    enum class Cardinality {
+        One,
+        Many
+    };
+
+    class GenericServiceDependency {
+    public:
+        virtual ~GenericServiceDependency() = default;
+
+        bool isResolved() const;
+        Cardinality getCardinality() const;
+        bool getRequired() const;
+        const std::string& getFilter() const;
+
+    protected:
+        GenericServiceDependency(std::shared_ptr<BundleContext> ctx);
+
+        //Fields
+        mutable std::mutex mutex{}; //protects below
+        bool required = false;
+        std::string filter{};
+        Cardinality cardinality = Cardinality::One;
+        std::vector<ServiceTracker> tracker{}; //max 1
+
+        std::shared_ptr<BundleContext> ctx;
+    };
+
+    template<typename T, typename I>
+    class ServiceDependency : public GenericServiceDependency {
+    public:
+        using ComponentType = T;
+        using ServiceType = I;
+
+        ServiceDependency(std::shared_ptr<ComponentManager<T>> mng);
+        ~ServiceDependency() override = default;
+
+        ServiceDependency<T,I>& setFilter(const std::string &filter);
+        ServiceDependency<T,I>& setRequired(bool required);
+        ServiceDependency<T,I>& setCardinality(celix::Cardinality cardinality);
+        ServiceDependency<T,I>& setCallbacks(void (T::*set)(std::shared_ptr<I>));
+        ServiceDependency<T,I>& setCallbacks(void (T::*add)(std::shared_ptr<I>), void (T::*remove)(std::shared_ptr<I>));
+        //TODO update callback
+
+        void enable();
+        void disable();
+        bool isResolved();
+    private:
+        std::function<void(std::shared_ptr<I>)> set{};
+        std::function<void(std::shared_ptr<I>)> add{};
+        std::function<void(std::shared_ptr<I>)> rem{};
+        std::shared_ptr<ComponentManager<T>> mng;
+    };
+}
+
+
+
+/**************************** IMPLEMENTATION *************************************************************************/
+
+template<typename T>
+celix::ComponentManager<T>::ComponentManager(std::shared_ptr<BundleContext> ctx, std::shared_ptr<T> cmpInstance) :
+    GenericComponentManager(ctx, std::static_pointer_cast<void>(cmpInstance)) {}
+
+template<typename T>
+celix::ComponentManager<T>& celix::ComponentManager<T>::enable() {
+    this->setEnabled(true);
+    return *this;
+}
+
+template<typename T>
+celix::ComponentManager<T>& celix::ComponentManager<T>::disable() {
+    this->setEnabled(false);
+    return *this;
+}
+
+template<typename T>
+celix::ComponentManager<T>& celix::ComponentManager<T>::setCallbacks(
+        void (T::*init)(),
+        void (T::*start)(),
+        void (T::*stop)(),
+        void (T::*deinit)()) {
+    std::lock_guard<std::mutex> lck{mutex};
+    auto initFunc = [this,init]() {
+        if (init) {
+            (this->instance->*init)();
+        }
+    };
+    auto startFunc = [this,start]() {
+        if (start) {
+            (this->instance->*start)();
+        }
+    };
+    auto stopFunc = [this,stop]() {
+        if (stop) {
+            (this->instance->*stop)();
+        }
+    };
+    auto deinitFunc = [this,deinit]() {
+        if (deinit) {
+            (this->instance->*deinit)();
+        }
+    };
+
+}
+
+template<typename T, typename I>
+celix::ServiceDependency<T,I>::ServiceDependency(std::shared_ptr<ComponentManager<T>> _mng) : mng{std::move(_mng)} {
+    add = [this](std::shared_ptr<I>) {
+        mng->updateState();
+    };
+    rem = [this](std::shared_ptr<I>) {
+        mng->updateState();
+    };
+}
+
+template<typename T, typename I>
+void celix::ServiceDependency<T,I>::enable() {
+    std::vector<celix::ServiceTracker> localTrackers{};
+    {
+        std::lock_guard<std::mutex> lck{mutex};
+        std::swap(localTrackers, tracker);
+        assert(tracker.size() == 0);
+
+        ServiceTrackerOptions<I> opts{};
+        opts.filter = this->filter;
+        opts.set = set;
+        opts.add = add;
+        opts.remove = rem;
+
+        this->tracker.push_back(this->ctx->trackServices(opts));
+    }
+
+}
+
+template<typename T, typename I>
+void celix::ServiceDependency<T,I>::disable() {
+    std::vector<celix::ServiceTracker> localTrackers{};
+    {
+        std::lock_guard<std::mutex> lck{mutex};
+        std::swap(localTrackers, tracker);
+        assert(tracker.size() == 0);
+    }
+}
+
+
+template<typename T, typename I>
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setCallbacks(void (T::*setfp)(std::shared_ptr<I>)) {
+    std::lock_guard<std::mutex> lck{mutex};
+    set = [this, setfp](std::shared_ptr<I> svc) {
+        (mng->instance->*setfp)(svc);
+    };
+    return *this;
+}
+
+template<typename T, typename I>
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setCallbacks(void (T::*addfp)(std::shared_ptr<I>), void (T::*remfp)(std::shared_ptr<I>)) {
+    std::lock_guard<std::mutex> lck{mutex};
+    add = [this, addfp](std::shared_ptr<I> svc) {
+        (mng->instance->*addfp)(svc);
+        mng->updateState();
+    };
+    rem = [this, remfp](std::shared_ptr<I> svc) {
+        (mng->instance->*remfp)(svc);
+        mng->updateState();
+    };
+    return *this;
+}
+
+template<typename T, typename I>
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setFilter(const std::string &f) {
+    std::lock_guard<std::mutex> lck{mutex};
+    filter = f;
+    return *this;
+}
+
+template<typename T, typename I>
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setRequired(bool r) {
+    std::lock_guard<std::mutex> lck{mutex};
+    required = r;
+    return *this;
+}
+
+template<typename T, typename I>
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setCardinality(celix::Cardinality c) {
+    std::lock_guard<std::mutex> lck{mutex};
+    cardinality = c;
+    return *this;
+}
+
+
+#endif //CXX_CELIX_PROPERTIES_H
diff --git a/libs/framework_cxx/include/celix/Framework.h b/libs/framework_cxx/include/celix/Framework.h
index 8689be7..8e7fdd7 100644
--- a/libs/framework_cxx/include/celix/Framework.h
+++ b/libs/framework_cxx/include/celix/Framework.h
@@ -88,7 +88,7 @@ namespace celix {
         std::string cacheDir() const;
         std::string uuid() const;
 
-        celix::BundleContext& context() const;
+        std::shared_ptr<celix::BundleContext> context() const;
 
         //TODO trackBundles
 
diff --git a/libs/framework_cxx/src/ComponentManager.cc b/libs/framework_cxx/src/ComponentManager.cc
new file mode 100644
index 0000000..b3b4205
--- /dev/null
+++ b/libs/framework_cxx/src/ComponentManager.cc
@@ -0,0 +1,102 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+
+#include <iostream>
+
+#include "celix/ComponentManager.h"
+
+celix::GenericServiceDependency::GenericServiceDependency(std::shared_ptr<celix::BundleContext> _ctx) : ctx{_ctx} {}
+
+
+bool celix::GenericServiceDependency::isResolved() const {
+    std::lock_guard<std::mutex> lck{mutex};
+    if (!tracker.empty()) {
+        return tracker[0].trackCount() >= 1;
+    } else {
+        return false;
+    }
+}
+
+celix::Cardinality celix::GenericServiceDependency::getCardinality() const {
+    std::lock_guard<std::mutex> lck{mutex};
+    return cardinality;
+}
+
+bool celix::GenericServiceDependency::getRequired() const {
+    std::lock_guard<std::mutex> lck{mutex};
+    return required;
+}
+
+const std::string &celix::GenericServiceDependency::getFilter() const {
+    std::lock_guard<std::mutex> lck{mutex};
+    return filter;
+}
+
+celix::ComponentState celix::GenericComponentManager::getState() const {
+    std::lock_guard<std::mutex> lck{mutex};
+    return state;
+}
+
+bool celix::GenericComponentManager::isEnabled() const  {
+    std::lock_guard<std::mutex> lck{mutex};
+    //TODO update state
+    return enabled;
+}
+
+bool celix::GenericComponentManager::isResolved() const {
+    std::lock_guard<std::mutex> lck{mutex};
+//    for (auto &pair : serviceDependencies) {
+//        if (!pair->second.isResolved()) {
+//            return false;
+//        }
+//    }
+    return true;
+}
+
+void celix::GenericComponentManager::removeServiceDependency(long serviceDependencyId) {
+    std::lock_guard<std::mutex> lck{mutex};
+    serviceDependencies.erase(serviceDependencyId);
+}
+
+void celix::GenericComponentManager::setEnabled(bool e) {
+    std::lock_guard<std::mutex> lck{mutex};
+    enabled = e;
+}
+
+void celix::GenericComponentManager::updateState() {
+    std::lock_guard<std::mutex> lck{mutex};
+
+    //TODO state thing
+
+    //TODO check enabled.
+
+    bool allDependenciesResolved = true;
+    for (auto &pair : serviceDependencies) {
+        if (!pair.second.isResolved()) {
+            allDependenciesResolved = false;
+            break;
+        }
+    }
+
+    std::cout << "resolved? " << (allDependenciesResolved ? "true" : "false") << std::endl;
+}
+
+
+
diff --git a/libs/framework_cxx/src/Framework.cc b/libs/framework_cxx/src/Framework.cc
index 9128c0e..c5eb0ac 100644
--- a/libs/framework_cxx/src/Framework.cc
+++ b/libs/framework_cxx/src/Framework.cc
@@ -301,9 +301,9 @@ public:
         return fwUUID;
     }
 
-    celix::BundleContext& frameworkContext() const {
+    std::shared_ptr<celix::BundleContext> frameworkContext() const {
         std::lock_guard<std::mutex> lck(bundles.mutex);
-        return *bundles.entries.at(celix::FRAMEWORK_BUNDLE_ID)->context();
+        return bundles.entries.at(celix::FRAMEWORK_BUNDLE_ID)->context();
     }
 
     bool startFramework() {
@@ -447,7 +447,7 @@ std::string celix::Framework::uuid() const {
     return pimpl->uuid();
 }
 
-celix::BundleContext& celix::Framework::context() const {
+std::shared_ptr<celix::BundleContext> celix::Framework::context() const {
     return pimpl->frameworkContext();
 }
 
diff --git a/libs/registry/include/celix/Properties.h b/libs/registry/include/celix/Properties.h
index 649cf4c..0588f3f 100644
--- a/libs/registry/include/celix/Properties.h
+++ b/libs/registry/include/celix/Properties.h
@@ -29,33 +29,53 @@ namespace celix {
 
     inline const std::string& getProperty(const Properties& props, const std::string &key, const std::string &defaultValue) noexcept {
         auto it = props.find(key);
-        if (it != props.end()) {
-            return props.at(key);
-        } else {
-            return defaultValue;
-        }
+        return it != props.end() ? it->second : defaultValue;
     }
 
-    inline int getProperty(const Properties& props, const std::string &key, int defaultValue)  noexcept {
-        std::string val = getProperty(props, key, std::to_string(defaultValue));
-        return std::stoi(val, nullptr, 10);
+    inline long getPropertyAsLong(const Properties& props, const std::string &key, long defaultValue) noexcept {
+        const std::string &strVal = getProperty(props, key, std::to_string(defaultValue));
+        char *endptr[1];
+        long lval = strtol(strVal.c_str(), endptr, 10);
+        return strVal.c_str() == *endptr ? defaultValue : lval;
     }
 
-    inline unsigned int getProperty(const Properties& props, const std::string &key, unsigned int defaultValue) noexcept {
-        std::string val = getProperty(props, key, std::to_string(defaultValue));
-        return static_cast<unsigned  int>(std::stoul(val, nullptr, 10)); //NOTE no std::stou ??
+    inline unsigned long getPropertyAsUnsignedLong(const Properties& props, const std::string &key, unsigned long defaultValue) noexcept {
+        const std::string &strVal = getProperty(props, key, std::to_string(defaultValue));
+        char *endptr[1];
+        unsigned long lval = strtoul(strVal.c_str(), endptr, 10);
+        return strVal.c_str() == *endptr ? defaultValue : lval;
     }
 
-    inline long getProperty(const Properties& props, const std::string &key, long defaultValue) noexcept {
-        std::string val = getProperty(props, key, std::to_string(defaultValue));
-        return std::stol(val, nullptr, 10);
+    inline int getPropertyAsInt(const Properties& props, const std::string &key, int defaultValue) noexcept {
+        long def = defaultValue;
+        long r = getPropertyAsLong(props, key, def);
+        return (int)r;
     }
 
-    inline unsigned int getProperty(const Properties& props, const std::string &key, unsigned long defaultValue) noexcept {
-        std::string val = getProperty(props, key, std::to_string(defaultValue));
-        return std::stoul(val, nullptr, 10);
+    inline unsigned int getPropertyAsUnsignedInt(const Properties& props, const std::string &key, unsigned int defaultValue) noexcept {
+        unsigned long def = defaultValue;
+        unsigned long r = getPropertyAsUnsignedLong(props, key, def);
+        return (unsigned int)r;
     }
 
+    inline bool getPropertyAsBool(const Properties& props, const std::string &key, bool defaultValue) noexcept {
+        const std::string &strVal = getProperty(props, key, std::to_string(defaultValue));
+        return strVal == "true" || strVal == "TRUE";
+    }
+
+    inline double getPropertyAsDouble(const Properties& props, const std::string &key, double defaultValue) noexcept {
+        const std::string &strVal = getProperty(props, key, std::to_string(defaultValue));
+        char *endptr[1];
+        double dval = strtod(strVal.c_str(), endptr);
+        return strVal.c_str() == *endptr ? defaultValue : dval;
+    }
+
+    inline float getPropertyAsFloat(const Properties& props, const std::string &key, float defaultValue) noexcept {
+        const std::string &strVal = getProperty(props, key, std::to_string(defaultValue));
+        char *endptr[1];
+        float fval = strtof(strVal.c_str(), endptr);
+        return strVal.c_str() == *endptr ? defaultValue : fval;
+    }
 
     celix::Properties loadProperties(const std::string &path);
     celix::Properties loadProperties(std::istream &stream);
diff --git a/libs/registry/src/ServiceRegistry.cc b/libs/registry/src/ServiceRegistry.cc
index 33b2bb6..a8cf2f5 100644
--- a/libs/registry/src/ServiceRegistry.cc
+++ b/libs/registry/src/ServiceRegistry.cc
@@ -67,7 +67,7 @@ namespace {
                  celix::Properties &&_props) :
                 owner{std::move(_owner)}, svcId{_svcId}, svcName{std::move(_svcName)},
                 props{std::forward<celix::Properties>(_props)},
-                ranking{celix::getProperty(props, celix::SERVICE_RANKING, 0L)},
+                ranking{celix::getPropertyAsLong(props, celix::SERVICE_RANKING, 0L)},
                 svc{_svc}, svcFactory{_svcFac} {}
 
         SvcEntry(SvcEntry &&rhs) = delete;


[celix] 02/02: CELIX-370: Update ServiceDependency implementation

Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/cxx
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 41cb4b5be5239d11d57e0af68ea760d7bd328c93
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Tue Jul 23 22:08:17 2019 +0200

    CELIX-370: Update ServiceDependency implementation
---
 .../gtest/src/ComponentManager_tests.cc            |   9 +-
 .../framework_cxx/include/celix/ComponentManager.h | 207 ++++++++++++++-------
 libs/framework_cxx/src/ComponentManager.cc         |  31 ++-
 libs/registry/include/celix/ServiceRegistry.h      |   2 +-
 4 files changed, 169 insertions(+), 80 deletions(-)

diff --git a/libs/framework_cxx/gtest/src/ComponentManager_tests.cc b/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
index f9a42ad..77dc8de 100644
--- a/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
+++ b/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
@@ -53,9 +53,16 @@ TEST_F(ComponentManagerTest, AddSvcDep) {
     class ISvc {};
 
     celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
-    cmpMng.addServiceDependency(); //TODO
+    cmpMng.addServiceDependency<ISvc>()
+            .setRequired(true);
     cmpMng.enable();
     EXPECT_TRUE(cmpMng.isEnabled());
 
+    //dep not available -> cmp manager not resolved
+    EXPECT_FALSE(cmpMng.isResolved());
 
+
+    auto svcReg = ctx->registerService(std::make_shared<ISvc>());
+    //dep available -> cmp manager resolved
+    EXPECT_TRUE(cmpMng.isResolved());
 }
\ No newline at end of file
diff --git a/libs/framework_cxx/include/celix/ComponentManager.h b/libs/framework_cxx/include/celix/ComponentManager.h
index 431b784..bfbd971 100644
--- a/libs/framework_cxx/include/celix/ComponentManager.h
+++ b/libs/framework_cxx/include/celix/ComponentManager.h
@@ -49,13 +49,15 @@ namespace celix {
         //TODO make friend of SvcDep
         void updateState();
     protected:
-        GenericComponentManager(std::shared_ptr<BundleContext> _ctx, std::shared_ptr<void> cmpInstance) : ctx{std::move(_ctx)}, instance{std::move(cmpInstance)} {};
+        GenericComponentManager(std::shared_ptr<BundleContext> _ctx) : ctx{std::move(_ctx)} {};
 
         void removeServiceDependency(long serviceDependencyId);
         void setEnabled(bool enable);
 
 
         /**** Fields ****/
+        std::shared_ptr<BundleContext> ctx;
+
         mutable std::mutex mutex{}; //protects below
         ComponentState state = ComponentState::Disabled;
         bool enabled = false;
@@ -64,11 +66,8 @@ namespace celix {
         std::function<void()> stop{};
         std::function<void()> deinit{};
 
-        std::shared_ptr<BundleContext> ctx;
-        std::shared_ptr<void> instance;
-
         long nextServiceDependencyId = 1L;
-        std::unordered_map<long,GenericServiceDependency> serviceDependencies{};
+        std::unordered_map<long,std::unique_ptr<GenericServiceDependency>> serviceDependencies{};
     };
 
     template<typename T>
@@ -82,17 +81,21 @@ namespace celix {
         ComponentManager<T>& enable();
         ComponentManager<T>& disable();
 
+        std::shared_ptr<T> instance();
+
         ComponentManager<T>& setCallbacks(
                 void (T::*init)(),
                 void (T::*start)(),
                 void (T::*stop)(),
                 void (T::*deinit)());
 
-//        template<typename I>
-//        ServiceDependency<T,I>& addServiceDependency();
+        template<typename I>
+        ServiceDependency<T,I>& addServiceDependency();
 //
 //        template<typename F>
 //        ServiceDependency<T,F>& addFunctionServiceDependency(const std::string &functionName);
+    private:
+        std::shared_ptr<T> inst;
 
     };
 
@@ -109,18 +112,26 @@ namespace celix {
         Cardinality getCardinality() const;
         bool getRequired() const;
         const std::string& getFilter() const;
+        void setEnable(bool enable);
 
     protected:
-        GenericServiceDependency(std::shared_ptr<BundleContext> ctx);
+        GenericServiceDependency(
+                std::shared_ptr<BundleContext> ctx,
+                std::function<void()> stateChangedCallback,
+                std::function<void()> enable,
+                std::function<void()> disable);
 
         //Fields
+        std::shared_ptr<BundleContext> ctx;
+        const std::function<void()> stateChangedCallback;
+        const std::function<void()> enable;
+        std::function<void()> disable;
+
         mutable std::mutex mutex{}; //protects below
         bool required = false;
         std::string filter{};
         Cardinality cardinality = Cardinality::One;
         std::vector<ServiceTracker> tracker{}; //max 1
-
-        std::shared_ptr<BundleContext> ctx;
     };
 
     template<typename T, typename I>
@@ -129,7 +140,7 @@ namespace celix {
         using ComponentType = T;
         using ServiceType = I;
 
-        ServiceDependency(std::shared_ptr<ComponentManager<T>> mng);
+        ServiceDependency(std::shared_ptr<BundleContext> ctx, std::function<void()> stateChangedCallback, std::function<std::shared_ptr<T>()> getCmpInstance);
         ~ServiceDependency() override = default;
 
         ServiceDependency<T,I>& setFilter(const std::string &filter);
@@ -138,15 +149,25 @@ namespace celix {
         ServiceDependency<T,I>& setCallbacks(void (T::*set)(std::shared_ptr<I>));
         ServiceDependency<T,I>& setCallbacks(void (T::*add)(std::shared_ptr<I>), void (T::*remove)(std::shared_ptr<I>));
         //TODO update callback
+        //TODO callbacks with properties and owner
+
+        ServiceDependency<T,I>& setFunctionCallbacks(
+                std::function<void(std::shared_ptr<I>, const celix::Properties &props, const celix::IResourceBundle &owner)> set,
+                std::function<void(std::shared_ptr<I>, const celix::Properties &props, const celix::IResourceBundle &owner)> add,
+                std::function<void(std::shared_ptr<I>, const celix::Properties &props, const celix::IResourceBundle &owner)> rem,
+                std::function<void(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices)> update);
 
-        void enable();
-        void disable();
+        ServiceDependency<T,I>& enable();
+        ServiceDependency<T,I>& disable();
         bool isResolved();
     private:
-        std::function<void(std::shared_ptr<I>)> set{};
-        std::function<void(std::shared_ptr<I>)> add{};
-        std::function<void(std::shared_ptr<I>)> rem{};
-        std::shared_ptr<ComponentManager<T>> mng;
+        const std::function<std::shared_ptr<T>()> getCmpInstance;
+
+
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> set{};
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> add{};
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> rem{};
+        std::function<void(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices)> update{};
     };
 }
 
@@ -155,8 +176,9 @@ namespace celix {
 /**************************** IMPLEMENTATION *************************************************************************/
 
 template<typename T>
-celix::ComponentManager<T>::ComponentManager(std::shared_ptr<BundleContext> ctx, std::shared_ptr<T> cmpInstance) :
-    GenericComponentManager(ctx, std::static_pointer_cast<void>(cmpInstance)) {}
+celix::ComponentManager<T>::ComponentManager(
+        std::shared_ptr<BundleContext> ctx,
+        std::shared_ptr<T> cmpInstance) : GenericComponentManager{ctx}, inst{std::move(cmpInstance)} {}
 
 template<typename T>
 celix::ComponentManager<T>& celix::ComponentManager<T>::enable() {
@@ -172,95 +194,138 @@ celix::ComponentManager<T>& celix::ComponentManager<T>::disable() {
 
 template<typename T>
 celix::ComponentManager<T>& celix::ComponentManager<T>::setCallbacks(
-        void (T::*init)(),
-        void (T::*start)(),
-        void (T::*stop)(),
-        void (T::*deinit)()) {
+        void (T::*memberInit)(),
+        void (T::*memberStart)(),
+        void (T::*memberStop)(),
+        void (T::*memberDeinit)()) {
     std::lock_guard<std::mutex> lck{mutex};
-    auto initFunc = [this,init]() {
-        if (init) {
-            (this->instance->*init)();
+    init = [this, memberInit]() {
+        if (memberInit) {
+            (this->instance()->*memberInit)();
         }
     };
-    auto startFunc = [this,start]() {
-        if (start) {
-            (this->instance->*start)();
+    start = [this, memberStart]() {
+        if (memberStart) {
+            (this->instance()->*memberStart)();
         }
     };
-    auto stopFunc = [this,stop]() {
-        if (stop) {
-            (this->instance->*stop)();
+    stop = [this, memberStop]() {
+        if (memberStop) {
+            (this->instance()->*memberStop)();
         }
     };
-    auto deinitFunc = [this,deinit]() {
-        if (deinit) {
-            (this->instance->*deinit)();
+    deinit = [this, memberDeinit]() {
+        if (memberDeinit) {
+            (this->instance()->*memberDeinit)();
         }
     };
+    return *this;
+}
 
+template<typename T>
+std::shared_ptr<T> celix::ComponentManager<T>::instance() {
+    return inst;
 }
 
-template<typename T, typename I>
-celix::ServiceDependency<T,I>::ServiceDependency(std::shared_ptr<ComponentManager<T>> _mng) : mng{std::move(_mng)} {
-    add = [this](std::shared_ptr<I>) {
-        mng->updateState();
-    };
-    rem = [this](std::shared_ptr<I>) {
-        mng->updateState();
-    };
+
+template<typename T>
+template<typename I>
+celix::ServiceDependency<T,I>& celix::ComponentManager<T>::addServiceDependency() {
+    auto *dep = new celix::ServiceDependency<T,I>{ctx, []{/*TODO*/}, [this]{return instance();}};
+    std::lock_guard<std::mutex> lck{mutex};
+    serviceDependencies[nextServiceDependencyId++] = std::unique_ptr<GenericServiceDependency>{dep};
+    return *dep;
 }
 
+
+
+
+
+
+
+
 template<typename T, typename I>
-void celix::ServiceDependency<T,I>::enable() {
-    std::vector<celix::ServiceTracker> localTrackers{};
-    {
-        std::lock_guard<std::mutex> lck{mutex};
-        std::swap(localTrackers, tracker);
-        assert(tracker.size() == 0);
+celix::ServiceDependency<T,I>::ServiceDependency(
+        std::shared_ptr<celix::BundleContext> _ctx,
+        std::function<void()> _stateChangedCallback,
+        std::function<std::shared_ptr<T>()> _getCmpInstance) : GenericServiceDependency{_ctx, _stateChangedCallback, [this]{enable();}, [this]{disable();}}, getCmpInstance{_getCmpInstance} {};
 
+template<typename T, typename I>
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::enable() {
+    std::lock_guard<std::mutex> lck{mutex};
+    if (tracker.size() == 0) { //disabled
         ServiceTrackerOptions<I> opts{};
         opts.filter = this->filter;
-        opts.set = set;
-        opts.add = add;
-        opts.remove = rem;
-
+        opts.setWithOwner = set;
+        opts.addWithOwner = add;
+        opts.removeWithOwner = rem;
+        opts.updateWithOwner = [this](std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices) {
+            if (this->update) {
+                //TODO lock?
+                this->update(std::move(rankedServices));
+            }
+            this->stateChangedCallback();
+        };
         this->tracker.push_back(this->ctx->trackServices(opts));
     }
+    return *this;
+}
 
+template<typename T, typename I>
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::disable() {
+    std::lock_guard<std::mutex> lck{mutex};
+    tracker.clear();
+    return *this;
 }
 
 template<typename T, typename I>
-void celix::ServiceDependency<T,I>::disable() {
-    std::vector<celix::ServiceTracker> localTrackers{};
-    {
-        std::lock_guard<std::mutex> lck{mutex};
-        std::swap(localTrackers, tracker);
-        assert(tracker.size() == 0);
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setFunctionCallbacks(
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> setArg,
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> addArg,
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> remArg,
+        std::function<void(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices)> updateArg) {
+
+    //TODO lock or disable?
+    set = {};
+    add = {};
+    rem = {};
+    update = {};
+
+    if (setArg) {
+        set = std::move(setArg);
+    }
+    if (addArg) {
+        add = addArg;
+    }
+    if (remArg) {
+        rem = remArg;
+    }
+    if (updateArg) {
+        update = std::move(updateArg);
     }
+    return *this;
 }
 
-
 template<typename T, typename I>
 celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setCallbacks(void (T::*setfp)(std::shared_ptr<I>)) {
     std::lock_guard<std::mutex> lck{mutex};
-    set = [this, setfp](std::shared_ptr<I> svc) {
-        (mng->instance->*setfp)(svc);
+    auto setFunc = [this, setfp](std::shared_ptr<I> svc, const celix::Properties &, const celix::IResourceBundle &) {
+        (getCmpInstance()->instance->*setfp)(svc);
     };
-    return *this;
+    return setFunctionCallbacks(std::move(setFunc), {}, {}, {});
 }
 
+
 template<typename T, typename I>
 celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setCallbacks(void (T::*addfp)(std::shared_ptr<I>), void (T::*remfp)(std::shared_ptr<I>)) {
     std::lock_guard<std::mutex> lck{mutex};
-    add = [this, addfp](std::shared_ptr<I> svc) {
-        (mng->instance->*addfp)(svc);
-        mng->updateState();
+    auto addFunc = [this, addfp](std::shared_ptr<I> svc, const celix::Properties &, const celix::IResourceBundle &) {
+        (getCmpInstance()->instance->*addfp)(svc);
     };
-    rem = [this, remfp](std::shared_ptr<I> svc) {
-        (mng->instance->*remfp)(svc);
-        mng->updateState();
+    auto remFunc = [this, remfp](std::shared_ptr<I> svc, const celix::Properties &, const celix::IResourceBundle &) {
+        (getCmpInstance()->instance->*remfp)(svc);
     };
-    return *this;
+    return setFunctionCallbacks({}, std::move(addFunc), std::move(remFunc), {});
 }
 
 template<typename T, typename I>
@@ -285,4 +350,4 @@ celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setCardinality(cel
 }
 
 
-#endif //CXX_CELIX_PROPERTIES_H
+#endif //CXX_CELIX_COMPONENT_MANAGER_H
diff --git a/libs/framework_cxx/src/ComponentManager.cc b/libs/framework_cxx/src/ComponentManager.cc
index b3b4205..f087b19 100644
--- a/libs/framework_cxx/src/ComponentManager.cc
+++ b/libs/framework_cxx/src/ComponentManager.cc
@@ -19,10 +19,16 @@
 
 
 #include <iostream>
+#include <celix/ComponentManager.h>
+
 
 #include "celix/ComponentManager.h"
 
-celix::GenericServiceDependency::GenericServiceDependency(std::shared_ptr<celix::BundleContext> _ctx) : ctx{_ctx} {}
+celix::GenericServiceDependency::GenericServiceDependency(
+        std::shared_ptr<celix::BundleContext> _ctx,
+        std::function<void()> _stateChangedCallback,
+        std::function<void()> _enable,
+        std::function<void()> _disable) : ctx{_ctx}, stateChangedCallback{std::move(_stateChangedCallback)}, enable{std::move(_enable)}, disable{std::move(_disable)} {}
 
 
 bool celix::GenericServiceDependency::isResolved() const {
@@ -49,6 +55,14 @@ const std::string &celix::GenericServiceDependency::getFilter() const {
     return filter;
 }
 
+void celix::GenericServiceDependency::setEnable(bool e) {
+    if (e) {
+        enable();
+    } else {
+        disable();
+    }
+}
+
 celix::ComponentState celix::GenericComponentManager::getState() const {
     std::lock_guard<std::mutex> lck{mutex};
     return state;
@@ -62,11 +76,11 @@ bool celix::GenericComponentManager::isEnabled() const  {
 
 bool celix::GenericComponentManager::isResolved() const {
     std::lock_guard<std::mutex> lck{mutex};
-//    for (auto &pair : serviceDependencies) {
-//        if (!pair->second.isResolved()) {
-//            return false;
-//        }
-//    }
+    for (auto &pair : serviceDependencies) {
+        if (!pair.second->isResolved()) {
+            return false;
+        }
+    }
     return true;
 }
 
@@ -78,6 +92,9 @@ void celix::GenericComponentManager::removeServiceDependency(long serviceDepende
 void celix::GenericComponentManager::setEnabled(bool e) {
     std::lock_guard<std::mutex> lck{mutex};
     enabled = e;
+    for (auto &pair : serviceDependencies) {
+        pair.second->setEnable(e);
+    }
 }
 
 void celix::GenericComponentManager::updateState() {
@@ -89,7 +106,7 @@ void celix::GenericComponentManager::updateState() {
 
     bool allDependenciesResolved = true;
     for (auto &pair : serviceDependencies) {
-        if (!pair.second.isResolved()) {
+        if (!pair.second->isResolved()) {
             allDependenciesResolved = false;
             break;
         }
diff --git a/libs/registry/include/celix/ServiceRegistry.h b/libs/registry/include/celix/ServiceRegistry.h
index c9a9a8e..4457d0e 100644
--- a/libs/registry/include/celix/ServiceRegistry.h
+++ b/libs/registry/include/celix/ServiceRegistry.h
@@ -601,7 +601,7 @@ inline celix::ServiceTracker celix::ServiceRegistry::trackServices(std::string s
         };
     }
 
-    return trackAnyServices(std::move(svcName), std::move(opts), requester);
+    return trackAnyServices(std::move(svcName), std::move(opts), std::move(requester));
 }
 
 #endif //CXX_CELIX_SERVICEREGISTRY_H