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

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

commit e4da77173539f368b400da2bf23870ced3e715f6
Author: Pepijn Noltes <[email protected]>
AuthorDate: Fri Apr 9 10:52:52 2021 +0200

    Adds setCallbacks functions with shared pointer support to the 
celix::dm::ServiceDependency class.
---
 .../gtest/src/CxxBundleContextTestSuite.cc         |  44 ++++-
 .../gtest/src/DependencyManagerTestSuite.cc        | 126 +++++++++++++
 .../framework/include/celix/dm/ServiceDependency.h | 131 ++++++++++++--
 .../include/celix/dm/ServiceDependency_Impl.h      | 194 +++++++++++++++++++--
 4 files changed, 458 insertions(+), 37 deletions(-)

diff --git a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc 
b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
index f77beed..ce019aa 100644
--- a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
+++ b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
@@ -238,21 +238,51 @@ TEST_F(CxxBundleContextTestSuite, TrackServicesTest) {
 
     std::atomic<int> count{0};
     auto tracker4 = ctx->trackServices<CInterface>()
-            .addAddCallback([&count](const std::shared_ptr<CInterface>&) {
+            .addAddCallback([&count](const std::shared_ptr<CInterface>& svc) {
+                EXPECT_TRUE(svc);
                 count += 1;
             })
-            .addRemCallback([&count](const std::shared_ptr<CInterface>&) {
+            .addRemCallback([&count](const std::shared_ptr<CInterface>& svc) {
+                EXPECT_TRUE(svc);
                 count += 1;
             })
             .build();
-    tracker4->wait();
-    EXPECT_EQ(2, count); //2x add called
+    auto tracker5 = ctx->trackServices<CInterface>()
+            .addAddWithPropertiesCallback([&count](std::shared_ptr<CInterface> 
svc /*note not the default expect const std::sharer_ptr<I>&*/, const 
std::shared_ptr<const celix::Properties>& props) {
+                EXPECT_TRUE(svc);
+                EXPECT_TRUE(props);
+                count += 1;
+            })
+            .addRemWithPropertiesCallback([&count](const 
std::shared_ptr<CInterface>& svc, const std::shared_ptr<const 
celix::Properties>& props) {
+                EXPECT_TRUE(svc);
+                EXPECT_TRUE(props);
+                count += 1;
+            })
+            .build();
+    auto tracker6 = ctx->trackServices<CInterface>()
+            .addAddWithOwnerCallback([&count](const 
std::shared_ptr<CInterface>& svc, std::shared_ptr<const celix::Properties> 
props /*note not the default expected const ref*/, std::shared_ptr<const 
celix::Bundle> bundle /*note not the default expected const ref*/) {
+                EXPECT_TRUE(svc);
+                EXPECT_TRUE(props);
+                EXPECT_TRUE(bundle);
+                count += 1;
+            })
+            .addRemWithOwnerCallback([&count](const 
std::shared_ptr<CInterface>& svc, const std::shared_ptr<const 
celix::Properties>& props, const std::shared_ptr<const celix::Bundle>& bundle) {
+                EXPECT_TRUE(svc);
+                EXPECT_TRUE(props);
+                EXPECT_TRUE(bundle);
+                count += 1;
+            })
+            .build();
+    ctx->waitForEvents();
+    EXPECT_EQ(6, count); //2x3 add called
     svcReg1->unregister();
     svcReg1->wait();
-    EXPECT_EQ(3, count); //2x add called, 1x rem called
+    EXPECT_EQ(9, count); //2x3 add called, 1x3 rem called
     tracker4->close();
-    tracker4->wait();
-    EXPECT_EQ(4, count); //2x add called, 2x rem called (1 rem call for 
closing the tracker)
+    tracker5->close();
+    tracker6->close();
+    ctx->waitForEvents();
+    EXPECT_EQ(12, count); //2x3 add called, 2x3 rem called (1 rem call for 
closing the tracker)
 
     EXPECT_EQ(1, tracker->getServiceCount()); //only 1 left
 
diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc 
b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
index 4bf1745..672a2f4 100644
--- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc
+++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
@@ -486,6 +486,132 @@ TEST_F(DependencyManagerTestSuite, 
RequiredDepsAreInjectedDuringStartStop) {
     celix_bundleContext_unregisterService(dm.bundleContext(), svcId);
 }
 
+TEST_F(DependencyManagerTestSuite, DepsAreInjectedAsSharedPointers) {
+    class LifecycleComponent {
+    public:
+        void start() {
+            std::lock_guard<std::mutex> lck{mutex};
+            EXPECT_TRUE(setSvc != nullptr);
+            EXPECT_EQ(services.size(), 1);
+        }
+
+        void stop() {
+            std::lock_guard<std::mutex> lck{mutex};
+            EXPECT_TRUE(setSvc != nullptr);
+            EXPECT_EQ(services.size(), 1);
+        }
+
+        void setService(const std::shared_ptr<TestService>& svc, const 
std::shared_ptr<const celix::Properties>& /*props*/) {
+            std::lock_guard<std::mutex> lck{mutex};
+            setSvc = svc;
+        }
+
+        void addService(const std::shared_ptr<TestService>& svc, const 
std::shared_ptr<const celix::Properties>& props) {
+            EXPECT_TRUE(props);
+            std::lock_guard<std::mutex> lck{mutex};
+            services.emplace_back(svc);
+        }
+
+        void remService(const std::shared_ptr<TestService>& svc, const 
std::shared_ptr<const celix::Properties>& props) {
+            EXPECT_TRUE(props);
+            std::lock_guard<std::mutex> lck{mutex};
+            for (auto it = services.begin(); it != services.end(); ++it) {
+                if (*it == svc) {
+                    services.erase(it);
+                    break;
+                }
+            }
+        }
+    private:
+        std::mutex mutex{};
+        std::shared_ptr<TestService> setSvc{};
+        std::vector<std::shared_ptr<TestService>> services{};
+    };
+
+    celix::dm::DependencyManager dm{ctx};
+    auto& cmp = dm.createComponent<LifecycleComponent>()
+            .setCallbacks(nullptr, &LifecycleComponent::start, 
&LifecycleComponent::stop, nullptr);
+    cmp.createServiceDependency<TestService>()
+            .setRequired(true)
+            .setCallbacks(&LifecycleComponent::setService)
+            .setCallbacks(&LifecycleComponent::addService, 
&LifecycleComponent::remService);
+    cmp.build();
+
+    TestService svc;
+    std::string svcName = celix::typeName<TestService>();
+    celix_service_registration_options opts{};
+    opts.svc = &svc;
+    opts.serviceName = svcName.c_str();
+    opts.serviceLanguage = CELIX_FRAMEWORK_SERVICE_CXX_LANGUAGE;
+    long svcId = 
celix_bundleContext_registerServiceWithOptions(dm.bundleContext(), &opts);
+    EXPECT_GE(svcId, 0);
+
+    EXPECT_EQ(cmp.getState(), ComponentState::TRACKING_OPTIONAL);
+    celix_bundleContext_unregisterService(dm.bundleContext(), svcId);
+}
+
+TEST_F(DependencyManagerTestSuite, DepsNoPropsAreInjectedAsSharedPointers) {
+    class LifecycleComponent {
+    public:
+        void start() {
+            std::lock_guard<std::mutex> lck{mutex};
+            EXPECT_TRUE(setSvc != nullptr);
+            EXPECT_EQ(services.size(), 1);
+        }
+
+        void stop() {
+            std::lock_guard<std::mutex> lck{mutex};
+            EXPECT_TRUE(setSvc != nullptr);
+            EXPECT_EQ(services.size(), 1);
+        }
+
+        void setService(const std::shared_ptr<TestService>& svc) {
+            std::lock_guard<std::mutex> lck{mutex};
+            setSvc = svc;
+        }
+
+        void addService(const std::shared_ptr<TestService>& svc) {
+            std::lock_guard<std::mutex> lck{mutex};
+            services.emplace_back(svc);
+        }
+
+        void remService(const std::shared_ptr<TestService>& svc) {
+            std::lock_guard<std::mutex> lck{mutex};
+            for (auto it = services.begin(); it != services.end(); ++it) {
+                if (*it == svc) {
+                    services.erase(it);
+                    break;
+                }
+            }
+        }
+    private:
+        std::mutex mutex{};
+        std::shared_ptr<TestService> setSvc{};
+        std::vector<std::shared_ptr<TestService>> services{};
+    };
+
+    celix::dm::DependencyManager dm{ctx};
+    auto& cmp = dm.createComponent<LifecycleComponent>()
+            .setCallbacks(nullptr, &LifecycleComponent::start, 
&LifecycleComponent::stop, nullptr);
+    cmp.createServiceDependency<TestService>()
+            .setRequired(true)
+            .setCallbacks(&LifecycleComponent::setService)
+            .setCallbacks(&LifecycleComponent::addService, 
&LifecycleComponent::remService);
+    cmp.build();
+
+    TestService svc;
+    std::string svcName = celix::typeName<TestService>();
+    celix_service_registration_options opts{};
+    opts.svc = &svc;
+    opts.serviceName = svcName.c_str();
+    opts.serviceLanguage = CELIX_FRAMEWORK_SERVICE_CXX_LANGUAGE;
+    long svcId = 
celix_bundleContext_registerServiceWithOptions(dm.bundleContext(), &opts);
+    EXPECT_GE(svcId, 0);
+
+    EXPECT_EQ(cmp.getState(), ComponentState::TRACKING_OPTIONAL);
+    celix_bundleContext_unregisterService(dm.bundleContext(), svcId);
+}
+
 TEST_F(DependencyManagerTestSuite, UnneededSuspendIsPrevented) {
     class CounterComponent {
     public:
diff --git a/libs/framework/include/celix/dm/ServiceDependency.h 
b/libs/framework/include/celix/dm/ServiceDependency.h
index eaa45a0..646969e 100644
--- a/libs/framework/include/celix/dm/ServiceDependency.h
+++ b/libs/framework/include/celix/dm/ServiceDependency.h
@@ -29,6 +29,7 @@
 #include <atomic>
 #include <vector>
 #include <cstring>
+#include <chrono>
 
 #include "dm_service_dependency.h"
 #include "celix_constants.h"
@@ -45,8 +46,9 @@ namespace celix { namespace dm {
 
     class BaseServiceDependency {
     private:
-        celix_dm_component_t* cCmp;
+        const std::chrono::milliseconds 
warningTimoutForNonExpiredSvcObject{5000};
         std::atomic<bool> depAddedToCmp{false};
+        celix_dm_component_t* cCmp;
     protected:
         celix_dm_service_dependency_t *cServiceDep {nullptr};
 
@@ -57,6 +59,9 @@ namespace celix { namespace dm {
                 
celix_dmServiceDependency_setStrategy(this->cServiceDependency(), 
DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND);
             }
         }
+
+        template<typename U>
+        void waitForExpired(std::weak_ptr<U> observe, long svcId, const char* 
observeType);
     public:
         BaseServiceDependency(celix_dm_component_t* c)  : cCmp{c} {
             this->cServiceDep = celix_dmServiceDependency_create();
@@ -119,6 +124,12 @@ namespace celix { namespace dm {
         void setComponentInstance(T* cmp) { componentInstance = cmp;}
     };
 
+    /**
+     * @brief A service dependency for a component.
+     * @tparam T The component type
+     * @tparam I The service interface type
+     * @warning CServiceDependency is considered deprecated use 
celix::dm::ServiceDependency instead.
+     */
     template<class T, typename I>
     class CServiceDependency : public TypedServiceDependency<T> {
         using type = I;
@@ -246,6 +257,11 @@ namespace celix { namespace dm {
         void setupService();
     };
 
+    /**
+     * @brief A service dependency for a component.
+     * @tparam T The component type
+     * @tparam I The service interface type
+     */
     template<class T, class I>
     class ServiceDependency : public TypedServiceDependency<T> {
         using type = I;
@@ -261,56 +277,84 @@ namespace celix { namespace dm {
         /**
          * Set the service name of the service dependency.
          *
-         * @return the C++ service dependency reference for chaining (fluent 
API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setName(const std::string &_name);
 
         /**
          * Set the service filter of the service dependency.
          *
-         * @return the C++ service dependency reference for chaining (fluent 
API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setFilter(const std::string &filter);
 
         /**
          * Set the service version range of the service dependency.
          *
-         * @return the C++ service dependency reference for chaining (fluent 
API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setVersionRange(const std::string 
&versionRange);
 
         /**
          * Set the set callback for when the service dependency becomes 
available
          *
-         * @return the C++ service dependency reference for chaining (fluent 
API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setCallbacks(void (T::*set)(I* service));
 
         /**
          * Set the set callback for when the service dependency becomes 
available
          *
-         * @return the C++ service dependency reference for chaining (fluent 
API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setCallbacks(void (T::*set)(I* service, 
Properties&& properties));
 
         /**
          * Set the set callback for when the service dependency becomes 
available
          *
-         * @return the C service dependency reference for chaining (fluent API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setCallbacks(std::function<void(I* service, 
Properties&& properties)> set);
 
         /**
+         * @brief Set the set callback for when the service dependency becomes 
available using shared pointers
+         *
+         * @return the service dependency reference for chaining (fluent API)
+         */
+        ServiceDependency<T,I>& setCallbacks(void (T::*set)(const 
std::shared_ptr<I>& service, const std::shared_ptr<const celix::Properties>& 
properties));
+
+        /**
+         * @brief Set the set callback for when the service dependency becomes 
available using shared pointers.
+         *
+         * @return the service dependency reference for chaining (fluent API)
+         */
+        ServiceDependency<T,I>& setCallbacks(std::function<void(const 
std::shared_ptr<I>& service, const std::shared_ptr<const celix::Properties>& 
properties)> set);
+
+        /**
+         * @brief Set the set callback for when the service dependency becomes 
available using shared pointers
+         *
+         * @return the service dependency reference for chaining (fluent API)
+         */
+        ServiceDependency<T,I>& setCallbacks(void (T::*set)(const 
std::shared_ptr<I>& service));
+
+        /**
+         * @brief Set the set callback for when the service dependency becomes 
available using shared pointers.
+         *
+         * @return the service dependency reference for chaining (fluent API)
+         */
+        ServiceDependency<T,I>& setCallbacks(std::function<void(const 
std::shared_ptr<I>& service)> set);
+
+        /**
          * Set the add and remove callback for when the services of service 
dependency are added or removed.
          *
-         * @return the C++ service dependency reference for chaining (fluent 
API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setCallbacks(void (T::*add)(I* service),  void 
(T::*remove)(I* service));
 
         /**
          * Set the add and remove callback for when the services of service 
dependency are added or removed.
          *
-         * @return the C++ service dependency reference for chaining (fluent 
API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setCallbacks(
                 void (T::*add)(I* service, Properties&& properties),
@@ -320,7 +364,7 @@ namespace celix { namespace dm {
         /**
          * Set the add and remove callback for when the services of service 
dependency are added or removed.
          *
-         * @return the C service dependency reference for chaining (fluent API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setCallbacks(
                 std::function<void(I* service, Properties&& properties)> add,
@@ -328,16 +372,53 @@ namespace celix { namespace dm {
         );
 
         /**
+         * @brief Set the add and remove callback for a service dependency 
using shared pointers.
+         *
+         * @return the service dependency reference for chaining (fluent API)
+         */
+        ServiceDependency<T,I>& setCallbacks(
+                void (T::*add)(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties),
+                void (T::*remove)(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties));
+
+        /**
+         * @brief Set the add and remove callback for a service dependency 
using shared pointers.
+         *
+         * @return the service dependency reference for chaining (fluent API)
+         */
+        ServiceDependency<T,I>& setCallbacks(
+                std::function<void(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties)> add,
+                std::function<void(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties)> remove);
+
+
+        /**
+         * @brief Set the add and remove callback for a service dependency 
using shared pointers.
+         *
+         * @return the service dependency reference for chaining (fluent API)
+         */
+        ServiceDependency<T,I>& setCallbacks(
+                void (T::*add)(const std::shared_ptr<I>& service),
+                void (T::*remove)(const std::shared_ptr<I>& service));
+
+        /**
+         * @brief Set the add and remove callback for a service dependency 
using shared pointers.
+         *
+         * @return the service dependency reference for chaining (fluent API)
+         */
+        ServiceDependency<T,I>& setCallbacks(
+                std::function<void(const std::shared_ptr<I>& service)> add,
+                std::function<void(const std::shared_ptr<I>& service)> remove);
+
+        /**
          * Specify if the service dependency is required. Default is false
          *
-         * @return the C service dependency reference for chaining (fluent API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setRequired(bool req);
 
         /**
          * Specify if the update strategy to use
          *
-         * @return the C service dependency reference for chaining (fluent API)
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setStrategy(DependencyUpdateStrategy strategy);
 
@@ -345,6 +426,8 @@ namespace celix { namespace dm {
          * Specify if the service dependency should add a service.lang filter 
part if it is not already present
          * For C++ service dependencies 'service.lang=C++' will be added.
          * Should be called before
+         *
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& setAddLanguageFilter(bool addLang);
 
@@ -354,26 +437,38 @@ namespace celix { namespace dm {
          * When build the service dependency is active and the service tracker 
is created.
          *
          * Should not be called on the Celix event thread.
+         *
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& build();
 
         /**
          * Same a build, but will not wait till the underlining service 
trackers are opened.
          * Can be called on the Celix event thread.
+         *
+         * @return the service dependency reference for chaining (fluent API)
          */
         ServiceDependency<T,I>& buildAsync();
     private:
+        void setupService();
+        void setupCallbacks();
+        int invokeCallback(std::function<void(I*, Properties&&)> fp, const 
celix_properties_t *props, const void* service);
+
         std::string name {};
         std::string filter {};
         std::string versionRange {};
 
-        std::function<void(I* service, Properties&& properties)> 
setFp{nullptr};
-        std::function<void(I* service, Properties&& properties)> 
addFp{nullptr};
-        std::function<void(I* service, Properties&& properties)> 
removeFp{nullptr};
+        std::function<void(I* service, Properties&& properties)> setFp{};
+        std::function<void(I* service, Properties&& properties)> addFp{};
+        std::function<void(I* service, Properties&& properties)> removeFp{};
 
-        void setupService();
-        void setupCallbacks();
-        int invokeCallback(std::function<void(I*, Properties&&)> fp, const 
celix_properties_t *props, const void* service);
+        std::function<void(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties)> setFpUsingSharedPtr{};
+        std::function<void(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties)> addFpUsingSharedPtr{};
+        std::function<void(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties)> removeFpUsingSharedPtr{};
+
+        //note below is only updated in the Celix event thread.
+        std::unordered_map<long, std::pair<std::shared_ptr<I>, 
std::shared_ptr<const celix::Properties>>> addedServices{};
+        std::pair<std::shared_ptr<I>, std::shared_ptr<const 
celix::Properties>> setService{};
     };
 }}
 
diff --git a/libs/framework/include/celix/dm/ServiceDependency_Impl.h 
b/libs/framework/include/celix/dm/ServiceDependency_Impl.h
index 753b517..2d53adf 100644
--- a/libs/framework/include/celix/dm/ServiceDependency_Impl.h
+++ b/libs/framework/include/celix/dm/ServiceDependency_Impl.h
@@ -20,6 +20,9 @@
 #include <vector>
 #include <iostream>
 #include <cstring>
+#include <thread>
+
+#include "celix/Constants.h"
 #include "celix_constants.h"
 #include "celix_properties.h"
 #include "celix_bundle_context.h"
@@ -29,6 +32,32 @@
 
 using namespace celix::dm;
 
+
+template<typename U>
+inline void BaseServiceDependency::waitForExpired(std::weak_ptr<U> observe, 
long svcId, const char* observeType) {
+    auto start = std::chrono::system_clock::now();
+    while (!observe.expired()) {
+        auto now = std::chrono::system_clock::now();
+        auto durationInMilli = 
std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
+        if (durationInMilli > warningTimoutForNonExpiredSvcObject) {
+            if (cCmp) {
+                auto* ctx = celix_dmComponent_getBundleContext(cCmp);
+                if (ctx) {
+                    celix_bundleContext_log(
+                            ctx,
+                            CELIX_LOG_LEVEL_WARNING,
+                            "celix::dm::ServiceDependency: Cannot remove %s 
associated with service.id %li, because it is still in use. Current shared_ptr 
use count is %i",
+                            observeType,
+                            svcId,
+                            (int)observe.use_count());
+                }
+            }
+            start = now;
+        }
+        std::this_thread::sleep_for(std::chrono::milliseconds{50});
+    }
+}
+
 inline void BaseServiceDependency::runBuild() {
     bool alreadyAdded = depAddedToCmp.exchange(true);
     if (!alreadyAdded) {
@@ -179,19 +208,19 @@ void CServiceDependency<T,I>::setupCallbacks() {
     int(*cadd)(void*, void *, const celix_properties_t*) {nullptr};
     int(*crem)(void*, void *, const celix_properties_t*) {nullptr};
 
-    if (setFp != nullptr) {
+    if (setFp) {
         cset = [](void* handle, void *service, const celix_properties_t 
*props) -> int {
             auto dep = (CServiceDependency<T,I>*) handle;
             return dep->invokeCallback(dep->setFp, props, service);
         };
     }
-    if (addFp != nullptr) {
+    if (addFp) {
         cadd = [](void* handle, void *service, const celix_properties_t 
*props) -> int {
             auto dep = (CServiceDependency<T,I>*) handle;
             return dep->invokeCallback(dep->addFp, props, service);
         };
     }
-    if (removeFp != nullptr) {
+    if (removeFp) {
         crem= [](void* handle, void *service, const celix_properties_t *props) 
-> int {
             auto dep = (CServiceDependency<T,I>*) handle;
             return dep->invokeCallback(dep->removeFp, props, service);
@@ -317,6 +346,40 @@ ServiceDependency<T,I>& 
ServiceDependency<T,I>::setCallbacks(std::function<void(
     return *this;
 }
 
+template<class T, class I>
+ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(void 
(T::*set)(const std::shared_ptr<I>& service, const std::shared_ptr<const 
celix::Properties>& properties)) {
+    this->setCallbacks([this, set](const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties) {
+        T *cmp = this->componentInstance;
+        (cmp->*set)(std::move(service), properties);
+    });
+    return *this;
+}
+
+template<class T, class I>
+ServiceDependency<T,I>& 
ServiceDependency<T,I>::setCallbacks(std::function<void(const 
std::shared_ptr<I>& service, const std::shared_ptr<const celix::Properties>& 
properties)> set) {
+    this->setFpUsingSharedPtr = std::move(set);
+    this->setupCallbacks();
+    return *this;
+}
+
+template<class T, class I>
+ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(void 
(T::*set)(const std::shared_ptr<I>& service)) {
+    this->setCallbacks([this, set](const std::shared_ptr<I>& service) {
+        T *cmp = this->componentInstance;
+        (cmp->*set)(service);
+    });
+    return *this;
+}
+
+template<class T, class I>
+ServiceDependency<T,I>& 
ServiceDependency<T,I>::setCallbacks(std::function<void(const 
std::shared_ptr<I>& service)> set) {
+    this->setCallbacks([set](const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& /*properties*/) {
+        set(service);
+    });
+    return *this;
+}
+
+
 //add remove callbacks
 template<class T, class I>
 ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
@@ -353,6 +416,7 @@ ServiceDependency<T,I>& 
ServiceDependency<T,I>::setCallbacks(
     return *this;
 }
 
+
 template<class T, class I>
 ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
         std::function<void(I* service, Properties&& properties)> add,
@@ -364,6 +428,70 @@ ServiceDependency<T,I>& 
ServiceDependency<T,I>::setCallbacks(
 }
 
 template<class T, class I>
+ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
+        void (T::*add)(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties),
+        void (T::*remove)(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties)
+) {
+    this->setCallbacks(
+            [this, add](const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties) {
+                T *cmp = this->componentInstance;
+                (cmp->*add)(service, properties);
+            },
+            [this, remove](const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties) {
+                T *cmp = this->componentInstance;
+                (cmp->*remove)(service, properties);
+            }
+    );
+    return *this;
+}
+
+
+template<class T, class I>
+ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
+        std::function<void(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties)> add,
+        std::function<void(const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& properties)> remove) {
+    this->addFpUsingSharedPtr = std::move(add);
+    this->removeFpUsingSharedPtr = std::move(remove);
+    this->setupCallbacks();
+    return *this;
+}
+
+template<class T, class I>
+ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
+        void (T::*add)(const std::shared_ptr<I>& service),
+        void (T::*remove)(const std::shared_ptr<I>& service)
+) {
+    this->setCallbacks(
+            [this, add](const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& /*properties*/) {
+                T *cmp = this->componentInstance;
+                (cmp->*add)(service);
+            },
+            [this, remove](const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& /*properties*/) {
+                T *cmp = this->componentInstance;
+                (cmp->*remove)(service);
+            }
+    );
+    return *this;
+}
+
+
+template<class T, class I>
+ServiceDependency<T,I>& ServiceDependency<T,I>::setCallbacks(
+        std::function<void(const std::shared_ptr<I>& service)> add,
+        std::function<void(const std::shared_ptr<I>& service)> remove) {
+    this->setCallbacks(
+            [add](const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& /*properties*/) {
+                add(service);
+            },
+            [remove](const std::shared_ptr<I>& service, const 
std::shared_ptr<const celix::Properties>& /*properties*/) {
+                remove(service);
+            }
+    );
+    return *this;
+}
+
+
+template<class T, class I>
 ServiceDependency<T,I>& ServiceDependency<T,I>::setRequired(bool req) {
     celix_dmServiceDependency_setRequired(this->cServiceDependency(), req);
     return *this;
@@ -403,22 +531,64 @@ void ServiceDependency<T,I>::setupCallbacks() {
     int(*cadd)(void*, void *, const celix_properties_t*) {nullptr};
     int(*crem)(void*, void *, const celix_properties_t*) {nullptr};
 
-    if (setFp != nullptr) {
-        cset = [](void* handle, void *service, const celix_properties_t* 
props) -> int {
+    if (setFp || setFpUsingSharedPtr) {
+        cset = [](void* handle, void* rawSvc, const celix_properties_t* 
rawProps) -> int {
+            int rc = 0;
             auto dep = (ServiceDependency<T,I>*) handle;
-            return dep->invokeCallback(dep->setFp, props, service);
+            if (dep->setFp) {
+                rc = dep->invokeCallback(dep->setFp, rawProps, rawSvc);
+            }
+            if (dep->setFpUsingSharedPtr) {
+                auto svcId = dep->setService.second ? 
dep->setService.second->getAsLong(celix::SERVICE_ID, -1) : -1;
+                std::weak_ptr<I> currentSvc = dep->setService.first;
+                std::weak_ptr<const celix::Properties> currentProps = 
dep->setService.second;
+                auto svc = std::shared_ptr<I>{static_cast<I*>(rawSvc), 
[](I*){/*nop*/}};
+                auto props = rawProps ? celix::Properties::wrap(rawProps) : 
nullptr;
+                dep->setService = std::make_pair(std::move(svc), 
std::move(props));
+                dep->setFpUsingSharedPtr(dep->setService.first, 
dep->setService.second);
+                dep->waitForExpired(currentSvc, svcId, "service pointer");
+                dep->waitForExpired(currentProps, svcId, "service properties");
+            }
+            return rc;
         };
     }
-    if (addFp != nullptr) {
-        cadd = [](void* handle, void *service, const celix_properties_t* 
props) -> int {
+    if (addFp || addFpUsingSharedPtr) {
+        cadd = [](void* handle, void *rawSvc, const celix_properties_t* 
rawProps) -> int {
+            int rc = 0;
             auto dep = (ServiceDependency<T,I>*) handle;
-            return dep->invokeCallback(dep->addFp, props, service);
+            if (dep->addFp) {
+                rc = dep->invokeCallback(dep->addFp, rawProps, rawSvc);
+            }
+            if (dep->addFpUsingSharedPtr) {
+                auto props = celix::Properties::wrap(rawProps);
+                auto svc = std::shared_ptr<I>{static_cast<I*>(rawSvc), 
[](I*){/*nop*/}};
+                auto svcId = props->getAsLong(celix::SERVICE_ID, -1);
+                dep->addFpUsingSharedPtr(svc, props);
+                dep->addedServices.template emplace(svcId, 
std::make_pair(std::move(svc), std::move(props)));
+            }
+            return rc;
         };
     }
-    if (removeFp != nullptr) {
-        crem = [](void* handle, void *service, const celix_properties_t*props) 
-> int {
+    if (removeFp || removeFpUsingSharedPtr) {
+        crem = [](void* handle, void *rawSvc, const celix_properties_t* 
rawProps) -> int {
+            int rc = 0;
             auto dep = (ServiceDependency<T,I>*) handle;
-            return dep->invokeCallback(dep->removeFp, props, service);
+            if (dep->removeFp) {
+                rc = dep->invokeCallback(dep->removeFp, rawProps, rawSvc);
+            }
+            if (dep->removeFpUsingSharedPtr) {
+                auto svcId = celix_properties_getAsLong(rawProps, 
celix::SERVICE_ID, -1);
+                auto it = dep->addedServices.find(svcId);
+                if (it != dep->addedServices.end()) {
+                    std::weak_ptr<I> currentSvc = it->second.first;
+                    std::weak_ptr<const celix::Properties> currentProps = 
it->second.second;
+                    dep->removeFpUsingSharedPtr(it->second.first, 
it->second.second);
+                    dep->addedServices.erase(it);
+                    dep->template waitForExpired(currentSvc, svcId, "service 
pointer");
+                    dep->template waitForExpired(currentProps, svcId, "service 
properties");
+                }
+            }
+            return rc;
         };
     }
 

Reply via email to