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:49 UTC

[celix] 01/22: CELIX-438: Separates ServiceRegistry & Framework

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 e27350fa503355d43d8ca5a18734932dea26d49c
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Sun Dec 30 15:44:25 2018 +0100

    CELIX-438: Separates ServiceRegistry & Framework
---
 .travis.yml                                        |  35 +-
 CMakeLists.txt                                     |   2 -
 .../service/private/include/framework_patch.h      |   2 +-
 .../private/test/rsa_client_server_tests.cpp       |   2 +-
 bundles/shell/CMakeLists.txt                       |   2 +
 {libs => bundles/shell/cxx_shell}/CMakeLists.txt   |  28 +-
 .../shell/cxx_shell/gtest}/CMakeLists.txt          |  24 +-
 .../cxx_shell/gtest/src/main.cc}                   |  26 +-
 .../cxx_shell/include/celix/IShell.h}              |  27 +-
 .../shell/cxx_shell/include/celix/IShellCommand.h  |  48 ++
 bundles/shell/cxx_shell/src/ShellActivator.cc      | 145 +++++
 bundles/shell/shell_bonjour/CMakeLists.txt         |   2 +-
 cmake/celix_project/AddGTest.cmake                 |   2 +-
 libs/CMakeLists.txt                                |   3 +
 libs/framework/CMakeLists.txt                      |   4 +-
 libs/framework/include/celix/Constants.h           |  21 +-
 libs/framework/src/{bundle.c => BundleImpl.c}      |   0
 libs/framework/src/bundle_context.c.orig           |   2 +-
 libs/{ => framework_cxx}/CMakeLists.txt            |  23 +-
 libs/{ => framework_cxx/gtest}/CMakeLists.txt      |  25 +-
 libs/framework_cxx/gtest/src/Framework_tests.cc    | 127 ++++
 .../framework_cxx/gtest/src/main.cc                |  26 +-
 libs/framework_cxx/include/celix/Framework.h       |  88 +++
 libs/framework_cxx/include/celix/IBundle.h         |  63 ++
 .../framework_cxx/include/celix/IBundleActivator.h |  29 +-
 libs/framework_cxx/include/celix/IBundleContext.h  | 137 ++++
 .../framework_cxx/include/celix/api.h              |  26 +-
 libs/framework_cxx/src/BundleImpl.h                | 178 +++++
 libs/framework_cxx/src/Framework.cc                | 350 ++++++++++
 libs/{ => registry}/CMakeLists.txt                 |  23 +-
 libs/{ => registry/gtest}/CMakeLists.txt           |  27 +-
 libs/registry/gtest/src/Filter_tests.cc            | 207 ++++++
 .../gtest/src/RegistryConcurrency_tests.cc         |  75 +++
 libs/registry/gtest/src/Registry_tests.cc          | 269 ++++++++
 libs/registry/gtest/src/ServiceTracking_tests.cc   | 275 ++++++++
 .../registry/gtest/src/main.cc                     |  26 +-
 libs/registry/include/celix/Constants.h            |  43 ++
 libs/registry/include/celix/Filter.h               |  73 +++
 libs/registry/include/celix/IResourceBundle.h      |  57 ++
 .../registry/include/celix/IServiceFactory.h       |  32 +-
 libs/registry/include/celix/Properties.h           |  60 ++
 libs/registry/include/celix/ServiceRegistry.h      | 509 +++++++++++++++
 libs/registry/include/celix/Utils.h                | 102 +++
 libs/registry/src/Filter.cc                        | 464 +++++++++++++
 libs/registry/src/ServiceRegistry.cc               | 716 +++++++++++++++++++++
 45 files changed, 4166 insertions(+), 239 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index ff86367..e3536d2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,3 @@
-
-sudo: required
-group: deprecated-2017Q2
-
-language: c
-
 env:
     global:
         - COVERITY_SCAN_BUILD_COMMAND="make"
@@ -19,17 +13,17 @@ env:
 matrix:
     include:
        - os: linux
-         dist: trusty
+         dist: xenial
          compiler: gcc
        - os: linux
-         dist: trusty
+         dist: xenial
          compiler: clang
        - os: osx
          osx_image: xcode7.3
          compiler: clang
          env: MACOSX_DEPLOYMENT_TARGET=10.11
        - os: linux
-         dist: trusty
+         dist: xenial
          compiler: gcc
          env: SANITIZE=1
 
@@ -41,27 +35,12 @@ matrix:
 #services: docker
 
 before_install:
-  - if [ "$TRAVIS_OS_NAME" = "linux" ] &&  [ -z "$ANDROID" ]; then sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && sudo apt-get -qq update && sudo apt-get install -y uuid-dev libxml2-dev lcov libffi-dev gcc-4.8 g++-4.8; fi
-  - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update && brew install lcov libffi zeromq czmq && brew link --force libffi; fi
+  - if [ "$TRAVIS_OS_NAME" = "linux" ] sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
+  - if [ "$TRAVIS_OS_NAME" = "linux" ] sudo apt-get update -qq
+  - if [ "$TRAVIS_OS_NAME" = "linux" ] sudo apt-get install -qq uuid-dev libxml2-dev lcov libffi-dev libgoogle-glog-dev libczmq-dev libcpputest-dev libjansson-dev
+  - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update && brew install lcov libffi zeromq czmq glog cpputest jansson && brew link --force libffi; fi
 
 before_script:
-    - wget https://github.com/cpputest/cpputest/releases/download/v3.8/cpputest-3.8.tar.gz -O /tmp/cpputest.tar.gz
-    - tar -xzvf /tmp/cpputest.tar.gz -C /tmp
-    - if [ "$CC" = "clang" ]; then export CXX="clang++"; fi && cd /tmp/cpputest-* && ./configure --prefix=/usr/local && make && sudo make install && cd -
-    - cd /tmp/cpputest-* && ./configure --prefix=/usr/local && make && sudo make install && cd -
-    - wget https://github.com/zeromq/libzmq/releases/download/v4.2.1/zeromq-4.2.1.tar.gz -O /tmp/zeromq.tar.gz
-    - tar -xzvf /tmp/zeromq.tar.gz -C /tmp && cd /tmp/zeromq-* && mkdir build && cd build
-    - if [ "$TRAVIS_OS_NAME" = "linux" ] &&  [ -z "$ANDROID" ]; then cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DENABLE_CURVE=ON .. && make && sudo make install; fi 
-    - cd $TRAVIS_BUILD_DIR
-    - wget https://github.com/zeromq/czmq/releases/download/v4.0.2/czmq-4.0.2.tar.gz -O /tmp/czmq.tar.gz
-    - tar -xzvf /tmp/czmq.tar.gz -C /tmp && cd /tmp/czmq-* && mkdir build && cd build
-    - if [ "$TRAVIS_OS_NAME" = "linux" ] &&  [ -z "$ANDROID" ]; then cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. && make && sudo make install; fi
-    - cd $TRAVIS_BUILD_DIR
-    - git clone https://github.com/akheron/jansson.git jansson-build
-    - cd jansson-build && git checkout 2.7
-    - cmake -DJANSSON_BUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=/usr/local . && make
-    - sudo make install
-    - cd -
     - mkdir build install
     - export BUILD_OPTIONS=" \
         -DBUILD_RSA_REMOTE_SERVICE_ADMIN_DFI=ON \
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 50bd853..9ba636e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -56,8 +56,6 @@ option(ENABLE_GTESTING "Enables unit testing using GTest" ON)
 
 if (ENABLE_TESTING)
 	enable_testing()
-endif ()
-if (ENABLE_TESTING AND ENABLE_GTESTING)
     include(cmake/celix_project/AddGTest.cmake)
 endif ()
 
diff --git a/bundles/config_admin/service/private/include/framework_patch.h b/bundles/config_admin/service/private/include/framework_patch.h
index 98194e1..8017f51 100644
--- a/bundles/config_admin/service/private/include/framework_patch.h
+++ b/bundles/config_admin/service/private/include/framework_patch.h
@@ -31,7 +31,7 @@
 
 /* celix.framework.public */
 #include "celix_errno.h"
-#include "bundle.h"
+#include "BundleImpl.h"
 #include "service_reference.h"
 
 celix_status_t bundle_getBundleLocation(bundle_pt bundle, const char **location);
diff --git a/bundles/remote_services/remote_service_admin_shm/private/test/rsa_client_server_tests.cpp b/bundles/remote_services/remote_service_admin_shm/private/test/rsa_client_server_tests.cpp
index 13c6941..fd3dd03 100644
--- a/bundles/remote_services/remote_service_admin_shm/private/test/rsa_client_server_tests.cpp
+++ b/bundles/remote_services/remote_service_admin_shm/private/test/rsa_client_server_tests.cpp
@@ -35,7 +35,7 @@ extern "C" {
 	#include "framework.h"
 	#include "remote_service_admin.h"
 	#include "calculator_service.h"
-	#include "bundle.h"
+	#include "BundleImpl.h"
 
 	#define DISCOVERY_CFG_NAME      "apache_celix_rsa_discovery_shm"
 	#define RSA_HTTP_NAME           "apache_celix_remote_service_admin_shm"
diff --git a/bundles/shell/CMakeLists.txt b/bundles/shell/CMakeLists.txt
index ae2d39a..2fd81dc 100644
--- a/bundles/shell/CMakeLists.txt
+++ b/bundles/shell/CMakeLists.txt
@@ -19,3 +19,5 @@ add_subdirectory(shell)
 add_subdirectory(remote_shell)
 add_subdirectory(shell_bonjour)
 add_subdirectory(shell_tui)
+
+add_subdirectory(cxx_shell)
diff --git a/libs/CMakeLists.txt b/bundles/shell/cxx_shell/CMakeLists.txt
similarity index 56%
copy from libs/CMakeLists.txt
copy to bundles/shell/cxx_shell/CMakeLists.txt
index 5df35a2..070f05e 100644
--- a/libs/CMakeLists.txt
+++ b/bundles/shell/cxx_shell/CMakeLists.txt
@@ -15,17 +15,23 @@
 # specific language governing permissions and limitations
 # under the License.
 
-#utils, dfi and etcdlib are standalone
-#(e.g. no dependency on celix framework
-add_subdirectory(utils)
-add_subdirectory(dfi)
-add_subdirectory(etcdlib)
+find_package(glog REQUIRED)
 
-add_subdirectory(framework)
+#TODO rename to celix::shell && celix::shell_api
 
-#launcher
-add_subdirectory(launcher)
+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_subdirectory(event_admin)# event_admin is unstable
-add_subdirectory(dependency_manager)
-add_subdirectory(dependency_manager_cxx)
\ No newline at end of file
+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)
+
+#if (ENABLE_TESTING)
+#    add_subdirectory(gtest)
+#endif ()
\ No newline at end of file
diff --git a/libs/CMakeLists.txt b/bundles/shell/cxx_shell/gtest/CMakeLists.txt
similarity index 66%
copy from libs/CMakeLists.txt
copy to bundles/shell/cxx_shell/gtest/CMakeLists.txt
index 5df35a2..b4a7204 100644
--- a/libs/CMakeLists.txt
+++ b/bundles/shell/cxx_shell/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,17 +15,11 @@
 # specific language governing permissions and limitations
 # under the License.
 
-#utils, dfi and etcdlib are standalone
-#(e.g. no dependency on celix framework
-add_subdirectory(utils)
-add_subdirectory(dfi)
-add_subdirectory(etcdlib)
+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(framework)
-
-#launcher
-add_subdirectory(launcher)
-
-#add_subdirectory(event_admin)# event_admin is unstable
-add_subdirectory(dependency_manager)
-add_subdirectory(dependency_manager_cxx)
\ No newline at end of file
+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/config_admin/service/private/include/framework_patch.h b/bundles/shell/cxx_shell/gtest/src/main.cc
similarity index 63%
copy from bundles/config_admin/service/private/include/framework_patch.h
copy to bundles/shell/cxx_shell/gtest/src/main.cc
index 98194e1..a76daa7 100644
--- a/bundles/config_admin/service/private/include/framework_patch.h
+++ b/bundles/shell/cxx_shell/gtest/src/main.cc
@@ -16,24 +16,18 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * framework_patch.h
- *
- *  \date       Aug 12, 2013
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
-
 
-#ifndef BUNDLE_PATCH_H_
-#define BUNDLE_PATCH_H_
+#include <gtest/gtest.h>
+#include <glog/logging.h>
 
+int main(int argc, char **argv) {
+    google::InitGoogleLogging(argv[0]);
+    google::LogToStderr();
 
-/* celix.framework.public */
-#include "celix_errno.h"
-#include "bundle.h"
-#include "service_reference.h"
+    ::testing::InitGoogleTest(&argc, argv);
+    int rc = RUN_ALL_TESTS();
 
-celix_status_t bundle_getBundleLocation(bundle_pt bundle, const char **location);
+    google::ShutdownGoogleLogging();
 
-#endif /* BUNDLE_PATCH_H_ */
+    return rc;
+}
\ No newline at end of file
diff --git a/bundles/config_admin/service/private/include/framework_patch.h b/bundles/shell/cxx_shell/include/celix/IShell.h
similarity index 64%
copy from bundles/config_admin/service/private/include/framework_patch.h
copy to bundles/shell/cxx_shell/include/celix/IShell.h
index 98194e1..9809ac5 100644
--- a/bundles/config_admin/service/private/include/framework_patch.h
+++ b/bundles/shell/cxx_shell/include/celix/IShell.h
@@ -16,24 +16,21 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * framework_patch.h
- *
- *  \date       Aug 12, 2013
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
 
+#ifndef CXX_CELIX_ISHELL_H
+#define CXX_CELIX_ISHELL_H
 
-#ifndef BUNDLE_PATCH_H_
-#define BUNDLE_PATCH_H_
+#include <iostream>
 
+namespace celix {
+    class IShell {
+    public:
+        static constexpr const char * const SERVICE_FQN = "celix::IShell [Version 1]";
 
-/* celix.framework.public */
-#include "celix_errno.h"
-#include "bundle.h"
-#include "service_reference.h"
+        virtual ~IShell() = default;
 
-celix_status_t bundle_getBundleLocation(bundle_pt bundle, const char **location);
+        virtual bool executeCommand(const std::string &commandLine, std::ostream &out, std::ostream &err) noexcept = 0;
+    };
+}
 
-#endif /* BUNDLE_PATCH_H_ */
+#endif //CXX_CELIX_ISHELL_H
diff --git a/bundles/shell/cxx_shell/include/celix/IShellCommand.h b/bundles/shell/cxx_shell/include/celix/IShellCommand.h
new file mode 100644
index 0000000..8a30133
--- /dev/null
+++ b/bundles/shell/cxx_shell/include/celix/IShellCommand.h
@@ -0,0 +1,48 @@
+/**
+ *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 <string>
+#include <iostream>
+
+#ifndef CXX_CELIX_ISHELLCOMMAND_H
+#define CXX_CELIX_ISHELLCOMMAND_H
+
+namespace celix {
+
+    class IShellCommand {
+    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";
+
+        virtual ~IShellCommand() = default;
+
+        virtual void executeCommand(const std::string &commandLine, 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";
+}
+
+#endif //CXX_CELIX_ISHELLCOMMAND_H
diff --git a/bundles/shell/cxx_shell/src/ShellActivator.cc b/bundles/shell/cxx_shell/src/ShellActivator.cc
new file mode 100644
index 0000000..5fd4f1f
--- /dev/null
+++ b/bundles/shell/cxx_shell/src/ShellActivator.cc
@@ -0,0 +1,145 @@
+/**
+ *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 "celix/api.h"
+#include "celix/IShellCommand.h"
+#include "celix/IShell.h"
+
+namespace {
+
+    class LbCommand : public celix::IShellCommand {
+    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);
+
+            //TODO useCService with a shell command service struct
+
+            out << "Available commands: " << std::endl;
+            for (auto &name : commands) {
+                out << "|- " << name << 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] = "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);
+
+            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;
+        }
+    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));
+
+            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;
+    };
+}
+
+__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
diff --git a/bundles/shell/shell_bonjour/CMakeLists.txt b/bundles/shell/shell_bonjour/CMakeLists.txt
index 771ccdb..2f40c7e 100644
--- a/bundles/shell/shell_bonjour/CMakeLists.txt
+++ b/bundles/shell/shell_bonjour/CMakeLists.txt
@@ -33,7 +33,7 @@ if (SHELL_BONJOUR)
 		 	private/src/activator.c
 		 	private/src/bonjour_shell.c
 	)
-	add_library(Celix::bonjour_shell ALIAS bonjour_shell)
+	add_library(Celix::bonjour_shell ALIAS bonjour_shell ../cxx_shell/src/ShellActivator.cc)
 
 
 	target_include_directories(bonjour_shell PRIVATE
diff --git a/cmake/celix_project/AddGTest.cmake b/cmake/celix_project/AddGTest.cmake
index 2b91c54..a1753a8 100644
--- a/cmake/celix_project/AddGTest.cmake
+++ b/cmake/celix_project/AddGTest.cmake
@@ -19,7 +19,7 @@ include(ExternalProject)
 ExternalProject_Add(
         googletest_project
         GIT_REPOSITORY https://github.com/google/googletest.git
-        GIT_TAG master
+        GIT_TAG release-1.8.1
         PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gtest
         INSTALL_COMMAND ""
 )
diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt
index 5df35a2..88d1928 100644
--- a/libs/CMakeLists.txt
+++ b/libs/CMakeLists.txt
@@ -23,6 +23,9 @@ add_subdirectory(etcdlib)
 
 add_subdirectory(framework)
 
+add_subdirectory(registry)
+add_subdirectory(framework_cxx)
+
 #launcher
 add_subdirectory(launcher)
 
diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt
index 75aab2d..ecfc795 100644
--- a/libs/framework/CMakeLists.txt
+++ b/libs/framework/CMakeLists.txt
@@ -24,7 +24,7 @@ if(WIN32)
 endif(WIN32)
 
 set(SOURCES
-        src/attribute.c src/bundle.c src/bundle_archive.c src/bundle_cache.c
+        src/attribute.c src/BundleImpl.c src/bundle_archive.c src/bundle_cache.c
         src/bundle_context.c src/bundle_revision.c src/capability.c src/celix_errorcodes.c
         src/framework.c src/manifest.c src/ioapi.c
         src/manifest_parser.c src/miniunz.c src/module.c
@@ -148,7 +148,7 @@ if (ENABLE_TESTING AND FRAMEWORK_TESTS)
         private/mock/bundle_revision_mock.c
         private/mock/resolver_mock.c
         private/mock/version_mock.c
-            src/bundle.c
+            src/BundleImpl.c
         src/celix_errorcodes.c
         private/mock/celix_log_mock.c)
     target_link_libraries(bundle_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
diff --git a/libs/framework/include/celix/Constants.h b/libs/framework/include/celix/Constants.h
index 6788b7e..adcb6a3 100644
--- a/libs/framework/include/celix/Constants.h
+++ b/libs/framework/include/celix/Constants.h
@@ -21,24 +21,19 @@
 #ifndef CXX_CELIX_CONSTANTS_H
 #define CXX_CELIX_CONSTANTS_H
 
-#include "celix_constants.h"
-
 namespace celix {
     class Constants {
     public:
-        static constexpr const char *const SERVICE_NAME = OSGI_FRAMEWORK_OBJECTCLASS;
-        static constexpr const char *const SERVICE_ID = OSGI_FRAMEWORK_SERVICE_ID;
-        static constexpr const char *const SERVICE_PID = OSGI_FRAMEWORK_SERVICE_PID;
-        static constexpr const char *const SERVICE_RANKING = OSGI_FRAMEWORK_SERVICE_RANKING;
+        //NOTE manually aligned with celix_constants.h
+        static constexpr const char *const SERVICE_NAME = "objectClass"; //TODO rename to service.name
+        static constexpr const char *const SERVICE_LANGUAGE = "service.version";
+        static constexpr const char *const SERVICE_ID = "service.id";
+        static constexpr const char *const SERVICE_RANKING = "service.ranking";
 
-        static constexpr const char *const SERVICE_VERSION = CELIX_FRAMEWORK_SERVICE_VERSION;
-        static constexpr const char *const SERVICE_LANGUAGE = CELIX_FRAMEWORK_SERVICE_LANGUAGE;
-        static constexpr const char *const SERVICE_C_LANG = CELIX_FRAMEWORK_SERVICE_C_LANGUAGE;
-        static constexpr const char *const SERVICE_CXX_LANG = CELIX_FRAMEWORK_SERVICE_CXX_LANGUAGE;
+        static constexpr const char *const SERVICE_C_LANG = "C";
+        static constexpr const char *const SERVICE_CXX_LANG = "C++";
 
-        static constexpr const char *const FRAMEWORK_STORAGE = OSGI_FRAMEWORK_FRAMEWORK_STORAGE;
-        static constexpr const char *const FRAMEWORK_CLEAN = OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME;
-        static constexpr const char *const FRAMEWORK_UUID = OSGI_FRAMEWORK_FRAMEWORK_UUID;
+        static constexpr const char *const FRAMEWORK_UUID = "framework.uuid";
     };
 }
 
diff --git a/libs/framework/src/bundle.c b/libs/framework/src/BundleImpl.c
similarity index 100%
rename from libs/framework/src/bundle.c
rename to libs/framework/src/BundleImpl.c
diff --git a/libs/framework/src/bundle_context.c.orig b/libs/framework/src/bundle_context.c.orig
index 8d3a0cc..8866472 100644
--- a/libs/framework/src/bundle_context.c.orig
+++ b/libs/framework/src/bundle_context.c.orig
@@ -26,7 +26,7 @@
 #include "constants.h"
 #include "bundle_context_private.h"
 #include "framework_private.h"
-#include "bundle.h"
+#include "BundleImpl.h"
 #include "celix_bundle.h"
 #include "celix_log.h"
 #include "service_tracker.h"
diff --git a/libs/CMakeLists.txt b/libs/framework_cxx/CMakeLists.txt
similarity index 65%
copy from libs/CMakeLists.txt
copy to libs/framework_cxx/CMakeLists.txt
index 5df35a2..e5fbe8a 100644
--- a/libs/CMakeLists.txt
+++ b/libs/framework_cxx/CMakeLists.txt
@@ -15,17 +15,16 @@
 # specific language governing permissions and limitations
 # under the License.
 
-#utils, dfi and etcdlib are standalone
-#(e.g. no dependency on celix framework
-add_subdirectory(utils)
-add_subdirectory(dfi)
-add_subdirectory(etcdlib)
+find_package(glog REQUIRED)
 
-add_subdirectory(framework)
+#TODO rename to celix::framework
+add_library(celix_framework_cxx SHARED
+        src/Framework.cc
+)
+target_include_directories(celix_framework_cxx PRIVATE src)
+target_include_directories(celix_framework_cxx PUBLIC include)
+target_link_libraries(celix_framework_cxx PUBLIC celix::registry glog::glog) #TODO glog private and static lib
 
-#launcher
-add_subdirectory(launcher)
-
-#add_subdirectory(event_admin)# event_admin is unstable
-add_subdirectory(dependency_manager)
-add_subdirectory(dependency_manager_cxx)
\ No newline at end of file
+if (ENABLE_TESTING)
+    add_subdirectory(gtest)
+endif ()
\ No newline at end of file
diff --git a/libs/CMakeLists.txt b/libs/framework_cxx/gtest/CMakeLists.txt
similarity index 64%
copy from libs/CMakeLists.txt
copy to libs/framework_cxx/gtest/CMakeLists.txt
index 5df35a2..0f407cc 100644
--- a/libs/CMakeLists.txt
+++ b/libs/framework_cxx/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,17 +15,12 @@
 # specific language governing permissions and limitations
 # under the License.
 
-#utils, dfi and etcdlib are standalone
-#(e.g. no dependency on celix framework
-add_subdirectory(utils)
-add_subdirectory(dfi)
-add_subdirectory(etcdlib)
+set(SOURCES
+        src/main.cc
+        src/Framework_tests.cc
+)
+add_executable(celix_framework_cxx_tests ${SOURCES})
+target_link_libraries(celix_framework_cxx_tests PRIVATE gtest celix_framework_cxx)
 
-add_subdirectory(framework)
-
-#launcher
-add_subdirectory(launcher)
-
-#add_subdirectory(event_admin)# event_admin is unstable
-add_subdirectory(dependency_manager)
-add_subdirectory(dependency_manager_cxx)
\ No newline at end of file
+add_test(NAME celix_framework_cxx_tests COMMAND celix_framework_cxx_tests)
+SETUP_TARGET_FOR_COVERAGE(celix_framework_cxx_tests_cov celix_framework_cxx_tests ${CMAKE_BINARY_DIR}/coverage/framework/celix_framework_cxx_tests)
\ No newline at end of file
diff --git a/libs/framework_cxx/gtest/src/Framework_tests.cc b/libs/framework_cxx/gtest/src/Framework_tests.cc
new file mode 100644
index 0000000..34cad54
--- /dev/null
+++ b/libs/framework_cxx/gtest/src/Framework_tests.cc
@@ -0,0 +1,127 @@
+/**
+ *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 "gtest/gtest.h"
+
+#include "celix/Framework.h"
+
+class FrameworkTest : public ::testing::Test {
+public:
+    FrameworkTest() {}
+    ~FrameworkTest(){}
+
+    celix::Framework& framework() { return fw; }
+private:
+    celix::Framework fw{};
+};
+
+
+TEST_F(FrameworkTest, CreateDestroy) {
+    //no bundles installed bundle (framework bundle)
+    EXPECT_EQ(1, framework().listBundles(true).size());
+    EXPECT_EQ(0, framework().listBundles(false).size());
+
+    bool isFramework = false;
+    framework().useBundle(0L, [&](const celix::IBundle &bnd) {
+       isFramework = bnd.isFrameworkBundle();
+    });
+    EXPECT_TRUE(isFramework);
+}
+
+TEST_F(FrameworkTest, InstallBundle) {
+
+    class EmbeddedActivator : public celix::IBundleActivator {
+    public:
+        virtual ~EmbeddedActivator() = default;
+
+        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;
+    };
+
+    long bndId1 = framework().installBundle<EmbeddedActivator>("embedded");
+    EXPECT_GE(bndId1, 0);
+
+    std::shared_ptr<EmbeddedActivator> act{new EmbeddedActivator};
+    long bndId2 = framework().installBundle("embedded2", act);
+    EXPECT_GE(bndId2, 0);
+    EXPECT_NE(bndId1, bndId2);
+    EXPECT_TRUE(act->resolveCalled);
+    EXPECT_TRUE(act->startCalled);
+    EXPECT_FALSE(act->stopCalled);
+
+    framework().stopBundle(bndId2);
+    EXPECT_TRUE(act->stopCalled);
+
+    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);
+
+        //NOTE fw out of scope -> bundle stopped
+    }
+    EXPECT_TRUE(act3->stopCalled);
+}
+
+TEST_F(FrameworkTest, StaticBundleTest) {
+    class EmbeddedActivator : public celix::IBundleActivator {
+    public:
+        virtual ~EmbeddedActivator() = default;
+
+        bool start(std::shared_ptr<celix::IBundleContext>) noexcept override {
+            return true;
+        }
+    };
+
+    int count = 0;
+    auto factory = [&]() -> 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);
+    EXPECT_EQ(1, framework().listBundles().size()); //static bundle instance installed
+    EXPECT_EQ(1, count);
+
+    celix::Framework fw{};
+    EXPECT_EQ(1, framework().listBundles().size()); //already registered static bundle instance installed.
+    EXPECT_EQ(2, count);
+}
\ No newline at end of file
diff --git a/bundles/config_admin/service/private/include/framework_patch.h b/libs/framework_cxx/gtest/src/main.cc
similarity index 63%
copy from bundles/config_admin/service/private/include/framework_patch.h
copy to libs/framework_cxx/gtest/src/main.cc
index 98194e1..a76daa7 100644
--- a/bundles/config_admin/service/private/include/framework_patch.h
+++ b/libs/framework_cxx/gtest/src/main.cc
@@ -16,24 +16,18 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * framework_patch.h
- *
- *  \date       Aug 12, 2013
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
-
 
-#ifndef BUNDLE_PATCH_H_
-#define BUNDLE_PATCH_H_
+#include <gtest/gtest.h>
+#include <glog/logging.h>
 
+int main(int argc, char **argv) {
+    google::InitGoogleLogging(argv[0]);
+    google::LogToStderr();
 
-/* celix.framework.public */
-#include "celix_errno.h"
-#include "bundle.h"
-#include "service_reference.h"
+    ::testing::InitGoogleTest(&argc, argv);
+    int rc = RUN_ALL_TESTS();
 
-celix_status_t bundle_getBundleLocation(bundle_pt bundle, const char **location);
+    google::ShutdownGoogleLogging();
 
-#endif /* BUNDLE_PATCH_H_ */
+    return rc;
+}
\ No newline at end of file
diff --git a/libs/framework_cxx/include/celix/Framework.h b/libs/framework_cxx/include/celix/Framework.h
new file mode 100644
index 0000000..60b6fca
--- /dev/null
+++ b/libs/framework_cxx/include/celix/Framework.h
@@ -0,0 +1,88 @@
+/**
+ *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.
+ */
+
+#ifndef CXX_CELIX_FRAMEWORK_H
+#define CXX_CELIX_FRAMEWORK_H
+
+#include <memory>
+
+#include "celix/Constants.h"
+#include "celix/ServiceRegistry.h"
+#include "celix/IBundleContext.h"
+#include "celix/IBundle.h"
+#include "celix/IBundleActivator.h"
+
+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
+
+    class Framework {
+    public:
+        Framework();
+        ~Framework();
+        Framework(Framework &&rhs);
+        Framework& operator=(Framework&& rhs);
+
+        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 symbolicName, std::shared_ptr<celix::IBundleActivator> activator, celix::Properties manifest = {}, bool autoStart = true);
+
+
+        //long installBundle(const std::string &path);
+        bool startBundle(long bndId);
+        bool stopBundle(long bndId);
+        bool uninstallBundle(long bndId);
+
+        bool useBundle(long bndId, std::function<void(const celix::IBundle &bnd)> use) const;
+        int useBundles(std::function<void(const celix::IBundle &bnd)> use, bool includeFrameworkBundle = false) const;
+
+        //long bundleIdForName(const std::string &bndName) const;
+        std::vector<long> listBundles(bool includeFrameworkBundle = false) const;
+
+        celix::ServiceRegistry& registry(const std::string &lang);
+    private:
+        class Impl;
+        std::unique_ptr<Impl> pimpl;
+    };
+
+};
+
+#endif //CXX_CELIX_FRAMEWORK_H
diff --git a/libs/framework_cxx/include/celix/IBundle.h b/libs/framework_cxx/include/celix/IBundle.h
new file mode 100644
index 0000000..a8d0de1
--- /dev/null
+++ b/libs/framework_cxx/include/celix/IBundle.h
@@ -0,0 +1,63 @@
+/**
+ *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.
+ */
+
+#ifndef CXX_CELIX_IBUNDLE_H
+#define CXX_CELIX_IBUNDLE_H
+
+#include "celix/IResourceBundle.h"
+#include "celix/Properties.h"
+
+namespace celix {
+
+    enum class BundleState {
+        INSTALLED,
+        RESOLVED,
+        ACTIVE,
+    };
+
+    class Framework; //forward declaration
+
+    class IBundle : public celix::IResourceBundle {
+    public:
+        virtual ~IBundle() = default;
+
+        virtual const std::string& name() const noexcept = 0;
+
+        virtual const std::string& symbolicName() const noexcept = 0;
+
+        virtual const std::string& group() const noexcept = 0;
+
+        virtual bool isFrameworkBundle() const noexcept  = 0;
+
+        virtual void* handle() const noexcept = 0;
+
+        virtual celix::BundleState state() const noexcept  = 0;
+
+        virtual const std::string& version() const noexcept = 0;
+
+        virtual const celix::Properties& manifest() const noexcept  = 0;
+
+        virtual bool isValid() const noexcept = 0;
+
+        virtual celix::Framework& framework() const noexcept = 0;
+    };
+
+}
+
+#endif //CXX_CELIX_IBUNDLE_H
diff --git a/bundles/config_admin/service/private/include/framework_patch.h b/libs/framework_cxx/include/celix/IBundleActivator.h
similarity index 58%
copy from bundles/config_admin/service/private/include/framework_patch.h
copy to libs/framework_cxx/include/celix/IBundleActivator.h
index 98194e1..1196e99 100644
--- a/bundles/config_admin/service/private/include/framework_patch.h
+++ b/libs/framework_cxx/include/celix/IBundleActivator.h
@@ -16,24 +16,23 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * framework_patch.h
- *
- *  \date       Aug 12, 2013
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
 
+#ifndef CXX_CELIX_IBUNDLEACTIVATOR_H
+#define CXX_CELIX_IBUNDLEACTIVATOR_H
 
-#ifndef BUNDLE_PATCH_H_
-#define BUNDLE_PATCH_H_
+#include <memory>
 
+#include "IBundleContext.h"
 
-/* celix.framework.public */
-#include "celix_errno.h"
-#include "bundle.h"
-#include "service_reference.h"
+namespace celix {
+    class IBundleActivator {
+    public:
+        virtual ~IBundleActivator() = default;
 
-celix_status_t bundle_getBundleLocation(bundle_pt bundle, const char **location);
+        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; }
+    };
+}
 
-#endif /* BUNDLE_PATCH_H_ */
+#endif //CXX_CELIX_IBUNDLEACTIVATOR_H
diff --git a/libs/framework_cxx/include/celix/IBundleContext.h b/libs/framework_cxx/include/celix/IBundleContext.h
new file mode 100644
index 0000000..e77623a
--- /dev/null
+++ b/libs/framework_cxx/include/celix/IBundleContext.h
@@ -0,0 +1,137 @@
+/**
+ *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.
+ */
+
+#ifndef CXX_CELIX_IBUNDLECONTEXT_H
+#define CXX_CELIX_IBUNDLECONTEXT_H
+
+#include "celix/IBundle.h"
+
+namespace celix {
+
+    //TODO rename and drop I, because it not a complete interface (templates)
+    class IBundleContext {
+    public:
+        virtual ~IBundleContext() = default;
+
+        virtual std::shared_ptr<celix::IBundle> bundle() const noexcept = 0;
+
+        template<typename I>
+        celix::ServiceRegistration registerService(I &svc, celix::Properties props = {}) {
+            return registry().registerService<I>(svc, std::move(props), bundle());
+        }
+
+        template<typename I>
+        celix::ServiceRegistration registerService(std::shared_ptr<I> svc, celix::Properties props = {}) {
+            return registry().registerService<I>(svc, std::move(props), bundle());
+        }
+
+        template<typename F>
+        celix::ServiceRegistration registerFunctionService(std::string functionName, F&& function, celix::Properties props = {}) {
+            return registry().registerFunctionService(std::move(functionName), std::forward<F>(function), std::move(props), bundle());
+        }
+
+        //TODO register C services
+
+        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;
+
+        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());
+        }
+
+        template<typename I>
+        bool useService(std::function<void(I &svc, const celix::Properties &props)> use, const std::string &filter = "") const noexcept {
+            return registry().useService<I>(std::move(use), filter, bundle());
+        }
+
+        template<typename I>
+        bool useService(std::function<void(I &svc, const celix::Properties &props, const celix::IResourceBundle &owner)> use, const std::string &filter = "") const noexcept {
+            return registry().useService<I>(std::move(use), filter, bundle());
+        }
+
+        template<typename F>
+        bool useFunctionService(const std::string &functionName, std::function<void(F &function)> use, const std::string &filter = "") const noexcept {
+            return registry().useFunctionService<F>(functionName, std::move(use), filter, bundle());
+        }
+
+        template<typename F>
+        bool useFunctionService(const std::string &functionName, std::function<void(F &function, const celix::Properties &props)> use, const std::string &filter = "") const noexcept {
+            return registry().useFunctionService<F>(functionName, std::move(use), filter, bundle());
+        }
+
+        template<typename F>
+        bool useFunctionService(const std::string &functionName, std::function<void(F &function, const celix::Properties &props, const celix::IResourceBundle &owner)> use, const std::string &filter = "") const noexcept {
+            return registry().useFunctionService<F>(functionName, std::move(use), filter, bundle());
+        }
+
+        template<typename I>
+        int useServices(std::function<void(I &svc)> use, const std::string &filter = "") const noexcept {
+            return registry().useServices<I>(std::move(use), filter, bundle());
+        }
+
+        template<typename I>
+        int useServices(std::function<void(I &svc, const celix::Properties &props)> use, const std::string &filter = "") const noexcept {
+            return registry().useServices<I>(std::move(use), filter, bundle());
+        }
+
+        template<typename I>
+        int useServices(std::function<void(I &svc, const celix::Properties &props, const celix::IResourceBundle &owner)> use, const std::string &filter = "") const noexcept {
+            return registry().useServices<I>(std::move(use), filter, bundle());
+        }
+
+        template<typename F>
+        int useFunctionServices(const std::string &functionName, std::function<void(F &function)> use, const std::string &filter = "") const noexcept {
+            return registry().useFunctionServices<F>(functionName, std::move(use), filter, bundle());
+        }
+
+        template<typename F>
+        int useFunctionServices(const std::string &functionName, std::function<void(F &function, const celix::Properties &props)> use, const std::string &filter = "") const noexcept {
+            return registry().useFunctionServices<F>(functionName, std::move(use), filter, bundle());
+        }
+
+        template<typename F>
+        int useFunctionServices(const std::string &functionName, std::function<void(F &function, const celix::Properties &props, const celix::IResourceBundle &owner)> use, const std::string &filter = "") const noexcept {
+            return registry().useFunctionServices<F>(functionName, std::move(use), filter, bundle());
+        }
+
+        //TODO use C services
+
+        template<typename I>
+        celix::ServiceTracker trackServices(celix::ServiceTrackerOptions<I> options = {}) {
+            return registry().trackServices<I>(std::move(options), bundle());
+        }
+
+        template<typename F>
+        celix::ServiceTracker trackFunctionServices(std::string functionName, celix::ServiceTrackerOptions<F> options = {}) {
+            return registry().trackFunctionServices<F>(functionName, std::move(options), bundle());
+        }
+
+        //TODO track C Services
+
+        //TODO track trackers
+
+        //TODO track c trackers
+    private:
+        virtual celix::ServiceRegistry& registry() const noexcept = 0;
+        virtual celix::ServiceRegistry& cRegistry() const noexcept = 0;
+    };
+}
+
+#endif //CXX_CELIX_IBUNDLECONTEXT_H
diff --git a/bundles/config_admin/service/private/include/framework_patch.h b/libs/framework_cxx/include/celix/api.h
similarity index 63%
copy from bundles/config_admin/service/private/include/framework_patch.h
copy to libs/framework_cxx/include/celix/api.h
index 98194e1..63b19d4 100644
--- a/bundles/config_admin/service/private/include/framework_patch.h
+++ b/libs/framework_cxx/include/celix/api.h
@@ -16,24 +16,14 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * framework_patch.h
- *
- *  \date       Aug 12, 2013
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
-
-
-#ifndef BUNDLE_PATCH_H_
-#define BUNDLE_PATCH_H_
-
 
-/* celix.framework.public */
-#include "celix_errno.h"
-#include "bundle.h"
-#include "service_reference.h"
+#ifndef CXX_CELIX_API_H
+#define CXX_CELIX_API_H
 
-celix_status_t bundle_getBundleLocation(bundle_pt bundle, const char **location);
+#include "celix/Constants.h"
+#include "celix/Filter.h"
+#include "celix/ServiceRegistry.h"
+#include "celix/Framework.h"
+#include "celix/IBundleActivator.h"
 
-#endif /* BUNDLE_PATCH_H_ */
+#endif //CXX_CELIX_API_H
diff --git a/libs/framework_cxx/src/BundleImpl.h b/libs/framework_cxx/src/BundleImpl.h
new file mode 100644
index 0000000..ab49636
--- /dev/null
+++ b/libs/framework_cxx/src/BundleImpl.h
@@ -0,0 +1,178 @@
+/**
+ *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.
+ */
+
+#ifndef CXX_CELIX_IMPL_BUNDLE_H
+#define CXX_CELIX_IMPL_BUNDLE_H
+
+#include <glog/logging.h>
+
+#include "celix/IBundle.h"
+#include "celix/IBundleContext.h"
+
+namespace celix {
+namespace impl {
+
+        class BundleContext : public celix::IBundleContext {
+        public:
+            BundleContext(std::shared_ptr<celix::IBundle> _bnd) : bnd{std::move(_bnd)},
+                reg{&bnd->framework().registry(celix::CXX_LANG)},
+                cReg(&bnd->framework().registry(celix::C_LANG)){}
+
+            virtual ~BundleContext() = default;
+
+            std::shared_ptr<celix::IBundle> bundle() const noexcept override {
+                return bnd;
+            }
+
+            bool useBundle(long bndId, std::function<void(const celix::IBundle &bnd)> use) const noexcept override {
+                return bnd->framework().useBundle(bndId, std::move(use));
+            }
+
+            int useBundles(std::function<void(const celix::IBundle &bnd)> use, bool includeFrameworkBundle = true) const noexcept override {
+                return bnd->framework().useBundles(std::move(use), includeFrameworkBundle);
+            }
+        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;
+        };
+
+
+        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)} {
+                bndState.store(BundleState::INSTALLED, std::memory_order_release);
+            }
+
+            //resource part
+            bool has(const std::string&) const noexcept override { return false; } //TODO
+            bool isDir(const std::string&) const noexcept override { return false; } //TODO
+            bool isFile(const std::string&) const noexcept override { return false; } //TODO
+            std::vector<std::string> readDir(const std::string&) const noexcept override { return std::vector<std::string>{};} //TODO
+            const std::string& root() const noexcept override { //TODO
+                static std::string empty{};
+                return empty;
+            }
+
+            //bundle part
+            bool isFrameworkBundle() const noexcept override { return false; }
+
+            void* handle() const noexcept override { return nullptr; } //TODO
+
+            long id() const noexcept override { return bndId; }
+            const std::string& name() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_NAME); }
+            const std::string& symbolicName() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_SYMBOLIC_NAME); }
+            const std::string& group() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_SYMBOLIC_NAME); }
+            const std::string& version() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_VERSION); }
+            const celix::Properties& manifest() const noexcept  override { return bndManifest;}
+            bool isValid() const noexcept override { return bndId >= 0; }
+            celix::Framework& framework() const noexcept override { return *fw; }
+
+            celix::BundleState state() const noexcept override {
+                return bndState.load(std::memory_order_acquire);
+            }
+
+            void setState(celix::BundleState state) {
+                bndState.store(state, std::memory_order_release);
+            }
+
+        private:
+            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;
+    };
+
+    class BundleController {
+    public:
+        BundleController(
+                std::shared_ptr<celix::IBundleActivator> _act,
+                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)} {}
+
+        //specific part
+        bool transitionTo(BundleState desired) {
+            bool success = false;
+            std::lock_guard<std::mutex> lck{mutex};
+            const BundleState state = bnd->state();
+            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 {
+                //LOG(ERROR) << "Unexpected desired state " << desired << " from state " << bndState << std::endl;
+                LOG(ERROR) << "Unexpected desired/form state combination " << std::endl;
+            }
+            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::shared_ptr<celix::impl::Bundle> bnd;
+        const std::shared_ptr<celix::impl::BundleContext> ctx;
+
+        mutable std::mutex mutex{};
+    };
+}
+};
+
+#endif //CXX_CELIX_IMPL_BUNDLE_H
diff --git a/libs/framework_cxx/src/Framework.cc b/libs/framework_cxx/src/Framework.cc
new file mode 100644
index 0000000..a224720
--- /dev/null
+++ b/libs/framework_cxx/src/Framework.cc
@@ -0,0 +1,350 @@
+#include <utility>
+
+#include <utility>
+
+/**
+ *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 <unordered_map>
+#include <mutex>
+#include <iostream>
+#include <set>
+#include <vector>
+
+#include <glog/logging.h>
+
+#include "celix/Framework.h"
+
+#include "BundleImpl.h"
+
+struct StaticBundleEntry {
+    const std::string symbolicName;
+    const celix::Properties manifest;
+    const std::function<celix::IBundleActivator*()> activatorFactory;
+};
+
+static struct {
+    std::mutex mutex{};
+    std::vector<StaticBundleEntry> bundles{};
+    std::set<celix::Framework *> frameworks{};
+} staticRegistry{};
+
+
+static void registerFramework(celix::Framework *fw);
+static void unregisterFramework(celix::Framework *fw);
+
+class celix::Framework::Impl : public IBundle {
+public:
+    Impl(celix::Framework *_fw) : fw{_fw}, bndManifest{createManifest()}, cwd{createCwd()} {}
+
+    ~Impl() {
+        stopFramework();
+    }
+
+    std::vector<long> listBundles(bool includeFrameworkBundle) const {
+        std::vector<long> result{};
+        if (includeFrameworkBundle) {
+            result.push_back(0L); //framework bundle id
+        }
+        std::lock_guard<std::mutex> lock{bundles.mutex};
+        for (auto &entry : bundles.entries) {
+            result.push_back(entry.first);
+        }
+        std::sort(result.begin(), result.end());//ensure that the bundles are order by bndId -> i.e. time of install
+        return result;
+    }
+
+    long installBundle(std::string symbolicName, std::shared_ptr<celix::IBundleActivator> activator, celix::Properties manifest, bool autoStart) {
+        //TODO on separate thread ?? specific bundle resolve thread ??
+        long bndId = -1L;
+        std::shared_ptr<celix::impl::BundleController> bndController{nullptr};
+        {
+            manifest[celix::MANIFEST_BUNDLE_SYMBOLIC_NAME] = symbolicName;
+            if (manifest.find(celix::MANIFEST_BUNDLE_NAME) == manifest.end()) {
+                manifest[celix::MANIFEST_BUNDLE_NAME] = symbolicName;
+            }
+            if (manifest.find(celix::MANIFEST_BUNDLE_VERSION) == manifest.end()) {
+                manifest[celix::MANIFEST_BUNDLE_NAME] = "0.0.0";
+            }
+            if (manifest.find(celix::MANIFEST_BUNDLE_GROUP) == manifest.end()) {
+                manifest[celix::MANIFEST_BUNDLE_GROUP] = "";
+            }
+
+            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 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}};
+            bundles.entries.emplace(std::piecewise_construct,
+                                     std::forward_as_tuple(bndId),
+                                     std::forward_as_tuple(bndController));
+
+            //TODO increase bnd entry usage
+        }
+
+        if (bndController) {
+            bool successful = bndController->transitionTo(BundleState::RESOLVED);
+            if (successful && autoStart) {
+                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);
+    }
+
+    bool stopBundle(long bndId) {
+        return transitionBundleTo(bndId, BundleState::RESOLVED);
+    }
+
+    bool uninstallBundle(long bndId) {
+        bool uninstalled = false;
+        std::shared_ptr<celix::impl::BundleController> removed{nullptr};
+        {
+            std::lock_guard<std::mutex> lck{bundles.mutex};
+            auto it = bundles.entries.find(bndId);
+            if (it != bundles.entries.end()) {
+                removed = std::move(it->second);
+                bundles.entries.erase(it);
+
+            }
+        }
+        if (removed) {
+            bool resolved = removed->transitionTo(BundleState::RESOLVED);
+            if (resolved) {
+                uninstalled = true;
+                bool unique = removed.unique();
+                assert(unique); //TODO cond / wait ?
+            } else {
+                //add bundle again -> not uninstalled
+                std::lock_guard<std::mutex> lck{bundles.mutex};
+                bundles.entries[bndId] = std::move(removed);
+            }
+        }
+        return uninstalled;
+    }
+
+    bool transitionBundleTo(long bndId, BundleState desired) {
+        bool successful = false;
+        std::shared_ptr<celix::impl::BundleController> match{nullptr};
+        {
+            std::lock_guard<std::mutex> lck{bundles.mutex};
+            auto it = bundles.entries.find(bndId);
+            if (it != bundles.entries.end()) {
+                match = it->second;
+            }
+        }
+        if (match) {
+            successful = match->transitionTo(desired);
+        }
+        return successful;
+    }
+
+    bool useBundle(long bndId, std::function<void(const celix::IBundle &bnd)> use) const {
+        bool called = false;
+        if (bndId == 0) {
+            //framework bundle
+            use(*this);
+            called = true;
+        } else {
+            std::shared_ptr<celix::impl::BundleController> match = nullptr;
+            {
+                std::lock_guard<std::mutex> lck{bundles.mutex};
+                auto it = bundles.entries.find(bndId);
+                if (it != bundles.entries.end()) {
+                    match = it->second;
+                    //TODO increase usage
+                }
+            }
+            if (match) {
+                use(*match->bundle());
+                called = true;
+                //TODO decrease usage -> use shared ptr instead
+            }
+        }
+        return called;
+    }
+
+    int useBundles(std::function<void(const celix::IBundle &bnd)> use, bool includeFramework) const {
+        std::map<long, std::shared_ptr<celix::impl::BundleController>> useBundles{};
+        {
+            std::lock_guard<std::mutex> lck{bundles.mutex};
+            for (const auto &it : bundles.entries) {
+                useBundles[it.first] = it.second;
+            }
+        }
+
+        if (includeFramework) {
+            use(*this);
+        }
+        for (const auto &cntr : useBundles) {
+            use(*cntr.second->bundle());
+        }
+        int count = (int)useBundles.size();
+        if (includeFramework) {
+            count += 1;
+        }
+        return count;
+    }
+
+    celix::ServiceRegistry& registry(const std::string &lang) {
+        std::lock_guard<std::mutex> lck{registries.mutex};
+        auto it = registries.entries.find(lang);
+        if (it == registries.entries.end()) {
+            registries.entries.emplace(std::string{lang}, celix::ServiceRegistry{std::string{lang}});
+            return registries.entries.at(lang);
+        } else {
+            return it->second;
+        }
+    }
+
+    //resource bundle part
+    long id() const noexcept override { return 1L /*note registry empty bundle is id 0, framework is id 1*/; }
+    bool has(const std::string&) const override { return false; }
+    bool isDir(const std::string&) const override { return false; }
+    bool isFile(const std::string&) const override { return false; }
+    std::vector<std::string> readDir(const std::string&) const override { return std::vector<std::string>{};}
+    const std::string& root() const noexcept override { //TODO
+        return cwd;
+    }
+
+    //bundle stuff
+    bool isFrameworkBundle() const noexcept override { return true; }
+    void* handle() const noexcept override { return nullptr; }
+    celix::BundleState state() const noexcept override { return BundleState::ACTIVE ; }
+    const std::string& name() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_NAME); }
+    const std::string& symbolicName() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_SYMBOLIC_NAME); }
+    const std::string& group() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_GROUP); }
+    const std::string& version() const noexcept override { return bndManifest.at(celix::MANIFEST_BUNDLE_VERSION); }
+    const celix::Properties& manifest() const noexcept  override { return bndManifest;}
+    bool isValid() const noexcept override { return true; }
+    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);
+        }
+
+        return true;
+    }
+private:
+    celix::Properties createManifest() {
+        celix::Properties m{};
+        m[celix::MANIFEST_BUNDLE_SYMBOLIC_NAME] = "framework";
+        m[celix::MANIFEST_BUNDLE_NAME] = "Framework";
+        m[MANIFEST_BUNDLE_GROUP] = "Celix";
+        m[celix::MANIFEST_BUNDLE_VERSION] = "3.0.0";
+        return m;
+    }
+
+    std::string createCwd() {
+        char workdir[PATH_MAX];
+        if (getcwd(workdir, sizeof(workdir)) != NULL) {
+            return std::string{workdir};
+        } else {
+            return std::string{};
+        }
+    }
+
+    celix::Framework * const fw;
+    const celix::Properties bndManifest;
+    const std::string cwd;
+
+    struct {
+        std::unordered_map<long, std::shared_ptr<celix::impl::BundleController>> entries{};
+        long nextBundleId = 2;
+        mutable std::mutex mutex{};
+    } bundles{};
+
+    struct {
+        mutable std::mutex mutex{};
+        std::unordered_map<std::string, celix::ServiceRegistry> entries;
+    } registries;
+};
+
+/***********************************************************************************************************************
+ * 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() {
+    unregisterFramework(this);
+}
+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);
+}
+
+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 {
+    return pimpl->useBundle(bndId, use);
+}
+
+int celix::Framework::useBundles(std::function<void(const celix::IBundle &bnd)> use, bool includeFrameworkBundle) const {
+    return pimpl->useBundles(use, includeFrameworkBundle);
+}
+
+bool celix::Framework::startBundle(long bndId) { return pimpl->stopBundle(bndId); }
+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); }
+
+/***********************************************************************************************************************
+ * Celix 'global' functions
+ **********************************************************************************************************************/
+
+void celix::registerStaticBundle(std::string symbolicName, const celix::StaticBundleOptions &opts) {
+    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);
+    }
+}
+
+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);
+    }
+}
+
+static void unregisterFramework(celix::Framework *fw) {
+    std::lock_guard<std::mutex> lck{staticRegistry.mutex};
+    staticRegistry.frameworks.erase(fw);
+}
\ No newline at end of file
diff --git a/libs/CMakeLists.txt b/libs/registry/CMakeLists.txt
similarity index 64%
copy from libs/CMakeLists.txt
copy to libs/registry/CMakeLists.txt
index 5df35a2..ee537cc 100644
--- a/libs/CMakeLists.txt
+++ b/libs/registry/CMakeLists.txt
@@ -15,17 +15,18 @@
 # specific language governing permissions and limitations
 # under the License.
 
-#utils, dfi and etcdlib are standalone
-#(e.g. no dependency on celix framework
-add_subdirectory(utils)
-add_subdirectory(dfi)
-add_subdirectory(etcdlib)
+find_package(glog REQUIRED)
 
-add_subdirectory(framework)
+add_library(celix_registry STATIC
+        src/ServiceRegistry.cc
+        src/Filter.cc
+)
+target_include_directories(celix_registry PRIVATE src)
+target_include_directories(celix_registry PUBLIC include)
+target_link_libraries(celix_registry PRIVATE glog::glog) #TODO make glog static and private
 
-#launcher
-add_subdirectory(launcher)
+add_library(celix::registry ALIAS celix_registry)
 
-#add_subdirectory(event_admin)# event_admin is unstable
-add_subdirectory(dependency_manager)
-add_subdirectory(dependency_manager_cxx)
\ No newline at end of file
+if (ENABLE_TESTING)
+    add_subdirectory(gtest)
+endif ()
\ No newline at end of file
diff --git a/libs/CMakeLists.txt b/libs/registry/gtest/CMakeLists.txt
similarity index 62%
copy from libs/CMakeLists.txt
copy to libs/registry/gtest/CMakeLists.txt
index 5df35a2..80f0159 100644
--- a/libs/CMakeLists.txt
+++ b/libs/registry/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,17 +15,16 @@
 # specific language governing permissions and limitations
 # under the License.
 
-#utils, dfi and etcdlib are standalone
-#(e.g. no dependency on celix framework
-add_subdirectory(utils)
-add_subdirectory(dfi)
-add_subdirectory(etcdlib)
+find_package(glog REQUIRED)
 
-add_subdirectory(framework)
+set(SOURCES
+        src/main.cc
+        src/Registry_tests.cc
+        src/Filter_tests.cc
+        src/ServiceTracking_tests.cc
+)
+add_executable(celix_registry_tests ${SOURCES})
+target_link_libraries(celix_registry_tests PRIVATE gtest glog::glog celix::registry)
 
-#launcher
-add_subdirectory(launcher)
-
-#add_subdirectory(event_admin)# event_admin is unstable
-add_subdirectory(dependency_manager)
-add_subdirectory(dependency_manager_cxx)
\ No newline at end of file
+add_test(NAME celix_registry_tests COMMAND celix_registry_tests)
+SETUP_TARGET_FOR_COVERAGE(celix_registry_tests_cov celix_registry_tests ${CMAKE_BINARY_DIR}/coverage/registry)
\ No newline at end of file
diff --git a/libs/registry/gtest/src/Filter_tests.cc b/libs/registry/gtest/src/Filter_tests.cc
new file mode 100644
index 0000000..0e481db
--- /dev/null
+++ b/libs/registry/gtest/src/Filter_tests.cc
@@ -0,0 +1,207 @@
+/**
+ *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 "gtest/gtest.h"
+
+#include "celix/Filter.h"
+
+class FilterTest : public ::testing::Test {
+public:
+    FilterTest() {}
+    ~FilterTest(){}
+};
+
+TEST_F(FilterTest, CreateFilterTest) {
+    const char *input1 = "(test_attr1=attr1)";
+    celix::Filter filter{input1};
+    EXPECT_TRUE(filter.valid());
+    EXPECT_EQ("test_attr1", filter.criteria->attribute);
+    EXPECT_EQ(celix::FilterOperator::EQUAL, filter.criteria->op);
+    EXPECT_EQ("attr1", filter.criteria->value);
+    EXPECT_EQ(0, filter.criteria->subcriteria.size());
+
+
+    const char *input2 = "(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3)))";
+    celix::Filter filter2{input2};
+    EXPECT_TRUE(filter2.valid());
+    EXPECT_EQ(input2, filter2.filterStr);
+    EXPECT_EQ(celix::FilterOperator::AND, filter2.criteria->op);
+    EXPECT_EQ(2, filter2.criteria->subcriteria.size());
+    EXPECT_EQ(2, filter2.criteria->subcriteria[1]->subcriteria.size());
+    EXPECT_EQ("test_attr1", filter2.criteria->subcriteria[0]->attribute);
+    EXPECT_EQ(celix::FilterOperator::EQUAL, filter2.criteria->subcriteria[0]->op);
+    EXPECT_EQ("attr1", filter2.criteria->subcriteria[0]->value);
+
+    //test last criteria
+    EXPECT_EQ("test_attr3", filter2.criteria->subcriteria[1]->subcriteria[1]->attribute);
+    EXPECT_EQ(celix::FilterOperator::EQUAL, filter2.criteria->subcriteria[1]->subcriteria[1]->op);
+    EXPECT_EQ("attr3", filter2.criteria->subcriteria[1]->subcriteria[1]->value);
+    EXPECT_EQ(0, filter2.criteria->subcriteria[1]->subcriteria[1]->subcriteria.size());
+
+
+    //creation using a const char* literal and additional white spaces
+    celix::Filter filter3 = "    (   &  (test_attr1=attr1)  (   |    (test_attr2=attr2)   (test_attr3=attr3   ) )  )    ";
+    filter3.valid();
+
+
+    //test PRESENT operator with trailing chars (should just register as substrings: "*" and "attr3")
+    celix::Filter f3 = "(test_attr3=*attr3)";
+    EXPECT_TRUE(f3.valid());
+    EXPECT_EQ(celix::FilterOperator::SUBSTRING, f3.criteria->op);
+    EXPECT_EQ("*attr3", f3.criteria->value);
+
+    //test parsing a value with a escaped closing bracket "\)"
+    celix::Filter f4 = "(test_attr3>=strWith\\)inIt)";
+    EXPECT_TRUE(f4.valid());
+    EXPECT_EQ(celix::FilterOperator::GREATER_EQUAL, f4.criteria->op);
+    EXPECT_EQ("strWith)inIt", f4.criteria->value);
+
+    //test parsing a equal with a escaped closing bracket "\)"
+    celix::Filter f5 = "(test_attr3=strWith\\)inIt)";
+    EXPECT_TRUE(f5.valid());
+    EXPECT_EQ(celix::FilterOperator::EQUAL, f5.criteria->op);
+    EXPECT_EQ("strWith)inIt", f5.criteria->value);
+
+    //test parsing a substring with a escaped closing bracket "\)"
+    celix::Filter f6 = "(test_attr3=*strWith\\)inIt)";
+    EXPECT_TRUE(f6.valid());
+    EXPECT_EQ(celix::FilterOperator::SUBSTRING, f6.criteria->op);
+    EXPECT_EQ("*strWith)inIt", f6.criteria->value);
+
+    celix::Filter f7 = ""; //empty is considered a valid filter
+    f7.valid();
+}
+
+TEST_F(FilterTest, CreateInvalidFilterTest) {
+
+    auto check = [](const char *filter) {
+        celix::Filter f = filter;
+        EXPECT_FALSE(f.valid());
+    };
+
+    check("no-parentheses");
+
+    //empty with whitespaces is also an invalid filter.
+    check(" ");
+
+    check("(attr=trailing_stuff) fdafa");
+
+    //test missing opening brackets in main filter
+    check("&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3))");
+
+    //test missing opening brackets in AND comparator
+    check("(&test_attr1=attr1|(test_attr2=attr2)(test_attr3=attr3))");
+
+    //test missing opening brackets in AND comparator
+    check("(&(test_attr1=attr1)(|test_attr2=attr2(test_attr3=attr3))");
+
+    //test missing opening brackets in NOT comparator
+    check("(&(test_attr1=attr1)(!test_attr2=attr2)");
+
+    //test missing closing brackets in substring
+    check("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3");
+
+    //test missing closing brackets in value
+    check("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3>=attr3");
+
+    //test missing closing brackets in substring
+    check("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=at(tr3)))");
+
+    //test missing closing brackets in value
+    check("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3>=att(r3)))");
+
+    //test trailing chars
+    check("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3))) oh no! trailing chars");
+
+    //test half APPROX operator (should be "~=", instead is "~")
+    check("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3~attr3)))");;
+
+    //test parsing a attribute of 0 length
+    check("(>=attr3)");
+
+    //test parsing a value of 0 length
+    check("(test_attr3>=)");
+}
+
+TEST_F(FilterTest, MatchComparators) {
+    celix::Properties props{};
+
+    props["test_attr1"] = "attr1";
+    props["test_attr2"] = "attr2";
+
+    //test present
+    {
+        celix::Filter f1 = "(test_attr1=*)"; //match true
+        celix::Filter f2 = "(test_attr3=*)"; //match false
+        EXPECT_TRUE(f1.valid());
+        EXPECT_TRUE(f2.valid());
+        EXPECT_TRUE(f1.match(props));
+        EXPECT_FALSE(f2.match(props));
+    }
+
+    //test equal
+    {
+        celix::Filter f1 = "(test_attr1=attr1)"; //match true
+        celix::Filter f2 = "(test_attr1=bla)"; //match false
+        EXPECT_TRUE(f1.valid());
+        EXPECT_TRUE(f2.valid());
+        EXPECT_TRUE(f1.match(props));
+        EXPECT_FALSE(f2.match(props));
+    }
+
+    //test not
+    {
+        celix::Filter f1 = "(!(test_attr1=bla))"; //match true
+        celix::Filter f2 = "(!(test_attr1=attr1))"; //match false
+        EXPECT_TRUE(f1.valid());
+        EXPECT_TRUE(f2.valid());
+        EXPECT_TRUE(f1.match(props));
+        EXPECT_FALSE(f2.match(props));
+    }
+
+    //test AND
+    {
+        celix::Filter f1 = "(&(test_attr1=attr1)(test_attr2=attr2))"; //match true
+        celix::Filter f2 = "(&(test_attr1=attr1)(test_attr3=attr3))"; //match false
+        EXPECT_TRUE(f1.valid());
+        EXPECT_TRUE(f2.valid());
+        EXPECT_TRUE(f1.match(props));
+        EXPECT_FALSE(f2.match(props));
+    }
+
+    //test OR
+    {
+        celix::Filter f1 = "(|(test_attr3=attr3)(test_attr2=attr2))"; //match true
+        celix::Filter f2 = "(|(test_attr4=attr4)(test_attr3=attr3))"; //match false
+        EXPECT_TRUE(f1.valid());
+        EXPECT_TRUE(f2.valid());
+        EXPECT_TRUE(f1.match(props));
+        EXPECT_FALSE(f2.match(props));
+    }
+
+    //test COMBINE
+    {
+        celix::Filter f1 = "(|(test_attr3=attr3)(&(!(test_attr4=*))(test_attr2=attr2)))"; //match true
+        celix::Filter f2 = "(|(test_attr3=attr3)(&(test_attr4=*)(test_attr2=attr2)))"; //match false
+        EXPECT_TRUE(f1.valid());
+        EXPECT_TRUE(f2.valid());
+        EXPECT_TRUE(f1.match(props));
+        EXPECT_FALSE(f2.match(props));
+    }
+}
diff --git a/libs/registry/gtest/src/RegistryConcurrency_tests.cc b/libs/registry/gtest/src/RegistryConcurrency_tests.cc
new file mode 100644
index 0000000..c77c198
--- /dev/null
+++ b/libs/registry/gtest/src/RegistryConcurrency_tests.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 "gtest/gtest.h"
+
+#include "celix/ServiceRegistry.h"
+#include "celix/Constants.h"
+
+class RegistryConcurrentcyTest : public ::testing::Test {
+public:
+    RegistryConcurrentcyTest() {}
+    ~RegistryConcurrentcyTest(){}
+
+    celix::ServiceRegistry& registry() { return reg; }
+private:
+    celix::ServiceRegistry reg{"C/C++"};
+};
+
+class ICalc {
+public:
+    virtual ~ICalc() = default;
+    virtual double calc();
+};
+
+class NodeCalc : public ICalc {
+public:
+    virtual ~NodeCalc() = default;
+
+    double calc() override {
+        double val = 1.0;
+        std::lock_guard<std::mutex> lck{mutex};
+        for (auto *calc : childern) {
+            val *= calc->calc();
+        }
+        return val;
+    }
+private:
+    std::mutex mutex{}
+    std::vector<ICalc*> childern{};
+};
+
+class LeafCalc : public ICalc {
+public:
+    virtual ~LeafCalc() = default;
+
+    double calc() override {
+        return seed;
+    }
+private:
+    double const seed = std::rand() / 100.0;
+};
+
+
+TEST_F(RegistryConcurrentcyTest, ServiceRegistrationTest) {
+//TODO start many thread and cals using the tiers of other calcs eventually leading ot leafs and try to break the registry.
+//tier 1 : NodeCalc
+//tier 2 : NodeCalc
+//tier 3 : LeafCalc
+}
diff --git a/libs/registry/gtest/src/Registry_tests.cc b/libs/registry/gtest/src/Registry_tests.cc
new file mode 100644
index 0000000..8c00b11
--- /dev/null
+++ b/libs/registry/gtest/src/Registry_tests.cc
@@ -0,0 +1,269 @@
+/**
+ *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 "gtest/gtest.h"
+
+#include <glog/logging.h>
+
+#include "celix/ServiceRegistry.h"
+
+class RegistryTest : public ::testing::Test {
+public:
+    RegistryTest() {}
+    ~RegistryTest(){}
+
+    celix::ServiceRegistry& registry() { return reg; }
+private:
+    celix::ServiceRegistry reg{"C/C++"};
+};
+
+class MarkerInterface1 {
+  //nop
+};
+class MarkerInterface2 {
+    //nop
+};
+class MarkerInterface3 {
+    //nop
+};
+
+
+TEST_F(RegistryTest, ServiceRegistrationTest) {
+    //empty registry
+    EXPECT_EQ(0, registry().nrOfRegisteredServices());
+
+    MarkerInterface1 intf1{};
+    {
+        celix::Properties props{};
+        props["TEST"] = "VAL";
+        celix::ServiceRegistration reg = registry().registerService(intf1, props);
+        //no copy possible celix::ServiceRegistration copy = reg;
+
+        long svcId = reg.serviceId();
+        EXPECT_GE(svcId, -1L);
+        EXPECT_TRUE(reg.valid());
+        EXPECT_EQ(reg.properties().at(celix::SERVICE_NAME), celix::serviceName<MarkerInterface1>());
+        EXPECT_EQ("VAL", celix::getProperty(reg.properties(), "TEST", ""));
+
+        EXPECT_EQ(1, registry().nrOfRegisteredServices());
+        EXPECT_EQ(1, registry().findServices<MarkerInterface1>().size());
+
+
+
+        celix::ServiceRegistration moved = std::move(reg); //moving is valid
+        EXPECT_EQ(svcId, moved.serviceId());
+        EXPECT_EQ(1, registry().nrOfRegisteredServices());
+
+        celix::ServiceRegistration moved2{std::move(moved)};
+        EXPECT_EQ(1, registry().nrOfRegisteredServices());
+
+        //out of scope -> deregister
+    }
+    EXPECT_EQ(0, registry().nrOfRegisteredServices());
+    EXPECT_EQ(0, registry().findServices<MarkerInterface1>().size());
+
+    MarkerInterface1 intf2{};
+    MarkerInterface2 intf3{};
+    {
+        celix::ServiceRegistration reg1 = registry().registerService(intf1);
+        EXPECT_EQ(1, registry().nrOfRegisteredServices());
+        celix::ServiceRegistration reg2 = registry().registerService(intf2);
+        EXPECT_EQ(2, registry().nrOfRegisteredServices());
+        celix::ServiceRegistration reg3 = registry().registerService(intf3);
+        EXPECT_EQ(3, registry().nrOfRegisteredServices());
+
+        EXPECT_GT(reg1.serviceId(), 0);
+        EXPECT_GT(reg2.serviceId(), 0);
+        EXPECT_GT(reg3.serviceId(), 0);
+        EXPECT_TRUE(reg1.valid());
+        EXPECT_TRUE(reg2.valid());
+        EXPECT_TRUE(reg3.valid());
+
+        EXPECT_EQ(3, registry().nrOfRegisteredServices());
+        EXPECT_EQ(2, registry().findServices<MarkerInterface1>().size());
+        EXPECT_EQ(1, registry().findServices<MarkerInterface2>().size());
+        EXPECT_EQ(0, registry().findServices<MarkerInterface3>().size());
+
+        //out of scope -> deregister
+    }
+    EXPECT_EQ(0, registry().nrOfRegisteredServices());
+    EXPECT_EQ(0, registry().findServices<MarkerInterface1>().size());
+    EXPECT_EQ(0, registry().findServices<MarkerInterface2>().size());
+    EXPECT_EQ(0, registry().findServices<MarkerInterface3>().size());
+}
+
+TEST_F(RegistryTest, SimpleFindServicesTest) {
+    MarkerInterface1 intf1{};
+    MarkerInterface2 intf2{};
+
+    auto reg1 = registry().registerService(intf1);
+    auto reg2 = registry().registerService(intf2);
+
+    long firstSvc = registry().findService<MarkerInterface1>();
+    EXPECT_GT(firstSvc, 0);
+    std::vector<long> services = registry().findServices<MarkerInterface1>();
+    EXPECT_EQ(1, services.size());
+
+    auto reg3 = registry().registerService(intf1);
+    auto reg4 = registry().registerService(intf2);
+
+    long foundSvc = registry().findService<MarkerInterface1>(); //should find the first services
+    EXPECT_GT(foundSvc, 0);
+    EXPECT_EQ(firstSvc, foundSvc);
+    services = registry().findServices<MarkerInterface1>();
+    EXPECT_EQ(2, services.size());
+}
+
+TEST_F(RegistryTest, FindServicesTest) {
+    MarkerInterface1 intf1{};
+
+    celix::Properties props1{};
+    props1["loc"] = "front";
+    props1["answer"] = "42";
+
+    celix::Properties props2{};
+    props2["loc"] = "back";
+
+    auto reg1 = registry().registerService(intf1, props1);
+    auto reg2 = registry().registerService(intf1, std::move(props2));
+    auto reg3 = registry().registerService(intf1);
+
+    auto find1 = registry().findServices<MarkerInterface1>("(loc=*)"); // expecting 2
+    auto find2 = registry().findServices<MarkerInterface1>("(answer=42)"); // expecting 1
+    auto find3 = registry().findServices<MarkerInterface1>("(!(loc=*))"); // expecting 1
+
+    EXPECT_EQ(2, find1.size());
+    EXPECT_EQ(1, find2.size());
+    EXPECT_EQ(1, find3.size());
+}
+
+TEST_F(RegistryTest, UseServices) {
+    MarkerInterface1 intf1{};
+    auto reg1 = registry().registerService(intf1);
+    auto reg2 = registry().registerService(intf1);
+    auto reg3 = registry().registerService(intf1);
+
+    long svcId1 = reg1.serviceId();
+
+    bool called = registry().useService<MarkerInterface1>([&](MarkerInterface1& svc) -> void {
+        EXPECT_EQ(&svc, &intf1);
+    });
+    EXPECT_TRUE(called);
+
+    called = registry().useService<MarkerInterface1>([&](MarkerInterface1& svc, const celix::Properties &props) -> void {
+        EXPECT_EQ(&svc, &intf1);
+        long id = celix::getProperty(props, celix::SERVICE_ID, 0);
+        EXPECT_EQ(svcId1, id);
+    });
+    EXPECT_TRUE(called);
+
+    called = registry().useService<MarkerInterface1>([&](MarkerInterface1& svc, const celix::Properties &props, const celix::IResourceBundle &bnd) -> void {
+        EXPECT_EQ(&svc, &intf1);
+        long id = celix::getProperty(props, celix::SERVICE_ID, 0);
+        EXPECT_EQ(svcId1, id);
+        EXPECT_EQ(0, bnd.id()); //not nullptr -> use empty bundle (bndId 0)
+    });
+    EXPECT_TRUE(called);
+}
+
+TEST_F(RegistryTest, RankingTest) {
+    MarkerInterface1 intf1{};
+    auto reg1 = registry().registerService(intf1); //no props -> ranking 0
+    auto reg2 = registry().registerService(intf1); //no props -> ranking 0
+
+    {
+        auto reg3 = registry().registerService(intf1); //no props -> ranking 0
+        auto find = registry().findServices<MarkerInterface1>(); // expecting 3
+        EXPECT_EQ(3, find.size());
+        EXPECT_EQ(reg1.serviceId(), find[0]); //first registered service should be found first
+        EXPECT_EQ(reg2.serviceId(), find[1]); //first registered service should be found first
+        EXPECT_EQ(reg3.serviceId(), find[2]); //first registered service should be found first
+
+        //note reg 3 out of scope
+    }
+
+    celix::Properties props{};
+    props[celix::SERVICE_RANKING] = "100";
+    auto reg4 = registry().registerService(intf1, props); // ranking 100 -> before services with ranking 0
+
+    {
+        auto reg5 = registry().registerService(intf1, props); // ranking 100 -> before services with ranking 0
+        auto find = registry().findServices<MarkerInterface1>();
+        EXPECT_EQ(4, find.size());
+        EXPECT_EQ(reg4.serviceId(), find[0]); //ranking 100, oldest (i.e. highest ranking with lowest svcId)
+        EXPECT_EQ(reg5.serviceId(), find[1]); //ranking 100, newest
+        EXPECT_EQ(reg1.serviceId(), find[2]); //ranking 0, oldest
+        EXPECT_EQ(reg2.serviceId(), find[3]); //ranking 0, newest
+
+        //note reg 5 out of scope
+    }
+
+    props[celix::SERVICE_RANKING] = "-100";
+    auto reg6 = registry().registerService(intf1, props); // ranking -100 -> after the rest
+    auto reg7 = registry().registerService(intf1, props); // ranking -100 -> after the rest
+    props[celix::SERVICE_RANKING] = "110";
+    auto reg8 = registry().registerService(intf1, props); // ranking 110 -> before the rest
+    props[celix::SERVICE_RANKING] = "80";
+    auto reg9 = registry().registerService(intf1, props); // ranking 80 -> between ranking 0 adn 100
+    {
+        auto find = registry().findServices<MarkerInterface1>();
+        EXPECT_EQ(7, find.size());
+        EXPECT_EQ(reg8.serviceId(), find[0]); //ranking 110
+        EXPECT_EQ(reg4.serviceId(), find[1]); //ranking 100
+        EXPECT_EQ(reg9.serviceId(), find[2]); //ranking 80
+        EXPECT_EQ(reg1.serviceId(), find[3]); //ranking 0, oldest
+        EXPECT_EQ(reg2.serviceId(), find[4]); //ranking 0, newest
+        EXPECT_EQ(reg6.serviceId(), find[5]); //ranking -100, oldest
+        EXPECT_EQ(reg7.serviceId(), find[6]); //ranking -100, newest
+    }
+}
+
+TEST_F(RegistryTest, StdFunctionTest) {
+    int count = 0;
+    std::function<void()> func1 = [&count]{
+        count++;
+    };
+
+    auto reg1 = registry().registerFunctionService("count", func1);
+    LOG(INFO) << reg1.serviceName() << std::endl;
+    EXPECT_TRUE(reg1.valid());
+    EXPECT_EQ(1, registry().nrOfRegisteredServices());
+
+    std::function<int(long,double,const std::string&)> funcWithReturnAndArgs = [](long a, double b, const std::string &ref) -> int {
+        return (int)(a/b) + (int)ref.size();
+    };
+    auto reg2 = registry().registerFunctionService("yet another function", std::move(funcWithReturnAndArgs));
+    EXPECT_TRUE(reg2.valid());
+    EXPECT_EQ(2, registry().nrOfRegisteredServices());
+    LOG(INFO) << reg2.serviceName() << std::endl;
+
+    std::function<void(std::function<void()>&)> use = [](std::function<void()> &count) {
+        count();
+    };
+    EXPECT_EQ(0, count);
+    registry().useFunctionService("count", use);
+    EXPECT_EQ(1, count);
+    registry().useFunctionService<std::function<void()>>("count", [](std::function<void()> &count) {
+        count();
+    });
+}
+
+//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
new file mode 100644
index 0000000..7a88f1b
--- /dev/null
+++ b/libs/registry/gtest/src/ServiceTracking_tests.cc
@@ -0,0 +1,275 @@
+/**
+ *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 <iostream>
+
+#include "gtest/gtest.h"
+
+#include "celix/ServiceRegistry.h"
+#include "celix/Constants.h"
+
+class ServiceTrackingTest : public ::testing::Test {
+public:
+    celix::ServiceRegistry& registry() { return reg; }
+private:
+    celix::ServiceRegistry reg{"C/C++"};
+};
+
+class MarkerInterface1 {
+  //nop
+};
+class MarkerInterface2 {
+    //nop
+};
+class MarkerInterface3 {
+    //nop
+};
+
+
+TEST_F(ServiceTrackingTest, CreateTrackersTest) {
+    EXPECT_EQ(0, registry().nrOfServiceTrackers());
+    {
+        celix::ServiceTracker trk1 = registry().trackServices<MarkerInterface1>();
+        EXPECT_EQ(1, registry().nrOfServiceTrackers());
+
+        celix::ServiceTracker moved = std::move(trk1);
+        EXPECT_EQ(1, registry().nrOfServiceTrackers());
+
+        celix::ServiceTracker moved2 = celix::ServiceTracker{std::move(moved)};
+        EXPECT_EQ(1, registry().nrOfServiceTrackers());
+
+        auto trk2 = registry().trackServices<MarkerInterface1>();
+        auto trk3 = registry().trackServices<MarkerInterface2>();
+        EXPECT_EQ(3, registry().nrOfServiceTrackers());
+    }
+    EXPECT_EQ(0, registry().nrOfServiceTrackers());
+}
+
+TEST_F(ServiceTrackingTest, ServicesCountTrackersTest) {
+    MarkerInterface1 intf1;
+    MarkerInterface2 intf2;
+    MarkerInterface3 intf3;
+
+    auto trk1 = registry().trackServices<MarkerInterface1>();
+    ASSERT_EQ(0, trk1.trackCount());
+
+    auto reg1 = registry().registerService(intf1);
+    auto reg2 = registry().registerService(intf2);
+
+    auto trk2 = registry().trackServices<MarkerInterface2>();
+    ASSERT_EQ(1, trk1.trackCount());
+    ASSERT_EQ(1, trk2.trackCount());
+
+    {
+
+        auto reg3 = registry().registerService(intf1);
+        ASSERT_EQ(2, trk1.trackCount());
+        ASSERT_EQ(1, trk2.trackCount());
+
+        {
+            auto reg4 = registry().registerService(intf1);
+            auto reg5 = registry().registerService(intf2);
+            auto reg6 = registry().registerService(intf3);
+
+            ASSERT_EQ(3, trk1.trackCount());
+            ASSERT_EQ(2, trk2.trackCount());
+
+            //out of scope -> services are deregistered
+        }
+
+        ASSERT_EQ(2, trk1.trackCount());
+        ASSERT_EQ(1, trk2.trackCount());
+        //out of scope -> services are deregistered
+    }
+
+    ASSERT_EQ(1, trk1.trackCount());
+    ASSERT_EQ(1, trk2.trackCount());
+}
+
+TEST_F(ServiceTrackingTest, SetServiceTest) {
+    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;
+    };
+
+    auto reg1 = registry().registerService(intf1);
+    auto reg2 = registry().registerService(intf2);
+    auto reg3 = registry().registerService(intf3);
+
+    auto trk1 = registry().trackServices(opts);
+    EXPECT_EQ(&intf1, ptrToSvc); //should be intf1
+
+    reg1.unregister();
+    EXPECT_EQ(nullptr, ptrToSvc); //unregistered -> nullptr
+
+
+    reg1 = registry().registerService(intf1);
+    EXPECT_EQ(&intf1, ptrToSvc); //set to intf1 again
+
+    MarkerInterface1 intf4;
+    auto reg4 = registry().registerService(intf4);
+    EXPECT_EQ(&intf1, ptrToSvc); //no change -> intf1 is older
+
+    reg1.unregister();
+    EXPECT_EQ(&intf4, ptrToSvc); //intf1 is gone, intf4 should be set
+
+    trk1.stop();
+    EXPECT_EQ(nullptr, ptrToSvc); //stop tracking nullptr svc is set
+
+    {
+        auto trk2 = registry().trackServices(opts);
+        EXPECT_EQ(&intf4, ptrToSvc); //intf1 is gone, intf4 should be set
+        //out of scope -> tracker stopped
+    }
+    EXPECT_EQ(nullptr, ptrToSvc); //stop tracking nullptr svc is set
+}
+
+TEST_F(ServiceTrackingTest, SetServiceWithPropsAndOwnderTest) {
+    /*
+    MarkerInterface1 intf1;
+    MarkerInterface2 intf2;
+    MarkerInterface3 intf3;
+
+    MarkerInterface1 *ptrToSvc = nullptr;
+    const celix::Properties *ptrToProps = nullptr;
+    const celix::IBundle *ptrToBnd = nullptr;
+    */
+    //TODO
+}
+
+TEST_F(ServiceTrackingTest, AddRemoveTest) {
+    MarkerInterface1 intf1;
+    MarkerInterface2 intf2;
+    MarkerInterface3 intf3;
+
+    std::vector<MarkerInterface1*> services{};
+
+    celix::ServiceTrackerOptions<MarkerInterface1> opts{};
+    opts.add = [&services](MarkerInterface1* svc) {
+        services.push_back(svc);
+    };
+    opts.remove = [&services](MarkerInterface1* svc) {
+        services.erase(std::remove(services.begin(), services.end(), svc), services.end());
+    };
+
+    auto reg1 = registry().registerService(intf1);
+    auto reg2 = registry().registerService(intf2);
+    auto reg3 = registry().registerService(intf3);
+
+    auto trk1 = registry().trackServices(opts);
+    ASSERT_EQ(1, services.size());
+    EXPECT_EQ(&intf1, services[0]); //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
+
+    MarkerInterface1 intf4{};
+    auto reg4 = registry().registerService(intf4);
+    ASSERT_EQ(2, services.size());
+    EXPECT_EQ(&intf1, services[0]);
+    EXPECT_EQ(&intf4, services[1]);
+
+    reg1.unregister();
+    ASSERT_EQ(1, services.size());
+    EXPECT_EQ(&intf4, services[0]); //intf1 gone -> index 0: intf4
+
+    trk1.stop();
+    EXPECT_EQ(0, services.size());
+
+    {
+        auto trk2 = registry().trackServices(opts);
+        ASSERT_EQ(1, services.size());
+        EXPECT_EQ(&intf4, services[0]);
+        //out of scope -> tracker stopped
+    }
+    EXPECT_EQ(0, services.size()); //stop tracking -> services removed
+}
+
+TEST_F(ServiceTrackingTest, AddRemoveServicesWithPropsAndOwnderTest) {
+    //TODO
+}
+
+TEST_F(ServiceTrackingTest, UpdateTest) {
+    MarkerInterface1 intf1;
+    MarkerInterface2 intf2;
+    MarkerInterface3 intf3;
+
+    std::vector<MarkerInterface1*> services{};
+
+    celix::ServiceTrackerOptions<MarkerInterface1> opts{};
+    opts.update = [&services](std::vector<MarkerInterface1*> rankedServices) {
+        services = rankedServices;
+    };
+
+    auto reg1 = registry().registerService(intf1);
+    auto reg2 = registry().registerService(intf2);
+    auto reg3 = registry().registerService(intf3);
+
+    auto trk1 = registry().trackServices(opts);
+    EXPECT_EQ(1, trk1.trackCount());
+    ASSERT_EQ(1, services.size());
+    EXPECT_EQ(&intf1, services[0]); //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
+
+    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]);
+
+    reg1.unregister();
+    ASSERT_EQ(1, services.size());
+    EXPECT_EQ(&intf4, services[0]); //intf1 gone -> index 0: intf4
+
+    trk1.stop();
+    EXPECT_EQ(0, services.size());
+
+    {
+        auto trk2 = registry().trackServices(opts);
+        ASSERT_EQ(1, services.size());
+        EXPECT_EQ(&intf4, services[0]);
+        //out of scope -> tracker stopped
+    }
+    EXPECT_EQ(0, services.size()); //stop tracking -> services removed
+}
+
+TEST_F(ServiceTrackingTest, UpdateTestWithPropsAndOwner) {
+    //TODO
+}
+
+//TODO function service tracking tests
diff --git a/bundles/config_admin/service/private/include/framework_patch.h b/libs/registry/gtest/src/main.cc
similarity index 63%
copy from bundles/config_admin/service/private/include/framework_patch.h
copy to libs/registry/gtest/src/main.cc
index 98194e1..a76daa7 100644
--- a/bundles/config_admin/service/private/include/framework_patch.h
+++ b/libs/registry/gtest/src/main.cc
@@ -16,24 +16,18 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * framework_patch.h
- *
- *  \date       Aug 12, 2013
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
-
 
-#ifndef BUNDLE_PATCH_H_
-#define BUNDLE_PATCH_H_
+#include <gtest/gtest.h>
+#include <glog/logging.h>
 
+int main(int argc, char **argv) {
+    google::InitGoogleLogging(argv[0]);
+    google::LogToStderr();
 
-/* celix.framework.public */
-#include "celix_errno.h"
-#include "bundle.h"
-#include "service_reference.h"
+    ::testing::InitGoogleTest(&argc, argv);
+    int rc = RUN_ALL_TESTS();
 
-celix_status_t bundle_getBundleLocation(bundle_pt bundle, const char **location);
+    google::ShutdownGoogleLogging();
 
-#endif /* BUNDLE_PATCH_H_ */
+    return rc;
+}
\ No newline at end of file
diff --git a/libs/registry/include/celix/Constants.h b/libs/registry/include/celix/Constants.h
new file mode 100644
index 0000000..f1fcad3
--- /dev/null
+++ b/libs/registry/include/celix/Constants.h
@@ -0,0 +1,43 @@
+/**
+ *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.
+ */
+
+
+#ifndef CXX_CELIX_CONSTANTS_H
+#define CXX_CELIX_CONSTANTS_H
+
+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 FRAMEWORK_UUID = "framework.uuid";
+
+    static constexpr const char *const CXX_LANG = "C++";
+    static constexpr const char *const C_LANG = "C";
+
+
+    static constexpr const char *const MANIFEST_BUNDLE_SYMBOLIC_NAME = "Bundle-SymbolicName";
+    static constexpr const char *const MANIFEST_BUNDLE_NAME = "Bundle-Name";
+    static constexpr const char *const MANIFEST_BUNDLE_VERSION = "Bundle-Version";
+    static constexpr const char *const MANIFEST_BUNDLE_GROUP = "Bundle-Group";
+}
+
+#endif //CXX_CELIX_CONSTANTS_H
diff --git a/libs/registry/include/celix/Filter.h b/libs/registry/include/celix/Filter.h
new file mode 100644
index 0000000..db851ba
--- /dev/null
+++ b/libs/registry/include/celix/Filter.h
@@ -0,0 +1,73 @@
+/**
+ *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.
+ */
+
+#ifndef CXX_CELIX_FILTER_H
+#define CXX_CELIX_FILTER_H
+
+#include <string>
+#include <vector>
+
+#include "celix/Properties.h"
+
+namespace celix {
+
+    enum class FilterOperator {
+        EQUAL,
+        APPROX,
+        GREATER,
+        GREATER_EQUAL,
+        LESS,
+        LESS_EQUAL,
+        PRESENT,
+        SUBSTRING,
+        AND,
+        OR,
+        NOT
+    };
+
+    struct FilterCriteria; //forward declr
+    struct FilterCriteria {
+        const std::string attribute;
+        const celix::FilterOperator op;
+        const std::string value;
+        const std::vector<std::shared_ptr<FilterCriteria>> subcriteria;
+    };
+
+    class Filter {
+    public:
+        Filter(const char* f) : filterStr{f}, criteria{parseFilter()} {}
+        Filter(std::string f) : filterStr{std::move(f)}, criteria{parseFilter()} {}
+        Filter(const Filter &rhs) = default;
+        Filter(Filter &&rhs) = default;
+
+        Filter& operator=(const Filter& rhs) = default;
+        Filter& operator=(Filter&& rhs) = default;
+
+        bool empty() const { return filterStr.empty(); }
+        bool valid() const { return filterStr.empty() || criteria != nullptr; }
+        bool match(const celix::Properties &props) const;
+
+        const std::string filterStr;
+        const std::shared_ptr<FilterCriteria> criteria;
+    private:
+        FilterCriteria* parseFilter();
+    };
+}
+
+#endif //CXX_CELIX_FILTER_H
diff --git a/libs/registry/include/celix/IResourceBundle.h b/libs/registry/include/celix/IResourceBundle.h
new file mode 100644
index 0000000..6352736
--- /dev/null
+++ b/libs/registry/include/celix/IResourceBundle.h
@@ -0,0 +1,57 @@
+/**
+ *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.
+ */
+
+#ifndef CXX_CELIX_IRESOURCEBUNDLE_H
+#define CXX_CELIX_IRESOURCEBUNDLE_H
+
+namespace celix {
+
+    class IResourceBundle {
+    public:
+        virtual ~IResourceBundle() = default;
+
+        virtual long id() const noexcept  = 0;
+
+        virtual const std::string& root() const noexcept = 0;
+
+        virtual bool has(const std::string &path) const noexcept = 0;
+        virtual bool isDir(const std::string &path) const noexcept = 0;
+        virtual bool isFile(const std::string &path) const noexcept = 0;
+
+        //virtual bool storeResource(const std::string &path, std::ostream content) noexcept = 0;
+        //virtual std::istream open(const std::string &path) const noexcept = 0;
+        //virtual std::fstream open(const std::string &path) noexcept = 0;
+        virtual std::vector<std::string> readDir(const std::string &path) const noexcept = 0;
+    };
+
+
+    /*
+     * void read_directory(const std::string& name, stringvec& v)
+{
+    DIR* dirp = opendir(name.c_str());
+    struct dirent * dp;
+    while ((dp = readdir(dirp)) != NULL) {
+        v.push_back(dp->d_name);
+    }
+    closedir(dirp);
+}
+     */
+}
+
+#endif //CXX_CELIX_IRESOURCEBUNDLE_H
diff --git a/bundles/config_admin/service/private/include/framework_patch.h b/libs/registry/include/celix/IServiceFactory.h
similarity index 57%
copy from bundles/config_admin/service/private/include/framework_patch.h
copy to libs/registry/include/celix/IServiceFactory.h
index 98194e1..af27312 100644
--- a/bundles/config_admin/service/private/include/framework_patch.h
+++ b/libs/registry/include/celix/IServiceFactory.h
@@ -16,24 +16,26 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * framework_patch.h
- *
- *  \date       Aug 12, 2013
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
 
+#ifndef CXX_CELIX_ISERVICEFACTORY_H
+#define CXX_CELIX_ISERVICEFACTORY_H
+
+#include "celix/Properties.h"
+#include "celix/IResourceBundle.h"
+
+namespace celix {
 
-#ifndef BUNDLE_PATCH_H_
-#define BUNDLE_PATCH_H_
+    template<typename I>
+    class IServiceFactory {
+    public:
+        using type = I;
 
+        virtual ~IServiceFactory() = default;
 
-/* celix.framework.public */
-#include "celix_errno.h"
-#include "bundle.h"
-#include "service_reference.h"
+        virtual I* getService(const celix::IResourceBundle &requestingBundle, const celix::Properties &properties) noexcept = 0;
+        virtual void ungetService(const celix::IResourceBundle &requestingBundle, const celix::Properties &properties) noexcept = 0;
+    };
 
-celix_status_t bundle_getBundleLocation(bundle_pt bundle, const char **location);
+}
 
-#endif /* BUNDLE_PATCH_H_ */
+#endif //CXX_CELIX_ISERVICEFACTORY_H
diff --git a/libs/registry/include/celix/Properties.h b/libs/registry/include/celix/Properties.h
new file mode 100644
index 0000000..65fd4ef
--- /dev/null
+++ b/libs/registry/include/celix/Properties.h
@@ -0,0 +1,60 @@
+/**
+ *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.
+ */
+
+#ifndef CXX_CELIX_PROPERTIES_H
+#define CXX_CELIX_PROPERTIES_H
+
+#include <string>
+#include <map>
+
+namespace celix {
+
+    using Properties = std::map<std::string, std::string>;
+
+    inline const std::string& getProperty(const Properties& props, const std::string &key, const std::string &defaultValue) noexcept {
+        auto it = props.find(key);
+        if (it != props.end()) {
+            return props.at(key);
+        } else {
+            return defaultValue;
+        }
+    }
+
+    inline int getProperty(const Properties& props, const std::string &key, int defaultValue)  noexcept {
+        std::string val = getProperty(props, key, std::to_string(defaultValue));
+        return std::stoi(val, nullptr, 10);
+    }
+
+    inline unsigned int getProperty(const Properties& props, const std::string &key, unsigned int defaultValue) noexcept {
+        std::string val = getProperty(props, key, std::to_string(defaultValue));
+        return static_cast<unsigned  int>(std::stoul(val, nullptr, 10)); //NOTE no std::stou ??
+    }
+
+    inline long getProperty(const Properties& props, const std::string &key, long defaultValue) noexcept {
+        std::string val = getProperty(props, key, std::to_string(defaultValue));
+        return std::stol(val, nullptr, 10);
+    }
+
+    inline unsigned int getProperty(const Properties& props, const std::string &key, unsigned long defaultValue) noexcept {
+        std::string val = getProperty(props, key, std::to_string(defaultValue));
+        return std::stoul(val, nullptr, 10);
+    }
+}
+
+#endif //CXX_CELIX_PROPERTIES_H
diff --git a/libs/registry/include/celix/ServiceRegistry.h b/libs/registry/include/celix/ServiceRegistry.h
new file mode 100644
index 0000000..7bbe16c
--- /dev/null
+++ b/libs/registry/include/celix/ServiceRegistry.h
@@ -0,0 +1,509 @@
+/**
+ *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.
+ */
+
+#ifndef CXX_CELIX_SERVICEREGISTRY_H
+#define CXX_CELIX_SERVICEREGISTRY_H
+
+#include <utility>
+#include <vector>
+
+#include "celix/Constants.h"
+#include "celix/Properties.h"
+#include "celix/Utils.h"
+#include "celix/IResourceBundle.h"
+#include "celix/IServiceFactory.h"
+
+namespace celix {
+
+    //forward declaration
+    class ServiceRegistry;
+
+    // RAII service registration: out of scope -> deregister service
+    // NOTE access not thread safe -> TODO make thread save?
+    class ServiceRegistration {
+    public:
+        ServiceRegistration();
+        ServiceRegistration(ServiceRegistration &&rhs) noexcept;
+        ServiceRegistration(const ServiceRegistration &rhs) = delete;
+        ~ServiceRegistration();
+        ServiceRegistration& operator=(ServiceRegistration &&rhs) noexcept;
+        ServiceRegistration& operator=(const ServiceRegistration &rhs) = delete;
+
+        long serviceId() const;
+        bool valid() const;
+        const celix::Properties& properties() const;
+        const std::string& serviceName() const;
+        bool factory() const;
+        bool registered() const;
+
+        void unregister();
+    private:
+        class Impl; //opaque impl class
+        std::unique_ptr<celix::ServiceRegistration::Impl> pimpl;
+        explicit ServiceRegistration(celix::ServiceRegistration::Impl *impl);
+        friend ServiceRegistry;
+    };
+
+    template<typename I>
+    struct ServiceTrackerOptions {
+        ServiceTrackerOptions() = default;
+        ServiceTrackerOptions(ServiceTrackerOptions &&rhs) noexcept = default;
+        ServiceTrackerOptions(const ServiceTrackerOptions &rhs) = default;
+        ServiceTrackerOptions& operator=(ServiceTrackerOptions &&rhs) = default;
+        ServiceTrackerOptions& operator=(const ServiceTrackerOptions &rhs) = default;
+
+        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(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(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(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<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 = {};
+    };
+
+    //RAII service tracker: out of scope -> stop tracker
+    // NOTE access not thread safe -> TODO make thread save?
+    class ServiceTracker {
+    public:
+        ServiceTracker();
+        ServiceTracker(ServiceTracker &&rhs) noexcept;
+        ServiceTracker(const ServiceTracker &rhs) = delete;
+        ~ServiceTracker();
+        ServiceTracker& operator=(ServiceTracker &&rhs) noexcept;
+        ServiceTracker& operator=(const ServiceTracker &rhs) = delete;
+
+        int trackCount() const;
+        const std::string& serviceName() const;
+        const std::string& filter() const;
+        bool valid() const;
+
+        //TODO useService(s) calls
+
+        void stop();
+    private:
+        class Impl; //opaque impl class
+        std::unique_ptr<celix::ServiceTracker::Impl> pimpl;
+        explicit ServiceTracker(celix::ServiceTracker::Impl *impl);
+        friend ServiceRegistry;
+    };
+
+    //NOTE access thread safe
+    class ServiceRegistry {
+    public:
+        explicit ServiceRegistry(std::string name);
+        ~ServiceRegistry();
+        ServiceRegistry(celix::ServiceRegistry &&rhs) noexcept;
+        ServiceRegistry& operator=(celix::ServiceRegistry&& rhs);
+        ServiceRegistry& operator=(ServiceRegistry &rhs) = delete;
+        ServiceRegistry(const ServiceRegistry &rhs) = delete;
+
+        const std::string& name() const;
+
+        template<typename I>
+        celix::ServiceRegistration registerService(I &svc, celix::Properties props = {}, std::shared_ptr<const celix::IResourceBundle> owner = {}) {
+            auto svcName = celix::serviceName<I>();
+            auto voidSvc = std::shared_ptr<void>(static_cast<void*>(&svc), [](void*){/*nop*/}); //transform to std::shared_ptr to minimize the underlining impl needed.
+            return registerService(svcName, std::move(voidSvc), std::move(props), std::move(owner));
+        }
+
+        template<typename I>
+        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));
+        }
+
+        template<typename F>
+        celix::ServiceRegistration registerFunctionService(const std::string &functionName, F&& func, celix::Properties props = {}, std::shared_ptr<const celix::IResourceBundle> owner = {});
+
+        template<typename I>
+        celix::ServiceRegistration registerServiceFactory(std::shared_ptr<celix::IServiceFactory<I>> factory, celix::Properties props = {}, std::shared_ptr<const celix::IResourceBundle> owner = {});
+
+        template<typename I>
+        //NOTE C++17 typename std::enable_if<!std::is_callable<I>::value, long>::type
+        long findService(const std::string &filter = "") const {
+            auto services = findServices<I>(filter);
+            return services.size() > 0 ? services[0] : -1L;
+        }
+
+        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);
+            return services.size() > 0 ? services[0] : -1L;
+        }
+
+        template<typename I>
+        //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);
+        }
+
+        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);
+        }
+
+        template<typename I>
+        celix::ServiceTracker trackServices(celix::ServiceTrackerOptions<I> options = {}, std::shared_ptr<const celix::IResourceBundle> requester = {}) {
+            auto svcName = celix::serviceName<I>();
+            return trackServices<I>(svcName, std::move(options), std::move(requester));
+        }
+
+        template<typename F>
+        celix::ServiceTracker trackFunctionServices(std::string functionName, celix::ServiceTrackerOptions<F> options = {}, std::shared_ptr<const celix::IResourceBundle> requester = {}) {
+            auto svcName = celix::functionServiceName<F>(functionName);
+            return trackServices<F>(svcName, std::move(options), std::move(requester));
+        }
+
+        //TODO trackTrackers
+
+        template<typename I>
+        int useServices(std::function<void(I& svc)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::serviceName<I>();
+            return useServices<I>(svcName, use, nullptr, nullptr, filter, std::move(requester));
+        }
+
+        template<typename I>
+        int useServices(std::function<void(I& svc, const celix::Properties &props)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::serviceName<I>();
+            return useServices<I>(svcName, nullptr, use, nullptr, filter, std::move(requester));
+        }
+
+        template<typename I>
+        int useServices(std::function<void(I& svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::serviceName<I>();
+            return useServices<I>(svcName, nullptr, nullptr, use, filter, std::move(requester));
+        }
+
+        template<typename F>
+        int useFunctionServices(const std::string &functionName, std::function<void(F &function)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::functionServiceName<F>(functionName);
+            return useServices<F>(svcName, use, nullptr, nullptr, filter, std::move(requester));
+        }
+
+        template<typename F>
+        int useFunctionServices(const std::string &functionName, std::function<void(F &function, const celix::Properties&)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::functionServiceName<F>(functionName);
+            return useServices<F>(svcName, nullptr, use, nullptr, filter, std::move(requester));
+        }
+
+        template<typename F>
+        int useFunctionServices(const std::string &functionName, std::function<void(F &function, const celix::Properties&, const celix::IResourceBundle&)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::functionServiceName<F>(functionName);
+            return useServices<F>(svcName, nullptr, nullptr, use, filter, std::move(requester));
+        }
+
+        template<typename I>
+        bool useService(std::function<void(I& svc)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::serviceName<I>();
+            return useService<I>(svcName, use, nullptr, nullptr, filter, std::move(requester));
+        }
+
+        template<typename I>
+        bool useService(std::function<void(I& svc, const celix::Properties &props)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::serviceName<I>();
+            return useService<I>(svcName, nullptr, use, nullptr, filter, std::move(requester));
+        }
+
+        template<typename I>
+        bool useService(std::function<void(I& svc, const celix::Properties &props, const celix::IResourceBundle &bnd)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::serviceName<I>();
+            return useService<I>(svcName, nullptr, nullptr, use, filter, std::move(requester));
+        }
+
+        template<typename F>
+        int useFunctionService(const std::string &functionName, std::function<void(F &function)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::functionServiceName<F>(functionName);
+            return useService<F>(svcName, use, nullptr, nullptr, filter, std::move(requester));
+        }
+
+        template<typename F>
+        int useFunctionService(const std::string &functionName, std::function<void(F &function, const celix::Properties&)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::functionServiceName<F>(functionName);
+            return useService<F>(svcName, nullptr, use, nullptr, filter, std::move(requester));
+        }
+
+        template<typename F>
+        int useFunctionService(const std::string &functionName, std::function<void(F &function, const celix::Properties&, const celix::IResourceBundle&)> use, const std::string &filter = "", std::shared_ptr<const celix::IResourceBundle> requester = {}) const {
+            auto svcName = celix::functionServiceName<F>(functionName);
+            return useService<F>(svcName, nullptr, nullptr, use, filter, std::move(requester));
+        }
+
+
+        long nrOfRegisteredServices() const;
+        long nrOfServiceTrackers() const;
+    private:
+        class Impl;
+        std::unique_ptr<celix::ServiceRegistry::Impl> pimpl;
+
+        //register services
+        celix::ServiceRegistration registerService(std::string svcName, std::shared_ptr<void> svc, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner);
+        celix::ServiceRegistration registerServiceFactory(std::string svcName, std::shared_ptr<celix::IServiceFactory<void>> factory, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner);
+
+        //use Services
+        template<typename I>
+        int useServices(
+                const std::string &svcName,
+                std::function<void(I &svc)> use,
+                std::function<void(I &svc, const celix::Properties &props)> useWithProps,
+                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(
+                const std::string &svcName,
+                std::function<void(I &svc)> use,
+                std::function<void(I &svc, const celix::Properties &props)> useWithProps,
+                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);
+    };
+}
+
+
+template<typename F>
+inline celix::ServiceRegistration celix::ServiceRegistry::registerFunctionService(const std::string &functionName, F&& func, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) {
+    class FunctionServiceFactory : public celix::IServiceFactory<void> {
+    public:
+        FunctionServiceFactory(F&& _function) : function{std::forward<F>(_function)} {}
+
+        void* getService(const celix::IResourceBundle &, const celix::Properties &) noexcept override {
+            return static_cast<void*>(&function);
+        }
+        void ungetService(const celix::IResourceBundle &, const celix::Properties &) noexcept override {
+            //nop;
+        }
+    private:
+        F function;
+    };
+    auto factory = std::shared_ptr<celix::IServiceFactory<void>>{new FunctionServiceFactory{std::forward<F>(func)}};
+
+    std::string svcName = celix::functionServiceName<typename std::remove_reference<F>::type>(functionName);
+
+    return registerServiceFactory(std::move(svcName), factory, std::move(props), std::move(owner));
+}
+
+template<typename I>
+inline celix::ServiceRegistration celix::ServiceRegistry::registerServiceFactory(std::shared_ptr<celix::IServiceFactory<I>> factory, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) {
+    std::string svcName = celix::serviceName<I>();
+
+    class VoidServiceFactory : public celix::IServiceFactory<void> {
+    public:
+        VoidServiceFactory(std::shared_ptr<celix::IServiceFactory<I>> _factory) : factory{std::move(_factory)} {}
+
+        void* getService(const celix::IResourceBundle &bnd, const celix::Properties &props) noexcept override {
+            I* service = factory->getService(bnd, props);
+            return static_cast<void*>(service);
+        }
+        void ungetService(const celix::IResourceBundle &bnd, const celix::Properties &props) noexcept override {
+            factory->ungetService(bnd, props);
+        }
+    private:
+        std::shared_ptr<celix::IServiceFactory<I>> factory;
+    };
+
+    auto voidFactory = std::shared_ptr<celix::IServiceFactory<void>>{new VoidServiceFactory{std::move(factory)}};
+    return registerServiceFactory(std::move(svcName), std::move(voidFactory), std::move(props), std::move(owner));
+}
+
+template<typename I>
+inline int celix::ServiceRegistry::useServices(
+        const std::string &svcName,
+        std::function<void(I &svc)> use,
+        std::function<void(I &svc, const celix::Properties &props)> useWithProps,
+        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);
+        if (use) {
+            use(*typedSvc);
+        }
+        if (useWithProps) {
+            useWithProps(*typedSvc, props);
+        }
+        if (useWithOwner) {
+            useWithOwner(*typedSvc, props, bnd);
+        }
+    };
+    return useServices(svcName, voidUse, filter, requester);
+}
+
+template<typename I>
+inline bool celix::ServiceRegistry::useService(
+        const std::string &svcName,
+        std::function<void(I &svc)> use,
+        std::function<void(I &svc, const celix::Properties &props)> useWithProps,
+        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);
+        if (use) {
+            use(*typedSvc);
+        }
+        if (useWithProps) {
+            useWithProps(*typedSvc, props);
+        }
+        if (useWithOwner) {
+            useWithOwner(*typedSvc, props, bnd);
+        }
+    };
+    return useService(svcName, voidUse, filter, 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) {
+    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);
+            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);
+            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);
+            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*
+            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*
+            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*
+            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*
+            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*
+            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*
+            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{};
+            typedServices.reserve(rankedServices.size());
+            for (void *svc : rankedServices) {
+                typedServices.push_back(static_cast<I*>(svc));
+            }
+            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{};
+            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)));
+            }
+            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{};
+            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)));
+            }
+            update(std::move(typedServices));
+        };
+    }
+
+    return trackServices(std::move(svcName), std::move(opts), requester);
+}
+
+#endif //CXX_CELIX_SERVICEREGISTRY_H
diff --git a/libs/registry/include/celix/Utils.h b/libs/registry/include/celix/Utils.h
new file mode 100644
index 0000000..ae61cd7
--- /dev/null
+++ b/libs/registry/include/celix/Utils.h
@@ -0,0 +1,102 @@
+/**
+ *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.
+ */
+
+#ifndef CXX_CELIX_UTILS_H
+#define CXX_CELIX_UTILS_H
+
+
+#include <string>
+#include <iostream>
+
+namespace {
+
+    template<typename INTERFACE_TYPENAME>
+    std::string typeName() {
+        std::string result;
+
+        const char *templateStr = "INTERFACE_TYPENAME = ";
+        const size_t templateStrLen = strlen(templateStr);
+
+        result = __PRETTY_FUNCTION__; //USING pretty function to retrieve the filled in template argument without using typeid()
+        size_t bpos = result.find(templateStr) + templateStrLen; //find begin pos after INTERFACE_TYPENAME = entry
+        size_t epos = bpos;
+        while (isalnum(result[epos]) || result[epos] == '_' || result[epos] == ':' || result[epos] == ' ' || result[epos] == '*' || result[epos] == '&' || result[epos] == '<' || result[epos] == '>') {
+            epos += 1;
+        }
+        size_t len = epos - bpos;
+        result = result.substr(bpos, len);
+
+        if (result.empty()) {
+            std::cerr << "Cannot infer type name in function call '" << __PRETTY_FUNCTION__ << "'\n'";
+        }
+
+        return result;
+    }
+
+    template<typename Arg>
+    std::string argName() {
+        return typeName<Arg>(); //terminal;
+    }
+
+    template<typename Arg1, typename Arg2, typename... Args>
+    std::string argName() {
+        return typeName<Arg1>() + ", " + argName<Arg2, Args...>();
+    }
+
+    template<typename R>
+    std::string functionName(const std::string &funcName) {
+        return funcName + " [std::function<" + typeName<R>() + "()>]";
+    }
+
+    template<typename R, typename Arg1, typename... Args>
+    std::string functionName(const std::string &funcName) {
+        return funcName + " [std::function<" + typeName<R>() + "("  + argName<Arg1, Args...>() + ")>]";
+    }
+};
+
+namespace celix {
+
+    /* TODO
+    template<typename I>
+    typename std::enable_if<I::FQN, std::string>::type
+    serviceName() {
+        return I::FQN;
+    }*/
+
+    /**
+    * Returns the service name for a type I
+    */
+    template<typename I>
+    //NOTE C++17 typename std::enable_if<!std::is_callable<I>::value, std::string>::type
+    std::string serviceName() {
+        return typeName<I>();
+    }
+
+    /**
+    * Returns the service name for a std::function I.
+    * Note that for a std::function the additional function name is needed to get a fully qualified service name;
+    */
+    template<typename F>
+    //NOTE C++17 typename std::enable_if<std::is_callable<I>::value, std::string>::type
+    std::string functionServiceName(const std::string &fName) {
+        return functionName<decltype(&F::operator())>(fName);
+    }
+}
+
+#endif //CXX_CELIX_UTILS_H
diff --git a/libs/registry/src/Filter.cc b/libs/registry/src/Filter.cc
new file mode 100644
index 0000000..b92cf32
--- /dev/null
+++ b/libs/registry/src/Filter.cc
@@ -0,0 +1,464 @@
+/**
+ *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 "celix/Filter.h"
+
+#include <glog/logging.h>
+
+static celix::FilterCriteria* filter_parseFilter(const char *filterString, int *pos);
+static void filter_skipWhiteSpace(const char *filterString, int *pos);
+static celix::FilterCriteria* filter_parseAndOrOr(const char *filterString, celix::FilterOperator andOrOr, int *pos);
+static celix::FilterCriteria* filter_parseFilterComp(const char *filterString, int *pos);
+static celix::FilterCriteria* filter_parseItem(const char *filterString, int *pos);
+static std::string filter_parseAttr(const char *filterString, int *pos);
+static std::string filter_parseValue(const char *filterString, int *pos);
+
+static void filter_skipWhiteSpace(const char *filterString, int *pos) {
+    size_t length;
+    for (length = strlen(filterString); (*pos < (int)(length)) && isspace(filterString[*pos]);) {
+        (*pos)++;
+    }
+}
+
+static celix::FilterCriteria* filter_parseAndOrOr(const char *filterString, celix::FilterOperator andOrOr, int *pos) {
+
+    filter_skipWhiteSpace(filterString, pos);
+    bool failure = false;
+
+    if (filterString[*pos] != '(') {
+        LOG(ERROR) << "Filter Error: Missing '('.\n";
+        return nullptr;
+    }
+
+    std::vector<std::shared_ptr<celix::FilterCriteria>> subcriteria{};
+    while (filterString[*pos] == '(') {
+        celix::FilterCriteria *cr = filter_parseFilter(filterString, pos);
+        if (cr == nullptr) {
+            failure = true;
+            break;
+        }
+        subcriteria.push_back(std::unique_ptr<celix::FilterCriteria>{cr});
+    }
+
+
+    celix::FilterCriteria* criteria = nullptr;
+    if (!failure) {
+        criteria = new celix::FilterCriteria{
+            .attribute = "",
+            .op = andOrOr,
+            .value = "",
+            .subcriteria = std::move(subcriteria)
+        };
+    }
+
+    return criteria;
+}
+
+static celix::FilterCriteria* filter_parseNot(const char * filterString, int * pos) {
+    celix::FilterCriteria *criteria = nullptr;
+
+    filter_skipWhiteSpace(filterString, pos);
+    if (filterString[*pos] != '(') {
+        LOG(ERROR) << "Filter Error: Missing '('.\n";
+        return nullptr;
+    }
+
+    std::vector<std::shared_ptr<celix::FilterCriteria>> subcriteria{};
+    celix::FilterCriteria *cr = filter_parseFilter(filterString, pos);
+    if (cr != nullptr) {
+        subcriteria.push_back(std::unique_ptr<celix::FilterCriteria>(cr));
+        criteria = new celix::FilterCriteria {
+            .attribute = "",
+            .op = celix::FilterOperator::NOT,
+            .value = "",
+            .subcriteria = std::move(subcriteria)
+        };
+    }
+
+    return criteria;
+}
+
+static std::string filter_parseAttr(const char *filterString, int *pos) {
+    std::string attr{};
+    char c;
+    int begin = *pos;
+    int end = *pos;
+    int length = 0;
+
+    filter_skipWhiteSpace(filterString, pos);
+    c = filterString[*pos];
+
+    while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') {
+        (*pos)++;
+
+        if (!isspace(c)) {
+            end = *pos;
+        }
+
+        c = filterString[*pos];
+    }
+
+    length = end - begin;
+
+    if (length == 0) {
+        LOG(ERROR) << "Filter Error: Missing attr.\n";
+    } else {
+        attr.assign(filterString+begin, (size_t)length);
+    }
+
+    return attr;
+}
+
+static std::string filter_parseValue(const char *filterString, int *pos) {
+    std::string val{};
+    int keepRunning = 1;
+
+    while (keepRunning) {
+        char c = filterString[*pos];
+
+        switch (c) {
+            case ')': {
+                keepRunning = 0;
+                break;
+            }
+            case '(': {
+                LOG(ERROR) << "Filter Error: Invalid value.\n";
+                val = "";
+                keepRunning = 0;
+                break;
+            }
+            case '\0':{
+                LOG(ERROR) << "Filter Error: Unclosed bracket.\n";
+                val = "";
+                keepRunning = 0;
+                break;
+            }
+            case '\\': {
+                (*pos)++;
+                c = filterString[*pos];
+                char ch[2];
+                ch[0] = c;
+                ch[1] = '\0';
+                val.append(ch);
+                (*pos)++;
+                break;
+            }
+            default: {
+                char ch[2];
+                ch[0] = c;
+                ch[1] = '\0';
+                val.append(ch);
+                (*pos)++;
+                break;
+            }
+        }
+    }
+
+    if (val.empty()) {
+        LOG(ERROR) << "Filter Error: Missing value.\n";
+    }
+    return val;
+}
+
+static celix::FilterCriteria* filter_parseItem(const char * filterString, int * pos) {
+    celix::FilterCriteria* criteria = nullptr;
+
+    std::string attr = filter_parseAttr(filterString, pos);
+    if (attr.empty()) {
+        return nullptr;
+    }
+
+    filter_skipWhiteSpace(filterString, pos);
+    switch(filterString[*pos]) {
+        case '~': {
+            if (filterString[*pos + 1] == '=') {
+                *pos += 2; //skip ~=
+                std::string val = filter_parseValue(filterString, pos);
+                if (val.empty()) {
+                    LOG(ERROR) << "Unexpected emtpy value after ~= operator in filter '" << filterString << "'\n";
+                } else {
+                    criteria = new celix::FilterCriteria{
+                            .attribute = std::move(attr),
+                            .op = celix::FilterOperator::APPROX,
+                            .value = std::move(val),
+                            .subcriteria = {}
+                    };
+                }
+            } else {
+                LOG(ERROR) << "Unexpected ~ char without the expected = in filter '" << filterString << "'\n";
+            }
+            break;
+        }
+        case '>': {
+            auto op = celix::FilterOperator::GREATER;
+            if (filterString[*pos + 1] == '=') {
+                *pos += 2; //skip >=
+                op = celix::FilterOperator::GREATER_EQUAL;
+            } else {
+                *pos += 1; //skip >
+            }
+            std::string val = filter_parseValue(filterString, pos);
+            if (val.empty()) {
+                LOG(ERROR) << "Unexpected empty value in > or >= operator for filter '" << filterString << "'\n";
+            } else {
+                criteria = new celix::FilterCriteria{
+                        .attribute = std::move(attr),
+                        .op = op,
+                        .value = std::move(val),
+                        .subcriteria = {}
+                };
+            }
+            break;
+        }
+        case '<': {
+            celix::FilterOperator op = celix::FilterOperator::LESS;
+            if (filterString[*pos + 1] == '=') {
+                *pos += 2; //skip <=
+                op = celix::FilterOperator::LESS_EQUAL;
+            } else {
+                *pos += 1; //skip <
+            }
+            std::string val = filter_parseValue(filterString, pos);
+            if (val.empty()) {
+                LOG(ERROR) << "Unexpected emtpy value after < or <= operator in filter '" << filterString <<"'\n";
+            } else {
+                criteria = new celix::FilterCriteria {
+                        .attribute = std::move(attr),
+                        .op = op,
+                        .value = std::move(val),
+                        .subcriteria = {}
+                };
+            }
+            break;
+        }
+        case '=': {
+            if (filterString[*pos + 1] == '*') {
+                int oldPos = *pos;
+                *pos += 2; //skip =*
+                filter_skipWhiteSpace(filterString, pos);
+                if (filterString[*pos] == ')') {
+                    criteria = new celix::FilterCriteria{
+                            .attribute = attr,
+                            .op = celix::FilterOperator::PRESENT,
+                            .value = "",
+                            .subcriteria = {}
+                    };
+                } else {
+                    *pos = oldPos; //no present criteria -> reset
+                }
+            }
+            if (criteria == nullptr) { //i.e. no present criteria set
+                //note that the value can start and end with a wildchar *. this is not parsed specifically, but tested
+                *pos += 1; //skip =
+                filter_skipWhiteSpace(filterString, pos);
+                std::string val = filter_parseValue(filterString, pos);
+                bool substring = val.size() > 2 && (val.front() == '*' || val.back() == '*');
+                if (val.empty()) {
+                    LOG(ERROR) << "Unexpected emtpy value after = operator in filter '" << filterString << "'\n";
+                } else {
+                    criteria = new celix::FilterCriteria{
+                            .attribute = std::move(attr),
+                            .op = substring ? celix::FilterOperator::SUBSTRING : celix::FilterOperator::EQUAL,
+                            .value = std::move(val),
+                            .subcriteria = {}
+                    };
+                }
+            }
+            break;
+        }
+        default: {
+            LOG(ERROR) << "Unexpected operator " << *pos << std::endl;
+            break;
+        }
+    }
+
+    if (criteria == nullptr) {
+        LOG(ERROR) << "Filter Error: Invalid operator.\n";
+    }
+
+    return criteria;
+}
+
+static celix::FilterCriteria* filter_parseFilterComp(const char *filterString, int *pos) {
+    celix::FilterCriteria* criteria = nullptr;
+    char c;
+    filter_skipWhiteSpace(filterString, pos);
+
+    c = filterString[*pos];
+
+    switch (c) {
+        case '&': {
+            (*pos)++;
+            criteria = filter_parseAndOrOr(filterString, celix::FilterOperator::AND, pos);
+            break;
+        }
+        case '|': {
+            (*pos)++;
+            criteria = filter_parseAndOrOr(filterString, celix::FilterOperator::OR, pos);
+            break;
+        }
+        case '!': {
+            (*pos)++;
+            criteria = filter_parseNot(filterString, pos);
+            break;
+        }
+        default : {
+            criteria =filter_parseItem(filterString, pos);
+            break;
+        }
+    }
+    return criteria;
+}
+
+
+static celix::FilterCriteria* filter_parseFilter(const char *filterString, int *pos) {
+    celix::FilterCriteria *criteria = nullptr;
+    filter_skipWhiteSpace(filterString, pos);
+    if (filterString[*pos] != '(') {
+        LOG(ERROR) << "Filter Error: Missing '(' in filter string '" << filterString << "'.\n";
+        return NULL;
+    }
+    (*pos)++; //consume (
+
+    criteria = filter_parseFilterComp(filterString, pos);
+
+    filter_skipWhiteSpace(filterString, pos);
+
+    if (filterString[*pos] != ')') {
+        LOG(ERROR) << "Filter Error: Missing ')' in filter string '" << filterString << "'.\n";
+        if (criteria != NULL) {
+            delete criteria;
+        }
+        return NULL;
+    }
+    (*pos)++;
+    filter_skipWhiteSpace(filterString, pos);
+
+    return criteria;
+}
+
+celix::FilterCriteria* celix::Filter::parseFilter() {
+    celix::FilterCriteria* criteria = nullptr;
+    if (!filterStr.empty()) {
+        int pos = 0;
+        criteria = filter_parseFilter(filterStr.c_str(), &pos);
+        if (criteria != nullptr && pos != (int) filterStr.size()) {
+            LOG(ERROR) << "Filter Error: Missing '(' in filter string '" << filterStr << "'.'n";
+            delete criteria;
+            criteria = nullptr;
+        }
+    }
+    return criteria;
+}
+
+static bool match_criteria(const celix::Properties &props, const celix::FilterCriteria &criteria) {
+    bool result;
+    switch (criteria.op) {
+        case celix::FilterOperator::AND: {
+            result = true;
+            for (const auto &sc : criteria.subcriteria) {
+                if (!match_criteria(props, *sc)) {
+                    result = false;
+                    break;
+                }
+            }
+            break;
+        }
+        case celix::FilterOperator::OR: {
+            result = false;
+            for (const auto &sc : criteria.subcriteria) {
+                if (match_criteria(props, *sc)) {
+                    result = true;
+                    break;
+                }
+            }
+            break;
+        }
+        case celix::FilterOperator::NOT: {
+            result = !match_criteria(props, *criteria.subcriteria[0]);
+            break;
+        }
+        case celix::FilterOperator::SUBSTRING: {
+            const std::string &val = celix::getProperty(props, criteria.attribute, "");
+            if (val.empty()) {
+                result = false;
+            } else {
+                bool wildcharAtFront = criteria.value.front() == '*';
+                bool wildcharAtBack = criteria.value.back() == '*';
+                std::string needle = wildcharAtFront ? criteria.value.substr(1) : criteria.value;
+                needle = wildcharAtBack ? needle.substr(0, needle.size() - 1) : needle;
+                const char *ptr = strstr(val.c_str(), needle.c_str());
+                if (wildcharAtFront && wildcharAtBack) {
+                    result = ptr != nullptr;
+                } else if (wildcharAtFront) { //-> end must match
+                    result = ptr != nullptr && ptr + strlen(ptr) == val.c_str() + strlen(val.c_str());
+                } else { //wildCharAtBack -> begin must match
+                    result = ptr != nullptr && ptr == val.c_str();
+                }
+            }
+            break;
+        }
+        case celix::FilterOperator::EQUAL: {
+            const std::string &val = celix::getProperty(props, criteria.attribute, "");
+            result = !val.empty() && val == criteria.value;
+            break;
+        }
+        case celix::FilterOperator::GREATER_EQUAL: {
+            const std::string &val = celix::getProperty(props, criteria.attribute, "");
+            result = !val.empty() && val >= criteria.value;
+            break;
+        }
+        case celix::FilterOperator::LESS: {
+            const std::string &val = celix::getProperty(props, criteria.attribute, "");
+            result = !val.empty() && val < criteria.value;
+            break;
+        }
+        case celix::FilterOperator::LESS_EQUAL: {
+            const std::string &val = celix::getProperty(props, criteria.attribute, "");
+            result = !val.empty() && val <= criteria.value;
+            break;
+        }
+        case celix::FilterOperator::PRESENT: {
+            const std::string &val = celix::getProperty(props, criteria.attribute, "");
+            result = !val.empty();
+            break;
+        }
+        case celix::FilterOperator::APPROX: {
+            const std::string &val = celix::getProperty(props, criteria.attribute, "");
+            result = !val.empty() && strcasecmp(val.c_str(), criteria.value.c_str()) == 0;
+            break;
+        }
+        default: {
+            result = false;
+            break;
+        }
+    }
+
+    return result;
+}
+
+bool celix::Filter::match(const celix::Properties &props) const {
+    if (!valid()) {
+        return false;
+    } else if (filterStr.empty()) {
+        return true;
+    }
+
+    return match_criteria(props, *criteria);
+}
\ No newline at end of file
diff --git a/libs/registry/src/ServiceRegistry.cc b/libs/registry/src/ServiceRegistry.cc
new file mode 100644
index 0000000..862013f
--- /dev/null
+++ b/libs/registry/src/ServiceRegistry.cc
@@ -0,0 +1,716 @@
+#include <utility>
+
+/**
+ *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 <unordered_map>
+#include <mutex>
+#include <set>
+#include <utility>
+#include <thread>
+
+#include <glog/logging.h>
+
+#include "celix/Constants.h"
+#include "celix/ServiceRegistry.h"
+#include "celix/Filter.h"
+
+static std::string emptyString{};
+
+namespace {
+
+    class EmptyBundle : public celix::IResourceBundle {
+    public:
+        ~EmptyBundle() override = default;
+
+        long id() const noexcept override { return 0; }
+
+        const std::string& root() const noexcept override {
+            static std::string empty{};
+            return empty;
+        }
+
+        bool has(const std::string&) const noexcept override { return false; }
+        bool isDir(const std::string&) const noexcept override { return false; }
+        bool isFile(const std::string&) const noexcept override { return false; }
+
+        //std::istream& open(const std::string &path) override {}
+        //std::fstream& open(const std::string &path) override {}
+        std::vector<std::string> readDir(const std::string&) const noexcept override { return std::vector<std::string>{};}
+    };
+
+    struct SvcEntry {
+        explicit SvcEntry(std::shared_ptr<const celix::IResourceBundle> _owner, long _svcId, std::string _svcName, std::shared_ptr<void> _svc, std::shared_ptr<celix::IServiceFactory<void>> _svcFac,
+                 celix::Properties &&_props) :
+                owner{std::move(_owner)}, svcId{_svcId}, svcName{std::move(_svcName)},
+                props{std::forward<celix::Properties>(_props)},
+                ranking{celix::getProperty(props, celix::SERVICE_RANKING, 0L)},
+                svc{_svc}, svcFactory{_svcFac} {}
+
+        SvcEntry(SvcEntry &&rhs) = delete;
+        SvcEntry &operator=(SvcEntry &&rhs) = delete;
+        SvcEntry(const SvcEntry &rhs) = delete;
+        SvcEntry &operator=(const SvcEntry &rhs) = delete;
+
+        const std::shared_ptr<const celix::IResourceBundle> owner;
+        const long svcId;
+        const std::string svcName;
+        const celix::Properties props;
+        const long ranking;
+
+        void *service(const celix::IResourceBundle &requester) const {
+            if (svcFactory) {
+                return svcFactory->getService(requester, props);
+            } else {
+                return svc.get();
+            }
+        }
+
+        bool factory() const { return svcFactory != nullptr; }
+
+        void incrUsage() const {
+            LOG(WARNING) << "TODO use shared_ptr unique instead ?? how to 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();
+        }
+
+        void waitTillUnused() const {
+            std::unique_lock<std::mutex> lock{mutex};
+            cond.wait(lock, [this]{return usage == 0;});
+        }
+    private:
+        //svc, svcSharedPtr or svcFactory is set
+        const std::shared_ptr<void> svc;
+        const std::shared_ptr<celix::IServiceFactory<void>> svcFactory;
+
+
+        //sync TODO refactor to atomics
+        mutable std::mutex mutex{};
+        mutable std::condition_variable cond{};
+        mutable int usage{1};
+    };
+
+    struct SvcEntryLess {
+        bool operator()( const std::shared_ptr<const SvcEntry>& lhs, const std::shared_ptr<const SvcEntry>& rhs ) const {
+            if (lhs->ranking == rhs->ranking) {
+                return lhs->svcId < rhs->svcId;
+            } else {
+                return lhs->ranking > rhs->ranking; //note inverse -> higher rank first in set
+            }
+        }
+    };
+
+    struct SvcTrackerEntry {
+        const long id;
+        const std::shared_ptr<const celix::IResourceBundle> owner;
+        const std::string svcName;
+        const celix::ServiceTrackerOptions<void> opts;
+        const celix::Filter filter;
+
+        explicit SvcTrackerEntry(long _id, std::shared_ptr<const celix::IResourceBundle> _owner, std::string _svcName, celix::ServiceTrackerOptions<void> _opts) :
+            id{_id}, owner{std::move(_owner)}, svcName{std::move(_svcName)}, opts{std::move(_opts)}, filter{opts.filter} {}
+
+        SvcTrackerEntry(SvcTrackerEntry &&rhs) = delete;
+        SvcTrackerEntry &operator=(SvcTrackerEntry &&rhs) = delete;
+        SvcTrackerEntry(const SvcTrackerEntry &rhs) = delete;
+        SvcTrackerEntry &operator=(const SvcTrackerEntry &rhs) = delete;
+        ~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);
+                }
+                tracked.entries.clear();
+            }
+            for (auto &entry : removeEntries) {
+                remMatch(entry); //note fill try to erase entry from entries again, TODO check if this is safe
+            }
+        }
+
+        bool valid() const {
+            return !svcName.empty() && filter.valid();
+        }
+
+        bool match(const SvcEntry& entry) const {
+            //note should only called for the correct svcName
+            assert(svcName == entry.svcName);
+
+            if (filter.empty()) {
+                return true;
+            } else {
+                return filter.match(entry.props);
+            }
+        }
+
+        void addMatch(std::shared_ptr<const SvcEntry> entry) {
+            //increase usage so that services cannot be removed while a service tracker is still active
+            entry->incrUsage();
+
+            {
+                std::lock_guard<std::mutex> lck{tracked.mutex};
+                tracked.entries.insert(entry);
+            }
+
+            //call callbacks
+            callSetCallbacks();
+            callAddRemoveCallbacks(entry, true);
+            callUpdateCallbacks();
+        }
+
+        void remMatch(const std::shared_ptr<const SvcEntry> &entry) {
+            {
+                std::lock_guard<std::mutex> lck{tracked.mutex};
+                tracked.entries.erase(entry);
+            }
+
+            //call callbacks
+            callSetCallbacks();
+            callAddRemoveCallbacks(entry, false);
+            callUpdateCallbacks();
+
+            //decrease usage so that services cannot be removed while a service tracker is still active
+            entry->decrUsage();
+        }
+
+        void callAddRemoveCallbacks(const std::shared_ptr<const SvcEntry> &updatedEntry, bool add) {
+            auto &update = add ? opts.add : opts.remove;
+            if (update != nullptr) {
+                void *svc = updatedEntry->service(*owner);
+                update(svc);
+            }
+            //TODO rest of add/remove
+        }
+
+        void callSetCallbacks() {
+            std::shared_ptr<const SvcEntry> currentHighest;
+            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 (currentHighest != tracked.highest) {
+                    tracked.highest = currentHighest;
+                    highestUpdated = true;
+                }
+            }
+
+            //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);
+                }
+                //TODO rest of set
+            }
+        }
+
+        void callUpdateCallbacks() {
+            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));
+                    }
+                }
+                opts.update(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();
+        }
+
+        void waitTillUnused() const {
+            std::unique_lock<std::mutex> lock{mutex};
+            cond.wait(lock, [this]{return usage == 0;});
+        }
+    private:
+        struct {
+            mutable std::mutex mutex; //protects matchedEntries & highestRanking
+            std::set<std::shared_ptr<const SvcEntry>, SvcEntryLess> entries{};
+            std::shared_ptr<const SvcEntry> highest{};
+        } tracked{};
+
+
+        //sync TODO refactor to atomics
+        mutable std::mutex mutex{};
+        mutable std::condition_variable cond{};
+        mutable int usage{1};
+    };
+}
+
+/**********************************************************************************************************************
+  Impl classes
+ **********************************************************************************************************************/
+
+class celix::ServiceRegistration::Impl {
+public:
+    const std::shared_ptr<const SvcEntry> entry;
+    const std::function<void()> unregisterCallback;
+    bool registered; //TODO make atomic?
+};
+
+class celix::ServiceTracker::Impl {
+public:
+    const std::shared_ptr<SvcTrackerEntry> entry;
+    const std::function<void()> untrackCallback;
+    bool active; //TODO make atomic?
+};
+
+class celix::ServiceRegistry::Impl {
+public:
+    const std::shared_ptr<const celix::IResourceBundle> emptyBundle = std::shared_ptr<const celix::IResourceBundle>{new EmptyBundle{}};
+    std::string regName;
+
+    struct {
+        mutable std::mutex mutex{};
+        long nextSvcId = 1L;
+
+        /* Services entries are always stored for it specific svc name.
+         * When using services is it always expected that the svc name is provided, and as such
+         * storing per svc name is more logical.
+         *
+         * Note that this also means that the classic 99% use cases used OSGi filter (objectClass=<svcName>)
+         * is not needed anymore -> simpler and faster.
+         *
+         * map key is svcName and the map value is a set of SvcEntry structs.
+         * note: The SvcEntry set is ordered (i.e. not a hashset with O(1) access) to ensure that service ranking and
+         * service id can be used for their position in the set (see SvcEntryLess).
+         */
+        std::unordered_map<std::string, std::set<std::shared_ptr<const SvcEntry>, SvcEntryLess>> registry{};
+
+        //Cache map for faster and easier access based on svcId.
+        std::unordered_map<long, std::shared_ptr<const SvcEntry>> cache{};
+    } services{};
+
+    struct {
+        mutable std::mutex mutex{};
+        long nextTrackerId = 1L;
+
+        /* Note same ordering as services registry, expect the ranking order requirement,
+         * so that it is easier and faster to update the trackers.
+         */
+        std::unordered_map<std::string, std::set<std::shared_ptr<SvcTrackerEntry>>> registry{};
+        std::unordered_map<long, std::shared_ptr<SvcTrackerEntry>> cache{};
+    } trackers{};
+
+    celix::ServiceRegistration registerService(std::string serviceName, std::shared_ptr<void> svc, std::shared_ptr<celix::IServiceFactory<void>> factory, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) {
+        props[celix::SERVICE_NAME] = std::move(serviceName);
+        std::string &svcName = props[celix::SERVICE_NAME];
+
+        std::lock_guard<std::mutex> lock{services.mutex};
+        long svcId = services.nextSvcId++;
+        props[celix::SERVICE_ID] = std::to_string(svcId);
+
+        //Add to registry
+        std::shared_ptr<const celix::IResourceBundle> bnd = owner ? owner : emptyBundle;
+
+        if (factory) {
+            VLOG(1) << "Registering service factory '" << svcName << "' from bundle id " << owner->id() << std::endl;
+        } else {
+            VLOG(1) << "Registering service '" << svcName << "' from bundle id " << owner->id() << std::endl;
+        }
+
+        const auto it = services.registry[svcName].emplace(new SvcEntry{std::move(bnd), svcId, svcName, std::move(svc), std::move(factory), std::move(props)});
+        assert(it.second); //should always lead to a new entry
+        const std::shared_ptr<const SvcEntry> &entry = *it.first;
+
+        //Add to svcId cache
+        services.cache[entry->svcId] = entry;
+
+        //update trackers
+        std::thread updateThread{[&]{updateTrackers(entry, true);}};
+        updateThread.join();
+        entry->decrUsage(); //note usage started at 1 during creation
+
+
+        //create unregister callback
+        std::function<void()> unreg = [this, svcId]() -> void {
+            this->unregisterService(svcId);
+        };
+        auto *impl = new celix::ServiceRegistration::Impl{
+                .entry = entry,
+                .unregisterCallback = std::move(unreg),
+                .registered = true
+        };
+        return celix::ServiceRegistration{impl};
+    }
+
+    void unregisterService(long svcId) {
+        if (svcId <= 0) {
+            return; //silent ignore
+        }
+
+        std::shared_ptr<const SvcEntry> match{nullptr};
+
+        {
+            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);
+            }
+        }
+
+        if (match) {
+            std::thread updateThread{[&]{updateTrackers(match, false);}};
+            updateThread.join();
+            match->waitTillUnused();
+        } else {
+            LOG(WARNING) << "Cannot unregister service. Unknown service id: " << svcId << "." << std::endl;
+        }
+    }
+
+    void removeTracker(long trkId) {
+        if (trkId <= 0) {
+            return; //silent ignore
+        }
+
+        std::shared_ptr<SvcTrackerEntry> match{nullptr};
+        {
+            std::lock_guard<std::mutex> lock{trackers.mutex};
+            const auto it = trackers.cache.find(trkId);
+            if (it != trackers.cache.end()) {
+                match = it->second;
+                trackers.cache.erase(it);
+                trackers.registry.at(match->svcName).erase(match);
+            }
+        }
+
+        if (match) {
+            match->waitTillUnused();
+            std::thread clearThread{[&]{match->clear();}}; //ensure that all service are removed using the callbacks
+            clearThread.join();
+        } else {
+            LOG(WARNING) << "Cannot remove tracker. Unknown tracker id: " << trkId << "." << std::endl;
+        }
+    }
+
+    void updateTrackers(const std::shared_ptr<const SvcEntry> &entry, bool adding) {
+        std::vector<std::shared_ptr<SvcTrackerEntry>> matchedTrackers{};
+        {
+            std::lock_guard<std::mutex> lock{trackers.mutex};
+            for (auto &tracker : trackers.registry[entry->svcName]) {
+                if (tracker->match(*entry)) {
+                    tracker->incrUsage();
+                    matchedTrackers.push_back(tracker);
+                }
+            }
+        }
+
+        for (auto &match : matchedTrackers) {
+            if (adding) {
+                match->addMatch(entry);
+            } else {
+                match->remMatch(entry);
+            }
+            match->decrUsage();
+        }
+    }
+};
+
+
+
+/**********************************************************************************************************************
+  Service Registry
+ **********************************************************************************************************************/
+
+
+celix::ServiceRegistry::ServiceRegistry(std::string name) : pimpl{new ServiceRegistry::Impl{}} {
+    pimpl->regName = std::move(name);
+}
+celix::ServiceRegistry::ServiceRegistry(celix::ServiceRegistry &&rhs) = default;
+celix::ServiceRegistry& celix::ServiceRegistry::operator=(celix::ServiceRegistry &&rhs) = default;
+celix::ServiceRegistry::~ServiceRegistry() {
+    if (pimpl) {
+        //TODO
+    }
+}
+
+const std::string& celix::ServiceRegistry::name() const { return pimpl->regName; }
+
+/*
+celix::ServiceRegistration celix::ServiceRegistry::registerService(const std::string &svcName, std::unique_ptr<void> svc, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) {
+    return pimpl->registerService(std::move(svcName), nullptr, {}, std::move(svc), std::move(props), std::move(owner));
+}*/
+
+celix::ServiceRegistration celix::ServiceRegistry::registerService(std::string svcName, std::shared_ptr<void> svc, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) {
+    return pimpl->registerService(std::move(svcName), std::move(svc), {}, std::move(props), std::move(owner));
+}
+
+celix::ServiceRegistration celix::ServiceRegistry::registerServiceFactory(std::string svcName, std::shared_ptr<celix::IServiceFactory<void>> factory, celix::Properties props, std::shared_ptr<const celix::IResourceBundle> owner) {
+    return pimpl->registerService(std::move(svcName), {}, std::move(factory), std::move(props), std::move(owner));
+}
+
+//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) {
+    //TODO create new tracker event and start new thread to update track trackers
+    long trkId = 0;
+    {
+        std::lock_guard<std::mutex> lck{pimpl->trackers.mutex};
+        trkId = pimpl->trackers.nextTrackerId++;
+    }
+
+    auto trkEntry = std::shared_ptr<SvcTrackerEntry>{new SvcTrackerEntry{trkId, requester, std::move(svcName), std::move(options)}};
+    if (trkEntry->valid()) {
+
+        //find initial services and add new tracker to registry.
+        //NOTE two locks to ensure no new services can be added/removed during initial tracker setup
+        std::vector<std::shared_ptr<const SvcEntry>> services{};
+        {
+            std::lock_guard<std::mutex> lck1{pimpl->services.mutex};
+            for (auto &svcEntry : pimpl->services.registry[trkEntry->svcName]) {
+                if (trkEntry->match(*svcEntry)) {
+                    svcEntry->incrUsage();
+                    services.push_back(svcEntry);
+                }
+            }
+
+            std::lock_guard<std::mutex> lck2{pimpl->trackers.mutex};
+            pimpl->trackers.registry[trkEntry->svcName].insert(trkEntry);
+            pimpl->trackers.cache[trkEntry->id] = trkEntry;
+        }
+        std::thread updateThread{[&]{
+            for (auto &svcEntry : services) {
+                trkEntry->addMatch(svcEntry);
+                svcEntry->decrUsage();
+            }
+        }};
+        updateThread.join();
+        trkEntry->decrUsage(); //note trkEntry usage started at 1
+
+        auto untrack = [this, trkId]() -> void {
+            this->pimpl->removeTracker(trkId);
+        };
+        auto *impl = new celix::ServiceTracker::Impl{
+                .entry = trkEntry,
+                .untrackCallback = std::move(untrack),
+                .active = true
+        };
+        return celix::ServiceTracker{impl};
+    } else {
+        trkEntry->decrUsage(); //note usage is 1 at creation
+        LOG(ERROR) << "Cannot create tracker. Invalid filter?" << std::endl;
+        return celix::ServiceTracker{nullptr};
+    }
+}
+
+//TODO move to Impl
+long celix::ServiceRegistry::nrOfServiceTrackers() const {
+    std::lock_guard<std::mutex> lck{pimpl->trackers.mutex};
+    return pimpl->trackers.cache.size();
+}
+        
+//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> result{};
+    celix::Filter filter = rawFilter;
+    if (!filter.valid()) {
+        LOG(WARNING) << "Invalid filter (" << rawFilter << ") 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);
+    if (it != pimpl->services.registry.end()) {
+        const auto &services = it->second;
+        for (const auto &visit : services) {
+            if (filter.empty() || filter.match(visit->props)) {
+                result.push_back(visit->svcId);
+            }
+        }
+    }
+    return result;
+}
+
+//TODO move to Impl
+long celix::ServiceRegistry::nrOfRegisteredServices() const {
+    std::lock_guard<std::mutex> lock{pimpl->services.mutex};
+    return pimpl->services.cache.size();
+}
+
+//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;
+    if (!filter.valid()) {
+        LOG(WARNING) << "Invalid filter (" << rawFilter << ") provided. Cannot find services" << std::endl;
+        return 0;
+    }
+
+    std::vector<std::shared_ptr<const SvcEntry>> matches{};
+    {
+        std::lock_guard<std::mutex> lock{pimpl->services.mutex};
+        const auto it = pimpl->services.registry.find(svcName);
+        if (it != pimpl->services.registry.end()) {
+            const auto &services = it->second;
+            for (const std::shared_ptr<const SvcEntry> &entry : services) {
+                if (filter.empty() || filter.match(entry->props)) {
+                    entry->incrUsage();
+                    matches.push_back(entry);
+                }
+            }
+        }
+    }
+
+    for (const std::shared_ptr<const SvcEntry> &entry : matches) {
+        use(entry->service(*requester), entry->props, *entry->owner);
+        entry->decrUsage();
+    }
+
+    return (int)matches.size();
+}
+
+//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;
+    if (!filter.valid()) {
+        LOG(WARNING) << "Invalid filter (" << rawFilter << ") provided. Cannot find services" << std::endl;
+        return false;
+    }
+
+    std::shared_ptr<const SvcEntry> match = nullptr;
+    {
+        std::lock_guard<std::mutex> lock{pimpl->services.mutex};
+        const auto it = pimpl->services.registry.find(svcName);
+        if (it != pimpl->services.registry.end()) {
+            const auto &services = it->second;
+            for (const std::shared_ptr<const SvcEntry> &visit : services) {
+                if (filter.empty() || filter.match(visit->props)) {
+                    visit->incrUsage();
+                    match = visit;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (match != nullptr) {
+        use(match->service(*requester), match->props, *match->owner);
+        match->decrUsage();
+    }
+
+    return match != nullptr;
+}
+
+/**********************************************************************************************************************
+  Service Registration
+ **********************************************************************************************************************/
+
+celix::ServiceRegistration::ServiceRegistration() : pimpl{nullptr} {}
+
+celix::ServiceRegistration::ServiceRegistration(celix::ServiceRegistration::Impl *impl) : pimpl{impl} {}
+celix::ServiceRegistration::ServiceRegistration(celix::ServiceRegistration &&rhs) noexcept = default;
+celix::ServiceRegistration& celix::ServiceRegistration::operator=(celix::ServiceRegistration &&rhs) noexcept = default;
+celix::ServiceRegistration::~ServiceRegistration() { unregister(); }
+
+long celix::ServiceRegistration::serviceId() const { return pimpl ? pimpl->entry->svcId : -1L; }
+bool celix::ServiceRegistration::valid() const { return serviceId() >= 0; }
+bool celix::ServiceRegistration::factory() const { return pimpl && pimpl->entry->factory(); }
+bool celix::ServiceRegistration::registered() const {return pimpl && pimpl->registered; }
+
+void celix::ServiceRegistration::unregister() {
+    if (pimpl && pimpl->registered) {
+        pimpl->registered = false; //TODO make thread safe
+        pimpl->unregisterCallback();
+    }
+}
+
+const celix::Properties& celix::ServiceRegistration::properties() const {
+    static const celix::Properties empty{};
+    return pimpl ? pimpl->entry->props : empty;
+}
+
+const std::string& celix::ServiceRegistration::serviceName() const {
+    static const std::string empty{};
+    if (pimpl) {
+        return celix::getProperty(pimpl->entry->props, celix::SERVICE_NAME, empty);
+    }
+    return empty;
+}
+
+
+
+
+/**********************************************************************************************************************
+  Service Tracker
+ **********************************************************************************************************************/
+
+celix::ServiceTracker::ServiceTracker() : pimpl{nullptr} {}
+
+celix::ServiceTracker::ServiceTracker(celix::ServiceTracker::Impl *impl) : pimpl{impl} {}
+
+celix::ServiceTracker::~ServiceTracker() {
+    if (pimpl && pimpl->active) {
+        pimpl->untrackCallback();
+    }
+}
+
+
+void celix::ServiceTracker::stop() {
+    if (pimpl && pimpl->active) { //TODO make thread safe
+        pimpl->untrackCallback();
+        pimpl->active = false;
+    }
+}
+
+celix::ServiceTracker::ServiceTracker(celix::ServiceTracker &&rhs) noexcept = default;
+celix::ServiceTracker& celix::ServiceTracker::operator=(celix::ServiceTracker &&rhs) noexcept = default;
+
+int celix::ServiceTracker::trackCount() const { return pimpl ? pimpl->entry->count() : 0; }
+const std::string& celix::ServiceTracker::serviceName() const { return pimpl? pimpl->entry->svcName : emptyString; }
+const std::string& celix::ServiceTracker::filter() const { return pimpl ? pimpl->entry->filter.filterStr : emptyString; }
+bool celix::ServiceTracker::valid() const { return pimpl != nullptr; }
\ No newline at end of file