From b95f2cd1654a167be5f77ff8e2e40da4e1375d0c Mon Sep 17 00:00:00 2001 From: Deedss Date: Tue, 31 Mar 2026 19:29:44 +0200 Subject: [PATCH 01/12] 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 02/12] 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 03/12] 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) */ From 1a9592f9577d846d8ec2e91288068a67c2cb6056 Mon Sep 17 00:00:00 2001 From: Deedss Date: Sat, 4 Apr 2026 17:35:49 +0000 Subject: [PATCH 04/12] - Fix formatting in changed files. - Add service count to printinfo --- .../include/celix/dm/ServiceDependency_Impl.h | 1 + libs/framework/src/dm_component_impl.c | 1 + libs/framework/src/dm_service_dependency.c | 24 +++++++++---------- .../src/dm_service_dependency_impl.h | 4 ++-- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/libs/framework/include/celix/dm/ServiceDependency_Impl.h b/libs/framework/include/celix/dm/ServiceDependency_Impl.h index 06256de9b..8b0a95f52 100644 --- a/libs/framework/include/celix/dm/ServiceDependency_Impl.h +++ b/libs/framework/include/celix/dm/ServiceDependency_Impl.h @@ -473,6 +473,7 @@ 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); diff --git a/libs/framework/src/dm_component_impl.c b/libs/framework/src/dm_component_impl.c index 770beabbb..f30487067 100644 --- a/libs/framework/src/dm_component_impl.c +++ b/libs/framework/src/dm_component_impl.c @@ -1108,6 +1108,7 @@ 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, " | %20s = %s\n", "Available", dependency->available ? "true " : "false"); fprintf(out, " | %20s = %lu\n", "Minimal Cardinality", dependency->minimalCardinality); + fprintf(out, " | %20s = %lu\n", "Service Count", dependency->count); 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); diff --git a/libs/framework/src/dm_service_dependency.c b/libs/framework/src/dm_service_dependency.c index f7ae17aca..33c045d23 100644 --- a/libs/framework/src/dm_service_dependency.c +++ b/libs/framework/src/dm_service_dependency.c @@ -352,19 +352,19 @@ celix_status_t serviceDependency_getServiceDependencyInfo(celix_dm_service_depen } dm_service_dependency_info_t* celix_dmServiceDependency_createInfo(celix_dm_service_dependency_t* dep) { - celix_dm_service_dependency_info_t *info = calloc(1, sizeof(*info)); - if (info != NULL) { - celixThreadMutex_lock(&dep->mutex); - info->available = dep->trackedSvcCount >= dep->minimalCardinality; + celix_dm_service_dependency_info_t* info = calloc(1, sizeof(*info)); + if (info != NULL) { + celixThreadMutex_lock(&dep->mutex); + 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); - info->required = dep->required; - info->count = dep->trackedSvcCount; - celixThreadMutex_unlock(&dep->mutex); - } - return info; + info->serviceName = celix_utils_strdup(dep->serviceName); + info->filter = celix_utils_strdup(dep->filter); + info->versionRange = celix_utils_strdup(dep->versionRange); + info->required = dep->required; + info->count = dep->trackedSvcCount; + celixThreadMutex_unlock(&dep->mutex); + } + return info; } diff --git a/libs/framework/src/dm_service_dependency_impl.h b/libs/framework/src/dm_service_dependency_impl.h index d8288e836..eb705e394 100644 --- a/libs/framework/src/dm_service_dependency_impl.h +++ b/libs/framework/src/dm_service_dependency_impl.h @@ -59,8 +59,8 @@ 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 + 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 }; celix_status_t celix_dmServiceDependency_enable(celix_dm_service_dependency_t *dependency); From ceea87abc1732d141841733d4c1dd58af2d7058d Mon Sep 17 00:00:00 2001 From: Deedss Date: Tue, 7 Apr 2026 19:09:08 +0000 Subject: [PATCH 05/12] Expand testcase with downflank --- .../gtest/src/DependencyManagerTestSuite.cc | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc b/libs/framework/gtest/src/DependencyManagerTestSuite.cc index b1ab31627..70a692f70 100644 --- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc +++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc @@ -1299,7 +1299,7 @@ TEST_F(DependencyManagerTestSuite, TestCardinality) { ASSERT_TRUE(cmpIt != cmpInfo.cend()); EXPECT_TRUE(!cmpIt->uuid.empty()); - EXPECT_EQ(cmpIt->state, "WAITING_FOR_REQUIRED"); + EXPECT_EQ(cmpIt->state, celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED)); EXPECT_FALSE(cmpIt->isActive); EXPECT_EQ(cmpIt->nrOfTimesStarted, 0); EXPECT_EQ(cmpIt->nrOfTimesResumed, 0); @@ -1335,4 +1335,28 @@ TEST_F(DependencyManagerTestSuite, TestCardinality) { EXPECT_EQ(dep.isAvailable, true); EXPECT_EQ(dep.nrOfTrackedServices, 2); } + + dm.removeComponent(cmp2.getUUID()); + + { + 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, celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED)); + EXPECT_FALSE(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, false); + EXPECT_EQ(dep.nrOfTrackedServices, 1); + } } \ No newline at end of file From c97255da6f1b8ce76eb07e4a67ba5a915da55fbc Mon Sep 17 00:00:00 2001 From: Deedss Date: Wed, 8 Apr 2026 19:08:50 +0000 Subject: [PATCH 06/12] Rework minimalCardinality to influence whether a service is required or not. --- .../baz/src/BazActivator.cc | 3 +- .../foo/src/FooActivator.cc | 3 +- .../phase2a/src/phase2a_activator.c | 2 +- .../phase2b/src/phase2b_activator.c | 2 +- .../dm_example/phase3/src/phase3_activator.c | 2 +- .../phase2/src/Phase2aActivator.cc | 3 +- .../phase2/src/Phase2bActivator.cc | 3 +- .../phase3/src/Phase3Activator.cc | 1 - .../phase3/src/Phase3BaseActivator.cc | 2 +- ...ponent_with_service_dependency_activator.c | 4 +- ...ComponentWithServiceDependencyActivator.cc | 3 +- .../include/celix/dm/ServiceDependency.h | 20 +- .../include/celix/dm/ServiceDependency_Impl.h | 13 -- .../include/celix_dm_service_dependency.h | 10 +- .../dm_service_dependency.h | 5 - libs/framework/src/dm_service_dependency.c | 177 ++++++++---------- .../src/dm_service_dependency_impl.h | 1 - 17 files changed, 103 insertions(+), 151 deletions(-) diff --git a/examples/celix-examples/dependency_manager_example_cxx/baz/src/BazActivator.cc b/examples/celix-examples/dependency_manager_example_cxx/baz/src/BazActivator.cc index a7023ccba..d80326e78 100644 --- a/examples/celix-examples/dependency_manager_example_cxx/baz/src/BazActivator.cc +++ b/examples/celix-examples/dependency_manager_example_cxx/baz/src/BazActivator.cc @@ -28,13 +28,12 @@ class BazActivator { .setCallbacks(nullptr, &Baz::start, &Baz::stop, nullptr); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setStrategy(DependencyUpdateStrategy::locking) .setVersionRange(IANOTHER_EXAMPLE_CONSUMER_RANGE) .setCallbacks(&Baz::addAnotherExample, &Baz::removeAnotherExample); cmp.createCServiceDependency(EXAMPLE_NAME) - .setRequired(false) .setStrategy(DependencyUpdateStrategy::locking) .setVersionRange(EXAMPLE_CONSUMER_RANGE) .setCallbacks(&Baz::addExample, &Baz::removeExample); diff --git a/examples/celix-examples/dependency_manager_example_cxx/foo/src/FooActivator.cc b/examples/celix-examples/dependency_manager_example_cxx/foo/src/FooActivator.cc index af79f4a8d..c558c8056 100644 --- a/examples/celix-examples/dependency_manager_example_cxx/foo/src/FooActivator.cc +++ b/examples/celix-examples/dependency_manager_example_cxx/foo/src/FooActivator.cc @@ -29,12 +29,11 @@ class FooActivator { .setCallbacks(nullptr, &Foo::start, &Foo::stop, nullptr); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setVersionRange(IANOTHER_EXAMPLE_CONSUMER_RANGE) .setCallbacks(&Foo::setAnotherExample); cmp.createCServiceDependency(EXAMPLE_NAME) - .setRequired(false) .setVersionRange(EXAMPLE_CONSUMER_RANGE) .setCallbacks(&Foo::setExample); } diff --git a/examples/celix-examples/dm_example/phase2a/src/phase2a_activator.c b/examples/celix-examples/dm_example/phase2a/src/phase2a_activator.c index f0849b770..e4bb33a71 100644 --- a/examples/celix-examples/dm_example/phase2a/src/phase2a_activator.c +++ b/examples/celix-examples/dm_example/phase2a/src/phase2a_activator.c @@ -56,7 +56,7 @@ static celix_status_t activator_start(struct phase2a_activator_struct *act, celi celix_dmServiceDependency_setService(dep, PHASE1_NAME, PHASE1_RANGE_ALL, NULL); celix_dmServiceDependency_setCallback(dep, (void*)phase2a_setPhase1); celix_dmServiceDependency_setStrategy(dep, DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING); - celix_dmServiceDependency_setRequired(dep, true); + celix_dmServiceDependency_setMinimalCardinality(dep, 1); celix_dmComponent_addServiceDependency(cmp, dep); celix_dependency_manager_t *mng = celix_bundleContext_getDependencyManager(ctx); diff --git a/examples/celix-examples/dm_example/phase2b/src/phase2b_activator.c b/examples/celix-examples/dm_example/phase2b/src/phase2b_activator.c index c912aed33..38679f2bc 100644 --- a/examples/celix-examples/dm_example/phase2b/src/phase2b_activator.c +++ b/examples/celix-examples/dm_example/phase2b/src/phase2b_activator.c @@ -56,7 +56,7 @@ static celix_status_t activator_start(struct phase2b_activator_struct *act, celi celix_dm_service_dependency_t *dep = celix_dmServiceDependency_create(); celix_dmServiceDependency_setService(dep, PHASE1_NAME, PHASE1_RANGE_EXACT, NULL); celix_dmServiceDependency_setCallback(dep, (void*)phase2b_setPhase1); - celix_dmServiceDependency_setRequired(dep, true); + celix_dmServiceDependency_setMinimalCardinality(dep, 1); celix_dmServiceDependency_setStrategy(dep, DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING); celix_dmComponent_addServiceDependency(cmp, dep); diff --git a/examples/celix-examples/dm_example/phase3/src/phase3_activator.c b/examples/celix-examples/dm_example/phase3/src/phase3_activator.c index 33a7bd1e8..be7fc7f37 100644 --- a/examples/celix-examples/dm_example/phase3/src/phase3_activator.c +++ b/examples/celix-examples/dm_example/phase3/src/phase3_activator.c @@ -47,7 +47,7 @@ static celix_status_t activator_start(struct phase3_activator_struct *act, celix opts.add = (void*)phase3_addPhase2; opts.remove = (void*)phase3_removePhase2; celix_dmServiceDependency_setCallbacksWithOptions(dep, &opts); - celix_dmServiceDependency_setRequired(dep, true); + celix_dmServiceDependency_setMinimalCardinality(dep, 1); celix_dmComponent_addServiceDependency(cmp, dep); celix_dependency_manager_t *mng = celix_bundleContext_getDependencyManager(ctx); diff --git a/examples/celix-examples/dm_example_cxx/phase2/src/Phase2aActivator.cc b/examples/celix-examples/dm_example_cxx/phase2/src/Phase2aActivator.cc index 150b36ba5..3dbe0bf7e 100644 --- a/examples/celix-examples/dm_example_cxx/phase2/src/Phase2aActivator.cc +++ b/examples/celix-examples/dm_example_cxx/phase2/src/Phase2aActivator.cc @@ -36,7 +36,7 @@ class Phase2aActivator { .addInterface(IPHASE2_VERSION, props); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setCallbacks(&Phase2Cmp::setPhase1); cmp.createServiceDependency() @@ -44,7 +44,6 @@ class Phase2aActivator { .setCallbacks(&Phase2Cmp::setName); cmp.createCServiceDependency(CELIX_LOG_SERVICE_NAME) - .setRequired(false) .setCallbacks(&Phase2Cmp::setLogService); } }; diff --git a/examples/celix-examples/dm_example_cxx/phase2/src/Phase2bActivator.cc b/examples/celix-examples/dm_example_cxx/phase2/src/Phase2bActivator.cc index 9c09cc969..977d914e8 100644 --- a/examples/celix-examples/dm_example_cxx/phase2/src/Phase2bActivator.cc +++ b/examples/celix-examples/dm_example_cxx/phase2/src/Phase2bActivator.cc @@ -32,11 +32,10 @@ class Phase2bActivator { .addInterface(IPHASE2_VERSION, props); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setCallbacks(&Phase2Cmp::setPhase1); cmp.createCServiceDependency(CELIX_LOG_SERVICE_NAME) - .setRequired(false) .setCallbacks(&Phase2Cmp::setLogService); } }; diff --git a/examples/celix-examples/dm_example_cxx/phase3/src/Phase3Activator.cc b/examples/celix-examples/dm_example_cxx/phase3/src/Phase3Activator.cc index 3c3e0e3aa..ae7e4e259 100644 --- a/examples/celix-examples/dm_example_cxx/phase3/src/Phase3Activator.cc +++ b/examples/celix-examples/dm_example_cxx/phase3/src/Phase3Activator.cc @@ -26,7 +26,6 @@ using namespace celix::dm; Phase3Activator::Phase3Activator(std::shared_ptr mng) : Phase3BaseActivator{mng} { cmp.createServiceDependency() - .setRequired(false) .setFilter("(&(name=phase2a)(non-existing=*))") .setCallbacks(&Phase3Cmp::setPhase2a); } diff --git a/examples/celix-examples/dm_example_cxx/phase3/src/Phase3BaseActivator.cc b/examples/celix-examples/dm_example_cxx/phase3/src/Phase3BaseActivator.cc index dc8f85a13..815a9585d 100644 --- a/examples/celix-examples/dm_example_cxx/phase3/src/Phase3BaseActivator.cc +++ b/examples/celix-examples/dm_example_cxx/phase3/src/Phase3BaseActivator.cc @@ -26,6 +26,6 @@ Phase3BaseActivator::Phase3BaseActivator(std::shared_ptr mng) cmp.setCallbacks(nullptr, &Phase3Cmp::start, &Phase3Cmp::stop, nullptr); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setCallbacks(&Phase3Cmp::addPhase2, &Phase3Cmp::removePhase2); } diff --git a/examples/celix-examples/readme_c_examples/src/component_with_service_dependency_activator.c b/examples/celix-examples/readme_c_examples/src/component_with_service_dependency_activator.c index c0ccfc3a1..bf1261982 100644 --- a/examples/celix-examples/readme_c_examples/src/component_with_service_dependency_activator.c +++ b/examples/celix-examples/readme_c_examples/src/component_with_service_dependency_activator.c @@ -94,7 +94,7 @@ static celix_status_t componentWithServiceDependencyActivator_start(component_wi celix_dm_service_dependency_t* dep1 = celix_dmServiceDependency_create(); // <-----------------------------------<4> celix_dmServiceDependency_setService(dep1, CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL); // <-------------------<5> celix_dmServiceDependency_setStrategy(dep1, DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND); // <------------------------<6> - celix_dmServiceDependency_setRequired(dep1, true); // <----------------------------------------------------------<7> + celix_dmServiceDependency_setMinimalCardinality(dep1, 1); // <----------------------------------------------------------<7> celix_dm_service_dependency_callback_options_t opts1 = CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; // <--<8> opts1.set = (void*)componentWithServiceDependency_setHighestRankingShellCommand; // <----------------------------<9> celix_dmServiceDependency_setCallbacksWithOptions(dep1, &opts1); // <-------------------------------------------<10> @@ -104,7 +104,7 @@ static celix_status_t componentWithServiceDependencyActivator_start(component_wi celix_dm_service_dependency_t* dep2 = celix_dmServiceDependency_create(); celix_dmServiceDependency_setService(dep2, CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL); celix_dmServiceDependency_setStrategy(dep2, DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING); // <----------------------<12> - celix_dmServiceDependency_setRequired(dep2, false); // <--------------------------------------------------------<13> + celix_dmServiceDependency_setMinimalCardinality(dep2, 0); // <--------------------------------------------------------<13> celix_dm_service_dependency_callback_options_t opts2 = CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; opts2.addWithProps = (void*)componentWithServiceDependency_addShellCommand; // <-------------------------------<14> opts2.removeWithProps = (void*)componentWithServiceDependency_removeShellCommand; diff --git a/examples/celix-examples/readme_cxx_examples/src/ComponentWithServiceDependencyActivator.cc b/examples/celix-examples/readme_cxx_examples/src/ComponentWithServiceDependencyActivator.cc index 1ba315001..0dbf0e6a2 100644 --- a/examples/celix-examples/readme_cxx_examples/src/ComponentWithServiceDependencyActivator.cc +++ b/examples/celix-examples/readme_cxx_examples/src/ComponentWithServiceDependencyActivator.cc @@ -60,12 +60,11 @@ class ComponentWithServiceDependencyActivator { cmp.createServiceDependency() .setCallbacks(&Cmp::setHighestRankingShellCommand) - .setRequired(true) + .setMinimalCardinality(1) .setStrategy(DependencyUpdateStrategy::suspend); cmp.createServiceDependency(CELIX_SHELL_COMMAND_SERVICE_NAME) .setCallbacks(&Cmp::addCShellCmd, &Cmp::removeCShellCmd) - .setRequired(false) .setStrategy(DependencyUpdateStrategy::locking); cmp.build(); // <--------------------------------------------------------------------------------------------<8> diff --git a/libs/framework/include/celix/dm/ServiceDependency.h b/libs/framework/include/celix/dm/ServiceDependency.h index 37e137edc..3245624f4 100644 --- a/libs/framework/include/celix/dm/ServiceDependency.h +++ b/libs/framework/include/celix/dm/ServiceDependency.h @@ -159,14 +159,10 @@ namespace celix { namespace dm { CServiceDependency& setFilter(const std::string &filter); /** - * Specify if the service dependency is required. Default is false + * Specify the minimum number of services the service dependency requires before being counted as available. * - * @return the C service dependency reference for chaining (fluent API) - */ - CServiceDependency& setRequired(bool req); - - /** - * Specify the minimum amount of service dependencies required to be available + * The minimal cardinality also affects whether a service is required. By default, the minimal cardinality is 0, + * implying that a service is not required. * * @return the C service dependency reference for chaining (fluent API) */ @@ -410,14 +406,10 @@ namespace celix { namespace dm { std::function& service)> remove); /** - * Specify if the service dependency is required. Default is false + * Specify the minimum number of services the service dependency requires before being counted as available. * - * @return the service dependency reference for chaining (fluent API) - */ - ServiceDependency& setRequired(bool req); - - /** - * Specify the minimum amount of service dependencies required to be available + * The minimal cardinality also affects whether a service is required. By default, the minimal cardinality is 0, + * implying that a service is not required. * * @return the service dependency reference for chaining (fluent API) */ diff --git a/libs/framework/include/celix/dm/ServiceDependency_Impl.h b/libs/framework/include/celix/dm/ServiceDependency_Impl.h index 8b0a95f52..25f4e99a3 100644 --- a/libs/framework/include/celix/dm/ServiceDependency_Impl.h +++ b/libs/framework/include/celix/dm/ServiceDependency_Impl.h @@ -112,12 +112,6 @@ void CServiceDependency::setupService() { celix_dmServiceDependency_setService(this->cServiceDependency(), this->name.c_str(), cversion, cfilter); } -template -CServiceDependency& CServiceDependency::setRequired(bool req) { - celix_dmServiceDependency_setRequired(this->cServiceDependency(), req); - return *this; -} - template CServiceDependency& CServiceDependency::setMinimalCardinality(size_t minimalCardinality) { celix_dmServiceDependency_setMinimalCardinality(this->cServiceDependency(), minimalCardinality); @@ -467,13 +461,6 @@ ServiceDependency& ServiceDependency::setCallbacks( return *this; } - -template -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); diff --git a/libs/framework/include/celix_dm_service_dependency.h b/libs/framework/include/celix_dm_service_dependency.h index 2c5c4c7d0..b17e07159 100644 --- a/libs/framework/include/celix_dm_service_dependency.h +++ b/libs/framework/include/celix_dm_service_dependency.h @@ -85,12 +85,10 @@ CELIX_FRAMEWORK_EXPORT void celix_dmServiceDependency_destroy(celix_dm_service_d CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_dm_service_dependency_t, celix_dmServiceDependency_destroy); /** - * Specify if the service dependency is required. default is false - */ -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. + * Specify the minimum number of services the service dependency requires before being counted as available. + * + * The minimal cardinality also affects whether a service is required. By default, the minimal cardinality is 0, + * implying that a service is not required. */ CELIX_FRAMEWORK_EXPORT celix_status_t celix_dmServiceDependency_setMinimalCardinality(celix_dm_service_dependency_t *dependency, size_t minimalCardinality); diff --git a/libs/framework/include_deprecated/dm_service_dependency.h b/libs/framework/include_deprecated/dm_service_dependency.h index eba99c019..3a0976588 100644 --- a/libs/framework/include_deprecated/dm_service_dependency.h +++ b/libs/framework/include_deprecated/dm_service_dependency.h @@ -70,11 +70,6 @@ CELIX_FRAMEWORK_DEPRECATED_EXPORT celix_status_t serviceDependency_create(celix_ */ CELIX_FRAMEWORK_DEPRECATED_EXPORT celix_status_t serviceDependency_destroy(celix_dm_service_dependency_t **dep); -/** - * Specify if the service dependency is required. default is false - */ -CELIX_FRAMEWORK_DEPRECATED_EXPORT celix_status_t serviceDependency_setRequired(celix_dm_service_dependency_t *dependency, bool required); - /** * Specify if the service dependency update strategy. * diff --git a/libs/framework/src/dm_service_dependency.c b/libs/framework/src/dm_service_dependency.c index 33c045d23..665f0535f 100644 --- a/libs/framework/src/dm_service_dependency.c +++ b/libs/framework/src/dm_service_dependency.c @@ -45,19 +45,18 @@ celix_status_t serviceDependency_create(celix_dm_service_dependency_t **dependen } 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); + celix_dm_service_dependency_t* dep = calloc(1, sizeof(*dep)); + dep->strategy = DM_SERVICE_DEPENDENCY_DEFAULT_STRATEGY; + dep->svcTrackerId = -1; + celixThreadMutex_create(&dep->mutex, NULL); return dep; } celix_status_t serviceDependency_destroy(celix_dm_service_dependency_t **dependency_ptr) { - if (dependency_ptr != NULL) { - celix_dmServiceDependency_destroy(*dependency_ptr); - } - return CELIX_SUCCESS; + if (dependency_ptr != NULL) { + celix_dmServiceDependency_destroy(*dependency_ptr); + } + return CELIX_SUCCESS; } void celix_dmServiceDependency_destroy(celix_dm_service_dependency_t *dep) { @@ -78,54 +77,39 @@ void celix_dmServiceDependency_destroy(celix_dm_service_dependency_t *dep) { } } -celix_status_t serviceDependency_setRequired(celix_dm_service_dependency_t *dependency, bool required) { - return celix_dmServiceDependency_setRequired(dependency, required); -} - -celix_status_t celix_dmServiceDependency_setRequired(celix_dm_service_dependency_t *dependency, bool required) { - celix_status_t status = CELIX_SUCCESS; - - if (!dependency) { - status = CELIX_ILLEGAL_ARGUMENT; - } - - if (status == CELIX_SUCCESS) { - dependency->required = required; - } - - return status; -} - celix_status_t celix_dmServiceDependency_setMinimalCardinality(celix_dm_service_dependency_t *dependency, size_t minimalCardinality) { - if (minimalCardinality > 0) { + celix_status_t status = CELIX_SUCCESS; + if (!dependency) { + status = CELIX_ILLEGAL_ARGUMENT; + } else { dependency->minimalCardinality = minimalCardinality; } - return CELIX_SUCCESS; + return status; } celix_status_t serviceDependency_setStrategy(celix_dm_service_dependency_t *dependency, dm_service_dependency_strategy_t strategy) { - return celix_dmServiceDependency_setStrategy(dependency, strategy); + return celix_dmServiceDependency_setStrategy(dependency, strategy); } celix_status_t celix_dmServiceDependency_setStrategy(celix_dm_service_dependency_t *dependency, dm_service_dependency_strategy_t strategy) { dependency->strategy = strategy; - return CELIX_SUCCESS; + return CELIX_SUCCESS; } celix_status_t serviceDependency_getStrategy(celix_dm_service_dependency_t *dependency, dm_service_dependency_strategy_t* strategy) { - celix_dm_service_dependency_strategy_t str = celix_dmServiceDependency_getStrategy(dependency); - if (strategy != NULL) { - *strategy = str; - } - return CELIX_SUCCESS; + celix_dm_service_dependency_strategy_t str = celix_dmServiceDependency_getStrategy(dependency); + if (strategy != NULL) { + *strategy = str; + } + return CELIX_SUCCESS; } celix_dm_service_dependency_strategy_t celix_dmServiceDependency_getStrategy(celix_dm_service_dependency_t *dependency) { - return dependency->strategy; + return dependency->strategy; } celix_status_t serviceDependency_setService(celix_dm_service_dependency_t *dependency, const char* serviceName, const char* serviceVersionRange, const char* filter) { - return celix_dmServiceDependency_setService(dependency, serviceName, serviceVersionRange, filter); + return celix_dmServiceDependency_setService(dependency, serviceName, serviceVersionRange, filter); } celix_status_t celix_dmServiceDependency_setService(celix_dm_service_dependency_t *dependency, const char* serviceName, const char* serviceVersionRange, const char* filter) { @@ -145,15 +129,15 @@ celix_status_t celix_dmServiceDependency_setService(celix_dm_service_dependency_ } celix_status_t serviceDependency_getFilter(celix_dm_service_dependency_t *dependency, const char** filter) { - const char *f = celix_dmServiceDependency_getFilter(dependency); - if (filter != NULL) { - *filter = f; - } - return CELIX_SUCCESS; + const char* f = celix_dmServiceDependency_getFilter(dependency); + if (filter != NULL) { + *filter = f; + } + return CELIX_SUCCESS; } const char* celix_dmServiceDependency_getFilter(celix_dm_service_dependency_t *dependency) { - return (const char*)dependency->filter; + return (const char*)dependency->filter; } celix_status_t serviceDependency_setCallbacks(celix_dm_service_dependency_t *dependency, service_set_fpt set, service_add_fpt add, service_change_fpt change CELIX_UNUSED, service_remove_fpt remove, service_swap_fpt swap CELIX_UNUSED) { @@ -164,57 +148,55 @@ celix_status_t serviceDependency_setCallbacks(celix_dm_service_dependency_t *dep } celix_status_t celix_dmServiceDependency_setCallback(celix_dm_service_dependency_t *dependency, celix_dm_service_update_fp set) { - dependency->set = set; - return CELIX_SUCCESS; + dependency->set = set; + return CELIX_SUCCESS; } - celix_status_t celix_dmServiceDependency_setCallbackWithProperties(celix_dm_service_dependency_t *dependency, celix_dm_service_update_with_props_fp set) { - dependency->setWithProperties = set; - return CELIX_SUCCESS; + dependency->setWithProperties = set; + return CELIX_SUCCESS; } - celix_status_t celix_dmServiceDependency_setCallbacksWithOptions(celix_dm_service_dependency_t *dependency, const celix_dm_service_dependency_callback_options_t *opts) { - dependency->set = opts->set; - dependency->add = opts->add; - dependency->remove = opts->remove; + dependency->set = opts->set; + dependency->add = opts->add; + dependency->remove = opts->remove; - dependency->setWithProperties = opts->setWithProps; - dependency->addWithProperties = opts->addWithProps; - dependency->remWithProperties = opts->removeWithProps; - return CELIX_SUCCESS; + dependency->setWithProperties = opts->setWithProps; + dependency->addWithProperties = opts->addWithProps; + dependency->remWithProperties = opts->removeWithProps; + return CELIX_SUCCESS; } celix_status_t celix_dmServiceDependency_setComponent(celix_dm_service_dependency_t *dependency, celix_dm_component_t *component) { dependency->component = component; - return CELIX_SUCCESS; + return CELIX_SUCCESS; } celix_status_t celix_dmServiceDependency_enable(celix_dm_service_dependency_t* dependency) { - celix_bundle_context_t* ctx = celix_dmComponent_getBundleContext(dependency->component); + celix_bundle_context_t* ctx = celix_dmComponent_getBundleContext(dependency->component); - if (dependency->serviceName == NULL && dependency->filter == NULL) { - celix_bundleContext_log( - ctx, CELIX_LOG_LEVEL_ERROR, "Cannot start a service dependency without a service name and filter"); - return CELIX_ILLEGAL_ARGUMENT; - } + if (dependency->serviceName == NULL && dependency->filter == NULL) { + celix_bundleContext_log( + ctx, CELIX_LOG_LEVEL_ERROR, "Cannot start a service dependency without a service name and filter"); + return CELIX_ILLEGAL_ARGUMENT; + } - celixThreadMutex_lock(&dependency->mutex); - if (dependency->svcTrackerId == -1L) { - celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; - opts.filter.filter = dependency->filter; - opts.filter.serviceName = dependency->serviceName; - opts.filter.versionRange = dependency->versionRange; - opts.callbackHandle = dependency; - opts.addWithProperties = serviceDependency_addServiceTrackerCallback; - opts.removeWithProperties = serviceDependency_removeServiceTrackerCallback; - opts.setWithProperties = serviceDependency_setServiceTrackerCallback; - dependency->svcTrackerId = celix_bundleContext_trackServicesWithOptionsAsync(ctx, &opts); - } - celixThreadMutex_unlock(&dependency->mutex); + celixThreadMutex_lock(&dependency->mutex); + if (dependency->svcTrackerId == -1L) { + celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; + opts.filter.filter = dependency->filter; + opts.filter.serviceName = dependency->serviceName; + opts.filter.versionRange = dependency->versionRange; + opts.callbackHandle = dependency; + opts.addWithProperties = serviceDependency_addServiceTrackerCallback; + opts.removeWithProperties = serviceDependency_removeServiceTrackerCallback; + opts.setWithProperties = serviceDependency_setServiceTrackerCallback; + dependency->svcTrackerId = celix_bundleContext_trackServicesWithOptionsAsync(ctx, &opts); + } + celixThreadMutex_unlock(&dependency->mutex); - return CELIX_SUCCESS; + return CELIX_SUCCESS; } static void celix_serviceDependency_stopCallback(void *data) { @@ -234,7 +216,7 @@ celix_status_t celix_dmServiceDependency_disable(celix_dm_service_dependency_t * } celixThreadMutex_unlock(&dependency->mutex); - return CELIX_SUCCESS; + return CELIX_SUCCESS; } bool celix_dmServiceDependency_isDisabled(celix_dm_service_dependency_t *dependency) { @@ -318,13 +300,18 @@ 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 >= dependency->minimalCardinality; + bool avail = false; + if (dependency->minimalCardinality == 0) { + avail = dependency->trackedSvcCount > 0; + } else { + avail = dependency->trackedSvcCount >= dependency->minimalCardinality; + } celixThreadMutex_unlock(&dependency->mutex); return avail; } bool celix_dmServiceDependency_isRequired(const celix_dm_service_dependency_t* dep) { - return dep->required; + return dep->minimalCardinality > 0; } bool celix_dmServiceDependency_isTrackerOpen(celix_dm_service_dependency_t* dependency) { @@ -345,10 +332,10 @@ bool celix_dmServiceDependency_isAddRemCallbacksConfigured(celix_dm_service_depe } celix_status_t serviceDependency_getServiceDependencyInfo(celix_dm_service_dependency_t *dep, dm_service_dependency_info_t **out) { - if (out != NULL) { - *out = celix_dmServiceDependency_createInfo(dep); - } - return CELIX_SUCCESS; + if (out != NULL) { + *out = celix_dmServiceDependency_createInfo(dep); + } + return CELIX_SUCCESS; } dm_service_dependency_info_t* celix_dmServiceDependency_createInfo(celix_dm_service_dependency_t* dep) { @@ -360,7 +347,7 @@ dm_service_dependency_info_t* celix_dmServiceDependency_createInfo(celix_dm_serv info->serviceName = celix_utils_strdup(dep->serviceName); info->filter = celix_utils_strdup(dep->filter); info->versionRange = celix_utils_strdup(dep->versionRange); - info->required = dep->required; + info->required = dep->minimalCardinality > 0; info->count = dep->trackedSvcCount; celixThreadMutex_unlock(&dep->mutex); } @@ -369,24 +356,24 @@ dm_service_dependency_info_t* celix_dmServiceDependency_createInfo(celix_dm_serv void dependency_destroyDependencyInfo(dm_service_dependency_info_pt info) { - celix_dmServiceDependency_destroyInfo(NULL, info); + celix_dmServiceDependency_destroyInfo(NULL, info); } void celix_dmServiceDependency_destroyInfo(celix_dm_service_dependency_t *dep CELIX_UNUSED, dm_service_dependency_info_t *info) { - if (info != NULL) { - free(info->serviceName); - free(info->filter); - free(info->versionRange); - } - free(info); + if (info != NULL) { + free(info->serviceName); + free(info->filter); + free(info->versionRange); + } + free(info); } celix_status_t serviceDependency_setCallbackHandle(celix_dm_service_dependency_t *dependency, void* handle) { - return celix_dmServiceDependency_setCallbackHandle(dependency, handle); + return celix_dmServiceDependency_setCallbackHandle(dependency, handle); } celix_status_t celix_dmServiceDependency_setCallbackHandle(celix_dm_service_dependency_t *dependency, void* handle) { - dependency->callbackHandle = handle; + dependency->callbackHandle = handle; return CELIX_SUCCESS; } diff --git a/libs/framework/src/dm_service_dependency_impl.h b/libs/framework/src/dm_service_dependency_impl.h index eb705e394..1e5beb2bb 100644 --- a/libs/framework/src/dm_service_dependency_impl.h +++ b/libs/framework/src/dm_service_dependency_impl.h @@ -51,7 +51,6 @@ struct celix_dm_service_dependency { char* serviceName; char* filter; char* versionRange; - bool required; dm_service_dependency_strategy_t strategy; celix_dm_component_t* component; From bfb47ead54961420baf6fa0de0aafbdfa894662c Mon Sep 17 00:00:00 2001 From: Deedss Date: Wed, 8 Apr 2026 19:11:59 +0000 Subject: [PATCH 07/12] Update all usages of setRequired with setMinimalCardinality as minimalCardinality now determines whether a serviceDependency is required. --- .../gtest/src/InactiveComponentBundle.cc | 2 +- .../admin/src/RemoteServiceAdminActivator.cc | 3 --- .../integration/src/CalculatorConsumer.cc | 2 +- .../integration/src/CalculatorProvider.cc | 4 ++-- .../TestExportImportRemoteServiceFactory.cc | 8 +++---- .../src/celix_event_admin_activator.c | 2 +- .../rsa_shm/src/rsa_shm_activator.c | 2 +- .../src/DependencyManagerBenchmark.cc | 2 +- .../gtest/src/DependencyManagerTestSuite.cc | 23 +++++++++---------- 9 files changed, 22 insertions(+), 26 deletions(-) diff --git a/bundles/components_ready_check/gtest/src/InactiveComponentBundle.cc b/bundles/components_ready_check/gtest/src/InactiveComponentBundle.cc index af4109ed0..8b795ae1b 100644 --- a/bundles/components_ready_check/gtest/src/InactiveComponentBundle.cc +++ b/bundles/components_ready_check/gtest/src/InactiveComponentBundle.cc @@ -34,7 +34,7 @@ class InactiveComponentBundleActivator { auto& cmp = ctx->getDependencyManager()->createComponent(); cmp.createServiceDependency(CELIX_CONDITION_SERVICE_NAME) .setFilter("(condition.id=does-not-exists)") - .setRequired(true); + .setMinimalCardinality(1); cmp.build(); } diff --git a/bundles/cxx_remote_services/admin/src/RemoteServiceAdminActivator.cc b/bundles/cxx_remote_services/admin/src/RemoteServiceAdminActivator.cc index 0b646ac5d..78b2993be 100644 --- a/bundles/cxx_remote_services/admin/src/RemoteServiceAdminActivator.cc +++ b/bundles/cxx_remote_services/admin/src/RemoteServiceAdminActivator.cc @@ -32,15 +32,12 @@ class AdminActivator { auto& cmp = ctx->getDependencyManager()->createComponent(admin); cmp.createServiceDependency() - .setRequired(false) .setStrategy(celix::dm::DependencyUpdateStrategy::locking) .setCallbacks(&celix::rsa::RemoteServiceAdmin::addEndpoint, &celix::rsa::RemoteServiceAdmin::removeEndpoint); cmp.createServiceDependency() - .setRequired(false) .setStrategy(celix::dm::DependencyUpdateStrategy::locking) .setCallbacks(&celix::rsa::RemoteServiceAdmin::addImportedServiceFactory, &celix::rsa::RemoteServiceAdmin::removeImportedServiceFactory); cmp.createServiceDependency() - .setRequired(false) .setStrategy(celix::dm::DependencyUpdateStrategy::locking) .setCallbacks(&celix::rsa::RemoteServiceAdmin::addExportedServiceFactory, &celix::rsa::RemoteServiceAdmin::removeExportedServiceFactory); cmp.build(); diff --git a/bundles/cxx_remote_services/integration/src/CalculatorConsumer.cc b/bundles/cxx_remote_services/integration/src/CalculatorConsumer.cc index 00e22ec6b..37305b38c 100644 --- a/bundles/cxx_remote_services/integration/src/CalculatorConsumer.cc +++ b/bundles/cxx_remote_services/integration/src/CalculatorConsumer.cc @@ -55,7 +55,7 @@ class CalculatorConsumerActivator { explicit CalculatorConsumerActivator(const std::shared_ptr& ctx) { auto& cmp = ctx->getDependencyManager()->createComponent(std::make_shared()); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setCallbacks(&CalculatorConsumer::setCalculator); cmp.createProvidedService() .addProperty(celix::IShellCommand::COMMAND_NAME, "calc"); diff --git a/bundles/cxx_remote_services/integration/src/CalculatorProvider.cc b/bundles/cxx_remote_services/integration/src/CalculatorProvider.cc index f3a46099f..7925eb892 100644 --- a/bundles/cxx_remote_services/integration/src/CalculatorProvider.cc +++ b/bundles/cxx_remote_services/integration/src/CalculatorProvider.cc @@ -91,10 +91,10 @@ class CalculatorProviderActivator { explicit CalculatorProviderActivator(const std::shared_ptr& ctx) { auto& cmp = ctx->getDependencyManager()->createComponent(std::make_shared()); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setCallbacks(&CalculatorImpl::setFactory); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setCallbacks(&CalculatorImpl::setPushStreamProvider); cmp.createProvidedService() .addProperty("service.exported.interfaces", celix::typeName()) diff --git a/bundles/cxx_remote_services/integration/src/TestExportImportRemoteServiceFactory.cc b/bundles/cxx_remote_services/integration/src/TestExportImportRemoteServiceFactory.cc index a711a81e3..1679a83ff 100644 --- a/bundles/cxx_remote_services/integration/src/TestExportImportRemoteServiceFactory.cc +++ b/bundles/cxx_remote_services/integration/src/TestExportImportRemoteServiceFactory.cc @@ -340,11 +340,11 @@ class CalculatorImportServiceFactory final : public celix::rsa::IImportServiceFa auto& cmp = ctx->getDependencyManager()->createComponent(std::make_unique(logHelper, c2pChannelId, p2cChannelId)); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setStrategy(DependencyUpdateStrategy::suspend) .setCallbacks(&ImportedCalculator::setPromiseFactory); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setStrategy(DependencyUpdateStrategy::suspend) .setCallbacks(&ImportedCalculator::setPushStreamProvider); @@ -560,12 +560,12 @@ class CalculatorExportServiceFactory final : public celix::rsa::IExportServiceFa std::make_unique(logHelper, c2pChannelId, p2cChannelId)); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setStrategy(DependencyUpdateStrategy::suspend) .setCallbacks(&ExportedCalculator::setPromiseFactory); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setStrategy(DependencyUpdateStrategy::suspend) .setFilter(std::string{"("}.append(celix::SERVICE_ID).append("=").append(svcId).append(")")) .setCallbacks(&ExportedCalculator::setICalculator); diff --git a/bundles/event_admin/event_admin/src/celix_event_admin_activator.c b/bundles/event_admin/event_admin/src/celix_event_admin_activator.c index 2396521a9..005b4e58d 100644 --- a/bundles/event_admin/event_admin/src/celix_event_admin_activator.c +++ b/bundles/event_admin/event_admin/src/celix_event_admin_activator.c @@ -122,7 +122,7 @@ celix_status_t celix_eventAdminActivator_start(celix_event_admin_activator_t *ac if (status != CELIX_SUCCESS) { return status; } - celix_dmServiceDependency_setRequired(eventAdminDep, true); + celix_dmServiceDependency_setMinimalCardinality(eventAdminDep, 1); celix_dmServiceDependency_setStrategy(eventAdminDep, DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING); celix_dm_service_dependency_callback_options_t opts2 = CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; opts2.set = celix_eventAdapter_setEventAdminService; diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_activator.c b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_activator.c index bfb4c55b4..1bea31100 100755 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_activator.c +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_activator.c @@ -46,7 +46,7 @@ celix_status_t celix_rsaShmActivator_addRpcFactorySvcDependency(celix_dm_compone if (status != CELIX_SUCCESS) { return status; } - celix_dmServiceDependency_setRequired(rpcFactoryDep, true); + celix_dmServiceDependency_setMinimalCardinality(rpcFactoryDep, 1); celix_dmServiceDependency_setStrategy(rpcFactoryDep, DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND); celix_dm_service_dependency_callback_options_t opts = CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; opts.addWithProps = celix_rsaShm_addRpcFactorySvc; diff --git a/libs/framework/benchmark/src/DependencyManagerBenchmark.cc b/libs/framework/benchmark/src/DependencyManagerBenchmark.cc index 1a43e2750..5c9cea787 100644 --- a/libs/framework/benchmark/src/DependencyManagerBenchmark.cc +++ b/libs/framework/benchmark/src/DependencyManagerBenchmark.cc @@ -94,7 +94,7 @@ static void createAndDestroyComponentTest(benchmark::State& state, bool cTest) { // This code gets timed auto& cmp = man->createComponent(); cmp.createProvidedService(IService::NAME); - cmp.createServiceDependency(IService::NAME).setRequired(true); + cmp.createServiceDependency(IService::NAME).setMinimalCardinality(1); man->buildAsync(); man->wait(); assert(cmp.getState() == ComponentState::TRACKING_OPTIONAL); diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc b/libs/framework/gtest/src/DependencyManagerTestSuite.cc index 70a692f70..e86827c03 100644 --- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc +++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc @@ -244,7 +244,7 @@ TEST_F(DependencyManagerTestSuite, TestCheckActive) { auto *dep = celix_dmServiceDependency_create(); celix_dmServiceDependency_setService(dep, "svcname", nullptr, nullptr); - celix_dmServiceDependency_setRequired(dep, true); + celix_dmServiceDependency_setMinimalCardinality(dep, 1); celix_dmComponent_addServiceDependency(cmp, dep); //required dep -> cmp not active @@ -281,7 +281,7 @@ TEST_F(DependencyManagerTestSuite, CxxDmGetInfo) { auto& cmp = mng.createComponent(); cmp.createProvidedService().addProperty("key", "value"); - cmp.createServiceDependency().setVersionRange("[1,2)").setRequired(true); + cmp.createServiceDependency().setVersionRange("[1,2)").setMinimalCardinality(1); auto infos = mng.getInfos(); EXPECT_EQ(infos.size(), 1); @@ -591,7 +591,7 @@ TEST_F(DependencyManagerTestSuite, RequiredDepsAreInjectedDuringStartStop) { auto& cmp = dm.createComponent() .setCallbacks(nullptr, &LifecycleComponent::start, &LifecycleComponent::stop, nullptr); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setCallbacks(&LifecycleComponent::setService) .setCallbacks(&LifecycleComponent::addService, &LifecycleComponent::remService); cmp.build(); @@ -634,7 +634,7 @@ TEST_F(DependencyManagerTestSuite, RemoveOwnDependencyShouldNotLeadToDoubleStop) .setCallbacks(nullptr, &LifecycleComponent::start, &LifecycleComponent::stop, nullptr); cmp.createProvidedService(); cmp.createServiceDependency() - .setRequired(true); + .setMinimalCardinality(1); cmp.build(); using celix::dm::ComponentState; @@ -660,7 +660,7 @@ TEST_F(DependencyManagerTestSuite, RemoveOwnDependencyShouldNotLeadToDoubleStop) //When an additional required service dependency is added cmp.createServiceDependency("DummyName") - .setRequired(true) + .setMinimalCardinality(1) .buildAsync(); celix_bundleContext_waitForEvents(ctx); @@ -738,11 +738,10 @@ TEST_F(DependencyManagerTestSuite, IntermediateStatesDuringInitDeinitStartingAnd .setCallbacks(&LifecycleComponent::init, &LifecycleComponent::start, &LifecycleComponent::stop, &LifecycleComponent::deinit); cmp.createServiceDependency() .setStrategy(celix::dm::DependencyUpdateStrategy::suspend) - .setCallbacks([](std::shared_ptr /*service*/, const std::shared_ptr& /*properties*/){ std::cout << "Dummy set for svc callback\n"; }) - .setRequired(false); + .setCallbacks([](std::shared_ptr /*service*/, const std::shared_ptr& /*properties*/){ std::cout << "Dummy set for svc callback\n"; }); cmp.createServiceDependency("RequiredTestService") .setStrategy(celix::dm::DependencyUpdateStrategy::locking) - .setRequired(true); + .setMinimalCardinality(1); cmp.buildAsync(); //Then the component state should become waiting for required @@ -882,7 +881,7 @@ TEST_F(DependencyManagerTestSuite, DepsAreInjectedAsSharedPointers) { auto& cmp = dm.createComponent() .setCallbacks(nullptr, &LifecycleComponent::start, &LifecycleComponent::stop, nullptr); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setCallbacks(&LifecycleComponent::setService) .setCallbacks(&LifecycleComponent::addService, &LifecycleComponent::remService); cmp.build(); @@ -943,7 +942,7 @@ TEST_F(DependencyManagerTestSuite, DepsNoPropsAreInjectedAsSharedPointers) { auto& cmp = dm.createComponent() .setCallbacks(nullptr, &LifecycleComponent::start, &LifecycleComponent::stop, nullptr); cmp.createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setCallbacks(&LifecycleComponent::setService) .setCallbacks(&LifecycleComponent::addService, &LifecycleComponent::remService); cmp.build(); @@ -1096,7 +1095,7 @@ TEST_F(DependencyManagerTestSuite, ExceptionsInLifecycle) { EXPECT_EQ(cmp.getState(), ComponentState::TRACKING_OPTIONAL); //required service -> should stop, but fails at stop and should become inactive (component will disable itself) - cmp.createServiceDependency().setRequired(true).build(); + cmp.createServiceDependency().setMinimalCardinality(1).build(); cmp.wait(); EXPECT_EQ(cmp.getState(), ComponentState::INACTIVE); dm.clear(); @@ -1284,7 +1283,7 @@ TEST_F(DependencyManagerTestSuite, TestCardinality) { cmp1.build(); auto& cmp3 = dm.createComponent() .createServiceDependency() - .setRequired(true) + .setMinimalCardinality(1) .setMinimalCardinality(2); cmp3.build(); From 6f6b2037b4fdcb0e3d1bed22a09230951d032993 Mon Sep 17 00:00:00 2001 From: Deedss Date: Wed, 8 Apr 2026 19:20:26 +0000 Subject: [PATCH 08/12] Fix last remaining use of setRequired --- libs/framework/benchmark/src/DependencyManagerBenchmark.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/framework/benchmark/src/DependencyManagerBenchmark.cc b/libs/framework/benchmark/src/DependencyManagerBenchmark.cc index 5c9cea787..0a52a322c 100644 --- a/libs/framework/benchmark/src/DependencyManagerBenchmark.cc +++ b/libs/framework/benchmark/src/DependencyManagerBenchmark.cc @@ -17,8 +17,10 @@ * under the License. */ -#include +#include "../../include/celix_dm_service_dependency.h" + #include "celix/FrameworkFactory.h" +#include //note using c++ service for both the C and C++ benchmark, because this should not impact the performance. class IService { @@ -81,7 +83,7 @@ static void createAndDestroyComponentTest(benchmark::State& state, bool cTest) { auto* dep = celix_dmServiceDependency_create(); celix_dmServiceDependency_setService(dep, IService::NAME, nullptr, nullptr); - celix_dmServiceDependency_setRequired(dep, true); + celix_dmServiceDependency_setMinimalCardinality(dep, 1); celix_dmComponent_addServiceDependency(cmp, dep); celix_dependencyManager_addAsync(cMan, cmp); From 3eabb99f327d8194c15bf87991252af654152b49 Mon Sep 17 00:00:00 2001 From: Deedss Date: Thu, 9 Apr 2026 22:32:46 +0200 Subject: [PATCH 09/12] Add minimalCardinality to DependencyManagerInfo, small fix for availability in dm_service_dependency --- .../framework/include/celix/dm/DependencyManagerInfo.h | 5 +++++ .../include/celix/dm/DependencyManager_Impl.h | 1 + libs/framework/src/dm_service_dependency.c | 10 +++------- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libs/framework/include/celix/dm/DependencyManagerInfo.h b/libs/framework/include/celix/dm/DependencyManagerInfo.h index 56524c3fb..7443800dd 100644 --- a/libs/framework/include/celix/dm/DependencyManagerInfo.h +++ b/libs/framework/include/celix/dm/DependencyManagerInfo.h @@ -69,6 +69,11 @@ namespace celix { namespace dm { */ bool isRequired{}; + /** + * Minimal amount of dependencies needed for the service to be available + */ + std::size_t minimalCardinality{0}; + /** * Nummer tracker services. */ diff --git a/libs/framework/include/celix/dm/DependencyManager_Impl.h b/libs/framework/include/celix/dm/DependencyManager_Impl.h index e364d9f10..d4bd2f44d 100644 --- a/libs/framework/include/celix/dm/DependencyManager_Impl.h +++ b/libs/framework/include/celix/dm/DependencyManager_Impl.h @@ -188,6 +188,7 @@ static celix::dm::DependencyManagerInfo createDepManInfoFromC(celix_dependency_m depInfo.versionRange = std::string{cDepInfo->versionRange == nullptr ? "" : cDepInfo->versionRange}; depInfo.isAvailable = cDepInfo->available; depInfo.isRequired = cDepInfo->required; + depInfo.minimalCardinality = cDepInfo->minimalCardinality; depInfo.nrOfTrackedServices = cDepInfo->count; cmpInfo.dependenciesInfo.emplace_back(std::move(depInfo)); } diff --git a/libs/framework/src/dm_service_dependency.c b/libs/framework/src/dm_service_dependency.c index 665f0535f..876a58974 100644 --- a/libs/framework/src/dm_service_dependency.c +++ b/libs/framework/src/dm_service_dependency.c @@ -300,12 +300,8 @@ 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 = false; - if (dependency->minimalCardinality == 0) { - avail = dependency->trackedSvcCount > 0; - } else { - avail = dependency->trackedSvcCount >= dependency->minimalCardinality; - } + bool avail = (dependency->minimalCardinality == 0) ? (dependency->trackedSvcCount > 0) + : (dependency->trackedSvcCount >= dependency->minimalCardinality); celixThreadMutex_unlock(&dependency->mutex); return avail; } @@ -342,7 +338,7 @@ 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 >= dep->minimalCardinality; + info->available = (dep->minimalCardinality == 0) ? (dep->trackedSvcCount > 0) : dep->trackedSvcCount >= dep->minimalCardinality; info->minimalCardinality = dep->minimalCardinality; info->serviceName = celix_utils_strdup(dep->serviceName); info->filter = celix_utils_strdup(dep->filter); From 7f6adf17a5c6c0fab1c0d5ee347c629d7c9b2a7d Mon Sep 17 00:00:00 2001 From: Deedss Date: Tue, 14 Apr 2026 14:27:19 +0000 Subject: [PATCH 10/12] Introduce internal availability function, update documentation, improve memory layout of celix_dm_service_dependency_info_struct. --- documents/components.md | 17 ++++++++++------- .../benchmark/src/DependencyManagerBenchmark.cc | 2 -- libs/framework/include/celix_dm_info.h | 6 +++--- libs/framework/src/dm_service_dependency.c | 14 +++++++++++--- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/documents/components.md b/documents/components.md index 2b78893db..6d73c4c6e 100644 --- a/documents/components.md +++ b/documents/components.md @@ -476,14 +476,16 @@ Remarks for the C example: 5. Configures for which service name the service dependency will track services for. Optionally it is also possible to fine tune the tracked service by providing a service version range and/or service filter. 6. Configures the update strategy for the service dependency to suspend-strategy. -7. Configures the service dependency as a required service dependency. +7. Configures the service dependency as a required service dependency by setting the minimalCardinality to at least `1`. + Setting the minimalCardinality determines howmany services are required for the service dependency to be available. 8. Creates an empty service dependency callback options struct. This struct can be used to configure different service dependency callbacks. 9. Configures the `set` service dependency callback to `componentWithServiceDependency_setHighestRankingShellCommand` 10. Configures the dependency manager to use the callbacks configures in opts. 11. Adds the DM service dependency object to the DM component object. 12. Configures the update strategy for the service dependency to locking-strategy. -13. Configures the service dependency as an optional service dependency. +13. Configures the service dependency as an optional service dependency by setting the minimalCardinality to `0`. By + default, minimalCardinality is set to `0`. 14. Configures the `addWithProps` service dependency callback to `componentWithServiceDependency_addShellCommand`. ```C @@ -564,7 +566,7 @@ static celix_status_t componentWithServiceDependencyActivator_start(component_wi celix_dm_service_dependency_t* dep1 = celix_dmServiceDependency_create(); // <-----------------------------------<4> celix_dmServiceDependency_setService(dep1, CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL); // <-------------------<5> celix_dmServiceDependency_setStrategy(dep1, DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND); // <------------------------<6> - celix_dmServiceDependency_setRequired(dep1, true); // <----------------------------------------------------------<7> + celix_dmServiceDependency_setMinimalCardinality(dep1, 1); // <---------------------------------------------------<7> celix_dm_service_dependency_callback_options_t opts1 = CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; // <--<8> opts1.set = (void*)componentWithServiceDependency_setHighestRankingShellCommand; // <----------------------------<9> celix_dmServiceDependency_setCallbacksWithOptions(dep1, &opts1); // <-------------------------------------------<10> @@ -574,7 +576,7 @@ static celix_status_t componentWithServiceDependencyActivator_start(component_wi celix_dm_service_dependency_t* dep2 = celix_dmServiceDependency_create(); celix_dmServiceDependency_setService(dep2, CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL); celix_dmServiceDependency_setStrategy(dep2, DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING); // <----------------------<12> - celix_dmServiceDependency_setRequired(dep2, false); // <--------------------------------------------------------<13> + celix_dmServiceDependency_setMinimalCardinality(dep2, 0); // <--------------------------------------------------<13> celix_dm_service_dependency_callback_options_t opts2 = CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; opts2.addWithProps = (void*)componentWithServiceDependency_addShellCommand; // <-------------------------------<14> opts2.removeWithProps = (void*)componentWithServiceDependency_removeShellCommand; @@ -622,7 +624,8 @@ Remarks for the C++ example: service dependency, component or DM is build. Note that the `celix::dm::Component::createServiceDependency` method is called without provided a service name, the service name will be inferred using the `celix::typeName`. 5. Configures the service dependency set callback. -6. Configures the service dependency as a required service dependency. +6. Configures the service dependency as a required service dependency by setting the minimalCardinality to at least `1`. + Setting the minimalCardinality determines howmany services are required for the service dependency to be available. 7. Configures the update strategy for the service dependency to suspend-strategy. 8. Creates another new DM service dependency object and in this case also explicitly provides the service name to use (`CELIX_SHELL_COMMAND_SERVICE_NAME`). @@ -672,12 +675,12 @@ public: cmp.createServiceDependency() // <-----------------------------------------------------<4> .setCallbacks(&Cmp::setHighestRankingShellCommand) // <----------------------------------------------<5> - .setRequired(true) // <------------------------------------------------------------------------------<6> + .setMinimalCardinality(1) // <-----------------------------------------------------------------------<6> .setStrategy(DependencyUpdateStrategy::suspend); // <------------------------------------------------<7> cmp.createServiceDependency(CELIX_SHELL_COMMAND_SERVICE_NAME) // <--------------------<8> .setCallbacks(&Cmp::addCShellCmd, &Cmp::removeCShellCmd) - .setRequired(false) + .setMinimalCardinality(0) .setStrategy(DependencyUpdateStrategy::locking); cmp.build(); // <--------------------------------------------------------------------------------------------<9> diff --git a/libs/framework/benchmark/src/DependencyManagerBenchmark.cc b/libs/framework/benchmark/src/DependencyManagerBenchmark.cc index 0a52a322c..502eb94f6 100644 --- a/libs/framework/benchmark/src/DependencyManagerBenchmark.cc +++ b/libs/framework/benchmark/src/DependencyManagerBenchmark.cc @@ -17,8 +17,6 @@ * under the License. */ -#include "../../include/celix_dm_service_dependency.h" - #include "celix/FrameworkFactory.h" #include diff --git a/libs/framework/include/celix_dm_info.h b/libs/framework/include/celix_dm_info.h index eaece5950..f1f5435ca 100644 --- a/libs/framework/include/celix_dm_info.h +++ b/libs/framework/include/celix_dm_info.h @@ -42,10 +42,10 @@ struct celix_dm_service_dependency_info_struct { char *serviceName; char *filter; char *versionRange; - bool available; + size_t count; size_t minimalCardinality; + bool available; bool required; - size_t count; }; typedef struct celix_dm_service_dependency_info_struct *dm_service_dependency_info_pt; //deprecated typedef struct celix_dm_service_dependency_info_struct dm_service_dependency_info_t; //deprecated @@ -56,8 +56,8 @@ struct celix_dm_component_info_struct { char* bundleSymbolicName; char* id; char* name; - bool active; char* state; + bool active; size_t nrOfTimesStarted; size_t nrOfTimesResumed; celix_array_list_t *interfaces; // type dm_interface_info_t* diff --git a/libs/framework/src/dm_service_dependency.c b/libs/framework/src/dm_service_dependency.c index 876a58974..afd1d378d 100644 --- a/libs/framework/src/dm_service_dependency.c +++ b/libs/framework/src/dm_service_dependency.c @@ -33,6 +33,7 @@ static void serviceDependency_addServiceTrackerCallback(void *handle, void *svc, static void serviceDependency_removeServiceTrackerCallback(void *handle, void *svc, const celix_properties_t *props); static void serviceDependency_setServiceTrackerCallback(void *handle, void *svc, const celix_properties_t *props); static void* serviceDependency_getCallbackHandle(celix_dm_service_dependency_t *dep); +static bool serviceDependency_isAvailable(celix_dm_service_dependency_t *dep); celix_status_t serviceDependency_create(celix_dm_service_dependency_t **dependency_ptr) { celix_dm_service_dependency_t *dep = celix_dmServiceDependency_create(); @@ -300,8 +301,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->minimalCardinality == 0) ? (dependency->trackedSvcCount > 0) - : (dependency->trackedSvcCount >= dependency->minimalCardinality); + bool avail = serviceDependency_isAvailable(dependency); celixThreadMutex_unlock(&dependency->mutex); return avail; } @@ -338,7 +338,7 @@ 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->minimalCardinality == 0) ? (dep->trackedSvcCount > 0) : dep->trackedSvcCount >= dep->minimalCardinality; + info->available = serviceDependency_isAvailable(dep); info->minimalCardinality = dep->minimalCardinality; info->serviceName = celix_utils_strdup(dep->serviceName); info->filter = celix_utils_strdup(dep->filter); @@ -376,3 +376,11 @@ celix_status_t celix_dmServiceDependency_setCallbackHandle(celix_dm_service_depe static void* serviceDependency_getCallbackHandle(celix_dm_service_dependency_t *dependency) { return dependency->callbackHandle == NULL ? component_getImplementation(dependency->component) : dependency->callbackHandle; } + +static bool serviceDependency_isAvailable(celix_dm_service_dependency_t* dep) { + if (dep->minimalCardinality == 0) { + return dep->trackedSvcCount > 0; + } + + return dep->trackedSvcCount >= dep->minimalCardinality; +} From 3da1906468f0b9c6c2de8f7a31a8829a0a12fd3e Mon Sep 17 00:00:00 2001 From: PengZheng Date: Wed, 15 Apr 2026 08:39:10 +0800 Subject: [PATCH 11/12] Fix minor typos Co-authored-by: PengZheng --- documents/components.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documents/components.md b/documents/components.md index 6d73c4c6e..52a4ce134 100644 --- a/documents/components.md +++ b/documents/components.md @@ -477,7 +477,7 @@ Remarks for the C example: to fine tune the tracked service by providing a service version range and/or service filter. 6. Configures the update strategy for the service dependency to suspend-strategy. 7. Configures the service dependency as a required service dependency by setting the minimalCardinality to at least `1`. - Setting the minimalCardinality determines howmany services are required for the service dependency to be available. + Setting the minimalCardinality determines how many services are required for the service dependency to be available. 8. Creates an empty service dependency callback options struct. This struct can be used to configure different service dependency callbacks. 9. Configures the `set` service dependency callback to `componentWithServiceDependency_setHighestRankingShellCommand` @@ -625,7 +625,7 @@ Remarks for the C++ example: is called without provided a service name, the service name will be inferred using the `celix::typeName`. 5. Configures the service dependency set callback. 6. Configures the service dependency as a required service dependency by setting the minimalCardinality to at least `1`. - Setting the minimalCardinality determines howmany services are required for the service dependency to be available. + Setting the minimalCardinality determines how many services are required for the service dependency to be available. 7. Configures the update strategy for the service dependency to suspend-strategy. 8. Creates another new DM service dependency object and in this case also explicitly provides the service name to use (`CELIX_SHELL_COMMAND_SERVICE_NAME`). From f9c85229e100d56f848d5c3fbaeb6f4936837a16 Mon Sep 17 00:00:00 2001 From: Deedss Date: Wed, 15 Apr 2026 17:33:46 +0200 Subject: [PATCH 12/12] update changes.md --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index dc7daa41e..3eec41940 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -85,10 +85,12 @@ limitations under the License. The old manifest attribute names are also no longer defined in `celix_constants.h`. - Using jar to packaging bundles is no longer support. Jar was used to ensure the MANIFEST.MF was the first entry in a bundle zip file, but MANIFEST.MF is no longer used (replaced by MANIFEST.json). +- It is no longer to set required or optional dependencies via `celix_dmServiceDependency_setRequired` or `setRequired`. This is now possible by using the new `celix_dmServiceDependency_setMinimalCardinality` or `setMinimalCardinality` function. ## New Features - Type support for value in celix Properties, including support for arrays. +- Support for minimal cardinality of service dependencies. Setting a minimal cardinality will determine the amount of services that are required before a service dependency is available. # Noteworthy Changes for 2.4.0 (2023-09-27)