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/22 19:58:12 UTC

[celix] branch feature/cxx updated: CELIX-370: Adds initial implementation for component manager state transition

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 bc4a582  CELIX-370: Adds initial implementation for component manager state transition
bc4a582 is described below

commit bc4a582fab6495823f25254440eda6e2652d8d31
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Thu Aug 22 21:57:46 2019 +0200

    CELIX-370: Adds initial implementation for component manager state transition
---
 .../gtest/src/ComponentManager_tests.cc            |  44 ++++
 .../framework_cxx/include/celix/ComponentManager.h | 131 +++++++----
 libs/framework_cxx/src/ComponentManager.cc         | 246 ++++++++++++++++++---
 libs/registry/include/celix/Utils.h                |  19 +-
 4 files changed, 367 insertions(+), 73 deletions(-)

diff --git a/libs/framework_cxx/gtest/src/ComponentManager_tests.cc b/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
index 77dc8de..db7fc7e 100644
--- a/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
+++ b/libs/framework_cxx/gtest/src/ComponentManager_tests.cc
@@ -44,6 +44,11 @@ TEST_F(ComponentManagerTest, CreateDestroy) {
 
     cmpMng.enable();
     EXPECT_TRUE(cmpMng.isEnabled());
+    EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Started);
+
+    cmpMng.disable();
+    EXPECT_FALSE(cmpMng.isEnabled());
+    EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Disabled);
 }
 
 TEST_F(ComponentManagerTest, AddSvcDep) {
@@ -57,6 +62,8 @@ TEST_F(ComponentManagerTest, AddSvcDep) {
             .setRequired(true);
     cmpMng.enable();
     EXPECT_TRUE(cmpMng.isEnabled());
+    EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Uninitialized);
+
 
     //dep not available -> cmp manager not resolved
     EXPECT_FALSE(cmpMng.isResolved());
@@ -65,4 +72,41 @@ 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);
+
+    cmpMng.disable();
+    //cmp disabled -> not resolved
+    EXPECT_FALSE(cmpMng.isResolved());
+    EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Disabled);
+
+    //dmp enabled & svc available -> resolved.
+    cmpMng.enable();
+    EXPECT_TRUE(cmpMng.isResolved());
+    EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Started);
+
+    svcReg.unregister();
+    EXPECT_EQ(cmpMng.getState(), celix::ComponentState::Initialized);
+    //dep unregisted -> state is Initialized
+}
+
+TEST_F(ComponentManagerTest, AddAndRemoveSvcDep) {
+    auto ctx = framework().context();
+
+    class Cmp {};
+    class ISvc {};
+    std::string svcDepUuid;
+
+    celix::ComponentManager<Cmp> cmpMng{ctx, std::make_shared<Cmp>()};
+    cmpMng.addServiceDependency<ISvc>()
+            .setRequired(true)
+            .extractUUID(svcDepUuid);
+    cmpMng.enable();
+    EXPECT_TRUE(cmpMng.isEnabled());
+
+    //dep not available -> cmp manager not resolved
+    EXPECT_FALSE(cmpMng.isResolved());
+
+    cmpMng.removeServiceDependency(svcDepUuid);
+    //dep removed -> cmp manager resolved
+    EXPECT_TRUE(cmpMng.isResolved());
 }
\ No newline at end of file
diff --git a/libs/framework_cxx/include/celix/ComponentManager.h b/libs/framework_cxx/include/celix/ComponentManager.h
index bfbd971..2612fa5 100644
--- a/libs/framework_cxx/include/celix/ComponentManager.h
+++ b/libs/framework_cxx/include/celix/ComponentManager.h
@@ -22,7 +22,9 @@
 
 #include <memory>
 #include <unordered_map>
+#include <queue>
 
+#include "celix/Utils.h"
 #include "celix/BundleContext.h"
 
 namespace celix {
@@ -45,29 +47,41 @@ namespace celix {
         ComponentState getState() const;
         bool isEnabled() const;
         bool isResolved() const;
+        std::string getName() const;
+        std::string getUUD() const;
 
         //TODO make friend of SvcDep
         void updateState();
+
+        void removeServiceDependency(const std::string& serviceDependencyUUID);
     protected:
-        GenericComponentManager(std::shared_ptr<BundleContext> _ctx) : ctx{std::move(_ctx)} {};
+        GenericComponentManager(std::shared_ptr<BundleContext> _ctx, const std::string &_name);
 
-        void removeServiceDependency(long serviceDependencyId);
         void setEnabled(bool enable);
 
-
         /**** Fields ****/
-        std::shared_ptr<BundleContext> ctx;
+        const std::shared_ptr<BundleContext> ctx;
+        const std::string name;
+        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::mutex serviceDependenciesMutex{};
+        std::unordered_map<std::string,std::shared_ptr<GenericServiceDependency>> serviceDependencies{}; //key = dep uuid
+    private:
+        void setState(ComponentState state);
+        void setInitialized(bool initialized);
+        void transition();
 
-        mutable std::mutex mutex{}; //protects below
+        mutable std::mutex stateMutex{}; //protects below
         ComponentState state = ComponentState::Disabled;
         bool enabled = false;
-        std::function<void()> init{};
-        std::function<void()> start{};
-        std::function<void()> stop{};
-        std::function<void()> deinit{};
-
-        long nextServiceDependencyId = 1L;
-        std::unordered_map<long,std::unique_ptr<GenericServiceDependency>> serviceDependencies{};
+        bool initialized = false;
+        std::queue<std::pair<ComponentState,ComponentState>> transitionQueue{};
     };
 
     template<typename T>
@@ -75,7 +89,7 @@ namespace celix {
     public:
         using ComponentType = T;
 
-        ComponentManager(std::shared_ptr<BundleContext> ctx, std::shared_ptr<T> cmpInstance);
+        ComponentManager(std::shared_ptr<BundleContext> ctx, std::shared_ptr<T> cmpInstance, const std::string &name = celix::typeName<T>());
         ~ComponentManager() override = default;
 
         ComponentManager<T>& enable();
@@ -91,6 +105,11 @@ namespace celix {
 
         template<typename I>
         ServiceDependency<T,I>& addServiceDependency();
+
+        template<typename I>
+        ServiceDependency<T,I>* findServiceDependency(const std::string& serviceDependencyUUID);
+
+        ComponentManager<T>& extractUUID(std::string& out);
 //
 //        template<typename F>
 //        ServiceDependency<T,F>& addFunctionServiceDependency(const std::string &functionName);
@@ -112,26 +131,25 @@ namespace celix {
         Cardinality getCardinality() const;
         bool getRequired() const;
         const std::string& getFilter() const;
-        void setEnable(bool enable);
+        std::string getUUD();
 
+        bool isEnabled();
+        virtual void setEnabled(bool e) = 0;
     protected:
         GenericServiceDependency(
                 std::shared_ptr<BundleContext> ctx,
-                std::function<void()> stateChangedCallback,
-                std::function<void()> enable,
-                std::function<void()> disable);
+                std::function<void()> stateChangedCallback);
 
         //Fields
-        std::shared_ptr<BundleContext> ctx;
+        const std::shared_ptr<BundleContext> ctx;
         const std::function<void()> stateChangedCallback;
-        const std::function<void()> enable;
-        std::function<void()> disable;
+        const std::string uuid;
 
         mutable std::mutex mutex{}; //protects below
         bool required = false;
         std::string filter{};
         Cardinality cardinality = Cardinality::One;
-        std::vector<ServiceTracker> tracker{}; //max 1
+        std::vector<ServiceTracker> tracker{}; //max 1 (1 == enabled / 0 = disabled
     };
 
     template<typename T, typename I>
@@ -157,9 +175,12 @@ namespace celix {
                 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();
-        bool isResolved();
+
+        void setEnabled(bool e) override;
+
     private:
         const std::function<std::shared_ptr<T>()> getCmpInstance;
 
@@ -171,6 +192,8 @@ namespace celix {
     };
 }
 
+std::ostream& operator<< (std::ostream& out, celix::ComponentState state);
+
 
 
 /**************************** IMPLEMENTATION *************************************************************************/
@@ -178,17 +201,19 @@ namespace celix {
 template<typename T>
 celix::ComponentManager<T>::ComponentManager(
         std::shared_ptr<BundleContext> ctx,
-        std::shared_ptr<T> cmpInstance) : GenericComponentManager{ctx}, inst{std::move(cmpInstance)} {}
+        std::shared_ptr<T> cmpInstance,
+        const std::string &name) : GenericComponentManager{ctx, name}, inst{std::move(cmpInstance)} {
+}
 
 template<typename T>
 celix::ComponentManager<T>& celix::ComponentManager<T>::enable() {
-    this->setEnabled(true);
+    setEnabled(true);
     return *this;
 }
 
 template<typename T>
 celix::ComponentManager<T>& celix::ComponentManager<T>::disable() {
-    this->setEnabled(false);
+    setEnabled(false);
     return *this;
 }
 
@@ -198,7 +223,7 @@ celix::ComponentManager<T>& celix::ComponentManager<T>::setCallbacks(
         void (T::*memberStart)(),
         void (T::*memberStop)(),
         void (T::*memberDeinit)()) {
-    std::lock_guard<std::mutex> lck{mutex};
+    std::lock_guard<std::mutex> lck{callbacksMutex};
     init = [this, memberInit]() {
         if (memberInit) {
             (this->instance()->*memberInit)();
@@ -227,17 +252,28 @@ 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;
+}
 
 template<typename T>
 template<typename I>
 celix::ServiceDependency<T,I>& celix::ComponentManager<T>::addServiceDependency() {
-    auto *dep = new celix::ServiceDependency<T,I>{ctx, []{/*TODO*/}, [this]{return instance();}};
-    std::lock_guard<std::mutex> lck{mutex};
-    serviceDependencies[nextServiceDependencyId++] = std::unique_ptr<GenericServiceDependency>{dep};
+    auto *dep = new celix::ServiceDependency<T,I>{ctx, [this]{updateState();}, [this]{return instance();}};
+    std::lock_guard<std::mutex> lck{serviceDependenciesMutex};
+    serviceDependencies[dep->getUUD()] = std::unique_ptr<GenericServiceDependency>{dep};
     return *dep;
 }
 
-
+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();
+}
 
 
 
@@ -248,12 +284,14 @@ 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{_ctx, _stateChangedCallback, [this]{enable();}, [this]{disable();}}, getCmpInstance{_getCmpInstance} {};
+        std::function<std::shared_ptr<T>()> _getCmpInstance) : GenericServiceDependency{std::move(_ctx), std::move(_stateChangedCallback)}, getCmpInstance{_getCmpInstance} {};
 
 template<typename T, typename I>
-celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::enable() {
-    std::lock_guard<std::mutex> lck{mutex};
-    if (tracker.size() == 0) { //disabled
+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;
@@ -266,15 +304,28 @@ celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::enable() {
             }
             this->stateChangedCallback();
         };
-        this->tracker.push_back(this->ctx->trackServices(opts));
+        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
+}
+
+template<typename T, typename I>
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::enable() {
+    setEnabled(true);
     return *this;
 }
 
 template<typename T, typename I>
 celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::disable() {
-    std::lock_guard<std::mutex> lck{mutex};
-    tracker.clear();
+    setEnabled(false);
     return *this;
 }
 
@@ -349,5 +400,11 @@ celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::setCardinality(cel
     return *this;
 }
 
+template<typename T, typename I>
+celix::ServiceDependency<T,I>& celix::ServiceDependency<T,I>::extractUUID(std::string& out) {
+    out = uuid;
+    return *this;
+}
+
 
 #endif //CXX_CELIX_COMPONENT_MANAGER_H
diff --git a/libs/framework_cxx/src/ComponentManager.cc b/libs/framework_cxx/src/ComponentManager.cc
index f087b19..07e3bc0 100644
--- a/libs/framework_cxx/src/ComponentManager.cc
+++ b/libs/framework_cxx/src/ComponentManager.cc
@@ -19,16 +19,29 @@
 
 
 #include <iostream>
+#include <uuid/uuid.h>
 #include <celix/ComponentManager.h>
+#include <glog/logging.h>
 
 
 #include "celix/ComponentManager.h"
 
+static std::string genUUID() {
+    uuid_t tmpUUID;
+    uuid_string_t str;
+
+    uuid_generate(tmpUUID);
+    uuid_unparse(tmpUUID, str);
+
+    return std::string{str};
+}
+
 celix::GenericServiceDependency::GenericServiceDependency(
         std::shared_ptr<celix::BundleContext> _ctx,
-        std::function<void()> _stateChangedCallback,
-        std::function<void()> _enable,
-        std::function<void()> _disable) : ctx{_ctx}, stateChangedCallback{std::move(_stateChangedCallback)}, enable{std::move(_enable)}, disable{std::move(_disable)} {}
+        std::function<void()> _stateChangedCallback) :
+            ctx{std::move(_ctx)},
+            stateChangedCallback{std::move(_stateChangedCallback)},
+            uuid{genUUID()} {}
 
 
 bool celix::GenericServiceDependency::isResolved() const {
@@ -55,27 +68,27 @@ const std::string &celix::GenericServiceDependency::getFilter() const {
     return filter;
 }
 
-void celix::GenericServiceDependency::setEnable(bool e) {
-    if (e) {
-        enable();
-    } else {
-        disable();
-    }
+std::string celix::GenericServiceDependency::getUUD() {
+    return uuid;
 }
 
-celix::ComponentState celix::GenericComponentManager::getState() const {
+bool celix::GenericServiceDependency::isEnabled() {
     std::lock_guard<std::mutex> lck{mutex};
+    return !tracker.empty();
+}
+
+celix::ComponentState celix::GenericComponentManager::getState() const {
+    std::lock_guard<std::mutex> lck{stateMutex};
     return state;
 }
 
 bool celix::GenericComponentManager::isEnabled() const  {
-    std::lock_guard<std::mutex> lck{mutex};
-    //TODO update state
+    std::lock_guard<std::mutex> lck{stateMutex};
     return enabled;
 }
 
 bool celix::GenericComponentManager::isResolved() const {
-    std::lock_guard<std::mutex> lck{mutex};
+    std::lock_guard<std::mutex> lck{stateMutex};
     for (auto &pair : serviceDependencies) {
         if (!pair.second->isResolved()) {
             return false;
@@ -84,36 +97,207 @@ bool celix::GenericComponentManager::isResolved() const {
     return true;
 }
 
-void celix::GenericComponentManager::removeServiceDependency(long serviceDependencyId) {
-    std::lock_guard<std::mutex> lck{mutex};
-    serviceDependencies.erase(serviceDependencyId);
-}
-
 void celix::GenericComponentManager::setEnabled(bool e) {
-    std::lock_guard<std::mutex> lck{mutex};
-    enabled = e;
-    for (auto &pair : serviceDependencies) {
-        pair.second->setEnable(e);
+    {
+        std::lock_guard<std::mutex> lck{stateMutex};
+        enabled = e;
     }
+    std::vector<std::shared_ptr<GenericServiceDependency>> deps{};
+    {
+        std::lock_guard<std::mutex> lck{serviceDependenciesMutex};
+        for (auto &pair : serviceDependencies) {
+            deps.push_back(pair.second);
+        }
+    }
+
+    //NOTE updating outside of the lock
+    for (auto &dep : deps) {
+        dep->setEnabled(e);
+    }
+    updateState();
 }
 
 void celix::GenericComponentManager::updateState() {
-    std::lock_guard<std::mutex> lck{mutex};
+    bool allDependenciesResolved = true;
+    {
+        std::lock_guard<std::mutex> lck{serviceDependenciesMutex};
+        for (auto &pair : serviceDependencies) {
+            if (!pair.second->isResolved()) {
+                allDependenciesResolved = false;
+                break;
+            }
+        }
+    }
 
-    //TODO state thing
+    {
+        std::lock_guard<std::mutex> lck{stateMutex};
+        ComponentState currentState = state;
+        ComponentState targetState = ComponentState::Disabled;
 
-    //TODO check enabled.
+        if (enabled && allDependenciesResolved) {
+            targetState = ComponentState::Started;
+        } else if (enabled) /*not all dep resolved*/ {
+            targetState = initialized ? ComponentState::Initialized : ComponentState::Uninitialized;
+        }
 
-    bool allDependenciesResolved = true;
-    for (auto &pair : serviceDependencies) {
-        if (!pair.second->isResolved()) {
-            allDependenciesResolved = false;
-            break;
+        if (currentState != targetState) {
+            transitionQueue.emplace(currentState, targetState);
         }
     }
+    transition();
+}
 
-    std::cout << "resolved? " << (allDependenciesResolved ? "true" : "false") << std::endl;
+void celix::GenericComponentManager::transition() {
+    ComponentState currentState;
+    ComponentState targetState;
+
+    {
+        std::lock_guard<std::mutex> lck{stateMutex};
+        if (transitionQueue.empty()) {
+            return;
+        }
+        auto pair = transitionQueue.front();
+        transitionQueue.pop();
+        currentState = pair.first;
+        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 ...
+
+    if (targetState == ComponentState::Disabled) {
+        switch (currentState) {
+            case celix::ComponentState::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);
+                break;
+        }
+    } else if (targetState == ComponentState::Uninitialized) {
+        switch (currentState) {
+            case celix::ComponentState::Disabled:
+                //TODO maybe enable callback
+                setState(ComponentState::Uninitialized);
+                break;
+            case celix::ComponentState::Uninitialized:
+                //nop
+                break;
+            case celix::ComponentState::Initialized:
+                deinit();
+                setInitialized(false);
+                setState(ComponentState::Uninitialized);
+                break;
+            case celix::ComponentState::Started:
+                stop();
+                setState(ComponentState::Initialized);
+                break;
+        }
+    } else if (targetState == ComponentState::Initialized) {
+        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:
+                //nop
+                break;
+            case celix::ComponentState::Started:
+                stop();
+                setState(ComponentState ::Initialized);
+                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:
+                //nop
+                break;
+        }
+    } else {
+        LOG(ERROR) << "Unexpected target state: " << targetState;
+    }
+
+    updateState();
+}
+
+void celix::GenericComponentManager::setState(ComponentState s) {
+    std::lock_guard<std::mutex> lck{stateMutex};
+    state = s;
+}
+
+
+std::string celix::GenericComponentManager::getUUD() const {
+    return uuid;
+}
+
+celix::GenericComponentManager::GenericComponentManager(std::shared_ptr<celix::BundleContext> _ctx, const std::string &_name) : ctx{std::move(_ctx)}, name{_name}, uuid{genUUID()} {
+}
+
+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::string celix::GenericComponentManager::getName() const {
+    return name;
+}
+
+void celix::GenericComponentManager::setInitialized(bool i) {
+    std::lock_guard<std::mutex> lck{stateMutex};
+    initialized = i;
 }
 
 
+std::ostream& operator<< (std::ostream& out, celix::ComponentState state)
+{
+    switch (state) {
+        case celix::ComponentState::Disabled:
+            out << "Disabled";
+            break;
+        case celix::ComponentState::Uninitialized:
+            out << "Uninitialized";
+            break;
+        case celix::ComponentState::Initialized:
+            out << "Initialized";
+            break;
+        case celix::ComponentState::Started:
+            out << "Started";
+            break;
+    }
+    return out;
+}
 
diff --git a/libs/registry/include/celix/Utils.h b/libs/registry/include/celix/Utils.h
index ce72e4f..56c4f53 100644
--- a/libs/registry/include/celix/Utils.h
+++ b/libs/registry/include/celix/Utils.h
@@ -34,7 +34,7 @@ namespace impl {
 namespace {
 
     template<typename INTERFACE_TYPENAME>
-    std::string typeName() {
+    std::string typeNameInternal() {
         static const std::string templateStr = "INTERFACE_TYPENAME = ";
         std::string pretty = __PRETTY_FUNCTION__;
         return celix::impl::typeNameFromPrettyFunction(templateStr, __PRETTY_FUNCTION__);
@@ -42,27 +42,35 @@ namespace {
 
     template<typename Arg>
     std::string argName() {
-        return typeName<Arg>(); //terminal;
+        return typeNameInternal<Arg>(); //terminal;
     }
 
     template<typename Arg1, typename Arg2, typename... Args>
     std::string argName() {
-        return typeName<Arg1>() + ", " + argName<Arg2, Args...>();
+        return typeNameInternal<Arg1>() + ", " + argName<Arg2, Args...>();
     }
 
     template<typename R>
     std::string functionName() {
-        return "std::function<" + typeName<R>() + "()>";
+        return "std::function<" + typeNameInternal<R>() + "()>";
     }
 
     template<typename R, typename Arg1, typename... Args>
     std::string functionName() {
-        return "std::function<" + typeName<R>() + "("  + argName<Arg1, Args...>() + ")>";
+        return "std::function<" + typeNameInternal<R>() + "("  + argName<Arg1, Args...>() + ")>";
     }
 };
 
 namespace celix {
 
+    /**
+     * Returns the type name of the provided template T
+     */
+    template<typename T>
+    std::string typeName() {
+        return typeNameInternal<T>();
+    }
+
     /* TODO
     template<typename I>
     typename std::enable_if<I::FQN, std::string>::type
@@ -81,6 +89,7 @@ namespace celix {
         return svcName;
     }
 
+
     //TODO resolve FQN for Function Service.
 
     /**