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/01/07 20:11:50 UTC

[celix] 02/22: CELIX-438: Adds the C++ shell/shell_tui initial impl and a small test application

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

commit 9231430205ed008ae79342e25b49d1178e793e67
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Wed Jan 2 14:53:06 2019 +0100

    CELIX-438: Adds the C++ shell/shell_tui initial impl and a small test application
---
 bundles/shell/CMakeLists.txt                       |   1 +
 bundles/shell/cxx_shell/CMakeLists.txt             |  18 +-
 bundles/shell/cxx_shell/include/celix/IShell.h     |   2 +-
 .../shell/cxx_shell/include/celix/IShellCommand.h  |  18 +-
 bundles/shell/cxx_shell/src/HelpCommand.cc         |  86 +++++++++
 bundles/shell/cxx_shell/src/InspectCommand.cc      |  70 +++++++
 bundles/shell/cxx_shell/src/LbCommand.cc           |  54 ++++++
 bundles/shell/cxx_shell/src/ShellActivator.cc      | 157 ++++++---------
 bundles/shell/cxx_shell/src/StopAndStartCommand.cc |  75 ++++++++
 .../shell/cxx_shell/src/commands.h                 |  27 ++-
 .../{cxx_shell => cxx_shell_tui}/CMakeLists.txt    |  29 +--
 .../shell/{ => cxx_shell_tui/gtest}/CMakeLists.txt |  16 +-
 .../IShell.h => cxx_shell_tui/gtest/src/main.cc}   |  23 +--
 .../shell/cxx_shell_tui/src/ShellTuiActivator.cc   | 150 +++++++++++++++
 .../IShell.h => cxx_shell_tui/src/shell_test.cc}   |  23 ++-
 cmake/celix_project/AddGTest.cmake                 |   4 +-
 libs/framework_cxx/gtest/src/Framework_tests.cc    |  81 ++++----
 libs/framework_cxx/include/celix/Framework.h       |  45 +++--
 libs/framework_cxx/include/celix/IBundle.h         |   1 -
 .../framework_cxx/include/celix/IBundleActivator.h |  12 +-
 libs/framework_cxx/include/celix/IBundleContext.h  |   7 +-
 libs/framework_cxx/src/BundleImpl.h                |  67 +++----
 libs/framework_cxx/src/Framework.cc                | 114 +++++++----
 .../gtest/src/RegistryConcurrency_tests.cc         |   3 +-
 libs/registry/gtest/src/Registry_tests.cc          |  23 ++-
 libs/registry/gtest/src/ServiceTracking_tests.cc   |  64 +++----
 libs/registry/include/celix/Constants.h            |   7 +-
 libs/registry/include/celix/Properties.h           |   6 +
 libs/registry/include/celix/ServiceRegistry.h      | 155 ++++++++-------
 libs/registry/src/ServiceRegistry.cc               | 211 ++++++++++++++-------
 30 files changed, 1048 insertions(+), 501 deletions(-)

diff --git a/bundles/shell/CMakeLists.txt b/bundles/shell/CMakeLists.txt
index 2fd81dc..851d601 100644
--- a/bundles/shell/CMakeLists.txt
+++ b/bundles/shell/CMakeLists.txt
@@ -21,3 +21,4 @@ add_subdirectory(shell_bonjour)
 add_subdirectory(shell_tui)
 
 add_subdirectory(cxx_shell)
+add_subdirectory(cxx_shell_tui)
diff --git a/bundles/shell/cxx_shell/CMakeLists.txt b/bundles/shell/cxx_shell/CMakeLists.txt
index 070f05e..5373caf 100644
--- a/bundles/shell/cxx_shell/CMakeLists.txt
+++ b/bundles/shell/cxx_shell/CMakeLists.txt
@@ -19,18 +19,22 @@ find_package(glog REQUIRED)
 
 #TODO rename to celix::shell && celix::shell_api
 
-add_library(shell_api_cxx INTERFACE)
-target_include_directories(shell_api INTERFACE
+add_library(celix_cxx_shell_api INTERFACE)
+target_include_directories(celix_cxx_shell_api INTERFACE
     $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
     $<INSTALL_INTERFACE:include/celix/shell>
 )
 
-add_library(celix_shell_cxx STATIC
+add_library(celix_cxx_shell SHARED
         src/ShellActivator.cc
-        include/celix/IShell.h)
-target_include_directories(celix_shell_cxx PRIVATE src)
-target_include_directories(celix_shell_cxx PUBLIC include)
-target_link_libraries(celix_shell_cxx PRIVATE glog::glog celix_framework_cxx)
+        src/LbCommand.cc
+        src/HelpCommand.cc
+        src/StopAndStartCommand.cc
+        src/InspectCommand.cc
+)
+target_include_directories(celix_cxx_shell PRIVATE src)
+target_link_libraries(celix_cxx_shell PRIVATE celix_cxx_shell_api)
+target_link_libraries(celix_cxx_shell PUBLIC glog::glog celix_framework_cxx)
 
 #if (ENABLE_TESTING)
 #    add_subdirectory(gtest)
diff --git a/bundles/shell/cxx_shell/include/celix/IShell.h b/bundles/shell/cxx_shell/include/celix/IShell.h
index 9809ac5..f272c52 100644
--- a/bundles/shell/cxx_shell/include/celix/IShell.h
+++ b/bundles/shell/cxx_shell/include/celix/IShell.h
@@ -29,7 +29,7 @@ namespace celix {
 
         virtual ~IShell() = default;
 
-        virtual bool executeCommand(const std::string &commandLine, std::ostream &out, std::ostream &err) noexcept = 0;
+        virtual bool executeCommandLine(const std::string &commandLine, std::ostream &out, std::ostream &err) noexcept = 0;
     };
 }
 
diff --git a/bundles/shell/cxx_shell/include/celix/IShellCommand.h b/bundles/shell/cxx_shell/include/celix/IShellCommand.h
index 8a30133..ec98c73 100644
--- a/bundles/shell/cxx_shell/include/celix/IShellCommand.h
+++ b/bundles/shell/cxx_shell/include/celix/IShellCommand.h
@@ -18,6 +18,7 @@
  */
 
 #include <string>
+#include <vector>
 #include <iostream>
 
 #ifndef CXX_CELIX_ISHELLCOMMAND_H
@@ -29,20 +30,21 @@ namespace celix {
     public:
         static constexpr const char * const SERVICE_FQN = "celix::IShellCommand [Version 1]";
 
-        static constexpr const char * const COMMAND_NAME = "name";
-        static constexpr const char * const COMMAND_USAGE = "usage";
-        static constexpr const char * const COMMAND_DESCRIPTION = "description";
+        static constexpr const char * const COMMAND_NAME = "COMMAND_NAME";
+        static constexpr const char * const COMMAND_USAGE = "COMMAND_USAGE";
+        static constexpr const char * const COMMAND_DESCRIPTION = "COMMAND_DESCRIPTION";
 
         virtual ~IShellCommand() = default;
 
-        virtual void executeCommand(const std::string &commandLine, std::ostream &out, std::ostream &err) noexcept = 0;
+        virtual void executeCommand(const std::string &cmdName, const std::vector<std::string> &cmdArgs, std::ostream &out, std::ostream &err) noexcept = 0;
     };
 
-    using ShellCommandFunction = std::function<void(const std::string &commandLine, std::ostream &out, std::ostream &err)>;
     static constexpr const char * const SHELL_COMMAND_FUNCTION_SERVICE_FQN = "celix::ShellFunction [Version 1]";
-    static constexpr const char * const SHELL_COMMAND_FUNCTION_COMMAND_NAME = "name";
-    static constexpr const char * const SHELL_COMMAND_FUNCTION_COMMAND_USAGE = "usage";
-    static constexpr const char * const SHELL_COMMAND_FUNCTION_COMMAND_DESCRIPTION = "description";
+    static constexpr const char * const SHELL_COMMAND_FUNCTION_COMMAND_NAME = "COMMAND_NAME";
+    static constexpr const char * const SHELL_COMMAND_FUNCTION_COMMAND_USAGE = "COMMAND_USAGE";
+    static constexpr const char * const SHELL_COMMAND_FUNCTION_COMMAND_DESCRIPTION = "COMMAND_DESCRIPTION";
+    using ShellCommandFunction = std::function<void(const std::string &cmdName, const std::vector<std::string> &cmdArgs, std::ostream &out, std::ostream &err)>;
+
 }
 
 #endif //CXX_CELIX_ISHELLCOMMAND_H
diff --git a/bundles/shell/cxx_shell/src/HelpCommand.cc b/bundles/shell/cxx_shell/src/HelpCommand.cc
new file mode 100644
index 0000000..3f5f5e9
--- /dev/null
+++ b/bundles/shell/cxx_shell/src/HelpCommand.cc
@@ -0,0 +1,86 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include "commands.h"
+
+#include "celix/api.h"
+#include "celix/IShellCommand.h"
+
+celix::ServiceRegistration impl::registerHelp(std::shared_ptr<celix::IBundleContext> ctx) {
+
+    celix::ShellCommandFunction help = [ctx](const std::string &, const std::vector<std::string> &commandArguments, std::ostream &out, std::ostream &) {
+
+        if (commandArguments.empty()) { //only command -> overview
+
+            std::string hasCommandNameFilter = std::string{"("} + celix::IShellCommand::COMMAND_NAME + "=*)";
+            std::vector<std::string> commands{};
+            ctx->useServices<celix::IShellCommand>([&](celix::IShellCommand &, const celix::Properties &props) {
+                commands.push_back(celix::getProperty(props, celix::IShellCommand::COMMAND_NAME, "!Error!"));
+            }, hasCommandNameFilter);
+
+            hasCommandNameFilter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=*)";
+
+            std::function<void(celix::ShellCommandFunction &, const celix::Properties &)> use = [&](
+                    celix::ShellCommandFunction &, const celix::Properties &props) {
+                commands.push_back(celix::getProperty(props, celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME, "!Error!"));
+            };
+            ctx->useFunctionServices(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, use, hasCommandNameFilter);
+
+            //TODO useCService with a shell command service struct
+
+            out << "Available commands: " << std::endl;
+            for (auto &name : commands) {
+                out << "|- " << name << std::endl;
+            }
+        } else { //details
+            for (auto &cmd : commandArguments) {
+                std::string commandNameFilter = std::string{"("} + celix::IShellCommand::COMMAND_NAME + "=" + cmd + ")";
+                bool found = ctx->useService<celix::IShellCommand>([&](celix::IShellCommand &, const celix::Properties &props) {
+                    out << "Command Name       : " << celix::getProperty(props, celix::IShellCommand::COMMAND_NAME, "!Error!") << std::endl;
+                    out << "Command Usage      : " << celix::getProperty(props, celix::IShellCommand::COMMAND_USAGE, "!Error!") << std::endl;
+                    out << "Command Description: " << celix::getProperty(props, celix::IShellCommand::COMMAND_DESCRIPTION, "!Error!") << std::endl;
+
+                }, commandNameFilter);
+                if (!found) {
+                    commandNameFilter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=" + cmd + ")";
+                    std::function<void(celix::ShellCommandFunction &, const celix::Properties &)> use = [&](
+                            celix::ShellCommandFunction &, const celix::Properties &props) {
+                        out << "Command Name       : " << celix::getProperty(props, celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME, "!Error!") << std::endl;
+                        out << "Command Usage      : " << celix::getProperty(props, celix::SHELL_COMMAND_FUNCTION_COMMAND_USAGE, "!Error!") << std::endl;
+                        out << "Command Description: " << celix::getProperty(props, celix::SHELL_COMMAND_FUNCTION_COMMAND_DESCRIPTION, "!Error!") << std::endl;
+                    };
+                    found = ctx->useFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, use, commandNameFilter);
+                }
+                if (!found) {
+                    //TODO use C cmd service
+                }
+                if (!found) {
+                    out << "Command '" << cmd << "' not available" << std::endl;
+                }
+                out << std::endl;
+            }
+        }
+    };
+
+    celix::Properties props{};
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME] = "help";
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_USAGE] = "help [command name]";
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_DESCRIPTION] = "display available commands and description.";
+    return ctx->registerFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, std::move(help), std::move(props));
+}
\ No newline at end of file
diff --git a/bundles/shell/cxx_shell/src/InspectCommand.cc b/bundles/shell/cxx_shell/src/InspectCommand.cc
new file mode 100644
index 0000000..da3bf24
--- /dev/null
+++ b/bundles/shell/cxx_shell/src/InspectCommand.cc
@@ -0,0 +1,70 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include "commands.h"
+
+#include <functional>
+
+#include "celix/api.h"
+#include "celix/IShellCommand.h"
+
+namespace {
+
+    void inspect(std::shared_ptr<celix::IBundleContext> ctx, const std::string &, const std::vector<std::string> &cmdArgs, std::ostream &out, std::ostream &) {
+        if (cmdArgs.empty()) {
+            out << "Provide a bundle id" << std::endl;
+        } else {
+            auto &bndId = cmdArgs[0];
+            auto servicesNames = ctx->registry().listAllRegisteredServiceNames();
+
+            const std::string *what{nullptr};
+            if (cmdArgs.size() >= 2) {
+                what = &cmdArgs[1];
+            }
+
+            if (what == nullptr || *what == "provided") {
+                out << "Provided Services: \n";
+                for (auto &svcName : servicesNames) {
+                    std::string filter = std::string{"("} + celix::SERVICE_BUNDLE + "=" + bndId + ")";
+                    ctx->registry().useAnyServices(svcName, [&out](std::shared_ptr<void>, const celix::Properties &props, const celix::IResourceBundle &) {
+                        out << "|- Service " << celix::getProperty(props, celix::SERVICE_ID, "!Error") << ":\n";
+                        for (auto &pair : props) {
+                            out << "   |- " << pair.first << " = " << pair.second << std::endl;
+                        }
+                    }, filter, ctx->bundle());
+                }
+            }
+            if (what == nullptr || *what == "tracked") {
+                //TODO trackers
+            }
+        }
+    }
+}
+
+
+celix::ServiceRegistration impl::registerInspect(std::shared_ptr<celix::IBundleContext> ctx) {
+    using namespace std::placeholders;
+    celix::ShellCommandFunction cmd = std::bind(&inspect, ctx, _1, _2, _3, _4);
+
+    celix::Properties props{};
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME] = "inspect";
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_USAGE] = "inspect bndId [provided|tracked]";
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_DESCRIPTION] = "Inspects a bundle. Showing the provided and/or tracked services";
+    return ctx->registerFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, std::move(cmd), std::move(props));
+}
\ No newline at end of file
diff --git a/bundles/shell/cxx_shell/src/LbCommand.cc b/bundles/shell/cxx_shell/src/LbCommand.cc
new file mode 100644
index 0000000..5c1b07c
--- /dev/null
+++ b/bundles/shell/cxx_shell/src/LbCommand.cc
@@ -0,0 +1,54 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include "commands.h"
+
+#include "celix/IShellCommand.h"
+
+namespace {
+    class LbCommand : public celix::IShellCommand {
+    public:
+        LbCommand(std::shared_ptr<celix::IBundleContext> _ctx) : ctx{std::move(_ctx)} {}
+
+        void executeCommand(const std::string &, const std::vector<std::string> &cmdArgs, std::ostream &out,
+                            std::ostream &) noexcept override {
+            if (cmdArgs.empty()) {
+                out << "Bundles: " << std::endl;
+                ctx->useBundles([&out](const celix::IBundle &bnd) {
+                    //TODO make aligned text table
+                    out << "|- " << bnd.id() << ": " << bnd.name() << std::endl;
+                }, true);
+            }
+            //TODO parse args
+        }
+
+    private:
+        std::shared_ptr<celix::IBundleContext> ctx;
+    };
+}
+
+celix::ServiceRegistration impl::registerLb(std::shared_ptr<celix::IBundleContext> ctx) {
+    celix::Properties props{};
+    props[celix::IShellCommand::COMMAND_NAME] = "lb";
+    props[celix::IShellCommand::COMMAND_USAGE] = "list bundles. Default only the groupless bundles are listed. Use -a to list all bundles." \
+                            "\nIf a group string is provided only bundles matching the group string will be listed." \
+                            "\nUse -l to print the bundle locations.\nUse -s to print the bundle symbolic names\nUse -u to print the bundle update location.";
+    props[celix::IShellCommand::COMMAND_DESCRIPTION] = "lb [-l | -s | -u | -a] [group]";
+    return ctx->registerService(std::shared_ptr<celix::IShellCommand>{new LbCommand{ctx}}, std::move(props));
+}
\ No newline at end of file
diff --git a/bundles/shell/cxx_shell/src/ShellActivator.cc b/bundles/shell/cxx_shell/src/ShellActivator.cc
index 5fd4f1f..ee89d98 100644
--- a/bundles/shell/cxx_shell/src/ShellActivator.cc
+++ b/bundles/shell/cxx_shell/src/ShellActivator.cc
@@ -21,125 +21,82 @@
 #include "celix/IShellCommand.h"
 #include "celix/IShell.h"
 
+#include "commands.h"
+
 namespace {
 
-    class LbCommand : public celix::IShellCommand {
+    class Shell : public celix::IShell {
     public:
-        LbCommand(std::shared_ptr<celix::IBundleContext> _ctx) : ctx{std::move(_ctx)} {}
-        void executeCommand(const std::string &/*command line*/, std::ostream &out, std::ostream &) noexcept override {
-            //TODO parse commandLine
-            out << "Bundles: " << std::endl;
-            ctx->useBundles([&out](const celix::IBundle &bnd) {
-                out << "|- " << bnd.id() << ": " << bnd.name() << std::endl;
-            }, true);
-        }
-    private:
-        std::shared_ptr<celix::IBundleContext> ctx;
-    };
-
-    celix::ServiceRegistration registerLb(std::shared_ptr<celix::IBundleContext> ctx) {
-        celix::Properties props{};
-        props[celix::IShellCommand::COMMAND_NAME] = "lb";
-        props[celix::IShellCommand::COMMAND_USAGE] = "list installed bundles";
-        props[celix::IShellCommand::COMMAND_DESCRIPTION] = "TODO";
-        return ctx->registerService(std::shared_ptr<celix::IShellCommand>{new LbCommand{ctx}}, std::move(props));
-    }
-
-    celix::ServiceRegistration registerHelp(std::shared_ptr<celix::IBundleContext> ctx) {
-
-        celix::ShellCommandFunction help = [ctx](const std::string &, std::ostream &out, std::ostream &) {
-
-            std::string hasCommandNameFilter = std::string{"("} + celix::IShellCommand::COMMAND_NAME + "=*)";
-            //TODO parse command line to see if details is requested instead of overview
-            std::vector<std::string> commands{};
-            ctx->useServices<celix::IShellCommand>([&](celix::IShellCommand&, const celix::Properties &props) {
-                commands.push_back(celix::getProperty(props, celix::IShellCommand::COMMAND_NAME, "!Error!"));
-            }, hasCommandNameFilter);
-
-            hasCommandNameFilter = std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=*)";
-
-            std::function<void(celix::ShellCommandFunction&, const celix::Properties&)> use = [&](celix::ShellCommandFunction&, const celix::Properties &props) {
-                commands.push_back(celix::getProperty(props, celix::IShellCommand::COMMAND_NAME, "!Error!"));
-            };
-            ctx->useFunctionServices(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, use, hasCommandNameFilter);
+        Shell(std::shared_ptr<celix::IBundleContext> _ctx) : ctx{std::move(_ctx)} {}
+
+        bool executeCommandLine(const std::string &commandLine, std::ostream &out, std::ostream &err) noexcept override {
+            std::string cmdName{};
+            std::vector<std::string> cmdArgs{};
+
+            char *savePtr = nullptr;
+            char *cl = strndup(commandLine.c_str(), 1024*1024);
+            char *token = strtok_r(cl, " ", &savePtr);
+            while (token != nullptr) {
+                if (cmdName.empty()) {
+                    cmdName = std::string{token};
+                } else {
+                    cmdArgs.emplace_back(std::string{token});
+                }
+                token = strtok_r(nullptr, " ", &savePtr);
+            }
 
-            //TODO useCService with a shell command service struct
+            bool commandCalled = false;
 
-            out << "Available commands: " << std::endl;
-            for (auto &name : commands) {
-                out << "|- " << name << std::endl;
+            if (!cmdName.empty()) {
+                std::string filter =
+                        std::string{"("} + celix::IShellCommand::COMMAND_NAME + "=" + cmdName + ")";
+                commandCalled = ctx->useService<celix::IShellCommand>([&](celix::IShellCommand &cmd) {
+                    cmd.executeCommand(cmdName, cmdArgs, out, err);
+                }, filter);
+            }
+            if (!cmdName.empty() && !commandCalled) {
+                std::string filter =
+                        std::string{"("} + celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME + "=" + cmdName + ")";
+                std::function<void(celix::ShellCommandFunction&)> use = [&](celix::ShellCommandFunction &cmd) -> void {
+                    cmd(cmdName, cmdArgs, out, err);
+                };
+                commandCalled = ctx->useFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, use, filter);
             }
-        };
-
-        celix::Properties props{};
-        props[celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME] = "help";
-        props[celix::SHELL_COMMAND_FUNCTION_COMMAND_USAGE] = "help [command name]";
-        props[celix::SHELL_COMMAND_FUNCTION_COMMAND_DESCRIPTION] = "TODO";
-        return ctx->registerFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, std::move(help), std::move(props));
-    }
 
-    class Shell : public celix::IShell {
-    public:
-        Shell(std::shared_ptr<celix::IBundleContext> _ctx) : ctx{std::move(_ctx)} {
-            celix::ServiceTrackerOptions<celix::IShellCommand> opts1{};
-            opts1.updateWithProperties = [this](std::vector<std::tuple<celix::IShellCommand*,const celix::Properties*>> services) {
-                std::lock_guard<std::mutex> lck(commands.mutex);
-                commands.commands = std::move(services);
-            };
-            trk1 = ctx->trackServices(opts1);
+            //TODO C command service struct
+            if (!cmdName.empty() && !commandCalled) {
+                out << "Command '" << cmdName << "' not available. Type 'help' to see a list of available commands." << std::endl;
+            }
 
-            celix::ServiceTrackerOptions<celix::ShellCommandFunction> opts2{};
-            opts2.updateWithProperties = [this](std::vector<std::tuple<celix::ShellCommandFunction*,const celix::Properties*>> services) {
-                std::lock_guard<std::mutex> lck(commands.mutex);
-                commands.commandFunctions = std::move(services);
-            };
-            trk2 = ctx->trackFunctionServices(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, opts2);
-        }
 
-        bool executeCommand(const std::string &commandLine, std::ostream &out, std::ostream &) noexcept override {
-            out << "TODO call command '" << commandLine << "'" << std::endl;
-            return false;
+            return commandCalled;
         }
     private:
         std::shared_ptr<celix::IBundleContext> ctx;
-
-        celix::ServiceTracker trk1{};
-        celix::ServiceTracker trk2{};
-
-        struct {
-            mutable std::mutex mutex{};
-            std::vector<std::tuple<celix::IShellCommand*, const celix::Properties*>> commands;
-            std::vector<std::tuple<celix::ShellCommandFunction*, const celix::Properties*>> commandFunctions;
-        } commands{};
     };
 
     class ShellBundleActivator : public celix::IBundleActivator {
     public:
-        bool start(std::shared_ptr<celix::IBundleContext> ctx) noexcept override {
-            //TODO ensure fixed framework thread that call bundle activators
-            registrations.push_back(registerLb(ctx));
-            registrations.push_back(registerHelp(ctx));
+        ShellBundleActivator(std::shared_ptr<celix::IBundleContext> ctx) {
+            //TODO ensure fixed framework thread that call ctor/dtor bundle activators
+            registrations.push_back(impl::registerLb(ctx));
+            registrations.push_back(impl::registerHelp(ctx));
+            registrations.push_back(impl::registerStop(ctx));
+            registrations.push_back(impl::registerStart(ctx));
+            registrations.push_back(impl::registerInspect(ctx));
 
             registrations.push_back(ctx->registerService(std::shared_ptr<celix::IShell>{new Shell{ctx}}));
-
-            return true;
-        }
-
-        bool stop(std::shared_ptr<celix::IBundleContext>) noexcept override {
-            registrations.clear();
-            return true;
         }
     private:
-        std::vector<celix::ServiceRegistration> registrations;
+        std::vector<celix::ServiceRegistration> registrations{};
     };
-}
 
-__attribute__((constructor))
-static void registerShellBundle() {
-    celix::StaticBundleOptions opts{};
-    opts.bundleActivatorFactory = [](){
-        return new ShellBundleActivator{};
-    };
-    opts.manifest[celix::MANIFEST_BUNDLE_VERSION] = "1.0.0";
-    celix::registerStaticBundle("celix::Shell", opts);
-}
\ No newline at end of file
+    __attribute__((constructor))
+    static void registerShellBundle() {
+        celix::Properties manifest{};
+        manifest[celix::MANIFEST_BUNDLE_NAME] = "Shell";
+        manifest[celix::MANIFEST_BUNDLE_GROUP] = "Celix";
+        manifest[celix::MANIFEST_BUNDLE_VERSION] = "1.0.0";
+        celix::registerStaticBundle<ShellBundleActivator>("celix::Shell", manifest);
+    }
+}
diff --git a/bundles/shell/cxx_shell/src/StopAndStartCommand.cc b/bundles/shell/cxx_shell/src/StopAndStartCommand.cc
new file mode 100644
index 0000000..aae5a69
--- /dev/null
+++ b/bundles/shell/cxx_shell/src/StopAndStartCommand.cc
@@ -0,0 +1,75 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include "commands.h"
+
+#include <functional>
+
+#include "celix/api.h"
+#include "celix/IShellCommand.h"
+
+namespace {
+
+    void stopOrStart(std::shared_ptr<celix::IBundleContext> ctx, const std::string &cmdName, const std::vector<std::string> &cmdArgs, std::ostream &out, std::ostream &err) {
+        if (cmdArgs.empty()) {
+            out << "Provide a bundle id name to " << cmdName << std::endl;
+        } else {
+            for (const auto &bndId : cmdArgs) {
+                bool isNum = true;
+                for(const char &c : bndId) {
+                    isNum = isNum && isdigit(c);
+                }
+
+                if (isNum) {
+                    long id = atoi(bndId.c_str());
+                    if (cmdName == "stop") {
+                        ctx->stopBundle(id);
+                    } else {
+                        ctx->startBundle(id);
+                    }
+                } else {
+                    err << "Cannot parse '" << bndId << "' to bundle id" << std::endl;
+                }
+            }
+        }
+    }
+}
+
+
+celix::ServiceRegistration impl::registerStop(std::shared_ptr<celix::IBundleContext> ctx) {
+    using namespace std::placeholders;
+    celix::ShellCommandFunction stop = std::bind(&stopOrStart, ctx, _1, _2, _3, _4);
+
+    celix::Properties props{};
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME] = "stop";
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_USAGE] = "stop (bndId)+";
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_DESCRIPTION] = "Stops the provided bundles, identified by the bundle ids";
+    return ctx->registerFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, std::move(stop), std::move(props));
+}
+
+celix::ServiceRegistration impl::registerStart(std::shared_ptr<celix::IBundleContext> ctx) {
+    using namespace std::placeholders;
+    celix::ShellCommandFunction stop = std::bind(&stopOrStart, ctx, _1, _2, _3, _4);
+
+    celix::Properties props{};
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_NAME] = "start";
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_USAGE] = "start (bndId)+";
+    props[celix::SHELL_COMMAND_FUNCTION_COMMAND_DESCRIPTION] = "Starts the provided bundles, identified by the bundle ids";
+    return ctx->registerFunctionService(celix::SHELL_COMMAND_FUNCTION_SERVICE_FQN, std::move(stop), std::move(props));
+}
\ No newline at end of file
diff --git a/libs/framework_cxx/include/celix/IBundleActivator.h b/bundles/shell/cxx_shell/src/commands.h
similarity index 53%
copy from libs/framework_cxx/include/celix/IBundleActivator.h
copy to bundles/shell/cxx_shell/src/commands.h
index 1196e99..5f641b8 100644
--- a/libs/framework_cxx/include/celix/IBundleActivator.h
+++ b/bundles/shell/cxx_shell/src/commands.h
@@ -17,22 +17,21 @@
  *under the License.
  */
 
-#ifndef CXX_CELIX_IBUNDLEACTIVATOR_H
-#define CXX_CELIX_IBUNDLEACTIVATOR_H
+#ifndef CELIX_COMMANDS_H
+#define CELIX_COMMANDS_H
 
-#include <memory>
+#include "celix/api.h"
 
-#include "IBundleContext.h"
+namespace impl {
+    celix::ServiceRegistration registerLb(std::shared_ptr<celix::IBundleContext> ctx);
+    celix::ServiceRegistration registerHelp(std::shared_ptr<celix::IBundleContext> ctx);
+    celix::ServiceRegistration registerStop(std::shared_ptr<celix::IBundleContext> ctx);
+    celix::ServiceRegistration registerStart(std::shared_ptr<celix::IBundleContext> ctx);
+    celix::ServiceRegistration registerInspect(std::shared_ptr<celix::IBundleContext> ctx);
 
-namespace celix {
-    class IBundleActivator {
-    public:
-        virtual ~IBundleActivator() = default;
-
-        virtual bool resolve(std::shared_ptr<celix::IBundleContext> /*ctx*/) noexcept { return true; };
-        virtual bool start(std::shared_ptr<celix::IBundleContext> ctx) noexcept = 0;
-        virtual bool stop(std::shared_ptr<celix::IBundleContext> /*ctx*/) noexcept { return true; }
-    };
+    //query services, trackers & meta trackers TODO
+    // celix::ServiceRegistration registerQuery(std::shared_ptr<celix::IBundleContext> ctx);
 }
 
-#endif //CXX_CELIX_IBUNDLEACTIVATOR_H
+
+#endif //CELIX_COMMANDS_H
diff --git a/bundles/shell/cxx_shell/CMakeLists.txt b/bundles/shell/cxx_shell_tui/CMakeLists.txt
similarity index 60%
copy from bundles/shell/cxx_shell/CMakeLists.txt
copy to bundles/shell/cxx_shell_tui/CMakeLists.txt
index 070f05e..df20046 100644
--- a/bundles/shell/cxx_shell/CMakeLists.txt
+++ b/bundles/shell/cxx_shell_tui/CMakeLists.txt
@@ -17,21 +17,22 @@
 
 find_package(glog REQUIRED)
 
-#TODO rename to celix::shell && celix::shell_api
+#TODO rename to celix::shell_tui
 
-add_library(shell_api_cxx INTERFACE)
-target_include_directories(shell_api INTERFACE
-    $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
-    $<INSTALL_INTERFACE:include/celix/shell>
-)
-
-add_library(celix_shell_cxx STATIC
-        src/ShellActivator.cc
-        include/celix/IShell.h)
-target_include_directories(celix_shell_cxx PRIVATE src)
-target_include_directories(celix_shell_cxx PUBLIC include)
-target_link_libraries(celix_shell_cxx PRIVATE glog::glog celix_framework_cxx)
+#OR static lib, but then with all symbols to force constructor attribute
+add_library(celix_cxx_shell_tui SHARED
+        src/ShellTuiActivator.cc
+        src/shell_test.cc)
+target_include_directories(celix_cxx_shell_tui PRIVATE src)
+target_link_libraries(celix_cxx_shell_tui PRIVATE celix_cxx_shell_api)
+target_link_libraries(celix_cxx_shell_tui PUBLIC glog::glog celix_framework_cxx)
 
 #if (ENABLE_TESTING)
 #    add_subdirectory(gtest)
-#endif ()
\ No newline at end of file
+#endif ()
+
+
+add_executable(shell_test
+        src/shell_test.cc
+)
+target_link_libraries(shell_test PRIVATE celix_cxx_shell celix_cxx_shell_tui)
\ No newline at end of file
diff --git a/bundles/shell/CMakeLists.txt b/bundles/shell/cxx_shell_tui/gtest/CMakeLists.txt
similarity index 66%
copy from bundles/shell/CMakeLists.txt
copy to bundles/shell/cxx_shell_tui/gtest/CMakeLists.txt
index 2fd81dc..b4a7204 100644
--- a/bundles/shell/CMakeLists.txt
+++ b/bundles/shell/cxx_shell_tui/gtest/CMakeLists.txt
@@ -5,9 +5,9 @@
 # to you under the Apache License, Version 2.0 (the
 # "License"); you may not use this file except in compliance
 # with the License.  You may obtain a copy of the License at
-#
+# 
 #   http://www.apache.org/licenses/LICENSE-2.0
-#
+# 
 # Unless required by applicable law or agreed to in writing,
 # software distributed under the License is distributed on an
 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -15,9 +15,11 @@
 # specific language governing permissions and limitations
 # under the License.
 
-add_subdirectory(shell)
-add_subdirectory(remote_shell)
-add_subdirectory(shell_bonjour)
-add_subdirectory(shell_tui)
+set(SOURCES
+        src/main.cc
+)
+add_executable(celix_shell_cxx_tests ${SOURCES})
+target_link_libraries(celix_shell_cxx_tests PRIVATE gtest celix_framework_cxx celix_shell_cxx)
 
-add_subdirectory(cxx_shell)
+add_test(NAME celix_shell_cxx_tests COMMAND celix_shell_cxx_tests)
+SETUP_TARGET_FOR_COVERAGE(celix_shell_cxx_tests_cov celix_shell_cxx_tests ${CMAKE_BINARY_DIR}/coverage/celix_shell_cxx_tests/celix_shell_cxx_tests)
\ No newline at end of file
diff --git a/bundles/shell/cxx_shell/include/celix/IShell.h b/bundles/shell/cxx_shell_tui/gtest/src/main.cc
similarity index 66%
copy from bundles/shell/cxx_shell/include/celix/IShell.h
copy to bundles/shell/cxx_shell_tui/gtest/src/main.cc
index 9809ac5..a76daa7 100644
--- a/bundles/shell/cxx_shell/include/celix/IShell.h
+++ b/bundles/shell/cxx_shell_tui/gtest/src/main.cc
@@ -17,20 +17,17 @@
  *under the License.
  */
 
-#ifndef CXX_CELIX_ISHELL_H
-#define CXX_CELIX_ISHELL_H
+#include <gtest/gtest.h>
+#include <glog/logging.h>
 
-#include <iostream>
+int main(int argc, char **argv) {
+    google::InitGoogleLogging(argv[0]);
+    google::LogToStderr();
 
-namespace celix {
-    class IShell {
-    public:
-        static constexpr const char * const SERVICE_FQN = "celix::IShell [Version 1]";
+    ::testing::InitGoogleTest(&argc, argv);
+    int rc = RUN_ALL_TESTS();
 
-        virtual ~IShell() = default;
+    google::ShutdownGoogleLogging();
 
-        virtual bool executeCommand(const std::string &commandLine, std::ostream &out, std::ostream &err) noexcept = 0;
-    };
-}
-
-#endif //CXX_CELIX_ISHELL_H
+    return rc;
+}
\ No newline at end of file
diff --git a/bundles/shell/cxx_shell_tui/src/ShellTuiActivator.cc b/bundles/shell/cxx_shell_tui/src/ShellTuiActivator.cc
new file mode 100644
index 0000000..dc71faa
--- /dev/null
+++ b/bundles/shell/cxx_shell_tui/src/ShellTuiActivator.cc
@@ -0,0 +1,150 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include <thread>
+#include <cstdio>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <glog/logging.h>
+
+#include "celix/api.h"
+#include "celix/IShellCommand.h"
+#include "celix/IShell.h"
+
+static constexpr int LINE_SIZE = 256;
+static constexpr const char * const PROMPT = "-> ";
+
+static constexpr int KEY_ENTER = '\n';
+
+namespace {
+
+    class ShellTui {
+    public:
+        ShellTui() {
+            int fds[2];
+            int rc  = pipe(fds);
+            if (rc == 0) {
+                readPipeFd = fds[0];
+                writePipeFd = fds[1];
+                if(fcntl(writePipeFd, F_SETFL, O_NONBLOCK) == 0) {
+                    readThread = std::thread{&ShellTui::runnable, this};
+                } else {
+                    LOG(ERROR) << "fcntl on pipe failed" << std::endl;
+                }
+            } else {
+                LOG(ERROR) << "fcntl on pipe failed" << std::endl;
+            }
+        }
+
+        ~ShellTui() {
+            write(writePipeFd, "\0", 1); //trigger select to stop
+            readThread.join();
+        }
+
+        void runnable() {
+            //setup file descriptors
+            fd_set rfds;
+            int nfds = writePipeFd > STDIN_FILENO ? (writePipeFd +1) : (STDIN_FILENO + 1);
+
+            for (;;) {
+                writePrompt();
+                FD_ZERO(&rfds);
+                FD_SET(STDIN_FILENO, &rfds);
+                FD_SET(readPipeFd, &rfds);
+
+                if (select(nfds, &rfds, NULL, NULL, NULL) > 0) {
+                    if (FD_ISSET(readPipeFd, &rfds)) {
+                        break; //something is written to the pipe -> exit thread
+                    } else if (FD_ISSET(STDIN_FILENO, &rfds)) {
+                       parseInput();
+                    }
+                }
+            }
+        }
+
+        void writePrompt() {
+            std::cout << PROMPT;
+            std::flush(std::cout);
+        }
+
+        void parseInput() {
+            char* line = NULL;
+            int nr_chars = (int)read(STDIN_FILENO, buffer, LINE_SIZE-pos-1);
+            for (int bufpos = 0; bufpos < nr_chars; bufpos++) {
+                if (buffer[bufpos] == KEY_ENTER) { //end of line -> forward command
+                    line = in; // todo trim string
+                    std::lock_guard<std::mutex> lck{mutex};
+                    if (shell) {
+                        shell->executeCommandLine(line, std::cout, std::cerr);
+                    } else {
+                        std::cerr << "Shell service not available\n";
+                    }
+                    pos = 0;
+                    in[pos] = '\0';
+                } else { //text
+                    in[pos] = buffer[bufpos];
+                    in[pos + 1] = '\0';
+                    pos++;
+                    continue;
+                }
+            } //for
+        }
+
+        void setShell(std::shared_ptr<celix::IShell> _shell) {
+           std::lock_guard<std::mutex> lck{mutex};
+           shell = _shell;
+        }
+    private:
+        std::mutex mutex{};
+        std::shared_ptr<celix::IShell> shell{};
+
+        std::thread readThread;
+
+        int readPipeFd;
+        int writePipeFd;
+
+
+        char in[LINE_SIZE+1]{};
+        char buffer[LINE_SIZE+1]{};
+        int pos{};
+    };
+
+
+    class ShellTuiBundleActivator : public celix::IBundleActivator {
+    public:
+        ShellTuiBundleActivator(std::shared_ptr<celix::IBundleContext> ctx) {
+            celix::ServiceTrackerOptions<celix::IShell> opts{};
+            opts.set = std::bind(&ShellTui::setShell, &tui, std::placeholders::_1);
+            trk = ctx->trackServices(opts);
+        }
+    private:
+        ShellTui tui{};
+        celix::ServiceTracker trk;
+    };
+
+    __attribute__((constructor))
+    static void registerShellBundle() {
+        celix::Properties manifest{};
+        manifest[celix::MANIFEST_BUNDLE_NAME] = "Shell Tui";
+        manifest[celix::MANIFEST_BUNDLE_GROUP] = "Celix";
+        manifest[celix::MANIFEST_BUNDLE_VERSION] = "1.0.0";
+        celix::registerStaticBundle<ShellTuiBundleActivator>("celix::ShellTui", manifest);
+    }
+}
\ No newline at end of file
diff --git a/bundles/shell/cxx_shell/include/celix/IShell.h b/bundles/shell/cxx_shell_tui/src/shell_test.cc
similarity index 68%
copy from bundles/shell/cxx_shell/include/celix/IShell.h
copy to bundles/shell/cxx_shell_tui/src/shell_test.cc
index 9809ac5..cd3af3c 100644
--- a/bundles/shell/cxx_shell/include/celix/IShell.h
+++ b/bundles/shell/cxx_shell_tui/src/shell_test.cc
@@ -17,20 +17,19 @@
  *under the License.
  */
 
-#ifndef CXX_CELIX_ISHELL_H
-#define CXX_CELIX_ISHELL_H
-
 #include <iostream>
 
-namespace celix {
-    class IShell {
-    public:
-        static constexpr const char * const SERVICE_FQN = "celix::IShell [Version 1]";
+#include <glog/logging.h>
+
+#include "celix/api.h"
 
-        virtual ~IShell() = default;
 
-        virtual bool executeCommand(const std::string &commandLine, std::ostream &out, std::ostream &err) noexcept = 0;
-    };
-}
+int main(int /*argc*/, char **argv) {
+    google::InitGoogleLogging(argv[0]);
+    google::LogToStderr();
 
-#endif //CXX_CELIX_ISHELL_H
+    auto fw = celix::Framework{};
+    std::cout << "Waiting for Framework shutdown\n";
+    fw.waitForShutdown();
+    return 0;
+}
\ No newline at end of file
diff --git a/cmake/celix_project/AddGTest.cmake b/cmake/celix_project/AddGTest.cmake
index a1753a8..93227c1 100644
--- a/cmake/celix_project/AddGTest.cmake
+++ b/cmake/celix_project/AddGTest.cmake
@@ -30,7 +30,7 @@ file(MAKE_DIRECTORY ${source_dir}/googletest/include)
 add_library(gtest IMPORTED STATIC GLOBAL)
 add_dependencies(gtest googletest_project)
 set_target_properties(gtest PROPERTIES
-        IMPORTED_LOCATION "${binary_dir}/lib/libgtest.a"
+        IMPORTED_LOCATION "${binary_dir}/googlemock/gtest/libgtest.a"
         INTERFACE_INCLUDE_DIRECTORIES "${source_dir}/googletest/include"
 )
 
@@ -38,6 +38,6 @@ file(MAKE_DIRECTORY ${source_dir}/googlemock/include)
 add_library(gmock IMPORTED STATIC GLOBAL)
 add_dependencies(gmock googletest_project)
 set_target_properties(gmock PROPERTIES
-        IMPORTED_LOCATION "${binary_dir}/lib/libgmock.a"
+        IMPORTED_LOCATION "${binary_dir}/googlemock/libgmock.a"
         INTERFACE_INCLUDE_DIRECTORIES "${source_dir}/googlemock/include"
 )
diff --git a/libs/framework_cxx/gtest/src/Framework_tests.cc b/libs/framework_cxx/gtest/src/Framework_tests.cc
index 34cad54..7afd9a1 100644
--- a/libs/framework_cxx/gtest/src/Framework_tests.cc
+++ b/libs/framework_cxx/gtest/src/Framework_tests.cc
@@ -44,80 +44,71 @@ TEST_F(FrameworkTest, CreateDestroy) {
     EXPECT_TRUE(isFramework);
 }
 
-TEST_F(FrameworkTest, InstallBundle) {
+class EmbeddedActivator : public celix::IBundleActivator {
+public:
+    EmbeddedActivator(std::shared_ptr<celix::IBundleContext>) {
+        startCount++;
+    }
 
-    class EmbeddedActivator : public celix::IBundleActivator {
-    public:
-        virtual ~EmbeddedActivator() = default;
+    virtual ~EmbeddedActivator() {
+        stopCount++;
+    }
 
-        bool resolve(std::shared_ptr<celix::IBundleContext> ctx) noexcept override {
-            EXPECT_GE(ctx->bundle()->id(), 1);
-            resolveCalled = true;
-            return true;
-        }
-
-        bool start(std::shared_ptr<celix::IBundleContext>) noexcept override {
-            startCalled = true;
-            return true;
-        }
-
-        bool stop(std::shared_ptr<celix::IBundleContext>) noexcept override {
-            stopCalled = true;
-            return true;
-        }
-
-        bool resolveCalled = false;
-        bool startCalled = false;
-        bool stopCalled = false;
-    };
+    static std::atomic<int> startCount;
+    static std::atomic<int> stopCount;
+};
 
-    long bndId1 = framework().installBundle<EmbeddedActivator>("embedded");
+std::atomic<int> EmbeddedActivator::startCount{0};
+std::atomic<int> EmbeddedActivator::stopCount{0};
+
+TEST_F(FrameworkTest, InstallBundle) {
+    EmbeddedActivator::startCount = 0;
+    EmbeddedActivator::stopCount = 0;
+
+    auto actFactory = [](std::shared_ptr<celix::IBundleContext> ctx) -> celix::IBundleActivator* {
+        return new EmbeddedActivator{std::move(ctx)};
+    };
+    long bndId1 = framework().installBundle("embedded", actFactory);
     EXPECT_GE(bndId1, 0);
+    EXPECT_EQ(1, EmbeddedActivator::startCount);
+    EXPECT_EQ(0, EmbeddedActivator::stopCount);
 
-    std::shared_ptr<EmbeddedActivator> act{new EmbeddedActivator};
-    long bndId2 = framework().installBundle("embedded2", act);
+    long bndId2 = framework().installBundle<EmbeddedActivator>("embedded2");
     EXPECT_GE(bndId2, 0);
     EXPECT_NE(bndId1, bndId2);
-    EXPECT_TRUE(act->resolveCalled);
-    EXPECT_TRUE(act->startCalled);
-    EXPECT_FALSE(act->stopCalled);
+    EXPECT_EQ(2, EmbeddedActivator::startCount);
+    EXPECT_EQ(0, EmbeddedActivator::stopCount);
 
     framework().stopBundle(bndId2);
-    EXPECT_TRUE(act->stopCalled);
+    EXPECT_EQ(1, EmbeddedActivator::stopCount);
 
-    std::shared_ptr<EmbeddedActivator> act3{new EmbeddedActivator};
     {
         celix::Framework fw{};
-        fw.installBundle("embedded3", act3);
-        EXPECT_TRUE(act3->resolveCalled);
-        EXPECT_TRUE(act3->startCalled);
-        EXPECT_FALSE(act3->stopCalled);
+        fw.installBundle<EmbeddedActivator>("embedded3");
+        EXPECT_EQ(3, EmbeddedActivator::startCount);
+        EXPECT_EQ(1, EmbeddedActivator::stopCount);
 
         //NOTE fw out of scope -> bundle stopped
     }
-    EXPECT_TRUE(act3->stopCalled);
+    EXPECT_EQ(3, EmbeddedActivator::startCount);
+    EXPECT_EQ(2, EmbeddedActivator::stopCount);
 }
 
 TEST_F(FrameworkTest, StaticBundleTest) {
     class EmbeddedActivator : public celix::IBundleActivator {
     public:
+        EmbeddedActivator() {}
         virtual ~EmbeddedActivator() = default;
-
-        bool start(std::shared_ptr<celix::IBundleContext>) noexcept override {
-            return true;
-        }
     };
 
     int count = 0;
-    auto factory = [&]() -> celix::IBundleActivator * {
+    auto factory = [&](std::shared_ptr<celix::IBundleContext>) -> celix::IBundleActivator * {
         count++;
         return new EmbeddedActivator{};
     };
 
     EXPECT_EQ(0, framework().listBundles().size()); //no bundles installed;
-    celix::StaticBundleOptions opts;
-    opts.bundleActivatorFactory = std::move(factory);
-    celix::registerStaticBundle("static", opts);
+    celix::registerStaticBundle("static", factory);
     EXPECT_EQ(1, framework().listBundles().size()); //static bundle instance installed
     EXPECT_EQ(1, count);
 
diff --git a/libs/framework_cxx/include/celix/Framework.h b/libs/framework_cxx/include/celix/Framework.h
index 60b6fca..a2d9b13 100644
--- a/libs/framework_cxx/include/celix/Framework.h
+++ b/libs/framework_cxx/include/celix/Framework.h
@@ -30,25 +30,25 @@
 
 namespace celix {
 
-    struct StaticBundleOptions {
-        std::string name{};
-        std::string group{};
-        std::string version{};
-        celix::Properties manifest{};
-
-        std::function<celix::IBundleActivator*()> bundleActivatorFactory{};
-
-        //TODO resources. poiting to bundle specific symbols which is linked zip file
-        char * const resoucreZip = nullptr;
-        size_t resourceZipLength = 0;
-    };
-
-    void registerStaticBundle(std::string symbolicName, const StaticBundleOptions &opts);
-    //TODO useFrameworks with a callback with as argument a fw ref
+    //TODO resources. resolved from bundle specific symbols which is linked zip file to the library
+    void registerStaticBundle(
+            std::string symbolicName,
+            std::function<celix::IBundleActivator*(std::shared_ptr<celix::IBundleContext>)> bundleActivatorFactory = {},
+            celix::Properties manifest = {});
+
+    template<typename T>
+    void registerStaticBundle(
+            std::string symbolicName,
+            celix::Properties manifest = {}) {
+        auto actFactory = [](std::shared_ptr<celix::IBundleContext> ctx) {
+            return new T{std::move(ctx)};
+        };
+        celix::registerStaticBundle(std::move(symbolicName), actFactory, std::move(manifest));
+    }
 
     class Framework {
     public:
-        Framework();
+        Framework(celix::Properties config = {});
         ~Framework();
         Framework(Framework &&rhs);
         Framework& operator=(Framework&& rhs);
@@ -56,14 +56,15 @@ namespace celix {
         Framework(const Framework& rhs) = delete;
         Framework& operator=(const Framework &rhs) = delete;
 
-
         template<typename T>
-        long installBundle(std::string symbolicName, celix::Properties manifest = {}, bool autoStart = true) {
-            std::shared_ptr<celix::IBundleActivator> activator{new T{}};
-            return installBundle(std::move(symbolicName), std::move(activator), std::move(manifest), autoStart);
+        long installBundle(std::string name, celix::Properties manifest = {}, bool autoStart = true) {
+            auto actFactory = [](std::shared_ptr<celix::IBundleContext> ctx) {
+                return new T{std::move(ctx)};
+            };
+            return installBundle(name, std::move(actFactory), manifest, autoStart);
         }
 
-        long installBundle(std::string symbolicName, std::shared_ptr<celix::IBundleActivator> activator, celix::Properties manifest = {}, bool autoStart = true);
+        long installBundle(std::string name, std::function<celix::IBundleActivator*(std::shared_ptr<celix::IBundleContext>)> actFactory, celix::Properties manifest = {}, bool autoStart = true);
 
 
         //long installBundle(const std::string &path);
@@ -78,6 +79,8 @@ namespace celix {
         std::vector<long> listBundles(bool includeFrameworkBundle = false) const;
 
         celix::ServiceRegistry& registry(const std::string &lang);
+
+        bool waitForShutdown() const;
     private:
         class Impl;
         std::unique_ptr<Impl> pimpl;
diff --git a/libs/framework_cxx/include/celix/IBundle.h b/libs/framework_cxx/include/celix/IBundle.h
index a8d0de1..9f2e8a8 100644
--- a/libs/framework_cxx/include/celix/IBundle.h
+++ b/libs/framework_cxx/include/celix/IBundle.h
@@ -27,7 +27,6 @@ namespace celix {
 
     enum class BundleState {
         INSTALLED,
-        RESOLVED,
         ACTIVE,
     };
 
diff --git a/libs/framework_cxx/include/celix/IBundleActivator.h b/libs/framework_cxx/include/celix/IBundleActivator.h
index 1196e99..a3ccd92 100644
--- a/libs/framework_cxx/include/celix/IBundleActivator.h
+++ b/libs/framework_cxx/include/celix/IBundleActivator.h
@@ -25,13 +25,17 @@
 #include "IBundleContext.h"
 
 namespace celix {
+    /**
+     * The BundleActivator.
+     *
+     * This is a marker interface and contains no virtual methods.
+     *
+     * The Celix Framework will expect a constructor with a std::shared_ptr<celix::IBundleContext> argument on the
+     * contrete bundle activator. RAII will be used to start (on ctor) and stop (on dtor) a bundle.
+     */
     class IBundleActivator {
     public:
         virtual ~IBundleActivator() = default;
-
-        virtual bool resolve(std::shared_ptr<celix::IBundleContext> /*ctx*/) noexcept { return true; };
-        virtual bool start(std::shared_ptr<celix::IBundleContext> ctx) noexcept = 0;
-        virtual bool stop(std::shared_ptr<celix::IBundleContext> /*ctx*/) noexcept { return true; }
     };
 }
 
diff --git a/libs/framework_cxx/include/celix/IBundleContext.h b/libs/framework_cxx/include/celix/IBundleContext.h
index e77623a..553372a 100644
--- a/libs/framework_cxx/include/celix/IBundleContext.h
+++ b/libs/framework_cxx/include/celix/IBundleContext.h
@@ -51,6 +51,10 @@ namespace celix {
         virtual bool useBundle(long bndId, std::function<void(const celix::IBundle &bnd)> use) const noexcept = 0;
         virtual int useBundles(std::function<void(const celix::IBundle &bnd)> use, bool includeFrameworkBundle = true) const noexcept = 0;
 
+        virtual bool stopBundle(long bndId) noexcept = 0;
+        virtual bool startBundle(long bndId) noexcept = 0;
+        //TODO install / uninstall bundles
+
         template<typename I>
         bool useService(std::function<void(I &svc)> use, const std::string &filter = "") const noexcept {
             return registry().useService<I>(std::move(use), filter, bundle());
@@ -128,7 +132,8 @@ namespace celix {
         //TODO track trackers
 
         //TODO track c trackers
-    private:
+
+
         virtual celix::ServiceRegistry& registry() const noexcept = 0;
         virtual celix::ServiceRegistry& cRegistry() const noexcept = 0;
     };
diff --git a/libs/framework_cxx/src/BundleImpl.h b/libs/framework_cxx/src/BundleImpl.h
index ab49636..dd2c53f 100644
--- a/libs/framework_cxx/src/BundleImpl.h
+++ b/libs/framework_cxx/src/BundleImpl.h
@@ -47,20 +47,29 @@ namespace impl {
             int useBundles(std::function<void(const celix::IBundle &bnd)> use, bool includeFrameworkBundle = true) const noexcept override {
                 return bnd->framework().useBundles(std::move(use), includeFrameworkBundle);
             }
+
+            bool stopBundle(long bndId) noexcept override {
+                return bnd->framework().stopBundle(bndId);
+            }
+
+            bool startBundle(long bndId) noexcept override {
+                return bnd->framework().startBundle(bndId);
+            }
+
         private:
             celix::ServiceRegistry& registry() const noexcept override { return *reg; }
             celix::ServiceRegistry& cRegistry() const noexcept override { return *cReg; }
 
             const std::shared_ptr<celix::IBundle> bnd;
-            const std::shared_ptr<celix::ServiceRegistry> reg;
-            const std::shared_ptr<celix::ServiceRegistry> cReg;
+            celix::ServiceRegistry * const reg; //TODO make weak_ptr
+            celix::ServiceRegistry * const cReg; //TODO make weak_ptr
         };
 
 
         class Bundle : public celix::IBundle {
         public:
-            Bundle(long _bndId, celix::Framework *_fw, celix::Properties _manifest, std::shared_ptr<celix::IBundleActivator> _activator) :
-            bndId{_bndId}, fw{_fw}, bndManifest{std::move(_manifest)}, activator{std::move(_activator)} {
+            Bundle(long _bndId, celix::Framework *_fw, celix::Properties _manifest) :
+            bndId{_bndId}, fw{_fw}, bndManifest{std::move(_manifest)} {
                 bndState.store(BundleState::INSTALLED, std::memory_order_release);
             }
 
@@ -100,7 +109,6 @@ namespace impl {
             const long bndId;
             celix::Framework * const fw;
             const celix::Properties bndManifest;
-            const std::shared_ptr<celix::IBundleActivator> activator;
             std::weak_ptr<celix::IBundleContext> context;
 
             std::atomic<BundleState> bndState;
@@ -109,10 +117,10 @@ namespace impl {
     class BundleController {
     public:
         BundleController(
-                std::shared_ptr<celix::IBundleActivator> _act,
+                std::function<celix::IBundleActivator*(std::shared_ptr<celix::IBundleContext>)> _actFactory,
                 std::shared_ptr<celix::impl::Bundle> _bnd,
                 std::shared_ptr<celix::impl::BundleContext> _ctx) :
-                act{std::move(_act)}, bnd{std::move(_bnd)}, ctx{std::move(_ctx)} {}
+                actFactory{std::move(_actFactory)}, bnd{std::move(_bnd)}, ctx{std::move(_ctx)} {}
 
         //specific part
         bool transitionTo(BundleState desired) {
@@ -122,39 +130,14 @@ namespace impl {
             if (state == desired) {
                 //nop
                 success = true;
-            } else if (state == BundleState::INSTALLED && desired == BundleState::RESOLVED) {
-                //TODO create cache dir for bundle
-                bool resolved = act->resolve(ctx);
-                if (resolved) {
-                    bnd->setState(BundleState::RESOLVED);
-                    success = true;
-                } else {
-                    LOG(WARNING) << "Transition to resolved state for bundle " << bnd->symbolicName() << " (" << bnd->id() << ") failed." << std::endl;
-                }
-
-            } else if (state == BundleState::RESOLVED && desired == BundleState::ACTIVE) {
-                bool started = act->start(ctx);
-                if (started) {
-                    bnd->setState(BundleState::ACTIVE);
-                    success = true;
-                } else {
-                    LOG(WARNING) << "Transition to active state for bundle " << bnd->symbolicName() << " (" << bnd->id() << ") failed." << std::endl;
-                }
-            } else if (state == BundleState::ACTIVE && desired == BundleState::RESOLVED ) {
-                bool stopped = act->stop(ctx);
-                if (stopped) {
-                    bnd->setState(BundleState::RESOLVED);
-                    success = true;
-
-                    //TODO use custom deleter to check this (use_count call is a race condition)
-                    bool unique  = ctx.use_count() == 1;
-                    if (!unique) {
-                        LOG(WARNING) << "Bundle Context is not unique. ";
-                        LOG(WARNING) << "Check if there are still some dangling references to the context of the stopped bundle." << std::endl;
-                    }
-                } else {
-                    LOG(WARNING) << "Transition to resolved state for bundle " << bnd->symbolicName() << " (" << bnd->id() << ") failed." << std::endl;
-                }
+            } else if (state == BundleState::INSTALLED && desired == BundleState::ACTIVE) {
+                act = std::unique_ptr<celix::IBundleActivator>{actFactory(ctx)};
+                bnd->setState(BundleState::ACTIVE);
+                success = true;
+            } else if (state == BundleState::ACTIVE && desired == BundleState::INSTALLED ) {
+                act = nullptr;
+                bnd->setState(BundleState::INSTALLED);
+                success = true;
             } else {
                 //LOG(ERROR) << "Unexpected desired state " << desired << " from state " << bndState << std::endl;
                 LOG(ERROR) << "Unexpected desired/form state combination " << std::endl;
@@ -162,15 +145,15 @@ namespace impl {
             return success;
         }
 
-        std::shared_ptr<celix::IBundleActivator> activator() const { return act; }
         std::shared_ptr<celix::impl::Bundle> bundle() const { return bnd; }
         std::shared_ptr<celix::impl::BundleContext> context() const { return ctx; }
     private:
-        const std::shared_ptr<celix::IBundleActivator> act;
+        const std::function<celix::IBundleActivator*(std::shared_ptr<celix::IBundleContext>)> actFactory;
         const std::shared_ptr<celix::impl::Bundle> bnd;
         const std::shared_ptr<celix::impl::BundleContext> ctx;
 
         mutable std::mutex mutex{};
+        std::unique_ptr<celix::IBundleActivator> act{nullptr};
     };
 }
 };
diff --git a/libs/framework_cxx/src/Framework.cc b/libs/framework_cxx/src/Framework.cc
index a224720..cb5b6ed 100644
--- a/libs/framework_cxx/src/Framework.cc
+++ b/libs/framework_cxx/src/Framework.cc
@@ -26,6 +26,7 @@
 #include <iostream>
 #include <set>
 #include <vector>
+#include <future>
 
 #include <glog/logging.h>
 
@@ -36,7 +37,7 @@
 struct StaticBundleEntry {
     const std::string symbolicName;
     const celix::Properties manifest;
-    const std::function<celix::IBundleActivator*()> activatorFactory;
+    const std::function<celix::IBundleActivator*(std::shared_ptr<celix::IBundleContext>)> activatorFactory;
 };
 
 static struct {
@@ -51,10 +52,11 @@ static void unregisterFramework(celix::Framework *fw);
 
 class celix::Framework::Impl : public IBundle {
 public:
-    Impl(celix::Framework *_fw) : fw{_fw}, bndManifest{createManifest()}, cwd{createCwd()} {}
+    Impl(celix::Framework *_fw, celix::Properties _config) : fw{_fw}, config{std::move(_config)}, bndManifest{createManifest()}, cwd{createCwd()} {}
 
     ~Impl() {
         stopFramework();
+        waitForShutdown();
     }
 
     std::vector<long> listBundles(bool includeFrameworkBundle) const {
@@ -70,9 +72,15 @@ public:
         return result;
     }
 
-    long installBundle(std::string symbolicName, std::shared_ptr<celix::IBundleActivator> activator, celix::Properties manifest, bool autoStart) {
+    long installBundle(std::string symbolicName, std::function<celix::IBundleActivator*(std::shared_ptr<celix::IBundleContext>)> actFactory, celix::Properties manifest, bool autoStart) {
+        //TODO if activator is nullptr -> use empty activator
         //TODO on separate thread ?? specific bundle resolve thread ??
         long bndId = -1L;
+        if (symbolicName.empty()) {
+            LOG(WARNING) << "Cannot install bundle with a empty symbolic name" << std::endl;
+            return bndId;
+        }
+
         std::shared_ptr<celix::impl::BundleController> bndController{nullptr};
         {
             manifest[celix::MANIFEST_BUNDLE_SYMBOLIC_NAME] = symbolicName;
@@ -88,9 +96,9 @@ public:
 
             std::lock_guard<std::mutex> lck{bundles.mutex};
             bndId = bundles.nextBundleId++;
-            auto bnd = std::shared_ptr<celix::impl::Bundle>{new celix::impl::Bundle{bndId, this->fw, std::move(manifest), std::move(activator)}};
+            auto bnd = std::shared_ptr<celix::impl::Bundle>{new celix::impl::Bundle{bndId, this->fw, std::move(manifest)}};
             auto ctx = std::shared_ptr<celix::impl::BundleContext>{new celix::impl::BundleContext{bnd}};
-            bndController = std::shared_ptr<celix::impl::BundleController>{new celix::impl::BundleController{activator, bnd, ctx}};
+            bndController = std::shared_ptr<celix::impl::BundleController>{new celix::impl::BundleController{std::move(actFactory), bnd, ctx}};
             bundles.entries.emplace(std::piecewise_construct,
                                      std::forward_as_tuple(bndId),
                                      std::forward_as_tuple(bndController));
@@ -99,26 +107,32 @@ public:
         }
 
         if (bndController) {
-            bool successful = bndController->transitionTo(BundleState::RESOLVED);
-            if (successful && autoStart) {
-                successful = bndController->transitionTo(BundleState::ACTIVE);
+            if (autoStart) {
+                bool successful = bndController->transitionTo(BundleState::ACTIVE);
                 if (!successful) {
                     LOG(WARNING) << "Cannot start bundle " << bndController->bundle()->symbolicName() << std::endl;
                 }
-            } else {
-                LOG(WARNING) << "Cannot resolve bundle " << bndController->bundle()->symbolicName() << std::endl;
             }
-            //TODO decrease bnd entry usage
         }
+
         return bndId;
     }
 
     bool startBundle(long bndId) {
-        return transitionBundleTo(bndId, BundleState::ACTIVE);
+        if (bndId == this->fwBndId) {
+            //TODO
+            return false;
+        } else {
+            return transitionBundleTo(bndId, BundleState::ACTIVE);
+        }
     }
 
     bool stopBundle(long bndId) {
-        return transitionBundleTo(bndId, BundleState::RESOLVED);
+        if (bndId == this->fwBndId) {
+            return stopFramework();
+        } else {
+            return transitionBundleTo(bndId, BundleState::INSTALLED);
+        }
     }
 
     bool uninstallBundle(long bndId) {
@@ -134,11 +148,10 @@ public:
             }
         }
         if (removed) {
-            bool resolved = removed->transitionTo(BundleState::RESOLVED);
-            if (resolved) {
-                uninstalled = true;
-                bool unique = removed.unique();
-                assert(unique); //TODO cond / wait ?
+            bool stopped = removed->transitionTo(BundleState::INSTALLED);
+            if (stopped) {
+                //TODO check and wait till bundle is not used anymore. is this needed (shared_ptr) or just let access
+                //to filesystem fail ...
             } else {
                 //add bundle again -> not uninstalled
                 std::lock_guard<std::mutex> lck{bundles.mutex};
@@ -245,15 +258,29 @@ public:
     celix::Framework& framework() const noexcept override { return *fw; }
 
     bool stopFramework() {
-        std::vector<long> bundles = listBundles(false);
-        while (!bundles.empty()) {
-            for (auto it = bundles.rbegin(); it != bundles.rend(); ++it) {
-                stopBundle(*it);
-                uninstallBundle(*it);
-            }
-            bundles = listBundles(false);
+        std::lock_guard<std::mutex> lck{shutdown.mutex};
+        if (!shutdown.shutdownStarted) {
+            shutdown.future = std::async(std::launch::async, [this]{
+                std::vector<long> bundles = listBundles(false);
+                while (!bundles.empty()) {
+                    for (auto it = bundles.rbegin(); it != bundles.rend(); ++it) {
+                        stopBundle(*it);
+                        uninstallBundle(*it);
+                    }
+                    bundles = listBundles(false);
+                }
+            });
+            shutdown.shutdownStarted = true;
+            shutdown.cv.notify_all();
         }
+        return true;
+    }
 
+    bool waitForShutdown() const {
+        std::unique_lock<std::mutex> lck{shutdown.mutex};
+        shutdown.cv.wait(lck, [this]{return this->shutdown.shutdownStarted;});
+        shutdown.future.wait();
+        lck.unlock();
         return true;
     }
 private:
@@ -275,10 +302,22 @@ private:
         }
     }
 
+    const long fwBndId = 1L;
     celix::Framework * const fw;
+    const celix::Properties config;
     const celix::Properties bndManifest;
     const std::string cwd;
 
+
+    struct {
+        mutable std::mutex mutex{};
+        mutable std::condition_variable cv{};
+        std::future<void> future{};
+        bool shutdownStarted = false;
+    } shutdown{};
+
+
+
     struct {
         std::unordered_map<long, std::shared_ptr<celix::impl::BundleController>> entries{};
         long nextBundleId = 2;
@@ -295,9 +334,9 @@ private:
  * Framework
  **********************************************************************************************************************/
 
-celix::Framework::Framework() {
-    pimpl = std::unique_ptr<Impl>{new Impl{this}};
-    registerFramework(this); //TODO improve ugly.. maybe register impl.. but that is private -> so make register static member functions of impl...
+celix::Framework::Framework(celix::Properties config) {
+    pimpl = std::unique_ptr<Impl>{new Impl{this, std::move(config)}};
+    registerFramework(this);
 }
 celix::Framework::~Framework() {
     unregisterFramework(this);
@@ -305,10 +344,12 @@ celix::Framework::~Framework() {
 celix::Framework::Framework(Framework &&rhs) = default;
 celix::Framework& celix::Framework::operator=(Framework&& rhs) = default;
 
-long celix::Framework::installBundle(std::string name, std::shared_ptr<celix::IBundleActivator> activator, celix::Properties manifest, bool autoStart) {
-    return pimpl->installBundle(std::move(name), std::move(activator), std::move(manifest), autoStart);
+
+long celix::Framework::installBundle(std::string name, std::function<celix::IBundleActivator*(std::shared_ptr<celix::IBundleContext>)> actFactory, celix::Properties manifest, bool autoStart) {
+    return pimpl->installBundle(std::move(name), actFactory, std::move(manifest), autoStart);
 }
 
+
 std::vector<long> celix::Framework::listBundles(bool includeFrameworkBundle) const { return pimpl->listBundles(includeFrameworkBundle); }
 
 bool celix::Framework::useBundle(long bndId, std::function<void(const celix::IBundle &bnd)> use) const {
@@ -324,23 +365,28 @@ bool celix::Framework::stopBundle(long bndId) { return pimpl->stopBundle(bndId);
 bool celix::Framework::uninstallBundle(long bndId) { return pimpl->uninstallBundle(bndId); }
 celix::ServiceRegistry& celix::Framework::registry(const std::string &lang) { return pimpl->registry(lang); }
 
+bool celix::Framework::waitForShutdown() const { return pimpl->waitForShutdown(); }
+
 /***********************************************************************************************************************
  * Celix 'global' functions
  **********************************************************************************************************************/
 
-void celix::registerStaticBundle(std::string symbolicName, const celix::StaticBundleOptions &opts) {
+void celix::registerStaticBundle(
+        std::string symbolicName,
+        std::function<celix::IBundleActivator*(std::shared_ptr<celix::IBundleContext>)> bundleActivatorFactory,
+        celix::Properties manifest) {
     std::lock_guard<std::mutex> lck{staticRegistry.mutex};
-    staticRegistry.bundles.emplace_back(StaticBundleEntry{.symbolicName = std::move(symbolicName), .manifest = opts.manifest, .activatorFactory = opts.bundleActivatorFactory});
     for (auto fw : staticRegistry.frameworks) {
-        fw->installBundle(symbolicName, std::shared_ptr<celix::IBundleActivator>{opts.bundleActivatorFactory()}, opts.manifest);
+        fw->installBundle(symbolicName, bundleActivatorFactory, manifest);
     }
+    staticRegistry.bundles.emplace_back(StaticBundleEntry{.symbolicName = std::move(symbolicName), .manifest = std::move(manifest), .activatorFactory = std::move(bundleActivatorFactory)});
 }
 
 static void registerFramework(celix::Framework *fw) {
     std::lock_guard<std::mutex> lck{staticRegistry.mutex};
     staticRegistry.frameworks.insert(fw);
     for (auto &entry : staticRegistry.bundles) {
-        fw->installBundle(entry.symbolicName, std::shared_ptr<celix::IBundleActivator>{entry.activatorFactory()}, entry.manifest);
+        fw->installBundle(entry.symbolicName, entry.activatorFactory, entry.manifest);
     }
 }
 
diff --git a/libs/registry/gtest/src/RegistryConcurrency_tests.cc b/libs/registry/gtest/src/RegistryConcurrency_tests.cc
index c77c198..f7e86d3 100644
--- a/libs/registry/gtest/src/RegistryConcurrency_tests.cc
+++ b/libs/registry/gtest/src/RegistryConcurrency_tests.cc
@@ -29,8 +29,7 @@ public:
 
     celix::ServiceRegistry& registry() { return reg; }
 private:
-    celix::ServiceRegistry reg{"C/C++"};
-};
+    celix::ServiceRegistry reg{"C++"};
 
 class ICalc {
 public:
diff --git a/libs/registry/gtest/src/Registry_tests.cc b/libs/registry/gtest/src/Registry_tests.cc
index 8c00b11..9bbb899 100644
--- a/libs/registry/gtest/src/Registry_tests.cc
+++ b/libs/registry/gtest/src/Registry_tests.cc
@@ -30,7 +30,7 @@ public:
 
     celix::ServiceRegistry& registry() { return reg; }
 private:
-    celix::ServiceRegistry reg{"C/C++"};
+    celix::ServiceRegistry reg{"C++"};
 };
 
 class MarkerInterface1 {
@@ -264,6 +264,27 @@ TEST_F(RegistryTest, StdFunctionTest) {
     });
 }
 
+TEST_F(RegistryTest, ListServicesTest) {
+    std::vector<std::string> serviceNames = registry().listAllRegisteredServiceNames();
+    EXPECT_EQ(0, serviceNames.size());
+
+    std::function<void()> nop = []{/*nop*/};
+    class MarkerInterface1 {};
+    MarkerInterface1 intf1;
+
+    {
+        auto reg1 = registry().registerFunctionService("nop", nop);
+        serviceNames = registry().listAllRegisteredServiceNames();
+        EXPECT_EQ(1, serviceNames.size());
+
+        auto reg2 = registry().registerService(intf1);
+        serviceNames = registry().listAllRegisteredServiceNames();
+        EXPECT_EQ(2, serviceNames.size());
+    }
+    serviceNames = registry().listAllRegisteredServiceNames();
+    EXPECT_EQ(0, serviceNames.size());
+}
+
 //TODO function use with props and bnd
 //TODO use with filter
 //TODO use with sync test (see BundleContext tests)
\ No newline at end of file
diff --git a/libs/registry/gtest/src/ServiceTracking_tests.cc b/libs/registry/gtest/src/ServiceTracking_tests.cc
index 7a88f1b..035e8a9 100644
--- a/libs/registry/gtest/src/ServiceTracking_tests.cc
+++ b/libs/registry/gtest/src/ServiceTracking_tests.cc
@@ -28,7 +28,7 @@ class ServiceTrackingTest : public ::testing::Test {
 public:
     celix::ServiceRegistry& registry() { return reg; }
 private:
-    celix::ServiceRegistry reg{"C/C++"};
+    celix::ServiceRegistry reg{"C++"};
 };
 
 class MarkerInterface1 {
@@ -62,9 +62,9 @@ TEST_F(ServiceTrackingTest, CreateTrackersTest) {
 }
 
 TEST_F(ServiceTrackingTest, ServicesCountTrackersTest) {
-    MarkerInterface1 intf1;
-    MarkerInterface2 intf2;
-    MarkerInterface3 intf3;
+    MarkerInterface1 intf1{};
+    MarkerInterface2 intf2{};
+    MarkerInterface3 intf3{};
 
     auto trk1 = registry().trackServices<MarkerInterface1>();
     ASSERT_EQ(0, trk1.trackCount());
@@ -103,17 +103,17 @@ TEST_F(ServiceTrackingTest, ServicesCountTrackersTest) {
 }
 
 TEST_F(ServiceTrackingTest, SetServiceTest) {
-    MarkerInterface1 intf1;
-    MarkerInterface2 intf2;
-    MarkerInterface3 intf3;
+    MarkerInterface1 intf1{};
+    MarkerInterface2 intf2{};
+    MarkerInterface3 intf3{};
 
     MarkerInterface1 *ptrToSvc = nullptr;
     //const celix::Properties *ptrToProps = nullptr;
     //const celix::IBundle *ptrToBnd = nullptr;
 
     celix::ServiceTrackerOptions<MarkerInterface1> opts{};
-    opts.set = [&ptrToSvc](MarkerInterface1* svc) {
-        ptrToSvc = svc;
+    opts.set = [&ptrToSvc](std::shared_ptr<MarkerInterface1> svc) {
+        ptrToSvc = svc.get();
     };
 
     auto reg1 = registry().registerService(intf1);
@@ -162,17 +162,17 @@ TEST_F(ServiceTrackingTest, SetServiceWithPropsAndOwnderTest) {
 }
 
 TEST_F(ServiceTrackingTest, AddRemoveTest) {
-    MarkerInterface1 intf1;
-    MarkerInterface2 intf2;
-    MarkerInterface3 intf3;
+    MarkerInterface1 intf1{};
+    MarkerInterface2 intf2{};
+    MarkerInterface3 intf3{};
 
-    std::vector<MarkerInterface1*> services{};
+    std::vector<std::shared_ptr<MarkerInterface1>> services{};
 
     celix::ServiceTrackerOptions<MarkerInterface1> opts{};
-    opts.add = [&services](MarkerInterface1* svc) {
+    opts.add = [&services](std::shared_ptr<MarkerInterface1> svc) {
         services.push_back(svc);
     };
-    opts.remove = [&services](MarkerInterface1* svc) {
+    opts.remove = [&services](std::shared_ptr<MarkerInterface1> svc) {
         services.erase(std::remove(services.begin(), services.end(), svc), services.end());
     };
 
@@ -182,24 +182,24 @@ TEST_F(ServiceTrackingTest, AddRemoveTest) {
 
     auto trk1 = registry().trackServices(opts);
     ASSERT_EQ(1, services.size());
-    EXPECT_EQ(&intf1, services[0]); //should be intf1
+    EXPECT_EQ(&intf1, services[0].get()); //should be intf1
 
     reg1.unregister();
     EXPECT_EQ(0, services.size());
 
     reg1 = registry().registerService(intf1);
     ASSERT_EQ(1, services.size());
-    EXPECT_EQ(&intf1, services[0]); //should be intf1 again
+    EXPECT_EQ(&intf1, services[0].get()); //should be intf1 again
 
     MarkerInterface1 intf4{};
     auto reg4 = registry().registerService(intf4);
     ASSERT_EQ(2, services.size());
-    EXPECT_EQ(&intf1, services[0]);
-    EXPECT_EQ(&intf4, services[1]);
+    EXPECT_EQ(&intf1, services[0].get());
+    EXPECT_EQ(&intf4, services[1].get());
 
     reg1.unregister();
     ASSERT_EQ(1, services.size());
-    EXPECT_EQ(&intf4, services[0]); //intf1 gone -> index 0: intf4
+    EXPECT_EQ(&intf4, services[0].get()); //intf1 gone -> index 0: intf4
 
     trk1.stop();
     EXPECT_EQ(0, services.size());
@@ -207,7 +207,7 @@ TEST_F(ServiceTrackingTest, AddRemoveTest) {
     {
         auto trk2 = registry().trackServices(opts);
         ASSERT_EQ(1, services.size());
-        EXPECT_EQ(&intf4, services[0]);
+        EXPECT_EQ(&intf4, services[0].get());
         //out of scope -> tracker stopped
     }
     EXPECT_EQ(0, services.size()); //stop tracking -> services removed
@@ -218,14 +218,14 @@ TEST_F(ServiceTrackingTest, AddRemoveServicesWithPropsAndOwnderTest) {
 }
 
 TEST_F(ServiceTrackingTest, UpdateTest) {
-    MarkerInterface1 intf1;
-    MarkerInterface2 intf2;
-    MarkerInterface3 intf3;
+    MarkerInterface1 intf1{};
+    MarkerInterface2 intf2{};
+    MarkerInterface3 intf3{};
 
-    std::vector<MarkerInterface1*> services{};
+    std::vector<std::shared_ptr<MarkerInterface1>> services{};
 
     celix::ServiceTrackerOptions<MarkerInterface1> opts{};
-    opts.update = [&services](std::vector<MarkerInterface1*> rankedServices) {
+    opts.update = [&services](std::vector<std::shared_ptr<MarkerInterface1>> rankedServices) {
         services = rankedServices;
     };
 
@@ -236,25 +236,25 @@ TEST_F(ServiceTrackingTest, UpdateTest) {
     auto trk1 = registry().trackServices(opts);
     EXPECT_EQ(1, trk1.trackCount());
     ASSERT_EQ(1, services.size());
-    EXPECT_EQ(&intf1, services[0]); //should be intf1
+    EXPECT_EQ(&intf1, services[0].get()); //should be intf1
 
     reg1.unregister();
     EXPECT_EQ(0, services.size());
 
     reg1 = registry().registerService(intf1);
     ASSERT_EQ(1, services.size());
-    EXPECT_EQ(&intf1, services[0]); //should be intf1 again
+    EXPECT_EQ(&intf1, services[0].get()); //should be intf1 again
 
     MarkerInterface1 intf4{};
     celix::Properties props{std::make_pair(celix::SERVICE_RANKING, "100")};
     auto reg4 = registry().registerService(intf4, std::move(props));
     ASSERT_EQ(2, services.size());
-    EXPECT_EQ(&intf4, services[0]); //note 4 higher ranking
-    EXPECT_EQ(&intf1, services[1]);
+    EXPECT_EQ(&intf4, services[0].get()); //note 4 higher ranking
+    EXPECT_EQ(&intf1, services[1].get());
 
     reg1.unregister();
     ASSERT_EQ(1, services.size());
-    EXPECT_EQ(&intf4, services[0]); //intf1 gone -> index 0: intf4
+    EXPECT_EQ(&intf4, services[0].get()); //intf1 gone -> index 0: intf4
 
     trk1.stop();
     EXPECT_EQ(0, services.size());
@@ -262,7 +262,7 @@ TEST_F(ServiceTrackingTest, UpdateTest) {
     {
         auto trk2 = registry().trackServices(opts);
         ASSERT_EQ(1, services.size());
-        EXPECT_EQ(&intf4, services[0]);
+        EXPECT_EQ(&intf4, services[0].get());
         //out of scope -> tracker stopped
     }
     EXPECT_EQ(0, services.size()); //stop tracking -> services removed
diff --git a/libs/registry/include/celix/Constants.h b/libs/registry/include/celix/Constants.h
index f1fcad3..517a372 100644
--- a/libs/registry/include/celix/Constants.h
+++ b/libs/registry/include/celix/Constants.h
@@ -24,9 +24,10 @@
 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_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";
 
diff --git a/libs/registry/include/celix/Properties.h b/libs/registry/include/celix/Properties.h
index 65fd4ef..1002bfc 100644
--- a/libs/registry/include/celix/Properties.h
+++ b/libs/registry/include/celix/Properties.h
@@ -55,6 +55,12 @@ namespace celix {
         std::string val = getProperty(props, key, std::to_string(defaultValue));
         return std::stoul(val, nullptr, 10);
     }
+
+    /*TODO
+    celix::Properties loadProperties(const std::string &path);
+    celix::Properties loadProperties(std::istream stream);
+    bool storeProperties(const celix::Properties &props, const std::string &path);
+     */
 }
 
 #endif //CXX_CELIX_PROPERTIES_H
diff --git a/libs/registry/include/celix/ServiceRegistry.h b/libs/registry/include/celix/ServiceRegistry.h
index 7bbe16c..710b218 100644
--- a/libs/registry/include/celix/ServiceRegistry.h
+++ b/libs/registry/include/celix/ServiceRegistry.h
@@ -70,25 +70,23 @@ namespace celix {
 
         std::string filter{};
 
-        /*TODO maybe refactor all I* to std::shared_ptr and use a custom deleter to sync whether a bundle is done using
-        all the functions -> i.e. safe delete and possible lock free? Not sure, because a std::shared_ptr instance
-        access it not thread safe?. Investigate */
+        std::function<void(std::shared_ptr<I> svc)> set{};
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props)> setWithProperties{};
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> setWithOwner{};
 
-        std::function<void(I *svc)> set = {};
-        std::function<void(I *svc, const celix::Properties &props)> setWithProperties = {};
-        std::function<void(I *svc, const celix::Properties &props, const celix::IResourceBundle &owner)> setWithOwner = {};
+        std::function<void(std::shared_ptr<I> svc)> add{};
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props)> addWithProperties{};
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> addWithOwner{};
 
-        std::function<void(I *svc)> add = {};
-        std::function<void(I *svc, const celix::Properties &props)> addWithProperties = {};
-        std::function<void(I *svc, const celix::Properties &props, const celix::IResourceBundle &owner)> addWithOwner = {};
+        std::function<void(std::shared_ptr<I> svc)> remove{};
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props)> removeWithProperties{};
+        std::function<void(std::shared_ptr<I> svc, const celix::Properties &props, const celix::IResourceBundle &owner)> removeWithOwner{};
 
-        std::function<void(I *svc)> remove = {};
-        std::function<void(I *svc, const celix::Properties &props)> removeWithProperties = {};
-        std::function<void(I *svc, const celix::Properties &props, const celix::IResourceBundle &owner)> removeWithOwner = {};
+        std::function<void(std::vector<std::shared_ptr<I>> rankedServices)> update{};
+        std::function<void(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*>> rankedServices)> updateWithProperties{};
+        std::function<void(std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*, const celix::IResourceBundle *>> rankedServices)> updateWithOwner{};
 
-        std::function<void(std::vector<I*> rankedServices)> update = {};
-        std::function<void(std::vector<std::tuple<I*, const celix::Properties*>> rankedServices)> updateWithProperties = {};
-        std::function<void(std::vector<std::tuple<I*, const celix::Properties*, const celix::IResourceBundle *>> rankedServices)> updateWithOwner = {};
+        //TODO lock free update calls atomics, rcu, hazard pointers ??
     };
 
     //RAII service tracker: out of scope -> stop tracker
@@ -107,7 +105,7 @@ namespace celix {
         const std::string& filter() const;
         bool valid() const;
 
-        //TODO useService(s) calls
+        //TODO use(Function)Service(s) calls
 
         void stop();
     private:
@@ -140,7 +138,8 @@ namespace celix {
         celix::ServiceRegistration registerService(std::shared_ptr<I> svc, celix::Properties props = {}, std::shared_ptr<const celix::IResourceBundle> owner = {}) {
             //TOOD refactor to using a service factory to store the shared or unique_ptr
             auto svcName = celix::serviceName<I>();
-            return registerService(svcName, static_cast<std::shared_ptr<void>>(svc), std::move(props), std::move(owner));
+            auto voidSvc = std::static_pointer_cast<I>(svc);
+            return registerService(svcName, voidSvc, std::move(props), std::move(owner));
         }
 
         template<typename F>
@@ -159,7 +158,7 @@ namespace celix {
         template<typename I>
         //NOTE C++17 typename std::enable_if<std::is_callable<I>::value, long>::type
         long findFunctionService(const std::string &functionName, const std::string &filter = "") const {
-            auto services = functionServiceName<I>(functionName, filter);
+            auto services = findFunctionService<I>(functionName, filter);
             return services.size() > 0 ? services[0] : -1L;
         }
 
@@ -167,14 +166,14 @@ namespace celix {
         //NOTE C++17 typename std::enable_if<!std::is_callable<I>::value, std::vector<long>>::type
         std::vector<long> findServices(const std::string &filter = "") const {
             auto svcName = celix::serviceName<I>();
-            return findServices(svcName, filter);
+            return findAnyServices(svcName, filter);
         }
 
         template<typename F>
         //NOTE C++17 typename std::enable_if<std::is_callable<I>::value, std::vector<long>>::type
         std::vector<long> findFunctionServices(const std::string &functionName, const std::string &filter = "") const {
             auto svcName = celix::functionServiceName<F>(functionName);
-            return findServices(svcName, filter);
+            return findAnyServices(svcName, filter);
         }
 
         template<typename I>
@@ -264,6 +263,30 @@ namespace celix {
         }
 
 
+        //GENERIC / ANY calls. note these work on void
+
+        int useAnyServices(
+                const std::string &svcName,
+                std::function<void(std::shared_ptr<void> svc, const celix::Properties &props,const celix::IResourceBundle &bnd)> use,
+                const std::string &filter = {},
+                std::shared_ptr<const celix::IResourceBundle> requester = {}) const;
+
+        bool useAnyService(
+                const std::string &svcName,
+                std::function<void(std::shared_ptr<void> svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> use,
+                const std::string &filter = {},
+                std::shared_ptr<const celix::IResourceBundle> requester = {}) const;
+
+        std::vector<long> findAnyServices(const std::string &name, const std::string &filter = {}) const;
+
+
+        celix::ServiceTracker trackAnyServices(
+                std::string svcName,
+                ServiceTrackerOptions<void> options,
+                std::shared_ptr<const celix::IResourceBundle> requester = {});
+
+        //some aditional registry info
+        std::vector<std::string> listAllRegisteredServiceNames() const;
         long nrOfRegisteredServices() const;
         long nrOfServiceTrackers() const;
     private:
@@ -283,7 +306,6 @@ namespace celix {
                 std::function<void(I &svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> useWithOwner,
                 const std::string &filter,
                 std::shared_ptr<const celix::IResourceBundle> requester) const;
-        int useServices(const std::string &svcName, std::function<void(void *svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> &use, const std::string &filter, std::shared_ptr<const celix::IResourceBundle> requester) const;
 
         template<typename I>
         bool useService(
@@ -293,16 +315,14 @@ namespace celix {
                 std::function<void(I &svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> useWithOwner,
                 const std::string &filter,
                 std::shared_ptr<const celix::IResourceBundle> requester) const;
-        bool useService(const std::string &svcName, std::function<void(void *svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> &use, const std::string &filter, std::shared_ptr<const celix::IResourceBundle> requester) const;
-
-        //find Services
-        std::vector<long> findServices(const std::string &name, const std::string &filter) const;
-
 
         //track services
         template<typename I>
-        celix::ServiceTracker trackServices(std::string svcName, celix::ServiceTrackerOptions<I> options, std::shared_ptr<const celix::IResourceBundle> requester);
-        celix::ServiceTracker trackServices(std::string svcName, ServiceTrackerOptions<void> options, std::shared_ptr<const celix::IResourceBundle> requester);
+        celix::ServiceTracker trackServices(
+                std::string svcName,
+                celix::ServiceTrackerOptions<I> options,
+                std::shared_ptr<const celix::IResourceBundle> requester);
+
     };
 }
 
@@ -360,8 +380,9 @@ inline int celix::ServiceRegistry::useServices(
         std::function<void(I &svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> useWithOwner,
         const std::string &filter,
         std::shared_ptr<const celix::IResourceBundle> requester) const {
-    std::function<void(void*,const celix::Properties&, const celix::IResourceBundle&)> voidUse = [&](void *svc, const celix::Properties &props, const celix::IResourceBundle &bnd) {
-        I* typedSvc = static_cast<I*>(svc);
+
+    std::function<void(std::shared_ptr<void>, const celix::Properties&, const celix::IResourceBundle&)> voidUse = [&](std::shared_ptr<void> svc, const celix::Properties &props, const celix::IResourceBundle &bnd) {
+        std::shared_ptr<I> typedSvc = std::static_pointer_cast<I>(svc);
         if (use) {
             use(*typedSvc);
         }
@@ -372,7 +393,7 @@ inline int celix::ServiceRegistry::useServices(
             useWithOwner(*typedSvc, props, bnd);
         }
     };
-    return useServices(svcName, voidUse, filter, requester);
+    return useAnyServices(svcName, std::move(voidUse), filter, std::move(requester));
 }
 
 template<typename I>
@@ -383,8 +404,9 @@ inline bool celix::ServiceRegistry::useService(
         std::function<void(I &svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> useWithOwner,
         const std::string &filter,
         std::shared_ptr<const celix::IResourceBundle> requester) const {
-    std::function<void(void*,const celix::Properties&, const celix::IResourceBundle&)> voidUse = [&](void *svc, const celix::Properties &props, const celix::IResourceBundle &bnd) -> void {
-        I* typedSvc = static_cast<I*>(svc);
+
+    std::function<void(std::shared_ptr<void>,const celix::Properties&, const celix::IResourceBundle&)> voidUse = [&](std::shared_ptr<void> svc, const celix::Properties &props, const celix::IResourceBundle &bnd) -> void {
+        std::shared_ptr<I> typedSvc = std::static_pointer_cast<I>(svc);
         if (use) {
             use(*typedSvc);
         }
@@ -395,115 +417,120 @@ inline bool celix::ServiceRegistry::useService(
             useWithOwner(*typedSvc, props, bnd);
         }
     };
-    return useService(svcName, voidUse, filter, requester);
+    return useAnyService(svcName, std::move(voidUse), filter, std::move(requester));
 }
 
 template<typename I>
-inline celix::ServiceTracker celix::ServiceRegistry::trackServices(std::string svcName, const celix::ServiceTrackerOptions<I> options, std::shared_ptr<const celix::IResourceBundle> requester) {
+inline celix::ServiceTracker celix::ServiceRegistry::trackServices(std::string svcName,
+                                                                      ServiceTrackerOptions<I> options,
+                                                                      std::shared_ptr<const celix::IResourceBundle> requester) {
     ServiceTrackerOptions<void> opts{};
     opts.filter = std::move(options.filter);
 
     if (options.set != nullptr) {
         auto set = std::move(options.set);
-        opts.set = [set](void *svc){
-            I *typedSvc = static_cast<I*>(svc);
+        opts.set = [set](std::shared_ptr<void> svc){
+            auto typedSvc = std::static_pointer_cast<I>(svc);
             set(typedSvc);
         };
     }
     if (options.setWithProperties != nullptr) {
         auto set = std::move(options.setWithProperties);
-        opts.setWithProperties = [set](void *svc, const celix::Properties &props){
-            I *typedSvc = static_cast<I*>(svc);
+        opts.setWithProperties = [set](std::shared_ptr<void> svc, const celix::Properties &props){
+            auto typedSvc = std::static_pointer_cast<I>(svc);
             set(typedSvc, props);
         };
     }
     if (options.setWithOwner != nullptr) {
         auto set = std::move(options.setWithOwner);
-        opts.setWithOwner = [set](void *svc, const celix::Properties &props, const celix::IResourceBundle &owner){
-            I *typedSvc = static_cast<I*>(svc);
+        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, props, owner);
         };
     }
 
     if (options.add != nullptr) {
         auto add = std::move(options.add);
-        opts.add = [add](void *svc) {
-            I *typedSvc = static_cast<I*>(svc); //note actual argument is I*
+        opts.add = [add](std::shared_ptr<void> svc) {
+            auto typedSvc = std::static_pointer_cast<I>(svc);
             add(typedSvc);
         };
     }
     if (options.addWithProperties != nullptr) {
         auto add = std::move(options.addWithProperties);
-        opts.addWithProperties = [add](void *svc, const celix::Properties &props) {
-            I *typedSvc = static_cast<I*>(svc); //note actual argument is I*
+        opts.addWithProperties = [add](std::shared_ptr<void> svc, const celix::Properties &props) {
+            auto typedSvc = std::static_pointer_cast<I>(svc);
             add(typedSvc, props);
         };
     }
     if (options.addWithOwner != nullptr) {
         auto add = std::move(options.addWithOwner);
-        opts.addWithOwner = [add](void *svc, const celix::Properties &props, const celix::IResourceBundle &bnd) {
-            I *typedSvc = static_cast<I*>(svc); //note actual argument is I*
+        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, props, bnd);
         };
     }
 
     if (options.remove != nullptr) {
         auto rem = std::move(options.remove);
-        opts.remove = [rem](void *svc) {
-            I *typedSvc = static_cast<I*>(svc); //note actual argument is I*
+        opts.remove = [rem](std::shared_ptr<void> svc) {
+            auto typedSvc = std::static_pointer_cast<I>(svc);
             rem(typedSvc);
         };
     }
     if (options.removeWithProperties != nullptr) {
         auto rem = std::move(options.removeWithProperties);
-        opts.removeWithProperties = [rem](void *svc, const celix::Properties &props) {
-            I *typedSvc = static_cast<I*>(svc); //note actual argument is I*
+        opts.removeWithProperties = [rem](std::shared_ptr<void> svc, const celix::Properties &props) {
+            auto typedSvc = std::static_pointer_cast<I>(svc);
             rem(typedSvc, props);
         };
     }
     if (options.removeWithOwner != nullptr) {
         auto rem = std::move(options.removeWithOwner);
-        opts.removeWithOwner = [rem](void *svc, const celix::Properties &props, const celix::IResourceBundle &bnd) {
-            I *typedSvc = static_cast<I*>(svc); //note actual argument is I*
+        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, props, bnd);
         };
     }
 
     if (options.update != nullptr) {
         auto update = std::move(options.update);
-        opts.update = [update](std::vector<void*> rankedServices) {
-            std::vector<I*> typedServices{};
+        opts.update = [update](std::vector<std::shared_ptr<void>> rankedServices) {
+            std::vector<std::shared_ptr<I>> typedServices{};
             typedServices.reserve(rankedServices.size());
-            for (void *svc : rankedServices) {
-                typedServices.push_back(static_cast<I*>(svc));
+            for (auto &svc : rankedServices) {
+                auto typedSvc = std::static_pointer_cast<I>(svc);
+                typedServices.push_back(typedSvc);
             }
             update(std::move(typedServices));
         };
     }
     if (options.updateWithProperties != nullptr) {
         auto update = std::move(options.updateWithProperties);
-        opts.updateWithProperties = [update](std::vector<std::tuple<void*, const celix::Properties *>> rankedServices) {
-            std::vector<std::tuple<I*, const celix::Properties*>> typedServices{};
+        opts.updateWithProperties = [update](std::vector<std::tuple<std::shared_ptr<void>, const celix::Properties *>> rankedServices) {
+            std::vector<std::tuple<std::shared_ptr<I>, const celix::Properties*>> typedServices{};
             typedServices.reserve(rankedServices.size());
             for (auto &tuple : rankedServices) {
-                typedServices.push_back(std::make_tuple(static_cast<I*>(std::get<0>(tuple)), std::get<1>(tuple)));
+                auto typedSvc = std::static_pointer_cast<I>(std::get<0>(tuple));
+                typedServices.push_back(std::make_tuple(typedSvc, std::get<1>(tuple)));
             }
             update(std::move(typedServices));
         };
     }
     if (options.updateWithOwner != nullptr) {
         auto update = std::move(options.updateWithOwner);
-        opts.updateWithOwner = [update](std::vector<std::tuple<void*, const celix::Properties *, const celix::IResourceBundle*>> rankedServices) {
-            std::vector<std::tuple<I*, const celix::Properties*, const celix::IResourceBundle*>> typedServices{};
+        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 &tuple : rankedServices) {
-                typedServices.push_back(std::make_tuple(static_cast<I*>(std::get<0>(tuple)), std::get<1>(tuple), std::get<2>(tuple)));
+                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));
         };
     }
 
-    return trackServices(std::move(svcName), std::move(opts), requester);
+    return trackAnyServices(std::move(svcName), std::move(opts), requester);
 }
 
 #endif //CXX_CELIX_SERVICEREGISTRY_H
diff --git a/libs/registry/src/ServiceRegistry.cc b/libs/registry/src/ServiceRegistry.cc
index 862013f..ac9a9dd 100644
--- a/libs/registry/src/ServiceRegistry.cc
+++ b/libs/registry/src/ServiceRegistry.cc
@@ -23,7 +23,7 @@
 #include <mutex>
 #include <set>
 #include <utility>
-#include <thread>
+#include <future>
 
 #include <glog/logging.h>
 
@@ -85,13 +85,12 @@ namespace {
         bool factory() const { return svcFactory != nullptr; }
 
         void incrUsage() const {
-            LOG(WARNING) << "TODO use shared_ptr unique instead ?? how to sync?";
+            //TODO look at atomics or shared_ptr to handled to counts / sync
             std::lock_guard<std::mutex> lck{mutex};
             usage += 1;
         }
 
         void decrUsage() const {
-            LOG(WARNING) << "TODO use shared_ptr unique instead ?? how is sync?";
             std::lock_guard<std::mutex> lck{mutex};
             usage -= 1;
             cond.notify_all();
@@ -140,17 +139,15 @@ namespace {
         ~SvcTrackerEntry() {}
 
         void clear() {
-            //TODO update, make special rem (e.g. only call the use set callbacks once with a nullptr)
             std::vector<std::shared_ptr<const SvcEntry>> removeEntries{};
             {
                 std::lock_guard<std::mutex> lck{tracked.mutex};
-                for (auto &entry : tracked.entries) {
-                    removeEntries.push_back(entry);
+                for (const auto &entry : tracked.entries) {
+                    removeEntries.push_back(entry.first);
                 }
-                tracked.entries.clear();
             }
             for (auto &entry : removeEntries) {
-                remMatch(entry); //note fill try to erase entry from entries again, TODO check if this is safe
+                remMatch(entry);
             }
         }
 
@@ -171,56 +168,74 @@ namespace {
 
         void addMatch(std::shared_ptr<const SvcEntry> entry) {
             //increase usage so that services cannot be removed while a service tracker is still active
+
+            //new custom deleter which arranges the count & sync for the used services
+
             entry->incrUsage();
 
+            void *rawSvc = entry->service(*owner);
+            //NOTE creating a shared_ptr with a custom deleter, so that the SvcEntry usage is synced with this shared_ptr.
+            auto svc = std::shared_ptr<void>{rawSvc, [entry](void *) {
+                entry->decrUsage();
+            }};
+
             {
                 std::lock_guard<std::mutex> lck{tracked.mutex};
-                tracked.entries.insert(entry);
+                tracked.entries.emplace(entry, svc);
             }
 
             //call callbacks
             callSetCallbacks();
-            callAddRemoveCallbacks(entry, true);
+            callAddRemoveCallbacks(entry, svc, true);
             callUpdateCallbacks();
         }
 
         void remMatch(const std::shared_ptr<const SvcEntry> &entry) {
+            std::shared_ptr<void> svc{};
             {
                 std::lock_guard<std::mutex> lck{tracked.mutex};
-                tracked.entries.erase(entry);
+                auto it = tracked.entries.find(entry);
+                svc = it->second;
+                tracked.entries.erase(it);
             }
 
             //call callbacks
-            callSetCallbacks();
-            callAddRemoveCallbacks(entry, false);
+            callSetCallbacks(); //note also removed highest if that was set to this svc
+            callAddRemoveCallbacks(entry, svc, false);
             callUpdateCallbacks();
 
-            //decrease usage so that services cannot be removed while a service tracker is still active
-            entry->decrUsage();
+
+            //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> &updatedEntry, bool add) {
+        void callAddRemoveCallbacks(const std::shared_ptr<const SvcEntry> &entry, std::shared_ptr<void> &svc, bool add) {
             auto &update = add ? opts.add : opts.remove;
-            if (update != nullptr) {
-                void *svc = updatedEntry->service(*owner);
+            auto &updateWithProps = add ? opts.addWithProperties : opts.removeWithProperties;
+            auto &updateWithOwner = add ? opts.addWithOwner : opts.removeWithOwner;
+            if (update) {
                 update(svc);
             }
-            //TODO rest of add/remove
+            if (updateWithProps) {
+                updateWithProps(svc, entry->props);
+            }
+            if (updateWithOwner) {
+                updateWithOwner(svc, entry->props, *entry->owner);
+            }
         }
 
         void callSetCallbacks() {
-            std::shared_ptr<const SvcEntry> currentHighest;
+            std::shared_ptr<void> currentHighestSvc{};
+            std::shared_ptr<const SvcEntry> currentHighestSvcEntry{};
             bool highestUpdated = false;
             {
                 std::lock_guard<std::mutex> lck{tracked.mutex};
                 auto begin = tracked.entries.begin();
-                if (begin == tracked.entries.end()) {
-                    currentHighest = nullptr;
-                } else {
-                    currentHighest = *begin;
+                if (begin != tracked.entries.end()) {
+                    currentHighestSvc = begin->second;
+                    currentHighestSvcEntry = begin->first;
                 }
-                if (currentHighest != tracked.highest) {
-                    tracked.highest = currentHighest;
+                if (currentHighestSvc != tracked.highest) {
+                    tracked.highest = currentHighestSvc;
                     highestUpdated = true;
                 }
             }
@@ -228,43 +243,58 @@ namespace {
             //TODO race condition. highest can be updated because lock is released.
 
             if (highestUpdated) {
-                void *svc = currentHighest == nullptr ? nullptr : currentHighest->service(*owner);
-                if (opts.set != nullptr) {
-                    opts.set(svc);
+                if (opts.set) {
+                    opts.set(currentHighestSvc); //note can be nullptr
+                }
+                if (opts.setWithProperties) {
+                    opts.setWithProperties(currentHighestSvc, currentHighestSvcEntry->props);
+                }
+                if (opts.setWithOwner) {
+                    opts.setWithOwner(currentHighestSvc, currentHighestSvcEntry->props, *currentHighestSvcEntry->owner);
                 }
-                //TODO rest of set
             }
         }
 
         void callUpdateCallbacks() {
+            std::vector<std::tuple<std::shared_ptr<void>, const celix::Properties*, const celix::IResourceBundle*>> rankedServices{};
+            if (opts.update || opts.updateWithProperties || opts.updateWithOwner) {
+                //fill vector
+                std::lock_guard<std::mutex> lck{tracked.mutex};
+                rankedServices.reserve(tracked.entries.size());
+                for (auto &tracked : tracked.entries) {
+                    rankedServices.push_back(std::make_tuple(tracked.second, &tracked.first->props, tracked.first->owner.get()));
+                }
+            }
             if (opts.update) {
-                std::vector<void *> rankedServices{};
-                {
-                    std::lock_guard<std::mutex> lck{tracked.mutex};
-                    rankedServices.reserve(tracked.entries.size());
-                    for (auto &tracked : tracked.entries) {
-                        rankedServices.push_back(tracked->service(*owner));
-                    }
+                std::vector<std::shared_ptr<void>> rnk{};
+                for (auto &tuple : rankedServices) {
+                    rnk.push_back(std::get<0>(tuple));
+                }
+                opts.update(std::move(rnk));
+            }
+            if (opts.updateWithProperties) {
+                std::vector<std::tuple<std::shared_ptr<void>, const celix::Properties*>> rnk{};
+                for (auto &tuple : rankedServices) {
+                    rnk.push_back(std::make_pair(std::get<0>(tuple), std::get<1>(tuple)));
                 }
-                opts.update(std::move(rankedServices));
+                opts.updateWithProperties(std::move(rnk));
+            }
+            if (opts.updateWithOwner) {
+                opts.updateWithOwner(std::move(rankedServices));
             }
-            //TODO rest of the update calls
         }
 
         int count() const {
-            LOG(INFO) << "TODO use shared_ptr count instead";
             std::lock_guard<std::mutex> lck{tracked.mutex};
             return (int)tracked.entries.size();
         }
 
         void incrUsage() const {
-            LOG(INFO) << "TODO use shared_ptr count instead";
             std::lock_guard<std::mutex> lck{mutex};
             usage += 1;
         }
 
         void decrUsage() const {
-            LOG(INFO) << "TODO use shared_ptr count instead";
             std::lock_guard<std::mutex> lck{mutex};
             usage -= 1;
             cond.notify_all();
@@ -277,12 +307,11 @@ namespace {
     private:
         struct {
             mutable std::mutex mutex; //protects matchedEntries & highestRanking
-            std::set<std::shared_ptr<const SvcEntry>, SvcEntryLess> entries{};
-            std::shared_ptr<const SvcEntry> highest{};
+            std::map<std::shared_ptr<const SvcEntry>, std::shared_ptr<void>, SvcEntryLess> entries{};
+            std::shared_ptr<void> highest{};
         } tracked{};
 
 
-        //sync TODO refactor to atomics
         mutable std::mutex mutex{};
         mutable std::condition_variable cond{};
         mutable int usage{1};
@@ -354,6 +383,7 @@ public:
 
         //Add to registry
         std::shared_ptr<const celix::IResourceBundle> bnd = owner ? owner : emptyBundle;
+        props[celix::SERVICE_BUNDLE] = std::to_string(bnd->id());
 
         if (factory) {
             VLOG(1) << "Registering service factory '" << svcName << "' from bundle id " << owner->id() << std::endl;
@@ -369,8 +399,8 @@ public:
         services.cache[entry->svcId] = entry;
 
         //update trackers
-        std::thread updateThread{[&]{updateTrackers(entry, true);}};
-        updateThread.join();
+        auto future = std::async([&]{updateTrackers(entry, true);});
+        future.wait();
         entry->decrUsage(); //note usage started at 1 during creation
 
 
@@ -395,17 +425,22 @@ public:
 
         {
             std::lock_guard<std::mutex> lock{services.mutex};
-            const auto it = services.cache.find(svcId);
-            if (it != services.cache.end()) {
-                match = it->second;
-                services.cache.erase(it);
-                services.registry.at(match->svcName).erase(match);
+            const auto cacheIter = services.cache.find(svcId);
+            if (cacheIter != services.cache.end()) {
+                match = cacheIter->second;
+                services.cache.erase(cacheIter);
+                const auto svcSetIter = services.registry.find(match->svcName);
+                svcSetIter->second.erase(match);
+                if (svcSetIter->second.empty()) {
+                    //last entry in the registry for this service name.
+                    services.registry.erase(svcSetIter);
+                }
             }
         }
 
         if (match) {
-            std::thread updateThread{[&]{updateTrackers(match, false);}};
-            updateThread.join();
+            auto future = std::async([&]{updateTrackers(match, false);});
+            future.wait();
             match->waitTillUnused();
         } else {
             LOG(WARNING) << "Cannot unregister service. Unknown service id: " << svcId << "." << std::endl;
@@ -430,8 +465,8 @@ public:
 
         if (match) {
             match->waitTillUnused();
-            std::thread clearThread{[&]{match->clear();}}; //ensure that all service are removed using the callbacks
-            clearThread.join();
+            auto future = std::async([&]{match->clear();}); //ensure that all service are removed using the callbacks
+            future.wait();
         } else {
             LOG(WARNING) << "Cannot remove tracker. Unknown tracker id: " << trkId << "." << std::endl;
         }
@@ -458,6 +493,15 @@ public:
             match->decrUsage();
         }
     }
+
+    std::vector<std::string> listAllRegisteredServiceNames() const {
+        std::vector<std::string> result{};
+        std::lock_guard<std::mutex> lck{services.mutex};
+        for (const auto& pair : services.registry) {
+            result.emplace_back(std::string{pair.first});
+        }
+        return result;
+    }
 };
 
 
@@ -496,7 +540,9 @@ celix::ServiceRegistration celix::ServiceRegistry::registerServiceFactory(std::s
 //TODO add useService(s) call to ServiceTracker object for fast service access
 
 //TODO move to Impl
-celix::ServiceTracker celix::ServiceRegistry::trackServices(std::string svcName, celix::ServiceTrackerOptions<void> options, std::shared_ptr<const celix::IResourceBundle> requester) {
+celix::ServiceTracker celix::ServiceRegistry::trackAnyServices(std::string svcName,
+                                                               celix::ServiceTrackerOptions<void> options,
+                                                               std::shared_ptr<const celix::IResourceBundle> requester) {
     //TODO create new tracker event and start new thread to update track trackers
     long trkId = 0;
     {
@@ -523,13 +569,13 @@ celix::ServiceTracker celix::ServiceRegistry::trackServices(std::string svcName,
             pimpl->trackers.registry[trkEntry->svcName].insert(trkEntry);
             pimpl->trackers.cache[trkEntry->id] = trkEntry;
         }
-        std::thread updateThread{[&]{
+        auto future = std::async([&]{
             for (auto &svcEntry : services) {
                 trkEntry->addMatch(svcEntry);
                 svcEntry->decrUsage();
             }
-        }};
-        updateThread.join();
+        });
+        future.wait();
         trkEntry->decrUsage(); //note trkEntry usage started at 1
 
         auto untrack = [this, trkId]() -> void {
@@ -556,16 +602,16 @@ long celix::ServiceRegistry::nrOfServiceTrackers() const {
         
 //TODO unregister tracker with remove tracker event in a new thread
 //TODO move to Impl
-std::vector<long> celix::ServiceRegistry::findServices(const std::string &svcName, const std::string &rawFilter) const {
+std::vector<long> celix::ServiceRegistry::findAnyServices(const std::string &name, const std::string &f) const {
     std::vector<long> result{};
-    celix::Filter filter = rawFilter;
+    celix::Filter filter = f;
     if (!filter.valid()) {
-        LOG(WARNING) << "Invalid filter (" << rawFilter << ") provided. Cannot find services" << std::endl;
+        LOG(WARNING) << "Invalid filter (" << f << ") provided. Cannot find services" << std::endl;
         return result;
     }
 
     std::lock_guard<std::mutex> lock{pimpl->services.mutex};
-    const auto it = pimpl->services.registry.find(svcName);
+    const auto it = pimpl->services.registry.find(name);
     if (it != pimpl->services.registry.end()) {
         const auto &services = it->second;
         for (const auto &visit : services) {
@@ -584,10 +630,14 @@ long celix::ServiceRegistry::nrOfRegisteredServices() const {
 }
 
 //TODO move to Impl
-int celix::ServiceRegistry::useServices(const std::string &svcName, std::function<void(void *svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> &use, const std::string &rawFilter, std::shared_ptr<const celix::IResourceBundle> requester) const {
-    celix::Filter filter = rawFilter;
+int celix::ServiceRegistry::useAnyServices(const std::string &svcName,
+                                           std::function<void(std::shared_ptr<void> svc, const celix::Properties &props,
+                                                              const celix::IResourceBundle &bnd)> use,
+                                           const std::string &f,
+                                           std::shared_ptr<const celix::IResourceBundle> requester) const {
+    celix::Filter filter = f;
     if (!filter.valid()) {
-        LOG(WARNING) << "Invalid filter (" << rawFilter << ") provided. Cannot find services" << std::endl;
+        LOG(WARNING) << "Invalid filter (" << f << ") provided. Cannot find services" << std::endl;
         return 0;
     }
 
@@ -607,7 +657,11 @@ int celix::ServiceRegistry::useServices(const std::string &svcName, std::functio
     }
 
     for (const std::shared_ptr<const SvcEntry> &entry : matches) {
-        use(entry->service(*requester), entry->props, *entry->owner);
+        void *rawSvc = entry->service(*requester);
+        std::shared_ptr<void> svc{rawSvc, [entry](void *) {
+            entry->decrUsage();
+        }};
+        use(svc, entry->props, *entry->owner);
         entry->decrUsage();
     }
 
@@ -615,10 +669,14 @@ int celix::ServiceRegistry::useServices(const std::string &svcName, std::functio
 }
 
 //TODO move to Impl
-bool celix::ServiceRegistry::useService(const std::string &svcName, std::function<void(void *svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> &use, const std::string &rawFilter, std::shared_ptr<const celix::IResourceBundle> requester) const {
-    celix::Filter filter = rawFilter;
+bool celix::ServiceRegistry::useAnyService(const std::string &svcName,
+                                           std::function<void(std::shared_ptr<void> svc, const celix::Properties &props,
+                                                              const celix::IResourceBundle &bnd)> use,
+                                           const std::string &f,
+                                           std::shared_ptr<const celix::IResourceBundle> requester) const {
+    celix::Filter filter = f;
     if (!filter.valid()) {
-        LOG(WARNING) << "Invalid filter (" << rawFilter << ") provided. Cannot find services" << std::endl;
+        LOG(WARNING) << "Invalid filter (" << f << ") provided. Cannot find services" << std::endl;
         return false;
     }
 
@@ -639,13 +697,20 @@ bool celix::ServiceRegistry::useService(const std::string &svcName, std::functio
     }
 
     if (match != nullptr) {
-        use(match->service(*requester), match->props, *match->owner);
-        match->decrUsage();
+        void *rawSvc = match->service(*requester);
+        std::shared_ptr<void> svc{rawSvc, [match](void *) {
+            match->decrUsage();
+        }};
+        use(svc, match->props, *match->owner);
     }
 
     return match != nullptr;
 }
 
+std::vector<std::string> celix::ServiceRegistry::listAllRegisteredServiceNames() const {
+    return pimpl->listAllRegisteredServiceNames();
+}
+
 /**********************************************************************************************************************
   Service Registration
  **********************************************************************************************************************/