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 2019/08/26 21:52:09 UTC
[celix] branch feature/cxx updated: CELIX-370: Improves state
handling for component manager and adds support for provided services for
the component manager
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/cxx
in repository https://gitbox.apache.org/repos/asf/celix.git
The following commit(s) were added to refs/heads/feature/cxx by this push:
new 69e1792 CELIX-370: Improves state handling for component manager and adds support for provided services for the component manager
69e1792 is described below
commit 69e179241b953b8b942d894dd5dada4119120419
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Mon Aug 26 23:51:28 2019 +0200
CELIX-370: Improves state handling for component manager and adds support for provided services for the component manager
---
.../gtest/src/ComponentManager_tests.cc | 225 ++++++++++-
libs/framework_cxx/include/celix/BundleContext.h | 4 +-
.../framework_cxx/include/celix/ComponentManager.h | 442 ++++++++++++++++-----
libs/framework_cxx/src/BundleContext.cc | 2 +-
libs/framework_cxx/src/ComponentManager.cc | 431 +++++++++++++++-----
libs/registry/include/celix/Constants.h | 10 +-
libs/registry/include/celix/ServiceRegistry.h | 99 +++--
libs/registry/src/ServiceRegistry.cc | 97 +++--
8 files changed, 996 insertions(+), 314 deletions(-)
diff --git a/libs/framework_cxx/gtest/src/ComponentManager_tests.cc b/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
index db7fc7e..7a0d3b1 100644
--- a/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
+++ b/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
@@ -32,37 +32,38 @@ private:
};
+class Cmp {};
+
+class ISvc {};
+
+
TEST_F(ComponentManagerTest, CreateDestroy) {
auto ctx = framework().context();
- class Cmp {};
-
celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
EXPECT_FALSE(cmpMng.isEnabled());
- EXPECT_TRUE(cmpMng.isResolved()); //no deps -> resolved
- EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Disabled);
+ EXPECT_FALSE(cmpMng.isResolved()); //disabled -> not resolved
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::Disabled);
cmpMng.enable();
EXPECT_TRUE(cmpMng.isEnabled());
- EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Started);
+ EXPECT_TRUE(cmpMng.isResolved()); //no deps -> resolved
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
cmpMng.disable();
EXPECT_FALSE(cmpMng.isEnabled());
- EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Disabled);
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::Disabled);
}
TEST_F(ComponentManagerTest, AddSvcDep) {
auto ctx = framework().context();
- class Cmp {};
- class ISvc {};
-
celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
cmpMng.addServiceDependency<ISvc>()
.setRequired(true);
cmpMng.enable();
EXPECT_TRUE(cmpMng.isEnabled());
- EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Uninitialized);
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentUninitialized);
//dep not available -> cmp manager not resolved
@@ -72,28 +73,38 @@ TEST_F(ComponentManagerTest, AddSvcDep) {
auto svcReg = ctx->registerService(std::make_shared<ISvc>());
//dep available -> cmp manager resolved
EXPECT_TRUE(cmpMng.isResolved());
- EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Started);
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
cmpMng.disable();
//cmp disabled -> not resolved
EXPECT_FALSE(cmpMng.isResolved());
- EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Disabled);
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::Disabled);
//dmp enabled & svc available -> resolved.
cmpMng.enable();
EXPECT_TRUE(cmpMng.isResolved());
- EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Started);
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
svcReg.unregister();
- EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Initialized);
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentInitialized);
//dep unregisted -> state is Initialized
}
-TEST_F(ComponentManagerTest, AddAndRemoveSvcDep) {
+TEST_F(ComponentManagerTest, FindServiceDepenencies) {
auto ctx = framework().context();
+ std::string svcDepUuid;
- class Cmp {};
- class ISvc {};
+ celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
+ cmpMng.addServiceDependency<ISvc>()
+ .extractUUID(svcDepUuid);
+
+ EXPECT_TRUE(cmpMng.findServiceDependency<ISvc>(svcDepUuid).isValid());
+ EXPECT_FALSE(cmpMng.findServiceDependency<Cmp /*in correct template*/>(svcDepUuid).isValid());
+ EXPECT_FALSE(cmpMng.findServiceDependency<ISvc>("non existing uuid").isValid());
+}
+
+TEST_F(ComponentManagerTest, AddAndRemoveSvcDep) {
+ auto ctx = framework().context();
std::string svcDepUuid;
celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
@@ -109,4 +120,182 @@ TEST_F(ComponentManagerTest, AddAndRemoveSvcDep) {
cmpMng.removeServiceDependency(svcDepUuid);
//dep removed -> cmp manager resolved
EXPECT_TRUE(cmpMng.isResolved());
-}
\ No newline at end of file
+}
+
+
+TEST_F(ComponentManagerTest, AddAndEnableSvcDep) {
+ auto ctx = framework().context();
+
+ celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
+ cmpMng.addServiceDependency<ISvc>()
+ .setRequired(true);
+ cmpMng.enable();
+ EXPECT_TRUE(cmpMng.isEnabled());
+ EXPECT_EQ(cmpMng.nrOfServiceDependencies(), 1);
+
+ //dep not available -> cmp manager not resolved
+ EXPECT_FALSE(cmpMng.isResolved());
+
+ auto svcReg = ctx->registerService(std::make_shared<ISvc>());
+ //svc add -> cmp resolved
+ EXPECT_TRUE(cmpMng.isResolved());
+
+ std::string svcUUID{};
+ cmpMng.addServiceDependency<ISvc>()
+ .setFilter("(non_existing=*)")
+ .extractUUID(svcUUID);
+ EXPECT_EQ(cmpMng.nrOfServiceDependencies(), 2);
+ //new dep is still disabled -> cmp is resolved
+ EXPECT_TRUE(cmpMng.isResolved());
+
+ cmpMng.findServiceDependency<ISvc>(svcUUID).enable();
+ //new required svc dep -> cmp not resolved
+ EXPECT_FALSE(cmpMng.isResolved());
+ //cmp already started should now be initialized
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentInitialized);
+ EXPECT_EQ(cmpMng.nrOfServiceDependencies(), 2);
+
+ cmpMng.removeServiceDependency(svcUUID);
+ //required svc dep is gone -> resolved
+ EXPECT_TRUE(cmpMng.isResolved());
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
+ EXPECT_EQ(cmpMng.nrOfServiceDependencies(), 1);
+}
+
+TEST_F(ComponentManagerTest, CmpLifecycleCallbacks) {
+ class TestCmp {
+ public:
+ int initCount = 0;
+ int startCount = 0;
+ int stopCount = 0;
+ int deinitCount = 0;
+
+ void init() {++initCount;}
+ void start() {++startCount;}
+ void stop() {++stopCount;}
+ void deinit() {++deinitCount;}
+ };
+
+ auto ctx = framework().context();
+
+ celix::ComponentManager<TestCmp> cmpMng{ctx, std::make_shared<TestCmp>()};
+ cmpMng.setCallbacks(&TestCmp::init, &TestCmp::start, &TestCmp::stop, &TestCmp::deinit);
+ auto cmp = cmpMng.getCmpInstance();
+ EXPECT_EQ(0, cmp->initCount);
+ EXPECT_EQ(0, cmp->startCount);
+ EXPECT_EQ(0, cmp->stopCount);
+ EXPECT_EQ(0, cmp->deinitCount);
+
+ cmpMng.enable(); // started
+ EXPECT_EQ(1, cmp->initCount);
+ EXPECT_EQ(1, cmp->startCount);
+ EXPECT_EQ(0, cmp->stopCount);
+ EXPECT_EQ(0, cmp->deinitCount);
+
+ cmpMng.disable(); // disbabling -> stop -> deinit
+ EXPECT_EQ(1, cmp->initCount);
+ EXPECT_EQ(1, cmp->startCount);
+ EXPECT_EQ(1, cmp->stopCount);
+ EXPECT_EQ(1, cmp->deinitCount);
+}
+
+TEST_F(ComponentManagerTest, SuspenseAndLockingStrategy) {
+ auto ctx = framework().context();
+
+ celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
+ cmpMng.addServiceDependency<ISvc>().setFilter("(id=locking)").setRequired(false).setStrategy(celix::UpdateServiceStrategy::Locking);
+ cmpMng.addServiceDependency<ISvc>().setFilter("(id=suspense)").setRequired(false);
+ cmpMng.enable(); //no required dep -> cmp started.
+
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
+
+ celix::Properties props{};
+ props["id"] = "locking";
+ auto reg1 = ctx->registerService(std::make_shared<ISvc>(), props); //svc registered -> cmp updated, using locking strategy so no suspense triggered.
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
+ EXPECT_EQ(cmpMng.getSuspendedCount(), 0); //no suspense needed;
+
+
+ props["id"] = "suspense";
+ auto reg2 = ctx->registerService(std::make_shared<ISvc>(), props); //svc registered -> cmp updated, using suspense strategy so 1 suspense triggered.
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
+ EXPECT_EQ(cmpMng.getSuspendedCount(), 1); //2x suspense needed (for both services);
+
+ reg2.unregister();
+ EXPECT_EQ(cmpMng.getSuspendedCount(), 2);
+}
+
+TEST_F(ComponentManagerTest, RequiredAndOptionalDependencies) {
+ auto ctx = framework().context();
+
+ celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
+ cmpMng.addServiceDependency<ISvc>().setFilter("(id=required)").setRequired(true);
+ cmpMng.addServiceDependency<ISvc>().setFilter("(id=optional)").setRequired(false);
+ cmpMng.enable(); //required dep -> cmp uninitialized.
+
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentUninitialized);
+
+ celix::Properties props{};
+ props["id"] = "optional";
+ auto reg1 = ctx->registerService(std::make_shared<ISvc>(), props);
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentUninitialized);
+
+
+ props["id"] = "required";
+ auto reg2 = ctx->registerService(std::make_shared<ISvc>(), props);
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
+
+ cmpMng.addServiceDependency<ISvc>().setFilter("(id=optional2)").setRequired(false).enable();
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
+
+ cmpMng.addServiceDependency<ISvc>().setFilter("(id=required2)").setRequired(true).enable();
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentInitialized);
+
+ props["id"] = "required2";
+ auto reg3 = ctx->registerService(std::make_shared<ISvc>(), props); //missing required cmp from started to initialized.
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
+}
+
+TEST_F(ComponentManagerTest, AddProvidedServices) {
+ class TestCmp : public ISvc {};
+ auto ctx = framework().context();
+ celix::ComponentManager<TestCmp> cmpMng{ctx, std::make_shared<TestCmp>()};
+ cmpMng.addProvidedService<ISvc>().addProperty("nr", "1");
+ cmpMng.enable();
+ EXPECT_EQ(cmpMng.getState(), celix::ComponentManagerState::ComponentStarted);
+ EXPECT_EQ(cmpMng.nrOfProvidedServices(), 1);
+
+ //one service should be registered
+ EXPECT_EQ(ctx->findServices<ISvc>().size(), 1);
+ EXPECT_EQ(ctx->findServices<ISvc>("(nr=1)").size(), 1);
+
+ std::string provideUUID;
+ cmpMng.addProvidedService<ISvc>().addProperty("nr", "2").extractUUID(provideUUID);
+ //still only one -> second provide not jet enabled
+ EXPECT_EQ(ctx->findServices<ISvc>().size(), 1);
+ EXPECT_EQ(cmpMng.nrOfProvidedServices(), 2);
+
+ cmpMng.findProvidedService<ISvc>(provideUUID).enable();
+ //enabled -> should be 2 now
+ EXPECT_EQ(ctx->findServices<ISvc>().size(), 2);
+ cmpMng.findProvidedService<ISvc>(provideUUID).disable();
+ //disabled -> should be 1 now
+ EXPECT_EQ(ctx->findServices<ISvc>().size(), 1);
+ cmpMng.findProvidedService<ISvc>(provideUUID).enable();
+ cmpMng.removeProvideService(provideUUID);
+ EXPECT_EQ(cmpMng.nrOfProvidedServices(), 1);
+}
+
+TEST_F(ComponentManagerTest, FindProvidedServices) {
+ class TestCmp : public ISvc {};
+ auto ctx = framework().context();
+ celix::ComponentManager<TestCmp> cmpMng{ctx, std::make_shared<TestCmp>()};
+
+ std::string uuid;
+ cmpMng.addProvidedService<ISvc>().extractUUID(uuid);
+
+ EXPECT_TRUE(cmpMng.findProvidedService<ISvc>(uuid).isValid());
+ EXPECT_FALSE(cmpMng.findProvidedService<ISvc>("bla").isValid());
+}
+
+//TODO test callbacks svc dep (set, add, rem, update)
diff --git a/libs/framework_cxx/include/celix/BundleContext.h b/libs/framework_cxx/include/celix/BundleContext.h
index 2cdbf97..ef6f5d1 100644
--- a/libs/framework_cxx/include/celix/BundleContext.h
+++ b/libs/framework_cxx/include/celix/BundleContext.h
@@ -39,8 +39,8 @@ namespace celix {
std::shared_ptr<celix::IBundle> bundle() const;
template<typename I>
- celix::ServiceRegistration registerService(I &svc, celix::Properties props = {}) {
- return registry().registerService<I>(svc, std::move(props), bundle());
+ celix::ServiceRegistration registerService(I &&svc, celix::Properties props = {}) {
+ return registry().registerService<I>(std::forward<I>(svc), std::move(props), bundle());
}
template<typename I>
diff --git a/libs/framework_cxx/include/celix/ComponentManager.h b/libs/framework_cxx/include/celix/ComponentManager.h
index 2612fa5..0e0183a 100644
--- a/libs/framework_cxx/include/celix/ComponentManager.h
+++ b/libs/framework_cxx/include/celix/ComponentManager.h
@@ -29,35 +29,47 @@
namespace celix {
- enum class ComponentState {
+ enum class ComponentManagerState {
Disabled,
- Uninitialized,
- Initialized,
- Started
+ ComponentUninitialized,
+ ComponentInitialized,
+ ComponentStarted
};
template<typename T, typename I>
class ServiceDependency; //forward declaration
class GenericServiceDependency; //forward declaration
+ template<typename T, typename I>
+ class ProvidedService; //forward declaration
+ class GenericProvidedService; //forward declaration
+
class GenericComponentManager {
public:
virtual ~GenericComponentManager() = default;
- ComponentState getState() const;
+ ComponentManagerState getState() const;
bool isEnabled() const;
bool isResolved() const;
std::string getName() const;
std::string getUUD() const;
+ std::size_t getSuspendedCount() const;
- //TODO make friend of SvcDep
- void updateState();
void removeServiceDependency(const std::string& serviceDependencyUUID);
+ void removeProvideService(const std::string& provideServiceUUID);
+ std::size_t nrOfServiceDependencies();
+ std::size_t nrOfProvidedServices();
protected:
- GenericComponentManager(std::shared_ptr<BundleContext> _ctx, const std::string &_name);
+ GenericComponentManager(std::shared_ptr<BundleContext> ctx, const std::string &name);
void setEnabled(bool enable);
+ std::shared_ptr<GenericServiceDependency> findGenericServiceDependency(const std::string& svcName, const std::string& svcDepUUID);
+ std::shared_ptr<GenericProvidedService> findGenericProvidedService(const std::string& svcName, const std::string& providedServiceUUID);
+ void updateState();
+ void updateServiceRegistrations();
+ void suspense();
+ void resume();
/**** Fields ****/
const std::shared_ptr<BundleContext> ctx;
@@ -65,23 +77,28 @@ namespace celix {
const std::string uuid;
std::mutex callbacksMutex{}; //protects below std::functions
- std::function<void()> init{[]{/*nop*/}};
- std::function<void()> start{[]{/*nop*/}};
- std::function<void()> stop{[]{/*nop*/}};
- std::function<void()> deinit{[]{/*nop*/}};
+ std::function<void()> initCmp{[]{/*nop*/}};
+ std::function<void()> startCmp{[]{/*nop*/}};
+ std::function<void()> stopCmp{[]{/*nop*/}};
+ std::function<void()> deinitCmp{[]{/*nop*/}};
std::mutex serviceDependenciesMutex{};
std::unordered_map<std::string,std::shared_ptr<GenericServiceDependency>> serviceDependencies{}; //key = dep uuid
+
+ std::mutex providedServicesMutex{};
+ std::unordered_map<std::string,std::shared_ptr<GenericProvidedService>> providedServices{}; //key = provide uuid
private:
- void setState(ComponentState state);
+ void setState(ComponentManagerState state);
void setInitialized(bool initialized);
void transition();
mutable std::mutex stateMutex{}; //protects below
- ComponentState state = ComponentState::Disabled;
+ ComponentManagerState state = ComponentManagerState::Disabled;
bool enabled = false;
bool initialized = false;
- std::queue<std::pair<ComponentState,ComponentState>> transitionQueue{};
+ bool suspended = false;
+ std::size_t suspendedCount = 0;
+ std::queue<std::pair<ComponentManagerState,ComponentManagerState>> transitionQueue{};
};
template<typename T>
@@ -95,8 +112,6 @@ namespace celix {
ComponentManager<T>& enable();
ComponentManager<T>& disable();
- std::shared_ptr<T> instance();
-
ComponentManager<T>& setCallbacks(
void (T::*init)(),
void (T::*start)(),
@@ -107,14 +122,22 @@ namespace celix {
ServiceDependency<T,I>& addServiceDependency();
template<typename I>
- ServiceDependency<T,I>* findServiceDependency(const std::string& serviceDependencyUUID);
+ ServiceDependency<T,I>& findServiceDependency(const std::string& serviceDependencyUUID);
ComponentManager<T>& extractUUID(std::string& out);
+
+ template<typename I>
+ ProvidedService<T,I>& addProvidedService();
+
+ template<typename I>
+ ProvidedService<T,I>& findProvidedService(const std::string& providedServiceUUID);
//
// template<typename F>
// ServiceDependency<T,F>& addFunctionServiceDependency(const std::string &functionName);
+
+ std::shared_ptr<T> getCmpInstance() const;
private:
- std::shared_ptr<T> inst;
+ const std::shared_ptr<T> inst;
};
@@ -123,30 +146,50 @@ namespace celix {
Many
};
+ enum class UpdateServiceStrategy {
+ Suspense,
+ Locking
+ };
+
class GenericServiceDependency {
public:
virtual ~GenericServiceDependency() = default;
bool isResolved() const;
Cardinality getCardinality() const;
- bool getRequired() const;
+ bool isRequired() const;
const std::string& getFilter() const;
- std::string getUUD();
+ const std::string& getUUD() const;
+ const std::string& getSvcName() const;
+ bool isValid() const;
+ UpdateServiceStrategy getStrategy() const;
- bool isEnabled();
+ bool isEnabled() const;
virtual void setEnabled(bool e) = 0;
protected:
GenericServiceDependency(
std::shared_ptr<BundleContext> ctx,
- std::function<void()> stateChangedCallback);
+ std::string svcName,
+ std::function<void()> stateChangedCallback,
+ std::function<void()> suspenseCallback,
+ std::function<void()> resumeCallback,
+ bool isValid);
+
+ void preServiceUpdate();
+ void postServiceUpdate();
//Fields
const std::shared_ptr<BundleContext> ctx;
+ const std::string svcName;
const std::function<void()> stateChangedCallback;
+ const std::function<void()> suspenseCallback;
+ const std::function<void()> resumeCallback;
const std::string uuid;
+ const bool valid;
mutable std::mutex mutex{}; //protects below
- bool required = false;
+ UpdateServiceStrategy strategy = UpdateServiceStrategy::Suspense;
+ bool required = true;
std::string filter{};
Cardinality cardinality = Cardinality::One;
std::vector<ServiceTracker> tracker{}; //max 1 (1 == enabled / 0 = disabled
@@ -158,10 +201,17 @@ namespace celix {
using ComponentType = T;
using ServiceType = I;
- ServiceDependency(std::shared_ptr<BundleContext> ctx, std::function<void()> stateChangedCallback, std::function<std::shared_ptr<T>()> getCmpInstance);
+ ServiceDependency(
+ std::shared_ptr<BundleContext> ctx,
+ std::function<void()> stateChangedCallback,
+ std::function<std::shared_ptr<T>()> getCmpInstance,
+ std::function<void()> suspenseCallback,
+ std::function<void()> resumeCallback,
+ bool isValid = true);
~ServiceDependency() override = default;
ServiceDependency<T,I>& setFilter(const std::string &filter);
+ ServiceDependency<T,I>& setStrategy(UpdateServiceStrategy strategy);
ServiceDependency<T,I>& setRequired(bool required);
ServiceDependency<T,I>& setCardinality(celix::Cardinality cardinality);
ServiceDependency<T,I>& setCallbacks(void (T::*set)(std::shared_ptr<I>));
@@ -169,12 +219,6 @@ namespace celix {
//TODO update callback
//TODO callbacks with properties and owner
- ServiceDependency<T,I>& setFunctionCallbacks(
- std::function<void(std::shared_ptr<I>, const celix::Properties &props, const celix::IResourceBundle &owner)> set,
- std::function<void(std::shared_ptr<I>, const celix::Properties &props, const celix::IResourceBundle &owner)> add,
- std::function<void(std::shared_ptr<I>, const celix::Properties &props, const celix::IResourceBundle &owner)> rem,
- std::function<void(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices)> update);
-
ServiceDependency<T,I>& extractUUID(std::string& out);
ServiceDependency<T,I>& enable();
ServiceDependency<T,I>& disable();
@@ -182,21 +226,80 @@ namespace celix {
void setEnabled(bool e) override;
private:
- const std::function<std::shared_ptr<T>()> getCmpInstance;
+ void setService(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner);
+ void addService(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner);
+ void remService(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner);
+ void updateServices(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices);
+ const std::function<std::shared_ptr<T>()> getCmpInstance;
+ std::mutex callbacksMutex{}; //protects below
std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> set{};
std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> add{};
std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> rem{};
std::function<void(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices)> update{};
};
+
+
+ class GenericProvidedService {
+ public:
+ virtual ~GenericProvidedService() = default;
+
+ bool isEnabled() const;
+ const std::string& getUUID() const;
+ const std::string& getServiceName() const;
+ bool isValid() const;
+
+ void setEnabled(bool enabled);
+ void unregisterService();
+ bool isServiceRegistered();
+ virtual void registerService() = 0;
+ protected:
+ GenericProvidedService(std::shared_ptr<celix::BundleContext> ctx, std::string svcName, std::function<void()> updateServiceRegistrationsCallback, bool valid);
+
+ const std::shared_ptr<celix::BundleContext> ctx;
+ const std::string uuid;
+ const std::string svcName;
+ const std::function<void()> updateServiceRegistrationsCallback;
+ const bool valid;
+
+ mutable std::mutex mutex{}; //protects below
+ bool enabled = false;
+ std::vector<celix::ServiceRegistration> registration{}; //max size 1 (optional). 0 == disabled, 1 == enabled
+ celix::Properties properties{};
+ };
+
+ template<typename T, typename I>
+ class ProvidedService : public GenericProvidedService {
+ public:
+ ProvidedService(
+ std::shared_ptr<celix::BundleContext> ctx,
+ std::function<std::shared_ptr<T>()> getCmpInstanceCallback,
+ std::function<void()> updateServiceRegistrationsCallback,
+ bool valid = true);
+ virtual ~ProvidedService() = default;
+
+ ProvidedService& extractUUID(std::string& out);
+ ProvidedService& enable();
+ ProvidedService& disable();
+ ProvidedService& setProperties(const celix::Properties& props);
+ ProvidedService& setProperties(celix::Properties props);
+ ProvidedService& addProperty(const std::string &name, const std::string &val); //TODO add int, long, bool, etc property
+
+ void registerService() override;
+ private:
+ const std::function<std::shared_ptr<T>()> getcmpInstanceCallback;
+ };
}
-std::ostream& operator<< (std::ostream& out, celix::ComponentState state);
+std::ostream& operator<< (std::ostream& out, celix::ComponentManagerState state);
+std::ostream& operator<< (std::ostream& out, const celix::GenericComponentManager& mng);
-/**************************** IMPLEMENTATION *************************************************************************/
+/**********************************************************************************************************************
+ ComponentManager Implementation
+ **********************************************************************************************************************/
template<typename T>
celix::ComponentManager<T>::ComponentManager(
@@ -224,35 +327,34 @@ celix::ComponentManager<T>& celix::ComponentManager<T>::setCallbacks(
void (T::*memberStop)(),
void (T::*memberDeinit)()) {
std::lock_guard<std::mutex> lck{callbacksMutex};
- init = [this, memberInit]() {
+ initCmp = [this, memberInit]() {
if (memberInit) {
- (this->instance()->*memberInit)();
+ T* ptr = this->getCmpInstance().get();
+ (ptr->*memberInit)();
}
};
- start = [this, memberStart]() {
+ startCmp = [this, memberStart]() {
if (memberStart) {
- (this->instance()->*memberStart)();
+ T* ptr = this->getCmpInstance().get();
+ (ptr->*memberStart)();
}
};
- stop = [this, memberStop]() {
+ stopCmp = [this, memberStop]() {
if (memberStop) {
- (this->instance()->*memberStop)();
+ T* ptr = this->getCmpInstance().get();
+ (ptr->*memberStop)();
}
};
- deinit = [this, memberDeinit]() {
+ deinitCmp = [this, memberDeinit]() {
if (memberDeinit) {
- (this->instance()->*memberDeinit)();
+ T* ptr = this->getCmpInstance().get();
+ (ptr->*memberDeinit)();
}
};
return *this;
}
template<typename T>
-std::shared_ptr<T> celix::ComponentManager<T>::instance() {
- return inst;
-}
-
-template<typename T>
celix::ComponentManager<T>& celix::ComponentManager<T>::extractUUID(std::string &out) {
out = uuid;
return *this;
@@ -261,7 +363,7 @@ celix::ComponentManager<T>& celix::ComponentManager<T>::extractUUID(std::string
template<typename T>
template<typename I>
celix::ServiceDependency<T,I>& celix::ComponentManager<T>::addServiceDependency() {
- auto *dep = new celix::ServiceDependency<T,I>{ctx, [this]{updateState();}, [this]{return instance();}};
+ auto *dep = new celix::ServiceDependency<T,I>{ctx, [this]{updateState();}, [this]{return getCmpInstance();}, [this]{suspense();}, [this]{resume();}};
std::lock_guard<std::mutex> lck{serviceDependenciesMutex};
serviceDependencies[dep->getUUD()] = std::unique_ptr<GenericServiceDependency>{dep};
return *dep;
@@ -269,52 +371,97 @@ celix::ServiceDependency<T,I>& celix::ComponentManager<T>::addServiceDependency(
template<typename T>
template<typename I>
-celix::ServiceDependency<T,I>* celix::ComponentManager<T>::findServiceDependency(const std::string& serviceDependencyUUID) {
- std::lock_guard<std::mutex> lck{serviceDependenciesMutex};
- auto it = serviceDependencies.find(serviceDependencyUUID);
- return it != serviceDependencies.end() ? nullptr : it->second.get();
+celix::ServiceDependency<T,I>& celix::ComponentManager<T>::findServiceDependency(const std::string& serviceDependencyUUID) {
+ static celix::ServiceDependency<T,I> invalid{ctx, []{}, []{return nullptr;}, []{} , []{}, false};
+ auto svcName = celix::typeName<I>();
+ auto found = findGenericServiceDependency(svcName, serviceDependencyUUID);
+ if (found) {
+ auto *ptr = static_cast<celix::ServiceDependency<T,I>*>(found.get());
+ return *ptr;
+ } else {
+ //note warning logged in findGenericServiceDependency
+ return invalid;
+ }
}
+template<typename T>
+std::shared_ptr<T> celix::ComponentManager<T>::getCmpInstance() const {
+ return inst;
+}
+template<typename T>
+template<typename I>
+celix::ProvidedService<T, I> &celix::ComponentManager<T>::addProvidedService() {
+ auto *provided = new celix::ProvidedService<T,I>{ctx, [this]{return getCmpInstance();}, [this]{updateServiceRegistrations();}};
+ std::lock_guard<std::mutex> lck{providedServicesMutex};
+ providedServices[provided->getUUID()] = std::shared_ptr<GenericProvidedService>{provided};
+ return *provided;
+}
+template<typename T>
+template<typename I>
+celix::ProvidedService<T, I> &celix::ComponentManager<T>::findProvidedService(const std::string &providedServiceUUID) {
+ static celix::ProvidedService<T,I> invalid{ctx, []{return nullptr;}, []{}, false};
+ auto svcName = celix::typeName<I>();
+ auto found = findGenericProvidedService(svcName, providedServiceUUID);
+ if (found) {
+ auto *ptr = static_cast<celix::ProvidedService<T,I>*>(found.get());
+ return *ptr;
+ } else {
+ //note warning logged in findGenericProvidedService
+ return invalid;
+ }
+}
+/**********************************************************************************************************************
+ ServiceDependency Implementation
+ **********************************************************************************************************************/
template<typename T, typename I>
celix::ServiceDependency<T,I>::ServiceDependency(
std::shared_ptr<celix::BundleContext> _ctx,
std::function<void()> _stateChangedCallback,
- std::function<std::shared_ptr<T>()> _getCmpInstance) : GenericServiceDependency{std::move(_ctx), std::move(_stateChangedCallback)}, getCmpInstance{_getCmpInstance} {};
+ std::function<std::shared_ptr<T>()> _getCmpInstance,
+ std::function<void()> _suspenseCallback,
+ std::function<void()> _resumeCallback,
+ bool isValid) :
+ GenericServiceDependency{std::move(_ctx),
+ celix::typeName<I>(),
+ std::move(_stateChangedCallback),
+ std::move(_suspenseCallback),
+ std::move(_resumeCallback),
+ isValid},
+ getCmpInstance{std::move(_getCmpInstance)} {};
template<typename T, typename I>
void celix::ServiceDependency<T,I>::setEnabled(bool enable) {
bool currentlyEnabled = isEnabled();
- std::vector<ServiceTracker> newTracker{};
- if (enable && !currentlyEnabled) {
- //enable
- ServiceTrackerOptions<I> opts{};
- opts.filter = this->filter;
- opts.setWithOwner = set;
- opts.addWithOwner = add;
- opts.removeWithOwner = rem;
- opts.updateWithOwner = [this](std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices) {
- if (this->update) {
- //TODO lock?
- this->update(std::move(rankedServices));
- }
- this->stateChangedCallback();
- };
- newTracker.emplace_back(ctx->trackServices(opts));
- std::lock_guard<std::mutex> lck{mutex};
- std::swap(tracker, newTracker);
-
- } else if (!enable and currentlyEnabled) {
- //disable
- std::lock_guard<std::mutex> lck{mutex};
- std::swap(tracker, newTracker/*empty*/);
+ {
+ std::vector<ServiceTracker> newTracker{};
+ if (enable && !currentlyEnabled) {
+ //enable
+ using namespace std::placeholders;
+ ServiceTrackerOptions<I> opts{};
+ opts.filter = this->filter;
+ opts.preServiceUpdateHook = [this]{preServiceUpdate();};
+ opts.postServiceUpdateHook = [this]{postServiceUpdate();};
+ opts.setWithOwner = std::bind(&ServiceDependency::setService, this, _1, _2, _3);
+ opts.addWithOwner = std::bind(&ServiceDependency::addService, this, _1, _2, _3);
+ opts.removeWithOwner = std::bind(&ServiceDependency::remService, this, _1, _2, _3);
+ opts.updateWithOwner = std::bind(&ServiceDependency::updateServices, this, _1);
+ newTracker.emplace_back(ctx->trackServices(opts));
+ std::lock_guard<std::mutex> lck{mutex};
+ std::swap(tracker, newTracker);
+
+ } else if (!enable and currentlyEnabled) {
+ //disable
+ std::lock_guard<std::mutex> lck{mutex};
+ std::swap(tracker, newTracker/*empty*/);
+ }
+ //newTracker out of scope -> RAII -> for disable clear current tracker, for enable empty newTracker
}
-
- //newTracker out of scope -> RAII -> for disable clear current tracker, for enable empty newTracker
+ stateChangedCallback();
}
template<typename T, typename I>
@@ -329,54 +476,28 @@ celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::disable() {
return *this;
}
-template<typename T, typename I>
-celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setFunctionCallbacks(
- std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> setArg,
- std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> addArg,
- std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> remArg,
- std::function<void(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices)> updateArg) {
-
- //TODO lock or disable?
- set = {};
- add = {};
- rem = {};
- update = {};
-
- if (setArg) {
- set = std::move(setArg);
- }
- if (addArg) {
- add = addArg;
- }
- if (remArg) {
- rem = remArg;
- }
- if (updateArg) {
- update = std::move(updateArg);
- }
- return *this;
-}
template<typename T, typename I>
celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setCallbacks(void (T::*setfp)(std::shared_ptr<I>)) {
- std::lock_guard<std::mutex> lck{mutex};
auto setFunc = [this, setfp](std::shared_ptr<I> svc, const celix::Properties &, const celix::IResourceBundle &) {
(getCmpInstance()->instance->*setfp)(svc);
};
- return setFunctionCallbacks(std::move(setFunc), {}, {}, {});
+ std::lock_guard<std::mutex> lck{callbacksMutex};
+ set = std::move(setFunc);
}
template<typename T, typename I>
celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setCallbacks(void (T::*addfp)(std::shared_ptr<I>), void (T::*remfp)(std::shared_ptr<I>)) {
- std::lock_guard<std::mutex> lck{mutex};
auto addFunc = [this, addfp](std::shared_ptr<I> svc, const celix::Properties &, const celix::IResourceBundle &) {
(getCmpInstance()->instance->*addfp)(svc);
};
auto remFunc = [this, remfp](std::shared_ptr<I> svc, const celix::Properties &, const celix::IResourceBundle &) {
(getCmpInstance()->instance->*remfp)(svc);
};
- return setFunctionCallbacks({}, std::move(addFunc), std::move(remFunc), {});
+ std::lock_guard<std::mutex> lck{callbacksMutex};
+ add = std::move(addFunc);
+ rem = std::move(remFunc);
}
template<typename T, typename I>
@@ -387,6 +508,13 @@ celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setFilter(const st
}
template<typename T, typename I>
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setStrategy(UpdateServiceStrategy s) {
+ std::lock_guard<std::mutex> lck{mutex};
+ strategy = s;
+ return *this;
+}
+
+template<typename T, typename I>
celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setRequired(bool r) {
std::lock_guard<std::mutex> lck{mutex};
required = r;
@@ -406,5 +534,101 @@ celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::extractUUID(std::s
return *this;
}
+template<typename T, typename I>
+void celix::ServiceDependency<T,I>::setService(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner) {
+ std::lock_guard<std::mutex> lck{callbacksMutex};
+ if (set) {
+ set(std::move(svc), props, owner);
+ }
+}
+
+template<typename T, typename I>
+void celix::ServiceDependency<T,I>::addService(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner) {
+ std::lock_guard<std::mutex> lck{callbacksMutex};
+ if (add) {
+ add(std::move(svc), props, owner);
+ }
+}
+
+template<typename T, typename I>
+void celix::ServiceDependency<T,I>::remService(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner) {
+ std::lock_guard<std::mutex> lck{callbacksMutex};
+ if (rem) {
+ rem(std::move(svc), props, owner);
+ }
+}
+
+template<typename T, typename I>
+void celix::ServiceDependency<T,I>::updateServices(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices) {
+ std::lock_guard<std::mutex> lck{callbacksMutex};
+ if (update) {
+ update(std::move(rankedServices));
+ }
+}
+
+/**********************************************************************************************************************
+ ProvidedService Implementation
+ **********************************************************************************************************************/
+
+template<typename T, typename I>
+celix::ProvidedService<T,I>::ProvidedService(
+ std::shared_ptr<celix::BundleContext> ctx,
+ std::function<std::shared_ptr<T>()> _getCmpInstanceCallback,
+ std::function<void()> updateServiceRegistrationsCallback,
+ bool valid) :
+ GenericProvidedService{ctx, celix::serviceName<I>(), updateServiceRegistrationsCallback, valid}, getcmpInstanceCallback{_getCmpInstanceCallback} {}
+
+template<typename T, typename I>
+void celix::ProvidedService<T, I>::registerService() {
+ if (isServiceRegistered()) {
+ return; //already registered. note that also means a disable -> enable is needed to update a provided service
+ }
+ auto inst = getcmpInstanceCallback();
+
+ //TODO try to improve compile error whent this happens
+ std::shared_ptr<I> svcPtr = inst; //NOTE T should implement (inherit) I
+
+ std::vector<ServiceRegistration> newReg{};
+ newReg.emplace_back(ctx->registerService<I>(inst, properties));
+ std::lock_guard<std::mutex> lck{mutex};
+ std::swap(newReg, registration);
+}
+
+template<typename T, typename I>
+celix::ProvidedService<T,I>& celix::ProvidedService<T, I>::extractUUID(std::string &out) {
+ out = uuid;
+ return *this;
+}
+
+template<typename T, typename I>
+celix::ProvidedService<T,I>& celix::ProvidedService<T, I>::enable() {
+ setEnabled(true);
+ return *this;
+}
+
+template<typename T, typename I>
+celix::ProvidedService<T,I>& celix::ProvidedService<T, I>::disable() {
+ setEnabled(false);
+ return *this;
+}
+
+template<typename T, typename I>
+celix::ProvidedService<T,I>& celix::ProvidedService<T, I>::setProperties(const celix::Properties& p) {
+ properties = p;
+ return *this;
+}
+
+template<typename T, typename I>
+celix::ProvidedService<T,I>& celix::ProvidedService<T, I>::setProperties(celix::Properties p) {
+ properties = std::move(p);
+ return *this;
+}
+
+template<typename T, typename I>
+celix::ProvidedService<T,I>& celix::ProvidedService<T, I>::addProperty(const std::string &name, const std::string &val) {
+ properties[name] = val;
+ return *this;
+}
+
#endif //CXX_CELIX_COMPONENT_MANAGER_H
diff --git a/libs/framework_cxx/src/BundleContext.cc b/libs/framework_cxx/src/BundleContext.cc
index 045f2e3..0d9e50d 100644
--- a/libs/framework_cxx/src/BundleContext.cc
+++ b/libs/framework_cxx/src/BundleContext.cc
@@ -26,7 +26,7 @@ namespace celix {
public:
Impl(std::shared_ptr<celix::IBundle> _bnd) :
bnd{std::move(_bnd)},
- reg{&bnd->framework().registry(celix::C_AND_CXX_LANG_REG)} {}
+ reg{&bnd->framework().registry("main")} {}
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
diff --git a/libs/framework_cxx/src/ComponentManager.cc b/libs/framework_cxx/src/ComponentManager.cc
index 07e3bc0..74af968 100644
--- a/libs/framework_cxx/src/ComponentManager.cc
+++ b/libs/framework_cxx/src/ComponentManager.cc
@@ -38,10 +38,18 @@ static std::string genUUID() {
celix::GenericServiceDependency::GenericServiceDependency(
std::shared_ptr<celix::BundleContext> _ctx,
- std::function<void()> _stateChangedCallback) :
+ std::string _svcName,
+ std::function<void()> _stateChangedCallback,
+ std::function<void()> _suspendCallback,
+ std::function<void()> _resumeCallback,
+ bool _isValid) :
ctx{std::move(_ctx)},
+ svcName{std::move(_svcName)},
stateChangedCallback{std::move(_stateChangedCallback)},
- uuid{genUUID()} {}
+ suspenseCallback{std::move(_suspendCallback)},
+ resumeCallback{std::move(_resumeCallback)},
+ uuid{genUUID()},
+ valid{_isValid} {}
bool celix::GenericServiceDependency::isResolved() const {
@@ -58,7 +66,7 @@ celix::Cardinality celix::GenericServiceDependency::getCardinality() const {
return cardinality;
}
-bool celix::GenericServiceDependency::getRequired() const {
+bool celix::GenericServiceDependency::isRequired() const {
std::lock_guard<std::mutex> lck{mutex};
return required;
}
@@ -68,16 +76,42 @@ const std::string &celix::GenericServiceDependency::getFilter() const {
return filter;
}
-std::string celix::GenericServiceDependency::getUUD() {
+const std::string& celix::GenericServiceDependency::getUUD() const {
return uuid;
}
-bool celix::GenericServiceDependency::isEnabled() {
+bool celix::GenericServiceDependency::isEnabled() const {
std::lock_guard<std::mutex> lck{mutex};
return !tracker.empty();
}
-celix::ComponentState celix::GenericComponentManager::getState() const {
+celix::UpdateServiceStrategy celix::GenericServiceDependency::getStrategy() const {
+ std::lock_guard<std::mutex> lck{mutex};
+ return strategy;
+}
+
+const std::string &celix::GenericServiceDependency::getSvcName() const {
+ return svcName;
+}
+
+bool celix::GenericServiceDependency::isValid() const {
+ return valid;
+}
+
+void celix::GenericServiceDependency::preServiceUpdate() {
+ if (getStrategy() == UpdateServiceStrategy::Suspense) {
+ suspenseCallback(); //note resume will be done in the updateServices (last called)
+ }
+}
+
+void celix::GenericServiceDependency::postServiceUpdate() {
+ if (getStrategy() == UpdateServiceStrategy::Suspense) {
+ resumeCallback(); //note suspend call is done in the setService (first called)
+ }
+ this->stateChangedCallback();
+}
+
+celix::ComponentManagerState celix::GenericComponentManager:: getState() const {
std::lock_guard<std::mutex> lck{stateMutex};
return state;
}
@@ -88,9 +122,12 @@ bool celix::GenericComponentManager::isEnabled() const {
}
bool celix::GenericComponentManager::isResolved() const {
+ if (!isEnabled()) {
+ return false; //not enabled is not resolved!
+ }
std::lock_guard<std::mutex> lck{stateMutex};
for (auto &pair : serviceDependencies) {
- if (!pair.second->isResolved()) {
+ if (pair.second->isEnabled() && !pair.second->isResolved()) {
return false;
}
}
@@ -98,32 +135,47 @@ bool celix::GenericComponentManager::isResolved() const {
}
void celix::GenericComponentManager::setEnabled(bool e) {
- {
- std::lock_guard<std::mutex> lck{stateMutex};
- enabled = e;
- }
std::vector<std::shared_ptr<GenericServiceDependency>> deps{};
+ std::vector<std::shared_ptr<GenericProvidedService>> provides{};
{
std::lock_guard<std::mutex> lck{serviceDependenciesMutex};
for (auto &pair : serviceDependencies) {
deps.push_back(pair.second);
}
}
-
+ {
+ std::lock_guard<std::mutex> lck{providedServicesMutex};
+ for (auto &pair : providedServices) {
+ provides.push_back(pair.second);
+ }
+ }
//NOTE updating outside of the lock
- for (auto &dep : deps) {
+ for (auto& dep : deps) {
dep->setEnabled(e);
}
+ for (auto& provide : provides) {
+ provide->setEnabled(e);
+ }
+
+
+ {
+ std::lock_guard<std::mutex> lck{stateMutex};
+ enabled = e;
+ }
+
updateState();
}
void celix::GenericComponentManager::updateState() {
- bool allDependenciesResolved = true;
+ bool allRequiredDependenciesResolved = true; /*all required and enabled dependencies resolved? */
{
std::lock_guard<std::mutex> lck{serviceDependenciesMutex};
for (auto &pair : serviceDependencies) {
- if (!pair.second->isResolved()) {
- allDependenciesResolved = false;
+ auto enabled = pair.second->isEnabled();
+ auto required = pair.second->isRequired();
+ auto resolved = pair.second->isResolved();
+ if (enabled && required && !resolved) {
+ allRequiredDependenciesResolved = false;
break;
}
}
@@ -131,13 +183,13 @@ void celix::GenericComponentManager::updateState() {
{
std::lock_guard<std::mutex> lck{stateMutex};
- ComponentState currentState = state;
- ComponentState targetState = ComponentState::Disabled;
+ ComponentManagerState currentState = state;
+ ComponentManagerState targetState = ComponentManagerState::Disabled;
- if (enabled && allDependenciesResolved) {
- targetState = ComponentState::Started;
- } else if (enabled) /*not all dep resolved*/ {
- targetState = initialized ? ComponentState::Initialized : ComponentState::Uninitialized;
+ if (enabled && allRequiredDependenciesResolved) {
+ targetState = ComponentManagerState::ComponentStarted;
+ } else if (enabled) /*not all required dep resolved*/ {
+ targetState = initialized ? ComponentManagerState::ComponentInitialized : ComponentManagerState::ComponentUninitialized;
}
if (currentState != targetState) {
@@ -148,8 +200,8 @@ void celix::GenericComponentManager::updateState() {
}
void celix::GenericComponentManager::transition() {
- ComponentState currentState;
- ComponentState targetState;
+ ComponentManagerState currentState;
+ ComponentManagerState targetState;
{
std::lock_guard<std::mutex> lck{stateMutex};
@@ -162,94 +214,69 @@ void celix::GenericComponentManager::transition() {
targetState = pair.second;
}
- DLOG(INFO) << "Transition for " << name << " from " << currentState << " to " << targetState;
-
- //TODO note callbacks are called outside of mutex. make local copies or ensure that callback can only be changed with disabled component managers ...
+ DLOG(INFO) << "Transition " << *this << " from " << currentState << " to " << targetState;
- if (targetState == ComponentState::Disabled) {
- switch (currentState) {
- case celix::ComponentState::Disabled:
+ if (currentState == ComponentManagerState::Disabled) {
+ switch (targetState) {
+ case celix::ComponentManagerState::Disabled:
//nop
break;
- case celix::ComponentState::Uninitialized:
- //TODO may disable callback to cmp
- setState(ComponentState::Disabled);
- break;
- case celix::ComponentState::Initialized:;
- deinit();
- setInitialized(false);
- setState(ComponentState::Uninitialized);
- break;
- case celix::ComponentState::Started:
- stop();
- setState(ComponentState::Initialized);
+ default:
+ setState(ComponentManagerState::ComponentUninitialized);
break;
}
- } else if (targetState == ComponentState::Uninitialized) {
- switch (currentState) {
- case celix::ComponentState::Disabled:
- //TODO maybe enable callback
- setState(ComponentState::Uninitialized);
+ } else if (currentState == ComponentManagerState::ComponentUninitialized) {
+ switch (targetState) {
+ case celix::ComponentManagerState::Disabled:
+ setState(ComponentManagerState::Disabled);
break;
- case celix::ComponentState::Uninitialized:
+ case celix::ComponentManagerState::ComponentUninitialized:
//nop
break;
- case celix::ComponentState::Initialized:
- deinit();
- setInitialized(false);
- setState(ComponentState::Uninitialized);
- break;
- case celix::ComponentState::Started:
- stop();
- setState(ComponentState::Initialized);
+ default: //targetState initialized of started
+ initCmp();
+ setInitialized(true);
+ setState(ComponentManagerState::ComponentInitialized);
break;
}
- } else if (targetState == ComponentState::Initialized) {
- switch (currentState) {
- case celix::ComponentState::Disabled:
- //TODO maybe enabled callback
- setState(ComponentState::Uninitialized);
+ } else if (currentState == ComponentManagerState::ComponentInitialized) {
+ switch (targetState) {
+ case celix::ComponentManagerState::Disabled:
+ deinitCmp();
+ setInitialized(false);
+ setState(ComponentManagerState::ComponentUninitialized);
break;
- case celix::ComponentState::Uninitialized:
- init();
- setInitialized(true);
- setState(ComponentState::Initialized);
+ case celix::ComponentManagerState::ComponentUninitialized:
+ deinitCmp();
+ setInitialized(false);
+ setState(ComponentManagerState::ComponentUninitialized);
break;
- case celix::ComponentState::Initialized:
+ case celix::ComponentManagerState::ComponentInitialized:
//nop
break;
- case celix::ComponentState::Started:
- stop();
- setState(ComponentState ::Initialized);
+ case celix::ComponentManagerState::ComponentStarted:
+ startCmp();
+ setState(ComponentManagerState ::ComponentStarted);
+ updateServiceRegistrations();
break;
}
- } else if (targetState == ComponentState::Started) {
- switch (currentState) {
- case celix::ComponentState::Disabled:
- //TODO maybe enabled callback
- setState(ComponentState::Uninitialized);
- break;
- case celix::ComponentState::Uninitialized:
- init();
- setInitialized(true);
- setState(ComponentState::Initialized);
- break;
- case celix::ComponentState::Initialized:
- start();
- setState(ComponentState::Started);
- break;
- case celix::ComponentState::Started:
+ } else if (currentState == ComponentManagerState::ComponentStarted) {
+ switch (targetState) {
+ case celix::ComponentManagerState::ComponentStarted:
//nop
break;
+ default:
+ stopCmp();
+ setState(ComponentManagerState::ComponentInitialized);
+ updateServiceRegistrations(); //TODO before stop?
+ break;
}
- } else {
- LOG(ERROR) << "Unexpected target state: " << targetState;
}
updateState();
}
-void celix::GenericComponentManager::setState(ComponentState s) {
+void celix::GenericComponentManager::setState(ComponentManagerState s) {
std::lock_guard<std::mutex> lck{stateMutex};
state = s;
}
@@ -263,13 +290,41 @@ celix::GenericComponentManager::GenericComponentManager(std::shared_ptr<celix::B
}
void celix::GenericComponentManager::removeServiceDependency(const std::string& serviceDependencyUUID) {
- std::lock_guard<std::mutex> lck{stateMutex};
- auto it = serviceDependencies.find(serviceDependencyUUID);
- if (it != serviceDependencies.end()) {
- serviceDependencies.erase(it);
- } else {
- LOG(WARNING) << "Cannot find service dependency with uuid " << serviceDependencyUUID << " in component manager " << name << " with uuid " << uuid << ".";
+ std::shared_ptr<GenericServiceDependency> removed{};
+ {
+ std::lock_guard<std::mutex> lck{serviceDependenciesMutex};
+ auto it = serviceDependencies.find(serviceDependencyUUID);
+ if (it != serviceDependencies.end()) {
+ removed = it->second;
+ serviceDependencies.erase(it);
+ } else {
+ LOG(WARNING) << "Cannot find service dependency with uuid " << serviceDependencyUUID
+ << " in component manager " << name << " with uuid " << uuid << ".";
+ }
+ }
+ if (removed) {
+ removed->setEnabled(false);
+ }
+ //NOTE removed out of scope -> RAII will cleanup
+}
+
+void celix::GenericComponentManager::removeProvideService(const std::string& provideServiceUUID) {
+ std::shared_ptr<GenericProvidedService> removed{};
+ {
+ std::lock_guard<std::mutex> lck{providedServicesMutex};
+ auto it = providedServices.find(provideServiceUUID);
+ if (it != providedServices.end()) {
+ removed = it->second;
+ providedServices.erase(it);
+ } else {
+ LOG(WARNING) << "Cannot find provided service with uuid " << provideServiceUUID
+ << " in component manager " << name << " with uuid " << uuid << ".";
+ }
}
+ if (removed) {
+ removed->setEnabled(false);
+ }
+ //NOTE removed out of scope -> RAII will cleanup
}
std::string celix::GenericComponentManager::getName() const {
@@ -281,23 +336,195 @@ void celix::GenericComponentManager::setInitialized(bool i) {
initialized = i;
}
+std::shared_ptr<celix::GenericServiceDependency>
+celix::GenericComponentManager::findGenericServiceDependency(const std::string &svcName,
+ const std::string &svcDepUUID) {
+ std::lock_guard<std::mutex> lck{serviceDependenciesMutex};
+ auto it = serviceDependencies.find(svcDepUUID);
+ if (it != serviceDependencies.end()) {
+ if (it->second->getSvcName() == svcName) {
+ return it->second;
+ } else {
+ LOG(WARNING) << "Requested svc name has svc name " << it->second->getSvcName() << " instead of the requested " << svcName;
+ return nullptr;
+ }
+ } else {
+ LOG(WARNING) << "Cmp Manager (" << uuid << ") does not have a service dependency with uuid " << svcDepUUID << "; returning an invalid GenericServiceDependency";
+ return nullptr;
+ }
+}
+
+std::size_t celix::GenericComponentManager::getSuspendedCount() const {
+ std::lock_guard<std::mutex> lck{stateMutex};
+ return suspendedCount;
+}
+
+void celix::GenericComponentManager::suspense() {
+ bool changedSuspended = false;
+ {
+ std::lock_guard<std::mutex> lck{stateMutex};
+ if (!suspended) {
+ suspended = true;
+ changedSuspended = true;
+ }
+ }
+ if (changedSuspended) {
+ transition();
+ std::lock_guard<std::mutex> lck{stateMutex};
+ suspendedCount += 1;
+ DLOG(INFO) << "Suspended " << *this;
+ }
+}
+
+void celix::GenericComponentManager::resume() {
+ bool changedSuspended = false;
+ {
+ std::lock_guard<std::mutex> lck{stateMutex};
+ if (suspended) {
+ suspended = false;
+ changedSuspended = true;
+ }
+ }
+ if (changedSuspended) {
+ transition();
+ DLOG(INFO) << "Resumed " << *this;
+ }
+}
+
+void celix::GenericComponentManager::updateServiceRegistrations() {
+ std::vector<std::shared_ptr<GenericProvidedService>> toRegisterServices{};
+ std::vector<std::shared_ptr<GenericProvidedService>> toUnregisterServices{};
+ if (getState() == ComponentManagerState::ComponentStarted) {
+ std::lock_guard<std::mutex> lck{providedServicesMutex};
+ for (auto &pair : providedServices) {
+ auto enabled = pair.second->isEnabled();
+ auto registered = pair.second->isServiceRegistered();
+ if (enabled && !registered) {
+ toRegisterServices.push_back(pair.second);
+ } else if (registered && !enabled) {
+ toUnregisterServices.push_back(pair.second);
+ }
+ }
+ } else {
+ std::lock_guard<std::mutex> lck{providedServicesMutex};
+ for (auto &pair : providedServices) {
+ auto registered = pair.second->isServiceRegistered();
+ if (registered) {
+ toUnregisterServices.push_back(pair.second);
+ }
+ }
+ }
+
+ //note (un)registering service outside of mutex
+ for (auto& provide : toRegisterServices) {
+ provide->registerService();
+ }
+ for (auto& provide : toUnregisterServices) {
+ provide->unregisterService();
+ }
+}
+
+std::shared_ptr<celix::GenericProvidedService>
+celix::GenericComponentManager::findGenericProvidedService(const std::string &svcName,
+ const std::string &providedServiceUUID) {
+ std::lock_guard<std::mutex> lck{providedServicesMutex};
+ auto it = providedServices.find(providedServiceUUID);
+ if (it != providedServices.end()) {
+ if (it->second->getServiceName() == svcName) {
+ return it->second;
+ } else {
+ LOG(WARNING) << "Requested svc name has svc name " << it->second->getServiceName() << " instead of the requested " << svcName;
+ return nullptr;
+ }
+ } else {
+ LOG(WARNING) << "Cmp Manager (" << uuid << ") does not have a provided service with uuid " << providedServiceUUID << "; returning an invalid GenericProvidedService";
+ return nullptr;
+ }
+}
+
+std::size_t celix::GenericComponentManager::nrOfServiceDependencies() {
+ std::lock_guard<std::mutex> lck{serviceDependenciesMutex};
+ return serviceDependencies.size();
+}
+
+std::size_t celix::GenericComponentManager::nrOfProvidedServices() {
+ std::lock_guard<std::mutex> lck{providedServicesMutex};
+ return providedServices.size();
+}
-std::ostream& operator<< (std::ostream& out, celix::ComponentState state)
+std::ostream& operator<< (std::ostream& out, const celix::GenericComponentManager& mng) {
+ out << "ComponentManager[name=" << mng.getName() << ", uuid=" << mng.getUUD() << "]";
+ return out;
+}
+
+
+std::ostream& operator<< (std::ostream& out, celix::ComponentManagerState state)
{
switch (state) {
- case celix::ComponentState::Disabled:
+ case celix::ComponentManagerState::Disabled:
out << "Disabled";
break;
- case celix::ComponentState::Uninitialized:
- out << "Uninitialized";
+ case celix::ComponentManagerState::ComponentUninitialized:
+ out << "ComponentUninitialized";
break;
- case celix::ComponentState::Initialized:
- out << "Initialized";
+ case celix::ComponentManagerState::ComponentInitialized:
+ out << "ComponentInitialized";
break;
- case celix::ComponentState::Started:
- out << "Started";
+ case celix::ComponentManagerState::ComponentStarted:
+ out << "ComponentStarted";
break;
}
return out;
}
+bool celix::GenericProvidedService::isEnabled() const {
+ std::lock_guard<std::mutex> lck{mutex};
+ return enabled;
+}
+
+const std::string &celix::GenericProvidedService::getUUID() const {
+ return uuid;
+}
+
+const std::string &celix::GenericProvidedService::getServiceName() const {
+ return svcName;
+}
+
+bool celix::GenericProvidedService::isValid() const {
+ return valid;
+}
+
+celix::GenericProvidedService::GenericProvidedService(
+ std::shared_ptr<celix::BundleContext> _ctx,
+ std::string _svcName,
+ std::function<void()> _updateServiceRegistrationsCallback,
+ bool _valid) :
+ ctx{std::move(_ctx)},
+ uuid{genUUID()},
+ svcName{std::move(_svcName)},
+ updateServiceRegistrationsCallback{std::move(_updateServiceRegistrationsCallback)},
+ valid{_valid} {
+
+}
+
+void celix::GenericProvidedService::setEnabled(bool e) {
+ {
+ std::lock_guard<std::mutex> lck{mutex};
+ enabled = e;
+ }
+ updateServiceRegistrationsCallback();
+}
+
+void celix::GenericProvidedService::unregisterService() {
+ std::vector<ServiceRegistration> unregister{};
+ {
+ std::lock_guard<std::mutex> lck{mutex};
+ std::swap(registration, unregister);
+ }
+ //NOTE RAII will ensure unregister
+}
+
+bool celix::GenericProvidedService::isServiceRegistered() {
+ std::lock_guard<std::mutex> lck{mutex};
+ return registration.size() > 0;
+}
diff --git a/libs/registry/include/celix/Constants.h b/libs/registry/include/celix/Constants.h
index 96f6326..d3d5cf8 100644
--- a/libs/registry/include/celix/Constants.h
+++ b/libs/registry/include/celix/Constants.h
@@ -24,15 +24,13 @@
namespace celix {
//NOTE manually aligned with celix_constants.h
- static constexpr const char *const SERVICE_NAME = "SERVICE_NAME";
- static constexpr const char *const SERVICE_ID = "SERVICE_ID";
- static constexpr const char *const SERVICE_RANKING = "SERVICE_RANKING";
- static constexpr const char *const SERVICE_BUNDLE = "SERVICE_BUNDLE";
+ static constexpr const char *const SERVICE_NAME = "service.name";
+ static constexpr const char *const SERVICE_ID = "service.id";
+ static constexpr const char *const SERVICE_RANKING = "service.ranking";
+ static constexpr const char *const SERVICE_BUNDLE = "service.bundle";
static constexpr const char *const FRAMEWORK_UUID = "framework.uuid";
- static constexpr const char *const C_AND_CXX_LANG_REG = "C/C++";
-
static constexpr const char *const MANIFEST_BUNDLE_SYMBOLIC_NAME = "Bundle-SymbolicName";
static constexpr const char *const MANIFEST_BUNDLE_NAME = "Bundle-Name";
static constexpr const char *const MANIFEST_BUNDLE_VERSION = "Bundle-Version";
diff --git a/libs/registry/include/celix/ServiceRegistry.h b/libs/registry/include/celix/ServiceRegistry.h
index 4457d0e..cc9e704 100644
--- a/libs/registry/include/celix/ServiceRegistry.h
+++ b/libs/registry/include/celix/ServiceRegistry.h
@@ -89,6 +89,13 @@ namespace celix {
std::function<void(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices)> updateWithOwner{};
//TODO lock free update calls atomics, rcu, hazard pointers ??
+
+
+ /**
+ * pre and post update hooks, can be used if a trigger is needed before or after an service update.
+ */
+ std::function<void()> preServiceUpdateHook{};
+ std::function<void()> postServiceUpdateHook{};
};
//RAII service tracker: out of scope -> stop tracker
@@ -130,11 +137,7 @@ namespace celix {
const std::string& name() const;
template<typename I>
- celix::ServiceRegistration registerService(I &svc, celix::Properties props = {}, std::shared_ptr<const celix::IResourceBundle> owner = {}) {
- auto svcName = celix::serviceName<I>();
- auto voidSvc = std::shared_ptr<void>(static_cast<void*>(&svc), [](void*){/*nop*/}); //transform to std::shared_ptr to minimize the underlining impl needed.
- return registerService(svcName, std::move(voidSvc), std::move(props), std::move(owner));
- }
+ celix::ServiceRegistration registerService(I &&svc, celix::Properties props = {}, std::shared_ptr<const celix::IResourceBundle> owner = {});
template<typename I>
celix::ServiceRegistration registerService(std::shared_ptr<I> svc, celix::Properties props = {}, std::shared_ptr<const celix::IResourceBundle> owner = {}) {
@@ -400,6 +403,9 @@ namespace celix {
}
+std::ostream& operator<<(std::ostream &out, const celix::ServiceRegistration& serviceRegistration);
+
+
template<typename F>
inline celix::ServiceRegistration celix::ServiceRegistry::registerFunctionService(const std::string &functionName, F&& func, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) {
class FunctionServiceFactory : public celix::IServiceFactory<void> {
@@ -498,11 +504,11 @@ inline celix::ServiceTracker celix::ServiceRegistry::trackServices(std::string s
ServiceTrackerOptions<void> opts{};
opts.filter = std::move(options.filter);
- if (options.set != nullptr) {
- auto set = std::move(options.set);
- opts.set = [set](std::shared_ptr<void> svc){
+ if (options.setWithOwner != nullptr) {
+ auto set = std::move(options.setWithOwner);
+ opts.setWithOwner = [set](std::shared_ptr<void> svc, const celix::Properties &props, const celix::IResourceBundle &owner){
auto typedSvc = std::static_pointer_cast<I>(svc);
- set(typedSvc);
+ set(typedSvc, props, owner);
};
}
if (options.setWithProperties != nullptr) {
@@ -512,19 +518,19 @@ inline celix::ServiceTracker celix::ServiceRegistry::trackServices(std::string s
set(typedSvc, props);
};
}
- if (options.setWithOwner != nullptr) {
- auto set = std::move(options.setWithOwner);
- opts.setWithOwner = [set](std::shared_ptr<void> svc, const celix::Properties &props, const celix::IResourceBundle &owner){
+ if (options.set != nullptr) {
+ auto set = std::move(options.set);
+ opts.set = [set](std::shared_ptr<void> svc){
auto typedSvc = std::static_pointer_cast<I>(svc);
- set(typedSvc, props, owner);
+ set(typedSvc);
};
}
- if (options.add != nullptr) {
- auto add = std::move(options.add);
- opts.add = [add](std::shared_ptr<void> svc) {
+ if (options.addWithOwner != nullptr) {
+ auto add = std::move(options.addWithOwner);
+ opts.addWithOwner = [add](std::shared_ptr<void> svc, const celix::Properties &props, const celix::IResourceBundle &bnd) {
auto typedSvc = std::static_pointer_cast<I>(svc);
- add(typedSvc);
+ add(typedSvc, props, bnd);
};
}
if (options.addWithProperties != nullptr) {
@@ -534,19 +540,19 @@ inline celix::ServiceTracker celix::ServiceRegistry::trackServices(std::string s
add(typedSvc, props);
};
}
- if (options.addWithOwner != nullptr) {
- auto add = std::move(options.addWithOwner);
- opts.addWithOwner = [add](std::shared_ptr<void> svc, const celix::Properties &props, const celix::IResourceBundle &bnd) {
+ if (options.add != nullptr) {
+ auto add = std::move(options.add);
+ opts.add = [add](std::shared_ptr<void> svc) {
auto typedSvc = std::static_pointer_cast<I>(svc);
- add(typedSvc, props, bnd);
+ add(typedSvc);
};
}
- if (options.remove != nullptr) {
- auto rem = std::move(options.remove);
- opts.remove = [rem](std::shared_ptr<void> svc) {
+ if (options.removeWithOwner != nullptr) {
+ auto rem = std::move(options.removeWithOwner);
+ opts.removeWithOwner = [rem](std::shared_ptr<void> svc, const celix::Properties &props, const celix::IResourceBundle &bnd) {
auto typedSvc = std::static_pointer_cast<I>(svc);
- rem(typedSvc);
+ rem(typedSvc, props, bnd);
};
}
if (options.removeWithProperties != nullptr) {
@@ -556,22 +562,22 @@ inline celix::ServiceTracker celix::ServiceRegistry::trackServices(std::string s
rem(typedSvc, props);
};
}
- if (options.removeWithOwner != nullptr) {
- auto rem = std::move(options.removeWithOwner);
- opts.removeWithOwner = [rem](std::shared_ptr<void> svc, const celix::Properties &props, const celix::IResourceBundle &bnd) {
+ if (options.remove != nullptr) {
+ auto rem = std::move(options.remove);
+ opts.remove = [rem](std::shared_ptr<void> svc) {
auto typedSvc = std::static_pointer_cast<I>(svc);
- rem(typedSvc, props, bnd);
+ rem(typedSvc);
};
}
- if (options.update != nullptr) {
- auto update = std::move(options.update);
- opts.update = [update](std::vector<std::shared_ptr<void>> rankedServices) {
- std::vector<std::shared_ptr<I>> typedServices{};
+ if (options.updateWithOwner != nullptr) {
+ auto update = std::move(options.updateWithOwner);
+ opts.updateWithOwner = [update](std::vector<std::tuple<std::shared_ptr<void>, const celix::Properties *, const celix::IResourceBundle*>> rankedServices) {
+ std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle*>> typedServices{};
typedServices.reserve(rankedServices.size());
- for (auto &svc : rankedServices) {
- auto typedSvc = std::static_pointer_cast<I>(svc);
- typedServices.push_back(typedSvc);
+ for (auto &tuple : rankedServices) {
+ auto typedSvc = std::static_pointer_cast<I>(std::get<0>(tuple));
+ typedServices.push_back(std::make_tuple(typedSvc, std::get<1>(tuple), std::get<2>(tuple)));
}
update(std::move(typedServices));
};
@@ -588,19 +594,26 @@ inline celix::ServiceTracker celix::ServiceRegistry::trackServices(std::string s
update(std::move(typedServices));
};
}
- if (options.updateWithOwner != nullptr) {
- auto update = std::move(options.updateWithOwner);
- opts.updateWithOwner = [update](std::vector<std::tuple<std::shared_ptr<void>, const celix::Properties *, const celix::IResourceBundle*>> rankedServices) {
- std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle*>> typedServices{};
+ if (options.update != nullptr) {
+ auto update = std::move(options.update);
+ opts.update = [update](std::vector<std::shared_ptr<void>> rankedServices) {
+ std::vector<std::shared_ptr<I>> typedServices{};
typedServices.reserve(rankedServices.size());
- for (auto &tuple : rankedServices) {
- auto typedSvc = std::static_pointer_cast<I>(std::get<0>(tuple));
- typedServices.push_back(std::make_tuple(typedSvc, std::get<1>(tuple), std::get<2>(tuple)));
+ for (auto &svc : rankedServices) {
+ auto typedSvc = std::static_pointer_cast<I>(svc);
+ typedServices.push_back(typedSvc);
}
update(std::move(typedServices));
};
}
+ if (options.preServiceUpdateHook) {
+ opts.preServiceUpdateHook = std::move(options.preServiceUpdateHook);
+ }
+ if (options.postServiceUpdateHook) {
+ opts.postServiceUpdateHook = std::move(options.postServiceUpdateHook);
+ }
+
return trackAnyServices(std::move(svcName), std::move(opts), std::move(requester));
}
diff --git a/libs/registry/src/ServiceRegistry.cc b/libs/registry/src/ServiceRegistry.cc
index a8cf2f5..c6e41a9 100644
--- a/libs/registry/src/ServiceRegistry.cc
+++ b/libs/registry/src/ServiceRegistry.cc
@@ -28,6 +28,8 @@
#include <glog/logging.h>
#include <assert.h>
+#include <celix/ServiceRegistry.h>
+
#include "celix/Constants.h"
#include "celix/ServiceRegistry.h"
@@ -196,9 +198,15 @@ namespace {
}
//call callbacks
+ if (opts.preServiceUpdateHook) {
+ opts.preServiceUpdateHook();
+ }
callSetCallbacks();
callAddRemoveCallbacks(entry, svc, true);
callUpdateCallbacks();
+ if (opts.postServiceUpdateHook) {
+ opts.postServiceUpdateHook();
+ }
}
void remMatch(const std::shared_ptr<const SvcEntry> &entry) {
@@ -211,26 +219,32 @@ namespace {
}
//call callbacks
+ if (opts.preServiceUpdateHook) {
+ opts.preServiceUpdateHook();
+ }
callSetCallbacks(); //note also removed highest if that was set to this svc
callAddRemoveCallbacks(entry, svc, false);
callUpdateCallbacks();
-
+ if (opts.postServiceUpdateHook) {
+ opts.postServiceUpdateHook();
+ }
//note sync will be done on the SvcEntry usage, which is controlled by the tracker svc shared ptr
}
- void callAddRemoveCallbacks(const std::shared_ptr<const SvcEntry> &entry, std::shared_ptr<void> &svc, bool add) {
- auto &update = add ? opts.add : opts.remove;
- auto &updateWithProps = add ? opts.addWithProperties : opts.removeWithProperties;
- auto &updateWithOwner = add ? opts.addWithOwner : opts.removeWithOwner;
- if (update) {
- update(svc);
+ void callAddRemoveCallbacks(const std::shared_ptr<const SvcEntry>& entry, std::shared_ptr<void>& svc, bool add) {
+ auto& update = add ? opts.add : opts.remove;
+ auto& updateWithProps = add ? opts.addWithProperties : opts.removeWithProperties;
+ auto& updateWithOwner = add ? opts.addWithOwner : opts.removeWithOwner;
+ //The more explicit callbacks are called first (i.e first WithOwner)
+ if (updateWithOwner) {
+ updateWithOwner(svc, entry->props, *entry->owner);
}
if (updateWithProps) {
updateWithProps(svc, entry->props);
}
- if (updateWithOwner) {
- updateWithOwner(svc, entry->props, *entry->owner);
+ if (update) {
+ update(svc);
}
}
@@ -254,14 +268,19 @@ namespace {
//TODO race condition. highest can be updated because lock is released.
if (highestUpdated) {
- if (opts.set) {
- opts.set(currentHighestSvc); //note can be nullptr
+ static celix::Properties emptyProps{};
+ static EmptyBundle emptyOwner{};
+ //The more explicit callbacks are called first (i.e first WithOwner)
+ if (opts.setWithOwner) {
+ opts.setWithOwner(currentHighestSvc,
+ currentHighestSvc == nullptr ? emptyProps : currentHighestSvcEntry->props,
+ currentHighestSvc == nullptr ? emptyOwner : *currentHighestSvcEntry->owner);
}
if (opts.setWithProperties) {
- opts.setWithProperties(currentHighestSvc, currentHighestSvcEntry->props);
+ opts.setWithProperties(currentHighestSvc, currentHighestSvc == nullptr ? emptyProps : currentHighestSvcEntry->props);
}
- if (opts.setWithOwner) {
- opts.setWithOwner(currentHighestSvc, currentHighestSvcEntry->props, *currentHighestSvcEntry->owner);
+ if (opts.set) {
+ opts.set(currentHighestSvc); //note can be nullptr
}
}
}
@@ -276,12 +295,9 @@ namespace {
rankedServices.push_back(std::make_tuple(entry.second, &entry.first->props, entry.first->owner.get()));
}
}
- if (opts.update) {
- std::vector<std::shared_ptr<void>> rnk{};
- for (auto &tuple : rankedServices) {
- rnk.push_back(std::get<0>(tuple));
- }
- opts.update(std::move(rnk));
+ //The more explicit callbacks are called first (i.e first WithOwner)
+ if (opts.updateWithOwner) {
+ opts.updateWithOwner(rankedServices);
}
if (opts.updateWithProperties) {
std::vector<std::tuple<std::shared_ptr<void>, const celix::Properties*>> rnk{};
@@ -290,8 +306,12 @@ namespace {
}
opts.updateWithProperties(std::move(rnk));
}
- if (opts.updateWithOwner) {
- opts.updateWithOwner(std::move(rankedServices));
+ if (opts.update) {
+ std::vector<std::shared_ptr<void>> rnk{};
+ for (auto &tuple : rankedServices) {
+ rnk.push_back(std::get<0>(tuple));
+ }
+ opts.update(std::move(rnk));
}
}
@@ -353,7 +373,7 @@ public:
class celix::ServiceRegistry::Impl {
public:
- Impl(std::string _regName) : regName{_regName} {}
+ Impl(std::string _regName) : regName{std::move(_regName)} {}
const std::shared_ptr<const celix::IResourceBundle> emptyBundle = std::shared_ptr<const celix::IResourceBundle>{new EmptyBundle{}};
const std::string regName;
@@ -403,9 +423,9 @@ public:
props[celix::SERVICE_BUNDLE] = std::to_string(bnd->id());
if (factory) {
- VLOG(1) << "Registering service factory '" << svcName << "' from bundle id " << owner->id() << std::endl;
+ DLOG(INFO) << "Registering service factory '" << svcName << "' from bundle id " << owner->id() << std::endl;
} else {
- VLOG(1) << "Registering service '" << svcName << "' from bundle id " << owner->id() << std::endl;
+ DLOG(INFO) << "Registering service '" << svcName << "' from bundle id " << owner->id() << std::endl;
}
const auto it = services.registry[svcName].emplace(new SvcEntry{std::move(bnd), svcId, svcName, std::move(svc), std::move(factory), std::move(props)});
@@ -430,6 +450,7 @@ public:
.unregisterCallback = std::move(unreg),
.registered = true
};
+
return celix::ServiceRegistration{impl};
}
@@ -524,7 +545,7 @@ public:
/**********************************************************************************************************************
- Service Registry
+ Service Registry Implementation
**********************************************************************************************************************/
@@ -539,11 +560,6 @@ celix::ServiceRegistry::~ServiceRegistry() {
const std::string& celix::ServiceRegistry::name() const { return pimpl->regName; }
-/*
-celix::ServiceRegistration celix::ServiceRegistry::registerService(const std::string &svcName, std::unique_ptr<void> svc, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) {
- return pimpl->registerService(std::move(svcName), nullptr, {}, std::move(svc), std::move(props), std::move(owner));
-}*/
-
celix::ServiceRegistration celix::ServiceRegistry::registerService(std::string svcName, std::shared_ptr<void> svc, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) {
return pimpl->registerService(std::move(svcName), std::move(svc), {}, std::move(props), std::move(owner));
}
@@ -728,8 +744,17 @@ std::vector<std::string> celix::ServiceRegistry::listAllRegisteredServiceNames()
return pimpl->listAllRegisteredServiceNames();
}
+template<typename I>
+celix::ServiceRegistration celix::ServiceRegistry::registerService(I &&svc, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) {
+ auto svcName = celix::serviceName<I>();
+ auto *servicesStore = new std::vector<I>{};
+ servicesStore->emplace_back(std::forward<I>(svc));
+ auto voidSvc = std::shared_ptr<void>(static_cast<void*>(&(*servicesStore)[0]), [servicesStore](void*){delete servicesStore;}); //transform to std::shared_ptr to minimize the underlining impl needed.
+ return registerService(svcName, std::move(voidSvc), std::move(props), std::move(owner));
+}
+
/**********************************************************************************************************************
- Service Registration
+ Service Registration Implementation
**********************************************************************************************************************/
celix::ServiceRegistration::ServiceRegistration() : pimpl{nullptr} {}
@@ -748,6 +773,7 @@ void celix::ServiceRegistration::unregister() {
if (pimpl && pimpl->registered) {
pimpl->registered = false; //TODO make thread safe
pimpl->unregisterCallback();
+ DLOG(INFO) << "Unregister " << *this;
}
}
@@ -764,11 +790,16 @@ const std::string& celix::ServiceRegistration::serviceName() const {
return empty;
}
+std::ostream& operator<<(std::ostream &out, const celix::ServiceRegistration& reg) {
+ out << "ServiceRegistration[service_id=" << reg.serviceId() << ",service_name=" << reg.serviceName() << "]";
+ return out;
+}
+
/**********************************************************************************************************************
- Service Tracker
+ Service Tracker Implementation
**********************************************************************************************************************/
celix::ServiceTracker::ServiceTracker() : pimpl{nullptr} {}