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

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

commit 965f7c6e6f470b576cdcf47b64185ffb660ae2f5
Author: Pepijn Noltes <[email protected]>
AuthorDate: Sun May 22 22:17:11 2022 +0200

    Adds dm component document and examples.
    
    Also adds support for configuring a component implementation destroy 
function
    so that C component bundle activator can operate with less boilerplate code.
---
 documents/components.md                            | 693 +++++++++++++++++----
 .../dm_example/phase1/src/phase1_activator.c       |  10 +-
 .../dm_example/phase2a/src/phase2a_activator.c     |  10 +-
 .../dm_example/phase2b/src/phase2b_activator.c     |   6 +-
 .../dm_example/phase3/src/phase3_activator.c       |  16 +-
 .../readme_c_examples/CMakeLists.txt               |  20 +
 .../component_with_provided_service_activator.c    |  90 +++
 .../component_with_service_dependency_activator.c  | 123 ++++
 .../src/simple_component_activator.c               |  92 +++
 .../readme_cxx_examples/CMakeLists.txt             |  22 +-
 .../src/ComponentWithProvidedServiceActivator.cc   |  69 ++
 .../src/ComponentWithServiceDependencyActivator.cc |  75 +++
 .../src/SimpleComponentActivator.cc                |  57 ++
 .../gtest/src/DependencyManagerTestSuite.cc        |  37 ++
 libs/framework/include/celix_bundle_activator.h    |  35 +-
 libs/framework/include/celix_dependency_manager.h  |  12 +-
 libs/framework/include/celix_dm_component.h        |  55 +-
 libs/framework/src/dm_component_impl.c             |  24 +-
 18 files changed, 1256 insertions(+), 190 deletions(-)

diff --git a/documents/components.md b/documents/components.md
index f0dcb5dc..5f8c96fb 100644
--- a/documents/components.md
+++ b/documents/components.md
@@ -19,203 +19,626 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 -->
 
-# Apache Celix Components
-
 TODO refactor this documentation file
+TODO also describes when cmp is suspended: there is a svc dep with 
suspend-strategy and the set or add/rem
+callback is configured.
 
-## Introduction
-
-The Dependency Manager contains a static library which can be used to manage 
(dynamic) services on a higher abstraction level in a declarative style.
-The Apache Celix Dependency Manager is inspired by the [Apache Felix 
Dependency 
Manager](http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager.html).
-
-## Components
-
-Components are the main building blocks for OSGi applications. They can 
publish services, and/or they can have dependencies. These dependencies will 
influence their life cycle as component will only be activated when all 
required dependencies are available.
-
-Within Apache Celix a component is expected to have a set of functions where 
the first argument is a handle to the component (e.g. self/this). How this is 
achieved is up the the user, for some examples how this can be done see the 
example in the Apache Celix Project.
-
-The Dependency Manager, as part of a bundle, shares the generic bundle life 
cycle explained in the OSGi specification.
-Each component you define gets its own life cycle. The component life cycle is 
depicted in the state diagram below.
+# 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 service and have services dependencies. 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 DM Component you define gets 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; Lifecycle 
callbacks are always called from the
+Celix event thread. 
+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`.
+
+A DM 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: 
+  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 `init` callback new service 
dependencies was added or that the component
+  was active, but a required service dependency is removed and as result the 
component is not active anymore._
+- `Starting`: _The component has found its required dependencies and is 
starting: Calling the `start` callback and
+  registering it's 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:
+  Unregistering its 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: Calling the `start` callback and registering its provided services.
+- `Stopping`: _The component has lost one or more of its required dependencies 
and is stopping: Unregistering its
+  provided service and calling the `stop` callback._
+- `Deinitializing`: _The component is being removed and is deinitializing: 
Calling the `deinit` callback._
+
+## 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 follow a
+    component approach (one argument with the component implementation pointer 
as type)
+ 3. Creates the DM component, but note that this component is not yet known to 
the DM. This makes it possible to
+    first configure the DM component over multiple function calls, before 
adding - and as result 
+    activating - the DM component 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 activate manage the 
component.
+ 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 component 
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 Life Cycle](doc-images/statediagram.png)
+//********************* COMPONENT *******************************/
 
-Changes in the state of the component will trigger the following life cycle 
callback functions:
+typedef struct simple_component {
+    int transitionCount; //not protected, only updated and read in the celix 
event thread.
+} simple_component_t;
 
-    `init`,
-    `start`,
-    `stop` and
-    `deinit`.
+static simple_component_t* simpleComponent_create() {
+    simple_component_t* cmp = calloc(1, sizeof(*cmp));
+    cmp->transitionCount = 1;
+    return cmp;
+}
 
-The callback functions can be specified by using the component_setCallbacks.
+static void simpleComponent_destroy(simple_component_t* cmp) {
+    free(cmp);
+}
 
-## DM Parts
+static int simpleComponent_init(simple_component_t* cmp) { // 
<------------------------------------------------------<1>
+    printf("Initializing simple component. Transition nr %i\n", 
cmp->transitionCount++);
+    return 0;
+}
 
-The Dependency Manager consist out of four main parts: `DM (Dependency 
Manager) Activator`, `Dependency Manager`, `DM Component` and `DM Service 
Dependency`.
+static int simpleComponent_start(simple_component_t* cmp) {
+    printf("Starting simple component. Transition nr %i\n", 
cmp->transitionCount++);
+    return 0;
+}
 
-### DM Activator
+static int simpleComponent_stop(simple_component_t* cmp) {
+    printf("Stopping simple component. Transition nr %i\n", 
cmp->transitionCount++);
+    return 0;
+}
 
-The `DM Activator` implements a "normal" Celix bundle activator and depends on 
four functions which needs to be implemented by the user of the Dependency 
Manager:
-- `dm_create` : Should be used to allocated and initialize a dm activator 
structure. If needed this structure can be used to store object during the 
lifecycle of the bundle.
-- `dm_init` : Should be used to interact with the `Dependency Manager`. Here a 
user can components, service dependencies and provided services.
-- `dm_destroy` : Should be used to deinitialize and deallocate objects created 
in the `dm_create` function.
+static int simpleComponent_deinit(simple_component_t* cmp) {
+    printf("De-initializing simple component. Transition nr %i\n", 
cmp->transitionCount++);
+    return 0;
+}
 
 
-### Dependency Manager
+//********************* 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;
+}
 
-The `Dependency Manager` act as an entry point to add or remove DM Components. 
The `Dependency Manager` is provided to the `dm_init` function.
+CELIX_GEN_BUNDLE_ACTIVATOR(simple_component_activator_t, 
simpleComponentActivator_start, NULL) // <------------------<8>
+```
 
-### DM Component
+## 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 components and also ensures that component 
implementations are kept in scope for as
+long as the components are 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 activate them. This way C++ components can be build using a fluent 
api and marked ready with a `build()`
+   method call. 
+   As component implementation the DM accepts a unique_pt, shared_ptr, value 
type of 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 as object instance.
+5. "Builds" the component. C++ component 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 as ready (build).
+   The generated C++ bundle activator will also enable all components created 
during the bundle activation, 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;
+    }
 
-The `DM Component` manages the life cycle of a component. For example, when 
all required service dependencies are available the `DM Component` will call 
the `start` specified callback function of the component.
+    void start() {
+        std::cout << "starting simple component. Transition nr " << 
transitionCount++ << std::endl;
+    }
 
-The `component_setImplementation` function can be used to specify which 
component handle to use.
-The `component_addInterface` can be used to specify one additional service 
provided by the component.
-The `component_addServiceDependency` can be used to specify one additional 
service dependency.
+    void stop() {
+        std::cout << "Stopping simple component. Transition nr " << 
transitionCount++ << std::endl;
+    }
 
-### Dm Service Dependency
+    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.
+};
 
-The `DM Service Dependency` can be used to specify service dependencies for a 
component. i
+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>
+    }
+};
 
-When these dependencies are set to required the `DM Component` will ensure 
that components will only be started when all required dependencies are 
available and stop the component if any of the required dependencies are 
removed.
-This feature should prevent a lot of boiler plating code compared to using a 
service tracker or services references directly.
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(SimpleComponentActivator)
+```
 
-A service dependency update strategy can also be specified. Default this 
strategy is set to `DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND` this strategy will 
stop and start (suspend) a component when any of the specified service 
dependencies change (are removed, added or modified).
-When correctly used this strategy removes the need for locking services during 
updates/invocation. See the dependency manager example for more details.
+# Component's Provided Services
+Components can be configured to provide services. These provided services will 
correspondent to service registration 
+when a component is in the `Tracking Optional` state. 
 
-The `serviceDependency_setCallbacks` function can be used to specify the 
function callback used when services are added, set, removed or modified.
-The `serviceDependency_setRequired` function can be used to specify if a 
service dependency is required.
-The `serviceDependency_setStrategy` function can be used to specify a service 
dependency update strategy (suspend or locking).
+If a component provide services, these service will have an additional 
metadata property - named "component.uuid"
+that couples the services to the component named "component.uuid".
 
-### Snippets
+## Example: Component with a provided service in C
+The following example shows how a component that provide a 
`celix_shell_command` service. 
 
-#### DM Bundle Activator
+Remarks for the C example:
+1. C and 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 if the component enters the state `Tracking 
Optional`.
 
-The next snippet shows a dm bundle activator and how to add components to the 
dependency manager.
 ```C
-
-//exmpl_activator.c
-#include <dm_activator.h>
+ //src/component_with_provided_service_activator.c
 #include <stdlib.h>
+#include <celix_api.h>
+#include <celix_shell_command.h>
 
-struct dm_exmpl_activator {
-    exmpl_t* exmpl;
-};
-
-celix_status_t dm_create(bundle_context_pt context, void **userData) {         
                                                                                
                                                    
-    *userData = calloc(1, sizeof(struct dm_exmpl_activator));
-    return *userData != NULL ? CELIX_SUCCESS : CELIX_ENOMEM;
-}
-
-celix_status_t dm_init(void * userData, bundle_context_pt context, 
dm_dependency_manager_pt manager) {
-    celix_status_t status = CELIX_SUCCESS;
-    struct dm_exmpl_activator *act = (struct dm_exmpl_activator*)userData;
+//********************* COMPONENT *******************************/
 
-    act->exmpl = exmpl_create();
-    if (act->exmpl != NULL) {
-        dm_component_pt cmp;
-        component_create(context, "Example Component", &cmp);
-        component_setImplementation(cmp, act->exmpl);
+typedef struct component_with_provided_service {
+    int callCount; //atomic
+} component_with_provided_service_t;
 
-        dependencyManager_add(manager, cmp);
-    } else {
-        status = CELIX_ENOMEM;
-    }
-
-    return status;
+static component_with_provided_service_t* 
componentWithProvidedService_create() {
+    component_with_provided_service_t* cmp = calloc(1, sizeof(*cmp));
+    return cmp;
 }
 
-celix_status_t dm_destroy(void * userData, bundle_context_pt context, 
dm_dependency_manager_pt manager) {
-    celix_status_t status = CELIX_SUCCESS;
-    struct dm_exmpl_activator *act = (struct dm_exmpl_activator*)userData;
+static void 
componentWithProvidedService_destroy(component_with_provided_service_t* cmp) {
+    free(cmp);
+}
 
-    if (act->exmpl != NULL) {
-        exmpl_destroy(act->exmpl);
-    }
-    free(act);
+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;
-}  
-```
-
-### References
+}
 
-For more information examples please see
+CELIX_GEN_BUNDLE_ACTIVATOR(
+        component_with_provided_service_activator_t,
+        componentWithProvidedServiceActivator_start,
+        NULL)
+```
 
-- [The Dependency Manager API](../../libs/framework/include/celix/dm): The 
dependency manager header files
-- [Getting Started: Using Service with 
C](../getting_started/using_services_with_c.md): A introduction how to work 
with services using the dependency manager
-- [Dm example](../../examples/celix-examples/dm_example): A DM example.
+## 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 `elix_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 if the component 
enters the state `Tracking Optional`.
+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 function 
pointers. 
+7. Configures the component to provide a C `celix_shell_command_t` service. 
Note that for a C service, the service
+   interface struct also needs to be stored to ensure that the service 
interface struct will outlive the component.
+   The service will not directly be registered, but instead will be registered 
if the component enters the state
+   `Tracking Optional`..
+8. "Build" the component so the DM will manage and try to activate 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};
+};
 
-## Dependency Manager Shell support
+class ComponentWithProvidedServiceActivator {
+public:
+    explicit ComponentWithProvidedServiceActivator(const 
std::shared_ptr<celix::BundleContext>& ctx) {
+        auto& cmp = 
ctx->getDependencyManager()->createComponent<ComponentWithProvidedService>(); 
// <---------------<4>
 
-There is support for retrieving information of the dm components with
-use of the `dm` command. This command will print all known dm component,
-their state, provided interfaces and required interfaces.
+        cmp.createProvidedService<celix::IShellCommand>()
+            .addProperty(celix::IShellCommand::COMMAND_NAME, 
"HelloComponent"); // <---------------------------------<5>
 
+        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.createProvidedCService(&shellCmd, CELIX_SHELL_COMMAND_SERVICE_NAME)
+            .addProperty(CELIX_SHELL_COMMAND_NAME, "hello_component"); // < 
-----------------------------------------<7>
 
-# Apache Celix C++ Dependency Manager
+        cmp.build(); // 
<--------------------------------------------------------------------------------------------<8>
+    }
+private:
+    celix_shell_command_t shellCmd{nullptr, nullptr};
+};
 
-## Introduction
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(ComponentWithProvidedServiceActivator)
+```
 
-The C++ Dependency Manager contains a static library which can be used to 
manage (dynamic) services on a higher abstraction level in a declarative style.
-The Apache Celix C++ Dependency Manager is inspired by the [Apache Felix 
Dependency 
Manager](http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager.html).
+# 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; 
+
+When configuring service dependencies, callbacks can be configured when 
services are being added, removed or when a 
+new highest ranking service is available. It is also possible to configure 
callbacks which only inject/remove service 
+pointers, or service pointers with their properties (metadata) and even 
service pointers with their properties and
+their providing bundle. 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 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. 
+- 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 `stop` callback no active thread, 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 service. 
+
+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 
metadata properties. 
+
+Remarks for the C example:
+1. TODO
 
-The C++ Dependency Manager uses fluent interface to make specifying DM 
components and service dependencies very concise and relies on features 
introduced in C++11.
+```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;
+    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);
+    cmp->cmdShells = celix_arrayList_create();
+    return cmp;
+}
 
-## C++ and C Dependency Manager
+static void 
componentWithServiceDependency_destroy(component_with_service_dependency_t* 
cmp) {
+    celix_arrayList_destroy(cmp->cmdShells);
+    celixThreadMutex_destroy(&cmp->mutex);
+    free(cmp);
+}
 
-The C++ Dependency Manager is build on top of the C Dependency Manager.
-To get a good overview of the C++ Dependency Manager please read the 
[Dependency Manager documentation](../../documents/components/README.md)
+static void componentWithServiceDependency_setHighestRankingShellCommand(
+        component_with_service_dependency_t* cmp,
+        celix_shell_command_t* shellCmd) {
+    printf("New highest ranking service (can be NULL): %p\n", shellCmd);
+    cmp->highestRankingCmdShell = shellCmd;
+}
 
-## DM Parts
+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);
+    celix_arrayList_add(cmp->cmdShells, shellCmd);
+    celixThreadMutex_unlock(&cmp->mutex);
+}
 
-The C++ Dependency Manager consist out of four main parts: 
`celix::dm::DmActivator`, `celix::dm::DependencyManager`, 
`celix::dm::Component` and `celix::dm::ServiceDependency`.
+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, shellCmd);
+    celixThreadMutex_unlock(&cmp->mutex);
+}
 
-### DmActivator
+//********************* 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();
+    celix_dmServiceDependency_setService(dep1, 
CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL);
+    celix_dmServiceDependency_setStrategy(dep1, 
DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND);
+    celix_dmServiceDependency_setRequired(dep1, true);
+    celix_dm_service_dependency_callback_options_t opts1 = 
CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS;
+    opts1.set = 
(void*)componentWithServiceDependency_setHighestRankingShellCommand;
+    celix_dmServiceDependency_setCallbacksWithOptions(dep1, &opts1);
+    celix_dmComponent_addServiceDependency(dmCmp, dep1);
+
+    //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);
+    celix_dmServiceDependency_setRequired(dep2, false);
+    celix_dm_service_dependency_callback_options_t opts2 = 
CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS;
+    opts2.addWithProps = (void*)componentWithServiceDependency_addShellCommand;
+    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;
+}
 
-The `DmActivator` class should be inherited by a bundle specific Activator.
+CELIX_GEN_BUNDLE_ACTIVATOR(
+        component_with_service_dependency_activator_t,
+        componentWithServiceDependencyActivator_start,
+        NULL)
+```
 
-- The static `DmActivator::create` method needs to be implemented and should 
return a bundle specific subclass instance of the DmActivator.
-- The `DmActivator::init` method should be overridden and can be used to 
specify which components to use in the bundle.
-- The `DmActivator::deinit` method can be overridden if some cleanup is needed 
when a bundle is stopped.
+## 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.
 
-### Dependency Manager
+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 `DependencyManager` act as an entry point to create (DM) Components.
+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 
metadata properties.
 
-### Component
+Note that for C++ component service dependencies there is no real different 
between a C++ or a C service; Both
+are injected as shared_ptr, and as optional properties or bundle argument the 
C++ variant are provided.
 
-The (DM) `Component` manages the life cycle of a component (of the template 
type T). For example, when all required service dependencies are available the 
`Component` will call the `start` specified callback function of the component.
+Remarks for the C++ example:
+1. TODO
 
-- The `Component::setInstance` method can be used to set the component 
instance to used. If no instance is set the (DM) `Component` will (lazy) create 
a component instance using the default constructor.
-- The `Component::addInterface` method can be used to specify one additional 
C++ service provided by the component.
-- The `Component::addCInterface` method can be used to specify one additional 
C service provided by the component.
-- The `Component::createServiceDependency` method can be used to specify one 
additional typed C++ service dependency.
-- The `Component::createCServiceDependency` method can be used to specify one 
additional typed C service dependency.
+```C++
+//src/ComponentWithServiceDependencyActivator.cc
+#include <celix/BundleActivator.h>
+#include <celix/IShellCommand.h>
+#include <celix_shell_command.h>
 
-### ServiceDependency and CServiceDependency
+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;
+    }
 
-The (DM) `ServiceDependency` can be used to specify C++ service dependencies 
for a component and the (DM) `CServiceDependency` can be used to specify C 
service dependencies for a component.
+    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};
+        shellCommands.emplace(id, cmdSvc);
+    }
 
-When these dependencies are set to required the `Component` will ensure that 
components will only be started when all required dependencies are available 
and stop the component if any of the required dependencies are removed.
-This feature should prevent a lot of boiler plating code compared to using a 
service tracker or services references directly.
+    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 below
+    std::unordered_map<long, std::shared_ptr<celix_shell_command_t>> 
shellCommands{};
+};
 
-A service dependency update strategy can also be specified (suspend or 
locking. Default this strategy is set to `DependencyUpdateStrategy::suspend` 
this strategy will stop and start (suspend) a component when any of the 
specified service dependencies changes (are removed, added or modified).
-When correctly used this strategy removes the need for locking services during 
updates/invocation. See the dependency manager_cxx example for more details.
+class ComponentWithServiceDependencyActivator {
+public:
+    explicit ComponentWithServiceDependencyActivator(const 
std::shared_ptr<celix::BundleContext>& ctx) {
+        using Cmp = ComponentWithServiceDependency;
+        auto& cmp = ctx->getDependencyManager()->createComponent<Cmp>(); // 
<-------------<1>
 
-- The `(C)ServiceDependency::setCallbacks` methods can be used to specify the 
function callback used when services are added, set, removed or modified.
-- The `(C)ServiceDependency::setRequired` methods can be used to specify if a 
service dependency is required.
-- The `(C)ServiceDependency::setStrategy` methods can be used to specify the 
service dependency update strategy (suspend or locking).
+        cmp.createServiceDependency<celix::IShellCommand>()
+                .setCallbacks(&Cmp::setHighestRankingShellCommand)
+                .setRequired(true)
+                .setStrategy(DependencyUpdateStrategy::suspend);
 
-### References
+        
cmp.createServiceDependency<celix_shell_command_t>(CELIX_SHELL_COMMAND_SERVICE_NAME)
+                .setCallbacks(&Cmp::addCShellCmd, &Cmp::removeCShellCmd)
+                .setRequired(false)
+                .setStrategy(DependencyUpdateStrategy::locking);
 
-For more information examples please see
+        cmp.build(); // 
<--------------------------------------------------------------------------------------------<8>
+    }
+};
 
-- [The C++ Dependency Manager API](../../libs/framework/include): The C++ 
dependency manager header files
-- [Dm C++ example](../../examples/celix-examples/dm_example_cxx): A DM C++ 
example.
-- [Getting Started: Using Services with 
C++](../../documents/getting_started/using_services_with_cxx.md): A 
introduction how to work with services using the C++ dependency manager
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(ComponentWithServiceDependencyActivator)
+```
 
-## Using info
+# When will a component be suspended
 
-If the Celix C++ Dependency Manager is installed, 'find_package(Celix)' will 
set:
-- The `Celix::shell_api` interface (i.e. headers only) library target
-- The `Celix::shell` bundle target
\ No newline at end of file
+TODO explain that a component will be suspended with service dependency on 
suspend strategy, a matching service update 
+and if there is a svc inject callback configured. TODO check also start/stop 
method?
diff --git a/examples/celix-examples/dm_example/phase1/src/phase1_activator.c 
b/examples/celix-examples/dm_example/phase1/src/phase1_activator.c
index fd72d831..812d6af5 100644
--- a/examples/celix-examples/dm_example/phase1/src/phase1_activator.c
+++ b/examples/celix-examples/dm_example/phase1/src/phase1_activator.c
@@ -43,7 +43,9 @@ static celix_status_t activator_start(struct 
phase1_activator_struct *act, celix
 
         celix_dm_component_t *cmp= celix_dmComponent_create(ctx, 
"PHASE1_PROCESSING_COMPONENT");
         celix_dmComponent_setImplementation(cmp, act->phase1Cmp);
-        CELIX_DMCOMPONENT_SETCALLBACKS(cmp, phase1_cmp_t *, phase1_init, 
phase1_start, phase1_stop, phase1_deinit);
+        CELIX_DM_COMPONENT_SET_CALLBACKS(cmp, phase1_cmp_t, phase1_init, 
phase1_start, phase1_stop, phase1_deinit);
+        CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION(cmp, 
phase1_cmp_t, phase1_destroy);
+
         phase1_setComp(act->phase1Cmp, cmp);
         celix_dmComponent_addInterface(cmp, PHASE1_NAME, PHASE1_VERSION, 
&act->phase1Serv, props);
 
@@ -57,12 +59,6 @@ static celix_status_t activator_start(struct 
phase1_activator_struct *act, celix
 
 static celix_status_t activator_stop(struct phase1_activator_struct *act, 
celix_bundle_context_t *ctx) {
     printf("PHASE1: stop\n");
-    celix_dependency_manager_t *mng = 
celix_bundleContext_getDependencyManager(ctx);
-    celix_dependencyManager_removeAllComponents(mng);
-    if (act->phase1Cmp != NULL) {
-        phase1_destroy(act->phase1Cmp);
-    }
-
     return CELIX_SUCCESS;
 }
 
diff --git a/examples/celix-examples/dm_example/phase2a/src/phase2a_activator.c 
b/examples/celix-examples/dm_example/phase2a/src/phase2a_activator.c
index d92664b3..2107c3e9 100644
--- a/examples/celix-examples/dm_example/phase2a/src/phase2a_activator.c
+++ b/examples/celix-examples/dm_example/phase2a/src/phase2a_activator.c
@@ -45,9 +45,10 @@ static celix_status_t activator_start(struct 
phase2a_activator_struct *act, celi
 
         celix_dm_component_t *cmp = celix_dmComponent_create(ctx, 
"PHASE2A_PROCESSING_COMPONENT");
         celix_dmComponent_setImplementation(cmp, act->phase2aCmp);
-        CELIX_DMCOMPONENT_SETCALLBACKS(cmp, phase2a_cmp_t *, phase2a_init, 
phase2a_start, phase2a_stop, phase2a_deinit);
-        celix_dmComponent_addInterface(cmp, PHASE2_NAME, PHASE2_VERSION, 
&act->phase2Serv, props);
+        CELIX_DM_COMPONENT_SET_CALLBACKS(cmp, phase2a_cmp_t, phase2a_init, 
phase2a_start, phase2a_stop, phase2a_deinit);
+        CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION(cmp, 
phase2a_cmp_t, phase2a_destroy);
 
+        celix_dmComponent_addInterface(cmp, PHASE2_NAME, PHASE2_VERSION, 
&act->phase2Serv, props);
 
         celix_dm_service_dependency_t *dep = 
celix_dmServiceDependency_create();
         celix_dmServiceDependency_setService(dep, PHASE1_NAME, 
PHASE1_RANGE_ALL, NULL);
@@ -67,11 +68,6 @@ static celix_status_t activator_start(struct 
phase2a_activator_struct *act, celi
 
 static celix_status_t activator_stop(struct phase2a_activator_struct *act, 
celix_bundle_context_t *ctx) {
     printf("phase2a: stop\n");
-    celix_dependency_manager_t *mng = 
celix_bundleContext_getDependencyManager(ctx);
-    celix_dependencyManager_removeAllComponents(mng);
-    if (act->phase2aCmp != NULL) {
-        phase2a_destroy(act->phase2aCmp);
-    }
     return CELIX_SUCCESS;
 }
 
diff --git a/examples/celix-examples/dm_example/phase2b/src/phase2b_activator.c 
b/examples/celix-examples/dm_example/phase2b/src/phase2b_activator.c
index c04ce045..cec241b6 100644
--- a/examples/celix-examples/dm_example/phase2b/src/phase2b_activator.c
+++ b/examples/celix-examples/dm_example/phase2b/src/phase2b_activator.c
@@ -45,7 +45,9 @@ static celix_status_t activator_start(struct 
phase2b_activator_struct *act, celi
 
         celix_dm_component_t *cmp = celix_dmComponent_create(ctx, 
"PHASE2B_PROCESSING_COMPONENT");
         celix_dmComponent_setImplementation(cmp, act->phase2bCmp);
-        CELIX_DMCOMPONENT_SETCALLBACKS(cmp, phase2b_cmp_t *, phase2b_init, 
phase2b_start, phase2b_stop, phase2b_deinit);
+        CELIX_DM_COMPONENT_SET_CALLBACKS(cmp, phase2b_cmp_t, phase2b_init, 
phase2b_start, phase2b_stop, phase2b_deinit);\
+        //note not configuring destroy callback -> destroying component 
manually in the activator stop callback.
+
         celix_dmComponent_addInterface(cmp, PHASE2_NAME, PHASE2_VERSION, 
&act->phase2Serv, props);
 
 
@@ -70,7 +72,7 @@ static celix_status_t activator_stop(struct 
phase2b_activator_struct *act, celix
     celix_dependency_manager_t *mng = 
celix_bundleContext_getDependencyManager(ctx);
     celix_dependencyManager_removeAllComponents(mng);
     if (act->phase2bCmp != NULL) {
-        phase2b_destroy(act->phase2bCmp);
+        phase2b_destroy(act->phase2bCmp); //destroy component implementation
     }
     return CELIX_SUCCESS;
 }
diff --git a/examples/celix-examples/dm_example/phase3/src/phase3_activator.c 
b/examples/celix-examples/dm_example/phase3/src/phase3_activator.c
index f699454f..77453c5c 100644
--- a/examples/celix-examples/dm_example/phase3/src/phase3_activator.c
+++ b/examples/celix-examples/dm_example/phase3/src/phase3_activator.c
@@ -36,7 +36,8 @@ static celix_status_t activator_start(struct 
phase3_activator_struct *act, celix
 
         celix_dm_component_t *cmp = celix_dmComponent_create(ctx, 
"PHASE3_PROCESSING_COMPONENT");
         celix_dmComponent_setImplementation(cmp, act->phase3Cmp);
-        CELIX_DMCOMPONENT_SETCALLBACKS(cmp, phase3_cmp_t *, phase3_init, 
phase3_start, phase3_stop, phase3_deinit);
+        CELIX_DM_COMPONENT_SET_CALLBACKS(cmp, phase3_cmp_t, phase3_init, 
phase3_start, phase3_stop, phase3_deinit);
+        CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION(cmp, 
phase3_cmp_t, phase3_destroy);
 
         celix_dm_service_dependency_t *dep = 
celix_dmServiceDependency_create();
         celix_dmServiceDependency_setService(dep, PHASE2_NAME, NULL, NULL);
@@ -57,16 +58,9 @@ static celix_status_t activator_start(struct 
phase3_activator_struct *act, celix
 
 }
 
-static celix_status_t activator_stop(struct phase3_activator_struct *act, 
celix_bundle_context_t *ctx) {
-    celix_status_t status = CELIX_SUCCESS;
+static celix_status_t activator_stop(struct phase3_activator_struct *act 
__attribute__((unused)), celix_bundle_context_t *ctx) {
     printf("phase3: stop\n");
-    celix_dependency_manager_t *mng = 
celix_bundleContext_getDependencyManager(ctx);
-    celix_dependencyManager_removeAllComponents(mng);
-    if (act->phase3Cmp != NULL) {
-        phase3_destroy(act->phase3Cmp);
-    }
-    return status;
+    return CELIX_SUCCESS;
 }
 
-
-CELIX_GEN_BUNDLE_ACTIVATOR(struct phase3_activator_struct, activator_start, 
activator_stop);
\ No newline at end of file
+CELIX_GEN_BUNDLE_ACTIVATOR(struct phase3_activator_struct, activator_start, 
activator_stop);
diff --git a/examples/celix-examples/readme_c_examples/CMakeLists.txt 
b/examples/celix-examples/readme_c_examples/CMakeLists.txt
index 4ea4d406..2b7d3c39 100644
--- a/examples/celix-examples/readme_c_examples/CMakeLists.txt
+++ b/examples/celix-examples/readme_c_examples/CMakeLists.txt
@@ -53,6 +53,23 @@ add_celix_bundle(tracker_command_services_bundle
 )
 target_link_libraries(tracker_command_services_bundle PRIVATE Celix::shell_api)
 
+add_celix_bundle(simple_component_bundle
+        VERSION 1.0.0
+        SOURCES src/simple_component_activator.c
+)
+
+add_celix_bundle(component_with_provided_service_bundle
+        VERSION 1.0.0
+        SOURCES src/component_with_provided_service_activator.c
+)
+target_link_libraries(component_with_provided_service_bundle PRIVATE 
Celix::shell_api)
+
+add_celix_bundle(component_with_service_dependency_bundle
+    VERSION 1.0.0
+    SOURCES src/component_with_service_dependency_activator.c
+)
+target_link_libraries(component_with_service_dependency_bundle PRIVATE 
Celix::shell_api)
+
 add_celix_container(readme_c_examples_container
     C
     BUNDLES
@@ -61,4 +78,7 @@ add_celix_container(readme_c_examples_container
         my_shell_command_provider_bundle
         using_command_service_bundle
         tracker_command_services_bundle
+        simple_component_bundle
+        component_with_provided_service_bundle
+        component_with_service_dependency_bundle
 )
\ No newline at end of file
diff --git 
a/examples/celix-examples/readme_c_examples/src/component_with_provided_service_activator.c
 
b/examples/celix-examples/readme_c_examples/src/component_with_provided_service_activator.c
new file mode 100644
index 00000000..5c79493b
--- /dev/null
+++ 
b/examples/celix-examples/readme_c_examples/src/component_with_provided_service_activator.c
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+//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)
diff --git 
a/examples/celix-examples/readme_c_examples/src/component_with_service_dependency_activator.c
 
b/examples/celix-examples/readme_c_examples/src/component_with_service_dependency_activator.c
new file mode 100644
index 00000000..e44347e1
--- /dev/null
+++ 
b/examples/celix-examples/readme_c_examples/src/component_with_service_dependency_activator.c
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+//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;
+    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);
+    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* shellCmd) {
+    printf("New highest ranking service (can be NULL): %p\n", shellCmd);
+    cmp->highestRankingCmdShell = shellCmd;
+}
+
+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);
+    celix_arrayList_add(cmp->cmdShells, shellCmd);
+    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, shellCmd);
+    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();
+    celix_dmServiceDependency_setService(dep1, 
CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL);
+    celix_dmServiceDependency_setStrategy(dep1, 
DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND);
+    celix_dmServiceDependency_setRequired(dep1, true);
+    celix_dm_service_dependency_callback_options_t opts1 = 
CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS;
+    opts1.set = 
(void*)componentWithServiceDependency_setHighestRankingShellCommand;
+    celix_dmServiceDependency_setCallbacksWithOptions(dep1, &opts1);
+    celix_dmComponent_addServiceDependency(dmCmp, dep1);
+
+    //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);
+    celix_dmServiceDependency_setRequired(dep2, false);
+    celix_dm_service_dependency_callback_options_t opts2 = 
CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS;
+    opts2.addWithProps = (void*)componentWithServiceDependency_addShellCommand;
+    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)
diff --git 
a/examples/celix-examples/readme_c_examples/src/simple_component_activator.c 
b/examples/celix-examples/readme_c_examples/src/simple_component_activator.c
new file mode 100644
index 00000000..0c21fcff
--- /dev/null
+++ b/examples/celix-examples/readme_c_examples/src/simple_component_activator.c
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+//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>
\ No newline at end of file
diff --git a/examples/celix-examples/readme_cxx_examples/CMakeLists.txt 
b/examples/celix-examples/readme_cxx_examples/CMakeLists.txt
index 0548072c..14d7fa6a 100644
--- a/examples/celix-examples/readme_cxx_examples/CMakeLists.txt
+++ b/examples/celix-examples/readme_cxx_examples/CMakeLists.txt
@@ -115,12 +115,29 @@ add_celix_bundle(UsingCommandServicesExampleBundle
 target_link_libraries(UsingCommandServicesExampleBundle PRIVATE 
Celix::shell_api)
 
 add_celix_bundle(TrackingCommandServicesExampleBundle
-        VERSION 1.0.0
+    VERSION 1.0.0
     SOURCES
         src/TrackingCommandServicesExample.cc
 )
 target_link_libraries(TrackingCommandServicesExampleBundle PRIVATE 
Celix::shell_api)
 
+add_celix_bundle(SimpleComponentBundle
+    VERSION 1.0.0
+    SOURCES src/SimpleComponentActivator.cc
+)
+
+add_celix_bundle(ComponentWithProvidedServiceBundle
+    VERSION 1.0.0
+    SOURCES src/ComponentWithProvidedServiceActivator.cc
+)
+target_link_libraries(ComponentWithProvidedServiceBundle PRIVATE 
Celix::shell_api)
+
+add_celix_bundle(ComponentWithServiceDependencyBundle
+    VERSION 1.0.0
+    SOURCES src/ComponentWithServiceDependencyActivator.cc
+)
+target_link_libraries(ComponentWithServiceDependencyBundle PRIVATE 
Celix::shell_api)
+
 add_celix_container(ReadmeCxxExamplesContainer
     BUNDLES
         Celix::ShellCxx
@@ -129,6 +146,9 @@ add_celix_container(ReadmeCxxExamplesContainer
         MyCShellCommandProviderBundle
         UsingCommandServicesExampleBundle
         TrackingCommandServicesExampleBundle
+        SimpleComponentBundle
+        ComponentWithProvidedServiceBundle
+        ComponentWithServiceDependencyBundle
 )
 
 if (TARGET my_shell_command_provider_bundle)
diff --git 
a/examples/celix-examples/readme_cxx_examples/src/ComponentWithProvidedServiceActivator.cc
 
b/examples/celix-examples/readme_cxx_examples/src/ComponentWithProvidedServiceActivator.cc
new file mode 100644
index 00000000..0095a73a
--- /dev/null
+++ 
b/examples/celix-examples/readme_cxx_examples/src/ComponentWithProvidedServiceActivator.cc
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+//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>
+
+        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.createProvidedCService(&shellCmd, CELIX_SHELL_COMMAND_SERVICE_NAME)
+                .addProperty(CELIX_SHELL_COMMAND_NAME, "hello_component"); // 
< -----------------------------------------<7>
+
+        cmp.build(); // 
<--------------------------------------------------------------------------------------------<8>
+    }
+private:
+    celix_shell_command_t shellCmd{nullptr, nullptr};
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(ComponentWithProvidedServiceActivator)
diff --git 
a/examples/celix-examples/readme_cxx_examples/src/ComponentWithServiceDependencyActivator.cc
 
b/examples/celix-examples/readme_cxx_examples/src/ComponentWithServiceDependencyActivator.cc
new file mode 100644
index 00000000..1ba31500
--- /dev/null
+++ 
b/examples/celix-examples/readme_cxx_examples/src/ComponentWithServiceDependencyActivator.cc
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//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;
+    }
+
+    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};
+        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 below
+    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>(); // 
<-------------<1>
+
+        cmp.createServiceDependency<celix::IShellCommand>()
+                .setCallbacks(&Cmp::setHighestRankingShellCommand)
+                .setRequired(true)
+                .setStrategy(DependencyUpdateStrategy::suspend);
+
+        
cmp.createServiceDependency<celix_shell_command_t>(CELIX_SHELL_COMMAND_SERVICE_NAME)
+                .setCallbacks(&Cmp::addCShellCmd, &Cmp::removeCShellCmd)
+                .setRequired(false)
+                .setStrategy(DependencyUpdateStrategy::locking);
+
+        cmp.build(); // 
<--------------------------------------------------------------------------------------------<8>
+    }
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(ComponentWithServiceDependencyActivator)
diff --git 
a/examples/celix-examples/readme_cxx_examples/src/SimpleComponentActivator.cc 
b/examples/celix-examples/readme_cxx_examples/src/SimpleComponentActivator.cc
new file mode 100644
index 00000000..d1cfcd6c
--- /dev/null
+++ 
b/examples/celix-examples/readme_cxx_examples/src/SimpleComponentActivator.cc
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <celix/BundleActivator.h>
+
+class SimpleComponent {
+public:
+    void init() {
+        std::cout << "Initializing SimpleComponent. Transition nr " << 
transitionCount++ << std::endl;
+    }
+
+    void start() {
+        std::cout << "starting SimpleComponent. Transition nr " << 
transitionCount++ << std::endl;
+    }
+
+    void stop() {
+        std::cout << "Stopping SimpleComponent. Transition nr " << 
transitionCount++ << std::endl;
+    }
+
+    void deinit() {
+        std::cout << "De-initializing SimpleComponent. 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>();
+        ctx->getDependencyManager()->createComponent(std::move(cmp), 
"SimpleComponent1")
+                .setCallbacks(
+                        &SimpleComponent::init,
+                        &SimpleComponent::start,
+                        &SimpleComponent::stop,
+                        &SimpleComponent::deinit)
+                .build();
+    }
+};
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(SimpleComponentActivator)
diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc 
b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
index 5cb65b0b..db217ad9 100644
--- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc
+++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
@@ -86,6 +86,43 @@ TEST_F(DependencyManagerTestSuite, DmComponentAddRemove) {
     ASSERT_EQ(0, celix_dependencyManager_nrOfComponents(mng));
 }
 
+TEST_F(DependencyManagerTestSuite, DmComponentsWithConfiguredDestroyFunction) {
+    //Given a simple component implementation (only a name field)
+    struct CmpImpl {
+        std::string name;
+    };
+
+    void(*destroyFn)(CmpImpl*) = [](CmpImpl* impl) {
+        std::cout << "Destroying " << impl->name << std::endl;
+        delete impl;
+    };
+
+    //When 10 of these components impls are created and configured (include 
destroy impl function)
+    //as component in the DM.
+    auto* dm = celix_bundleContext_getDependencyManager(ctx);
+    for (int i = 0; i < 10; ++i) {
+        auto* impl = new CmpImpl{std::string{"Component"} + 
std::to_string(i+1)};
+        auto* dmCmp = celix_dmComponent_create(ctx, impl->name.c_str());
+        celix_dmComponent_setImplementation(dmCmp, impl);
+        CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION(dmCmp, CmpImpl, 
destroyFn);
+        celix_dependencyManager_addAsync(dm, dmCmp);
+    }
+
+    //Then all component should become activate (note components with no svc 
dependencies)
+    celix_dependencyManager_wait(dm);
+    celix_dependencyManager_allComponentsActive(dm);
+    EXPECT_EQ(celix_dependencyManager_nrOfComponents(dm), 10);
+
+    //When all 10 components are removed
+    celix_dependencyManager_removeAllComponents(dm);
+
+    //Then all components should be removed
+    EXPECT_EQ(celix_dependencyManager_nrOfComponents(dm), 0);
+
+    //And when the test goes out of scope, no memory should be leaked
+    //nop
+}
+
 
 TEST_F(DependencyManagerTestSuite, DmComponentAddRemoveAsync) {
     auto *mng = celix_bundleContext_getDependencyManager(ctx);
diff --git a/libs/framework/include/celix_bundle_activator.h 
b/libs/framework/include/celix_bundle_activator.h
index bab054c3..19dc1770 100644
--- a/libs/framework/include/celix_bundle_activator.h
+++ b/libs/framework/include/celix_bundle_activator.h
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 
 #include "celix_bundle_context.h"
+#include "celix_dependency_manager.h"
 
 #ifndef CELIX_BUNDLE_ACTIVATOR_H_
 #define CELIX_BUNDLE_ACTIVATOR_H_
@@ -103,11 +104,6 @@ celix_status_t celix_bundleActivator_stop(void *userData, 
celix_bundle_context_t
  */
 celix_status_t celix_bundleActivator_destroy(void *userData, 
celix_bundle_context_t* ctx);
 
-/**
- * @brief Returns the C bundle context.
- */
-celix_bundle_context_t* celix_bundleActivator_getBundleContext();
-
 /**
  * @brief This macro generates the required bundle activator functions for C.
  *
@@ -118,9 +114,16 @@ celix_bundle_context_t* 
celix_bundleActivator_getBundleContext();
  * - bundleActivator_start/stop which will call the respectively provided 
typed start/stop functions.
  * - bundleActivator_destroy will free the allocated for the provided type.
  *
- * @param type The activator type (e.g. 'struct shell_activator').
- * @param start the activator actStart function with the following signature: 
celix_status_t (*)(<actType>*, celix_bundle_context_t*).
- * @param stop the activator actStop function with the following signature: 
celix_status_t (*)(<actType>*, celix_bundle_context_t*).
+ * After the (optional) provided activator stop callback is called, the 
generated `celix_bundleActivator_stop`
+ * function will remove all components from the bundle's dependency manager
+ * (using `celix_dependencyManager_removeAllComponents). This will ensure that 
dependency manager components can be
+ * used without explicitly programming their removal and destroy functionality.
+ *
+ * @param actType The activator type (e.g. 'struct shell_activator').
+ * @param actStart The optional activator actStart function with the following 
signature:
+ *                 celix_status_t (*)(<actType>*, celix_bundle_context_t*).
+ * @param actStop The optional activator actStop function with the following 
signature:
+ *                celix_status_t (*)(<actType>*, celix_bundle_context_t*).
  */
 #define CELIX_GEN_BUNDLE_ACTIVATOR(actType, actStart, actStop)                 
                                        \
                                                                                
                                        \
@@ -136,11 +139,23 @@ celix_status_t 
celix_bundleActivator_create(celix_bundle_context_t *ctx, void **
 }                                                                              
                                        \
                                                                                
                                        \
 celix_status_t celix_bundleActivator_start(void *userData, 
celix_bundle_context_t *ctx) {                              \
-    return actStart((actType*)userData, ctx);                                  
                                        \
+    celix_status_t status = CELIX_SUCCESS;                                     
                                        \
+    celix_status_t (*fn)(actType*, celix_bundle_context_t*) = (actStart);      
                                        \
+    if (fn != NULL) {                                                          
                                        \
+        status = fn((actType*)userData, ctx);                                  
                                        \
+    }                                                                          
                                        \
+    return status;                                                             
                                        \
 }                                                                              
                                        \
                                                                                
                                        \
 celix_status_t celix_bundleActivator_stop(void *userData, 
celix_bundle_context_t *ctx) {                               \
-    return actStop((actType*)userData, ctx);                                   
                                        \
+    celix_status_t status = CELIX_SUCCESS;                                     
                                        \
+    celix_status_t (*fn)(actType*, celix_bundle_context_t*) = (actStop);       
                                        \
+    if (fn != NULL) {                                                          
                                        \
+        status = fn((actType*)userData, ctx);                                  
                                        \
+    }                                                                          
                                        \
+    celix_dependency_manager_t* mng = 
celix_bundleContext_getDependencyManager(ctx);                                  
 \
+    celix_dependencyManager_removeAllComponents(mng);                          
                                        \
+    return status;                                                             
                                        \
 }                                                                              
                                        \
                                                                                
                                        \
 celix_status_t celix_bundleActivator_destroy(void *userData, 
celix_bundle_context_t *ctx) {                            \
diff --git a/libs/framework/include/celix_dependency_manager.h 
b/libs/framework/include/celix_dependency_manager.h
index d4cf37a5..8e369375 100644
--- a/libs/framework/include/celix_dependency_manager.h
+++ b/libs/framework/include/celix_dependency_manager.h
@@ -45,9 +45,12 @@ extern "C" {
 /**
  * Adds a DM component to the dependency manager
  *
- * After this call the components will be created and if the components can be 
started, they
+ * After this call the components will be build and if the components can be 
started, they
  * will be started and the services will be registered.
  *
+ * After this call the dependency manager has ownership of the component and 
the dependency manager will also
+ * de-active and destroy the component when the dependency manager is 
destroyed.
+ *
  * Should not be called from the Celix event thread.
  */
 celix_status_t celix_dependencyManager_add(celix_dependency_manager_t 
*manager, celix_dm_component_t *component);
@@ -62,16 +65,15 @@ celix_status_t 
celix_dependencyManager_addAsync(celix_dependency_manager_t *mana
 /**
  * Removes a DM component from the dependency manager and destroys it
  *
- * After this call the components will be destroyed and if the components was 
started, the service registrations
- * and service tracked of this component will be unregistered and closed.
+ * After this call - and if the component was found - the component will be 
destroyed and if the component was started,
+ * the component will have been stopped and de-initialized.
  *
  * Should not be called from the Celix event thread.
  */
 celix_status_t celix_dependencyManager_remove(celix_dependency_manager_t 
*manager, celix_dm_component_t *component);
 
 /**
- * Same as celix_dependencyManager_remove, but this call will not wait until 
all service registrations and
- * tracker are unregistered/closed on the Celix event thread.
+ * Same as celix_dependencyManager_remove, but this call will not wait until 
component is deactivated.
  * Can be called on the Celix event thread.
  *
  * The doneCallback will be called (if not NULL) with doneData as argument 
when the component is removed
diff --git a/libs/framework/include/celix_dm_component.h 
b/libs/framework/include/celix_dm_component.h
index 8302dca0..6f0b0d5a 100644
--- a/libs/framework/include/celix_dm_component.h
+++ b/libs/framework/include/celix_dm_component.h
@@ -61,6 +61,7 @@ typedef enum celix_dm_component_state_enum {
 #define CELIX_DM_COMPONENT_MAX_NAME_LENGTH 128
 
 typedef int (*celix_dm_cmp_lifecycle_fpt)(void *userData);
+typedef void (*celix_dm_cmp_impl_destroy_fpt)(void*);
 
 /**
  * Creates a DM Component with a random generated UUID.
@@ -82,14 +83,14 @@ const char* celix_dmComponent_getUUID(celix_dm_component_t* 
cmp);
 /**
  * Destroys a DM Component
  */
-void celix_dmComponent_destroy(celix_dm_component_t *cmp);
+void celix_dmComponent_destroy(celix_dm_component_t* cmp);
 
 /**
  * Destroys a DM Component on the event thread.
  * Will call doneCallback (if not NULL) when done.
  *
  */
-void celix_dmComponent_destroyAsync(celix_dm_component_t *cmp, void *doneData, 
void (*doneCallback)(void*));
+void celix_dmComponent_destroyAsync(celix_dm_component_t* cmp, void *doneData, 
void (*doneCallback)(void*));
 
 /**
  * Specify if a default 'service.lang=C' should be added to the properties of 
interfaces if no 'service.lang' has been
@@ -119,6 +120,26 @@ celix_status_t 
celix_dmComponent_removeInterface(celix_dm_component_t *component
  */
 celix_status_t celix_dmComponent_setImplementation(celix_dm_component_t 
*component, void* implementation);
 
+/**
+ * Configures the destroy function for the component implementation.
+ *
+ * If a destroy function for the component implementation is configured, this 
will be used
+ * when the component is removed from the dependency manager and component is 
successfully de-activated.
+ *
+ * The destroy function will not be called if the component implementation is 
not set. e.g. if the
+ * celix_dmComponent_setImplementation is not called with a non NULL value.
+ */
+void celix_dmComponent_setImplementationDestroyFunction(celix_dm_component_t* 
cmp, celix_dm_cmp_impl_destroy_fpt destroyFn);
+
+/**
+ * Configures the destroy function for the component implementation using a 
MACRO for improving the type safety.
+ */
+#define CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION(dmCmp, type, 
destroy) \
+    do {  \
+        void (*_destroyFunction)(type*) = (destroy); \
+        celix_dmComponent_setImplementationDestroyFunction((dmCmp), 
(void(*)(void*))_destroyFunction); \
+    } while(0)
+
 /**
  * Returns an arraylist of service names. The caller owns the arraylist and 
strings (char *)
  */
@@ -137,17 +158,22 @@ celix_status_t 
celix_dmComponent_removeServiceDependency(celix_dm_component_t *c
 /**
  * Returns the current state of the component.
  */
-celix_dm_component_state_t celix_dmComponent_currentState(celix_dm_component_t 
*cmp);
+celix_dm_component_state_t 
celix_dmComponent_currentState(celix_dm_component_t* cmp);
 
 /**
  * Returns the implementation of the component. e.g. the component 
handle/self/this pointer.
  */
-void * celix_dmComponent_getImplementation(celix_dm_component_t *cmp);
+void * celix_dmComponent_getImplementation(celix_dm_component_t* cmp);
+
+/**
+ * Returns the configured component implementation destroy function.
+ */
+celix_dm_cmp_impl_destroy_fpt 
celix_dmComponent_getImplementationDestroyFunction(celix_dm_component_t* cmp);
 
 /**
  * Returns the DM component name. This is used when printing information about 
the component.
  */
-const char* celix_dmComponent_getName(celix_dm_component_t *cmp);
+const char* celix_dmComponent_getName(celix_dm_component_t* cmp);
 
 /**
  * Returns bundle context for the bundle where this DM component is part of.
@@ -163,15 +189,22 @@ celix_status_t 
celix_dmComponent_setCallbacks(celix_dm_component_t *component, c
 /**
  * Set the component life cycle callbacks using a MACRO for improving the type 
safety.
  */
-#define CELIX_DMCOMPONENT_SETCALLBACKS(dmCmp, type, init, start, stop, deinit) 
\
+#define CELIX_DM_COMPONENT_SET_CALLBACKS(dmCmp, type, init, start, stop, 
deinit) \
     do {  \
-        int (*tmp_init)(type)   = (init); \
-        int (*tmp_start)(type)  = (start); \
-        int (*tmp_stop)(type)   = (stop); \
-        int (*tmp_deinit)(type) = (deinit); \
-        celix_dmComponent_setCallbacks((dmCmp), 
(celix_dm_cmp_lifecycle_fpt)tmp_init, (celix_dm_cmp_lifecycle_fpt)tmp_start, 
(celix_dm_cmp_lifecycle_fpt)tmp_stop, (celix_dm_cmp_lifecycle_fpt)tmp_deinit); \
+        int (*_tmp_init)(type*)   = (init); \
+        int (*_tmp_start)(type*)  = (start); \
+        int (*_tmp_stop)(type*)   = (stop); \
+        int (*_tmp_deinit)(type*) = (deinit); \
+        celix_dmComponent_setCallbacks((dmCmp), 
(celix_dm_cmp_lifecycle_fpt)_tmp_init, (celix_dm_cmp_lifecycle_fpt)_tmp_start, 
(celix_dm_cmp_lifecycle_fpt)_tmp_stop, 
(celix_dm_cmp_lifecycle_fpt)_tmp_deinit); \
     } while(0)
 
+/**
+ * Deprecated, use CELIX_DM_COMPONENT_SET_CALLBACKS instead.
+ */
+
+#define CELIX_DMCOMPONENT_SETCALLBACKS(dmCmp, type, init, start, stop, deinit) 
\
+    CELIX_DM_COMPONENT_SET_CALLBACKS(dmCmp, type*, init, start, stop, deinit)
+
 /**
  * Create a DM Component info struct. Containing information about the 
component.
  * Caller has ownership.
diff --git a/libs/framework/src/dm_component_impl.c 
b/libs/framework/src/dm_component_impl.c
index a951efc1..befa81bb 100644
--- a/libs/framework/src/dm_component_impl.c
+++ b/libs/framework/src/dm_component_impl.c
@@ -35,6 +35,7 @@ struct celix_dm_component_struct {
 
     celix_bundle_context_t* context;
     void* implementation;
+    celix_dm_cmp_impl_destroy_fpt implementationDestroyFn;
 
     celix_dm_cmp_lifecycle_fpt callbackInit;
     celix_dm_cmp_lifecycle_fpt callbackStart;
@@ -130,6 +131,10 @@ celix_dm_component_t* 
celix_dmComponent_createWithUUID(bundle_context_t *context
     component->callbackStart = NULL;
     component->callbackStop = NULL;
     component->callbackDeinit = NULL;
+
+    component->implementation= NULL;
+    component->implementationDestroyFn = NULL;
+
     component->state = CELIX_DM_CMP_STATE_INACTIVE;
 
     component->providedInterfaces = celix_arrayList_create();
@@ -178,8 +183,21 @@ struct celix_dm_component_destroy_data {
 static void celix_dmComponent_destroyCallback(void *voidData) {
     struct celix_dm_component_destroy_data *data = voidData;
     celix_dm_component_t *component = data->cmp;
-    celix_dmComponent_disable(component); //all service deregistered // all 
svc tracker stopped
+    celix_dmComponent_disable(component); //all service unregistered // all 
svc tracker stopped
     if (celix_dmComponent_isDisabled(component)) {
+        if (component->implementationDestroyFn) {
+            if (component->implementation == NULL) {
+                celix_bundleContext_log(component->context, 
CELIX_LOG_LEVEL_ERROR,
+                                        "Component `%s` [uuid=%s] has a 
configured destroy component "
+                                        "implementation callback, but the 
implementation pointer is NULL. "
+                                        "Destroy callback will not be called!",
+                                        component->name,
+                                        component->uuid);
+            } else {
+                component->implementationDestroyFn(component->implementation);
+            }
+        }
+
         for (int i = 0; i < 
celix_arrayList_size(component->providedInterfaces); ++i) {
             dm_interface_t *interface = 
celix_arrayList_get(component->providedInterfaces, i);
 
@@ -975,6 +993,10 @@ celix_status_t 
celix_dmComponent_setImplementation(celix_dm_component_t *compone
     return CELIX_SUCCESS;
 }
 
+void celix_dmComponent_setImplementationDestroyFunction(celix_dm_component_t* 
component, celix_dm_cmp_impl_destroy_fpt destroyFn) {
+    component->implementationDestroyFn = destroyFn;
+}
+
 celix_status_t component_getBundleContext(celix_dm_component_t *component, 
bundle_context_pt *context) {
     *context = celix_dmComponent_getBundleContext(component);
     return *context == NULL ? CELIX_BUNDLE_EXCEPTION : CELIX_SUCCESS;

Reply via email to