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 2022/07/14 17:50:38 UTC

[celix-site] branch feature/update_after_release created (now a9d9c54)

This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a change to branch feature/update_after_release
in repository https://gitbox.apache.org/repos/asf/celix-site.git


      at a9d9c54  Update news for latest release

This branch includes the following new commits:

     new 80e9ae1  Update celix-site for 2.3.0 release
     new a9d9c54  Update news for latest release

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[celix-site] 01/02: Update celix-site for 2.3.0 release

Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/update_after_release
in repository https://gitbox.apache.org/repos/asf/celix-site.git

commit 80e9ae1c4cb5788a36dae9b37a764f2b683fc737
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Thu Jul 14 18:57:22 2022 +0200

    Update celix-site for 2.3.0 release
---
 celix-src                                          |   2 +-
 config.toml                                        |   2 +-
 layouts/partials/header.html                       |   1 +
 source/docs/2.3.0/celix/CHANGES.md                 | 328 ++++++++++
 source/docs/2.3.0/celix/README.md                  | 358 +++++++++++
 .../2.3.0/celix/bundles/deployment_admin/README.md |  47 ++
 .../2.3.0/celix/bundles/device_access/README.md    |  40 ++
 .../device_access/example/base_driver/README.md    |  31 +
 .../example/consuming_driver/README.md             |  29 +
 .../example/refining_driver/README.md              |  29 +
 .../docs/2.3.0/celix/bundles/http_admin/README.md  |  57 ++
 source/docs/2.3.0/celix/bundles/logging/README.md  |  59 ++
 .../celix/bundles/logging/log_writers/README.md    |  17 +
 source/docs/2.3.0/celix/bundles/pubsub/README.md   | 118 ++++
 .../celix/bundles/pubsub/examples/keys/README.md   |  41 ++
 .../bundles/pubsub/pubsub_admin_udp_mc/README.md   |  85 +++
 .../2.3.0/celix/bundles/remote_services/README.md  | 176 +++++
 .../remote_services/deprecated_rsa_spi/README.md   |  17 +
 .../remote_services/discovery_etcd/README.md       |  39 ++
 .../remote_service_admin_dfi/README.md             |  44 ++
 .../remote_services/remote_services_api/README.md  |  17 +
 .../remote_services/topology_manager/README.md     |  29 +
 source/docs/2.3.0/celix/bundles/shell/README.md    |  94 +++
 source/docs/2.3.0/celix/documents/README.md        |  92 +++
 .../docs/2.3.0/celix/documents/building/README.md  | 168 +++++
 .../documents/building/dev_celix_with_clion.md     |  66 ++
 source/docs/2.3.0/celix/documents/bundles.md       | 301 +++++++++
 .../2.3.0/celix/documents/cmake_commands/README.md | 579 +++++++++++++++++
 source/docs/2.3.0/celix/documents/components.md    | 708 +++++++++++++++++++++
 source/docs/2.3.0/celix/documents/containers.md    | 119 ++++
 source/docs/2.3.0/celix/documents/framework.md     | 209 ++++++
 source/docs/2.3.0/celix/documents/patterns.md      | 155 +++++
 source/docs/2.3.0/celix/documents/services.md      | 643 +++++++++++++++++++
 source/docs/2.3.0/celix/documents/subprojects.md   |  42 ++
 .../examples/celix-examples/http_example/README.md |  33 +
 .../celix-examples/services_example_c/README.md    |  89 +++
 .../celix-examples/services_example_cxx/README.md  |  84 +++
 .../celix/examples/conan_test_package/README.md    |  54 ++
 source/docs/2.3.0/celix/libs/etcdlib/README.md     |  95 +++
 source/docs/2.3.0/celix/libs/framework/doxygen.md  |  72 +++
 source/docs/2.3.0/celix/libs/launcher/README.md    |  56 ++
 source/docs/2.3.0/celix/libs/promises/README.md    |  93 +++
 source/docs/2.3.0/celix/libs/pushstreams/README.md |  25 +
 source/docs/2.3.0/celix/libs/utils/README.md       |  32 +
 .../2.3.0/celix/libs/utils/docs/thpool/Design.md   |  58 ++
 .../docs/2.3.0/celix/libs/utils/docs/thpool/FAQ.md |  39 ++
 .../2.3.0/celix/libs/utils/docs/thpool/README.md   |  68 ++
 .../celix/libs/utils/include/memstream/README.md   |  55 ++
 .../docs/2.3.0/celix/misc/experimental/README.md   |  27 +
 .../experimental/bundles/config_admin/README.md    |  60 ++
 50 files changed, 5680 insertions(+), 2 deletions(-)

diff --git a/celix-src b/celix-src
index b618e6a..a03cd54 160000
--- a/celix-src
+++ b/celix-src
@@ -1 +1 @@
-Subproject commit b618e6aa1df05c91b2d7ba8a6768d023cafdce36
+Subproject commit a03cd54755a7b3736914296852070ab663ce628f
diff --git a/config.toml b/config.toml
index 0b69eeb..45abbb4 100644
--- a/config.toml
+++ b/config.toml
@@ -33,7 +33,7 @@ fractions = false
 date = ["date", ":filename", "publishDate", "lastmod"]
 
 [params]
-latestVersion = "2.2.1"
+latestVersion = "2.3.0"
 
 repositoryUrl = "https://github.com/apache/celix"
 repositorySourceBranch = "master"
diff --git a/layouts/partials/header.html b/layouts/partials/header.html
index 1d4a81e..42461f4 100644
--- a/layouts/partials/header.html
+++ b/layouts/partials/header.html
@@ -25,6 +25,7 @@
                     </a>
                     <div class="dropdown-menu" aria-labelledby="ddDocs">
                         <a class="dropdown-item" href="/docs/{{ .Site.Params.latestVersion }}/docs.html">{{ .Site.Params.latestVersion }} (latest)</a>
+                        <a class="dropdown-item" href="/docs/2.2.0/docs.html">2.1.0</a>
                         <a class="dropdown-item" href="/docs/2.1.0/docs.html">2.1.0</a>
                     </div>
                 </li>
diff --git a/source/docs/2.3.0/celix/CHANGES.md b/source/docs/2.3.0/celix/CHANGES.md
new file mode 100644
index 0000000..74576df
--- /dev/null
+++ b/source/docs/2.3.0/celix/CHANGES.md
@@ -0,0 +1,328 @@
+---
+title: Changes
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Noteworthy changes for 2.3.0 (TBD)
+
+# New Features
+
+ - Support for Conan package manager
+ - Async api to (un0)register services, track services, track bundles and create/remove components.
+ - C++17 API.
+ - Celix Promises (experimental)
+ - Celix PushStreams (experimental)
+ - C++ Remote Service Admin (experimental)
+ - Refactored LogAdmin
+
+# Improvements
+
+ - Build
+   - multi build type support 
+ - Added celix_ api for
+   - long and string hash map
+   - shell command
+   - logging
+ - Added C++17 api for
+   - BundleContext (service registration, service trackers, use services, bundle trackers)
+   - BundleActivator
+   - Framework
+   - LogHelper
+   - IShellCommand
+   - Filter
+   - Properties
+   - Utils
+ - Remote Services 
+   - Interceptors support
+ - PubSub
+   - Interceptors
+   - Wire protocol service support
+   - Refactored message serialization
+
+# Fixes
+
+ - Too many to mention
+
+# Changes for 2.2.1 (2020-05-10)
+
+# Fixes
+
+- Fixes etcdlib CMake setup to that etcdlib can be build as a separate project
+
+# Noteworthy changes for 2.2.0 (2020-01-06)
+
+## New features:
+- PubSub TCP (donation)
+- PubSub Avro bin serializer
+- PubSub Websocket (donation)
+- HTTP Admin (donation)
+- Shell Web UI (using HTTP Admin)
+ 
+## Improvements
+- CELIX-438: Refactored celix api so that include files and symbols have a _celix "namespace"
+- CELIX-459: Adds PubSub health/usage monitoring
+- CELIX-467: Adds doxygen generation
+- Refactored etcdlib to supported multiple instances
+
+## Bugs
+- CELIX-410: Fixes issue with property loader duplicating spaces and tabs
+- CELIX-454: Fixed race condition in the etcd pubsub discovery
+- CELIX-460: Fixed issue with msg not found in pub/sub serializer map due to signed/unsigned difference
+- CELIX-466: Fixed race condition Race condition in adding/removing service listener hooks
+
+# Noteworthy changes for 2.1.0 (2018-01-24)
+
+## New Features:
+-  CELIX-408: Adds support for generating runtime shell scripts so that multiple Celix containers and other executable can be run with a single command.
+-  CELIX-418: Adds support for generating properties in the Celix container launcher.
+-  CELIX-407: Adds support for serializers as a service for PubSub. This way PubSubAdmin are purely focused on transport techniques.
+-  CELIX-401: Adds support for creating Celix docker images using a CMake function.
+-  CELIX-397: Adds support for PubSub selection based on a match function. This way multiple PubSubAdmin can be active.
+-  CELIX-389: Adds the PubSub implementation. A set of bundles which together operates as a service based publish subscribe technology agnostic abstraction.
+-  CELIX-385: Adds etcdlib as library. This libray can be used to communicate with etcd using a C abstraction.
+-  CELIX-370: Adds C++11 support by adding a C++ Dependency Manager library. This is moslty a header based library.
+
+## Improvements:
+- CELIX-415: Improves handling of ANSI control sequences to better support running in IDE's.
+- CELIX-414: Improves support for running Celix container inside IDE's by basicly handling Celix containers as add_executable CMake target.
+- CELIX-406: Improves handling of descriptor files, by allowing different directories for Remote Services and PubSub.
+- CELIX-399: Improves PubSub to use etcdlib instead of local copy of etcd.c file.
+- CELIX-396: Improves the ZMQ PubSub security so that enabling/disable of security can be done per topic.
+- CELIX-395: Improves Remote Service to use the etcdlib instead of a local etcd.c file.
+- CELIX-392: Removes the use of the deprecated readdir_r function. 
+
+## Bugs:
+-  CELIX-416: Fixes an issue for the Android build.
+-  CELIX-410: Fixes an issue where spaces and tabs are duplicated when loading properties.
+-  CELIX-405: Fixes an issue with crashes because of invalid DFI descriptors.
+-  CELIX-404: Fixes an issue with crashes using the inspect shell command.
+-  CELIX-403: Fixes an memory leak in the service tracker.
+-  CELIX-400: Fixes an issue with private libraries being loaded twice.
+-  CELIX-398: Fixes an issue with PubSub and multiple UDP connections.
+-  CELIX-393: Fixes an issue with the add_bundle CMake function and using existing libaries.
+-  CELIX-391: Fixes an issue with the utils_stringHash not genering unique (enough) hashes.
+-  CELIX-390: Fixes an issue with cycle dependency between the Celix framework and Celix utils libraries.
+-  CELIX-387: Fixes an issue with the travis build and OSX
+-  CELIX-386: Fixes an issue with the C++ dependency manager and register multiple C++ services.
+
+# Changes for 2.0.0 (2016-10-26)
+
+## New Features
+- CELIX-77 Configuration Admin Implementation
+- CELIX-116 Event admin
+- CELIX-119 Remove apr usage from framework
+- CELIX-172 Bonjour Shell
+- CELIX-237 RSA with libffi
+- CELIX-269 New Dependency Manager
+- CELIX-370 Add C++ support
+
+## Improvements
+- CELIX-63 make cmake directory useable for custom bundle projects
+- CELIX-66 Refactor shell service struct
+- CELIX-90 add additional build options for RSA components
+- CELIX-111 Support multiple libraries
+- CELIX-115 logservice bundle entries list grows indefinitely
+- CELIX-118 Deployment Admin - Support auditlog of Apache ACE
+- CELIX-123 enable code coverage for utils_test
+- CELIX-125 CMakeCelix module
+- CELIX-134 Update source from incubator structure to TLP
+- CELIX-138 Parameterise launcher
+- CELIX-144 Document Developing Celix with Eclipse
+- CELIX-146 Replace printfs wit fw_log calls
+- CELIX-149 Add log_writer_syslog
+- CELIX-152 Added Discovery/ETCD support
+- CELIX-153 add cmake configuration options for rsa_bundles
+- CELIX-156 Enable all warnings
+- CELIX-158 RSA is unable to re-use already started proxy factory
+- CELIX-165 Add port collision auto-correction to RSA
+- CELIX-169 Add port collision auto-correction to discovery
+- CELIX-182 loghelper eases log_service tracking
+- CELIX-187 discovery_etcd: add watchindex, handle expire action
+- CELIX-193 support portable celix_thread_t initalization
+- CELIX-199 Code Coverage should be optional rather than required by cmake
+- CELIX-200 SEGFAULT occurs when remote services are closed
+- CELIX-216 Replace strtok with strtok_r
+- CELIX-230 Refactoring of the shell command service
+- CELIX-242 Fix Warnings
+- CELIX-245 Update civetweb to latest version
+- CELIX-246 enable Travis CI for Apache Celix
+- CELIX-247 Enable ANDROID support
+- CELIX-249 Refactor most char * usage to const char *
+- CELIX-251 missing includes in device access example
+- CELIX-255 Update default BUILD option
+- CELIX-258 framework uses  dlopen/dlsym to set the bundleActivator
+- CELIX-259 dispatcherThread does not perform a graceful shutdown
+- CELIX-275 Can't do mkstemp on root system (deploymentAdmin_download)
+- CELIX-278 Adding tags to ACE target through deployment admin
+- CELIX-284 Restrict export and imports based on properties
+- CELIX-285 Discovery SHM: remove obsolete jansson dependency
+- CELIX-295 Many compiling warnings in unit tests
+- CELIX-296 Framework unit tests improvement
+- CELIX-309 Make DFI available for common use
+- CELIX-317 Dependency Manager suspend state
+- CELIX-320 outdated utils tests (threads, hashmap)
+- CELIX-323 Version and version_range moved from framework to utils
+- CELIX-326 Add service version support to dependency manager
+- CELIX-327 Filter does not support greater than and lesser than operators
+- CELIX-328 Service version support for RSA DFI
+- CELIX-330 document using markdown
+- CELIX-333 integrate coverity scans
+- CELIX-335 Refactor deploying bundles with cmake
+- CELIX-339 celix_log_mock doesnt show logs to the user
+- CELIX-341 Fix coverity issues in Shell / Shell TUI
+- CELIX-348 The utils_stringHash does not generate unique hashes.
+- CELIX-352 RSA_DFI and embedded celix
+- CELIX-353 Make bundle context retrievable form dm component
+- CELIX-365 Refactor some usage of void* to const void*
+
+## Bugs
+- CELIX-104 deployment_admin bundle won't start when missing properties
+- CELIX-105 Fixed array_list_test
+- CELIX-114 Potential deadlock in log_service bundle during stop
+- CELIX-122 missing dependency uuid
+- CELIX-124 Celix memory leaks fixing
+- CELIX-127 Makefiles not generated using CMake 3.0
+- CELIX-128 remote_shell port cannot be changed
+- CELIX-129 Update RSA to be compatible with the Amdatu RSA implementation
+- CELIX-130 Implement Configured Endpoint discovery compatible with Amdatu RSA
+- CELIX-136 contrib Configured endpoint discovery
+- CELIX-137 Possible concurrency issues in topology manager
+- CELIX-139 Update tests and mocks to latest CppUTest
+- CELIX-147 RSA_SHM: concurrency issue when client segfaults
+- CELIX-150 Topology Manager segfaults when RSA/bundle w/ exp. service stops in wrong order
+- CELIX-154 echo exampe not working
+- CELIX-155 Fix CMake warnings during configuration
+- CELIX-157 service_reference misses functions to get property keys and values
+- CELIX-159 PThread usage not correct for Linux
+- CELIX-161 newly added RSA cannot manage already exported/imported services
+- CELIX-162 Update encoding/decoding of replies.
+- CELIX-167 Update command to be able to pass a pointer (handle)
+- CELIX-168 discovery_etcd:Make root-path configurable
+- CELIX-170 Remote services can fail to restart when felix restarts
+- CELIX-173 stopping rsa_http bundle does not stop rsa webserver
+- CELIX-174  invalid bundle_context during fw shutdown
+- CELIX-175 segfault during shutdown when calculator is already stopped
+- CELIX-177 not all endpoints are unistalled when rsa_http bundle is stopped
+- CELIX-178 Shell_Tui bundle hangs on stop
+- CELIX-179 memory leak in rsa_http callback
+- CELIX-180 framework_tests do not compile
+- CELIX-181 Incorrect reply status when no data is returned on a remote call.
+- CELIX-185 Memory leaks in Discovery Endpoint Descriptor Reader
+- CELIX-186 deployment_admin segfaults while downloading bundle
+- CELIX-188 Add missing log_service headers to installations
+- CELIX-189 LogService segfaults when log message pointer is overwritten
+- CELIX-190 remote services memory leaks
+- CELIX-192 rsa_http: add locking
+- CELIX-194 Refactor RemoteService proxy factory
+- CELIX-195 SEGFAULT occurs when running a log command.
+- CELIX-197 insufficient memory allocated
+- CELIX-198 Logging can segfault for strings 512 characters or longer
+- CELIX-201 SEGFAULT occurs when restarting apache_celix_rs_topology_manager
+- CELIX-202 Not all components are disabled with a clean build
+- CELIX-205 RSA Discovery (Configured) bundle gets stuck
+- CELIX-213 SEGFAULT occurs due to memory access after memory is free'd
+- CELIX-215 curl_global_init() not called directly
+- CELIX-218 Memory leaks in service_registry.c
+- CELIX-219 Memory Leaks
+- CELIX-221 Deployment admin segfaults when deploying a bundle
+- CELIX-223 Celix crashes because of wrong bundle versions
+- CELIX-224 Wrong use of errno in launcher.c
+- CELIX-226 __unused atttibute does not work with  Linux
+- CELIX-227 compile error under linux due to missing header include
+- CELIX-229 Make APR optional
+- CELIX-231 Missing log_helper creation in discovery_etcd
+- CELIX-238 Contributing page links incorrect
+- CELIX-239 TopologyManager does not maintain exportedServices
+- CELIX-240 RSA: deadlock when stopping
+- CELIX-241 remote_interface incorrect
+- CELIX-248 too many arguments for format
+- CELIX-250 config.h is not exported
+- CELIX-252 discovery_etcd cannot handle celix restarts
+- CELIX-253 Deployment admin does not always download the latest version from ACE
+- CELIX-254 Memory leakage in deployment_admin
+- CELIX-260 missing include in deployment admin
+- CELIX-262 Fix minor issues in hashMap/linkedList
+- CELIX-263 replace utils cunit tests w/ cpputest tests
+- CELIX-264 Missing strdup leads to invalid free
+- CELIX-270 Fix Code Coverage
+- CELIX-271 setup coveralls.io
+- CELIX-272 framework: improve locking / synchronization
+- CELIX-274 waitForShutdown issue when starting two embedded celix frameworks.
+- CELIX-279 Celix fails to compile w/ CMake 3.3
+- CELIX-280 deployment_admin misses proper shutdown functionality
+- CELIX-287 racecondition for framework event listener
+- CELIX-288 Archive directory not properly read
+- CELIX-289 Fix celix mocks
+- CELIX-290 Mock fixes, CMakelist fix, build warning fix
+- CELIX-292 Memory leak in refactored shell
+- CELIX-294 changed dfi library from static to shared
+- CELIX-298 Memory leaks in rsa_dfi
+- CELIX-300 Invalid read in serviceRegistry during framework_shutdown
+- CELIX-301 Memory leaks in rsa_shm
+- CELIX-302 Service Tracker Test error breaks the build
+- CELIX-304 Memory leaks in manifest parser, requirement, capability; out-of-date tests
+- CELIX-305 Memory leaks in RSA_SHM, RSA_DFI, RSA_HTTP
+- CELIX-306 Memory leaks in remote_proxy_factory, unit tests issues
+- CELIX-307 "service registration set properties" deadlocks
+- CELIX-308 Dependency Manager memory leaks
+- CELIX-310 "serviceRegistry_getRegisteredServices" deadlocks
+- CELIX-311 Framework Tests Build broken
+- CELIX-312 ServiceReference usage counter inconsistent state
+- CELIX-313 out of date/defunct tests
+- CELIX-316 Wrong conversion for 'N' type in json_serializer
+- CELIX-322 Memory leaks in resolver and framework tests
+- CELIX-324 Version support in dfi library
+- CELIX-325 Bundle test sporadicly fails
+- CELIX-329 framework "service_" tests are outdates, some small bugs in the sources
+- CELIX-331 test configuraiton needs update for newer CMake
+- CELIX-332 filter tests absent, small bugs in the source
+- CELIX-334 Race Condition in Topology Manager causes spurious segfaults
+- CELIX-336 resolver_test doesn't compile
+- CELIX-343 configuration_unbind never called
+- CELIX-344 service tracker removes wrong service
+- CELIX-345 Typo in Dependency Manager interface
+- CELIX-346 celix-bootstrap problems
+- CELIX-347 Memory leaks in dm_service_dependency
+- CELIX-349 ServiceTracker update references list after invoking added callback
+- CELIX-350 shell_tui wrong handling service reference
+- CELIX-354 Coverity High Impact issues
+- CELIX-356 Import libraries not supported in revamped cmake commands
+- CELIX-357 Coverity Medium Impact issues
+- CELIX-358 Coverity Low+New High Impact issues
+- CELIX-359 Android build stopped working
+- CELIX-360 Coverity leftover issues
+- CELIX-361 etcd_watcher notifications loss when ETCD transaction rate is high
+- CELIX-363 Memory leak in DFI exportRegistration_create
+- CELIX-364 Incorrect destroy of dependency manager info struct
+- CELIX-366 eclipse launch file not correctly generated
+- CELIX-367 Memory leak in properties
+- CELIX-369 Tests fail with sanitizer
+- CELIX-371 Due to a fixed maximum length of lines in property file not all bundles are started
+- CELIX-372 serviceRegistry_clearReferencesFor warning info unclear
+- CELIX-373 Endpoint Server number is fixed and too low
+- CELIX-374 RTLD_NODELETE flag
+- CELIX-375 Topology manager deadlocks when interacts with dependency manager
+- CELIX-377 wrong rpath setup in CMake files
+- CELIX-378 Travis build errors on Max OSX
+- CELIX-379 Extend cmake fucntion add_deploy with an option to specify the launcher
+- CELIX-376 serviceRegistration sometimes paired to invalidated serviceReference
+- CELIX-380 PROPERTIES_FOR_EACH macro does not iterate over all keys
+- CELIX-381 Invoke set for dependency manager called before suspending the component
diff --git a/source/docs/2.3.0/celix/README.md b/source/docs/2.3.0/celix/README.md
new file mode 100644
index 0000000..2d7c709
--- /dev/null
+++ b/source/docs/2.3.0/celix/README.md
@@ -0,0 +1,358 @@
+---
+title: README.md
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Apache Celix
+[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
+![Celix Ubuntu](https://github.com/apache/celix/workflows/Celix%20Ubuntu/badge.svg)
+![Celix MacOS](https://github.com/apache/celix/workflows/Celix%20MacOS/badge.svg)
+[![codecov](https://codecov.io/gh/apache/celix/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/celix)
+[![Coverity Scan Build Status](https://scan.coverity.com/projects/6685/badge.svg)](https://scan.coverity.com/projects/6685)
+
+Apache Celix is an implementation of a dynamic service framework inspired by the OSGi specification and adapted to C 
+and C++ (C++17).
+It is a framework to develop dynamic modular software applications using component and in-process service-oriented 
+programming.
+
+## Documentation
+- [Building Apache Celix](documents/building/README.html)
+- [Apache Celix Intro](documents/README.html)
+
+## C++ Usage
+
+### Hello World Bundle
+
+Modularity in Celix is achieved by runtime installable bundles and dynamic - in process - services.  
+A Celix bundle is set of resources packed in a zip containing at least a manifest and almost always
+some shared library containing the bundle functionality.
+A Celix bundle can be created using the Celix CMake function `add_celix_bundle`.
+A Celix bundle is activated by executing the bundle entry points. For C++ bundles these bundle entry points are generated using the `CELIX_GEN_CXX_BUNDLE_ACTIVATOR` macro. 
+
+Celix applications (Celix containers) can be created with the Celix CMake function `add_celix_container`.
+This function generates a C++ main function and is also used to configure default installed bundles. 
+This can be bundles provided by Celix, an other project or build by the project self. 
+
+```C++
+//src/MyBundleActivator.cc
+#include <iostream>
+#include "celix/BundleActivator.h"
+
+class MyBundleActivator {
+public:
+    explicit MyBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        std::cout << "Hello world from bundle with id " << ctx->getBundleId() << std::endl;
+    }
+
+    ~MyBundleActivator() noexcept {
+        std::cout << "Goodbye world" << std::endl;
+    }
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(MyBundleActivator)
+```
+
+```CMake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+
+add_celix_bundle(MyBundle
+    SOURCES src/MyBundleActivator.cc
+)
+
+add_celix_container(MyContainer
+    BUNDLES
+        Celix::ShellCxx
+        Celix::shell_tui
+        MyBundle
+)
+```
+
+```sh
+#bash
+#goto project dir
+cd cmake-build-debug #assuming clion cmake-build-debug dir
+cd deploy/MyContainer
+./MyContainer
+#Celix shell
+-> lb -a
+#list of all installed bundles
+-> help
+#list of all available Celix shell commands
+-> help celix::lb
+#Help info about the shell command `celix::lb`
+-> stop 3
+#stops MyBundle
+-> start 3
+#starts MyBundle
+-> stop 0 
+#stops the Celix framework
+```
+
+### Register a service
+
+In the Celix framework, a service is a C++ object or C struct registered in the Celix framework service registry under one interface together with properties (meta information). Services can be discovered and used by bundles.
+
+```C++
+//include/ICalc.h
+#pragma once
+class ICalc {
+public:
+    virtual ~ICalc() noexcept = default;
+    virtual int add(int a, int b) = 0;
+};
+```
+
+```C++
+//src/CalcProviderBundleActivator.cc
+#include "ICalc.h"
+#include "celix/BundleActivator.h"
+
+class CalcProvider : public ICalc {
+public:
+    ~CalcProvider() noexcept override = default;
+    int add(int a, int b) override { return a + b; }
+};
+
+class CalcProviderBundleActivator {
+public:
+    explicit CalcProviderBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        reg = ctx->registerService<ICalc>(std::make_shared<CalcProvider>())
+                .build();
+    }
+private:
+    std::shared_ptr<celix::ServiceRegistration> reg{};
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(CalcProviderBundleActivator)
+```
+
+```CMake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+
+add_celix_bundle(CalcProviderBundle
+    SOURCES src/CalcProviderBundleActivator.cc
+)
+target_include_directories(CalcProviderBundle PRIVATE include)
+
+add_celix_container(CalcProviderContainer
+    BUNDLES
+        Celix::ShellCxx
+        Celix::shell_tui
+        CalcProviderBundle
+)
+```
+
+```bash
+#bash
+#goto project dir
+cd cmake-build-debug #assuming clion cmake-build-debug dir
+cd deploy/CalcProviderBundle
+./CalcProviderBundle
+```
+
+### Use a service (ad hoc)
+
+```C++
+//include/ICalc.h
+#pragma once
+class ICalc {
+public:
+    virtual ~ICalc() noexcept = default;
+    virtual int add(int a, int b) = 0;
+};
+```
+
+
+```C++
+//src/CalcUserBundleActivator.cc
+#include <iostream>
+#include "ICalc.h"
+#include "celix/BundleActivator.h"
+
+class CalcUserBundleActivator {
+public:
+    explicit CalcUserBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        ctx->useService<ICalc>()
+            .addUseCallback([](ICalc& calc) {
+                std::cout << "result is " << calc.add(2, 3) << std::endl;
+            })
+            .setTimeout(std::chrono::seconds{1}) //wait for 1 second if a service is not directly found
+            .build();
+    }
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(CalcUserBundleActivator)
+```
+
+```CMake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+
+add_celix_bundle(CalcUserBundle
+    SOURCES src/CalcUserBundleActivator.cc
+)
+target_include_directories(CalcUserBundle PRIVATE include)
+
+add_celix_container(CalcUserContainer
+    BUNDLES
+        Celix::ShellCxx
+        Celix::shell_tui
+        CalcProviderBundle
+        CalcUserBundle
+)
+```
+
+```bash
+#bash
+#goto project dir
+cd cmake-build-debug #assuming clion cmake-build-debug dir
+cd deploy/CalcUserContainer
+./CalcUserContainer
+```
+
+### Track services 
+
+```C++
+//include/ICalc.h
+#pragma once
+class ICalc {
+public:
+    virtual ~ICalc() noexcept = default;
+    virtual int add(int a, int b) = 0;
+};
+```
+
+```C++
+//src/CalcTrackerBundleActivator.cc
+#include <mutex>
+#include "ICalc.h"
+#include "celix/BundleActivator.h"
+
+class CalcTrackerBundleActivator {
+public:
+    explicit CalcTrackerBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        tracker = ctx->trackServices<ICalc>()
+            .build();
+        for (auto calc : tracker->getServices()) {
+            std::cout << "result is " << std::to_string(calc->add(2, 3)) << std::endl;
+        }
+    }
+    
+private:
+    std::shared_ptr<celix::ServiceTracker<ICalc>> tracker{};
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(CalcTrackerBundleActivator)
+```
+```CMake
+find_package(Celix REQUIRED)
+
+add_celix_bundle(CalcTrackerBundle
+    SOURCES src/CalcTrackerBundleActivator.cc
+)
+target_include_directories(CalcTrackerBundle PRIVATE include)
+
+add_celix_container(CalcTrackerContainer
+    BUNDLES
+        Celix::ShellCxx
+        Celix::shell_tui
+        CalcProviderBundle
+        CalcTrackerBundle
+)
+```
+
+```bash
+#bash
+#goto project dir
+cd cmake-build-debug #assuming clion cmake-build-debug dir
+cd deploy/CalcTrackerContainer
+./CalcTrackerContainer
+```
+
+### Service properties and filters
+
+```C++
+//src/FilterExampleBundleActivator.cc
+#include <iostream>
+#include "celix/BundleActivator.h"
+#include "celix/IShellCommand.h"
+
+class HelloWorldShellCommand : public celix::IShellCommand {
+public:
+    void executeCommand(const std::string& /*commandLine*/, const std::vector<std::string>& /*commandArgs*/, FILE* outStream, FILE* /*errorStream*/) {
+        fprintf(outStream, "Hello World\n");
+    }
+};
+
+class FilterExampleBundleActivator {
+public:
+    explicit FilterExampleBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        auto reg1 = ctx->registerService<celix::IShellCommand>(std::make_shared<HelloWorldShellCommand>())
+                .addProperty(celix::IShellCommand::COMMAND_NAME, "command1")
+                .build();
+        auto reg2 = ctx->registerService<celix::IShellCommand>(std::make_shared<HelloWorldShellCommand>())
+                .addProperty(celix::IShellCommand::COMMAND_NAME, "command2")
+                .build();
+        regs.push_back(reg1);
+        regs.push_back(reg2);
+        
+        auto serviceIdsNoFilter  = ctx->findServices<celix::IShellCommand>();
+        auto serviceIdsWithFilter = ctx->findServices<celix::IShellCommand>(std::string{"("} + celix::IShellCommand::COMMAND_NAME + "=" + "command1)");
+        std::cout << "Found " << std::to_string(serviceIdsNoFilter.size()) << " IShelLCommand services and found ";
+        std::cout << std::to_string(serviceIdsWithFilter.size()) << " IShellCommand service with name command1" << std::endl;
+    }
+private:
+    std::vector<std::shared_ptr<celix::ServiceRegistration>> regs{};
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(FilterExampleBundleActivator)
+```
+
+```CMake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+
+add_celix_bundle(FilterExampleBundle
+    SOURCES src/FilterExampleBundleActivator.cc
+)
+target_link_libraries(FilterExampleBundle PRIVATE Celix::shell_api) #adds celix/IShellCommand.h to the include path
+
+add_celix_container(FilterExampleContainer
+    BUNDLES
+        Celix::ShellCxx
+        Celix::shell_tui
+        FilterExampleBundle
+)
+```
+
+```bash
+#bash
+#goto project dir
+cd cmake-build-debug #assuming clion cmake-build-debug dir
+cd deploy/FilterExampleContainer
+./FilterExampleContainer
+#Celix shell
+-> command1
+-> command2
+-> help
+```
diff --git a/source/docs/2.3.0/celix/bundles/deployment_admin/README.md b/source/docs/2.3.0/celix/bundles/deployment_admin/README.md
new file mode 100644
index 0000000..7474b09
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/deployment_admin/README.md
@@ -0,0 +1,47 @@
+---
+title: Deployment Admin
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+## Deployment Admin
+
+The Celix Deployment Admin implements the OSGi Deployment Admin specification, which provides functionality to manage deployment packages. Deployment package are bundles and other artifacts that can be installed, updated and uninstalled as single unit.
+
+It can be used for example with Apache Ace, which allows you to centrally manage and distribute software components, configuration data and other artifacts.
+
+###### Properties
+                  tags used by the deployment admin
+
+## CMake option
+    BUILD_DEPLOYMENT_ADMIN=ON
+
+## Deployment Admin Config Options
+
+- deployment_admin_identification     id used by the deployment admin to identify itself
+- deployment_admin_url                url of the deployment server
+- deployment_cache_dir                possible cache dir for the deployment admin update
+- deployment_tags
+
+## Using info
+
+If the Celix Deployment Admin is installed, 'find_package(Celix)' will set:
+ - The `Celix::deployment_admin_api` interface (i.e. headers only) library target
+ - The `Celix::deployment_admin` bundle target
diff --git a/source/docs/2.3.0/celix/bundles/device_access/README.md b/source/docs/2.3.0/celix/bundles/device_access/README.md
new file mode 100644
index 0000000..925e031
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/device_access/README.md
@@ -0,0 +1,40 @@
+---
+title: Device Access
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+## Device Access
+
+The Device Access contains a for Celix adapted implementation of the OSGi Compendium Device Access Specification.
+
+## Properties
+    DRIVER_LOCATOR_PATH     Path to the directory containing the driver bundles, defaults to "drivers".
+                            The Driver Locator uses this path to find drivers.
+
+## CMake option
+    BUILD_DEVICE_ACCESS=ON
+
+## Using info
+
+If the Celix Device Access is installed, 'find_package(Celix)' will set:
+ - The `Celix::device_access_api` interface (i.e. headers only) library target
+ - The `Celix::device_manager` bundle target
+ - The `Celix::driver_locator` bundle target
diff --git a/source/docs/2.3.0/celix/bundles/device_access/example/base_driver/README.md b/source/docs/2.3.0/celix/bundles/device_access/example/base_driver/README.md
new file mode 100644
index 0000000..3ab828e
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/device_access/example/base_driver/README.md
@@ -0,0 +1,31 @@
+---
+title: Base driver
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Base driver
+
+The base driver is a "special" driver that will not be loaded by the device manager.
+Normally the device manager will load drivers if it find device which are idle... But before that can happen 
+at least one device should exists. This is the role of a base driver and it should function like a "normal" OSGi
+bundle which registers a device service.
+
+In this example the base driver will provide two device service with a DEVICE_CATEGORY of "char".
\ No newline at end of file
diff --git a/source/docs/2.3.0/celix/bundles/device_access/example/consuming_driver/README.md b/source/docs/2.3.0/celix/bundles/device_access/example/consuming_driver/README.md
new file mode 100644
index 0000000..e3302d2
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/device_access/example/consuming_driver/README.md
@@ -0,0 +1,29 @@
+---
+title: Consuming driver
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Consuming driver
+
+A consuming driver will be able to attach to certain device services, 
+but will not - in contrast with a refining driver - publish device services.
+
+In this example the consuming driver will look for "word" services and will print the result a few times.
diff --git a/source/docs/2.3.0/celix/bundles/device_access/example/refining_driver/README.md b/source/docs/2.3.0/celix/bundles/device_access/example/refining_driver/README.md
new file mode 100644
index 0000000..7965b3e
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/device_access/example/refining_driver/README.md
@@ -0,0 +1,29 @@
+---
+title: Refining driver
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Refining driver
+
+A refining driver is a driver which is able to attach to certain device services and
+as result publishes different - refined - device services.
+This example will attach to device services with a "char" device category and publish 
+- for every char device services found - a "word" device services.  
diff --git a/source/docs/2.3.0/celix/bundles/http_admin/README.md b/source/docs/2.3.0/celix/bundles/http_admin/README.md
new file mode 100755
index 0000000..dd6aa0f
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/http_admin/README.md
@@ -0,0 +1,57 @@
+---
+title: HTTP Admin
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+## HTTP Admin
+
+The HTTP admin provides a service tracker and starts a HTTP web server. The civetweb web server is used as an embedded
+web server. Websockets are supported by the HTTP admin.
+
+Services can register and implement HTTP requests or websocket support for a specified URI.
+The supported HTTP requests are: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS and PATCH.
+The websocket service can support different callback handlers: connect, ready, data and close.
+
+Aliasing is also supported for both HTTP services and websocket services. Multiple aliases can be added by using the comma as seperator.
+Adding aliasing is done by adding the following function to the target CMakeFile (fill in <Alias path> and <Path to destination>):
+
+```CMake
+celix_bundle_headers(<TARGET>
+        "X-Web-Resource: /<Alias path>$<SEMICOLON>/<Path to destination>, /<Alias path 2>$<SEMICOLON>/<Path to destination>"
+)
+```
+
+Bundle alias resources can be added by the with the following function in the bundle CMakefile:
+
+```CMake
+celix_bundle_add_dir(<TARGET> <Document root of bundle> DESTINATION ".")
+```
+
+### Celix supported config.properties
+    CELIX_HTTP_ADMIN_LISTENING_PORTS                 default = 8080, can be multiple ports divided by a comma
+    CELIX_HTTP_ADMIN_PORT_RANGE_MIN                  default = 8000
+    CELIX_HTTP_ADMIN_PORT_RANGE_MAX                  default = 9000
+    CELIX_HTTP_ADMIN_USE_WEBSOCKETS                  default = true
+    CELIX_HTTP_ADMIN_WEBSOCKET_TIMEOUT_MS            default = 3600000
+    CELIX_HTTP_ADMIN_NUM_THREADS                     default = 1
+
+## CMake option
+    BUILD_HTTP_ADMIN=ON
diff --git a/source/docs/2.3.0/celix/bundles/logging/README.md b/source/docs/2.3.0/celix/bundles/logging/README.md
new file mode 100644
index 0000000..130de9c
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/logging/README.md
@@ -0,0 +1,59 @@
+---
+title: Logging Facilities
+type: celix-doc
+version: 2.3.0
+---
+
+# Celix Logging Facilities
+
+The Celix Logging facility is service oriented and logging technology-agnostic logging solution.
+
+Bundles can request (services on demand) and use `celix_log_service_t` services to log events.
+Logging support the following log levels: `trace`, `debug`, `info`, `error`, `fatal`. 
+
+Bundles can provide `celix_log_sink_t` services to sink log message to different logging backends (e.g. syslog, log4c, etc)
+
+The `Celix::log_admin` bundle facilitates the `celix_log_service_t` services and 'connects' these to the available 
+`celix_log_sink_t` services. If there is no `celix_log_sink_t` service available, log messages will be
+printed on stdout/stderr.
+
+The Celix shell command `celix::log_admin` can be used to view the existing log services and sinks,
+changed the active log level per log services and enable/disable log sinks.
+For example:
+- `celix::log_admin` list the available log services and log sinks.
+- `celix::log_admin log error` Set the active log level for all log services to `error`.
+- `celix::log_admin log celix_ trace` Set the active log level for all log services starting with 'celix_' to `trace`.
+- `celix::log_admin sink false` Disables all available log sinks.
+- `celix::log_admin sink celix_syslog true` Enables all log sinks starting with 'celix_syslog'.
+
+The `Celix::log_helper` static library can be used to more easily request a `celix_log_service_t`. 
+An additional benefit of the `Celix:log_helper` is that if the `Celix::log_admin` is not installed, 
+log messages will be printed on stdout/stderr.
+
+
+## Logging Properties
+Properties shared among the logging bundles
+
+    CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL The default active log level for created log services. Default is "info".
+
+## Log Admin Properties
+Properties specific for the Celix Log Admin (`Celix::log_admin` bundle)
+
+    CELIX_LOG_ADMIN_FALLBACK_TO_STDOUT If set to true, the log admin will log to stdout/stderr if no celix log writers are available. Default is true
+    CELIX_LOG_ADMIN_ALWAYS_USE_STDOUT If set to true, the log admin will always log to stdout/stderr after forwaring log statements to the available celix log writers. Default is false.
+    CELIX_LOG_ADMIN_LOG_SINKS_DEFAULT_ENABLED Whether discovered log sink are default enabled. Default is true.
+    
+## CMake option
+    BUILD_LOG_SERVICE=ON
+
+## Using info
+
+If the Celix Log Service is installed, 'find_package(Celix)' will set:
+ - The `Celix::log_service_api` interface (i.e. header only) library target (v2 and v3 api)
+ - The `Celix::log_admin` bundle target. The log admin will create log services on demand and forward log message to the available log sinks. 
+ - The `Celix::log_helper` static library target. Helper library with common logger functionality and helpers to setup logging
+ - The `Celix::log_writer_syslog` bundle target. A bundle which provides a `celix_log_sink_t` service for syslog.
+ 
+Also the following deprecated bundle will be set:
+ - The `Celix::log_service` bundle target. The log service bundle. Deprecated, use Celix::log_admin instead.
+ - The `Celix::log_writer_stdout` bundle target. Deprecated bundle. Logging to stdout is now an integral part of the log admin.
\ No newline at end of file
diff --git a/source/docs/2.3.0/celix/bundles/logging/log_writers/README.md b/source/docs/2.3.0/celix/bundles/logging/log_writers/README.md
new file mode 100644
index 0000000..1389302
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/logging/log_writers/README.md
@@ -0,0 +1,17 @@
+---
+title: Log Writers
+type: celix-doc
+version: 2.3.0
+---
+
+# Log Writer
+
+The Celix Log Writers are components that sinks log from the Celix log service to different backends.
+
+## CMake options
+    BUILD_SYSLOG_WRITER=ON
+
+## Using info
+
+If the Celix Log Writers are installed `find_package(CELIX)` will set:
+ - The `Celix::syslog_writer` bundle target
diff --git a/source/docs/2.3.0/celix/bundles/pubsub/README.md b/source/docs/2.3.0/celix/bundles/pubsub/README.md
new file mode 100644
index 0000000..fb41b16
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/pubsub/README.md
@@ -0,0 +1,118 @@
+---
+title: Publisher / subscriber implementation
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Publisher / subscriber implementation
+
+This subdirectory contains an implementation for a publish-subscribe remote services system, that use dfi library for message serialization.
+For low-level communication, TCP, UDP and ZMQ is used.
+
+# Description
+
+This publisher / subscriber implementation is based on the concepts of the remote service admin (i.e. rsa / topology / discovery pattern).
+
+Publishers are senders of data, subscribers can receive data. Publishers can publish/send data to certain channels (called 'topics' further on), subscribers can subscribe to these topics. For every topic a publisher service is created by the pubsub admin. This publisher is announced through etcd. So etcd is used for discovery of the publishers. Subscribers are also registered as a service by the pubsub admin and will watch etcd for changes and when a new publisher is announced, the subsc [...]
+
+The dfi library is used for message serialization. The publisher / subscriber implementation will arrange that every message which will be send gets an unique id. 
+
+For communication between publishers and subscribers TCP, UDP and ZeroMQ can be used. When using ZeroMQ it's also possible to setup a secure connection to encrypt the traffic being send between publishers and subscribers. This connection can be secured with ZeroMQ by using a curve25519 key pair per topic.
+
+The publisher/subscriber implementation supports sending of a single message and sending of multipart messages.
+
+## Getting started
+
+The publisher/subscriber implementation contains 3 different PubSubAdmins for managing connections:
+  * PubsubAdminUDP: This pubsub admin is using udp (multicast) linux sockets to setup a connection.
+  * PubsubAdminTCP: This pubsub admin is using tcp linux sockets to setup a connection.
+  * PubsubAdminZMQ (LGPL License): This pubsub admin is using ZeroMQ and is disabled as default. This is a because the pubsub admin is using ZeroMQ which is licensed as LGPL ([View ZeroMQ License](https://github.com/zeromq/libzmq#license)).
+  
+  The ZeroMQ pubsub admin can be enabled by specifying the build flag `BUILD_PUBSUB_PSA_ZMQ=ON`. To get the ZeroMQ pubsub admin running, [ZeroMQ](https://github.com/zeromq/libzmq) and [CZMQ](https://github.com/zeromq/czmq) need to be installed. Also, to make use of encrypted traffic, [OpenSSL](https://github.com/openssl/openssl) is required.
+
+## Running instructions
+
+### Running PSA UDP-Multicast
+
+1. Open a terminal
+1. Run `etcd`
+1. Open second terminal on project build location
+1. Run `cd deploy/pubsub/pubsub_publisher_udp_mc`
+1. Run `sh run.sh`
+1. Open third terminal on project build location
+1. Run `cd deploy/pubsub/pubsub_subscriber_udp_mc`
+1. Run `sh run.sh`
+
+Design information can be found at pubsub\_admin\_udp\_mc/README.md
+
+
+### Running PSA TCP
+
+1. Open a terminal
+1. Run `cd runtimes/pubsub/tcp`
+1. Run `sh start.sh`
+
+### Properties PSA TCP
+
+Some properties can be set to configure the PSA-TCP. If not configured defaults will be used. These
+properties can be set in the config.properties file (<PROPERTY>=<VALUE> format)
+
+
+    PSA_IP                              The url address to be used by the TCP admin to publish its data. Default the first IP not on localhost
+                                        This can be hostname / IP address / IP address with postfix, e.g. 192.168.1.0/24
+
+
+### Running PSA ZMQ
+
+For ZeroMQ without encryption, skip the steps 1-12 below
+
+1. Run `touch ~/pubsub.keys`
+1. Run `echo "aes_key:{AES_KEY here}" >> ~/pubsub.keys`. Note that AES_KEY is just a sequence of random bytes. To generate such a key, you can use the command `cat /dev/urandom | hexdump -v -e '/1 "%02X"' | head -c 32` (this will take out of /dev/urandom 16 bytes, thus a 128bit key)
+1. Run `echo "aes_iv:{AES_IV here}" >> ~/pubsub.keys`.  Note that AES_IV is just a sequence of random bytes. To generate such an initial vector , you can use the command `cat /dev/urandom | hexdump -v -e '/1 "%02X"' | head -c 16` (this will take out of /dev/urandom 8 bytes, thus a 64bit initial vector) 
+1. Run `touch ~/pubsub.conf`
+1. Run `echo "keys.file.path=$HOME" >> ~/pubsub.conf`
+1. Run `echo "keys.file.name=pubsub.keys" >> ~/pubsub.conf`
+1. Generate ZMQ keypairs by running `pubsub/keygen/makecert pub_<topic_name>.pub pub_<topic_name>.key`
+1. Encrypt the private key file using `pubsub/keygen/ed_file ~/pubsub.keys pub_<topic_name>.key pub_<topic>.key.enc`
+1. Store the keys in the pubsub/examples/keys/ directory, as described in the pubsub/examples/keys/README.
+1. Build project to include these keys (check the CMakeLists.txt files to be sure that the keys are included in the bundles)
+1. Add to the config.properties the property SECURE_TOPICS=<list_of_secure_topics> 
+
+For ZeroMQ without encryption, start here
+
+1. Run `etcd`
+1. Open second terminal on pubsub root
+1. Run `cd deploy/pubsub/pubsub_publisher_zmq`
+1. Run `cat ~/pubsub.conf >> config.properties` (only for ZeroMQ with encryption)
+1. Run `sh run.sh`
+1. Open third terminal on pubsub root
+1. Run `cd deploy/pubsub/pubsub_subscriber_zmq`
+1. Run `cat ~/pubsub.conf >> config.properties` (only for ZeroMQ with encryption)
+1. Run `sh run.sh`
+
+### Properties PSA ZMQ
+
+Some properties can be set to configure the PSA-ZMQ. If not configured defaults will be used. These
+properties can be set in the config.properties file (<PROPERTY>=<VALUE> format)
+
+
+    PSA_IP                              The local IP address to be used by the ZMQ admin to publish its data. Default the first IP not on localhost
+    PSA_INTERFACE                       The local ethernet interface to be used by the ZMQ admin to publish its data (ie eth0). Default the first non localhost interface
+    PSA_ZMQ_RECEIVE_TIMEOUT_MICROSEC    Set the polling interval of the ZMQ receive thread. Default 1ms
\ No newline at end of file
diff --git a/source/docs/2.3.0/celix/bundles/pubsub/examples/keys/README.md b/source/docs/2.3.0/celix/bundles/pubsub/examples/keys/README.md
new file mode 100644
index 0000000..871f590
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/pubsub/examples/keys/README.md
@@ -0,0 +1,41 @@
+---
+title: Pubsub Keys
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+Store the AES key for encrypting and decrypting the encoded secret keys safe in a file!
+Default file is `/etc/pubsub.keys` with the following format:
+```
+aes_key:{32 character AES key here}
+aes_iv:{16 character AES iv here}
+```
+
+Use the $PROJECT_BUILD/pubsub/keygen/makecert for generating keypairs
+Use the $PROJECT_BUILD/pubsub/keygen/ed_file for encrypting and decrypting private keys
+
+Public keys need to be stored in the 'public' folder having the following format:
+- pub_{topic}.pub
+- sub_{topic}.pub
+
+Secret keys need to be stored in the 'private' folder having the following format:
+- pub_{topic}.key.enc
+- sub_{topic}.key.enc
+These files need to be encrypted using the 'ed_file' executable.
diff --git a/source/docs/2.3.0/celix/bundles/pubsub/pubsub_admin_udp_mc/README.md b/source/docs/2.3.0/celix/bundles/pubsub/pubsub_admin_udp_mc/README.md
new file mode 100644
index 0000000..ada7e4a
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/pubsub/pubsub_admin_udp_mc/README.md
@@ -0,0 +1,85 @@
+---
+title: PSA UDP Multicast
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# PUBSUB-Admin UDP Multicast
+
+---
+
+## Description
+
+This description is particular for the UDP-Multicast PUB-SUB. 
+
+The UDP multicast pubsub admin is used to transfer user data transparent via UDP multicast. UDP packets can contain approximately  
+64kB . To overcome this limit the admin has a protocol on top of UDP which fragments the data to be send and these  
+fragments are reassembled at the reception side.
+
+### IP Addresses
+
+To use UDP-multicast 2 IP addresses are needed:
+
+1. IP address which is bound to an (ethernet) interface
+2. The multicast address (in the range 224.X.X.X - 239.X.X.X)
+
+When the PubSubAdmin starts it determines the bound IP address. This is done in the order:
+
+1. The first IP number bound to the interface which is set by the "PSA_INTERFACE" property
+2. The interfaces are iterated and the first IP number found is used. (typically this is 127.0.0.1 (localhost)
+
+The multicast IP address is determined in the order:
+
+1. If the `PSA_IP` property is defined, this IP will be used as multicast.
+2. If the `PSA_MC_PREFIX` property, is defined, this property is used as the first 2 numbers of the multicast address extended with the last 2 numbers of the bound IP.
+3. If the `PSA_MC_PREFIX` property is not defined `224.100` is used.
+
+### Discovery
+
+When a publisher request for a topic a TopicSender is created by a ServiceFactory. This TopicSender uses the multicast address as described above with a random chosen portnumber. The combination of the multicast-IP address with the portnumber and protocol(udp) is the endpoint.  
+This endpoint is published by the PubSubDiscovery within its topic in ETCD (i.e. udp://224.100.10.20:40123).
+ 
+A subscriber, interested in the topic, is informed by the the TopologyManager that there is a new endpoint. The TopicReceiver at the subscriber side creates a listening socket based on this endpoint.
+
+Now a data-connection is created and data send by the publisher will be received by the subscriber.  
+
+---
+
+## Properties
+
+<table border="1">
+    <tr><th>Property</th><th>Description</th></tr>
+    <tr><td>PSA_INTERFACE</td><td>Interface which has to be used for multicast communication</td></tr>
+    <tr><td>PSA_IP</td><td>Multicast IP address used by the bundle</td></tr>
+    <tr><td>PSA_MC_PREFIX</td><td>First 2 digits of the MC IP address </td></tr>
+</table>
+
+---
+
+## Shortcomings
+
+1. Per topic a random portnr is used for creating an endpoint. It is theoretical possible that for 2 topic the same endpoint is created.
+2. For every message a 32 bit random message ID is generated to discriminate segments of different messages which could be sent at the same time. It is theoretically possible that there are 2 equal message ID's at the same time. But since the message ID is valid only during the transmission of a message (maximum some milliseconds with large messages) this is not very plausible.
+3. When sending large messages, these messages are segmented and sent after each other. This could cause UDP-buffer overflows in the kernel. A solution could be to add a delay between sending of the segments but this will introduce extra latency.
+4. A Hash is created, using the message definition, to identify the message type. When 2 messages generate the same hash something will terribly go wrong. A check should be added to prevent this (or another way to identify the message type). This problem is also valid for the other admins.
+
+
+
+
diff --git a/source/docs/2.3.0/celix/bundles/remote_services/README.md b/source/docs/2.3.0/celix/bundles/remote_services/README.md
new file mode 100644
index 0000000..48af374
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/remote_services/README.md
@@ -0,0 +1,176 @@
+---
+title: Remote Service Admin Service
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+## Introduction
+
+The Remote Service Admin Service subproject contains an adapted implementation of the OSGi Enterprise Remote Service Admin Service Specification. The subproject consists of three parts, each described in more detail in the following sections.
+
+### Topology Manager
+
+The topology manager decides which services should be imported and exported according to a defined policy. Currently, only one policy is implemented in Celix, the *promiscuous* policy, which simply imports and exports all services.
+
+| **Bundle** | `topology_manager.zip` |
+|--|--|
+| **Configuration** | *None* |
+
+### Remote Service Admin
+
+The Remote Service Admin (RSA) provides the mechanisms to import and export services when instructed to do so by the Topology Manager. 
+
+#### Endpoints and proxies
+
+To delegate a *received* method call to the actual service implementation, the RSA uses an "endpoint" bundle, which has all the knowledge about the marshalling and unmarshalling of data for the service. This endpoint bundle is specific to the used RSA implementation, and as such cannot be reused between various RSA implementations.
+
+Invoking a *remote* method is done by using "proxy" bundles. Similar as to endpoints, proxy bundles encapsulate all knowledge to marshall and unmarshall data for a remote method call and as such can not be shared between RSA implementations.
+
+Both proxy and endpoint bundles are loaded on demand when a service is imported or exported by the RSA. As such, these bundles **must** not be added to the list of "auto started" bundles, but placed in a separate location. By default, `endpoints` is used as location for locating proxy and/or endpoint bundles.
+
+Note that since endpoints and proxies need to be created manually, one has full control about the handling of specifics of marshalling and unmarshalling data and dealing with exceptions. 
+
+#### HTTP/JSON
+
+Provides a RSA implementation that uses JSON to marshal requests and HTTP as transport mechanism for its remote method invocation. It is compatible with the *Remote Service Admin HTTP* implementation provided by [Amdatu Remote](https://amdatu.atlassian.net/wiki/display/AMDATUDEV/Amdatu+Remote).
+
+| **Bundle** | `remote_service_admin_http.zip` |
+|--|--|
+| **Configuration** | `RSA_PORT`: defines the port on which the HTTP server should listen for incoming requests. Defaults to port `8888`; |
+| | `ENDPOINTS`: defines the location in which service endpoints and/or proxies can be found. Defaults to `endpoints` in the current working directory |
+
+#### Shared memory (SHM)
+
+Provides a RSA implementation that uses shared memory for its remote method invocation. Note that this only works when all remote services are located on the same machine.
+
+| **Bundle** | `remote_service_admin_shm.zip` |
+|--|--|
+| **Configuration** | `ENDPOINTS`: defines the location in which service endpoints and/or proxies can be found. Defaults to `endpoints` in the current working directory |
+
+### Discovery
+
+Actively discovers the presence of remote exported services and provides information about local exported services, as given by the Topology Manager, to others.
+
+#### Shared memory (SHM) based discovery
+
+Provides service discovery for the RSA SHM implementation.
+
+| **Bundle** | `discovery_shm.zip` |
+|--|--|
+| **Configuration** | *None* |
+
+#### Configured discovery
+
+Provides a service discovery with preconfigured discovery endpoints, allowing a static mesh of nodes for remote service invocation to be created. The configured discovery bundle in Celix is compatible with the configured discovery implementation provided by [Amdatu Remote](https://amdatu.atlassian.net/wiki/display/AMDATUDEV/Amdatu+Remote).
+
+| **Bundle** | `discovery_configured.zip` |
+|--|--|
+| **Configuration** | `DISCOVERY_CFG_POLL_ENDPOINTS`: defines a comma-separated list of discovery endpoints that should be used to query for remote services. Defaults to `http://localhost:9999/org.apache.celix.discovery.configured`; |
+| | `DISCOVERY_CFG_POLL_INTERVAL`: defines the interval (in seconds) in which the discovery endpoints should be polled. Defaults to `10` seconds. |
+| | `DISCOVERY_CFG_POLL_TIMEOUT`: defines the maximum time (in seconds) a request of the discovery endpoint poller may take. Defaults to `10` seconds. |
+| | `DISCOVERY_CFG_SERVER_PORT`: defines the port on which the HTTP server should listen for incoming requests from other configured discovery endpoints. Defaults to port `9999`; |
+| | `DISCOVERY_CFG_SERVER_PATH`: defines the path on which the HTTP server should accept requests from other configured discovery endpoints. Defaults to `/org.apache.celix.discovery.configured`. |
+
+Note that for configured discovery, the "Endpoint Description Extender" XML format defined in the OSGi Remote Service Admin specification (section 122.8 of OSGi Enterprise 5.0.0) is used.
+
+See [etcd discovery](discovery_etcd/README.html)
+
+#### etcd discovery 
+
+| **Bundle** | `discovery_etcd.zip` |
+
+Provides a service discovery using etcd distributed key/value store.
+
+See [etcd discovery](discovery_etcd/README.html)
+
+## Usage
+
+To develop for the Remote Service Admin implementation of Celix, one needs the following:
+
+1. A service **interface**, describes the actual service and methods[^1] that can be called. The service interface is needed at development time to allow a consistent definition;
+2. A service **implementation**, when exporting it as remote service. A service endpoint is needed to delegate remote requests to your service implementation;
+3. A service **client** or user, which invokes methods on the local or remote service. The client is oblivious to the fact whether the service is running locally or remote.
+
+The Celix source repository provides a simple calculator example that shows all of the described parts:
+
+1. [The calculator service interface](https://github.com/apache/celix/blob/master/bundles/remote_services/examples/calculator_api/include/calculator_service.h), providing three methods: one for adding two numbers, one for subtracting two numbers, and lastly, a method that calculates the square root of a number;
+2. [A calculator service implementation](https://github.com/apache/celix/blob/master/bundles/remote_services/examples/calculator_service/src/calculator_impl.c) that simply implements the three previously described functions. To mark this service as "remote service", you need to add the `service.exported.interfaces` service property to its service registration. This way, the RSA implementation can expose it as remote service to others;
+3. [A service client](https://github.com/apache/celix/blob/master/bundles/remote_services/examples/calculator_shell/src/add_command.c), that exposes the three calculator methods to as Celix shell commands. The implementation simply retrieves the calculator service as it would do with any other Celix service.
+
+If you have access to the Celix source repository, you can run the calculator example using various discovery implementations by invoking the `deploy` target. You can find the example deployments in the `CELIX_BUILD/deploy` directory. For example, to run the calculator example using the configured discovery mechanism, you should open two terminals. In the first terminal, type:
+
+    remote-service-cfg$ export RSA_PORT=18888
+    remote-service-cfg$ sh run.sh
+    ...
+    RSA: Export services (org.apache.celix.calc.api.Calculator)
+    ...
+    -> _
+
+In the second terminal, type:
+
+    remote-service-cfg-client$ export RSA_PORT=28888
+    remote-service-cfg-client$ sh run.sh
+    ...
+    RSA: Import service org.apache.celix.calc.api.Calculator
+    ...
+    -> _
+
+Now, if all went well, the client (second terminal) has three new shell commands, `add`, `sub` and `sqrt`, which you can use to invoke the calculator service:
+
+    -> add 3 5
+    CALCULATOR_SHELL: Add: 3.000000 + 5.000000 = 8.000000
+    -> _
+
+On the server side (first terminal), you can follow each invocation as well:
+
+    CALCULATOR_ENDPOINT: Handle request "add(DD)D" with data "{"m": "add(DD)D", "a": [3.0, 5.0]}"
+    CALCULATOR: Add: 3.000000 + 5.000000 = 8.000000
+
+Note that the `RSA_PORT` property needs to be unique for at least the client in order to communicate correctly when running the examples on the same machine. 
+
+## Building
+
+To build the Remote Service Admin Service the CMake build option "`BUILD_REMOTE_SERVICE_ADMIN`" has to be enabled.
+
+## Dependencies
+
+The Remote Service Admin Service depends on the following subprojects:
+
+- Framework
+- Utils
+
+Also the following libraries are required for building and/or using the Remote Service Admin Service subproject:
+
+- Jansson (build and runtime)
+- cURL (build and runtime)
+
+## RSA Bundles
+
+* [Remote Service Admin DFI](remote_service_admin_dfi) - A Dynamic Function Interface (DFI) implementation of the RSA.
+* [Remote Service Admin SHM](remote_service_admin_shm) - A shared memory implementation of the RSA.
+* [Topology Manager](topology_manager) - A (scoped) RSA Topology Manager implementation.
+* [Discovery Configured](discovery_configured) - A RSA Discovery implementation using static configuration (xml).
+* [Discovery Etcd](discovery_etcd/README.html) - A RSA Discovery implementation using etcd.
+* [Discovery SHM](discovery_shm) - A RSA Discovery implementation using shared memory.
+
+
+## Notes
+
+[^1]: Although C does not use the term "method", we use this term to align with the terminology used in the RSA specification. 
diff --git a/source/docs/2.3.0/celix/bundles/remote_services/deprecated_rsa_spi/README.md b/source/docs/2.3.0/celix/bundles/remote_services/deprecated_rsa_spi/README.md
new file mode 100644
index 0000000..822f130
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/remote_services/deprecated_rsa_spi/README.md
@@ -0,0 +1,17 @@
+---
+title: Remote Services SPI
+type: celix-doc
+version: 2.3.0
+---
+
+# Remote Service Admin
+
+The Remote Service Admin (RSA) provides the mechanisms to import and export services when instructed to do so by the Topology Manager. 
+
+To delegate method calls to the actual service implementation, the RSA_SHM and the RSA_HTTP are using "endpoint/proxy" bundles, which has all the knowledge about the marshalling and unmarshalling of data for the service. The RSA_DFI implementation combines a [foreign function interface](https://en.wikipedia.org/wiki/Foreign_function_interface) technique together with manually created descriptors.
+
+Note that this folder contains code commonly used by the RSA implementations and therefore does not include any CMAKE configuration.
+
+## Properties
+    ENDPOINTS				 defines the relative directory where endpoints and proxys can be found (default: endpoints)
+    CELIX_FRAMEWORK_EXTENDER_PATH  Used in RSA_DFI only. Can be used to define a path to use as an extender path point for the framework bundle. For normal bundles the bundle cache is used. 
diff --git a/source/docs/2.3.0/celix/bundles/remote_services/discovery_etcd/README.md b/source/docs/2.3.0/celix/bundles/remote_services/discovery_etcd/README.md
new file mode 100644
index 0000000..2f689ac
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/remote_services/discovery_etcd/README.md
@@ -0,0 +1,39 @@
+---
+title: Discovery ETCD
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+## Discovery ETCD
+
+The Celix Discovery ETCD bundles realizes OSGi services discovery based on [etcd](https://github.com/coreos/etcd).
+
+###### Properties
+    DISCOVERY_ETCD_ROOT_PATH            Used path to announce and find discovery entpoints (default: discovery)
+    DISCOVERY_ETCD_SERVER_IP            ip address of the etcd server (default: 127.0.0.1)
+    DISCOVERY_ETCD_SERVER_PORT          port of the etcd server  (default: 2379)
+    DISCOVERY_ETCD_TTL                  time-to-live for etcd entries in seconds (default: 30)
+    
+    DISCOVERY_CFG_SERVER_IP             The host to use/announce for this framewokr discovery endpoint. Default "127.0.0.1"
+    DISCOVERY_CFG_SERVER_PORT           The port to use/announce for this framework endpoint endpoint. Default 9999
+    DISCOVERY_CFG_SERVER_PATH           The path to use for this framework discovery endpoint.Default "/org.apache.celix.discovery.etcd"
+
+###### CMake option
+    BUILD_RSA_DISCOVERY_ETCD=ON
diff --git a/source/docs/2.3.0/celix/bundles/remote_services/remote_service_admin_dfi/README.md b/source/docs/2.3.0/celix/bundles/remote_services/remote_service_admin_dfi/README.md
new file mode 100644
index 0000000..c9ec060
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/remote_services/remote_service_admin_dfi/README.md
@@ -0,0 +1,44 @@
+---
+title: Remote Service Admin DFI
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+## Remote Service Admin DFI
+
+The Celix Remote Service Admin DFI bundle realizes OSGi remote service using HTTP and JSON.
+The serialization is done using libdfi to json. 
+Libffi is configured using descriptor files in the bundles. 
+
+###### Properties
+    RSA_PORT                    The RSA HTTP port to use (default 8888)
+    RSA_IP                      The RSA ip address to use for discovery (default 127.0.0.1)
+    RSA_INTERFACE               If specified, the ip adress of interface (i.g. eth0) will be used.
+    
+    RSA_LOG_CALLS              If set to true, the RSA will Log calls info (including serialized data) to the file in RSA_LOG_CALLS_FILE. Default is false.
+    RSA_LOG_CALLS_FILE         If RSA_LOG_CALLS is enabled to file to log to (starting rsa will truncate file). Default is stdout.   
+
+    RSA_DFI_USE_CURL_SHARE_HANDLE   If set to true the RSA will use curl's share handle. 
+                                    The curl share handle has a significant performance boost by sharing DNS, COOKIE en CONNECTIONS over multiple calls, 
+                                    but can also introduce some issues (based on experience).
+                                    Default is false
+
+###### CMake option
+    RSA_REMOTE_SERVICE_ADMIN_DFI=ON
diff --git a/source/docs/2.3.0/celix/bundles/remote_services/remote_services_api/README.md b/source/docs/2.3.0/celix/bundles/remote_services/remote_services_api/README.md
new file mode 100644
index 0000000..e3cfe38
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/remote_services/remote_services_api/README.md
@@ -0,0 +1,17 @@
+---
+title: Remote Services API
+type: celix-doc
+version: 2.3.0
+---
+
+# Remote Service Admin
+
+The Remote Service Admin (RSA) provides the mechanisms to import and export services when instructed to do so by the Topology Manager. 
+
+To delegate method calls to the actual service implementation, the RSA_SHM and the RSA_HTTP are using "endpoint/proxy" bundles, which has all the knowledge about the marshalling and unmarshalling of data for the service. The RSA_DFI implementation combines a [foreign function interface](https://en.wikipedia.org/wiki/Foreign_function_interface) technique together with manually created descriptors.
+
+Note that this folder contains code commonly used by the RSA implementations and therefore does not include any CMAKE configuration.
+
+## Properties
+    ENDPOINTS				 defines the relative directory where endpoints and proxys can be found (default: endpoints)
+    CELIX_FRAMEWORK_EXTENDER_PATH  Used in RSA_DFI only. Can be used to define a path to use as an extender path point for the framework bundle. For normal bundles the bundle cache is used. 
diff --git a/source/docs/2.3.0/celix/bundles/remote_services/topology_manager/README.md b/source/docs/2.3.0/celix/bundles/remote_services/topology_manager/README.md
new file mode 100644
index 0000000..f183496
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/remote_services/topology_manager/README.md
@@ -0,0 +1,29 @@
+---
+title: RSA Topology Manager
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+## Topology Manager
+
+The Topology Manager decides which services should be imported and exported according to a defined policy. Currently, only one policy is implemented in Celix, the *promiscuous* policy, which simply imports and exports all services. Note that the Topology Manager is essential to use remote services.
+
+###### CMake option
+    BUILD_RSA_TOPOLOGY_MANAGER=ON
diff --git a/source/docs/2.3.0/celix/bundles/shell/README.md b/source/docs/2.3.0/celix/bundles/shell/README.md
new file mode 100644
index 0000000..228d06d
--- /dev/null
+++ b/source/docs/2.3.0/celix/bundles/shell/README.md
@@ -0,0 +1,94 @@
+---
+title: Shell
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Intro
+The Celix Shell provides a service interface which can be used to interact with the Celix framework. It uses a modular
+approach to enable multiple frontends, e.g. textual or graphical.
+
+While the shell can be extended with additional commands by other bundles, it already offers some built in commands,
+for example:
+ - `lb`: list bundles
+ - `install`: install additional bundle 
+ - `uninstall`: uninstall bundles
+ - `start`: start bundle
+ - `stop`: stop bundle
+ - `help`: displays available commands
+
+Further information about a command can be retrieved by using `help` combined with the command.
+
+# Service interfaces
+The Celix Shell functionality is achieved by 3 service interfaces. These interfaces are available through the 
+`Celix::shel_api` CMake INTERFACE library target. 
+
+- `celix_shell_t`: The shell service can be used to get an overview of the available shell commands and to execute
+   shell commands.
+- `celix_shell_command_t`: A C service interface to provide an additional shell command to the shell. 
+- `celix::IShellCommand`: A C++ service interface to provide an additional shell command to the shell.
+
+# Bundles
+The complete Celix shell functionality is provided by serveral bundles:
+ - `Celix::shell` : The core shell which offer a `celix_shell_t` service and uses `celix_shell_command_t` services.
+ - `Celix::CxxShell` : The core C++ shell which offers a `celix_shell_t` service and uses both `celix_shell_command_t`
+   and `celix::IShellCommand` services. Offers the same functionality as `Celix::shell`, but also supports C++
+   `celix::IShellCommand` services.
+ - `Celix::shell_tui` : Textual (terminal) user interface to the shell service. 
+ - `Celix::shell_wui` : Web user interface to the shell service.
+ - `Celix::remote_shell` : Remote telnet interface to shell service 
+ - `Celix::bonjour_shell`: Chat interface to the shell service using bonjour. Warning not mature and still unstable. When used it should be possible to chat to a Celix shell using Linux's pidgin application or OSX's 
+   Messages application.
+
+## Logical Design Celix Shell
+
+|![Celix Shell Logical Design](diagrams/celix_shell.png)
+
+## Logical Design Celix Shell for C++
+![Celix C++ Shell Logical Design](diagrams/celix_cxx_shell.png)
+
+# CMake options
+
+- BUILD_SHELL=ON
+- BUILD_SHELL_TUI=ON
+- BUILD_SHELL_WUI=ON
+- BUILD_REMOTE_SHELL=ON
+
+# Shell Config Options
+
+- SHELL_USE_ANSI_COLORS - Configures whether shell commands are allowed to use
+ANSI colors when printing info for `Celix::shell`. Default is true.
+- SHELL_TUI_USE_ANSI_CONTROL_SEQUENCES - Configures whether to use ANSI control
+  sequences to support backspace, left, up, etc key commands in the
+  `Celix::shell_tui`. Default is true if a TERM environment is set else false.
+- "remote.shell.telnet.port": Configures port used in `Celix::remote_shell`. Default is 6666.
+- "remote.shell.telnet.maxconn": Configures max nr of concurrent connections in `Celix::remote_shell`. Default is 2.
+
+# Using info
+
+If the Celix Shell is installed, `find_package(Celix)` will set:
+ - The `Celix::shell_api` interface (i.e. header only) library target
+ - The `Celix::shell` bundle target
+
+If the Celix Shell TUI is installed, `find_package(Celix)` will set:
+- The `Celix::shell_tui` bundle target if the shell_tui is installed
+
+If the Celix Shell WUI is installed, `find_package(Celix)` will set:
+- The `Celix::shell_wui` bundle target if the shell_wui is installed
\ No newline at end of file
diff --git a/source/docs/2.3.0/celix/documents/README.md b/source/docs/2.3.0/celix/documents/README.md
new file mode 100644
index 0000000..2f8d949
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/README.md
@@ -0,0 +1,92 @@
+---
+title: Introduction
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Apache Celix Introduction
+
+## What is Apache Celix
+Apache Celix is an implementation of a dynamic service framework inspired by the 
+[OSGi specification](https://www.osgi.org/developer/specifications) and adapted to C and C++ (C++17).
+It is a framework to develop dynamic modular software applications using component and in-process service-oriented programming.
+
+Apache Celix core is written in C and has a C++17 header-only API on top of the C API. 
+
+Building applications with Apache Celix can be done by creating `bundles` which provide and use `services`; 
+These `services` can be used directly or in a declarative way using `components`. 
+To run a selection of bundles, an Apache Celix `container` executable can be created. An Apache Celix `containter` will  
+start an Apache Celix framework and install and start the provided bundles.  
+
+## Bundles
+An Apache Celix Bundle is a zip file which contains a collection of shared libraries, 
+configuration files and optional an activation entry. 
+Bundles can be dynamically installed and started in an Apache Celix framework.
+
+## Services
+An Apache Celix Service is a pointer registered to the Apache Celix framework under a set of properties (metadata).
+Services can be dynamically registered into and looked up from the Apache Celix framework.
+
+By convention a C service in Apache Celix is a pointer to struct of function pointers and a C++ service is a pointer
+(which can be provided as a `std::shared_ptr`) to an object implementing a (pure) abstract class.
+
+## Components
+Apache Celix also offers a way to create components which interact with dynamic services in declarative way. 
+
+This removes some complexity of dynamic services by declaring service dependency and configuring the dependency 
+as required or optional. 
+
+Apache Celix components can be created using the built-in C and C++ dependency manager.
+
+Note that the dependency manager is not part of the OSGi standard, and it is inspired by the 
+Apache Felix Dependency Manager. 
+
+## Containers
+Apache Celix Containers are executables which starts an Apache Celix framework, with a set of preconfigured properties 
+and a set of preconfigured bundles. 
+Although it is also possible to create and start a Celix framework in code, the benefit of a Celix container 
+is that this can be done with a single `add_celix_container` Apache Celix CMake command. 
+
+## C++ Support
+
+One of the reasons why C was chosen as implementation language is that C can act as a common denominator for 
+(service oriented) interoperability between a range of languages.
+
+C++ (C++17) support is build on top of the C API and is realized using a header only implementation. 
+This means that all the binary artifact for the Apache Celix framework and util library are pure C and do not depend on 
+libstdc++. 
+
+Apache Celix also offers some C++ only libraries and bundles. The C++ libraries are also header only, but the C++
+bundles contains binaries depending on the stdlibc++ library.
+
+## More information
+
+* Building
+  * [Building and Installing Apache Celix](building)
+  * [Building and Developing Apache Celix with CLion](building/dev_celix_with_clion.html)
+* Framework 
+  * [Apache Celix Bundles](bundles.html)
+  * [Apache Celix Services](services.html)
+  * [Apache Celix Components](components.html) 
+  * [Apache Celix Framework](framework.html)
+  * [Apache Celix Containers](containers.html)
+  * [Apache Celix Patterns](patterns.html)
+* [Apache Celix CMake Commands](cmake_commands)
+* [Apache Celix Sub Projects](subprojects.html)
diff --git a/source/docs/2.3.0/celix/documents/building/README.md b/source/docs/2.3.0/celix/documents/building/README.md
new file mode 100644
index 0000000..e817f83
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/building/README.md
@@ -0,0 +1,168 @@
+---
+title: Building and Installing Apache Celix
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Building and Installing Apache Celix
+Apache Celix aims to be support a broad range of UNIX platforms.
+ 
+Currently, the [continuous integration build server] builds and tests Apache Celix for:
+
+* Ubuntu Bionic Beaver (20.04)
+    * GCC 
+    * CLang 
+* OSX
+    * CLang
+
+
+### Download the Apache Celix sources
+To get started you first have to download the Apache Celix sources. This can be done by cloning the Apache Celix git repository:
+
+```bash
+#clone the repro
+git clone --single-branch --branch master https://github.com/apache/celix.git
+```
+
+## Building and installing
+Apache Celix uses [CMake](https://cmake.org) as build system. CMake can generate (among others) makefiles.
+
+### Building and installing with preinstalled libraries
+The following packages (libraries + headers) should be installed on your system:
+
+* Development Environment
+    * build-essentials (gcc/g++ or clang/clang++) 
+    * java or zip (for packaging bundles)
+    * make (3.14 or higher)
+    * git
+* Apache Celix Dependencies
+    * libzip
+    * uuid
+    * zlib
+    * curl (only initialized in the Celix framework)
+    * jansson (for serialization in libdfi)
+    * libffi (for libdfi)
+    * libxml2 (for remote services and bonjour shell)
+    * rapidjson (for C++ remote service discovery)
+    * libczmq (for PubSubAdmin ZMQ)
+	
+
+For Ubuntu 20.04, use the following commands:
+```bash
+#### get dependencies
+sudo apt-get install -yq --no-install-recommends \
+    build-essential \
+    git \
+    curl \
+    uuid-dev \
+    libjansson-dev \
+    libcurl4-openssl-dev \
+    default-jdk \
+    libffi-dev \
+    libzip-dev \
+    libxml2-dev \
+    libczmq-dev \
+    libcpputest-dev \
+    rapidjson-dev
+
+#The cmake version for Ubuntu 20 is older than 3.14,
+#use snap to install the latest cmake version
+snap install cmake
+```
+
+For OSX systems with brew installed, use the following commands:
+```bash
+    brew update && \
+    brew install lcov libffi libzip czmq rapidjson libxml2 cmake && \
+    brew link --force libffi
+``` 
+
+Use CMake and make to build Apache Celix
+```bash
+cd celix
+mkdir build
+cd build
+cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. 
+make -j
+```
+
+## Editing Build options
+With use of CMake, Apache Celix makes it possible to edit build options. This enabled users, among other options, to configure a install location and select additional bundles.
+To edit the options use ccmake or cmake-gui. For cmake-gui an additional package install can be necessary (Fedora: `dnf install cmake-gui`). 
+
+```bash
+cd celix/build
+ccmake .
+#Edit options, e.g. enable BUILD_REMOTE_SHELL to build the remote (telnet) shell
+#Edit the CMAKE_INSTALL_PREFIX config to set the install location
+```
+
+For this guide we assume the CMAKE_INSTALL_PREFIX is `/usr/local`.
+
+## Installing Apache Celix
+
+```bash
+cd celix/build
+make -j
+sudo make install
+```
+
+## Running Apache Celix
+If Apache Celix is successfully installed running
+```bash
+celix
+```
+should give the following output:
+"Error: invalid or non-existing configuration file: 'config.properties'.No such file or directory".
+
+For more info how to build your own projects and/or running the Apache Celix examples see [Celix Intro](../README.html).
+
+# Building etcdlib library standalone
+```bash
+#bash
+git clone git@github.com:apache/celix.git
+mkdir celix/build
+cd celix/build
+cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ../libs/etcdlib
+make -j
+sudo make install
+```
+
+# Building Celix Promises library standalone
+```bash
+#bash
+git clone git@github.com:apache/celix.git
+mkdir celix/build
+cd celix/build
+cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ../libs/promises
+make -j
+sudo make install
+```
+
+# Building Celix Push Streams library standalone
+```bash
+#bash
+git clone git@github.com:apache/celix.git
+mkdir celix/build
+cd celix/build
+cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ../libs/pushstreams
+make -j
+sudo make install
+```
\ No newline at end of file
diff --git a/source/docs/2.3.0/celix/documents/building/dev_celix_with_clion.md b/source/docs/2.3.0/celix/documents/building/dev_celix_with_clion.md
new file mode 100644
index 0000000..7523c1d
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/building/dev_celix_with_clion.md
@@ -0,0 +1,66 @@
+---
+title: Building and Developing Apache Celix with CLion
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Building and Developing Apache Celix with CLion
+Apache Celix can be build for development in CLion with use of the Conan package manager.
+Conan will arrange the building of the Apache Celix dependencies and generate Find<package> files for these dependencies.
+
+Conan will also generate a `active_run.sh` and `deactivate_run.sh` script that does the environment (de)setup for the 
+binary locations of the build dependencies (i.e. configures `PATH` and `LD_LIBRARY_PATH`/`DYLD_LIBRARY_PATH`).
+
+## Setting up the build directory
+```shell
+#clone git repo
+git clone https://github.com/apache/celix.git
+cd celix
+
+#if needed setup conan default and debug profile
+conan profile new default --detect
+conan profile new debug --detect
+conan profile update settings.build_type=Debug debug
+
+#generate and configure cmake-build-debug directory
+conan install . celix/2.3.0 -pr:b default -pr:h debug -if cmake-build-debug/ -o celix:enable_testing=True -o celix:enable_address_sanitizer=True -o celix:build_all=True -b missing
+conan build . -bf cmake-build-debug/ --configure
+
+#optional build
+cd cmake-build-debug
+make -j
+
+#optional setup run env and run tests
+source activate_run.sh 
+ctest --verbose
+source deactivate_run.sh 
+```
+
+## Configuring CLion
+To ensure that all Conan build dependencies can be found the Run/Debug configurations of CLion needs te be updated.
+
+This can be done under the menu "Run->Edit Configurations...", then select "Edit configuration templates..." and
+then update the "Google Test" template so that the `active_run.sh` Conan generated script is sourced in the 
+"Environment variables" entry. 
+
+If the Apache Celix CMake build directory is `home/joe/workspace/celix/cmake-build-debug` then the value for 
+"Environment variables" should be: `source /home/joe/workspace/celix/cmake-build-debug/activate_run.sh`
+
+![Configure CLion](media/clion_run_configuration_template.png)
\ No newline at end of file
diff --git a/source/docs/2.3.0/celix/documents/bundles.md b/source/docs/2.3.0/celix/documents/bundles.md
new file mode 100644
index 0000000..ef1d1dd
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/bundles.md
@@ -0,0 +1,301 @@
+---
+title: Apache Celix Bundles
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Apache Celix Bundles
+An Apache Celix Bundle contains a collection of shared libraries, configuration files and optional
+an activation entry combined in a zip file. Bundles can be dynamically installed and started in an Apache Celix framework.
+
+## The anatomy of a Celix Bundle
+Technically an Apache Celix Bundle is a zip file with the following content:
+
+- META-INF/MANIFEST.MF: The required bundle manifest, containing information about the bundle (name, activator library etc)
+- Bundle shared libraries (so/dylib files): Optionally a bundle has 1 or more shared libraries.
+  The bundle manifest configures which libraries will be loaded (private libs) and which - if any - library is used
+  when activating the bundle.
+- Bundle resource files: A bundle can also contain additional resource files. 
+  This could be configuration files, html files, etc.  
+  It is also possible to have bundles which no shared library, but only resource files.
+  Note that bundles can access other bundles resources files.
+
+If a `jar` command is available the Celix CMake commands will use that (instead of the `zip` command) to create bundle
+zip files so that the MANIFEST.MF is always the first entry in the zip file.
+
+
+```bash
+#unpacking celix_shell_wui.zip bundle file from a cmake build `cmake-build-debug`.
+#The celix_shell_wui.zip file is the Celix Shell Web UI bundle. Which provides a web ui interface to the Celix 
+#interactive shell; It contains a manifest file, shared libraries, and additional web resources 
+#which can be picked up by the `Celix::http_admin` bundle. 
+% unzip cmake-build-debug/bundles/shell/shell_wui/celix_shell_wui.zip -d unpacked_bundle_dir 
+% find unpacked_bundle_dir 
+unpacked_bundle_dir
+unpacked_bundle_dir/resources
+unpacked_bundle_dir/resources/index.html
+unpacked_bundle_dir/resources/ansi_up.js
+unpacked_bundle_dir/resources/script.js
+unpacked_bundle_dir/META-INF
+unpacked_bundle_dir/META-INF/MANIFEST.MF
+unpacked_bundle_dir/libcivetweb_shared.so #or dylib for OSX
+unpacked_bundle_dir/libshell_wui.1.so #or dylib for OSX    
+```
+
+## Bundle lifecycle
+An Apache Celix Bundle has its own lifecycle with the following states:
+
+- Installed - The bundle has been installed into the Celix framework, but it is not yet resolved. For Celix this 
+  currently means that not all bundle libraries can or have been loaded. 
+- Resolved - The bundle is installed and its requirements have been met. For Celix this currently means that the
+  bundle libraries have been loaded. 
+- Starting - Starting is a temporary state while the bundle activator's create and start callbacks are being executed.
+- Active - The bundle is active. 
+- Stopping - Stopping is a temporary state while the bundle activator stop and destroy callbacks are being executed. 
+- Uninstalled - The bundle has been removed from the Celix framework. 
+
+![State diagram of the bundle lifecycle](diagrams/bundles_lifecycle.png)
+
+## Bundle activation
+Bundles can be installed and started dynamically. When a bundle is started it will be activated by looking up the bundle
+activator entry points (using `dlsym`). The entry points signatures are:
+- `celix_status_t celix_bundleActivator_create(celix_bundle_context_t *ctx, void **userData)`: 
+   Called to create the bundle activator.
+- `celix_status_t celix_bundleActivator_start(void *userData, celix_bundle_context_t *ctx)`: 
+   Called to start the bundle.
+- `celix_status_t celix_bundleActivator_stop(void *userData, celix_bundle_context_t *ctx)`: 
+   Called to stop the bundle.
+- `celix_status_t celix_bundleActivator_destroy(void *userData, celix_bundle_context_t* ctx)`: 
+   Called to destroy (free mem) the bundle activator.
+
+The most convenient way to create a bundle activator in C is to use the macro `CELIX_GEN_BUNDLE_ACTIVATOR` defined in
+`celix_bundle_activator.h`. This macro requires two functions (start,stop), these function can be `static` and
+use a typed bundle activator struct instead of `void*`.
+
+For C++, the macro `CELIX_GEN_CXX_BUNDLE_ACTIVATOR` defined in `celix/BundleActivator.h` must be used to create a
+bundle activator. For C++ a RAII approach is used for bundle activation.
+This means that a C++ bundle is started by creating a bundle activator object and stopped by
+letting the bundle activator object go out of scope.
+
+## Bundle and Bundle Context
+
+A bundle can interact with the Apache Celix framework using a bundle execution context or bundle context in short.
+The bundle context provides functions/methods to:
+ - Register and un-register services. 
+ - Install, start, stop or uninstall bundles.
+ - Track for service being added or removed.
+ - Track for bundles being installed, started, stopped or uninstalled.
+ - Track for service tracker being started or stopped
+ - Find service ids for a given filter.
+ - Use services directly (without manually creating a service tracker).
+ - Use bundles directly (without manually creating a bundle tracker).
+ - Wait for events in the Celix event thread.
+ - Retrieve framework property values. 
+ - Retrieve the bundle object associated with the bundle context. 
+ 
+## Hello World Bundle Example
+The hello world bundle example is a simple example which print a "Hello world" and "Goodbye world" line when
+starting / stopping the bundle.
+
+Knowledge about C, C++ and CMake is expected to understand the examples.
+
+The C and C++ examples exists of a single source file which contains the bundle activator and some Apache Celix 
+CMake commands to create a bundle and a container.
+
+Both containers example uses 3 bundles: the Apache Celix Shell bundle, the Apache Celix Shell Textual UI bundle 
+and the Hello World bundle. The Apache Celix Shell bundle provides a set of interactive shell commands and the
+Apache Celix Shell Textual UI bundle can be used to run these command from a console terminal. 
+
+When the C or C++ Hello World bundle example container is started, the following commands can be used to dynamically
+stop and start the Hello World bundle.
+```bash
+stop 3 #Stopping the Hello World bundle. Note that the Hello World is the third bundle, so it will get a bundle id 3.
+start 3 #Starting the Hello World bundle again.
+uninstall 3 #Stoping and uninstalling the Hello World bundle.
+stop 0 #stop the Apache Celix framework
+```
+
+The see what other Apache Celix shell commands are available run the `celix::help` command:
+```bash
+help #note can also be triggered with celix::help (the fully qualified command name). 
+help celix::start 
+help celix::lb
+stop 0 #stop the Apache Celix framework
+```
+
+### C Example
+```C
+//src/my_bundle_activator.c
+#include <celix_api.h>
+
+typedef struct my_bundle_activator_data {
+    /*the hello world bundle activator struct is empty*/
+} my_bundle_activator_data_t;
+
+static celix_status_t my_bundle_start(my_bundle_activator_data_t *data, celix_bundle_context_t *ctx) {
+    printf("Hello world from bundle with id %li\n", celix_bundleContext_getBundleId(ctx));
+    return CELIX_SUCCESS;
+}
+
+static celix_status_t my_bundle_stop(my_bundle_activator_data_t *data, celix_bundle_context_t *ctx) {
+    printf("Goodbye world\n");
+    return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(my_bundle_activator_data_t, my_bundle_start, my_bundle_stop)
+```
+
+```CMake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+
+#With `make all`, `make celix-bundles` this bundle will be created at:
+#  ${CMAKE_CURRENT_BINARY_DIR}/my_bundle.zip.
+add_celix_bundle(my_bundle
+    VERSION 1.0.0 
+    SOURCES src/my_bundle_activator.c
+)
+
+#With `make all`, `make celix-containers` or `make my_container` this Celix container executable will be created at:
+# ${CMAKE_BINARY_DIR}/deploy/my_container/my_container
+add_celix_container(my_container
+    C
+    BUNDLES
+        Celix::shell
+        Celix::shell_tui
+        my_bundle
+)
+```
+
+### C++ Example
+```C++
+//src/MyBundleActivator.cc
+#include <iostream>
+#include "celix/BundleActivator.h"
+
+class MyBundleActivator {
+public:
+    explicit MyBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        std::cout << "Hello world from bundle with id " << ctx->getBundleId() << std::endl;
+    }
+
+    ~MyBundleActivator() noexcept {
+        std::cout << "Goodbye world" << std::endl;
+    }
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(MyBundleActivator)
+```
+
+```CMake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+
+#With `make all`, `make celix-bundles` this bundle will be created at:
+#  ${CMAKE_CURRENT_BINARY_DIR}/MyBundle.zip.
+add_celix_bundle(MyBundle
+    SOURCES src/MyBundleActivator.cc
+)
+
+#With `make all`, `make celix-containers` or `make MyContainer` this Celix container executable will be created at:
+# ${CMAKE_BINARY_DIR}/deploy/my_container/MyContainer
+add_celix_container(MyContainer
+    CXX
+    BUNDLES
+        Celix::ShellCxx
+        Celix::shell_tui
+        MyBundle
+)
+```
+
+## Interaction between bundles
+By design bundles cannot directly access the symbols of another bundle. Interaction between bundles must be done using
+Apache Celix services. This means that unless functionality is provided by means of an Apache Celix service, 
+bundle functionality is private to the bundle.
+In Apache Celix symbols are kept private by loading bundle libraries locally (`dlopen` with `RTLD_LOCAL`). 
+
+## Installing bundles
+Apache Celix bundles can be installed on the system with the Apache Celix CMake command `install_celix_bundle`.
+Bundles will be installed as zip files in the package (default the CMAKE_PROJECT_NAME) share directory 
+(e.g `/use/share/celix/bundles`).
+
+It is also possible to use Apache Celix bundles as CMake imported targets, but this requires a more complex 
+CMake installation setup.
+
+## Installing Celix CMake targets
+The `install_celix_targets` can be used to generate a CMake file with the imported Apache Celix Bundle CMake targets 
+and this is ideally coupled with a CMake config file so that the bundles are made available when 
+CMake's `find_package` is used.
+
+Example:
+```CMake
+#Project setup
+project(ExamplePackage C CXX)
+find_package(Celix REQUIRED)
+
+#Create bundles
+add_celix_bundle(ExampleBundleA ...)
+add_celix_bundle(ExampleBundleB ...)
+
+#Install bundle zips
+install_celix_bundle(ExampleBundleA EXPORT MyExport)
+install_celix_bundle(ExampleBundleB EXPORT MyExport)
+#install exported Celix CMake targets
+install_celix_targets(MyExport NAMESPACE ExamplePackage:: DESTINATION share/ExamplePackage/cmake FILE CelixTargets)
+
+#Install Package CMake configuration
+file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/ExamplePackageConfig.cmake CONTENT "
+  # relative install dir from lib/CMake/ExamplePackage.
+  get_filename_component(REL_INSTALL_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+  get_filename_component(REL_INSTALL_DIR "${REL_INSTALL_DIR}" PATH)
+  get_filename_component(REL_INSTALL_DIR "${REL_INSTALL_DIR}" PATH)
+  get_filename_component(REL_INSTALL_DIR "${REL_INSTALL_DIR}" PATH)
+  include(${REL_INSTALL_DIR}/share/celix/cmake/CelixTargets.cmake)
+")
+
+install(FILES
+  ${CMAKE_BINARY_DIR}/ExamplePackageConfig.cmake
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ExamplePackage)
+```
+
+Downstream Usage Example:
+```CMake 
+project(UsageExample C CXX)
+find_package(Celix REQUIRED)
+find_package(ExamplePackage REQUIRED)
+add_celix_container(test_container BUNDLES
+  Celix::shell
+  Celix::shell_tui
+  ExamplePackage::ExampleBundleA
+  ExamplePackage::ExampleBundleB
+)
+```
+
+See [Apache Celix CMake Commands](cmake_commands) for more detailed information.
+
+# The `celix::lb` shell command
+To interactively see the installed bundles the `celix::lb` shell command (list bundles) can be used.
+
+Examples of supported `lb` command lines are:
+ - `celix::lb` - Show an overview of the installed bundles with their bundle id, bundle state, bundle name and 
+   bundle group.
+ - `lb` - Same as `celix::lb` (as long as there is no colliding other `lb` commands). 
+ - `lb -s` - Same as `celix::lb` but instead of showing the bundle name the bundle symbolic name is printed.
+ - `lb -u` - Same as `celix::lb` but instead of showing the bundle name the bundle update location is printed.
diff --git a/source/docs/2.3.0/celix/documents/cmake_commands/README.md b/source/docs/2.3.0/celix/documents/cmake_commands/README.md
new file mode 100644
index 0000000..94bbf75
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/cmake_commands/README.md
@@ -0,0 +1,579 @@
+---
+title: CMake Commands
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Apache Celix - CMake Commands
+
+For Apache Celix several cmake command are added to be able to work with Apache Celix bundles and deployments.
+
+# Bundles
+
+## add_celix_bundle
+Add a Celix bundle to the project.  There are three variants:
+- With SOURCES the bundle will be created using a list of sources files as input for the bundle activator library.
+- With ACTIVATOR the bundle will be created using the library target or absolute path to existing library as activator library.
+- With the NO_ACTIVATOR option will create a bundle without a activator (i.e. a pure resource bundle).
+
+Optional arguments are:
+- NAME: The (human readable) name of the bundle. This will be used as Bundle-Name manifest entry. Default is the  <bundle_target_name>.
+- SYMBOLIC_NAME: The symbolic name of the bundle. This will be used as Bundle-SymbolicName manifest entry. Default is the <bundle_target_name>.
+- DESCRIPTION: The description of the bundle. This will be used as Bundle-Description manifest entry. Default this is empty.
+- GROUP: The group the bundle is part of. This will be used as Bundle-Group manifest entry. Default this is empty (no group).
+- VERSION: The bundle version. This will be used for the Bundle-Version manifest entry. In combination with SOURCES the version will also be used to set the activator library target property VERSION and SOVERSION.
+  For SOVERSION only the major part is used. Expected scheme is "<major>.<minor>.<path>". Default version is "0.0.0"
+- FILENAME: The filename of the bundle file, without extension. Default is <bundle_target_name>. Together with the BUILD_TYPE, this will result in a filename like "bundle_target_name_Debug.zip
+- PRIVATE_LIBRARIES: private libraries to be included in the bundle. Specified libraries are added to the "Private-Library" manifest statement and added in the root of the bundle. libraries can be cmake library targets or absolute paths to existing libraries.
+- HEADERS: Additional headers values that are appended to the bundle manifest.
+
+```CMake
+add_celix_bundle(<bundle_target_name>
+        SOURCES source1 source2 ...
+        [NAME bundle_name]
+        [SYMBOLIC_NAME bundle_symbolic_name]
+        [DESCRIPTION bundle_description]
+        [GROUP bundle_group]
+        [VERSION bundle_version]
+        [FILENAME bundle_filename]
+        [PRIVATE_LIBRARIES private_lib1 private_lib2 ...]
+        [HEADERS "header1: header1_value" "header2: header2_value" ...]
+)
+```
+
+```CMake
+add_celix_bundle(<bundle_target_name>
+        ACTIVATOR <activator_lib>
+        [NAME bundle_name]
+        [SYMBOLIC_NAME bundle_symbolic_name]
+        [DESCRIPTION bundle_description]
+        [GROUP bundle_group]
+        [VERSION bundle_version]
+        [FILENAME bundle_filename]
+        [PRIVATE_LIBRARIES private_lib1 private_lib2 ...]
+        [HEADERS "header1: header1_value" "header2: header2_value" ...]
+)
+```
+
+```CMake
+add_celix_bundle(<bundle_target_name>
+        NO_ACTIVATOR
+        [NAME bundle_name]
+        [SYMBOLIC_NAME bundle_symbolic_name]
+        [DESCRIPTION bundle_description]
+        [GROUP bundle_group]
+        [VERSION bundle_version]
+        [FILENAME bundle_filename]
+        [PRIVATE_LIBRARIES private_lib1 private_lib2 ...]
+        [HEADERS "header1: header1_value" "header2: header2_value" ...]
+)
+```
+
+## celix_bundle_private_libs
+Add libraries to a bundle. The libraries should be cmake library targets or an absolute path to an existing library.
+
+The libraries will be copied into the bundle zip and activator library will be linked (PRIVATE) against them.
+
+Apache Celix uses dlopen with RTLD_LOCAL to load the activator library in a bundle.
+It is important to note that dlopen will always load the activator library,
+but not always load the libraries the bundle activator library is linked against.
+If the activator library is linked against a library which is already loaded, the already loaded library will be used.
+More specifically dlopen will decide this based on the NEEDED header in the activator library
+and the SO_NAME headers of the already loaded libraries.
+
+For example installing in order:
+- Bundle A with a private library libfoo (SONAME=libfoo.so) and
+- Bundle B with a private library libfoo (SONAME=libfoo.so).
+  Will result in Bundle B also using libfoo loaded from the cache dir in Bundle A.
+
+This also applies if multiple Celix frameworks are created in the same process. For example installed in order:
+- Bundle A with a private library libfoo (SONAME=libfoo.so) in Celix Framework A and
+- The same Bundle A in Celix Framework B.
+  Will result in Bundle A from Framework B to use the libfoo loaded from the cache dir of Bundle A in framework A.
+ 
+Will result in BundleA from framework B to use the libfoo loaded in BundleA from framework A.
+
+```CMake
+celix_bundle_private_libs(<bundle_target>
+    lib1 lib2 ...
+)
+```
+
+## celix_bundle_files
+Add files to the target bundle. DESTINATION is relative to the bundle archive root.
+The rest of the command is conform file(COPY ...) cmake command.
+See cmake file(COPY ...) command for more info.
+
+Note with celix_bundle_files files are copied cmake generation time. 
+Updates are not copied !
+
+```CMake
+celix_bundle_files(<bundle_target>
+    files... DESTINATION <dir>
+    [FILE_PERMISSIONS permissions...]
+    [DIRECTORY_PERMISSIONS permissions...]
+    [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS]
+    [FILES_MATCHING]
+    [ [PATTERN <pattern> | REGEX <regex>]
+      [EXCLUDE] [PERMISSIONS permissions...] ] 
+    [...]
+)
+```
+
+
+## celix_bundle_headers
+Append the provided headers to the target bundle manifest.
+
+```CMake
+celix_bundle_headers(<bundle_target>
+    "header1: header1_value"
+    "header2: header2_value"
+    ...
+)
+```
+
+## celix_bundle_symbolic_name
+Set bundle symbolic name
+
+```CMake
+celix_bundle_symbolic_name(<bundle_target> symbolic_name)
+```
+
+## celix_bundle_name
+Set bundle name
+
+```CMake
+celix_bundle_name(<bundle_target> name)
+```
+
+## celix_bundle_version
+Set bundle version
+
+```CMake
+celix_bundle_version(<bundle_target> version)
+```
+
+## celix_bundle_description
+Set bundle description
+
+```CMake
+celix_bundle_description(<bundle_target> description)
+```
+
+## celix_bundle_group
+Set bundle group.
+
+```CMake  
+celix_bundle_group(<bundle_target> bundle group)
+```
+
+## celix_get_bundle_filename
+Get bundle filename from an (imported) bundle target taking into account the
+used CMAKE_BUILD_TYPE and available bundle configurations. 
+
+```CMake
+celix_get_bundle_filename(<bundle_target> VARIABLE_NAME)
+```
+
+Example: `celix_get_bundle_filename(Celix::shell SHELL_BUNDLE_FILENAME)` will result in `celix_shell.zip` for a `RelWithDebInfo` cmake build type and in `celix_shell-Debug.zip` for a `Debug` cmake build type (if the a debug bundle version exists). 
+
+## celix_get_bundle_file
+Get bundle file (absolute path to a bundle) from an (imported) bundle target taking into account the used CMAKE_BUILD_TYPE and available bundle configurations.
+
+```CMake
+celix_get_bundle_file(<bundle_target> VARIABLE_NAME)
+```
+
+Example: `celix_get_bundle_file(Celix::shell SHELL_BUNDLE_FILE)`
+
+## add_celix_bundle_dependencies
+Add bundles as dependencies to a cmake target, so that the bundle zip files will be created before the cmake target.
+
+```CMake
+add_celix_bundle_dependencies(<cmake_target>
+    bundles...
+)
+```
+
+## install_celix_bundle
+Install bundle when 'make install' is executed. 
+Bundles are installed at `<install-prefix>/share/<project_name>/bundles`.
+Headers are installed at `<install-prefix>/include/<project_name>/<bundle_name>`
+Resources are installed at `<install-prefix>/shared/<project_name>/<bundle_name>`
+
+Optional arguments:
+- EXPORT: Associates the installed bundle with a export_name. 
+  The export name can be used to generate a Celix Targets cmake file (see install_celix_bundle_targets)
+- PROJECT_NAME: The project name for installing. Default is the cmake project name.
+- BUNDLE_NAME: The bundle name used when installing headers/resources. Default is the bundle target name.
+- HEADERS: A list of headers to install for the bundle.
+- RESOURCES: A list of resources to install for the bundle.
+
+```CMake
+install_celix_bundle(<bundle_target>
+    [EXPORT] export_name
+    [PROJECT_NAME] project_name
+    [BUNDLE_NAME] bundle_name
+    [HEADERS header_file1 header_file2 ...]
+    [RESOURCES resource1 resource2 ...]
+)
+```
+
+## install_celix_targets
+Generate and install a Celix Targets cmake file which contains CMake commands to create imported targets for the bundles 
+install using the provided <export_name>. These imported CMake targets can be used in CMake projects using the installed
+bundles. 
+
+Optional Arguments:
+- FILE: The Celix Targets cmake filename to used, without the cmake extension. Default is <export_name>BundleTargets.
+- PROJECT_NAME: The project name to used for the share location. Default is the cmake project name.
+- DESTINATION: The (relative) location to install the Celix Targets cmake file to. Default is share/<PROJECT_NAME>/cmake.
+
+```CMake
+install_celix_targets(<export_name>
+    NAMESPACE <namespace>
+    [FILE <celix_target_filename>]
+    [PROJECT_NAME <project_name>]
+    [DESTINATION <celix_targets_destination>]
+)
+```
+
+Example:
+```CMake
+install_celix_targets(celix NAMESPACE Celix:: DESTINATION share/celix/cmake FILE CelixTargets)
+```
+
+
+
+
+
+# Celix Containers
+The 'add_celix_container' Celix CMake command can be used to create Celix containers.
+Celix containers are executables preconfigured with configuration properties and bundles to run.    
+
+## add_celix_container
+Add a Celix container, consisting out of a selection of bundles and a Celix launcher.
+Celix containers can be used to run/test a selection of bundles in the celix framework.
+A Celix container will be build in `<cmake_build_dir>/deploy[/<group_name>]/<celix_container_name>`.
+Use the `<celix_container_name>` executable to run the containers.
+
+There are three variants of 'add_celix_container':
+- If no launcher is specified a custom Celix launcher will be generated. This launcher also contains the configured properties.
+- If a LAUNCHER_SRC is provided a Celix launcher will be build using the provided sources. Additional sources can be added with the
+  CMake 'target_sources' command.
+- If a LAUNCHER (absolute path to a executable of CMake `add_executable` target) is provided that will be used as Celix launcher.
+
+Creating a Celix containers using 'add_celix_container' will lead to a CMake executable target (expect if a LAUNCHER is used).
+These targets can be used to run/debug Celix containers from a IDE (if the IDE supports CMake).
+
+Optional Arguments:
+- COPY: With this option the used bundles are copied to the container build dir in the 'bundles' dir.
+  A additional result of this is that the configured references to the bundles are then relative instead of absolute.
+  Default is COPY
+- NO_COPY: With this option the used bundles configured for the container with absolute paths.
+  Default is COPY
+- CXX: With this option the generated Celix launcher (if used) will be a C++ source. (Default is CXX)
+  This ensures that the Celix launcher is linked against stdlibc++.
+  Default is CXX
+- C: With this option the generated Celix launcher (if used) will be a C source.
+  Default is CXX
+- USE_CONFIG: With this option config properties are generated in a 'config.properties' instead of embedded in the Celix launcher.
+- GROUP: If configured the build location will be prefixed the GROUP. Default is empty.
+- NAME: The name of the executable. Default is <celix_container_name>. Only useful for generated/LAUNCHER_SRC Celix launchers.
+- DIR: The base build directory of the Celix container. Default is `<cmake_build_dir>/deploy`.
+- BUNDLES: A list of bundles for the Celix container to install and start.
+  These bundle will be configured for run level 3. See 'celix_container_bundles' for more info.
+- INSTALL_BUNDLES: A list of bundles for the Celix container to install (but not start).
+- PROPERTIES: A list of configuration properties, these can be used to configure the Celix framework and/or bundles.
+  Normally this will be EMBEDED_PROPERTIES, but if the USE_CONFIG option is used this will be RUNTIME_PROPERTIES.
+  See the framework library or bundles documentation about the available configuration options.
+- EMBEDDED_PROPERTIES: A list of configuration properties which will be used in the generated Celix launcher.
+- RUNTIME_PROPERTIES: A list of configuration properties which will be used in the generated config.properties file.
+
+```CMake
+add_celix_container(<celix_container_name>
+    [COPY]
+    [NO_COPY]
+    [CXX]
+    [C]
+    [USE_CONFIG]
+    [GROUP group_name]
+    [NAME celix_container_name]
+    [DIR dir]
+    [BUNDLES <bundle1> <bundle2> ...]
+    [INSTALL_BUNDLES <bundle1> <bundle2> ...]
+    [PROPERTIES "prop1=val1" "prop2=val2" ...]
+    [EMBEDDED_PROPERTIES "prop1=val1" "prop2=val2" ...]
+    [RUNTIME_PROPERTIES "prop1=val1" "prop2=val2" ...]
+)
+```
+
+```CMake
+add_celix_container(<celix_container_name>
+    LAUNCHER launcher
+    [COPY]
+    [NO_COPY]
+    [CXX]
+    [C]
+    [USE_CONFIG]
+    [GROUP group_name]
+    [NAME celix_container_name]
+    [DIR dir]
+    [BUNDLES <bundle1> <bundle2> ...]
+    [INSTALL_BUNDLES <bundle1> <bundle2> ...]
+    [PROPERTIES "prop1=val1" "prop2=val2" ...]
+    [EMBEDDED_PROPERTIES "prop1=val1" "prop2=val2" ...]
+    [RUNTIME_PROPERTIES "prop1=val1" "prop2=val2" ...]
+)
+```
+
+```CMake
+add_celix_container(<celix_container_name>
+        LAUNCHER_SRC launcher_src
+        [COPY]
+        [NO_COPY]
+        [CXX]
+        [C]
+        [USE_CONFIG]
+        [GROUP group_name]
+        [NAME celix_container_name]
+        [DIR dir]
+        [BUNDLES <bundle1> <bundle2> ...]
+        [INSTALL_BUNDLES <bundle1> <bundle2> ...]
+        [PROPERTIES "prop1=val1" "prop2=val2" ...]
+        [EMBEDDED_PROPERTIES "prop1=val1" "prop2=val2" ...]
+        [RUNTIME_PROPERTIES "prop1=val1" "prop2=val2" ...]
+        )
+```
+
+## celix_container_bundles
+Add the selected bundles to the Celix container. These bundles are (if configured) copied to the container build dir and
+are added to the configuration properties so that they are installed and started when the Celix container executed.
+
+The Celix framework supports 7 (0 - 6) run levels. Run levels can be used to control the start and stop order of bundles.
+Bundles in run level 0 are started first and bundles in run level 6 are started last.
+When stopping bundles in run level 6 are stopped first and bundles in run level 0 are stopped last.
+Within a run level the order of configured decides the start order; bundles added earlier are started first.
+
+
+Optional Arguments:
+- LEVEL: The run level for the added bundles. Default is 3.
+- INSTALL: If this option is present, the bundles will only be installed instead of the default install and start.
+  The bundles will be installed after all bundle in LEVEL 0..6 are installed and started.
+
+```CMake
+celix_container_bundles(<celix_container_target_name>
+    [LEVEL (0..6)]
+    [INSTALL]
+    bundle1
+    bundle2
+    ...
+)
+```
+
+## celix_container_properties
+Add the provided properties to the target Celix container config properties.
+If the USE_CONFIG option is used these configuration properties will be added to the 'config.properties' file else they
+will be added to the generated Celix launcher.
+
+```CMake
+celix_container_properties(<celix_container_target_name>
+    "prop1=val1"
+    "prop2=val2"
+    ...
+)
+```
+
+## celix_container_embedded_properties
+Add the provided properties to the target Celix container config properties.
+These properties will be embedded into the generated Celix launcher.
+
+```CMake
+celix_container_embedded_properties(<celix_container_target_name>
+    "prop1=val1" 
+    "prop2=val2" 
+    ...
+)
+```
+
+## celix_container_runtime_properties
+Add the provided properties to the target Celix container config properties.
+These properties will be added to the config.properties in the container build dir. 
+
+```CMake
+celix_container_runtime_properties(<celix_container_target_name>
+    "prop1=val1" 
+    "prop2=val2" 
+    ...
+)
+```
+
+
+
+
+
+
+
+
+
+# Celix Docker Images
+The `add_celix_docker` Apache Celix CMake command can be used to create Apache Celix docker directories.
+These directories can be used (with 'docker build' or podman) to create very small Apache Celix docker images.
+
+## add_celix_docker
+Adds a docker target dir, containing a all the required executables,
+libraries, filesystem files and selected bundles needed to run a Apache Celix framework in a docker container.
+
+The 'add_celix_docker' target is a executable target and can be used to link libraries which are needed in the docker image.
+
+The docker dir can be found in `<cmake_build_dir>/docker[/<group_name>]/<docker_name>`.
+
+The docker directories are build with the target `celix-build-docker-dirs`, this does not create the
+docker images and can also be executed on systems without docker. The `celix-build-docker-dirs` is trigger
+with `make all`.
+
+The docker images are build with the target `celix-build-docker-images`. For this to work docker needs te installed
+and the user executing the `celix-build-docker-images` should have right to create docker images.
+The `celix-build-docker-images` is not triggered with `make all`
+
+There are three variants of 'add_celix_docker':
+- If no launcher is specified a custom Celix launcher will be generated. This launcher also contains the configured properties.
+- If a LAUNCHER_SRC is provided a Celix launcher will be build using the provided sources. Additional sources can be added with the
+  CMake 'target_sources' command.
+- If a LAUNCHER (absolute path to a executable of CMake `add_executable` target) is provided that will be used as Celix launcher.
+
+Optional arguments:
+- CXX: With this option the generated Celix launcher (if used) will be a C++ source instead of a C source.
+  A additional result of this is that Celix launcher is also linked against stdlibc++.
+- GROUP: If configured the build location will be prefixed the GROUP. Default is empty.
+- NAME: The name of the executable. Default is <docker_target_name>. Only useful for generated/LAUNCHER_SRC Celix launchers.
+- FROM: Configured the docker image base. Default is scratch.
+  If configured a minimal filesystem will not be created!
+- BUNDLES_DIR: Configures the directory where are all the bundles are copied. Default is /bundles.
+- WORKDIR: Configures the workdir of the docker image. Default is /root.
+- IMAGE_NAME: Configure the image name. Default is NAME.
+- BUNDLES: Configures the used bundles. These bundles are configured for run level 3. see 'celix_docker_bundles' for more info.
+- PROPERTIES: Configure configuration properties.
+- INSTRUCTIONS: Additional dockker instruction to add the the generated Dockerfile.
+
+```CMake
+add_celix_docker(<docker_target_name>
+    [CXX]
+    [GROUP group_name]
+    [NAME deploy_name]
+    [FROM docker_from_image]
+    [BUNDLES_DIR bundle_dir_in_docker_image]
+    [WORKDIR workdir_in_docker_image]
+    [IMAGE_NAME docker_image_name]
+    [BUNDLES <bundle1> <bundle2> ...]
+    [PROPERTIES "prop1=val1" "prop2=val2" ...]
+    [INSTRUCTIONS "instr1" "instr2" ...]
+)
+```
+
+```CMake
+add_celix_docker(<docker_target_name>
+    LAUNCHER_SRC launcher_src
+    [CXX]
+    [GROUP group_name]
+    [NAME deploy_name]
+    [FROM docker_from_image]
+    [BUNDLES_DIR bundle_dir_in_docker_image]
+    [WORKDIR workdir_in_docker_image]
+    [IMAGE_NAME docker_image_name]
+    [BUNDLES <bundle1> <bundle2> ...]
+    [PROPERTIES "prop1=val1" "prop2=val2" ...]
+    [INSTRUCTIONS "instr1" "instr2" ...]
+)
+```
+
+```CMake
+add_celix_docker(<docker_target_name>
+    LAUNCHER launcher
+    [CXX]
+    [GROUP group_name]
+    [NAME deploy_name]
+    [FROM docker_from_image]
+    [BUNDLES_DIR bundle_dir_in_docker_image]
+    [WORKDIR workdir_in_docker_image]
+    [IMAGE_NAME docker_image_name]
+    [BUNDLES <bundle1> <bundle2> ...]
+    [PROPERTIES "prop1=val1" "prop2=val2" ...]
+    [INSTRUCTIONS "instr1" "instr2" ...]
+)
+```
+
+## celix_docker_bundles
+Add the selected bundles to the Celix docker image. These bundles are copied to the docker build dir and
+are added to the configuration properties so that they are installed and started when the Celix docker container is created and started.
+
+The Celix framework support 7 (0 - 6) run levels. Run levels can be used to control the start and stop order of bundles.
+Bundles in run level 0 are started first and bundles in run level 6 are started last.
+When stopping bundles in run level 6 are stopped first and bundles in run level 0 are stopped last.
+Within a run level the order of configured decides the start order; bundles added earlier are started first.
+
+
+Optional Arguments:
+- LEVEL: The run level for the added bundles. Default is 3.
+
+```CMake
+celix_docker_bundles(<celix_container_target_name>
+    [LEVEL (0..5)]
+    bundle1
+    bundle2
+    ...
+)
+```
+
+## celix_docker_properties
+Same as `celix_container_properties`, but then for the celix container
+in the docker image.
+
+```CMake
+celix_docker_properties(<docker_target_name>
+    "prop1=val1"
+    "prop2=val2"
+    ...
+)
+```
+
+## celix_docker_embedded_properties
+Same as `celix_container_embedded_properties`, but then for the celix container
+in the docker image.
+
+```CMake
+celix_docker_embedded_properties(<docker_target_name>
+    "prop1=val1"
+    "prop2=val2"
+    ...
+)
+```
+
+## celix_docker_instructions
+Add the provided docker instruction to the end of the generated
+Dockerfile.
+
+```CMake
+celix_docker_instructions(<docker_target_name>
+    "instruction1"
+    "instruction2"
+    ...
+)
+```
diff --git a/source/docs/2.3.0/celix/documents/components.md b/source/docs/2.3.0/celix/documents/components.md
new file mode 100644
index 0000000..534b21d
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/components.md
@@ -0,0 +1,708 @@
+---
+title: Apache Celix Components
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Apache Celix Components
+In Apache Celix, components are plain old C/C++ objects (POCOs) managed by the Apache Celix Dependency Manager (DM).
+Components can provide services and depend on services. Components are configured declarative using the DM api.
+
+Service dependencies will influence the component's lifecycle as a component will only be active when all required
+dependencies are available.   
+The DM is responsible for managing the component's service dependencies, the component's lifecycle and when
+to register/unregister the component's provided services.
+
+Note that the Apache Celix Dependency Manager is inspired by the 
+[Apache Felix Dependency Manager](http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager.html), 
+adapted to Apache Celix and the C/C++ usage.
+
+# Component Lifecycle
+Each component has its own lifecycle.
+A component's lifecycle state model is depicted in the state diagram below.
+
+![Component Life Cycle](diagrams/component_lifecycle.png)
+
+The DM can be used to configure a component's lifecycle callbacks, the following component's lifecycle callbacks can
+be configured:
+
+- `init`
+- `start`
+- `stop`
+- `deinit`
+
+These callbacks are used in the intermediate component's lifecycle states `Initializing`, `Starting`, `Suspending`, `Resuming`, `Stopping` and `Deinitializing` and the lifecycle callbacks are always called from the Celix event thread.
+
+A component has the following lifecycle states:
+- `Inactive`: The component is inactive and the DM is not managing the component yet.
+- `Waiting For Required`: The component is waiting for required service dependencies.
+- `Initializing`: The component has found its required dependencies and is initializing by
+  calling the `init` callback.
+- `Initialized And Waiting For Required`: The component has been initialized, but is waiting for required
+  dependencies.
+  _Note: that this can mean that:
+    - During the `init` callback, 1 or more unavailable required service dependencies where added.
+    - The component was active, but 1 or more required service dependency where removed and as result the
+      component is not active anymore.
+- `Starting`: The component has found its required dependencies and is starting by calling the `start` callback and
+  registering the components provided services.
+- `Tracking Optional`: The component has found its required dependencies and is started. It is still tracking for
+  additional optional and required services.
+- `Suspending`: The component has found its required dependencies, but is suspending to prepare for a service change by
+  unregistering the components provided service and calling the `stop` callback.
+- `Suspended`: The component has found its required dependencies and is suspended so that a service change can be
+  processed.
+- `Resuming`: The component has found its required dependencies, a service change has been processed, and it is
+  resuming by calling the `start` callback and registering the components provided services.
+- `Stopping`: The component has lost one or more of its required dependencies and is stopping by unregistering the
+  components provided service and calling the `stop` callback.
+- `Deinitializing`: The component is being removed and is deinitializing by calling the `deinit` callback.
+
+## Component API
+
+The DM Component C api can be found in the `celix_dm_component.h` header and the C++ api can be found in the
+`celix/dm/Component.h` header.
+
+## Example: Create and configure component's lifecycle callbacks in C
+The following example shows how a simple component can be created and managed with the DM in C.
+Because the component's lifecycle is managed by the DM, this also means that if configured correctly no additional
+code is needed to remove and destroy the DM component and its implementation.
+
+Remarks for the C example:
+1. Although this is a C component. The simple component functions have been design for a component approach,
+   using the component pointer as first argument.
+2. The component implementation can be any POCO, as long as its lifecycle and destroy function signature follow a
+   component approach: A single argument, with as type the component implementation pointer and an int return
+   for the component lifecycle functions and a void return for the component destroy function.
+3. Creates the DM component, but note that the DM component is not yet known to the DM. This makes it possible to
+   first configure the DM component over multiple function calls, before adding it to the DM.
+4. Configures the component implementation in the DM component, so that the implementation pointer can be used
+   in the configured component callbacks.
+5. Configures the component lifecycle callbacks to the DM Component. These callbacks should accept the component
+   implementation as its only argument. The `CELIX_DM_COMPONENT_SET_CALLBACKS` marco is used instead of the
+   `celix_dmComponent_setCallbacks` function so that the component implementation type can directly be used
+   in the lifecycle callbacks (instead of `void*`).
+6. Configures the component destroy implementation callback to the Dm Component. This callback will be called when
+   the DM component is removed from the DM and has become inactive. The callback will be called from the Celix event
+   thread. The advantages of configuring this callback is that the DM manages when the callback needs to be called;
+   this removes some complexity for the users. The `CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION` marco
+   is used instead of the `celix_dmComponent_setImplementationDestroyFunction` function so that the component
+   implementation type can be directly used in the callback (instead of `void*`).
+7. Adds the DM Component the DM and as result the DM will that point on manage the components' lifecycle, service
+   dependencies and provided services.
+8. No additional code is needed to clean up components and as such no activator stop callback function needs to be
+   configured. The generated bundle activator will ensure that all components are removed from the DM when the
+   bundle is stopped and the DM will ensure that the components are deactivated and destroyed correctly.
+
+```C
+//src/simple_component_activator.c
+#include <stdio.h>
+#include <celix_api.h>
+
+//********************* COMPONENT *******************************/
+
+typedef struct simple_component {
+    int transitionCount; //not protected, only updated and read in the celix event thread.
+} simple_component_t;
+
+static simple_component_t* simpleComponent_create() {
+    simple_component_t* cmp = calloc(1, sizeof(*cmp));
+    cmp->transitionCount = 1;
+    return cmp;
+}
+
+static void simpleComponent_destroy(simple_component_t* cmp) {
+    free(cmp);
+}
+
+static int simpleComponent_init(simple_component_t* cmp) { // <------------------------------------------------------<1>
+    printf("Initializing simple component. Transition nr %i\n", cmp->transitionCount++);
+    return 0;
+}
+
+static int simpleComponent_start(simple_component_t* cmp) {
+    printf("Starting simple component. Transition nr %i\n", cmp->transitionCount++);
+    return 0;
+}
+
+static int simpleComponent_stop(simple_component_t* cmp) {
+    printf("Stopping simple component. Transition nr %i\n", cmp->transitionCount++);
+    return 0;
+}
+
+static int simpleComponent_deinit(simple_component_t* cmp) {
+    printf("De-initializing simple component. Transition nr %i\n", cmp->transitionCount++);
+    return 0;
+}
+
+
+//********************* ACTIVATOR *******************************/
+
+typedef struct simple_component_activator {
+    //nop
+} simple_component_activator_t;
+
+static celix_status_t simpleComponentActivator_start(simple_component_activator_t *act, celix_bundle_context_t *ctx) {
+    //creating component
+    simple_component_t* impl = simpleComponent_create(); // <--------------------------------------------------------<2>
+
+    //create and configuring component and its lifecycle callbacks using the Apache Celix Dependency Manager
+    celix_dm_component_t* dmCmp = celix_dmComponent_create(ctx, "simple_component_1"); // <--------------------------<3>
+    celix_dmComponent_setImplementation(dmCmp, impl); // <-----------------------------------------------------------<4>
+    CELIX_DM_COMPONENT_SET_CALLBACKS(
+            dmCmp,
+            simple_component_t,
+            simpleComponent_init,
+            simpleComponent_start,
+            simpleComponent_stop,
+            simpleComponent_deinit); // <----------------------------------------------------------------------------<5>
+    CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION(
+            dmCmp,
+            simple_component_t,
+            simpleComponent_destroy); // <---------------------------------------------------------------------------<6>
+
+    //Add dm component to the dm.
+    celix_dependency_manager_t* dm = celix_bundleContext_getDependencyManager(ctx);
+    celix_dependencyManager_add(dm, dmCmp); // <---------------------------------------------------------------------<7>
+    return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(simple_component_activator_t, simpleComponentActivator_start, NULL) // <------------------<8>
+```
+
+## Example: Create and configure component's lifecycle callbacks in C++
+The following example shows how a simple component can be created and managed with the DM in C++.
+For C++ the DM will manage the component and also ensures that component implementation is kept in scope for as
+long as the component is managed by the DM.
+
+Remarks for the C++ example:
+1. For C++ the DM can directly work on classes and as result lifecycle callback can be class methods.
+2. Creates a component implementation using a unique_ptr.
+3. Create a C++ DM Component and directly add it to the DM. For C++ DM Component needs to be "build" first, before the
+   DM will manage them. This way C++ components can be build using a fluent api and marked complete with a `build()`
+   method call.
+   For a component implementation the DM accepts a unique_ptr, a shared_ptr, a value type or no implementation. If no
+   implementation is provided the DM will create a component implementation using the template argument and
+   assuming a default constructor (e.g. `ctx->getDependencyManager()->createComponent<CmpWithDefaultCTOR>()`).
+4. Configures the component lifecycle callbacks as class methods. The DM will call these callbacks using the
+   component implementation raw pointer as object instance (`this`).
+5. "Builds" the component. C++ components will only be managed by the DM after they are build. This makes it possible
+   to configure a component over multiple method calls before marking the component complete (build).
+   The generated C++ bundle activator will also enable all components created during the bundle activation, this is
+   done to ensure that the build behaviour is backwards compatible with previous released DM implementation.
+   It is preferred that users explicitly build their components when they are completely configured.
+
+```C++
+//src/SimpleComponentActivator.cc
+#include <celix/BundleActivator.h>
+
+class SimpleComponent {
+public:
+    void init() { // <-----------------------------------------------------------------------------------------------<1>
+        std::cout << "Initializing simple component. Transition nr " << transitionCount++ << std::endl;
+    }
+
+    void start() {
+        std::cout << "starting simple component. Transition nr " << transitionCount++ << std::endl;
+    }
+
+    void stop() {
+        std::cout << "Stopping simple component. Transition nr " << transitionCount++ << std::endl;
+    }
+
+    void deinit() {
+        std::cout << "De-initializing simple component. Transition nr " << transitionCount++ << std::endl;
+    }
+private:
+    int transitionCount = 1; //not protected, only updated and read in the celix event thread.
+};
+
+class SimpleComponentActivator {
+public:
+    explicit SimpleComponentActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        auto cmp = std::make_unique<SimpleComponent>(); // <---------------------------------------------------------<2>
+        ctx->getDependencyManager()->createComponent(std::move(cmp), "SimpleComponent1") // <------------------------<3>
+                .setCallbacks(
+                        &SimpleComponent::init,
+                        &SimpleComponent::start,
+                        &SimpleComponent::stop,
+                        &SimpleComponent::deinit) // <---------------------------------------------------------------<4>
+                .build(); // <---------------------------------------------------------------------------------------<5>
+    }
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(SimpleComponentActivator)
+```
+
+# Component's Provided Services
+Components can be configured to provide services. These provided services will result in service registrations
+when a component is `Starting` or `Resuming` (i.e. when a component goes to the `Tracking Optional` state).
+
+If a component provide services, these services will have an additional automatically added service property - named "component.uuid" - next to its configured provided service properties. The "component.uuid" service property can be
+used to identify if a service is provided by a component and which component.
+
+## Example: Component with a provided service in C
+The following example shows how a component that provide a `celix_shell_command` service.
+
+Remarks for the C example:
+1. C services do not support inheritance. So even if a C component provides a certain service, it is not an
+   instance of said service. This also means the C service struct provided by a component needs to be stored
+   separately. In this example this is done storing the service struct in the bundle activator data. Note
+   that the bundle activator data "outlives" the component, because all components are removed before a bundle
+   is completely stopped.
+2. Configures a provided service (interface) for the component. The service will not directly be registered, but
+   instead will be registered in the component states `Starting` and `Resuming`.
+
+```C
+ //src/component_with_provided_service_activator.c
+#include <stdlib.h>
+#include <celix_api.h>
+#include <celix_shell_command.h>
+
+//********************* COMPONENT *******************************/
+
+typedef struct component_with_provided_service {
+    int callCount; //atomic
+} component_with_provided_service_t;
+
+static component_with_provided_service_t* componentWithProvidedService_create() {
+    component_with_provided_service_t* cmp = calloc(1, sizeof(*cmp));
+    return cmp;
+}
+
+static void componentWithProvidedService_destroy(component_with_provided_service_t* cmp) {
+    free(cmp);
+}
+
+static bool componentWithProvidedService_executeCommand(
+        component_with_provided_service_t *cmp,
+        const char *commandLine,
+        FILE *outStream,
+        FILE *errorStream __attribute__((unused))) {
+    int count = __atomic_add_fetch(&cmp->callCount, 1, __ATOMIC_SEQ_CST);
+    fprintf(outStream, "Hello from cmp. command called %i times. commandLine: %s\n", count, commandLine);
+    return true;
+}
+
+//********************* ACTIVATOR *******************************/
+
+typedef struct component_with_provided_service_activator {
+    celix_shell_command_t shellCmd; // <-----------------------------------------------------------------------------<1>
+} component_with_provided_service_activator_t;
+
+static celix_status_t componentWithProvidedServiceActivator_start(component_with_provided_service_activator_t *act, celix_bundle_context_t *ctx) {
+    //creating component
+    component_with_provided_service_t* impl = componentWithProvidedService_create();
+
+    //create and configuring component and its lifecycle callbacks using the Apache Celix Dependency Manager
+    celix_dm_component_t* dmCmp = celix_dmComponent_create(ctx, "component_with_provided_service_1");
+    celix_dmComponent_setImplementation(dmCmp, impl);
+    CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION(
+            dmCmp,
+            component_with_provided_service_t,
+            componentWithProvidedService_destroy);
+
+    //configure provided service
+    act->shellCmd.handle = impl;
+    act->shellCmd.executeCommand = (void*)componentWithProvidedService_executeCommand;
+    celix_properties_t* props = celix_properties_create();
+    celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "hello_component");
+    celix_dmComponent_addInterface(
+            dmCmp,
+            CELIX_SHELL_COMMAND_SERVICE_NAME,
+            CELIX_SHELL_COMMAND_SERVICE_VERSION,
+            &act->shellCmd,
+            props); // <---------------------------------------------------------------------------------------------<2>
+
+
+    //Add dm component to the dm.
+    celix_dependency_manager_t* dm = celix_bundleContext_getDependencyManager(ctx);
+    celix_dependencyManager_add(dm, dmCmp);
+    return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(
+        component_with_provided_service_activator_t,
+        componentWithProvidedServiceActivator_start,
+        NULL)
+```
+
+## Example: Component with a provided service in C++
+The following example shows how a C++ component that provide a C++ `celix::IShellCommand` service
+and a C `celix_shell_command` service. For a C++ component it's possible to provide C and C++ services.
+
+Remarks for the C++ example:
+1. If a component provides a C++ services, it also expected that the component implementation inherits the service
+   interface.
+2. The overridden `executeCommand` method of `celix::IShellCommand`.
+3. Methods of C service interfaces can be implemented as class methods, but the bundle activator should ensure that
+   the underlining C service interface structs are assigned with compatible C function pointers.
+4. Creating a component using only a template argument. The DM will construct - using a default constructor - a
+   component implementation instance.
+5. Configures the component to provide a C++ `celix::IShellCommand` service. Note that because the component
+   implementation is an instance of `celix::IShellCommand` no additional storage is needed. The service will not
+   directly be registered, but instead will be registered in the components states `Starting` and `Resuming`.
+6. Set the C `executeCommand` function pointer of the `celix_shell_command_t` service interface struct to a
+   capture-less lambda expression. The lambda expression is used to forward the call to the `executeCCommand`
+   class method. Note the capture-less lambda expression can decay to C-style function pointers.
+7. Configures the component to provide a C `celix_shell_command_t` service. Note that for a C service, the
+   `createUnassociatedProvidedService` must be used, because the component does not inherit `celix_shell_command_t`.
+   The service will not directly be registered, but instead will be registered in the component states `Starting` and
+   `Resuming`.
+8. "Build" the component so the DM will manage the component.
+
+
+```C++
+//src/ComponentWithProvidedServiceActivator.cc
+#include <celix/BundleActivator.h>
+#include <celix/IShellCommand.h>
+#include <celix_shell_command.h>
+
+class ComponentWithProvidedService : public celix::IShellCommand { // <----------------------------------------------<1>
+public:
+    ~ComponentWithProvidedService() noexcept override = default;
+
+    void executeCommand(
+            const std::string& commandLine,
+            const std::vector<std::string>& /*commandArgs*/,
+            FILE* outStream,
+            FILE* /*errorStream*/) override {
+        fprintf(outStream, "Hello from cmp. C++ command called %i times. commandLine is %s\n", 
+                cxxCallCount++, commandLine.c_str());
+    } // <-----------------------------------------------------------------------------------------------------------<2>
+
+    void executeCCommand(const char* commandLine, FILE* outStream) {
+        fprintf(outStream, "Hello from cmp. C command called %i times. commandLine is %s\n", cCallCount++, commandLine);
+    } // <-----------------------------------------------------------------------------------------------------------<3>
+private:
+    std::atomic<int> cxxCallCount{1};
+    std::atomic<int> cCallCount{1};
+};
+
+class ComponentWithProvidedServiceActivator {
+public:
+    explicit ComponentWithProvidedServiceActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        auto& cmp = ctx->getDependencyManager()->createComponent<ComponentWithProvidedService>(); // <---------------<4>
+
+        cmp.createProvidedService<celix::IShellCommand>()
+                .addProperty(celix::IShellCommand::COMMAND_NAME, "HelloComponent"); // <-----------------------------<5>
+
+        auto shellCmd = std::make_shared<celix_shell_command_t>();
+        shellCmd->handle = static_cast<void*>(&cmp.getInstance());
+        shellCmd->executeCommand = [](void* handle, const char* commandLine, FILE* outStream, FILE*) -> bool {
+            auto* impl = static_cast<ComponentWithProvidedService*>(handle);
+            impl->executeCCommand(commandLine, outStream);
+            return true;
+        }; // <------------------------------------------------------------------------------------------------------<6>
+
+        cmp.createUnassociatedProvidedService(std::move(shell.html), CELIX_SHELL_COMMAND_SERVICE_NAME)
+                .addProperty(CELIX_SHELL_COMMAND_NAME, "hello_component"); // < -------------------------------------<7>
+
+        cmp.build(); // <--------------------------------------------------------------------------------------------<8>
+    }
+private:
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(ComponentWithProvidedServiceActivator)
+```
+
+# Component's Service Dependencies
+Components can be configured to have service dependencies. These service dependencies will influence the component's
+lifecycle. Components can have optional and required service dependencies. When service dependencies are required the
+component can only be active if all required dependencies are available; where available means at least 1 matching
+service dependency is found.
+
+When configuring service dependencies, callbacks can be configured for handling services that are being added,
+removed or for when a new highest ranking service is available.
+
+Service dependency callbacks can be configured with 3 different types of argument signatures:
+- A single argument for the service pointer (raw pointer or shared_ptr);
+- A service pointer (raw pointer or shared_ptr) as first argument and the service properties as second argument.
+- A service pointer (raw pointer or shared_ptr) as first argument, the service properties as second argument and
+  the bundle providing the service as third argument.
+
+Service dependency callbacks will always be called from the Celix event thread.
+
+A service change (injection/removal) can be handled by the component using a Locking-strategy or a suspend-strategy.
+This strategy can be configured per service dependency and expect the following behaviour from the component
+implementation:
+- Locking-strategy: The component implementation must ensure that the stored service pointers (and if applicable the
+  service properties and its bundle) are protected using a locking mechanism (e.g. a mutex).
+  This should ensure that services are no longer in use after they are removed (or replaced) from a component and
+  thus can be safely deleted from memory.
+- Suspend-strategy: The DM will ensure that before service dependency callbacks are called, all provided services
+  are (temporary) unregistered and the component is suspended (using the components' `stop` callback). This should mean
+  that there are no active users - through the provided services or active threads - of the service dependencies
+  anymore and that service changes can safely be handling without locking. The component implementation must ensure
+  that after a `stop` callback there are no active threads, thread pools, timers, etc - that use service dependencies -
+  are active anymore.
+
+## Example: Component with a service dependencies in C
+The following example shows how a C component that has two service dependency on the `celix_shell_command_t` service.
+
+One service dependency is a required dependency with a suspend-strategy and uses a `set ` callback which ensure
+that a single service is injected and that is always the highest ranking service. Note that the highest ranking
+service can be `NULL` if there are no other matching services.
+
+The other dependency is an optional dependency with a locking-strategy and uses a `addWithProps` and
+`removeWithProps` callback. These callbacks will be called for every `celix_shell_command_t` service being added/removed
+and will be called with not only the service pointer, but also the service properties.
+
+Remarks for the C example:
+1. Creates a mutex to protect the `cmdShells` field which is configured with a locking-strategy service dependency.
+2. Updates the `highestRankingCmdShell` field without locking. Note that because the service dependency is
+   configured with a suspend-strategy the `componentWithServiceDependency_setHighestRankingShellCommand` function
+   will only be called when the component is in the `Suspended` state or when it is not in the `Active` compound state.
+3. Locks the mutex and adds the newly added service to the `cmdShells` list. Note that because the service dependency
+   is configured with a locking-strategy the `componentWithServiceDependency_addShellCommand` and
+   `componentWithServiceDependency_removeShellCommand` functions can be called from any component lifecycle state.
+4. Creates a new DM service dependency object. Note that the DM service dependency is not yet known to the DM Component.
+5. Configures for which service name the service dependency will track services for. Optionally it is also possible
+   to fine tune the tracked service by providing a service version range and/or service filter.
+6. Configures the update strategy for the service dependency to suspend-strategy.
+7. Configures the service dependency as a required service dependency.
+8. Creates an empty service dependency callback options struct. This struct can be used to configure different
+   service dependency callbacks.
+9. Configures the `set` service dependency callback to `componentWithServiceDependency_setHighestRankingShellCommand`
+10. Configures the dependency manager to use the callbacks configures in opts.
+11. Adds the DM service dependency object to the DM component object.
+12. Configures the update strategy for the service dependency to locking-strategy.
+13. Configures the service dependency as an optional service dependency.
+14. Configures the `addWithProps` service dependency callback to `componentWithServiceDependency_addShellCommand`.
+
+```C
+//src/component_with_service_dependency_activator.c
+#include <stdlib.h>
+#include <celix_api.h>
+#include <celix_shell_command.h>
+
+//********************* COMPONENT *******************************/
+
+typedef struct component_with_service_dependency {
+    celix_shell_command_t* highestRankingCmdShell; //only updated when component is not active or suspended
+    celix_thread_mutex_t mutex; //protects cmdShells
+    celix_array_list_t* cmdShells;
+} component_with_service_dependency_t;
+
+static component_with_service_dependency_t* componentWithServiceDependency_create() {
+    component_with_service_dependency_t* cmp = calloc(1, sizeof(*cmp));
+    celixThreadMutex_create(&cmp->mutex, NULL); // <-----------------------------------------------------------------<1>
+    cmp->cmdShells = celix_arrayList_create();
+    return cmp;
+}
+
+static void componentWithServiceDependency_destroy(component_with_service_dependency_t* cmp) {
+    celix_arrayList_destroy(cmp->cmdShells);
+    celixThreadMutex_destroy(&cmp->mutex);
+    free(cmp);
+}
+
+static void componentWithServiceDependency_setHighestRankingShellCommand(
+        component_with_service_dependency_t* cmp,
+        celix_shell_command_t* shell.html) {
+    printf("New highest ranking service (can be NULL): %p\n", shell.html);
+    cmp->highestRankingCmdShell = shellCmd; // <---------------------------------------------------------------------<2>
+}
+
+static void componentWithServiceDependency_addShellCommand(
+        component_with_service_dependency_t* cmp,
+        celix_shell_command_t* shellCmd,
+        const celix_properties_t* props) {
+    long id = celix_properties_getAsLong(props, CELIX_FRAMEWORK_SERVICE_ID, -1);
+    printf("Adding shell command service with service.id %li\n", id);
+    celixThreadMutex_lock(&cmp->mutex); // <-------------------------------------------------------------------------<3>
+    celix_arrayList_add(cmp->cmdShells, shell.html);
+    celixThreadMutex_unlock(&cmp->mutex);
+}
+
+static void componentWithServiceDependency_removeShellCommand(
+        component_with_service_dependency_t* cmp,
+        celix_shell_command_t* shellCmd,
+        const celix_properties_t* props) {
+    long id = celix_properties_getAsLong(props, CELIX_FRAMEWORK_SERVICE_ID, -1);
+    printf("Removing shell command service with service.id %li\n", id);
+    celixThreadMutex_lock(&cmp->mutex);
+    celix_arrayList_remove(cmp->cmdShells, shell.html);
+    celixThreadMutex_unlock(&cmp->mutex);
+}
+
+//********************* ACTIVATOR *******************************/
+
+typedef struct component_with_service_dependency_activator {
+    //nop
+} component_with_service_dependency_activator_t;
+
+static celix_status_t componentWithServiceDependencyActivator_start(component_with_service_dependency_activator_t *act, celix_bundle_context_t *ctx) {
+    //creating component
+    component_with_service_dependency_t* impl = componentWithServiceDependency_create();
+
+    //create and configuring component and its lifecycle callbacks using the Apache Celix Dependency Manager
+    celix_dm_component_t* dmCmp = celix_dmComponent_create(ctx, "component_with_service_dependency_1");
+    celix_dmComponent_setImplementation(dmCmp, impl);
+    CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION(
+            dmCmp,
+            component_with_service_dependency_t,
+            componentWithServiceDependency_destroy);
+
+    //create mandatory service dependency with cardinality one and with a suspend-strategy
+    celix_dm_service_dependency_t* dep1 = celix_dmServiceDependency_create(); // <-----------------------------------<4>
+    celix_dmServiceDependency_setService(dep1, CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL); // <-------------------<5>
+    celix_dmServiceDependency_setStrategy(dep1, DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND); // <------------------------<6>
+    celix_dmServiceDependency_setRequired(dep1, true); // <----------------------------------------------------------<7>
+    celix_dm_service_dependency_callback_options_t opts1 = CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; // <--<8>
+    opts1.set = (void*)componentWithServiceDependency_setHighestRankingShellCommand; // <----------------------------<9>
+    celix_dmServiceDependency_setCallbacksWithOptions(dep1, &opts1); // <-------------------------------------------<10>
+    celix_dmComponent_addServiceDependency(dmCmp, dep1); // <-------------------------------------------------------<11>
+
+    //create optional service dependency with cardinality many and with a locking-strategy
+    celix_dm_service_dependency_t* dep2 = celix_dmServiceDependency_create();
+    celix_dmServiceDependency_setService(dep2, CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL);
+    celix_dmServiceDependency_setStrategy(dep2, DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING);  // <----------------------<12>
+    celix_dmServiceDependency_setRequired(dep2, false); // <--------------------------------------------------------<13>
+    celix_dm_service_dependency_callback_options_t opts2 = CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS;
+    opts2.addWithProps = (void*)componentWithServiceDependency_addShellCommand;  // <-------------------------------<14>
+    opts2.removeWithProps = (void*)componentWithServiceDependency_removeShellCommand;
+    celix_dmServiceDependency_setCallbacksWithOptions(dep2, &opts2);
+    celix_dmComponent_addServiceDependency(dmCmp, dep2);
+
+    //Add dm component to the dm.
+    celix_dependency_manager_t* dm = celix_bundleContext_getDependencyManager(ctx);
+    celix_dependencyManager_add(dm, dmCmp);
+    return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(
+        component_with_service_dependency_activator_t,
+        componentWithServiceDependencyActivator_start,
+        NULL)
+```
+
+## Example: Component with a service dependencies in C++
+The following example shows how a C++ component that has two service dependency. One
+service dependency for the C++ `celix::IShellCommand` service and one for the C `celix_shell_command_t` service.
+
+The `celix::IShellCommand` service dependency is a required dependency with a suspend-strategy and uses a
+`set` callback which ensure that a single service is injected and that is always the highest ranking service.
+Note that the highest ranking service can be an empty shared_ptr if there are no service.
+
+The `celix_shell_command_t` service dependency is an optional dependency with a locking-strategy and uses a
+`addWithProperties` and `removeWithProperties` callback.
+These callbacks will be called for every `celix_shell_command_t` service being added/removed
+and will be called with not only the service shared_ptr, but also the service properties.
+
+Note that for C++ component service dependencies, there is no real different between a C++ or a C service dependency;
+In both cases the service pointers are injected using shared_ptr and if applicable the service properties and
+bundle argument are also provided as shared_ptr using the C++ `celix::Properties` and `celix::Bundle`.
+
+Remarks for the C++ example:
+1. Creates a mutex to protect the `shellCommands` field which is configured with a locking-strategy service dependency.
+2. Updates the `highestRankingShellCmd` field without locking. Note that because the service dependency is
+   configured with a suspend-strategy the `ComponentWithServiceDependency::setHighestRankingShellCommand` method
+   will only be called when the component is in the `Suspended` state or when it is not in the `Active` compound state.
+3. Locks the mutex and adds the newly added service to the `shellCommands` list. Note that because the service
+   dependency is configured with a locking-strategy the `ComponentWithServiceDependency::addCShellCmd` and
+   `ComponentWithServiceDependency::removeCShellCmd` methods can be called from any component lifecycle state.
+4. Creates a new DM service dependency object, the service dependency is considered incomplete until the
+   service dependency, component or DM is build. Note that the `celix::dm::Component::createServiceDependency` method
+   is called without provided a service name, the service name will be inferred using the `celix::typeName`.
+5. Configures the service dependency set callback.
+6. Configures the service dependency as a required service dependency.
+7. Configures the update strategy for the service dependency to suspend-strategy.
+8. Creates another new DM service dependency object and in this case also explicitly provides the service name
+   to use (`CELIX_SHELL_COMMAND_SERVICE_NAME`).
+9. Builds the component and as result also builds the components' service dependencies (i.e. marking them as complete).
+
+```C++
+//src/ComponentWithServiceDependencyActivator.cc
+#include <celix/BundleActivator.h>
+#include <celix/IShellCommand.h>
+#include <celix_shell_command.h>
+
+class ComponentWithServiceDependency {
+public:
+    void setHighestRankingShellCommand(const std::shared_ptr<celix::IShellCommand>& cmdSvc) {
+        std::cout << "New highest ranking service (can be NULL): " << (intptr_t)cmdSvc.get() << std::endl;
+        highestRankingShellCmd = cmdSvc; // <------------------------------------------------------------------------<2>
+    }
+
+    void addCShellCmd(
+            const std::shared_ptr<celix_shell_command_t>& cmdSvc,
+            const std::shared_ptr<const celix::Properties>& props) {
+        auto id = props->getAsLong(celix::SERVICE_ID, -1);
+        std::cout << "Adding shell command service with service.id: " << id << std::endl;
+        std::lock_guard lck{mutex}; // <-----------------------------------------------------------------------------<3>
+        shellCommands.emplace(id, cmdSvc);
+    }
+
+    void removeCShellCmd(
+            const std::shared_ptr<celix_shell_command_t>& /*cmdSvc*/,
+            const std::shared_ptr<const celix::Properties>& props) {
+        auto id = props->getAsLong(celix::SERVICE_ID, -1);
+        std::cout << "Removing shell command service with service.id: " << id << std::endl;
+        std::lock_guard lck{mutex};
+        shellCommands.erase(id);
+    }
+private:
+    std::shared_ptr<celix::IShellCommand> highestRankingShellCmd{};
+    std::mutex mutex{}; //protect shellCommands // <-----------------------------------------------------------------<1>
+    std::unordered_map<long, std::shared_ptr<celix_shell_command_t>> shellCommands{};
+};
+
+class ComponentWithServiceDependencyActivator {
+public:
+    explicit ComponentWithServiceDependencyActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        using Cmp = ComponentWithServiceDependency;
+        auto& cmp = ctx->getDependencyManager()->createComponent<Cmp>(); 
+
+        cmp.createServiceDependency<celix::IShellCommand>() // <-----------------------------------------------------<4>
+                .setCallbacks(&Cmp::setHighestRankingShellCommand) // <----------------------------------------------<5>
+                .setRequired(true) // <------------------------------------------------------------------------------<6>
+                .setStrategy(DependencyUpdateStrategy::suspend); // <------------------------------------------------<7>
+
+        cmp.createServiceDependency<celix_shell_command_t>(CELIX_SHELL_COMMAND_SERVICE_NAME) // <--------------------<8>
+                .setCallbacks(&Cmp::addCShellCmd, &Cmp::removeCShell.html) 
+                .setRequired(false)
+                .setStrategy(DependencyUpdateStrategy::locking);
+
+        cmp.build(); // <--------------------------------------------------------------------------------------------<9>
+    }
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(ComponentWithServiceDependencyActivator)
+```
+
+# When will a component be suspended
+Components will only suspend if:
+- The component is in the state `Tracking Optional`;
+- The component has at least 1 service dependency where the update strategy is configured as suspend-strategy;
+- There is a service update event ongoing, where the update service event matches 1 of the components'
+  suspend-strategy service dependencies;
+- And least one of the component's matching suspend-strategy service dependency has a configured service injection/
+  removal callback configured.
+
+# The `celix::dm` shell command
+To interactively see the available components, their current lifecycle state, provided service and service dependencies
+the `celix::dm` shell command can be used.
+
+Examples of supported `dm` command lines are:
+- `celix::dm` - Show an overview of all components in the Celix framework. Only shows component lifecycle state.
+- `dm` - Same as `celix::dm` (as long as there is no colliding other `dm` commands).
+- `dm full` - Show a detailed overview of all components in the Celix framework. This also shows the provided
+  services and service dependencies of each component.
\ No newline at end of file
diff --git a/source/docs/2.3.0/celix/documents/containers.md b/source/docs/2.3.0/celix/documents/containers.md
new file mode 100644
index 0000000..334705d
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/containers.md
@@ -0,0 +1,119 @@
+---
+title: Apache Celix Containers
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Apache Celix Containers
+Apache Celix containers are executables which starts an Apache Celix framework, with an embedded set of properties
+and an embedded set of bundles.
+Although it is also possible to create and start an Apache Celix framework in code, the benefit of an Apache Celix 
+Container is that this can be done with a single `add_celix_container` Apache Celix CMake command. 
+
+The `add_celix_container` Apache Celix CMake command eventually uses the CMake `add_executable` with the same 
+target name.  As result, it is possible to handle an Apache Celix Container as a normal CMake executable 
+(e.g. use `target_link_libraries`) and also ensures that the CLion IDE detects the containers as an executable.
+
+For a complete list of options the `add_celix_container` Apache Celix CMake command supports, see the 
+[Apache Celix CMake Commands documentation](cmake_commands)
+
+## Generated main source files
+The main purpose of the `add_celix_container` Apache Celix CMake command is to generate a main source file 
+which starts an Apache Celix framework with a set of preconfigured properties and set of preconfigured bundles.
+
+For example the following (empty) Apache Celix Container:
+```CMake
+add_celix_container(my_empty_container)
+```
+
+will create the following main source file (note: reformatted for display purpose):
+```C++
+//${CMAKE_BINARY_DIR}/celix/gen/containers/my_empty_container/main.cc
+#include <celix_launcher.h>
+int main(int argc, char *argv[]) {
+    const char * config = "\
+CELIX_CONTAINER_NAME=my_empty_container\n\
+CELIX_BUNDLES_PATH=bundles\n\
+";
+    celix_properties_t *embeddedProps = celix_properties_loadFromString(config);
+    return celixLauncher_launchAndWaitForShutdown(argc, argv, embeddedProps);
+}
+```
+
+Note that because the source file is a C++ source file (.cc extension) the executable will be compiled with a C++ 
+compiler. 
+
+To create C Apache Celix Containers, use the `C` option in the `add_celix_container` Apache Celix CMake command; 
+This will generate a `main.c` instead of `main.cc` source file:
+
+```CMake
+add_celix_container(my_empty_container C)
+```
+
+When an Apache Celix Container is also configured with framework properties and/or auto start of bundles, the
+generated main source file will add these properties as embedded framework properties.
+
+For example the following `add_celix_container` Apache Celix CMake command:
+```CMake
+add_celix_container(my_web_shell_container
+    BUNDLES
+        Celix::http_admin
+        Celix::shell
+        Celix::shell_wui
+    PROPERTIES
+        CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL=debug
+        CELIX_HTTP_ADMIN_LISTENING_PORTS=8888
+)
+```
+
+will create the following main source file (note: reformatted for display purpose):
+```C++
+#include <celix_launcher.h>
+int main(int argc, char *argv[]) {
+    const char * config = "\
+CELIX_CONTAINER_NAME=my_web_shell_container\n\
+CELIX_BUNDLES_PATH=bundles\n\
+CELIX_AUTO_START_3=celix_http_admin-Debug.zip celix_shell-Debug.zip celix_shell_wui-Debug.zip\n\
+CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL=debug\n\
+CELIX_HTTP_ADMIN_LISTENING_PORTS=8888";
+
+    celix_properties_t *embeddedProps = celix_properties_loadFromString(config);
+    return celixLauncher_launchAndWaitForShutdown(argc, argv, embeddedProps);
+}
+```
+
+## Installing Celix container
+Currently, installing Apache Celix containers (i.e. using `make install` on a Celix Container) is not supported. 
+
+The reason behind this is that an Apache Celix container depends on the location of bundles and there is currently no
+reliable way to find bundles in a system. For this to work Apache Celix should support something like: 
+ - A bundle search path concept like `LD_LIBRARY_PATH` 
+ - Support for embedded bundles in an executable so that Apache Celix containers can be self containing
+ - Bundles as shared libraries (instead of zip) so that the normal shared libraries concepts
+   (installation, `LD_LIBRARY_PATH`, etc ) can be reused.
+
+There is an exception when an installation of an Apache Celix containers works: If all used bundles are based on already
+installed bundles and are added to the Apache Celix container with an absolute path (default).
+
+ 
+
+
+
+
diff --git a/source/docs/2.3.0/celix/documents/framework.md b/source/docs/2.3.0/celix/documents/framework.md
new file mode 100644
index 0000000..17fa167
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/framework.md
@@ -0,0 +1,209 @@
+---
+title: Apache Celix Framework
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Apache Celix Framework
+The Apache Celix framework is the core of Apache Celix applications and provides supports for deployments of 
+dynamic, extensible modules known as bundles. 
+
+An instance of an Apache Celix framework can be created with the celix framework factory or by configuring 
+[Apache Celix containers](containers.html) using the `add_celix_container` Apache Celix CMake command.
+
+
+## Framework factory
+A new instance of an Apache Celix framework can be created using the C/C++ function/method:
+- `celix_frameworkFactory_createFramework`
+- `celix::createFramework`
+
+When an Apache Celix framework is destroyed it will automatically stop and uninstall all running bundles.
+For C, an Apache Celix framework needs to be destroyed with the call `celix_frameworkFactory_destroyFramework` and
+for C++ this happens when the framework goes out of scope. 
+
+### Example: Creating an Apache Celix Framework in C
+```C
+//src/main.c
+#include <celix_api.h>
+int main() {
+    //create framework properties
+    celix_properties_t* properties = properties_create();
+    properties_set(properties, "CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "debug");
+
+    //create framework
+    celix_framework_t* fw = celix_frameworkFactory_createFramework(properties);
+
+    //get framework bundle context and log hello
+    celix_bundle_context_t* fwContext = celix_framework_getFrameworkContext(fw);
+    celix_bundleContext_log(fwContext, CELIX_LOG_LEVEL_INFO, "Hello from framework bundle context");
+
+    //destroy framework
+    celix_frameworkFactory_destroyFramework(fw);
+}
+```
+
+```cmake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+add_executable(create_framework_in_c src/main.c)
+target_link_libraries(create_framework_in_c PRIVATE Celix::framework)
+```
+
+### Example: Creating an Apache Celix Framework in C++
+```C++
+//src/main.cc
+#include <celix/FrameworkFactory.h>
+int main() {
+    //create framework properties
+    celix::Properties properties{};
+    properties.set("CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "debug");
+
+    //create framework
+    std::shared_ptr<celix::Framework> fw = celix::createFramework(properties);
+
+    //get framework bundle context and log hello
+    std::shared_ptr<celix::BundleContext> ctx = fw->getFrameworkBundleContext();
+    ctx->logInfo("Hello from framework bundle context");
+}
+```
+
+```cmake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+add_executable(create_framework_in_cxx src/main.cc)
+target_link_libraries(create_framework_in_cxx PRIVATE Celix::framework)
+```
+
+## Apache Celix launcher
+If the Apache Celix framework is the main application, the Apache Celix launcher can be used to create the framework 
+and wait for a framework shutdown.
+
+The Apache Celix launcher also does some additional work:
+
+- Handles command arguments (mainly to print to embedded and runtime framework properties).
+- Tries to read a "config.properties" file from the current workdir and combines this with the optional provided 
+  embedded properties to the Apache Celix Launcher.
+- Configures a framework shutdown for the `SIGINT` and `SIGTERM` signal.
+- Configures an "ignore" signal handler for the `SIGUSR1` and `SIGUSR2` signal.
+- Calls the `curl_global_init` to initialize potential use of curl. Note that the `curl_global_init` is not thread safe
+  or protected by something like pthread_once.
+- Destroys the Apache Celix Framework after shutdown. 
+
+### Example: Creating an Apache Celix Framework with the Apache Celix Launcher
+```C
+//src/launcher.c
+#include <celix_api.h>
+int main(int argc, char** argv) {
+    return celixLauncher_launchAndWaitForShutdown(argc, argv, NULL);
+}
+```
+```cmake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+add_executable(create_framework_with_celix_launcher src/launcher.c)
+target_link_libraries(create_framework_with_celix_launcher PRIVATE Celix::framework)
+```
+
+## Installing and starting bundles in an Apache Celix framework
+
+Bundles can be installed and started using the Apache Celix framework bundle context or - when using the Apache Celix
+launcher - with a "config.properties" file.
+
+Bundles are installed using a path to a zip file. If the path is a relative path, the framework will search for the
+bundle in the directories configured in the framework property `CELIX_BUNDLES_PATH`. 
+The default value of `CELIX_BUNDLES_PATH` is "bundles". 
+
+Another option is to use framework properties to configure which bundles to install and start. 
+This can be done by using the CELIX_AUTO_START_0 till CELIX_AUTO_START_6 framework properties. 
+(note that bundles configured in CELIX_AUTO_START_0 are installed and started first).
+For a more complete overview of possible framework properties see `celix_constants.h`
+
+If the Apache Celix launcher is used, the framework properties can be provided with a "config.properties" 
+file using the Java Properties File Format.
+
+Framework properties to install and start bundles:
+
+- CELIX_AUTO_START_0
+- CELIX_AUTO_START_1
+- CELIX_AUTO_START_2
+- CELIX_AUTO_START_3
+- CELIX_AUTO_START_4
+- CELIX_AUTO_START_5
+- CELIX_AUTO_START_6 
+
+### Example: Installing and starting bundles in C
+```C
+//src/main.c
+#include <celix_api.h>
+int main() {
+    //create framework properties
+    celix_properties_t* properties = properties_create();
+    properties_set(properties, "CELIX_BUNDLES_PATH", "bundles;/opt/alternative/bundles");
+    
+    //create framework
+    celix_framework_t* fw = celix_frameworkFactory_createFramework(NULL);
+
+    //get framework bundle context and install a bundle
+    celix_bundle_context_t* fwContext = celix_framework_getFrameworkContext(fw);
+    celix_bundleContext_installBundle(fwContext, "FooBundle.zip", true);
+
+    //destroy framework
+    celix_frameworkFactory_destroyFramework(fw);
+}
+```
+
+### Example: Installing and starting bundles in C++
+```C++
+//src/main.cc
+#include <celix/FrameworkFactory.h>
+int main() {
+    //create framework properties
+    celix::Properties properties{};
+    properties.set("CELIX_BUNDLES_PATH", "bundles;/opt/alternative/bundles");
+    
+    //create framework
+    std::shared_ptr<celix::Framework> fw = celix::createFramework(properties);
+    
+    //get framework bundle context and install a bundle
+    std::shared_ptr<celix::BundleContext> ctx = fw->getFrameworkBundleContext();
+    ctx->installBundle("FooBundle.zip");
+}
+```
+
+### Example: Installing and starting bundles using the Apache Celix Launcher
+
+```C
+//src/launcher.c
+#include <celix_api.h>
+int main(int argc, char** argv) {
+    return celixLauncher_launchAndWaitForShutdown(argc, argv, NULL);
+}
+```
+
+```cmake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/config.properties CONTENT "
+CELIX_BUNDLES_PATH=bundles;/opt/alternative/bundles
+CELIX_AUTO_START_3=FooBundle.zip
+")
+add_executable(create_framework_with_celix_launcher src/launcher.c)
+target_link_libraries(create_framework_with_celix_launcher PRIVATE Celix::framework)
+```
\ No newline at end of file
diff --git a/source/docs/2.3.0/celix/documents/patterns.md b/source/docs/2.3.0/celix/documents/patterns.md
new file mode 100644
index 0000000..6557c4b
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/patterns.md
@@ -0,0 +1,155 @@
+---
+title: Apache Celix Services
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Apache Celix / OSGi  patterns 
+There are several design patterns used in Apache Celix and OSGi.  
+
+## Whiteboard Pattern
+The whiteboard pattern is a pattern where the act of registering a service is enough to participate in or extend 
+an existing functionality.  
+A typical aspect of the whiteboard pattern is that an application should 
+still resolve and startup even if the bundle or bundles that pick up the whiteboard pattern services are absent.
+
+![Whiteboard Pattern](diagrams/whiteboard_pattern.png)
+
+Many Apache Celix services are whiteboard services. For example:
+ - `celix_shell_command_t` and `celix::IShellCommand` services. These services can be 
+   picked up by the `Celix::shell` bundle, but applications should still work if there is no `Celix::shell` installed 
+   and started. <br/>
+   ![Celix Shell](diagrams/whiteboard_pattern_shell.png)
+ - `celix_http_service_t` and `celix_websocket_service_t` services. These services can be picked up by the
+   `Celix::http_admin` bundle to provide http url endpoints or websocket url endpoints. <br/>
+   ![Celix HTTP Admin](diagrams/whiteboard_pattern_http_admin.png)
+ - `celix_log_sink_t` services. If there is no `Celix::log_admin` bundle installed and started, the log sinks 
+   services will never be called, but the application should still work. Note that the `Celix::log_admin` bundle
+   also uses a service on demand pattern (see below). <br/>
+   ![Celix Log Admin](diagrams/whiteboard_pattern_log_sink.png)
+ - Services marked as remote service (`service.exported.interface=*`). These services will work fine
+   but only as local services - if there are no remote service bundles installed and started.
+
+
+
+
+
+For modularity, the whiteboard pattern is a nice fit, because a whiteboard service admin does not need to know how 
+many - if any - whiteboard services are going to be provided and how the implementation details work (as long as 
+the implementation adheres to the service contract).    
+
+Whiteboard pattern services are always [consumer types](https://docs.osgi.org/javadoc/osgi.annotation/8.0.0/org/osgi/annotation/versioning/ConsumerType.html), although for Apache Celix interfaces cannot be annotated as
+consumer or provider type. 
+
+One of the downsides of the whiteboard pattern is that it is not always clear why an application is not working as 
+expected or what is missing to get the application working as expected. This is because it is not an error 
+if there are unused services, and as result there is no error to help a user to identify what is missing. 
+
+For example: A `log_collector` bundle which provides a `celix_log_sink_t` service is installed and started, 
+so that logging can be collected at in a central log database. 
+But no logging is added to the central log database. Initially it could seem that the `log_collector` bundle 
+does not work, especially because the application will not print any warnings or errors. 
+But if the `Celix::log_admin` bundle is not installed and started, the `log_collector` bundle provided  
+`celix_log_sink_t` service will never be called, so installing and starting the `Celix::log_admin` is the issue 
+in this example.
+
+
+## Extender Pattern
+The extender pattern is a design pattern which leverages the concept of resource containing bundles.
+With the extender pattern, functionality of an extender bundle can be extended by installing so called extendee bundles. 
+The extendee bundles contain certain resources files and/or bundle manifest entries which are used by the extender
+bundle.
+
+![Extender Pattern](diagrams/extender_pattern.png)
+
+An example of the extender pattern is the `Celix::http_admin` bundle. The extender bundle `Celix::http_admin` 
+monitors installed bundles and reads bundle `MANIFEST.MF` entries for a `X-Web-Resource` entry. 
+If a `X-Web-Resource` entry is found, its value is used to set up new HTTP endpoint in the HTTP server of
+the `Celix::http_admin` bundle using the static web resources of the extendee bundle.
+
+### `Celix::http_admin` Extendee Bundle Example
+The following example shows how a very simple `Celix::http_admin` extendee bundle, which provided a minimal
+hello world `index.html` page for the `Celix::http_admin` to pick up.
+
+Remarks for the `Celix::http_admin` extendee bundle example:
+1. Creates a bundle which will function as an extendee bundle for the `Celix::http_admin`.
+2. Marks the bundle as a resource-only bundle, i.e. a bundle with no C or C++ activator.
+3. Creates a very simple `index.html` file in CMake
+4. Adds the `index.html` file to the `http_admin_extendee_bundle` bundle in the bundle directory resources.
+5. Adds a `X-Web-Resource` bundle manifest entry, which marks the bundle as an extendee bundle for the 
+   `Celix::http_admin` bundle. See `Celix::http_admin` for more info. Note that `$<SEMICOLON>` is used, 
+   because a literal `;` has a special meaning in CMake.
+6. Create a container which installs and starts the `Celix::http_admin` (extender) bundle and the
+   `http_admin_extendee_bundle` (extendee) bundle.
+ 
+```CMake
+#CMakeLists.txt
+add_celix_bundle(http_admin_extendee_bundle # <----------------------------------------------------------------------<1>
+    VERSION 1.0.0
+    NO_ACTIVATOR # <-------------------------------------------------------------------------------------------------<2>
+)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/index.html" "<html><body>Hello World</body></html>") # <---------------------<3>
+celix_bundle_files(http_admin_extendee_bundle "${CMAKE_CURRENT_BINARY_DIR}/index.html" DESTINATION resources) # <----<4>
+celix_bundle_headers(http_admin_extendee_bundle "X-Web-Resource: /hello$<SEMICOLON>/resources") # <------------------<5>
+
+add_celix_container(extender_pattern_example_container # <-----------------------------------------------------------<6>
+    BUNDLES
+        Celix::http_admin
+        http_admin_extendee_bundle
+)
+```
+
+When the `extender_pattern_example_container` executable is running the web address `http://localhost:8080/hello`
+should show the content of the `index.html`
+
+
+## Service on Demand (SOD) Pattern
+
+A less known Apache Celix / OSGi pattern is the service on demand (SOD) pattern. With the SOD pattern,
+services are ad hoc registered at the moment they are requested.
+
+Where the whiteboard pattern can be used to extend functionality in modular and service oriented fashion, the SOD
+pattern can be used to use to provide more functional cohesive services to users in a service oriented fashion.
+
+For the SOD pattern, the service filter to request services can be used to extract information about if and how
+a service on demand needs to be created.
+
+![Service On Demand Pattern](diagrams/sod_pattern.png)
+
+Some Apache Celix bundles use the SOD pattern. For example:
+ - The `Celix::log_admin` bundle creates and registers `celix_log_service_t` services already preconfigured for 
+   a requested logger name. <br/>
+   ![Celix Log Admin](diagrams/sod_pattern_log_service.png)
+ - The Celix PubSub bundles uses SOD to create and register `pubsub_publisher_t` services when these are requested 
+   with a valid "topic.name" and "topic.scope" filter attribute. For PubSub, the Celix PubSub Topology Manager monitors
+   the `pubsub_publisher_t` requests and instructs the available Celix PubSub Admins to create 
+   `pubsub_publisher_t`. <br/>
+   ![Celix PubSub](diagrams/sod_pattern_publisher_service.png)
+ - The Apache Celix / OSGi remote services uses SOD, by ad hoc imported services only when they are discovered and
+   requested.
+
+SOD services are always [provider types](https://docs.osgi.org/javadoc/osgi.annotation/8.0.0/org/osgi/annotation/versioning/ProviderType.html), although for Apache Celix interfaces cannot be annotated as
+consumer or provider type.
+
+For OSGi the [FindHook](https://docs.osgi.org/javadoc/osgi.core/8.0.0/org/osgi/framework/hooks/service/FindHook.html)
+service can be used to further fine tune which services are visible for bundle requesting a SOD service. 
+Apache Celix does not yet support the FindHook service. 
+
+
diff --git a/source/docs/2.3.0/celix/documents/services.md b/source/docs/2.3.0/celix/documents/services.md
new file mode 100644
index 0000000..0bafe06
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/services.md
@@ -0,0 +1,643 @@
+---
+title: Apache Celix Services
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Apache Celix Services
+An Apache Celix Service is a pointer registered to the Celix framework under a set of properties (metadata).
+Services can be dynamically registered into and looked up from the Apache Celix framework.
+
+By convention a C service in Apache Celix is a pointer to struct of function pointers and a C++ service is a pointer
+(which can be provided as a `std::shared_ptr`) to an object implementing a (pure) abstract class.
+
+A service is always registered under a service name and this service name is also used to lookup services. 
+For C the service name must be provided by the user and for C++ the service name can be provided by the user. 
+If for C++ no service name is provided the service name will be inferred based on the service template argument using
+`celix::typeName<I>`. 
+
+Note that the service name is represented in the service properties under the property name `objectClass`, 
+this is inherited for the Java OSGi specification. 
+Also note that for Celix - in contrast with Java OSGi - it is only possible to register a single interface 
+per service registration in the Apache Celix Framework. This restriction was added because C does not 
+(natively) supports multiple interfaces (struct with function pointers) on a single object/pointer.  
+
+## A C service example
+As mentioned an Apache Celix C service is a registered pointer to a struct with function pointers. 
+This struct ideally contains a handle pointer, a set of function pointers and should be well documented to
+form a well-defined service contract.
+
+A simple example of an Apache Celix C service is a shell command service. 
+For C, the shell command header looks like:
+```C
+//celix_shell_command.h
+...
+#define CELIX_SHELL_COMMAND_NAME                "command.name"
+#define CELIX_SHELL_COMMAND_USAGE               "command.usage"
+#define CELIX_SHELL_COMMAND_DESCRIPTION         "command.description"
+
+#define  CELIX_SHELL_COMMAND_SERVICE_NAME       "celix_shell_command"
+#define  CELIX_SHELL_COMMAND_SERVICE_VERSION    "1.0.0"
+
+typedef struct celix_shell_command celix_shell_command_t;
+
+/**
+ * The shell command can be used to register additional shell commands.
+ * This service should be registered with the following properties:
+ *  - command.name: mandatory, name of the command e.g. 'lb'
+ *  - command.usage: optional, string describing how tu use the command e.g. 'lb [-l | -s | -u]'
+ *  - command.description: optional, string describing the command e.g. 'list bundles.'
+ */
+struct celix_shell_command {
+    void *handle;
+
+    /**
+     * Calls the shell command.
+     * @param handle        The shell command handle.
+     * @param commandLine   The complete provided cmd line (e.g. for a 'stop' command -> 'stop 42')
+     * @param outStream     The output stream, to use for printing normal flow info.
+     * @param errorStream   The error stream, to use for printing error flow info.
+     * @return              Whether a command is successfully executed.
+     */
+    bool (*executeCommand)(void *handle, const char *commandLine, FILE *outStream, FILE *errorStream);
+};
+```
+
+The service struct is documented, explains which service properties needs to be provided, contains a handle pointer and
+a `executeCommand` function pointer. 
+
+The `handle` field and the `handle` function argument should function as an opaque instance (`this` / `self`) handle 
+and generally is unique for every service instance. Users of the service should forward the handle field when calling
+a service function, e.g.:
+```C
+celix_shell_command_t* command = ...;
+command->executeCommand(command->handle, "test 123", stdout, stderr);
+```
+
+## A C++ service example
+As mentioned an Apache Celix C++ service is a registered pointer to an object implementing an abstract class.
+The service class ideally should be well documented to form a well-defined service contract.
+
+A simple example of an Apache Celix C++ service is a C++ shell command. 
+For C++, the shell command header looks like:
+```C++
+//celix/IShellCommand.h
+...
+namespace celix {
+
+    /**
+     * The shell command interface can be used to register additional Celix shell commands.
+     * This service should be registered with the following properties:
+     *  - name: mandatory, name of the command e.g. 'celix::lb'
+     *  - usage: optional, string describing how tu use the command e.g. 'celix::lb [-l | -s | -u]'
+     *  - description: optional, string describing the command e.g. 'list bundles.'
+     */
+    class IShellCommand {
+    public:
+        /**
+         * The required name of the shell command service (service property)
+         */
+        static constexpr const char * const COMMAND_NAME = "name";
+
+        /**
+         * The optional usage text of the shell command service (service property)
+         */
+        static constexpr const char * const COMMAND_USAGE = "usage";
+
+        /**
+         * The optional description text of the shell command service (service property)
+         */
+        static constexpr const char * const COMMAND_DESCRIPTION = "description";
+
+        virtual ~IShellCommand() = default;
+
+        /**
+         * Calls the shell command.
+         * @param commandLine   The complete provided command line (e.g. for a 'stop' command -> 'stop 42'). Only valid during the call.
+         * @param commandArgs   A list of the arguments for the command (e.g. for a "stop 42 43" commandLine -> {"42", "43"}). Only valid during the call.
+         * @param outStream     The C output stream, to use for printing normal flow info.
+         * @param errorStream   The C error stream, to use for printing error flow info.
+         * @return              Whether the command has been executed correctly.
+         */
+        virtual void executeCommand(const std::string& commandLine, const std::vector<std::string>& commandArgs, FILE* outStream, FILE* errorStream) = 0;
+    };
+}
+```
+
+As with the C shell command struct, the C++ service class is documented and explains which service properties needs to 
+be provided. The `handle` construct is not needed for C++ services and using a C++ service function is just the same 
+as calling a function member of any C++ object.
+
+## Impact of dynamic services
+Services in Apache Celix are dynamic, meaning that they can come and go at any moment.
+This makes it possible to create emerging functionality based on the coming and going of Celix services.
+How to cope with this dynamic behaviour is critical for creating a stable solution.
+
+For Java OSGi this is already a challenge to program correctly, but less critical because generally speaking the
+garbage collector will arrange that objects still exists even if the providing bundle is un-installed.
+Taking into account that C and C++ has no garbage collection, handling the dynamic behaviour correctly is
+more critical; If a bundle providing a certain service is removed, the code segment / memory allocated for
+that service will also be removed / deallocated.
+
+Apache Celix has several mechanisms for dealing with this dynamic behaviour:
+
+* A built-in abstraction to use services with callbacks function where the Celix framework ensures the services
+  are not removed during callback execution.
+* Service trackers which ensure that service can only complete their un-registration when all service
+  remove callbacks have been processed.
+* Components with declarative service dependency so that a component life cycle is coupled with the availability of
+  service dependencies. See the components' documentation section for more information about components.
+* The Celix framework will handle all service registration/un-registration events and the starting/stopping of trackers
+  on the Celix event thread to ensure that only 1 event can be processed per time and that callbacks for service
+  registration and service tracker are always called from the same thread.
+* Service registration, service un-registration, starting trackers and closing trackers can be done async.
+ 
+## Registering and un-registering services
+Service registration and un-registration in Celix can be done synchronized or asynchronized and although 
+(un-)registering services synchronized is more inline with the OSGi spec, (un-)registering is preferred for Celix. 
+
+When registering a service synchronized, the service registration event and all events resulting from the service
+registration are handled; in practice this means that when a synchronized service registration returns all bundles
+are aware of the new service and if needed have updated their administration accordingly.
+
+Synchronized service (un-)registration can lead to problems if for example another service registration event is 
+triggered on the handling of the current service registration events. 
+In that case normal mutexes are not always enough and reference counting or recursive mutexes are needed. 
+reference counting can be complex to handle (especially in C) and recursive mutexes are arguable a bad idea.
+
+Interestingly for Java the use of `synchronized` is recursive and as result this seems te be smaller issue with Java.
+
+When registering a service asynchronized, the service properties and specifically the `service.id` property will be 
+finalized when the service registration call returns. The actual service registration event will be done asynchronized
+by the Celix event thread and this can be done before or after the service registration call returns.
+
+To register a service asynchronized the following C functions / C++ methods can be used:
+ - `celix_bundleContext_registerServiceAsync`.
+ - `celix_bundleContext_registerServiceWithOptionsAsync`.
+ - `celix::BundleContext::registerService`.
+ - `celix::BundleContext::registerUnmanagedService`.
+
+To register a service synchronized the following C functions / C++ methods can be used:
+ - `celix_bundleContext_registerService`.
+ - `celix_bundleContext_registerServiceWithOptions`.
+ - `celix::BundleContext::registerService`, use `celix::ServiceRegistrationBuilder::setRegisterAsync` to configure 
+    registration synchronized because the default is asynchronized.
+ - `celix::BundleContext::registerUnmanagedService`, use `celix::ServiceRegistrationBuilder::setRegisterAsync` 
+   to configure registration synchronized because the default is asynchronized.
+ 
+
+To unregister a service asynchronized the following C function can be used:
+- `celix_bundleContext_unregisterServiceAsync`.
+
+And to unregister a service synchronized the following C function can be used:
+- `celix_bundleContext_unregisterService`.
+
+For C++ a service un-registration happens when its corresponding `celix::ServiceRegistration` object goes out of 
+scope. A C++ service can be configured for synchronized un-registration using ServiceRegistrationBuilder, 
+specifically:
+- `celix::ServiceRegistrationBuilder::setUnregisterAsync`. The default is asynchronized. 
+
+### Example: Register a service in C
+```C
+//src/my_shell_command_provider_bundle_activator.c
+#include <celix_api.h>
+#include <celix_shell_command.h>
+
+typedef struct my_shell_command_provider_activator_data {
+    celix_bundle_context_t* ctx;
+    celix_shell_command_t shellCmdSvc;
+    long shellCmdSvcId;
+} my_shell_command_provider_activator_data_t;
+
+static bool my_shell_command_executeCommand(void *handle, const char *commandLine, FILE *outStream, FILE *errorStream __attribute__((unused))) {
+    my_shell_command_provider_activator_data_t* data = handle;
+    celix_bundle_t* bnd = celix_bundleContext_getBundle(data->ctx);
+    fprintf(outStream, "Hello from bundle %s with command line '%s'\n", celix_bundle_getName(bnd), commandLine);
+    return true;
+}
+
+static celix_status_t my_shell_command_provider_bundle_start(my_shell_command_provider_activator_data_t *data, celix_bundle_context_t *ctx) {
+    data->ctx = ctx;
+    data->shellCmdSvc.handle = data;
+    data->shellCmdSvc.executeCommand = my_shell_command_executeCommand;
+    
+    celix_properties_t* props = celix_properties_create();
+    celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "my_command");
+    
+    data->shellCmdSvcId = celix_bundleContext_registerServiceAsync(ctx, &data->shellCmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+    return CELIX_SUCCESS;
+}
+
+static celix_status_t my_shell_command_provider_bundle_stop(my_shell_command_provider_activator_data_t *data, celix_bundle_context_t *ctx) {
+    celix_bundleContext_unregisterServiceAsync(ctx, data->shellCmdSvcId, NULL, NULL);
+    return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(my_shell_command_provider_activator_data_t, my_shell_command_provider_bundle_start, my_shell_command_provider_bundle_stop)
+```
+
+### Example: Register a C++ service in C++
+```C++
+//src/MyShellCommandBundleActivator.cc
+#include <celix/BundleActivator.h>
+#include <celix/IShellCommand.h>
+
+class MyCommand : public celix::IShellCommand {
+public:
+    explicit MyCommand(std::string_view _name) : name{_name} {}
+
+    ~MyCommand() noexcept override = default;
+
+    void executeCommand(
+            const std::string& commandLine,
+            const std::vector<std::string>& /*commandArgs*/,
+            FILE* outStream,
+            FILE* /*errorStream*/) override {
+        fprintf(outStream, "Hello from bundle %s with command line '%s'\n", name.c_str(), commandLine.c_str());
+    }
+private:
+    const std::string name;
+};
+
+class MyShellCommandProviderBundleActivator {
+public:
+    explicit MyShellCommandProviderBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        auto svcObject = std::make_shared<MyCommand>(ctx->getBundle().getName());
+        cmdShellRegistration = ctx->registerService<celix::IShellCommand>(std::move(svcObject))
+                .addProperty(celix::IShellCommand::COMMAND_NAME, "MyCommand")
+                .build();
+    }
+
+    ~MyShellCommandProvider() noexcept = default;
+private:
+    //NOTE when celix::ServiceRegistration goes out of scope the underlining service will be un-registered
+    std::shared_ptr<celix::ServiceRegistration> cmdShellRegistration{};
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(MyShellCommandProviderBundleActivator)
+```
+
+### Example: Register a C service in C++
+```C++
+//src/MyCShellCommandProviderBundleActivator.cc
+#include <celix/BundleActivator.h>
+#include <celix_shell_command.h>
+
+struct MyCShellCommand : public celix_shell_command {
+    explicit MyCShellCommand(std::shared_ptr<celix::BundleContext> _ctx) : celix_shell_command(), ctx{std::move(_ctx)} {
+        handle = this;
+        executeCommand = [] (void *handle, const char* commandLine, FILE* outStream, FILE* /*errorStream*/) -> bool {
+            auto* cmdProvider = static_cast<MyCShellCommand*>(handle);
+            fprintf(outStream, "Hello from bundle %s with command line '%s'\n", cmdProvider->ctx->getBundle().getName().c_str(), commandLine);
+            return true;
+        };
+    }
+
+    const std::shared_ptr<celix::BundleContext> ctx;
+};
+
+class MyCShellCommandProviderBundleActivator {
+public:
+    explicit MyCShellCommandProviderBundleActivator(const std::shared_ptr<celix::BundleContext>&  ctx) {
+        auto shellCmd = std::make_shared<MyCShellCommand>(ctx);
+        cmdShellRegistration = ctx->registerService<celix_shell_command>(std::move(shell.html), CELIX_SHELL_COMMAND_SERVICE_NAME)
+                .addProperty(CELIX_SHELL_COMMAND_NAME, "MyCCommand")
+                .setUnregisterAsync(false)
+                .build();
+    }
+private:
+    //NOTE when celix::ServiceRegistration goes out of scope the underlining service will be un-registered
+    std::shared_ptr<celix::ServiceRegistration> cmdShellRegistration{};
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(MyCShellCommandProviderBundleActivator)
+```
+
+### Sequence diagrams for service registration
+![Register Service Async](diagrams/services_register_service_async_seq.png)
+A asynchronized service registration
+---
+
+![Register Service Async](diagrams/services_register_service_seq.png)
+A synchronized service registration
+---
+
+![Unregister Service Async](diagrams/services_unregister_service_async_seq.png)
+A asynchronized service un-registration
+---
+
+![Unregister Service Async](diagrams/services_unregister_service_seq.png)
+A synchronized service un-registration
+---
+
+## Using services
+Services can be used directly using the bundle context C functions or C++ methods:
+- `celix_bundleContext_useServiceWithId`
+- `celix_bundleContext_useService`
+- `celix_bundleContext_useServices`
+- `celix_bundleContext_useServiceWithOptions`
+- `celix_bundleContext_useServicesWithOptions`
+- `celix::BundleContext::useService`
+- `celix::BundleContext::useServices`
+
+These functions and methods work by providing a callback function which will be called by the Celix framework with the 
+matching service or services.
+when a "use service" function/method returns the callback function can can be safely deallocated. 
+A "use service" function/method return value will indicate if a matching service is found or how many matching services 
+are found.
+
+The Celix framework provides service usage through callbacks - instead of directly return a service pointer - 
+to ensure that services are prevented from removal while the services are still in use without forwarding 
+this responsibility to the user; i.e. by adding an api to "lock" and "unlock" services for usage.
+
+### Example: Using a service in C
+```C
+#include <stdio.h>
+#include <celix_api.h>
+#include <celix_shell_command.h>
+
+typedef struct use_command_service_example_data {
+    //nop
+} use_command_service_example_data_t;
+
+static void useShellCommandCallback(void *handle __attribute__((unused)), void *svc) {
+    celix_shell_command_t* cmdSvc = (celix_shell_command_t*)svc;
+    cmdSvc->executeCommand(cmdSvc->handle, "my_command test call from C", stdout, stderr);
+}
+
+static celix_status_t use_command_service_example_start(use_command_service_example_data_t *data __attribute__((unused)), celix_bundle_context_t *ctx) {
+    celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
+    opts.callbackHandle = NULL;
+    opts.use = useShellCommandCallback;
+    opts.filter.serviceName = CELIX_SHELL_COMMAND_SERVICE_NAME;
+    opts.filter.filter = "(command.name=my_command)";
+    bool called = celix_bundleContext_useServicesWithOptions(ctx, &opts);
+    if (!called) {
+        fprintf(stderr, "%s: Command service not called!\n", __PRETTY_FUNCTION__);
+    }
+    return CELIX_SUCCESS;
+}
+
+static celix_status_t use_command_service_example_stop(use_command_service_example_data_t *data __attribute__((unused)), celix_bundle_context_t *ctx __attribute__((unused))) {
+    return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(use_command_service_example_data_t, use_command_service_example_start, use_command_service_example_stop)
+```
+
+### Example: Using a service in C++
+```C++
+//src/UsingCommandServicesExample.cc
+#include <celix/IShellCommand.h>
+#include <celix/BundleActivator.h>
+#include <celix_shell_command.h>
+
+static void useCxxShellCommand(const std::shared_ptr<celix::BundleContext>& ctx) {
+    auto called = ctx->useService<celix::IShellCommand>()
+            .setFilter("(name=MyCommand)")
+            .addUseCallback([](celix::IShellCommand& cmdSvc) {
+                cmdSvc.executeCommand("MyCommand test call from C++", {}, stdout, stderr);
+            })
+            .build();
+    if (!called) {
+        std::cerr << __PRETTY_FUNCTION__  << ": Command service not called!" << std::endl;
+    }
+}
+
+static void useCShellCommand(const std::shared_ptr<celix::BundleContext>& ctx) {
+    auto calledCount = ctx->useServices<celix_shell_command>(CELIX_SHELL_COMMAND_SERVICE_NAME)
+            //Note the filter should match 2 shell commands
+            .setFilter("(|(command.name=MyCCommand)(command.name=my_command))") 
+            .addUseCallback([](celix_shell_command& cmdSvc) {
+                cmdSvc.executeCommand(cmdSvc.handle, "MyCCommand test call from C++", stdout, stderr);
+            })
+            .build();
+    if (calledCount == 0) {
+        std::cerr << __PRETTY_FUNCTION__  << ": Command service not called!" << std::endl;
+    }
+}
+
+class UsingCommandServicesExample {
+public:
+    explicit UsingCommandServicesExample(const std::shared_ptr<celix::BundleContext>& ctx) {
+        useCxxShellCommand(ctx);
+        useCShellCommand(ctx);
+    }
+
+    ~UsingCommandServicesExample() noexcept = default;
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(UsingCommandServicesExample)
+```
+
+## Tracking services
+To monitor the coming and going of services, a service tracker can be used. Service trackers use - user provided - 
+callbacks to handle matching services being added or removed. A service name and an optional LDAP filter is used
+to select which services to monitor. A service name `*` can be used to match services with any service name. 
+When a service unregisters, the un-registration can only finish after all matching service trackers 
+remove callbacks are processed.
+
+For C a service tracker can be created using the following bundle context functions:
+- `celix_bundleContext_trackServicesAsync`
+- `celix_bundleContext_trackServices`
+- `celix_bundleContext_trackServicesWithOptionsAsync`
+- `celix_bundleContext_trackServicesWithOptions`
+
+The "track services" C functions always return a service id (long) which can be used to close and destroy the 
+service tracker:
+- `celix_bundleContext_stopTrackerAsync`
+- `celix_bundleContext_stopTracker`
+
+For C++ a service tracker can be created using the following bundle context methods:
+- `celix::BundleContext::trackServices`
+- `celix::BundleContext::trackAnyServices`
+
+The C++ methods work with a builder API and will eventually return a `std::shared_ptr<celix::ServiceTracker<I>>` object.
+if the underlining ServiceTracker object goes out of scope, the service tracker will be closed and destroyed.
+
+C++ service trackers are created and opened asynchronized, but closed synchronized. 
+The closing is done synchronized so that users can be sure that after a `celix::ServiceTracker::close()` call the 
+added callbacks will not be invoked anymore.  
+
+### Example: Tracking services in C
+```C
+//src/track_command_services_example.c
+#include <stdio.h>
+#include <celix_api.h>
+#include <celix_shell_command.h>
+
+typedef struct track_command_services_example_data {
+    long trackerId;
+    celix_thread_mutex_t mutex; //protects below
+    celix_array_list_t* commandServices;
+} track_command_services_example_data_t;
+
+
+static void addShellCommandService(void* data,void* svc, const celix_properties_t * properties) {
+    track_command_services_example_data_t* activatorData = data;
+    celix_shell_command_t* cmdSvc = svc;
+
+    printf("Adding command service with svc id %li\n", celix_properties_getAsLong(properties, CELIX_FRAMEWORK_SERVICE_ID, -1));
+    celixThreadMutex_lock(&activatorData->mutex);
+    celix_arrayList_add(activatorData->commandServices, cmdSvc);
+    printf("Nr of command service found: %i\n", celix_arrayList_size(activatorData->commandServices));
+    celixThreadMutex_unlock(&activatorData->mutex);
+}
+
+static void removeShellCommandService(void* data,void* svc, const celix_properties_t * properties) {
+    track_command_services_example_data_t* activatorData = data;
+    celix_shell_command_t* cmdSvc = svc;
+
+    printf("Removing command service with svc id %li\n", celix_properties_getAsLong(properties, CELIX_FRAMEWORK_SERVICE_ID, -1));
+    celixThreadMutex_lock(&activatorData->mutex);
+    celix_arrayList_remove(activatorData->commandServices, cmdSvc);
+    printf("Nr of command service found: %i\n", celix_arrayList_size(activatorData->commandServices));
+    celixThreadMutex_unlock(&activatorData->mutex);
+}
+
+static celix_status_t track_command_services_example_start(track_command_services_example_data_t *data, celix_bundle_context_t *ctx) {
+    celixThreadMutex_create(&data->mutex, NULL);
+    data->commandServices = celix_arrayList_create();
+
+    celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
+    opts.filter.serviceName = CELIX_SHELL_COMMAND_SERVICE_NAME;
+    opts.filter.filter = "(command.name=my_command)";
+    opts.callbackHandle = data;
+    opts.addWithProperties = addShellCommandService;
+    opts.removeWithProperties = removeShellCommandService;
+    data->trackerId = celix_bundleContext_trackServicesWithOptionsAsync(ctx, &opts);
+    return CELIX_SUCCESS;
+}
+
+static celix_status_t track_command_services_example_stop(track_command_services_example_data_t *data, celix_bundle_context_t *ctx) {
+    celix_bundleContext_stopTracker(ctx, data->trackerId);
+    celixThreadMutex_lock(&data->mutex);
+    celix_arrayList_destroy(data->commandServices);
+    celixThreadMutex_unlock(&data->mutex);
+    return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(track_command_services_example_data_t, track_command_services_example_start, track_command_services_example_stop)
+```
+
+### Example: Tracking services in C++
+```C++
+//src/TrackingCommandServicesExample.cc
+#include <unordered_map>
+#include <celix/IShellCommand.h>
+#include <celix/BundleActivator.h>
+#include <celix_shell_command.h>
+
+class TrackingCommandServicesExample {
+public:
+    explicit TrackingCommandServicesExample(const std::shared_ptr<celix::BundleContext>& ctx) {
+        //Tracking C++ IShellCommand services and filtering for services that have a "name=MyCommand" property.
+        cxxCommandServiceTracker = ctx->trackServices<celix::IShellCommand>()
+                .setFilter("(name=MyCommand)")
+                .addAddWithPropertiesCallback([this](const auto& svc, const auto& properties) {
+                    long svcId = properties->getAsLong(celix::SERVICE_ID, -1);
+                    std::cout << "Adding C++ command services with svc id" << svcId << std::endl;
+                    std::lock_guard lock{mutex};
+                    cxxCommandServices[svcId] = svc;
+                    std::cout << "Nr of C++ command services found: " << cxxCommandServices.size() << std::endl;
+                })
+                .addRemWithPropertiesCallback([this](const auto& /*svc*/, const auto& properties) {
+                    long svcId = properties->getAsLong(celix::SERVICE_ID, -1);
+                    std::cout << "Removing C++ command services with svc id " << svcId << std::endl;
+                    std::lock_guard lock{mutex};
+                    auto it = cxxCommandServices.find(svcId);
+                    if (it != cxxCommandServices.end()) {
+                        cxxCommandServices.erase(it);
+                    }
+                    std::cout << "Nr of C++ command services found: " << cxxCommandServices.size() << std::endl;
+                })
+                .build();
+
+        //Tracking C celix_shell_command services and filtering for services that have a "command.name=MyCCommand" or
+        // "command.name=my_command" property.
+        cCommandServiceTracker = ctx->trackServices<celix_shell_command>()
+                .setFilter("(|(command.name=MyCCommand)(command.name=my_command))")
+                .addAddWithPropertiesCallback([this](const auto& svc, const auto& properties) {
+                    long svcId = properties->getAsLong(celix::SERVICE_ID, -1);
+                    std::cout << "Adding C command services with svc id " << svcId << std::endl;
+                    std::lock_guard lock{mutex};
+                    cCommandServices[svcId] = svc;
+                    std::cout << "Nr of C command services found: " << cxxCommandServices.size() << std::endl;
+                })
+                .addRemWithPropertiesCallback([this](const auto& /*svc*/, const auto& properties) {
+                    long svcId = properties->getAsLong(celix::SERVICE_ID, -1);
+                    std::cout << "Removing C command services with svc id " << svcId << std::endl;
+                    std::lock_guard lock{mutex};
+                    auto it = cCommandServices.find(svcId);
+                    if (it != cCommandServices.end()) {
+                        cCommandServices.erase(it);
+                    }
+                    std::cout << "Nr of C command services found: " << cxxCommandServices.size() << std::endl;
+                })
+                .build();
+    }
+
+    ~TrackingCommandServicesExample() noexcept {
+        cxxCommandServiceTracker->close();
+        cCommandServiceTracker->close();
+    };
+private:
+    std::mutex mutex; //protects cxxCommandServices and cCommandServices
+    std::unordered_map<long, std::shared_ptr<celix::IShellCommand>> cxxCommandServices{};
+    std::unordered_map<long, std::shared_ptr<celix_shell_command>> cCommandServices{};
+
+    std::shared_ptr<celix::ServiceTracker<celix::IShellCommand>> cxxCommandServiceTracker{};
+    std::shared_ptr<celix::ServiceTracker<celix_shell_command>> cCommandServiceTracker{};
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(TrackingCommandServicesExample)
+```
+
+### Sequence diagrams for service tracker and service registration
+
+![Register Service Async](diagrams/services_tracker_services_add_async_seq.png)
+Service tracker callback with an asynchronized service registration
+---
+
+![Register Service Async](diagrams/services_tracker_services_rem_async_seq.png)
+Service tracker callback with an asynchronized service un-registration
+---
+
+![Register Service Async](diagrams/services_tracker_services_add_seq.png)
+Service tracker callback with a synchronized service registration
+---
+
+![Register Service Async](diagrams/services_tracker_services_rem_seq.png)
+Service tracker callback with a synchronized service un-registration
+---
+
+# The `celix::query` shell command
+To interactively see the which service and service trackers are available the `celix::query` shell command 
+can be used.
+
+Examples of supported `query` command lines are:
+- `celix::query` - Show an overview of registered services and active service trackers per bundle.
+- `query` - Same as `celix::query` (as long as there is no colliding other `query` commands).
+- `query -v` - Show a detailed overview of registered services and active service trackers per bundle.
+  For registered services the services properties are also printed and for active service trackers the number
+  of tracked services is also printed.
+- `query foo` - Show an overview of registered services and active service tracker where "foo" is
+  (case-insensitive) part of the provided/tracked service name.   
+- `query (service.id>=10)` - Shown an overview of registered services which match the provided LDAP filter. 
diff --git a/source/docs/2.3.0/celix/documents/subprojects.md b/source/docs/2.3.0/celix/documents/subprojects.md
new file mode 100644
index 0000000..5f42ea8
--- /dev/null
+++ b/source/docs/2.3.0/celix/documents/subprojects.md
@@ -0,0 +1,42 @@
+---
+title: Subprojects
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Apache Celix - Subprojects
+
+Apache Celix is organized into several subprojects. The following subproject are available:
+
+* [Framework](../libs/framework) - The Apache Celix framework, an implementation of OSGi adapted to C and C++11.
+* [Utils](../libs/utils) - The Celix utils library, containing a wide range of utils functions (string, file, C hashmap, C arraylist, etc)
+* [Examples](../examples) - A Selection of examples showing how the framework can be used.
+* [Log Service](../bundles/logging) - A Log Service logging abstraction for Apache Celix.
+* [Syslog Writer](../bundles/logging/log_writers/syslog_writer) - A syslog writer for use in combination with the Log Service.
+* [Shell](../bundles/shell/README.html) - A OSGi C and C++11 shell implementation.
+* [Pubsub](../bundles/pubsub) - An implementation for a publish-subscribe remote message communication system. 
+* [HTTP Admin](../bundles/http_admin) - An implementation for the OSGi HTTP whiteboard adapted to C and based on civetweb.
+* [Remote Services](../bundles/cxx_remote_services) - A C++17 adaption and implementation of the OSGi Remote Service Admin specification.
+
+Standalone libraries:
+
+* [Etcd library](../libs/etcdlib) - A C library that interfaces with ETCD.
+* [Promises library](../libs/promises) - A C++17 header only adaption and implementation of the OSGi Promise specification.
+* [Push Streams Library](../libs/pushstreams) - A C++17 header adaption and only implementation of the OSGi Push Stream specification. 
\ No newline at end of file
diff --git a/source/docs/2.3.0/celix/examples/celix-examples/http_example/README.md b/source/docs/2.3.0/celix/examples/celix-examples/http_example/README.md
new file mode 100644
index 0000000..66a43cb
--- /dev/null
+++ b/source/docs/2.3.0/celix/examples/celix-examples/http_example/README.md
@@ -0,0 +1,33 @@
+---
+title: HTTP Example
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# HTTP Example
+
+This examples shows how the Celix HTTP Admin can be used. 
+
+This examples contains a `http_example` example bundle and uses the `Celix::http_admin` `Celix::shell` and `Celix::shell_wui` 
+bundles to create a `http_example_cnt` Celix container.
+
+The `http_example_cnt` Celix container shows how you can create a use existing http/websocket services.
+After running the container browse to localhost:8080. 
+Under the /shell uri you find the `Celix::shell_wui` functionality and under /hello uri you find the `http_example` functionality
diff --git a/source/docs/2.3.0/celix/examples/celix-examples/services_example_c/README.md b/source/docs/2.3.0/celix/examples/celix-examples/services_example_c/README.md
new file mode 100644
index 0000000..2b67664
--- /dev/null
+++ b/source/docs/2.3.0/celix/examples/celix-examples/services_example_c/README.md
@@ -0,0 +1,89 @@
+---
+title: Services example C
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Intro
+
+These examples shows howto create and interact with services by example.
+
+In both examples there is a provider and consumer bundle.
+The provider bundle creates services and registers them to the Celix framework so that these services are available for use.
+And the consumer bundle request the services from the Celix framework and uses them.
+
+The examples use the `celix_bundleContext_registerService` to provide
+services and uses a combination of `celix_bundleContext_useService`,
+`celix_bundleContext_useServices` and `celix_bundleContext_trackServices`
+to consume services.
+
+The bundle context is the proxy to the Celix framework for a bundle
+and can be used to:
+
+- Register services
+- Register service factories
+- Use services
+- Track services
+- Track bundles
+- Track service trackers
+
+See the `bundle_context.h` for documentation about these - and other -functions
+
+# Simple Service Provider & Consumer Example
+
+The simple provider/consumer example can be executed by launching the
+`services_example_c` executable target
+(build in the directory `${CMAKE_BUILD_DIR}/deploy/c_examples/services_example_c`)
+
+In this example the provider bundle only registers 1 calc service. And
+the consumer bundle tries to use this during startup and registered
+a service tracker for the calc service.
+
+```ditaa
++----------------------+                  +------------------------+
+|                      |                  |                        |
+|                      |                  |                        |
+|   provider_example   |   example_calc   |    consumer_example    |
+|                      +--------O)--------+                        |
+|       <bundle>       |                  |       <bundle>         |
+|                      |                  |                        |
+|                      |                  |                        |
++----------------------+                  +------------------------+
+```
+
+Try stopping/starting the provider/consumer bundles (respectively bundle id 3 & 4) using the interactive shell
+to see how this works at runtime. 
+I.e. type `stop 3`, `stop 4`, `start 3`, `start 4` in different combinations.
+
+
+# Dynamic Service Provider & Consumer Example
+
+The dynamic provider/consumer example can be executed by launching the
+`dynamic_services_example_c` executable target
+(build in `${CMAKE_BUILD_DIR}/deploy/c_examples/dynamic_services_example_c`)
+
+The dynamic service provide / consumer example show how the framework copes
+with the dynamic behaviour of services.
+
+This this example the provided dynamically register more and less calc services in a thread.
+The consumer bundle uses these services in a every 5 seconds and print some info.
+
+This example should give an idea how services can be safely used and tracked in a dynamic environment.
+
diff --git a/source/docs/2.3.0/celix/examples/celix-examples/services_example_cxx/README.md b/source/docs/2.3.0/celix/examples/celix-examples/services_example_cxx/README.md
new file mode 100644
index 0000000..056f5e7
--- /dev/null
+++ b/source/docs/2.3.0/celix/examples/celix-examples/services_example_cxx/README.md
@@ -0,0 +1,84 @@
+---
+title: Services Example C++
+type: celix-doc
+version: 2.3.0++
+---
+
+<!--
+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.
+-->
+
+# Intro
+
+These examples show howto create and interact with services by example.
+
+In both examples there is a provider and consumer bundle.
+The provider bundle creates services and registers them to the Celix framework so that these services are available for use.
+And the consumer bundle request the services from the Celix framework and uses them.
+
+The examples use the `celix::BundleContext::registerService` to provide
+services and uses a `celix::BundleContext::trackServices` to consume services.
+
+The bundle context is the proxy to the Celix framework for a bundle
+and can be used to:
+
+- Register services
+- Use services
+- Track services
+- Track bundles
+- Track service trackers
+
+See the `celix/BundleContext.h` for documentation about these - and other -functions
+
+# Simple Service Provider & Consumer Example
+
+The simple provider/consumer example can be executed by launching the
+`SimpleServicesExample` executable target
+(build in `${CMAKE_BUILD_DIR}/deploy/cxx_examples/SimpleServicesExample`)
+
+In this example the provider bundle only register one calc service. And
+the consumer bundle uses this service with use of a service tracker.
+
+```ditaa
++----------------------+                  +------------------------+
+|                      |                  |                        |
+|                      |                  |                        |
+|   SimpleProvider     | examples::ICalc  |    SimpleConsumer      |
+|                      +--------O)--------+                        |
+|       <bundle>       |                  |       <bundle>         |
+|                      |                  |                        |
+|                      |                  |                        |
++----------------------+                  +------------------------+
+```
+
+The effect of this can be examed by stopping and starting the provider/consumer bundles (respectively bundle id 3 & 4) using the interactive shell
+to see how this works at runtime.
+I.e. type `stop 3`, `stop 4`, `start 3`, `start 4` in different combinations.
+
+
+# Dynamic Service Provider & Consumer Example
+
+The dynamic provider/consumer example can be executed by launching the
+`DynamicServicesExample` executable target
+(build in `${CMAKE_BUILD_DIR}/deploy/cxx_examples/DynamicServicesExample`)
+
+The dynamic service provide / consumer example show howto handle the dynamic behavior
+of services. 
+
+In this example the provider dynamically register more and less ICalc services in a thread.
+The consumer create and destroy consumer for the ICalc services.
+
+This example should give an idea how services can be safely used and tracked in a dynamic environment.
\ No newline at end of file
diff --git a/source/docs/2.3.0/celix/examples/conan_test_package/README.md b/source/docs/2.3.0/celix/examples/conan_test_package/README.md
new file mode 100644
index 0000000..4e5c665
--- /dev/null
+++ b/source/docs/2.3.0/celix/examples/conan_test_package/README.md
@@ -0,0 +1,54 @@
+---
+title: Conan Test Package
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Conan Test Package
+
+> To learn API usage, we refer our users to `celix-examples` and various tests. The C/C++ source codes in this folder are NOT worth reading.
+
+This example is actually a classical Conan `test_package`, which is quite different from traditional tests. Its main purpose is to verify that 
+a Celix package is properly installed in the local Conan cache. To this end, it needs to make sure that:
+
+* Celix CMake commands are usable.
+* Public headers can be included.
+* Libraries are linkable.
+* Bundles are accessible to commands such as `add_celix_container`.
+
+To create a Celix package in the local cache with C++ support and verify that it's properly installed, run the following command in the Celix root directory:
+
+```BASH
+conan create . celix/2.2.3@zhengpeng/testing -tf examples/conan_test_package/ -o celix:celix_cxx=True
+```
+
+To verify a Celix package with C++ support is properly installed in the local cache, run the following command in the Celix root directory:
+
+```BASH
+conan test examples/conan_test_package/ celix/2.2.3@zhengpeng/testing  -o celix:celix_cxx=True
+```
+
+Though it might not be wise to spend time reading C/C++ codes in this folder, it's instructive to have a look at `conanfile.py` and `CMakeLists.txt`,
+which illustrates a non-intrusive way of using Conan with CMake build system. Pay attention to our use of `cmake_paths` `cmake_find_package` generators
+and the following line:
+
+```python
+    cmake.definitions["CMAKE_PROJECT_test_package_INCLUDE"] = os.path.join(self.build_folder, "conan_paths.cmake")
+```
diff --git a/source/docs/2.3.0/celix/libs/etcdlib/README.md b/source/docs/2.3.0/celix/libs/etcdlib/README.md
new file mode 100644
index 0000000..b9e85f8
--- /dev/null
+++ b/source/docs/2.3.0/celix/libs/etcdlib/README.md
@@ -0,0 +1,95 @@
+---
+title: Etcdlib
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Etcdlib
+etcd is a distributed, consistent key-value store for shared configuration and service discovery, part of the CoreOS project.
+
+This repository provides a library for etcd for C applications.
+It uses the v2 (REST) api of etcd.
+
+Etcdlib can be used as part of Celix but is also usable stand-alone.
+
+## Preparing
+The following packages (libraries + headers) should be installed on your system:
+
+* Development Environment
+  * build-essentials (gcc/g++ or clang/clang++)
+  * cmake (3.2 or higher)
+
+* Etcdlib Dependencies
+  * curl
+  * jansson
+
+## Download the Apache Celix sources
+To get started you first have to download the Apache Celix sources. This can be done by cloning the Apache Celix git repository:
+
+```bash
+# Create a new workspace to work in, e.g:
+mkdir -p ${HOME}/workspace
+export WS=${HOME}/workspace
+cd ${WS}
+
+# clone the repro
+git clone --single-branch --branch master https://github.com/apache/celix.git
+```
+
+## Building
+Etcdlib uses [CMake](https://cmake.org) as build system. CMake can generate (among others) makefiles or ninja build files. Using ninja build files will result in a faster build.
+
+### Building using CMake and makefiles:
+```bash
+cd ${WS}/celix/etcdlib
+mkdir build
+cd build
+cmake .. 
+make 
+```
+
+### Building using CMake and Ninja
+```bash
+cd ${WS}/celix/etcdlib
+mkdir build
+cd build
+cmake -G Ninja ..
+ninja
+```
+
+## Editing Build options
+With use of CMake, Etcdlib makes it possible to edit build options. This enabled users, among other options, to configure a install location.
+To edit the options use ccmake or cmake-gui. For cmake-gui an additional package install can be necessary (Fedora: `dnf install cmake-gui`). 
+
+```bash
+cd ${WS}/celix/etcdlib/build
+ccmake .
+# Edit the CMAKE_INSTALL_PREFIX config to set the install location
+```
+
+For this guide we assume the CMAKE_INSTALL_PREFIX is `/usr/local`.
+
+## Installing Etcdlib
+
+```bash
+cd ${WS}/celix/etcdlib/build
+make
+sudo make install
+```
diff --git a/source/docs/2.3.0/celix/libs/framework/doxygen.md b/source/docs/2.3.0/celix/libs/framework/doxygen.md
new file mode 100644
index 0000000..37befbf
--- /dev/null
+++ b/source/docs/2.3.0/celix/libs/framework/doxygen.md
@@ -0,0 +1,72 @@
+---
+title: doxygen.md
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Intro
+
+The main way to use Celix is through the bundle context of a bundle.
+When a bundle is started the bundle context will be injected in the bundle activator.
+
+Apache Celix is a C framework with a C and C++ (C++11) API. 
+
+## C Bundle Activator
+```
+#include <celix_api.h>
+
+typedef struct activator_data {
+    /*intentional empty*/
+} activator_data_t;
+
+static celix_status_t activator_start(activator_data_t *data, celix_bundle_context_t *ctx) {
+    //use the bundle context ctx to activate the bundle
+    return CELIX_SUCCESS;
+}
+
+static celix_status_t activator_stop(activator_data_t *data, celix_bundle_context_t *ctx) {
+    //use the bundle context ctx to cleanup
+    return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(activator_data_t, activator_start, activator_stop)
+```
+
+## C++ Bundle Activator
+```
+#include <celix/BundleActivator.h>
+
+class MyBundleActivator {
+public:
+    explicit MyBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+        //use the bundle context ctx to activate the bundle
+    }
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(MyBundleActivator)
+```
+
+# C API
+
+See include/celix_bundle_context.h as a starting point for the C API.
+
+# C++ API
+
+See celix::BundleContext as a starting point for the C++ API. 
diff --git a/source/docs/2.3.0/celix/libs/launcher/README.md b/source/docs/2.3.0/celix/libs/launcher/README.md
new file mode 100644
index 0000000..3f2b5c2
--- /dev/null
+++ b/source/docs/2.3.0/celix/libs/launcher/README.md
@@ -0,0 +1,56 @@
+---
+title: Launcher
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+## Launcher
+
+The Celix Launcher is a generic executable for launching the Framework. It reads a java properties based configuration file.
+
+The Launcher also passes the entire configuration to the Framework, this makes them available to the bundleContext_getProperty function.
+
+###### Properties
+
+    CELIX_AUTO_START_0                  Space delimited list of bundles to install and start when the
+                                        Framework is started. The is for runtime level 0, which is started first.
+
+    CELIX_AUTO_START_1                  Space delimited list of bundles to install and start when the
+                                        Framework is started. The is for runtime level 1.
+
+    CELIX_AUTO_START_2                  Space delimited list of bundles to install and start when the
+                                        Framework is started. The is for runtime level 2.
+
+    CELIX_AUTO_START_3                  Space delimited list of bundles to install and start when the
+                                        Framework is started. The is for runtime level 3.
+
+    CELIX_AUTO_START_4                  Space delimited list of bundles to install and start when the
+                                        Framework is started. The is for runtime level 4.
+
+    CELIX_AUTO_START_5                  Space delimited list of bundles to install and start when the
+                                        Framework is started. The is for runtime level 5, which is started last.
+
+    org.osgi.framework.storage          Sets the bundle cache directory
+
+    org.osgi.framework.storage.clean    If set to "onFirstInit", the bundle cache will be flushed
+                                        when the framework starts
+
+###### CMake option
+    BUILD_LAUNCHER=ON
diff --git a/source/docs/2.3.0/celix/libs/promises/README.md b/source/docs/2.3.0/celix/libs/promises/README.md
new file mode 100644
index 0000000..e35bdc2
--- /dev/null
+++ b/source/docs/2.3.0/celix/libs/promises/README.md
@@ -0,0 +1,93 @@
+---
+title: Promises
+type: celix-doc
+version: 2.3.0
+---
+
+# Celix Promises
+
+Celix Promises are based on the OSGi Promises Specification (OSGi Compendium Release 7 Specification, Chapter 705).
+It follows the specification as close as possible, but some adjustments are mode for C++17.
+
+NOTE: this implementation is still experiment and the api and behaviour will probably still change.  
+
+## OSGi Information
+
+[OSGi Compendium Release 7 Promises Specification (HTML)](https://osgi.org/specification/osgi.cmpn/7.0.0/util.promise.html)
+
+[OSGi Compendium Release 7 Specification (PDF)](https://osgi.org/specification/osgi.cmpn/7.0.0/util.promise.html)
+
+## Usage
+
+```C++
+//src/PromiseExample.cc
+#include <iostream>
+#include "celix/PromiseFactory.h"
+
+static long calc_fib(long n) {
+    long m = 1;
+    long k = 0;
+    for (long i = 0; i <= n; ++i) {
+        int tmp = m + k;
+        m = k;
+        k = tmp;
+    }
+    return m;
+}
+
+celix::Promise<long> fib(celix::PromiseFactory& factory, long n) {
+    return factory.deferredTask<long>([n](auto deferred) {
+        deferred.resolve(calc_fib(n));
+    });
+}
+
+int main() {
+    celix::PromiseFactory factory{};
+    
+    fib(factory, 1000000000)
+        .setTimeout(std::chrono::milliseconds {100})
+        .onSuccess([](long val) {
+            std::cout << "Success promise 1 : " << std::to_string(val) << std::endl;
+        })
+        .onFailure([](const std::exception& e) {
+            std::cerr << "Failure promise 1 : " << e.what() << std::endl;
+        });
+    
+    fib(factory, 39)
+        .setTimeout(std::chrono::milliseconds{100})
+        .onSuccess([](long val) {
+            std::cout << "Success promise 2 : " << std::to_string(val) << std::endl;
+        })
+        .onFailure([](const std::exception& e) {
+            std::cerr << "Failure promise 2 : " << e.what() << std::endl;
+        });
+    
+    //NOTE the program can only exit if the executor in the PromiseFactory is done executing all tasks.
+}
+```
+
+```cmake
+#CMakeLists.txt
+find_package(Celix REQUIRED)
+add_executable(PromiseExamples src/PromiseExamples.cc)
+target_link_libraries(PromiseExamples PRIVATE Celix::Promises)
+```
+
+## Differences with OSGi Promises & Java
+
+1. Promises must always be resolved, otherwise the Celix::Promises library will leak memory. To support this more easily the `Promise::setTimeout` method can be used to set a timeout on the current promise. 
+2. There is no singleton default executor. A PromiseFactory can be constructed argument-less to create a default executor, but this executor is then bound to the lifecycle of the PromiseFactory. If celix::IExecutor is injected in the PromiseFactory, it is up to user to control the complete lifecycle of the executor (e.g. by providing this in a ThreadExecutionModel bundle and ensuring this is started early (and as result stopped late).
+3. The default constructor for celix::Deferred has been removed. A celix:Deferred can only be created through a PromiseFactory. This is done because the promise concept is heavily bound with the execution abstraction and thus a execution model. Creating a Deferred without a explicit executor is not desirable.
+4. The PromiseFactory also has a deferredTask method. This is a convenient method create a Deferred, execute a task async to resolve the Deferred and return a Promise of the created Deferred in one call.
+5. The celix::IExecutor abstraction has a priority argument (and as result also the calls in PromiseFactory, etc).
+6. The IExecutor has a added wait() method. This can be used to ensure an executor is done executing the tasks backlog.
+7. The methods celix::Deferred<T>::fail and celix::Deferred<T>::resolve are robust for resolving a promise if it is already resolved. 
+  This is different from the OSGi spec and this is done because it always a race condition to check if a promise is already resolved (isDone()) and then resolve the promise. 
+  The methods `celix::Deferred<T>::tryFail` and `celix::Deferred<T>::tryResolve` can be used to resolve a promise and check if it was already resolved atomically.
+
+## Open Issues & TODOs
+
+- Documentation not complete
+- PromiseFactory is not complete yet
+- The static helper class Promises is not implemented yet (e.g. all/any)
+- Promise::flatMap not implemented yet
diff --git a/source/docs/2.3.0/celix/libs/pushstreams/README.md b/source/docs/2.3.0/celix/libs/pushstreams/README.md
new file mode 100644
index 0000000..634d544
--- /dev/null
+++ b/source/docs/2.3.0/celix/libs/pushstreams/README.md
@@ -0,0 +1,25 @@
+---
+title: PushStream
+type: celix-doc
+version: 2.3.0
+---
+
+# Celix PushStream
+
+Celix PushSteams are based on the OSGI Push Stream Specification (OSGi Compendium Release 7 Specification, Chapter 706).
+It follows the specification as close as possible, but some adjustments are mode for C++17.
+
+NOTE: this implementation is still experiment and the api and behaviour will probably still change.  
+
+## OSGi Information
+
+[OSGi Compendium Release 7 Promises Specification (HTML)](https://osgi.org/specification/osgi.cmpn/7.0.0/util.pushstream.html)
+
+[OSGi Compendium Release 7 Specification (PDF)](https://osgi.org/specification/osgi.cmpn/7.0.0/util.pushstream.html)
+
+## Usage
+
+## Differences with OSGi PushStreams & Java
+
+
+## Open Issues & TODOs
diff --git a/source/docs/2.3.0/celix/libs/utils/README.md b/source/docs/2.3.0/celix/libs/utils/README.md
new file mode 100644
index 0000000..29e01eb
--- /dev/null
+++ b/source/docs/2.3.0/celix/libs/utils/README.md
@@ -0,0 +1,32 @@
+---
+title: Utils
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+## Utils
+
+Celix Utils contains several useful containers/lists implementation used with the Celix project. The following types are available:
+
+    Array List
+    Celix Thread Container
+    Hash Map
+    Linked List
+    Thread Pool
diff --git a/source/docs/2.3.0/celix/libs/utils/docs/thpool/Design.md b/source/docs/2.3.0/celix/libs/utils/docs/thpool/Design.md
new file mode 100644
index 0000000..1c38e1e
--- /dev/null
+++ b/source/docs/2.3.0/celix/libs/utils/docs/thpool/Design.md
@@ -0,0 +1,58 @@
+---
+title: Design.md
+type: celix-doc
+version: 2.3.0
+---
+
+## High level
+	
+	Description: Library providing a threading pool where you can add work on the fly. The number
+	             of threads in the pool is adjustable when creating the pool. In most cases
+	             this should equal the number of threads supported by your cpu.
+	         
+	             For an example on how to use the threadpool, check the main.c file or just read
+	             the documentation found in the README.md file.
+	
+	             In this header file a detailed overview of the functions and the threadpool's logical
+	             scheme is presented in case you wish to tweak or alter something. 
+	
+	
+	
+	              _______________________________________________________        
+	            /                                                       \
+	            |   JOB QUEUE        | job1 | job2 | job3 | job4 | ..   |
+	            |                                                       |
+	            |   threadpool      | thread1 | thread2 | ..            |
+	            \_______________________________________________________/
+	
+	
+	   Description:       Jobs are added to the job queue. Once a thread in the pool
+	                      is idle, it is assigned with the first job from the queue(and
+	                      erased from the queue). It's each thread's job to read from 
+	                      the queue serially(using lock) and executing each job
+	                      until the queue is empty.
+	
+	
+	   Scheme:
+	
+	   thpool______                jobqueue____                      ______ 
+	   |           |               |           |       .----------->|_job0_| Newly added job
+	   |           |               |  rear  ----------'             |_job1_|
+	   | jobqueue----------------->|           |                    |_job2_|
+	   |           |               |  front ----------.             |__..__| 
+	   |___________|               |___________|       '----------->|_jobn_| Job for thread to take
+	
+	
+	   job0________ 
+	   |           |
+	   | function---->
+	   |           |
+	   |   arg------->
+	   |           |         job1________ 
+	   |  next-------------->|           |
+	   |___________|         |           |..
+
+
+## Synchronisation
+
+*Mutexes* and *binary semaphores* are the main tools to achieve synchronisation between threads.
diff --git a/source/docs/2.3.0/celix/libs/utils/docs/thpool/FAQ.md b/source/docs/2.3.0/celix/libs/utils/docs/thpool/FAQ.md
new file mode 100644
index 0000000..71960c3
--- /dev/null
+++ b/source/docs/2.3.0/celix/libs/utils/docs/thpool/FAQ.md
@@ -0,0 +1,39 @@
+---
+title: FAQ.md
+type: celix-doc
+version: 2.3.0
+---
+
+
+### Why isn't pthread_exit() used to exit a thread?
+`thread_do` used to use pthread_exit(). However that resulted in
+hard times of testing for memory leaks. The reason is that on pthread_exit()
+not all memory is freed bt pthread (probably for future threads or false
+belief that the application is terminating). For these reasons a simple return
+is used.
+
+Interestingly using `pthread_exit()` results in much more memory being allocated.
+
+
+### Why do you use sleep() after calling thpool_destroy()?
+This is needed only in the tests. The reason is that if you call thpool_destroy
+and then exit immediately, maybe the program will exit before all the threads
+had the time to deallocate. In that way it is impossible to check for memory
+leaks.
+
+In production you don't have to worry about this since if you call exit,
+immediately after you destroyed the pool, the threads will be freed
+anyway by the OS. If you either way destroy the pool in the middle of your
+program it doesn't matter again since the program will not exit immediately
+and thus threads will have more than enough time to terminate.
+
+
+
+### Why does wait() use all my CPU?
+Normally `wait()` will spike CPU usage to full when called. This is normal as long as it doesn't last for more than 1 second. The reason this happens is that `wait()` goes through various phases of polling (what is called smart polling).
+
+ * Initially there is no interval between polling and hence the 100% use of your CPU.
+ * After that the polling interval grows exponentially.
+ * Finally after x seconds, if there is still work, polling falls back to a very big interval.
+ 
+The reason `wait()` works in this way, is that the function is mostly used when someone wants to wait for some calculation to finish. So if the calculation is assumed to take a long time then we don't want to poll too often. Still we want to poll fast in case the calculation is a simple one. To solve these two problems, this seemingly awkward behaviour is present.
diff --git a/source/docs/2.3.0/celix/libs/utils/docs/thpool/README.md b/source/docs/2.3.0/celix/libs/utils/docs/thpool/README.md
new file mode 100644
index 0000000..4f5abbd
--- /dev/null
+++ b/source/docs/2.3.0/celix/libs/utils/docs/thpool/README.md
@@ -0,0 +1,68 @@
+---
+title: README.md
+type: celix-doc
+version: 2.3.0
+---
+
+![Build status](http://178.62.170.124:3000/pithikos/c-thread-pool/badge/?branch=master)
+
+# C Thread Pool
+
+This is a minimal but fully functional threadpool implementation.
+
+  * ANCI C and POSIX compliant
+  * Number of threads can be chosen on initialization
+  * Minimal but powerful interface
+  * Full documentation
+
+The threadpool is under MIT license. Notice that this project took a considerable amount of work and sacrifice of my free time and the reason I give it for free (even for commercial use) is so when you become rich and wealthy you don't forget about us open-source creatures of the night. Cheers!
+
+
+## v2 Changes
+
+This is an updated and heavily refactored version of my original threadpool. The main things taken into consideration in this new version are:
+
+  * Synchronisation control from the user (pause/resume/wait)
+  * Thorough testing for memory leaks and race conditions
+  * Cleaner and more opaque API
+  * Smart polling - polling interval changes on-the-fly
+
+
+## Run an example
+
+The library is not precompiled so you have to compile it with your project. The thread pool
+uses POSIX threads so if you compile with gcc on Linux you have to use the flag `-pthread` like this:
+
+    gcc example.c thpool.c -D THPOOL_DEBUG -pthread -o example
+
+
+Then run the executable like this:
+
+    ./example
+
+
+## Basic usage
+
+1. Include the header in your source file: `#include "thpool.h"`
+2. Create a thread pool with number of threads you want: `threadpool thpool = thpool_init(4);`
+3. Add work to the pool: `thpool_add_work(thpool, (void*)function_p, (void*)arg_p);`
+
+The workers(threads) will start their work automatically as fast as there is new work
+in the pool. If you want to wait for all added work to be finished before continuing
+you can use `thpool_wait(thpool);`. If you want to destroy the pool you can use
+`thpool_destroy(thpool);`.
+
+
+
+## API
+
+For a deeper look into the documentation check in the [thpool.h](https://github.com/Pithikos/C-Thread-Pool/blob/master/thpool.h) file. Below is a fast practical overview.
+
+| Function example                | Description                                                         |
+|---------------------------------|---------------------------------------------------------------------|
+| ***thpool_init(4)***            | Will return a new threadpool with `4` threads.                        |
+| ***thpool_add_work(thpool, (void&#42;)function_p, (void&#42;)arg_p)*** | Will add new work to the pool. Work is simply a function. You can pass a single argument to the function if you wish. If not, `NULL` should be passed. |
+| ***thpool_wait(thpool)***       | Will wait for all jobs (both in queue and currently running) to finish. |
+| ***thpool_destroy(thpool)***    | This will destroy the threadpool. If jobs are currently being executed, then it will wait for them to finish. |
+| ***thpool_pause(thpool)***      | All threads in the threadpool will pause no matter if they are idle or executing work. |
+| ***thpool_resume(thpool)***      | If the threadpool is paused, then all threads will resume from where they were.   |
diff --git a/source/docs/2.3.0/celix/libs/utils/include/memstream/README.md b/source/docs/2.3.0/celix/libs/utils/include/memstream/README.md
new file mode 100644
index 0000000..129c4db
--- /dev/null
+++ b/source/docs/2.3.0/celix/libs/utils/include/memstream/README.md
@@ -0,0 +1,55 @@
+---
+title: README.md
+type: celix-doc
+version: 2.3.0
+---
+
+fmemopen for Mac OS and iOS
+===========================
+
+Originally ported from [ingenuitas python-tesseract](https://github.com/ingenuitas/python-tesseract/blob/master/fmemopen.c). Ported by Jeff Verkoeyen under the Apache 2.0 License.
+
+From the fmemopen man page:
+
+> FILE *fmemopen(void *buf, size_t size, const char *mode);
+>
+> The fmemopen() function opens a stream that permits the access specified by mode. The stream
+> allows I/O to be performed on the string or memory buffer pointed to by buf. This buffer must be
+> at least size bytes long.
+
+Alas, this method does not exist on BSD operating systems (specifically Mac OS X and iOS). It is
+possible to recreate this functionality using a BSD-specific method called `funopen`.
+
+From the funopen man page:
+
+> FILE * funopen(const void *cookie, int (*readfn)(void *, char *, int),
+>                int (*writefn)(void *, const char *, int), fpos_t (*seekfn)(void *, fpos_t, int),
+>                int (*closefn)(void *));
+>
+> The funopen() function associates a stream with up to four ``I/O functions''.  Either readfn or
+> writefn must be specified; the others can be given as an appropriately-typed NULL pointer.  These
+> I/O functions will be used to read, write, seek and close the new stream.
+
+fmemopen.c provides a simple implementation of fmemopen using funopen so that you can create FILE
+pointers to blocks of memory.
+
+Adding it to your Project
+=========================
+
+Drag fmemopen.h and fmemopen.c to your project and add them to your target. `#include "fmemopen.h"`
+wherever you need to use `fmemopen`.
+
+Examples
+========
+
+```obj-c
+#import "fmemopen.h"
+
+NSString* string = @"fmemopen in Objective-C";
+const char* cstr = [string UTF8String];
+FILE* file = fmemopen((void *)cstr, sizeof(char) * (string.length + 1), "r");
+
+// fread on file will now read the contents of the NSString
+
+fclose(file);
+```
diff --git a/source/docs/2.3.0/celix/misc/experimental/README.md b/source/docs/2.3.0/celix/misc/experimental/README.md
new file mode 100644
index 0000000..ef6bee3
--- /dev/null
+++ b/source/docs/2.3.0/celix/misc/experimental/README.md
@@ -0,0 +1,27 @@
+---
+title: Experimental
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Intro
+
+This directory contains experimental bundles and libraries.
+These bundles/libraries are not considered stable and/or their API can still drastically change.
diff --git a/source/docs/2.3.0/celix/misc/experimental/bundles/config_admin/README.md b/source/docs/2.3.0/celix/misc/experimental/bundles/config_admin/README.md
new file mode 100644
index 0000000..b379c5e
--- /dev/null
+++ b/source/docs/2.3.0/celix/misc/experimental/bundles/config_admin/README.md
@@ -0,0 +1,60 @@
+---
+title: Configuration Admin
+type: celix-doc
+version: 2.3.0
+---
+
+<!--
+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.
+-->
+
+# Configuration Admin
+
+---
+
+## Introduction
+The configuration Admin service allows defining and deploying configuration data to bundles.
+When compared to config.properties it adds the option to update configuration data by providing a persistent storage. It also allows changing configuration data at run-time.
+
+---
+
+## Design
+
+The config_admin bundle implements the configuration_admin service, the interface to configuration objects and the interface of a managed service. At the moment, the implementation uses a config_admin_factory to generate config_admin services for each bundle that wants to use this service. This is an inheritance of the original design and not needed.
+The configuration data is stored persistently in a subdirectory store of the current bundle directory. 
+The filenames have the name of the PID and have an extension pid, e.g. base.device1.pid
+The files contains a list of key/value pairs. At least the following keys need to be present:
+service.bundleLocation
+service.pid
+
+---
+
+## TODO
+
+1. Test the configuration of a service_factory
+2. Think about the option to allow remote update of the managed_services
+3. Support configuration of multiple managed services with the same PID. At the moment, only one service is bound to a configuration object.
+   To support this the getConfiguration2 function needs to be called with a location NULL according to the spec.
+
+---
+
+## Usage
+
+1. Bundle that needs configuration data
+   This bundle has to register next to its normal service a managed service that has an update method. This managed service needs to be registered with a properties object that contains the key/value pair service.pid=<PID NAME>.
+ Use config_admin_tst/example_test as an example (it is better than example_test2)
+2. Bundle/application that wants to update the configuration data of the system
+   This bundle needs to retrieve the running config_admin service. With this service it can retrieve all configuration objects for all known Persistent Identifiers (PIDs). For each PID, get all properties that need to be updated. See config_admin_test for an example.


[celix-site] 02/02: Update news for latest release

Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/update_after_release
in repository https://gitbox.apache.org/repos/asf/celix-site.git

commit a9d9c545440235dea044b5f23a398a4e385b1e02
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Thu Jul 14 19:49:32 2022 +0200

    Update news for latest release
---
 layouts/index.html | 1 +
 1 file changed, 1 insertion(+)

diff --git a/layouts/index.html b/layouts/index.html
index 75271b7..8890d07 100644
--- a/layouts/index.html
+++ b/layouts/index.html
@@ -104,6 +104,7 @@ limitations under the License.
                 <div class="card-body">
                     <h4 class="card-title">News</h4>
                     <p class="card-text">
+                        <strong>14-July-2022</strong> - After a successful vote Celix 2.3.0 is released.<br>
                         <strong>17-May-2020</strong> - After a successful vote Celix 2.2.1 is released.<br>
                         <strong>09-Jan-2020</strong> - After a successful vote Celix 2.2.0 is released.<br>
                         <strong>30-Jan-2018</strong> - After a successful vote Celix 2.1.0 is released.<br>