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 <[email protected]>
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;
+ }
};
/**