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

pnoltes pushed a commit to branch 
feature/87-add-additional-svc-tracker-bundle-context-funtions
in repository https://gitbox.apache.org/repos/asf/celix.git


The following commit(s) were added to 
refs/heads/feature/87-add-additional-svc-tracker-bundle-context-funtions by 
this push:
     new 9321f514 gh-87: Add useService(s) methods to C++ ServiceTracker
9321f514 is described below

commit 9321f514d4613b577debab7f3e8e9fc0a46410d0
Author: Pepijn Noltes <pnol...@apache.org>
AuthorDate: Sun Feb 11 17:17:34 2024 +0100

    gh-87: Add useService(s) methods to C++ ServiceTracker
---
 .../gtest/src/CxxBundleContextTestSuite.cc         | 103 ++++++++++++++++++
 libs/framework/include/celix/Trackers.h            | 119 +++++++++++++++++++++
 2 files changed, 222 insertions(+)

diff --git a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc 
b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
index 5155c2bb..b987d28b 100644
--- a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
+++ b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
@@ -784,3 +784,106 @@ TEST_F(CxxBundleContextTestSuite, 
TestOldCStyleTrackerWithCxxMetaTracker) {
     serviceTracker_close(tracker);
     serviceTracker_destroy(tracker);
 }
+
+TEST_F(CxxBundleContextTestSuite, UseTrackedServidesTest) {
+    // Given 2 registered services
+    auto svc1 = std::make_shared<CInterface>(CInterface{nullptr, nullptr});
+    auto svcReg1 = ctx->registerService<CInterface>(svc1).build();
+    auto svc2 = std::make_shared<CInterface>(CInterface{nullptr, nullptr});
+    auto svcReg2 = ctx->registerService<CInterface>(svc2).build();
+
+    // And a tracker for the services
+    auto tracker = ctx->trackServices<CInterface>().build();
+    tracker->wait();
+
+    // Then I can use the useServices method to use the services
+    int count{0}; // note useService(s) callback are called in the current 
thread, so no need for atomic
+    size_t nrCalled = tracker->useServices([&count](CInterface& svc) {
+        (void)svc;
+        count++;
+    });
+    EXPECT_EQ(2, nrCalled);
+    EXPECT_EQ(2, count);
+
+    // And I can use the useServicesWithProperties method to use the services 
with their properties
+    count = 0;
+    nrCalled = tracker->useServicesWithProperties([&count](CInterface& svc, 
const celix::Properties& props) {
+        (void)svc;
+        long svcId = props.getAsLong(CELIX_FRAMEWORK_SERVICE_ID, -1L);
+        EXPECT_GE(svcId, 0);
+        count++;
+    });
+    EXPECT_EQ(2, nrCalled);
+    EXPECT_EQ(2, count);
+
+    // And I can use the useServicesWithOwner method to use the services with 
their properties and the bundle
+    count = 0;
+    nrCalled = tracker->useServicesWithOwner(
+        [&count](CInterface& svc, const celix::Properties& props, const 
celix::Bundle& bnd) {
+            (void)svc;
+            long svcId = props.getAsLong(CELIX_FRAMEWORK_SERVICE_ID, -1L);
+            EXPECT_GE(svcId, 0);
+            EXPECT_GE(bnd.getId(), 0);
+            count++;
+        });
+    EXPECT_EQ(2, nrCalled);
+    EXPECT_EQ(2, count);
+
+    // And I can use the useService method to use the highest ranking service
+    count = 0;
+    bool called = tracker->useService([&count](CInterface& svc) {
+        (void)svc;
+        count++;
+    });
+    EXPECT_TRUE(called);
+    EXPECT_EQ(1, count);
+
+    // And I can use the useServiceWithProperties method to use the highest 
ranking service with its properties
+    count = 0;
+    called = tracker->useServiceWithProperties([&count](CInterface& svc, const 
celix::Properties& props) {
+        (void)svc;
+        long svcId = props.getAsLong(CELIX_FRAMEWORK_SERVICE_ID, -1L);
+        EXPECT_GE(svcId, 0);
+        count++;
+    });
+    EXPECT_TRUE(called);
+    EXPECT_EQ(1, count);
+
+    // And I can use the useServiceWithOwner method to use the highest ranking 
service with its properties and the
+    // bundle
+    count = 0;
+    called = tracker->useServiceWithOwner(
+        [&count](CInterface& svc, const celix::Properties& props, const 
celix::Bundle& bnd) {
+            (void)svc;
+            long svcId = props.getAsLong(CELIX_FRAMEWORK_SERVICE_ID, -1L);
+            EXPECT_GE(svcId, 0);
+            EXPECT_GE(bnd.getId(), 0);
+            count++;
+        });
+    EXPECT_TRUE(called);
+    EXPECT_EQ(1, count);
+
+    // When registering a new service with a service raking of 100
+    auto svc3 = std::make_shared<CInterface>(CInterface{nullptr, nullptr});
+    auto svcReg3 = 
ctx->registerService<CInterface>(svc3).addProperty(celix::SERVICE_RANKING, 
100).build();
+    svcReg3->wait();
+
+    // Then the useServices method returns 3 services
+    count = 0;
+    nrCalled = tracker->useServices([&count](CInterface& svc) {
+        (void)svc;
+        count++;
+    });
+    EXPECT_EQ(3, nrCalled);
+    EXPECT_EQ(3, count);
+
+    // And the useServiceWithProperties method is called with a service with a 
service ranking of 100 and returns true
+    count = 0;
+    called = tracker->useServiceWithProperties([&count](CInterface& svc, const 
celix::Properties& props) {
+        (void)svc;
+        long ranking = props.getAsLong(celix::SERVICE_RANKING, -1L);
+        EXPECT_EQ(100, ranking);
+        count++;
+    });
+    EXPECT_TRUE(called);
+}
diff --git a/libs/framework/include/celix/Trackers.h 
b/libs/framework/include/celix/Trackers.h
index 60df7c86..1521757e 100644
--- a/libs/framework/include/celix/Trackers.h
+++ b/libs/framework/include/celix/Trackers.h
@@ -371,6 +371,98 @@ namespace celix {
             }
             return result;
         }
+
+        /**
+         * @brief Applies the provided function to each service being tracked.
+         *
+         * @tparam F A function or callable object type. The function 
signature should be equivalent to the following:
+         *           `void func(I& svc)`
+         *           where I is the service type being tracked.
+         * @param f The function or callable object to apply to each service.
+         * @return The number of services to which the function was applied.
+         */
+        template<typename F>
+        size_t useServices(const F& f) {
+            return this->template useServicesInternal(
+                [&f](I& svc, const celix::Properties&, const celix::Bundle&) { 
f(svc); });
+        }
+
+        /**
+         * @brief Applies the provided function to each service being tracked, 
along with its properties.
+         *
+         * @tparam F A function or callable object type. The function 
signature should be equivalent to the following:
+         *           `void func(I& svc, const celix::Properties& props)`
+         *           where I is the service type being tracked.
+         * @param f The function or callable object to apply to each service.
+         * @return The number of services to which the function was applied.
+         */
+        template<typename F>
+        size_t useServicesWithProperties(const F& f) {
+            return this->template useServicesInternal(
+                [&f](I& svc, const celix::Properties& props, const 
celix::Bundle&) { f(svc, props); });
+        }
+
+        /**
+         * @brief Applies the provided function to each service being tracked, 
along with its properties and owner
+         * bundle.
+         *
+         * @tparam F A function or callable object type. The function 
signature should be equivalent to the following:
+         *           `void func(I& svc, const celix::Properties& props, const 
celix::Bundle& bnd)`
+         *           where I is the service type being tracked.
+         * @param f The function or callable object to apply to each service.
+         * @return The number of services to which the function was applied.
+         */
+        template<typename F>
+        size_t useServicesWithOwner(const F& f) {
+            return this->template useServicesInternal(
+                [&f](I& svc, const celix::Properties& props, const 
celix::Bundle& bnd) { f(svc, props, bnd); });
+        }
+
+        /**
+         * @brief Applies the provided function to the highest ranking service 
being tracked.
+         *
+         * @tparam F A function or callable object type. The function 
signature should be equivalent to the following:
+         *           `void func(I& svc)`
+         *           where I is the service type being tracked.
+         * @param f The function or callable object to apply to the highest 
ranking service.
+         * @return True if the function was applied to a service, false 
otherwise.
+         */
+        template<typename F>
+        bool useService(const F& f) {
+            return this->template useServiceInternal(
+                [&f](I& svc, const celix::Properties&, const celix::Bundle&) { 
f(svc); });
+        }
+
+        /**
+         * @brief Applies the provided function to the highest ranking service 
being tracked, along with its properties.
+         *
+         * @tparam F A function or callable object type. The function 
signature should be equivalent to the following:
+         *           `void func(I& svc, const celix::Properties& props)`
+         *           where I is the service type being tracked.
+         * @param f The function or callable object to apply to the highest 
ranking service.
+         * @return True if the function was applied to a service, false 
otherwise.
+         */
+        template<typename F>
+        bool useServiceWithProperties(const F& f) {
+            return this->template useServiceInternal(
+                [&f](I& svc, const celix::Properties& props, const 
celix::Bundle&) { f(svc, props); });
+        }
+
+        /**
+         * @brief Applies the provided function to the highest ranking service 
being tracked, along with its properties
+         * and owner bundle.
+         *
+         * @tparam F A function or callable object type. The function 
signature should be equivalent to the following:
+         *           `void func(I& svc, const celix::Properties& props, const 
celix::Bundle& bnd)`
+         *           where I is the service type being tracked.
+         * @param f The function or callable object to apply to the highest 
ranking service.
+         * @return True if the function was applied to a service, false 
otherwise.
+         */
+        template<typename F>
+        bool useServiceWithOwner(const F& f) {
+            return this->template useServiceInternal(
+                [&f](I& svc, const celix::Properties& props, const 
celix::Bundle& bnd) { f(svc, props, bnd); });
+        }
     protected:
         struct SvcEntry {
             SvcEntry(long _svcId, long _svcRanking, std::shared_ptr<I> _svc,
@@ -561,6 +653,33 @@ namespace celix {
                 tracker->waitForExpiredSvcEntry(prevEntry);
             };
         }
+
+        template<typename F>
+        size_t useServicesInternal(const F& f) {
+            size_t count = 0;
+            std::lock_guard<std::mutex> lck{mutex};
+            for (auto& e : entries) {
+                I& svc = *e->svc;
+                const celix::Properties& props = *e->properties;
+                const celix::Bundle& owner = *e->owner;
+                f(svc, props, owner);
+                count++;
+            }
+            return count;
+        }
+
+        template<typename F>
+        bool useServiceInternal(const F& f) {
+            std::lock_guard<std::mutex> lck{mutex};
+            if (highestRankingServiceEntry) {
+                I& svc = *highestRankingServiceEntry->svc;
+                const celix::Properties& props = 
*highestRankingServiceEntry->properties;
+                const celix::Bundle& owner = 
*highestRankingServiceEntry->owner;
+                f(svc, props, owner);
+                return true;
+            }
+            return false;
+        }
     };
 
     /**

Reply via email to