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} {}