Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions libs/framework/gtest/src/DependencyManagerTestSuite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
14 changes: 14 additions & 0 deletions libs/framework/include/celix/dm/ServiceDependency.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ namespace celix { namespace dm {
*/
CServiceDependency<T,I>& setRequired(bool req);

/**
* Specify the minimum amount of service dependencies required 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
*
Expand Down Expand Up @@ -409,6 +416,13 @@ namespace celix { namespace dm {
*/
ServiceDependency<T,I>& setRequired(bool req);

/**
* Specify the minimum amount of service dependencies required 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
*
Expand Down
13 changes: 12 additions & 1 deletion libs/framework/include/celix/dm/ServiceDependency_Impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions libs/framework/include/celix_dm_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
5 changes: 5 additions & 0 deletions libs/framework/include/celix_dm_service_dependency.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
9 changes: 5 additions & 4 deletions libs/framework/src/dm_component_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
13 changes: 11 additions & 2 deletions libs/framework/src/dm_service_dependency.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -95,6 +96,13 @@ 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) {
if (minimalCardinality > 0) {
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);
}
Expand Down Expand Up @@ -310,7 +318,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;
}
Expand Down Expand Up @@ -347,7 +355,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);
Expand Down
1 change: 1 addition & 0 deletions libs/framework/src/dm_service_dependency_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down
Loading