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

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


The following commit(s) were added to 
refs/heads/feature/update_component_and_pattern_documentation by this push:
     new b74930c8 Updates dm component document and examples.
b74930c8 is described below

commit b74930c86d44cd9b5d1138fe83ddb3586d253192
Author: Pepijn Noltes <[email protected]>
AuthorDate: Sun May 29 19:16:35 2022 +0200

    Updates dm component document and examples.
    
    Also:
    - Adds small chapter for `celix::lb` and `celix::query` shell commands
    - Update find_package(CppUTest) to optional so that Celix can be build
      with tests, but without CppUTest.
---
 documents/bundles.md                               |  12 +-
 documents/components.md                            | 373 ++++++++++++---------
 documents/services.md                              |  22 +-
 .../component_with_service_dependency_activator.c  |  30 +-
 .../src/ComponentWithProvidedServiceActivator.cc   |   7 +-
 libs/utils/CMakeLists.txt                          | 112 ++++---
 6 files changed, 321 insertions(+), 235 deletions(-)

diff --git a/documents/bundles.md b/documents/bundles.md
index bd18f7b1..908442eb 100644
--- a/documents/bundles.md
+++ b/documents/bundles.md
@@ -286,4 +286,14 @@ add_celix_container(test_container BUNDLES
 )
 ```
 
-See [Apache Celix CMake Commands](cmake_commands) for more detailed 
information.
\ No newline at end of file
+See [Apache Celix CMake Commands](cmake_commands) for more detailed 
information.
+
+# The `celix::lb` shell command
+To interactively see the installed bundles the `celix::lb` shell command (list 
bundles) can be used.
+
+Examples of supported `lb` command lines are:
+ - `celix::lb` - Show an overview of the installed bundles with their bundle 
id, bundle state, bundle name and 
+   bundle group.
+ - `lb` - Same as `celix::lb` (as long as there is no colliding other `lb` 
commands). 
+ - `lb -s` - Same as `celix::lb` but instead of showing the bundle name the 
bundle symbolic name is printed.
+ - `lb -u` - Same as `celix::lb` but instead of showing the bundle name the 
bundle update location is printed.
diff --git a/documents/components.md b/documents/components.md
index 86e2986a..2f20555b 100644
--- a/documents/components.md
+++ b/documents/components.md
@@ -25,49 +25,51 @@ Components can provide services and depend on services. 
Components are configure
 
 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 
+The DM is responsible for managing the co7mponent'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 has its own lifecycle. 
+Each component has its own lifecycle.
 A component's lifecycle state model is depicted in the state diagram below.
 
 ![Component Life Cycle](diagrams/component_lifecycle.png)
 
-The DM can be used to configure a component's lifecycle callbacks, the 
following component's lifecycle callbacks can 
+The DM can be used to configure a component's lifecycle callbacks, the 
following component's lifecycle callbacks can
 be configured:
 
- - `init`
- - `start`
- - `stop`
- - `deinit`
-   
+- `init`
+- `start`
+- `stop`
+- `deinit`
+
 These callbacks are used in the intermediate component's lifecycle states 
`Initializing`, `Starting`, `Suspending`, `Resuming`, `Stopping` and 
`Deinitializing` and the lifecycle callbacks are always called from the Celix 
event thread.
 
-A 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._
+A component has the following lifecycle states:
+- `Inactive`: The component is inactive and the DM is not managing the 
component yet.
+- `Waiting For Required`: The component is waiting for required service 
dependencies.
+- `Initializing`: The component has found its required dependencies and is 
initializing by
+  calling the `init` callback.
+- `Initialized And Waiting For Required`: The component has been initialized, 
but is waiting for required
+  dependencies.
+  _Note: that this can mean that:
+    - During the `init` callback, 1 or more unavailable required service 
dependencies where added.
+    - The component was active, but 1 or more required service dependency 
where removed and as result the
+      component is not active anymore.
+- `Starting`: The component has found its required dependencies and is 
starting by calling the `start` callback and
+  registering the components provided services.
+- `Tracking Optional`: The component has found its required dependencies and 
is started. It is still tracking for
+  additional optional and required services.
+- `Suspending`: The component has found its required dependencies, but is 
suspending to prepare for a service change by
+  unregistering the components provided service and calling the `stop` 
callback.
+- `Suspended`: The component has found its required dependencies and is 
suspended so that a service change can be
+  processed.
+- `Resuming`: The component has found its required dependencies, a service 
change has been processed, and it is
+  resuming by calling the `start` callback and registering the components 
provided services.
+- `Stopping`: The component has lost one or more of its required dependencies 
and is stopping by unregistering the
+  components provided service and calling the `stop` callback.
+- `Deinitializing`: The component is being removed and is deinitializing by 
calling the `deinit` callback.
 
 ## Component API
 
@@ -77,33 +79,34 @@ The DM Component C api can be found in the 
`celix_dm_component.h` header and the
 ## 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. 
+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.
-    
+1. Although this is a C component. The simple component functions have been 
design for a component approach,
+   using the component pointer as first argument.
+2. The component implementation can be any POCO, as long as its lifecycle and 
destroy function signature follow a
+   component approach: A single argument, with as type the component 
implementation pointer and an int return
+   for the component lifecycle functions and a void return for the component 
destroy function.
+3. Creates the DM component, but note that the DM component is not yet known 
to the DM. This makes it possible to
+   first configure the DM component over multiple function calls, before 
adding it to the DM.
+4. Configures the component implementation in the DM component, so that the 
implementation pointer can be used
+   in the configured component callbacks.
+5. Configures the component lifecycle callbacks to the DM Component. These 
callbacks should accept the component
+   implementation as its only argument. The `CELIX_DM_COMPONENT_SET_CALLBACKS` 
marco is used instead of the
+   `celix_dmComponent_setCallbacks` function so that the component 
implementation type can directly be used
+   in the lifecycle callbacks (instead of `void*`).
+6. Configures the component destroy implementation callback to the Dm 
Component. This callback will be called when
+   the DM component is removed from the DM and has become inactive. The 
callback will be called from the Celix event
+   thread. The advantages of configuring this callback is that the DM manages 
when the callback needs to be called;
+   this removes some complexity for the users. The 
`CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION` marco
+   is used instead of the `celix_dmComponent_setImplementationDestroyFunction` 
function so that the component
+   implementation type can be directly used in the callback (instead of 
`void*`).
+7. Adds the DM Component the DM and as result the DM will that point on manage 
the components' lifecycle, service
+   dependencies and provided services.
+8. No additional code is needed to clean up components and as such no 
activator stop callback function needs to be
+   configured. The generated bundle activator will ensure that all components 
are removed from the DM when the
+   bundle is stopped and the DM will ensure that the components are 
deactivated and destroyed correctly.
+
 ```C
 //src/simple_component_activator.c
 #include <stdio.h>
@@ -181,26 +184,26 @@ CELIX_GEN_BUNDLE_ACTIVATOR(simple_component_activator_t, 
simpleComponentActivato
 ```
 
 ## 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. 
+The following example shows how a simple component can be created and managed 
with the DM in C++.
+For C++ the DM will manage the component and also ensures that component 
implementation is kept in scope for as
+long as the component is managed by the DM.
 
 Remarks for the C++ example:
 1. For C++ the DM can directly work on classes and as result lifecycle 
callback can be class methods.
-2. Creates a component implementation using a unique_ptr. 
+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>()`). 
+   DM will manage them. This way C++ components can be build using a fluent 
api and marked complete with a `build()`
+   method call.
+   For a component implementation the DM accepts a unique_ptr, a shared_ptr, a 
value type or no implementation. If no
+   implementation is provided the DM will create a component implementation 
using the template argument and
+   assuming a default constructor (e.g. 
`ctx->getDependencyManager()->createComponent<CmpWithDefaultCTOR>()`).
 4. Configures the component lifecycle callbacks as class methods. The DM will 
call these callbacks using the
-   component implementation 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.
+   component implementation raw pointer as object instance (`this`).
+5. "Builds" the component. C++ components will only be managed by the DM after 
they are build. This makes it possible
+   to configure a component over multiple method calls before marking the 
component complete (build).
+   The generated C++ bundle activator will also enable all components created 
during the bundle activation, this is
+   done to ensure that the build behaviour is backwards compatible with 
previous released DM implementation.
+   It is preferred that users explicitly build their components when they are 
completely configured.
 
 ```C++
 //src/SimpleComponentActivator.cc
@@ -245,23 +248,23 @@ CELIX_GEN_CXX_BUNDLE_ACTIVATOR(SimpleComponentActivator)
 ```
 
 # 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. 
+Components can be configured to provide services. These provided services will 
result in service registrations
+when a component is `Starting` or `Resuming` (i.e. when a component goes to 
the `Tracking Optional` state).
 
-If a component provide services, these service will have an additional 
metadata property - named "component.uuid"
-that couples the services to the component named "component.uuid".
+If a component provide services, these services will have an additional 
automatically added service property - named "component.uuid" - next to its 
configured provided service properties. The "component.uuid" service property 
can be
+used to identify if a service is provided by a component and which component.
 
 ## Example: Component with a provided service in C
-The following example shows how a component that provide a 
`celix_shell_command` service. 
+The following example shows how a component that provide a 
`celix_shell_command` service.
 
 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 
+1. C services do not support inheritance. So even if a C component provides a 
certain service, it is not an
+   instance of said service. This also means the C service struct provided by 
a component needs to be stored
    separately. In this example this is done storing the service struct in the 
bundle activator data. Note
-   that the bundle activator data "outlives" the component, because all 
components are removed before a bundle 
+   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`.
+   instead will be registered in the component states `Starting` and 
`Resuming`.
 
 ```C
  //src/component_with_provided_service_activator.c
@@ -338,28 +341,28 @@ CELIX_GEN_BUNDLE_ACTIVATOR(
 ```
 
 ## 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.  
+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. 
+   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 
+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 
-   `createUnassociatedProvidedService` must be used, because the component 
does not inherit `celix_shell_command_t`. 
-   The service will not directly be registered, but instead will be registered 
if the component enters the state
-   `Tracking Optional`..
-8. "Build" the component so the DM will manage and try to activate the 
component. 
+   implementation is an instance of `celix::IShellCommand` no additional 
storage is needed. The service will not
+   directly be registered, but instead will be registered in the components 
states `Starting` and `Resuming`.
+6. Set the C `executeCommand` function pointer of the `celix_shell_command_t` 
service interface struct to a
+   capture-less lambda expression. The lambda expression is used to forward 
the call to the `executeCCommand`
+   class method. Note the capture-less lambda expression can decay to C-style 
function pointers.
+7. Configures the component to provide a C `celix_shell_command_t` service. 
Note that for a C service, the
+   `createUnassociatedProvidedService` must be used, because the component 
does not inherit `celix_shell_command_t`.
+   The service will not directly be registered, but instead will be registered 
in the component states `Starting` and
+   `Resuming`.
+8. "Build" the component so the DM will manage the component.
 
 
 ```C++
@@ -377,7 +380,8 @@ public:
             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());
+        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) {
@@ -394,7 +398,7 @@ public:
         auto& cmp = 
ctx->getDependencyManager()->createComponent<ComponentWithProvidedService>(); 
// <---------------<4>
 
         cmp.createProvidedService<celix::IShellCommand>()
-                .addProperty(celix::IShellCommand::COMMAND_NAME, 
"HelloComponent"); // <---------------------------------<5>
+                .addProperty(celix::IShellCommand::COMMAND_NAME, 
"HelloComponent"); // <-----------------------------<5>
 
         auto shellCmd = std::make_shared<celix_shell_command_t>();
         shellCmd->handle = static_cast<void*>(&cmp.getInstance());
@@ -405,7 +409,7 @@ public:
         }; // 
<------------------------------------------------------------------------------------------------------<6>
 
         cmp.createUnassociatedProvidedService(std::move(shellCmd), 
CELIX_SHELL_COMMAND_SERVICE_NAME)
-                .addProperty(CELIX_SHELL_COMMAND_NAME, "hello_component"); // 
< -----------------------------------------<7>
+                .addProperty(CELIX_SHELL_COMMAND_NAME, "hello_component"); // 
< -------------------------------------<7>
 
         cmp.build(); // 
<--------------------------------------------------------------------------------------------<8>
     }
@@ -416,41 +420,68 @@ 
CELIX_GEN_CXX_BUNDLE_ACTIVATOR(ComponentWithProvidedServiceActivator)
 ```
 
 # Component's Service Dependencies
-Components can be configured to have service dependencies. These service 
dependencies will influence the component's 
+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; 
+component can only be active if all required dependencies are available; where 
available means at least 1 matching
+service dependency is found.
 
-When configuring service dependencies, callbacks can be configured 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.
+When configuring service dependencies, callbacks can be configured for 
handling services that are being added,
+removed or for when a new highest ranking service is available.
+
+Service dependency callbacks can be configured with 3 different types of 
argument signatures:
+- A single argument for the service pointer (raw pointer or shared_ptr);
+- A service pointer (raw pointer or shared_ptr) as first argument and the 
service properties as second argument.
+- A service pointer (raw pointer or shared_ptr) as first argument, the service 
properties as second argument and
+  the bundle providing the service as third argument.
+
+Service dependency callbacks will always be called from the Celix event thread.
 
 A service change (injection/removal) can be handled by the component using a 
Locking-strategy or a suspend-strategy.
-This strategy can be configured per service dependency and expect the 
following behaviour from the component 
+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. 
+- Locking-strategy: The component implementation must ensure that the stored 
service pointers (and if applicable the
+  service properties and its bundle) are protected using a locking mechanism 
(e.g. a mutex).
+  This should ensure that services are no longer in use after they are removed 
(or replaced) from a component and
+  thus can be safely deleted from memory.
 - Suspend-strategy: The DM will ensure that before service dependency 
callbacks are called, all provided services
-  are (temporary) unregistered and the component is suspended (using the 
components' stop callback). This should mean
-  that there are no active users - through the provided services or active 
threads - of the service dependencies 
+  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.
+  that after a `stop` callback there are no active threads, thread pools, 
timers, etc - that use service dependencies -
+  are active anymore.
 
 ## Example: Component with a service dependencies in C
 The following example shows how a C component that has two service dependency 
on the `celix_shell_command_t` service.
 
-One service dependency is a required dependency with a suspend-strategy and 
uses a `set ` callback which ensure 
+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. 
+service can be `NULL` if there are no other matching services.
 
-The other dependency is an optional dependency with a locking-strategy and 
uses a `addWithProps` and 
+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. 
+and will be called with not only the service pointer, but also the service 
properties.
 
 Remarks for the C example:
-1. TODO
+1. Creates a mutex to protect the `cmdShells` field which is configured with a 
locking-strategy service dependency.
+2. Updates the `highestRankingCmdShell` field without locking. Note that 
because the service dependency is
+   configured with a suspend-strategy the 
`componentWithServiceDependency_setHighestRankingShellCommand` function
+   will only be called when the component is in the `Suspended` state or when 
it is not in the `Active` compound state.
+3. Locks the mutex and adds the newly added service to the `cmdShells` list. 
Note that because the service dependency
+   is configured with a locking-strategy the 
`componentWithServiceDependency_addShellCommand` and
+   `componentWithServiceDependency_removeShellCommand` functions can be called 
from any component lifecycle state.
+4. Creates a new DM service dependency object. Note that the DM service 
dependency is not yet known to the DM Component.
+5. Configures for which service name the service dependency will track 
services for. Optionally it is also possible
+   to fine tune the tracked service by providing a service version range 
and/or service filter.
+6. Configures the update strategy for the service dependency to 
suspend-strategy.
+7. Configures the service dependency as a required service dependency.
+8. Creates an empty service dependency callback options struct. This struct 
can be used to configure different
+   service dependency callbacks.
+9. Configures the `set` service dependency callback to 
`componentWithServiceDependency_setHighestRankingShellCommand`
+10. Configures the dependency manager to use the callbacks configures in opts.
+11. Adds the DM service dependency object to the DM component object.
+12. Configures the update strategy for the service dependency to 
locking-strategy.
+13. Configures the service dependency as an optional service dependency.
+14. Configures the `addWithProps` service dependency callback to 
`componentWithServiceDependency_addShellCommand`.
 
 ```C
 //src/component_with_service_dependency_activator.c
@@ -462,13 +493,13 @@ Remarks for the C example:
 
 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_thread_mutex_t mutex; //protects cmdShells
     celix_array_list_t* cmdShells;
 } component_with_service_dependency_t;
 
 static component_with_service_dependency_t* 
componentWithServiceDependency_create() {
     component_with_service_dependency_t* cmp = calloc(1, sizeof(*cmp));
-    celixThreadMutex_create(&cmp->mutex, NULL);
+    celixThreadMutex_create(&cmp->mutex, NULL); // 
<-----------------------------------------------------------------<1>
     cmp->cmdShells = celix_arrayList_create();
     return cmp;
 }
@@ -483,7 +514,7 @@ 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;
+    cmp->highestRankingCmdShell = shellCmd; // 
<---------------------------------------------------------------------<2>
 }
 
 static void componentWithServiceDependency_addShellCommand(
@@ -492,7 +523,7 @@ static void componentWithServiceDependency_addShellCommand(
         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);
+    celixThreadMutex_lock(&cmp->mutex); // 
<-------------------------------------------------------------------------<3>
     celix_arrayList_add(cmp->cmdShells, shellCmd);
     celixThreadMutex_unlock(&cmp->mutex);
 }
@@ -527,22 +558,22 @@ static celix_status_t 
componentWithServiceDependencyActivator_start(component_wi
             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);
+    celix_dm_service_dependency_t* dep1 = celix_dmServiceDependency_create(); 
// <-----------------------------------<4>
+    celix_dmServiceDependency_setService(dep1, 
CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL); // <-------------------<5>
+    celix_dmServiceDependency_setStrategy(dep1, 
DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND); // <------------------------<6>
+    celix_dmServiceDependency_setRequired(dep1, true); // 
<----------------------------------------------------------<7>
+    celix_dm_service_dependency_callback_options_t opts1 = 
CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; // <--<8>
+    opts1.set = 
(void*)componentWithServiceDependency_setHighestRankingShellCommand; // 
<----------------------------<9>
+    celix_dmServiceDependency_setCallbacksWithOptions(dep1, &opts1); // 
<-------------------------------------------<10>
+    celix_dmComponent_addServiceDependency(dmCmp, dep1); // 
<-------------------------------------------------------<11>
 
     //create optional service dependency with cardinality many and with a 
locking-strategy
     celix_dm_service_dependency_t* dep2 = celix_dmServiceDependency_create();
     celix_dmServiceDependency_setService(dep2, 
CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL);
-    celix_dmServiceDependency_setStrategy(dep2, 
DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING);
-    celix_dmServiceDependency_setRequired(dep2, false);
+    celix_dmServiceDependency_setStrategy(dep2, 
DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING);  // <----------------------<12>
+    celix_dmServiceDependency_setRequired(dep2, false); // 
<--------------------------------------------------------<13>
     celix_dm_service_dependency_callback_options_t opts2 = 
CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS;
-    opts2.addWithProps = (void*)componentWithServiceDependency_addShellCommand;
+    opts2.addWithProps = 
(void*)componentWithServiceDependency_addShellCommand;  // 
<-------------------------------<14>
     opts2.removeWithProps = 
(void*)componentWithServiceDependency_removeShellCommand;
     celix_dmServiceDependency_setCallbacksWithOptions(dep2, &opts2);
     celix_dmComponent_addServiceDependency(dmCmp, dep2);
@@ -560,23 +591,39 @@ CELIX_GEN_BUNDLE_ACTIVATOR(
 ```
 
 ## Example: Component with a service dependencies in C++
-The following example shows how a C++ component that has two service 
dependency. One 
+The following example shows how a C++ component that has two service 
dependency. One
 service dependency for the C++ `celix::IShellCommand` service and one for the 
C `celix_shell_command_t` service.
 
-The `celix::IShellCommand` service dependency is a required dependency with a 
suspend-strategy and uses a 
-`set ` callback which ensure that a single service is injected and that is 
always the highest ranking service. 
+The `celix::IShellCommand` service dependency is a required dependency with a 
suspend-strategy and uses a
+`set` callback which ensure that a single service is injected and that is 
always the highest ranking service.
 Note that the highest ranking service can be an empty shared_ptr if there are 
no service.
 
 The `celix_shell_command_t` service dependency is an optional dependency with 
a locking-strategy and uses a
-`addWithProperties` and `removeWithProperties` callback. 
+`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.
+and will be called with not only the service shared_ptr, but also the service 
properties.
 
-Note that for C++ component service dependencies there is no real different 
between a C++ or a C service; Both
-are injected as shared_ptr, and as optional properties or bundle argument the 
C++ variant are provided.
+Note that for C++ component service dependencies, there is no real different 
between a C++ or a C service dependency;
+In both cases the service pointers are injected using shared_ptr and if 
applicable the service properties and
+bundle argument are also provided as shared_ptr using the C++ 
`celix::Properties` and `celix::Bundle`.
 
 Remarks for the C++ example:
-1. TODO
+1. Creates a mutex to protect the `shellCommands` field which is configured 
with a locking-strategy service dependency.
+2. Updates the `highestRankingShellCmd` field without locking. Note that 
because the service dependency is
+   configured with a suspend-strategy the 
`ComponentWithServiceDependency::setHighestRankingShellCommand` method
+   will only be called when the component is in the `Suspended` state or when 
it is not in the `Active` compound state.
+3. Locks the mutex and adds the newly added service to the `shellCommands` 
list. Note that because the service
+   dependency is configured with a locking-strategy the 
`ComponentWithServiceDependency::addCShellCmd` and
+   `ComponentWithServiceDependency::removeCShellCmd` methods can be called 
from any component lifecycle state.
+4. Creates a new DM service dependency object, the service dependency is 
considered incomplete until the
+   service dependency, component or DM is build. Note that the 
`celix::dm::Component::createServiceDependency` method
+   is called without provided a service name, the service name will be 
inferred using the `celix::typeName`.
+5. Configures the service dependency set callback.
+6. Configures the service dependency as a required service dependency.
+7. Configures the update strategy for the service dependency to 
suspend-strategy.
+8. Creates another new DM service dependency object and in this case also 
explicitly provides the service name
+   to use (`CELIX_SHELL_COMMAND_SERVICE_NAME`).
+9. Builds the component and as result also builds the components' service 
dependencies (i.e. marking them as complete).
 
 ```C++
 //src/ComponentWithServiceDependencyActivator.cc
@@ -588,7 +635,7 @@ 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;
+        highestRankingShellCmd = cmdSvc; // 
<------------------------------------------------------------------------<2>
     }
 
     void addCShellCmd(
@@ -596,7 +643,7 @@ public:
             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};
+        std::lock_guard lck{mutex}; // 
<-----------------------------------------------------------------------------<3>
         shellCommands.emplace(id, cmdSvc);
     }
 
@@ -610,7 +657,7 @@ public:
     }
 private:
     std::shared_ptr<celix::IShellCommand> highestRankingShellCmd{};
-    std::mutex mutex{}; //protect below
+    std::mutex mutex{}; //protect shellCommands // 
<-----------------------------------------------------------------<1>
     std::unordered_map<long, std::shared_ptr<celix_shell_command_t>> 
shellCommands{};
 };
 
@@ -618,19 +665,19 @@ class ComponentWithServiceDependencyActivator {
 public:
     explicit ComponentWithServiceDependencyActivator(const 
std::shared_ptr<celix::BundleContext>& ctx) {
         using Cmp = ComponentWithServiceDependency;
-        auto& cmp = ctx->getDependencyManager()->createComponent<Cmp>(); // 
<-------------<1>
+        auto& cmp = ctx->getDependencyManager()->createComponent<Cmp>(); 
 
-        cmp.createServiceDependency<celix::IShellCommand>()
-                .setCallbacks(&Cmp::setHighestRankingShellCommand)
-                .setRequired(true)
-                .setStrategy(DependencyUpdateStrategy::suspend);
+        cmp.createServiceDependency<celix::IShellCommand>() // 
<-----------------------------------------------------<4>
+                .setCallbacks(&Cmp::setHighestRankingShellCommand) // 
<----------------------------------------------<5>
+                .setRequired(true) // 
<------------------------------------------------------------------------------<6>
+                .setStrategy(DependencyUpdateStrategy::suspend); // 
<------------------------------------------------<7>
 
-        
cmp.createServiceDependency<celix_shell_command_t>(CELIX_SHELL_COMMAND_SERVICE_NAME)
-                .setCallbacks(&Cmp::addCShellCmd, &Cmp::removeCShellCmd)
+        
cmp.createServiceDependency<celix_shell_command_t>(CELIX_SHELL_COMMAND_SERVICE_NAME)
 // <--------------------<8>
+                .setCallbacks(&Cmp::addCShellCmd, &Cmp::removeCShellCmd) 
                 .setRequired(false)
                 .setStrategy(DependencyUpdateStrategy::locking);
 
-        cmp.build(); // 
<--------------------------------------------------------------------------------------------<8>
+        cmp.build(); // 
<--------------------------------------------------------------------------------------------<9>
     }
 };
 
@@ -638,10 +685,20 @@ 
CELIX_GEN_CXX_BUNDLE_ACTIVATOR(ComponentWithServiceDependencyActivator)
 ```
 
 # When will a component be suspended
-
-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?
-
-# TODOs
-
-overview of function (e.g. setFilter for dependencies, etc)
\ No newline at end of file
+Components will only suspend if:
+- The component is in the state `Tracking Optional`;
+- The component has at least 1 service dependency where the update strategy is 
configured as suspend-strategy;
+- There is a service update event ongoing, where the update service event 
matches 1 of the components'
+  suspend-strategy service dependencies;
+- And least one of the component's matching suspend-strategy service 
dependency has a configured service injection/
+  removal callback configured.
+
+# The `celix::dm` shell command
+To interactively see the available components, their current lifecycle state, 
provided service and service dependencies
+the `celix::dm` shell command can be used.
+
+Examples of supported `dm` command lines are:
+- `celix::dm` - Show an overview of all components in the Celix framework. 
Only shows component lifecycle state.
+- `dm` - Same as `celix::dm` (as long as there is no colliding other `dm` 
commands).
+- `dm full` - Show a detailed overview of all components in the Celix 
framework. This also shows the provided
+  services and service dependencies of each component.
\ No newline at end of file
diff --git a/documents/services.md b/documents/services.md
index ae7e17bd..81e22a25 100644
--- a/documents/services.md
+++ b/documents/services.md
@@ -365,7 +365,7 @@ The Celix framework provides service usage through 
callbacks - instead of direct
 to ensure that services are prevented from removal while the services are 
still in use without forwarding 
 this responsibility to the user; i.e. by adding an api to "lock" and "unlock" 
services for usage.
 
-###Example: Using a service in C
+### Example: Using a service in C
 ```C
 #include <stdio.h>
 #include <celix_api.h>
@@ -400,7 +400,7 @@ static celix_status_t 
use_command_service_example_stop(use_command_service_examp
 CELIX_GEN_BUNDLE_ACTIVATOR(use_command_service_example_data_t, 
use_command_service_example_start, use_command_service_example_stop)
 ```
 
-###Example: Using a service in C++
+### Example: Using a service in C++
 ```C++
 //src/UsingCommandServicesExample.cc
 #include <celix/IShellCommand.h>
@@ -474,7 +474,7 @@ C++ service trackers are created and opened asynchronized, 
but closed synchroniz
 The closing is done synchronized so that users can be sure that after a 
`celix::ServiceTracker::close()` call the 
 added callbacks will not be invoked anymore.  
 
-###Example: Tracking services in C
+### Example: Tracking services in C
 ```C
 //src/track_command_services_example.c
 #include <stdio.h>
@@ -535,7 +535,7 @@ static celix_status_t 
track_command_services_example_stop(track_command_services
 CELIX_GEN_BUNDLE_ACTIVATOR(track_command_services_example_data_t, 
track_command_services_example_start, track_command_services_example_stop)
 ```
 
-###Example: Tracking services in C++
+### Example: Tracking services in C++
 ```C++
 //src/TrackingCommandServicesExample.cc
 #include <unordered_map>
@@ -625,3 +625,17 @@ Service tracker callback with a synchronized service 
registration
 ![Register Service Async](diagrams/services_tracker_services_rem_seq.png)
 Service tracker callback with a synchronized service un-registration
 ---
+
+# The `celix::query` shell command
+To interactively see the which service and service trackers are available the 
`celix::query` shell command 
+can be used.
+
+Examples of supported `query` command lines are:
+- `celix::query` - Show an overview of registered services and active service 
trackers per bundle.
+- `query` - Same as `celix::query` (as long as there is no colliding other 
`query` commands).
+- `query -v` - Show a detailed overview of registered services and active 
service trackers per bundle.
+  For registered services the services properties are also printed and for 
active service trackers the number
+  of tracked services is also printed.
+- `query foo` - Show an overview of registered services and active service 
tracker where "foo" is
+  (case-insensitive) part of the provided/tracked service name.   
+- `query (service.id>=10)` - Shown an overview of registered services which 
match the provided LDAP filter. 
diff --git 
a/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
index e44347e1..79883b40 100644
--- 
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
@@ -26,13 +26,13 @@
 
 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_thread_mutex_t mutex; //protects cmdShells
     celix_array_list_t* cmdShells;
 } component_with_service_dependency_t;
 
 static component_with_service_dependency_t* 
componentWithServiceDependency_create() {
     component_with_service_dependency_t* cmp = calloc(1, sizeof(*cmp));
-    celixThreadMutex_create(&cmp->mutex, NULL);
+    celixThreadMutex_create(&cmp->mutex, NULL); // 
<-----------------------------------------------------------------<1>
     cmp->cmdShells = celix_arrayList_create();
     return cmp;
 }
@@ -47,7 +47,7 @@ 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;
+    cmp->highestRankingCmdShell = shellCmd; // 
<---------------------------------------------------------------------<2>
 }
 
 static void componentWithServiceDependency_addShellCommand(
@@ -56,7 +56,7 @@ static void componentWithServiceDependency_addShellCommand(
         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);
+    celixThreadMutex_lock(&cmp->mutex); // 
<-------------------------------------------------------------------------<3>
     celix_arrayList_add(cmp->cmdShells, shellCmd);
     celixThreadMutex_unlock(&cmp->mutex);
 }
@@ -91,22 +91,22 @@ static celix_status_t 
componentWithServiceDependencyActivator_start(component_wi
             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);
+    celix_dm_service_dependency_t* dep1 = celix_dmServiceDependency_create(); 
// <-----------------------------------<4>
+    celix_dmServiceDependency_setService(dep1, 
CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL); // <-------------------<5>
+    celix_dmServiceDependency_setStrategy(dep1, 
DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND); // <------------------------<6>
+    celix_dmServiceDependency_setRequired(dep1, true); // 
<----------------------------------------------------------<7>
+    celix_dm_service_dependency_callback_options_t opts1 = 
CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; // <--<8>
+    opts1.set = 
(void*)componentWithServiceDependency_setHighestRankingShellCommand; // 
<----------------------------<9>
+    celix_dmServiceDependency_setCallbacksWithOptions(dep1, &opts1); // 
<-------------------------------------------<10>
+    celix_dmComponent_addServiceDependency(dmCmp, dep1); // 
<-------------------------------------------------------<11>
 
     //create optional service dependency with cardinality many and with a 
locking-strategy
     celix_dm_service_dependency_t* dep2 = celix_dmServiceDependency_create();
     celix_dmServiceDependency_setService(dep2, 
CELIX_SHELL_COMMAND_SERVICE_NAME, NULL, NULL);
-    celix_dmServiceDependency_setStrategy(dep2, 
DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING);
-    celix_dmServiceDependency_setRequired(dep2, false);
+    celix_dmServiceDependency_setStrategy(dep2, 
DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING);  // <----------------------<12>
+    celix_dmServiceDependency_setRequired(dep2, false); // 
<--------------------------------------------------------<13>
     celix_dm_service_dependency_callback_options_t opts2 = 
CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS;
-    opts2.addWithProps = (void*)componentWithServiceDependency_addShellCommand;
+    opts2.addWithProps = 
(void*)componentWithServiceDependency_addShellCommand;  // 
<-------------------------------<14>
     opts2.removeWithProps = 
(void*)componentWithServiceDependency_removeShellCommand;
     celix_dmServiceDependency_setCallbacksWithOptions(dep2, &opts2);
     celix_dmComponent_addServiceDependency(dmCmp, dep2);
diff --git 
a/examples/celix-examples/readme_cxx_examples/src/ComponentWithProvidedServiceActivator.cc
 
b/examples/celix-examples/readme_cxx_examples/src/ComponentWithProvidedServiceActivator.cc
index 31b9758e..73be1ab5 100644
--- 
a/examples/celix-examples/readme_cxx_examples/src/ComponentWithProvidedServiceActivator.cc
+++ 
b/examples/celix-examples/readme_cxx_examples/src/ComponentWithProvidedServiceActivator.cc
@@ -31,7 +31,8 @@ public:
             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());
+        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) {
@@ -48,7 +49,7 @@ public:
         auto& cmp = 
ctx->getDependencyManager()->createComponent<ComponentWithProvidedService>(); 
// <---------------<4>
 
         cmp.createProvidedService<celix::IShellCommand>()
-                .addProperty(celix::IShellCommand::COMMAND_NAME, 
"HelloComponent"); // <---------------------------------<5>
+                .addProperty(celix::IShellCommand::COMMAND_NAME, 
"HelloComponent"); // <-----------------------------<5>
 
         auto shellCmd = std::make_shared<celix_shell_command_t>();
         shellCmd->handle = static_cast<void*>(&cmp.getInstance());
@@ -59,7 +60,7 @@ public:
         }; // 
<------------------------------------------------------------------------------------------------------<6>
 
         cmp.createUnassociatedProvidedService(std::move(shellCmd), 
CELIX_SHELL_COMMAND_SERVICE_NAME)
-                .addProperty(CELIX_SHELL_COMMAND_NAME, "hello_component"); // 
< -----------------------------------------<7>
+                .addProperty(CELIX_SHELL_COMMAND_NAME, "hello_component"); // 
< -------------------------------------<7>
 
         cmp.build(); // 
<--------------------------------------------------------------------------------------------<8>
     }
diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt
index b33781a8..1cdae108 100644
--- a/libs/utils/CMakeLists.txt
+++ b/libs/utils/CMakeLists.txt
@@ -84,60 +84,64 @@ add_library(Celix::utils ALIAS utils)
 if (ENABLE_TESTING)
     add_subdirectory(gtest)
 
-    find_package(CppUTest REQUIRED)
-
-    include_directories(SYSTEM PRIVATE ${CppUTest_INCLUDE_DIR})
-    include_directories(include)
-    include_directories(src)
-
-    add_executable(hash_map_test private/test/hash_map_test.cpp)
-    target_link_libraries(hash_map_test Celix::utils CppUTest::CppUTest 
pthread)
-
-    add_executable(array_list_test private/test/array_list_test.cpp)
-    target_link_libraries(array_list_test  Celix::utils CppUTest::CppUTest 
pthread)
-
-    add_executable(celix_threads_test private/test/celix_threads_test.cpp)
-    target_link_libraries(celix_threads_test Celix::utils CppUTest::CppUTest 
${CppUTest_EXT_LIBRARIES} pthread)
-
-    add_executable(linked_list_test private/test/linked_list_test.cpp)
-    target_link_libraries(linked_list_test  Celix::utils CppUTest::CppUTest 
pthread)
-
-    add_executable(properties_test private/test/properties_test.cpp)
-    target_link_libraries(properties_test CppUTest::CppUTest 
CppUTest::CppUTestExt  Celix::utils pthread)
-
-    add_executable(utils_test private/test/utils_test.cpp)
-    target_link_libraries(utils_test CppUTest::CppUTest  Celix::utils pthread)
-
-    add_executable(ip_utils_test private/test/ip_utils_test.cpp)
-    target_link_libraries(ip_utils_test CppUTest::CppUTest  Celix::utils 
pthread)
-
-    add_executable(filter_test private/test/filter_test.cpp)
-    target_link_libraries(filter_test CppUTest::CppUTest  Celix::utils pthread)
-
-    add_executable(version_test private/test/version_test.cpp)
-    target_link_libraries(version_test CppUTest::CppUTest  Celix::utils 
pthread)
-
-    configure_file(private/resources-test/properties.txt 
${CMAKE_CURRENT_BINARY_DIR}/resources-test/properties.txt COPYONLY)
-
-    add_test(NAME run_array_list_test COMMAND array_list_test)
-    add_test(NAME run_hash_map_test COMMAND hash_map_test)
-    add_test(NAME run_celix_threads_test COMMAND celix_threads_test)
-    add_test(NAME run_linked_list_test COMMAND linked_list_test)
-    add_test(NAME run_properties_test COMMAND properties_test)
-    add_test(NAME run_utils_test COMMAND utils_test)
-    add_test(NAME run_ip_utils_test COMMAND ip_utils_test)
-    add_test(NAME filter_test COMMAND filter_test)
-    add_test(NAME version_test COMMAND version_test)
-
-    setup_target_for_coverage(array_list_test)
-    setup_target_for_coverage(hash_map_test)
-    setup_target_for_coverage(celix_threads_test)
-    setup_target_for_coverage(linked_list_test)
-    setup_target_for_coverage(properties_test)
-    setup_target_for_coverage(utils_test)
-    setup_target_for_coverage(ip_utils_test)
-    setup_target_for_coverage(filter_test)
-    setup_target_for_coverage(version_test)
+    find_package(CppUTest)
+
+    if (CppUTest_FOUND)
+        include_directories(SYSTEM PRIVATE ${CppUTest_INCLUDE_DIR})
+        include_directories(include)
+        include_directories(src)
+
+        add_executable(hash_map_test private/test/hash_map_test.cpp)
+        target_link_libraries(hash_map_test Celix::utils CppUTest::CppUTest 
pthread)
+
+        add_executable(array_list_test private/test/array_list_test.cpp)
+        target_link_libraries(array_list_test  Celix::utils CppUTest::CppUTest 
pthread)
+
+        add_executable(celix_threads_test private/test/celix_threads_test.cpp)
+        target_link_libraries(celix_threads_test Celix::utils 
CppUTest::CppUTest ${CppUTest_EXT_LIBRARIES} pthread)
+
+        add_executable(linked_list_test private/test/linked_list_test.cpp)
+        target_link_libraries(linked_list_test  Celix::utils 
CppUTest::CppUTest pthread)
+
+        add_executable(properties_test private/test/properties_test.cpp)
+        target_link_libraries(properties_test CppUTest::CppUTest 
CppUTest::CppUTestExt  Celix::utils pthread)
+
+        add_executable(utils_test private/test/utils_test.cpp)
+        target_link_libraries(utils_test CppUTest::CppUTest  Celix::utils 
pthread)
+
+        add_executable(ip_utils_test private/test/ip_utils_test.cpp)
+        target_link_libraries(ip_utils_test CppUTest::CppUTest  Celix::utils 
pthread)
+
+        add_executable(filter_test private/test/filter_test.cpp)
+        target_link_libraries(filter_test CppUTest::CppUTest  Celix::utils 
pthread)
+
+        add_executable(version_test private/test/version_test.cpp)
+        target_link_libraries(version_test CppUTest::CppUTest  Celix::utils 
pthread)
+
+        configure_file(private/resources-test/properties.txt 
${CMAKE_CURRENT_BINARY_DIR}/resources-test/properties.txt COPYONLY)
+
+        add_test(NAME run_array_list_test COMMAND array_list_test)
+        add_test(NAME run_hash_map_test COMMAND hash_map_test)
+        add_test(NAME run_celix_threads_test COMMAND celix_threads_test)
+        add_test(NAME run_linked_list_test COMMAND linked_list_test)
+        add_test(NAME run_properties_test COMMAND properties_test)
+        add_test(NAME run_utils_test COMMAND utils_test)
+        add_test(NAME run_ip_utils_test COMMAND ip_utils_test)
+        add_test(NAME filter_test COMMAND filter_test)
+        add_test(NAME version_test COMMAND version_test)
+
+        setup_target_for_coverage(array_list_test)
+        setup_target_for_coverage(hash_map_test)
+        setup_target_for_coverage(celix_threads_test)
+        setup_target_for_coverage(linked_list_test)
+        setup_target_for_coverage(properties_test)
+        setup_target_for_coverage(utils_test)
+        setup_target_for_coverage(ip_utils_test)
+        setup_target_for_coverage(filter_test)
+        setup_target_for_coverage(version_test)
+    else ()
+        message(WARNING "Cannot find CppUTest, deprecated cpputest-based unit 
test will not be added")
+    endif () #end CppUTest_FOUND
 
 endif ()
 

Reply via email to