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

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

commit 03580b681910cca56e3e3c86e7f2813fa353e906
Author: Deedss <[email protected]>
AuthorDate: Tue Mar 31 19:29:44 2026 +0200

    add property minimalCardinality to service dependencies
---
 .../gtest/src/DependencyManagerTestSuite.cc        | 59 ++++++++++++++++++++++
 .../framework/include/celix/dm/ServiceDependency.h | 14 +++++
 .../include/celix/dm/ServiceDependency_Impl.h      | 13 ++++-
 libs/framework/include/celix_dm_info.h             |  1 +
 .../include/celix_dm_service_dependency.h          |  5 ++
 libs/framework/src/dm_component_impl.c             |  9 ++--
 libs/framework/src/dm_service_dependency.c         | 11 +++-
 libs/framework/src/dm_service_dependency_impl.h    |  1 +
 8 files changed, 106 insertions(+), 7 deletions(-)

diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc 
b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
index 53d9e432c..b1ab31627 100644
--- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc
+++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
@@ -1277,3 +1277,62 @@ TEST_F(DependencyManagerTestSuite, TestPrintInfo) {
     ss << cmp;
     EXPECT_TRUE(strstr(ss.str().c_str(), "Cmp1"));
 }
+
+TEST_F(DependencyManagerTestSuite, TestCardinality) {
+    celix::dm::DependencyManager dm{ctx};
+    auto& cmp1 = dm.createComponent<Cmp1>().addInterface<TestService>();
+    cmp1.build();
+    auto& cmp3 = dm.createComponent<Cmp3>()
+                     .createServiceDependency<TestService>()
+                     .setRequired(true)
+                     .setMinimalCardinality(2);
+    cmp3.build();
+
+    dm.build();
+
+    {
+        auto info = dm.getInfo();
+        ASSERT_EQ(info.components.size(), 2);
+        auto& cmpInfo = info.components;
+        auto cmpIt =
+            std::find_if(cmpInfo.cbegin(), cmpInfo.cend(), [](const 
ComponentInfo& cmp) { return cmp.name == "Cmp3"; });
+        ASSERT_TRUE(cmpIt != cmpInfo.cend());
+
+        EXPECT_TRUE(!cmpIt->uuid.empty());
+        EXPECT_EQ(cmpIt->state, "WAITING_FOR_REQUIRED");
+        EXPECT_FALSE(cmpIt->isActive);
+        EXPECT_EQ(cmpIt->nrOfTimesStarted, 0);
+        EXPECT_EQ(cmpIt->nrOfTimesResumed, 0);
+
+        ASSERT_EQ(cmpIt->dependenciesInfo.size(), 1);
+        auto& dep = cmpIt->dependenciesInfo[0];
+        EXPECT_EQ(dep.serviceName, "TestService");
+        EXPECT_EQ(dep.isRequired, true);
+        EXPECT_EQ(dep.isAvailable, false);
+        EXPECT_EQ(dep.nrOfTrackedServices, 1);
+    }
+
+    auto& cmp2 = dm.createComponent(Cmp2{"c"}).addInterface<TestService>();
+    cmp2.build();
+
+    {
+        auto info = dm.getInfo();
+        ASSERT_EQ(info.components.size(), 3);
+        auto& cmpInfo = info.components;
+        auto cmpIt =
+            std::find_if(cmpInfo.cbegin(), cmpInfo.cend(), [](const 
ComponentInfo& cmp) { return cmp.name == "Cmp3"; });
+        ASSERT_TRUE(cmpIt != cmpInfo.cend());
+
+        EXPECT_TRUE(!cmpIt->uuid.empty());
+        EXPECT_TRUE(cmpIt->isActive);
+        EXPECT_EQ(cmpIt->nrOfTimesStarted, 1);
+        EXPECT_EQ(cmpIt->nrOfTimesResumed, 0);
+
+        ASSERT_EQ(cmpIt->dependenciesInfo.size(), 1);
+        auto& dep = cmpIt->dependenciesInfo[0];
+        EXPECT_EQ(dep.serviceName, "TestService");
+        EXPECT_EQ(dep.isRequired, true);
+        EXPECT_EQ(dep.isAvailable, true);
+        EXPECT_EQ(dep.nrOfTrackedServices, 2);
+    }
+}
\ No newline at end of file
diff --git a/libs/framework/include/celix/dm/ServiceDependency.h 
b/libs/framework/include/celix/dm/ServiceDependency.h
index f8a343f07..0dcf9fc86 100644
--- a/libs/framework/include/celix/dm/ServiceDependency.h
+++ b/libs/framework/include/celix/dm/ServiceDependency.h
@@ -165,6 +165,13 @@ namespace celix { namespace dm {
          */
         CServiceDependency<T,I>& setRequired(bool req);
 
+        /**
+         * Specify if the minimum amount of services required for the service 
dependency to be available
+         *
+         * @return the C service dependency reference for chaining (fluent API)
+         */
+        CServiceDependency<T,I>& setMinimalCardinality(size_t 
minimalCardinality);
+
         /**
          * Specify if the update strategy to use
          *
@@ -409,6 +416,13 @@ namespace celix { namespace dm {
          */
         ServiceDependency<T,I>& setRequired(bool req);
 
+        /**
+         * Specify if the minimum amount of services required for the service 
dependency to be available
+         *
+         * @return the service dependency reference for chaining (fluent API)
+         */
+        ServiceDependency<T,I>& setMinimalCardinality(size_t 
minimalCardinality);
+
         /**
          * Specify if the update strategy to use
          *
diff --git a/libs/framework/include/celix/dm/ServiceDependency_Impl.h 
b/libs/framework/include/celix/dm/ServiceDependency_Impl.h
index 4867db910..06256de9b 100644
--- a/libs/framework/include/celix/dm/ServiceDependency_Impl.h
+++ b/libs/framework/include/celix/dm/ServiceDependency_Impl.h
@@ -118,6 +118,12 @@ CServiceDependency<T,I>& 
CServiceDependency<T,I>::setRequired(bool req) {
     return *this;
 }
 
+template<class T, typename I>
+CServiceDependency<T,I>& CServiceDependency<T,I>::setMinimalCardinality(size_t 
minimalCardinality) {
+    
celix_dmServiceDependency_setMinimalCardinality(this->cServiceDependency(), 
minimalCardinality);
+    return *this;
+}
+
 template<class T, typename I>
 CServiceDependency<T,I>& 
CServiceDependency<T,I>::setStrategy(DependencyUpdateStrategy strategy) {
     this->setDepStrategy(strategy);
@@ -467,8 +473,13 @@ ServiceDependency<T,I>& 
ServiceDependency<T,I>::setRequired(bool req) {
     celix_dmServiceDependency_setRequired(this->cServiceDependency(), req);
     return *this;
 }
+template <class T, class I>
+ServiceDependency<T, I>& ServiceDependency<T, I>::setMinimalCardinality(size_t 
minimalCardinality) {
+    
celix_dmServiceDependency_setMinimalCardinality(this->cServiceDependency(), 
minimalCardinality);
+    return *this;
+}
 
-template<class T, class I>
+template <class T, class I>
 ServiceDependency<T,I>& 
ServiceDependency<T,I>::setStrategy(DependencyUpdateStrategy strategy) {
     this->setDepStrategy(strategy);
     return *this;
diff --git a/libs/framework/include/celix_dm_info.h 
b/libs/framework/include/celix_dm_info.h
index ab7c65497..eaece5950 100644
--- a/libs/framework/include/celix_dm_info.h
+++ b/libs/framework/include/celix_dm_info.h
@@ -43,6 +43,7 @@ struct celix_dm_service_dependency_info_struct {
     char *filter;
     char *versionRange;
     bool available;
+    size_t minimalCardinality;
     bool required;
     size_t count;
 };
diff --git a/libs/framework/include/celix_dm_service_dependency.h 
b/libs/framework/include/celix_dm_service_dependency.h
index 28d25ef5c..2c5c4c7d0 100644
--- a/libs/framework/include/celix_dm_service_dependency.h
+++ b/libs/framework/include/celix_dm_service_dependency.h
@@ -89,6 +89,11 @@ 
CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_dm_service_dependency_t, celix_dmService
  */
 CELIX_FRAMEWORK_EXPORT celix_status_t 
celix_dmServiceDependency_setRequired(celix_dm_service_dependency_t 
*dependency, bool required);
 
+/**
+ * Specify the minimum number of services the service dependency requires 
before being available.
+ */
+CELIX_FRAMEWORK_EXPORT celix_status_t 
celix_dmServiceDependency_setMinimalCardinality(celix_dm_service_dependency_t 
*dependency, size_t minimalCardinality);
+
 /**
  * Specify if the service dependency update strategy.
  *
diff --git a/libs/framework/src/dm_component_impl.c 
b/libs/framework/src/dm_component_impl.c
index 2afb709fb..770beabbb 100644
--- a/libs/framework/src/dm_component_impl.c
+++ b/libs/framework/src/dm_component_impl.c
@@ -1106,10 +1106,11 @@ static void celix_dmComponent_printFullInfo(FILE *out, 
bool colors, celix_dm_com
             }
         }
         fprintf(out, "   |- %sDependency %i: %s%s\n", depStartColors, 
(depCnt+1), dependency->serviceName == NULL ? "(any)" : 
dependency->serviceName, endColors);
-        fprintf(out, "      | %15s = %s\n", "Available", dependency->available 
? "true " : "false");
-        fprintf(out, "      | %15s = %s\n", "Required", dependency->required ? 
"true " : "false");
-        fprintf(out, "      | %15s = %s\n", "Version Range", 
dependency->versionRange == NULL ? "N/A" : dependency->versionRange);
-        fprintf(out, "      | %15s = %s\n", "Filter", dependency->filter == 
NULL ? "N/A" : dependency->filter);
+        fprintf(out, "      | %20s = %s\n", "Available", dependency->available 
? "true " : "false");
+        fprintf(out, "      | %20s = %lu\n", "Minimal Cardinality", 
dependency->minimalCardinality);
+        fprintf(out, "      | %20s = %s\n", "Required", dependency->required ? 
"true " : "false");
+        fprintf(out, "      | %20s = %s\n", "Version Range", 
dependency->versionRange == NULL ? "N/A" : dependency->versionRange);
+        fprintf(out, "      | %20s = %s\n", "Filter", dependency->filter == 
NULL ? "N/A" : dependency->filter);
     }
     fprintf(out, "\n");
 }
diff --git a/libs/framework/src/dm_service_dependency.c 
b/libs/framework/src/dm_service_dependency.c
index ab80e835b..e69d2727c 100644
--- a/libs/framework/src/dm_service_dependency.c
+++ b/libs/framework/src/dm_service_dependency.c
@@ -48,6 +48,7 @@ celix_dm_service_dependency_t* 
celix_dmServiceDependency_create() {
        celix_dm_service_dependency_t *dep = calloc(1, sizeof(*dep));
        dep->strategy = DM_SERVICE_DEPENDENCY_DEFAULT_STRATEGY;
        dep->svcTrackerId = -1;
+    dep->minimalCardinality = 1;
        celixThreadMutex_create(&dep->mutex, NULL);
     return dep;
 }
@@ -95,6 +96,11 @@ celix_status_t 
celix_dmServiceDependency_setRequired(celix_dm_service_dependency
        return status;
 }
 
+celix_status_t 
celix_dmServiceDependency_setMinimalCardinality(celix_dm_service_dependency_t 
*dependency, size_t minimalCardinality) {
+    dependency->minimalCardinality = minimalCardinality;
+    return CELIX_SUCCESS;
+}
+
 celix_status_t serviceDependency_setStrategy(celix_dm_service_dependency_t 
*dependency, dm_service_dependency_strategy_t strategy) {
        return celix_dmServiceDependency_setStrategy(dependency, strategy);
 }
@@ -310,7 +316,7 @@ celix_status_t 
celix_dmServiceDependency_invokeRemove(celix_dm_service_dependenc
 
 bool celix_dmServiceDependency_isAvailable(celix_dm_service_dependency_t 
*dependency) {
     celixThreadMutex_lock(&dependency->mutex);
-    bool avail = dependency->trackedSvcCount > 0;
+    bool avail = dependency->trackedSvcCount >= dependency->minimalCardinality;
     celixThreadMutex_unlock(&dependency->mutex);
     return avail;
 }
@@ -347,7 +353,8 @@ dm_service_dependency_info_t* 
celix_dmServiceDependency_createInfo(celix_dm_serv
        celix_dm_service_dependency_info_t *info = calloc(1, sizeof(*info));
        if (info != NULL) {
                celixThreadMutex_lock(&dep->mutex);
-               info->available = dep->trackedSvcCount > 0;
+               info->available = dep->trackedSvcCount >= 
dep->minimalCardinality;
+        info->minimalCardinality = dep->minimalCardinality;
                info->serviceName = celix_utils_strdup(dep->serviceName);
                info->filter = celix_utils_strdup(dep->filter);
                info->versionRange = celix_utils_strdup(dep->versionRange);
diff --git a/libs/framework/src/dm_service_dependency_impl.h 
b/libs/framework/src/dm_service_dependency_impl.h
index 6d43785d6..d8288e836 100644
--- a/libs/framework/src/dm_service_dependency_impl.h
+++ b/libs/framework/src/dm_service_dependency_impl.h
@@ -59,6 +59,7 @@ struct celix_dm_service_dependency {
     long svcTrackerId;                 // active tracker id
     size_t nrOfActiveStoppingTrackers; // nr of async stop tracker still 
active (should be 0 or 1)
     size_t trackedSvcCount;
+    size_t minimalCardinality;         // minimal nr of service required for 
availability
     void* callbackHandle; // This handle can be set to be used instead of the 
component implementation
 };
 

Reply via email to