You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2021/01/17 15:18:28 UTC
[celix] branch feature/refactor_c_dep_man_service_trackers updated:
Adds mutex usage to C++ dep man and adds getInfo(s) to C++ dep man.
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/refactor_c_dep_man_service_trackers
in repository https://gitbox.apache.org/repos/asf/celix.git
The following commit(s) were added to refs/heads/feature/refactor_c_dep_man_service_trackers by this push:
new f788226 Adds mutex usage to C++ dep man and adds getInfo(s) to C++ dep man.
f788226 is described below
commit f7882262e0f77ca5bbe9eba5f363941f260f2310
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Sun Jan 17 16:18:11 2021 +0100
Adds mutex usage to C++ dep man and adds getInfo(s) to C++ dep man.
---
bundles/shell/shell/src/dm_shell_list_command.c | 18 +--
libs/dependency_manager_cxx/src/dm_activator.cc | 6 +-
.../gtest/src/DependencyManagerTestSuite.cc | 76 ++++++++---
libs/framework/include/celix/dm/Component.h | 6 +-
libs/framework/include/celix/dm/Component_Impl.h | 12 +-
.../framework/include/celix/dm/DependencyManager.h | 43 +++++--
.../include/celix/dm/DependencyManagerInfo.h | 142 +++++++++++++++++++++
.../include/celix/dm/DependencyManager_Impl.h | 105 ++++++++++++---
.../framework/include/celix/dm/ServiceDependency.h | 2 +-
libs/framework/include/celix_bundle_context.h | 6 +
libs/framework/include/celix_dependency_manager.h | 47 ++++++-
libs/framework/include/celix_dm_info.h | 11 +-
libs/framework/src/bundle_context.c | 5 +
libs/framework/src/dm_component_impl.c | 9 +-
libs/framework/src/dm_dependency_manager_impl.c | 33 +++--
15 files changed, 446 insertions(+), 75 deletions(-)
diff --git a/bundles/shell/shell/src/dm_shell_list_command.c b/bundles/shell/shell/src/dm_shell_list_command.c
index 34b0fcc..df1fdca 100644
--- a/bundles/shell/shell/src/dm_shell_list_command.c
+++ b/bundles/shell/shell/src/dm_shell_list_command.c
@@ -54,7 +54,7 @@ static void parseCommandLine(const char*line, celix_array_list_t **requestedBund
free (str);
}
-static void printFullInfo(FILE *out, bool colors, long bundleId, dm_component_info_pt compInfo) {
+static void printFullInfo(FILE *out, bool colors, long bundleId, const char* bndName, dm_component_info_pt compInfo) {
const char *startColors = "";
const char *endColors = "";
if (colors) {
@@ -65,7 +65,9 @@ static void printFullInfo(FILE *out, bool colors, long bundleId, dm_component_in
fprintf(out, "|- UUID = %s\n", compInfo->id);
fprintf(out, "|- Active = %s\n", compInfo->active ? "true" : "false");
fprintf(out, "|- State = %s\n", compInfo->state);
- fprintf(out, "|- Bundle = %li\n", bundleId);
+ fprintf(out, "|- Bundle = %li (%s)\n", bundleId, bndName);
+ fprintf(out, "|- Nr of times started = %i\n", (int)compInfo->nrOfTimesStarted);
+ fprintf(out, "|- Nr of times resumed = %i\n", (int)compInfo->nrOfTimesResumed);
fprintf(out, "|- Interfaces (%d):\n", celix_arrayList_size(compInfo->interfaces));
for (int interfCnt = 0; interfCnt < celix_arrayList_size(compInfo->interfaces); interfCnt++) {
@@ -101,15 +103,15 @@ static void printFullInfo(FILE *out, bool colors, long bundleId, dm_component_in
}
-static void printBasicInfo(FILE *out, bool colors, long bundleId, dm_component_info_pt compInfo) {
+static void printBasicInfo(FILE *out, bool colors, long bundleId, const char* bndName, dm_component_info_pt compInfo) {
const char *startColors = "";
const char *endColors = "";
if (colors) {
startColors = compInfo->active ? OK_COLOR : NOK_COLOR;
endColors = END_COLOR;
}
- fprintf(out, "Component: Name=%s, ID=%s, %sActive=%s%s, State=%s, Bundle=%li\n", compInfo->name, compInfo->id,
- startColors, compInfo->active ? "true " : "false", endColors, compInfo->state, bundleId);
+ fprintf(out, "Component: Name=%s, ID=%s, %sActive=%s%s, State=%s, Bundle=%li (%s)\n", compInfo->name, compInfo->id,
+ startColors, compInfo->active ? "true " : "false", endColors, compInfo->state, bundleId, bndName);
}
@@ -120,9 +122,9 @@ static void dm_printInfo(FILE *out, bool useColors, bool fullInfo, celix_depende
for (unsigned int cmpCnt = 0; cmpCnt < size; cmpCnt++) {
dm_component_info_pt compInfo = celix_arrayList_get(info->components, cmpCnt);
if (fullInfo) {
- printFullInfo(out, useColors, info->bndId, compInfo);
+ printFullInfo(out, useColors, info->bndId, info->bndSymbolicName, compInfo);
} else {
- printBasicInfo(out, useColors, info->bndId, compInfo);
+ printBasicInfo(out, useColors, info->bndId, info->bndSymbolicName, compInfo);
}
}
fprintf(out, "\n");
@@ -155,7 +157,7 @@ celix_status_t dmListCommand_execute(void* handle, char * line, FILE *out, FILE
nrOfComponents += 1;
if (!cmpInfo->active) {
allActive = false;
- printFullInfo(out, useColors, info->bndId, cmpInfo);
+ printFullInfo(out, useColors, info->bndId, info->bndSymbolicName, cmpInfo);
}
}
}
diff --git a/libs/dependency_manager_cxx/src/dm_activator.cc b/libs/dependency_manager_cxx/src/dm_activator.cc
index 2d5e0b6..0bba0a5 100644
--- a/libs/dependency_manager_cxx/src/dm_activator.cc
+++ b/libs/dependency_manager_cxx/src/dm_activator.cc
@@ -29,7 +29,7 @@
* Deprecated. Use the CELIX_GEN_CXX_BUNDLE_ACTIVATOR marco from celix_bundle_activator.h instead
*/
struct BundleActivatorData {
- DependencyManager mng;
+ std::shared_ptr<DependencyManager> mng;
std::unique_ptr<celix::dm::DmActivator> act;
};
@@ -39,7 +39,7 @@ extern "C" celix_status_t bundleActivator_create(celix_bundle_context_t *context
BundleActivatorData* data = nullptr;
#ifdef __EXCEPTIONS
data = new BundleActivatorData{
- .mng = celix::dm::DependencyManager{context},
+ .mng = std::make_shared<celix::dm::DependencyManager>(context),
.act = nullptr
};
#else
@@ -49,7 +49,7 @@ extern "C" celix_status_t bundleActivator_create(celix_bundle_context_t *context
};
#endif
if (data != nullptr) {
- data->act = std::unique_ptr<celix::dm::DmActivator>{celix::dm::DmActivator::create(data->mng)};
+ data->act = std::unique_ptr<celix::dm::DmActivator>{celix::dm::DmActivator::create(*data->mng)};
}
if (data == nullptr || data->act == nullptr) {
diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
index 03163d1..78bce4f 100644
--- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc
+++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
@@ -84,7 +84,7 @@ TEST_F(DependencyManagerTestSuite, DmComponentAddRemove) {
ASSERT_EQ(0, celix_dependencyManager_nrOfComponents(mng));
}
-TEST_F(DependencyManagerTestSuite, DmGetInfo) {
+TEST_F(DependencyManagerTestSuite, CDmGetInfo) {
auto* mng = celix_bundleContext_getDependencyManager(ctx);
auto* cmp = celix_dmComponent_create(ctx, "test1");
@@ -108,7 +108,6 @@ TEST_F(DependencyManagerTestSuite, DmGetInfo) {
celix_dependencyManager_destroyInfos(mng, infos);
}
-
TEST_F(DependencyManagerTestSuite, TestCheckActive) {
auto *mng = celix_bundleContext_getDependencyManager(ctx);
auto *cmp = celix_dmComponent_create(ctx, "test1");
@@ -127,6 +126,64 @@ class TestComponent {
};
+struct TestService {
+ void *handle = nullptr;
+};
+
+class Cmp1 : public TestService {
+
+};
+
+class Cmp2 : public TestService {
+public:
+ explicit Cmp2(const std::string& name) {
+ std::cout << "usage arg: " << name << std::endl;
+ }
+};
+
+
+TEST_F(DependencyManagerTestSuite, CxxDmGetInfo) {
+ celix::dm::DependencyManager mng{ctx};
+
+ auto& cmp = mng.createComponent<Cmp1>();
+ cmp.createProvidedService<TestService>().addProperty("key", "value");
+ cmp.createServiceDependency<TestService>().setVersionRange("[1,2)").setRequired(true);
+
+ auto infos = mng.getInfos();
+ EXPECT_EQ(infos.size(), 1);
+
+ auto info = mng.getInfo();
+ EXPECT_EQ(info.bndId, 0);
+ EXPECT_EQ(info.bndSymbolicName, "Framework");
+ EXPECT_EQ(info.components.size(), 0); //not build yet
+
+ mng.build();
+ info = mng.getInfo(); //new info
+ ASSERT_EQ(info.components.size(), 1); //build
+
+ auto& cmpInfo = info.components[0];
+ EXPECT_TRUE(!cmpInfo.uuid.empty());
+ EXPECT_EQ(cmpInfo.name, "Cmp1");
+ EXPECT_EQ(cmpInfo.state, "WAITING_FOR_REQUIRED");
+ EXPECT_FALSE(cmpInfo.isActive);
+ EXPECT_EQ(cmpInfo.nrOfTimesStarted, 0);
+ EXPECT_EQ(cmpInfo.nrOfTimesResumed, 0);
+
+ ASSERT_EQ(cmpInfo.interfacesInfo.size(), 1);
+ auto& intf = cmpInfo.interfacesInfo[0];
+ EXPECT_EQ(intf.serviceName, "TestService");
+ EXPECT_TRUE(intf.properties.size() > 0);
+ EXPECT_NE(intf.properties.find("key"), intf.properties.end());
+
+ ASSERT_EQ(cmpInfo.dependenciesInfo.size(), 1);
+ auto& dep = cmpInfo.dependenciesInfo[0];
+ EXPECT_EQ(dep.serviceName, "TestService");
+ EXPECT_EQ(dep.isRequired, true);
+ EXPECT_EQ(dep.versionRange, "[1,2)");
+ EXPECT_EQ(dep.isAvailable, false);
+ EXPECT_EQ(dep.nrOfTrackedServices, 0);
+}
+
TEST_F(DependencyManagerTestSuite, OnlyActiveAfterBuildCheck) {
celix::dm::DependencyManager dm{ctx};
EXPECT_EQ(0, dm.getNrOfComponents());
@@ -159,21 +216,6 @@ TEST_F(DependencyManagerTestSuite, StartDmWillBuildCmp) {
EXPECT_EQ(0, dm.getNrOfComponents()); //dm cleared so no components
}
-struct TestService {
- void *handle = nullptr;
-};
-
-class Cmp1 : public TestService {
-
-};
-
-class Cmp2 : public TestService {
-public:
- explicit Cmp2(const std::string& name) {
- std::cout << "usage arg: " << name << std::endl;
- }
-};
-
TEST_F(DependencyManagerTestSuite, CreateComponentVariant) {
celix::dm::DependencyManager dm{ctx};
diff --git a/libs/framework/include/celix/dm/Component.h b/libs/framework/include/celix/dm/Component.h
index 05e3989..87954a7 100644
--- a/libs/framework/include/celix/dm/Component.h
+++ b/libs/framework/include/celix/dm/Component.h
@@ -301,9 +301,9 @@ namespace celix { namespace dm {
Component<T>& build();
/**
- * Same as build, but this call will not wait until all service registrations and tracker are created on the
- * Celix event thread.
- * Can also be called on the Celix event thread.
+ * Same as build, but this call will not wait til all service registrations and tracker are registered/openend
+ * on the Celix event thread.
+ * Can be called on the Celix event thread.
*/
Component<T>& buildAsync();
};
diff --git a/libs/framework/include/celix/dm/Component_Impl.h b/libs/framework/include/celix/dm/Component_Impl.h
index 704438c..c19bf84 100644
--- a/libs/framework/include/celix/dm/Component_Impl.h
+++ b/libs/framework/include/celix/dm/Component_Impl.h
@@ -47,7 +47,7 @@ inline void BaseComponent::runBuild() {
bool alreadyAdded = cmpAddedToDepMan.exchange(true);
if (!alreadyAdded) {
- celix_dependencyManager_add(cDepMan, cCmp);
+ celix_dependencyManager_addAsync(cDepMan, cCmp);
}
}
@@ -58,7 +58,15 @@ inline void BaseComponent::wait() const {
}
template<class T>
-Component<T>::Component(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, std::string name, std::string uuid) : BaseComponent(context, cDepMan, std::move(name), std::move(uuid)) {}
+Component<T>::Component(
+ celix_bundle_context_t *context,
+ celix_dependency_manager_t* cDepMan,
+ std::string name,
+ std::string uuid) : BaseComponent(
+ context,
+ cDepMan,
+ name.empty() ? celix::dm::typeName<T>() : std::move(name),
+ std::move(uuid)) {}
template<class T>
Component<T>::~Component() = default;
diff --git a/libs/framework/include/celix/dm/DependencyManager.h b/libs/framework/include/celix/dm/DependencyManager.h
index 0ca43de..e294702 100644
--- a/libs/framework/include/celix/dm/DependencyManager.h
+++ b/libs/framework/include/celix/dm/DependencyManager.h
@@ -22,6 +22,7 @@
#include "celix/dm/types.h"
#include "celix/dm/Component.h"
#include "celix/dm/ServiceDependency.h"
+#include "celix/dm/DependencyManagerInfo.h"
#include "bundle_context.h"
#include "celix_bundle_context.h"
@@ -32,7 +33,15 @@
namespace celix { namespace dm {
/**
- * The Dependency Manager, Component, ServiceDependency and Properties are not thread safe!
+ *
+ * The build() methods For celix::dm::DependencyManager, celix::dm::Component and
+ * celix::dm::(C)ServiceDependency should be called outside the Celix event thread.
+ * Note that bundle activators are started and stopped outside the Celix event thread and thus the build()
+ * methods can be used in bundle activators.
+ *
+ * Inside the Celix event thread - i.e. during a useService callback or add/rem/set call from a service tracker -
+ * the buildAsync version should be used. After a buildASync method has returned, service registration and opening
+ * service trackers are (possibly) still in progress.
*/
class DependencyManager {
public:
@@ -40,8 +49,8 @@ namespace celix { namespace dm {
virtual ~DependencyManager();
- DependencyManager(DependencyManager&& mgr) = default;
- DependencyManager& operator=(DependencyManager&& rhs) = default;
+ DependencyManager(DependencyManager&& mgr) = delete;
+ DependencyManager& operator=(DependencyManager&& rhs) = delete;
DependencyManager(const DependencyManager&) = delete;
DependencyManager& operator=(const DependencyManager&) = delete;
@@ -97,17 +106,17 @@ namespace celix { namespace dm {
* If a component is updated after the dependency manager build is called, an new build call will result in
* that the changes to the component are enabled.
*
- * Note that the after this call the components will be created and if the components can be started, they
+ * After this call the components will be created and if the components can be started, they
* will be started and the services will be registered.
*
- * Should not be called from the Celix event thread.
+ * Should not be called from the Celix event thread.
*/
void build();
/**
- * Same as build, but this call will not wait until all service registrations and tracker are created on the
- * Celix event thread.
- * Can also be called on the Celix event thread.
+ * Same as build, but this call will not wait until all service registrations and tracker are registered/opened
+ * on the Celix event thread.
+ * Can be called on the Celix event thread.
*/
void buildAsync();
@@ -149,21 +158,33 @@ namespace celix { namespace dm {
std::size_t getNrOfComponents() const;
/**
- * Tries to find the component with UUID and staticly cast it to
+ * Tries to find the component with UUID and statically cast it to
* dm component of type T
* @return pointer to found component or null if the component cannot be found.
*
- * Note: DependencyManager is not thread safe!
*/
template<typename T>
std::shared_ptr<Component<T>> findComponent(const std::string& uuid) const;
+
+ /**
+ * Get Dependency Management info for this component manager.
+ * @return A DependencyManagerInfo struct.
+ */
+ celix::dm::DependencyManagerInfo getInfo() const;
+
+ /**
+ * Get Dependency Management info for all component manager (for all bundles).
+ * @return A vector of DependencyManagerInfo structs.
+ */
+ std::vector<celix::dm::DependencyManagerInfo> getInfos() const;
private:
template<class T>
Component<T>& createComponentInternal(std::string name, std::string uuid);
std::shared_ptr<celix_bundle_context_t> context;
std::shared_ptr<celix_dependency_manager_t> cDepMan;
- std::vector<std::shared_ptr<BaseComponent>> components {};
+ mutable std::mutex mutex{}; //protects below
+ std::vector<std::shared_ptr<BaseComponent>> components{};
};
}}
diff --git a/libs/framework/include/celix/dm/DependencyManagerInfo.h b/libs/framework/include/celix/dm/DependencyManagerInfo.h
new file mode 100644
index 0000000..56524c3
--- /dev/null
+++ b/libs/framework/include/celix/dm/DependencyManagerInfo.h
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+
+namespace celix { namespace dm {
+
+ /**
+ * Trivial struct containing interface info.
+ */
+ struct InterfaceInfo {
+ /**
+ * The service name of the interface.
+ */
+ std::string serviceName{};
+
+ /**
+ * All the meta information for the component interface.
+ */
+ std::unordered_map<std::string, std::string> properties{};
+ };
+
+ /**
+ * Trivial struct containing service dependency info.
+ */
+ struct ServiceDependencyInfo {
+ /**
+ * The service name targeted by this service dependency.
+ */
+ std::string serviceName{};
+
+ /**
+ * The additional filter used to track services.
+ */
+ std::string filter{};
+
+ /**
+ * The optional version range used to track services.
+ */
+ std::string versionRange{};
+
+ /**
+ * Whether the service is available (at least 1 dependency found).
+ */
+ bool isAvailable{};
+
+ /**
+ * Whether the service is required (need at least 1 available service to be resolved).
+ */
+ bool isRequired{};
+
+ /**
+ * Nummer tracker services.
+ */
+ std::size_t nrOfTrackedServices{0};
+ };
+
+ /**
+ * Trivial struct component info.
+ */
+ struct ComponentInfo {
+ /**
+ * The UUID of the component.
+ */
+ std::string uuid{};
+
+ /**
+ * The name of the component.
+ */
+ std::string name{};
+
+ /**
+ * Whether the component is active.
+ */
+ bool isActive{};
+
+ /**
+ * The state of the component.
+ */
+ std::string state{};
+
+ /**
+ * Number of time started.
+ */
+ std::size_t nrOfTimesStarted{0};
+
+ /**
+ * Number of time resumed cycles.
+ */
+ std::size_t nrOfTimesResumed{0};
+
+ /**
+ * The interface provided by the component (when active).
+ */
+ std::vector<InterfaceInfo> interfacesInfo{};
+
+ /**
+ * The service dependencies of the component.
+ */
+ std::vector<ServiceDependencyInfo> dependenciesInfo{};
+ };
+
+ /**
+ * Trivial struct containing Dependency Manager info.
+ */
+ struct DependencyManagerInfo {
+ /**
+ * The owning bundle id of the dependency manager where information is extracted from.
+ */
+ long bndId{};
+
+ /**
+ * The owning bundle symbolic name of the dependency manager where information is extracted from.
+ */
+ std::string bndSymbolicName{};
+
+ /**
+ * vector of component info for all the (build) components for this dependency manager
+ */
+ std::vector<ComponentInfo> components{};
+ };
+}}
\ No newline at end of file
diff --git a/libs/framework/include/celix/dm/DependencyManager_Impl.h b/libs/framework/include/celix/dm/DependencyManager_Impl.h
index 68dc7cb..d976b08 100644
--- a/libs/framework/include/celix/dm/DependencyManager_Impl.h
+++ b/libs/framework/include/celix/dm/DependencyManager_Impl.h
@@ -35,6 +35,7 @@ Component<T>& DependencyManager::createComponentInternal(std::string name, std::
auto cmp = Component<T>::create(this->context.get(), this->cDepMan.get(), std::move(name), std::move(uuid));
if (cmp->isValid()) {
auto baseCmp = std::static_pointer_cast<BaseComponent>(cmp);
+ std::lock_guard<std::mutex> lck{mutex};
this->components.push_back(baseCmp);
}
@@ -45,22 +46,22 @@ template<class T>
inline
typename std::enable_if<std::is_default_constructible<T>::value, Component<T>&>::type
DependencyManager::createComponent(std::string name, std::string uuid) {
- return createComponentInternal<T>(name, uuid);
+ return createComponentInternal<T>(std::move(name), std::move(uuid));
}
template<class T>
Component<T>& DependencyManager::createComponent(std::unique_ptr<T>&& rhs, std::string name, std::string uuid) {
- return createComponentInternal<T>(name, uuid).setInstance(std::move(rhs));
+ return createComponentInternal<T>(std::move(name), std::move(uuid)).setInstance(std::move(rhs));
}
template<class T>
Component<T>& DependencyManager::createComponent(std::shared_ptr<T> rhs, std::string name, std::string uuid) {
- return createComponentInternal<T>(name, uuid).setInstance(rhs);
+ return createComponentInternal<T>(std::move(name), std::move(uuid)).setInstance(rhs);
}
template<class T>
Component<T>& DependencyManager::createComponent(T rhs, std::string name, std::string uuid) {
- return createComponentInternal<T>(name, uuid).setInstance(std::forward<T>(rhs));
+ return createComponentInternal<T>(std::move(name), std::move(uuid)).setInstance(std::forward<T>(rhs));
}
inline void DependencyManager::start() {
@@ -68,29 +69,40 @@ inline void DependencyManager::start() {
}
inline void DependencyManager::build() {
- for (auto& cmp : components) {
- cmp->runBuild();
- }
+ buildAsync();
wait();
}
inline void DependencyManager::buildAsync() {
- build();
+ std::lock_guard<std::mutex> lck{mutex};
+ for (auto& cmp : components) {
+ cmp->runBuild();
+ }
}
template<typename T>
void DependencyManager::destroyComponent(Component<T> &component) {
- for (auto it = components.begin(); it != components.end(); ++it) {
- if ( (*it).get() == &component) {
- //found
- components.erase(it);
- break;
+ std::shared_ptr<BaseComponent> tmpStore{};
+ {
+ std::lock_guard<std::mutex> lck{mutex};
+ for (auto it = components.begin(); it != components.end(); ++it) {
+ if ( (*it).get() == &component) {
+ //found
+ tmpStore = *it; //prevents destruction in lock
+ components.erase(it);
+ break;
+ }
}
}
}
inline void DependencyManager::clear() {
- components.clear();
+ std::vector<std::shared_ptr<BaseComponent>> swappedComponents{};
+ {
+ std::lock_guard<std::mutex> lck{mutex};
+ std::swap(swappedComponents, components);
+ }
+ swappedComponents.clear();
}
inline void DependencyManager::wait() const {
@@ -106,7 +118,8 @@ inline std::size_t DependencyManager::getNrOfComponents() const {
}
template<typename T>
-inline std::shared_ptr<Component<T>> DependencyManager::findComponent(const std::string& uuid) const {
+inline std::shared_ptr<Component<T>> DependencyManager::findComponent(const std::string& uuid) const {
+ std::lock_guard<std::mutex> lck{mutex};
std::shared_ptr<BaseComponent> found{nullptr};
for (const auto& cmp : components) {
if (cmp->getUUID() == uuid) {
@@ -120,3 +133,65 @@ inline std::shared_ptr<Component<T>> DependencyManager::findComponent(const std:
}
}
+static celix::dm::DependencyManagerInfo createDepManInfoFromC(celix_dependency_manager_info_t* cInfo) {
+ celix::dm::DependencyManagerInfo info{};
+ info.bndId = cInfo->bndId;
+ info.bndSymbolicName = std::string{cInfo->bndSymbolicName};
+
+ for (int i = 0; i < celix_arrayList_size(cInfo->components); ++i) {
+ auto* cCmpInfo = static_cast<dm_component_info_t*>(celix_arrayList_get(cInfo->components, i));
+ celix::dm::ComponentInfo cmpInfo{};
+ cmpInfo.uuid = std::string{cCmpInfo->id};
+ cmpInfo.name = std::string{cCmpInfo->name};
+ cmpInfo.isActive = cCmpInfo->active;
+ cmpInfo.state = std::string{cCmpInfo->state};
+ cmpInfo.nrOfTimesStarted = cCmpInfo->nrOfTimesStarted;
+ cmpInfo.nrOfTimesResumed = cCmpInfo->nrOfTimesResumed;
+
+ for (int k = 0; k < celix_arrayList_size(cCmpInfo->interfaces); ++k) {
+ auto* cIntInfo = static_cast<dm_interface_info_t*>(celix_arrayList_get(cCmpInfo->interfaces, k));
+ celix::dm::InterfaceInfo intInfo{};
+ intInfo.serviceName = std::string{cIntInfo->name};
+ const char* key;
+ CELIX_PROPERTIES_FOR_EACH(cIntInfo->properties, key) {
+ const char* val =celix_properties_get(cIntInfo->properties, key, nullptr);
+ intInfo.properties[std::string{key}] = std::string{val};
+ }
+ cmpInfo.interfacesInfo.emplace_back(std::move(intInfo));
+ }
+
+ for (int k = 0; k < celix_arrayList_size(cCmpInfo->dependency_list); ++k) {
+ auto *cDepInfo = static_cast<dm_service_dependency_info_t *>(celix_arrayList_get(cCmpInfo->dependency_list, k));
+ celix::dm::ServiceDependencyInfo depInfo{};
+ depInfo.serviceName = std::string{cDepInfo->serviceName == nullptr ? "" : cDepInfo->serviceName};
+ depInfo.filter = std::string{cDepInfo->filter == nullptr ? "" : cDepInfo->filter};
+ depInfo.versionRange = std::string{cDepInfo->versionRange == nullptr ? "" : cDepInfo->versionRange};
+ depInfo.isAvailable = cDepInfo->available;
+ depInfo.isRequired = cDepInfo->required;
+ depInfo.nrOfTrackedServices = cDepInfo->count;
+ cmpInfo.dependenciesInfo.emplace_back(std::move(depInfo));
+ }
+
+ info.components.emplace_back(std::move(cmpInfo));
+ }
+ return info;
+}
+
+inline celix::dm::DependencyManagerInfo DependencyManager::getInfo() const {
+ auto* cInfo = celix_dependencyManager_createInfo(cDependencyManager(), celix_bundleContext_getBundleId(context.get()));
+ auto result = createDepManInfoFromC(cInfo);
+ celix_dependencyManager_destroyInfo(cDependencyManager(), cInfo);
+ return result;
+}
+
+
+inline std::vector<celix::dm::DependencyManagerInfo> DependencyManager::getInfos() const {
+ std::vector<celix::dm::DependencyManagerInfo> result{};
+ auto* cInfos = celix_dependencyManager_createInfos(cDependencyManager());
+ for (int i = 0; i < celix_arrayList_size(cInfos); ++i) {
+ auto* cInfo = static_cast<celix_dependency_manager_info_t*>(celix_arrayList_get(cInfos, i));
+ result.emplace_back(createDepManInfoFromC(cInfo));
+ }
+ celix_dependencyManager_destroyInfos(cDependencyManager(), cInfos);
+ return result;
+}
\ 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 11874ff..ad95c00 100644
--- a/libs/framework/include/celix/dm/ServiceDependency.h
+++ b/libs/framework/include/celix/dm/ServiceDependency.h
@@ -361,7 +361,7 @@ namespace celix { namespace dm {
ServiceDependency<T,I>& build();
/**
- * Same a build, but will not wait till the underlining service tracker is created.
+ * Same a build, but will not wait till the underlining service trackers are opened.
* Can be called on the Celix event thread.
*/
ServiceDependency<T,I>& buildAsync();
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index 1d62fa3..4e23e2e 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -1158,6 +1158,12 @@ void celix_bundleContext_waitForEvents(celix_bundle_context_t* ctx);
*/
celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx);
+
+/**
+ * Returns the bundle if for the bundle of this bundle context.
+ */
+long celix_bundleContext_getBundleId(const celix_bundle_context_t *ctx);
+
celix_framework_t* celix_bundleContext_getFramework(const celix_bundle_context_t* ctx);
/**
diff --git a/libs/framework/include/celix_dependency_manager.h b/libs/framework/include/celix_dependency_manager.h
index 8a9897e..6710f12 100644
--- a/libs/framework/include/celix_dependency_manager.h
+++ b/libs/framework/include/celix_dependency_manager.h
@@ -30,18 +30,53 @@
extern "C" {
#endif
+/**
+ * The `celix_dependencyManager_add`, `celix_dependencyManager_remove` and `celix_dependencyManager_removeAllComponents`
+ * funcions for celix_dependency_manager_t should be called outside the Celix event thread.
+ * Note that bundle activators are started and stopped outside the Celix event thread and thus these
+ * functions can be used in bundle activators.
+ *
+ * Inside the Celix event thread - i.e. during a useService callback or add/rem/set call from a service tracker -
+ * the async versions should be used. After a async function has returned, service registration and opening
+ * service trackers are (possibly) still in progress.
+ */
+
/**
* Adds a DM component to the dependency manager
+ *
+ * After this call the components will be created and if the components can be started, they
+ * will be started and the services will be registered.
+ *
+ * Should not be called from the Celix event thread.
*/
celix_status_t celix_dependencyManager_add(celix_dependency_manager_t *manager, celix_dm_component_t *component);
/**
+ * Same as celix_dependencyManager_add, but this call will not wait until all service registrations and
+ * tracker are registered/opened on the Celix event thread.
+ * Can be called on the Celix event thread.
+ */
+celix_status_t celix_dependencyManager_addAsync(celix_dependency_manager_t *manager, celix_dm_component_t *component);
+
+/**
* Removes a DM component from the dependency manager and destroys it
+ *
+ * After this call the components will be destroyed and if the components was started, the service registrations
+ * and service tracked of this component will be unregistered and closed.
+ *
+ * Should not be called from the Celix event thread.
*/
celix_status_t celix_dependencyManager_remove(celix_dependency_manager_t *manager, celix_dm_component_t *component);
/**
+ * Same as celix_dependencyManager_remove, but this call will not wait until all service registrations and
+ * tracker are unregistered/closed on the Celix event thread.
+ * Can be called on the Celix event thread.
+ */
+celix_status_t celix_dependencyManager_removeAsync(celix_dependency_manager_t *manager, celix_dm_component_t *component);
+
+/**
* Removes a DM component from the dependency manager.
*/
celix_status_t celix_dependencyManager_removeWithoutDestroy(celix_dependency_manager_t *manager, celix_dm_component_t *component);
@@ -49,11 +84,19 @@ celix_status_t celix_dependencyManager_removeWithoutDestroy(celix_dependency_man
/**
* Removes all DM components from the dependency manager.
*
- * This function cannot be called on the Celix event thread.
+ * Should not be called from the Celix event thread.
*/
celix_status_t celix_dependencyManager_removeAllComponents(celix_dependency_manager_t *manager);
/**
+ * Same as celix_dependencyManager_removeAllComponents, but this call will not wait til all
+ * service registration and service trackers are unregistered/closed.
+ *
+ * Can be called on the Celix event thread.
+ */
+celix_status_t celix_dependencyManager_removeAllComponentsAsync(celix_dependency_manager_t *manager);
+
+/**
* Create and returns a dependency manager info struct for the specified bundle.
* The dependency manager info contains information about the state of the dependency manager components
*
@@ -75,7 +118,7 @@ celix_dependency_manager_info_t* celix_dependencyManager_createInfo(celix_depend
* @returns A Celix array of dependency manager infos (celix_dependency_manager_info_t*)
* for the provided bundle id or NULL if the bundle id is invalid.
*/
-celix_array_list_t * /*celix_dependency_manager_info_t entries*/ celix_dependencyManager_createInfos(celix_dependency_manager_t *manager);
+celix_array_list_t * /*celix_dependency_manager_info_t* entries*/ celix_dependencyManager_createInfos(celix_dependency_manager_t *manager);
/**
* Destroys a DM info struct.
diff --git a/libs/framework/include/celix_dm_info.h b/libs/framework/include/celix_dm_info.h
index b7cfda9..fa66d95 100644
--- a/libs/framework/include/celix_dm_info.h
+++ b/libs/framework/include/celix_dm_info.h
@@ -55,9 +55,11 @@ struct celix_dm_component_info_struct {
char id[64];
char name[128];
bool active;
- char * state;
- celix_array_list_t *interfaces; // type dm_interface_info_pt
- celix_array_list_t *dependency_list; // type dm_service_dependency_info_pt
+ char* state;
+ size_t nrOfTimesStarted;
+ size_t nrOfTimesResumed;
+ celix_array_list_t *interfaces; // type dm_interface_info_t*
+ celix_array_list_t *dependency_list; // type dm_service_dependency_info_t*
};
typedef struct celix_dm_component_info_struct *dm_component_info_pt; //deprecated
typedef struct celix_dm_component_info_struct dm_component_info_t; //deprecated
@@ -65,7 +67,8 @@ typedef struct celix_dm_component_info_struct celix_dm_component_info_t;
struct celix_dm_dependency_manager_info_struct {
long bndId;
- celix_array_list_t *components; // type dm_component_info
+ char* bndSymbolicName;
+ celix_array_list_t *components; // type dm_component_info_t*
};
typedef struct celix_dm_dependency_manager_info_struct *dm_dependency_manager_info_pt; //deprecated
typedef struct celix_dm_dependency_manager_info_struct dm_dependency_manager_info_t; //deprecated
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index 1cffcce..674ab68 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -1616,6 +1616,11 @@ celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx)
return bnd;
}
+long celix_bundleContext_getBundleId(const celix_bundle_context_t *ctx) {
+ celix_bundle_t *bnd = celix_bundleContext_getBundle(ctx);
+ return bnd == NULL ? -1L : celix_bundle_getId(bnd);
+}
+
celix_framework_t* celix_bundleContext_getFramework(const celix_bundle_context_t *ctx) {
celix_framework_t *fw = NULL;
if (ctx != NULL) {
diff --git a/libs/framework/src/dm_component_impl.c b/libs/framework/src/dm_component_impl.c
index da767dc..332ce58 100644
--- a/libs/framework/src/dm_component_impl.c
+++ b/libs/framework/src/dm_component_impl.c
@@ -63,6 +63,9 @@ struct celix_dm_component_struct {
*/
size_t nrOfSvcDepependenciesInProgress;
+ size_t nrOfTimesStarted;
+ size_t nrOfTimesResumed;
+
bool isEnabled;
};
@@ -519,13 +522,14 @@ static celix_status_t celix_dmComponent_suspend(celix_dm_component_t *component,
static celix_status_t celix_dmComponent_resume(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency) {
celix_status_t status = CELIX_SUCCESS;
dm_service_dependency_strategy_t strategy = celix_dmServiceDependency_getStrategy(dependency);
- if (strategy == DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND && component->callbackStop != NULL) {
+ if (strategy == DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND && component->callbackStart != NULL) {
celix_bundleContext_log(component->context, CELIX_LOG_LEVEL_TRACE,
"Resuming component %s (uuid=%s)",
component->name,
component->uuid);
celix_dmComponent_registerServices(component);
status = component->callbackStart(component->implementation);
+ component->nrOfTimesResumed += 1;
}
return status;
}
@@ -750,6 +754,7 @@ static celix_status_t celix_dmComponent_performTransition(celix_dm_component_t *
status = component->callbackStart(component->implementation);
}
celix_dmComponent_registerServices(component);
+ component->nrOfTimesStarted += 1;
*transition = true;
} else if (oldState == DM_CMP_STATE_TRACKING_OPTIONAL && newState == DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED) {
celix_dmComponent_unregisterServices(component);
@@ -901,6 +906,8 @@ celix_status_t celix_dmComponent_getComponentInfo(celix_dm_component_t *componen
info->active = false;
memcpy(info->id, component->uuid, DM_COMPONENT_MAX_ID_LENGTH);
memcpy(info->name, component->name, DM_COMPONENT_MAX_NAME_LENGTH);
+ info->nrOfTimesStarted = component->nrOfTimesStarted;
+ info->nrOfTimesResumed = component->nrOfTimesResumed;
switch (component->state) {
case DM_CMP_STATE_INACTIVE :
diff --git a/libs/framework/src/dm_dependency_manager_impl.c b/libs/framework/src/dm_dependency_manager_impl.c
index f3811e7..dced291 100644
--- a/libs/framework/src/dm_dependency_manager_impl.c
+++ b/libs/framework/src/dm_dependency_manager_impl.c
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <dm_dependency_manager.h>
#include <memory.h>
+#include <celix_utils.h>
#include "bundle_context.h"
#include "dm_component_impl.h"
@@ -52,20 +53,22 @@ void celix_private_dependencyManager_destroy(celix_dependency_manager_t *manager
}
}
-
celix_status_t celix_dependencyManager_add(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
- celix_status_t status;
+ celix_status_t status = celix_dependencyManager_addAsync(manager, component);
+ celix_dependencyManager_wait(manager);
+ return status;
+}
+celix_status_t celix_dependencyManager_addAsync(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
celixThreadMutex_lock(&manager->mutex);
celix_arrayList_add(manager->components, component);
celixThreadMutex_unlock(&manager->mutex);
- status = celix_private_dmComponent_enable(component);
- return status;
+ return celix_private_dmComponent_enable(component);
}
celix_status_t celix_dependencyManager_removeWithoutDestroy(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
- celix_status_t status;
+ celix_status_t status = CELIX_SUCCESS;
celixThreadMutex_lock(&manager->mutex);
bool found = false;
@@ -90,13 +93,24 @@ celix_status_t celix_dependencyManager_removeWithoutDestroy(celix_dependency_man
}
celix_status_t celix_dependencyManager_remove(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
+ celix_status_t status = celix_dependencyManager_removeAsync(manager, component);
+ celix_dependencyManager_wait(manager);
+ return status;
+}
+
+celix_status_t celix_dependencyManager_removeAsync(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
celix_status_t status = celix_dependencyManager_removeWithoutDestroy(manager, component);
celix_dmComponent_destroy(component);
return status;
}
-
celix_status_t celix_dependencyManager_removeAllComponents(celix_dependency_manager_t *manager) {
+ celix_status_t status = celix_dependencyManager_removeAllComponentsAsync(manager);
+ celix_dependencyManager_wait(manager);
+ return status;
+}
+
+celix_status_t celix_dependencyManager_removeAllComponentsAsync(celix_dependency_manager_t *manager) {
celix_status_t status = CELIX_SUCCESS;
celix_array_list_t *toRemoveComponents = celix_arrayList_create();
@@ -119,7 +133,6 @@ celix_status_t celix_dependencyManager_removeAllComponents(celix_dependency_mana
return status;
}
-
static void celix_dm_getInfoCallback(void *handle, const celix_bundle_t *bnd) {
celix_dependency_manager_info_t **out = handle;
@@ -128,6 +141,8 @@ static void celix_dm_getInfoCallback(void *handle, const celix_bundle_t *bnd) {
celix_dependency_manager_t *mng = celix_bundleContext_getDependencyManager(context);
celix_dependency_manager_info_t *info = calloc(1, sizeof(*info));
+ info->bndId = celix_bundle_getId(bnd);
+ info->bndSymbolicName = celix_utils_strdup(celix_bundle_getSymbolicName(bnd));
celixThreadMutex_lock(&mng->mutex);
if (info != NULL) {
info->components = celix_arrayList_create();
@@ -161,6 +176,7 @@ static void celix_dm_getInfosCallback(void *handle, const celix_bundle_t *bnd) {
celix_dependency_manager_info_t *info = calloc(1, sizeof(*info));
celixThreadMutex_lock(&mng->mutex);
info->bndId = celix_bundle_getId(bnd);
+ info->bndSymbolicName = celix_utils_strdup(celix_bundle_getSymbolicName(bnd));
info->components = celix_arrayList_create();
int size = celix_arrayList_size(mng->components);
for (int i = 0; i < size; i += 1) {
@@ -236,6 +252,7 @@ void celix_dependencyManager_destroyInfo(celix_dependency_manager_t *manager __a
component_destroyComponentInfo(cmpinfo);
}
arrayList_destroy(info->components);
+ free(info->bndSymbolicName);
free(info);
}
@@ -314,4 +331,4 @@ celix_status_t dependencyManager_getInfo(celix_dependency_manager_t *manager, dm
void dependencyManager_destroyInfo(celix_dependency_manager_t *manager, celix_dependency_manager_info_t *info) {
celix_dependencyManager_destroyInfo(manager, info);
-}
+}
\ No newline at end of file