From b95f2cd1654a167be5f77ff8e2e40da4e1375d0c Mon Sep 17 00:00:00 2001 From: Deedss Date: Tue, 31 Mar 2026 19:29:44 +0200 Subject: [PATCH 1/3] add property minimalCardinality to service dependencies --- .../gtest/src/DependencyManagerTestSuite.cc | 59 +++++++++++++++++++ .../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 +++- .../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().addInterface(); + cmp1.build(); + auto& cmp3 = dm.createComponent() + .createServiceDependency() + .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(); + 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& 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& setMinimalCardinality(size_t minimalCardinality); + /** * Specify if the update strategy to use * @@ -409,6 +416,13 @@ namespace celix { namespace dm { */ ServiceDependency& 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& 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& CServiceDependency::setRequired(bool req) { return *this; } +template +CServiceDependency& CServiceDependency::setMinimalCardinality(size_t minimalCardinality) { + celix_dmServiceDependency_setMinimalCardinality(this->cServiceDependency(), minimalCardinality); + return *this; +} + template CServiceDependency& CServiceDependency::setStrategy(DependencyUpdateStrategy strategy) { this->setDepStrategy(strategy); @@ -467,8 +473,13 @@ ServiceDependency& ServiceDependency::setRequired(bool req) { celix_dmServiceDependency_setRequired(this->cServiceDependency(), req); return *this; } +template +ServiceDependency& ServiceDependency::setMinimalCardinality(size_t minimalCardinality) { + celix_dmServiceDependency_setMinimalCardinality(this->cServiceDependency(), minimalCardinality); + return *this; +} -template +template ServiceDependency& ServiceDependency::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 }; From 733630f31ed5265d5007c22fd210c00450ee5fac Mon Sep 17 00:00:00 2001 From: Deedss Date: Tue, 31 Mar 2026 19:29:44 +0200 Subject: [PATCH 2/3] add property minimalCardinality to service dependencies --- libs/framework/src/dm_service_dependency.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/framework/src/dm_service_dependency.c b/libs/framework/src/dm_service_dependency.c index e69d2727c..f7ae17aca 100644 --- a/libs/framework/src/dm_service_dependency.c +++ b/libs/framework/src/dm_service_dependency.c @@ -97,7 +97,9 @@ celix_status_t celix_dmServiceDependency_setRequired(celix_dm_service_dependency } celix_status_t celix_dmServiceDependency_setMinimalCardinality(celix_dm_service_dependency_t *dependency, size_t minimalCardinality) { - dependency->minimalCardinality = minimalCardinality; + if (minimalCardinality > 0) { + dependency->minimalCardinality = minimalCardinality; + } return CELIX_SUCCESS; } From d469c5a5453ed45e53e0b28ec2d11479eb43c04f Mon Sep 17 00:00:00 2001 From: Deedss Date: Wed, 1 Apr 2026 11:19:54 +0200 Subject: [PATCH 3/3] update documentation --- libs/framework/include/celix/dm/ServiceDependency.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/framework/include/celix/dm/ServiceDependency.h b/libs/framework/include/celix/dm/ServiceDependency.h index 0dcf9fc86..37e137edc 100644 --- a/libs/framework/include/celix/dm/ServiceDependency.h +++ b/libs/framework/include/celix/dm/ServiceDependency.h @@ -166,7 +166,7 @@ namespace celix { namespace dm { CServiceDependency& setRequired(bool req); /** - * Specify if the minimum amount of services required for the service dependency to be available + * Specify the minimum amount of service dependencies required to be available * * @return the C service dependency reference for chaining (fluent API) */ @@ -417,7 +417,7 @@ namespace celix { namespace dm { ServiceDependency& setRequired(bool req); /** - * Specify if the minimum amount of services required for the service dependency to be available + * Specify the minimum amount of service dependencies required to be available * * @return the service dependency reference for chaining (fluent API) */