blob: dc2bfc18e98f65cb135989f37720c6eaee5ff326 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Apache Celix Components / Apache Celix</title>
<link rel="icon" href="/assets/img/favicon.ico">
<link href="/assets/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/css/style.css" rel="stylesheet">
<style>
.card-body img {
max-width: 100%;
width: 100%;
height: auto;
}
.card-body img + em {
text-decoration: underline;
}
</style>
<script>
var _paq = window._paq = window._paq || [];
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="https://analytics.apache.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '9']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
</head>
<body class="light-grey">
<a href="https://github.com/apache/celix" class="github-ribbon">
<img src="/assets/img/forkme_right_red_aa0000.png" alt="Fork me on GitHub">
</a>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top">
<div class="container">
<a class="navbar-brand" href="/">
<img src="/assets/img/celix-white.svg" height="40" class="d-inline-block align-top" alt="Celix Logo">
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/download.cgi">Download</a>
</li>
<li class="nav-item dropdown active">
<a class="nav-link dropdown-toggle" href="#" id="ddDocs" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Docs
</a>
<div class="dropdown-menu" aria-labelledby="ddDocs">
<a class="dropdown-item" href="/docs/2.4.0/docs.html">2.4.0 (latest)</a>
<a class="dropdown-item" href="/docs/2.3.0/docs.html">2.3.0</a>
<a class="dropdown-item" href="/docs/2.2.1/docs.html">2.2.1</a>
<a class="dropdown-item" href="/docs/2.1.0/docs.html">2.1.0</a>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="ddContributing" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Contributing
</a>
<div class="dropdown-menu" aria-labelledby="ddContributing">
<a class="dropdown-item" href="/contributing/youatcelix.html">You at Celix</a>
<a class="dropdown-item" href="/contributing/submitting-patches.html">Submitting patches</a>
<a class="dropdown-item" href="/contributing/source-and-builds.html">Source code and builds</a>
<hr>
<a class="dropdown-item" href="/contributing/releasing.html">Releasing</a>
<a class="dropdown-item" href="/contributing/volunteers.html">Volunteers</a>
<a class="dropdown-item" href="https://whimsy.apache.org/board/minutes/Celix.html">Board Reports</a>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="ddSupport" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Support
</a>
<div class="dropdown-menu" aria-labelledby="ddSupport">
<a class="dropdown-item" href="/support/mailing-list.html">Mailing Lists</a>
<a class="dropdown-item" href="/support/issue-tracking.html">Issue Tracking</a>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="ddFoundation" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
ASF
</a>
<div class="dropdown-menu" aria-labelledby="ddFoundation">
<a class="dropdown-item" href="https://www.apache.org/">ASF Home</a>
<a class="dropdown-item" href="https://www.apache.org/foundation/how-it-works.html">How it works</a>
<a class="dropdown-item" href="https://www.apache.org/licenses/">License</a>
<a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
<a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a>
<a class="dropdown-item" href="https://www.apache.org/security/">Security</a>
<a class="dropdown-item" href="https://www.apache.org/foundation/policies/conduct">Code of Conduct</a>
</div>
</li>
</ul>
</div>
</div>
</nav>
<div class="section">
<div class="container">
<div class="row py-4">
<div class="col-sm-12 card">
<div class="card-body pt-5">
<a class="edit-on-gh" href="https://github.com/apache/celix/edit/master/documents/components.md" title="Edit this page on GitHub">Edit on GitHub</a>
<a href="/docs/2.4.0/docs.html" title="back to documentation">&lt;&lt; back to documentation</a>
<!--
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.
-->
<h1 id="apache-celix-components">Apache Celix Components</h1>
<p>In Apache Celix, components are plain old C/C++ objects (POCOs) managed by the Apache Celix Dependency Manager (DM).
Components can provide services and depend on services. Components are configured declarative using the DM api.</p>
<p>Service dependencies will influence the component&rsquo;s lifecycle as a component will only be active when all required
dependencies are available.<br>
The DM is responsible for managing the component&rsquo;s service dependencies, the component&rsquo;s lifecycle and when
to register/unregister the component&rsquo;s provided services.</p>
<p>Note that the Apache Celix Dependency Manager is inspired by the
<a href="http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager.html">Apache Felix Dependency Manager</a>,
adapted to Apache Celix and the C/C++ usage.</p>
<h1 id="component-lifecycle">Component Lifecycle</h1>
<p>Each component has its own lifecycle.
A component&rsquo;s lifecycle state model is depicted in the state diagram below.</p>
<p><img src="diagrams/component_lifecycle.png" alt="Component Life Cycle"></p>
<p>The DM can be used to configure a component&rsquo;s lifecycle callbacks, the following component&rsquo;s lifecycle callbacks can
be configured:</p>
<ul>
<li><code>init</code></li>
<li><code>start</code></li>
<li><code>stop</code></li>
<li><code>deinit</code></li>
</ul>
<p>These callbacks are used in the intermediate component&rsquo;s lifecycle states <code>Initializing</code>, <code>Starting</code>, <code>Suspending</code>, <code>Resuming</code>, <code>Stopping</code> and <code>Deinitializing</code> and the lifecycle callbacks are always called from the Celix event thread.</p>
<p>A component has the following lifecycle states:</p>
<ul>
<li><code>Inactive</code>: The component is inactive and the DM is not managing the component yet.</li>
<li><code>Waiting For Required</code>: The component is waiting for required service dependencies.</li>
<li><code>Initializing</code>: The component has found its required dependencies and is initializing by
calling the <code>init</code> callback.</li>
<li><code>Initialized And Waiting For Required</code>: The component has been initialized, but is waiting for required
dependencies.
_Note: that this can mean that:
<ul>
<li>During the <code>init</code> callback, 1 or more unavailable required service dependencies where added.</li>
<li>The component was active, but 1 or more required service dependency where removed and as result the
component is not active anymore.</li>
</ul>
</li>
<li><code>Starting</code>: The component has found its required dependencies and is starting by calling the <code>start</code> callback and
registering the components provided services.</li>
<li><code>Tracking Optional</code>: The component has found its required dependencies and is started. It is still tracking for
additional optional and required services.</li>
<li><code>Suspending</code>: 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 <code>stop</code> callback.</li>
<li><code>Suspended</code>: The component has found its required dependencies and is suspended so that a service change can be
processed.</li>
<li><code>Resuming</code>: The component has found its required dependencies, a service change has been processed, and it is
resuming by calling the <code>start</code> callback and registering the components provided services.</li>
<li><code>Stopping</code>: The component has lost one or more of its required dependencies and is stopping by unregistering the
components provided service and calling the <code>stop</code> callback.</li>
<li><code>Deinitializing</code>: The component is being removed and is deinitializing by calling the <code>deinit</code> callback.</li>
</ul>
<h2 id="component-api">Component API</h2>
<p>The DM Component C api can be found in the <code>celix_dm_component.h</code> header and the C++ api can be found in the
<code>celix/dm/Component.h</code> header.</p>
<h2 id="example-create-and-configure-components-lifecycle-callbacks-in-c">Example: Create and configure component&rsquo;s lifecycle callbacks in C</h2>
<p>The following example shows how a simple component can be created and managed with the DM in C.
Because the component&rsquo;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.</p>
<p>Remarks for the C example:</p>
<ol>
<li>Although this is a C component. The simple component functions have been design for a component approach,
using the component pointer as first argument.</li>
<li>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.</li>
<li>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.</li>
<li>Configures the component implementation in the DM component, so that the implementation pointer can be used
in the configured component callbacks.</li>
<li>Configures the component lifecycle callbacks to the DM Component. These callbacks should accept the component
implementation as its only argument. The <code>CELIX_DM_COMPONENT_SET_CALLBACKS</code> marco is used instead of the
<code>celix_dmComponent_setCallbacks</code> function so that the component implementation type can directly be used
in the lifecycle callbacks (instead of <code>void*</code>).</li>
<li>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 <code>CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION</code> marco
is used instead of the <code>celix_dmComponent_setImplementationDestroyFunction</code> function so that the component
implementation type can be directly used in the callback (instead of <code>void*</code>).</li>
<li>Adds the DM Component the DM and as result the DM will that point on manage the components&rsquo; lifecycle, service
dependencies and provided services.</li>
<li>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.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#080;font-style:italic">//src/simple_component_activator.c
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#080">#include</span> <span style="color:#080">&lt;stdio.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix_bundle_activator.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix_dm_component.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080"></span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">//********************* COMPONENT *******************************/
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">typedef</span> <span style="color:#a2f;font-weight:bold">struct</span> simple_component {
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">int</span> transitionCount; <span style="color:#080;font-style:italic">//not protected, only updated and read in the celix event thread.
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>} <span style="color:#0b0;font-weight:bold">simple_component_t</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">simple_component_t</span><span style="color:#666">*</span> <span style="color:#00a000">simpleComponent_create</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">simple_component_t</span><span style="color:#666">*</span> cmp <span style="color:#666">=</span> <span style="color:#00a000">calloc</span>(<span style="color:#666">1</span>, <span style="color:#a2f;font-weight:bold">sizeof</span>(<span style="color:#666">*</span>cmp));
</span></span><span style="display:flex;"><span> cmp<span style="color:#666">-&gt;</span>transitionCount <span style="color:#666">=</span> <span style="color:#666">1</span>;
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> cmp;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">simpleComponent_destroy</span>(<span style="color:#0b0;font-weight:bold">simple_component_t</span><span style="color:#666">*</span> cmp) {
</span></span><span style="display:flex;"><span> <span style="color:#00a000">free</span>(cmp);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">int</span> <span style="color:#00a000">simpleComponent_init</span>(<span style="color:#0b0;font-weight:bold">simple_component_t</span><span style="color:#666">*</span> cmp) { <span style="color:#080;font-style:italic">// &lt;------------------------------------------------------&lt;1&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">printf</span>(<span style="color:#b44">&#34;Initializing simple component. Transition nr %i</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">&#34;</span>, cmp<span style="color:#666">-&gt;</span>transitionCount<span style="color:#666">++</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> <span style="color:#666">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">int</span> <span style="color:#00a000">simpleComponent_start</span>(<span style="color:#0b0;font-weight:bold">simple_component_t</span><span style="color:#666">*</span> cmp) {
</span></span><span style="display:flex;"><span> <span style="color:#00a000">printf</span>(<span style="color:#b44">&#34;Starting simple component. Transition nr %i</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">&#34;</span>, cmp<span style="color:#666">-&gt;</span>transitionCount<span style="color:#666">++</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> <span style="color:#666">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">int</span> <span style="color:#00a000">simpleComponent_stop</span>(<span style="color:#0b0;font-weight:bold">simple_component_t</span><span style="color:#666">*</span> cmp) {
</span></span><span style="display:flex;"><span> <span style="color:#00a000">printf</span>(<span style="color:#b44">&#34;Stopping simple component. Transition nr %i</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">&#34;</span>, cmp<span style="color:#666">-&gt;</span>transitionCount<span style="color:#666">++</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> <span style="color:#666">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">int</span> <span style="color:#00a000">simpleComponent_deinit</span>(<span style="color:#0b0;font-weight:bold">simple_component_t</span><span style="color:#666">*</span> cmp) {
</span></span><span style="display:flex;"><span> <span style="color:#00a000">printf</span>(<span style="color:#b44">&#34;De-initializing simple component. Transition nr %i</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">&#34;</span>, cmp<span style="color:#666">-&gt;</span>transitionCount<span style="color:#666">++</span>);
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> <span style="color:#666">0</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">//********************* ACTIVATOR *******************************/
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">typedef</span> <span style="color:#a2f;font-weight:bold">struct</span> simple_component_activator {
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//nop
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>} <span style="color:#0b0;font-weight:bold">simple_component_activator_t</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">celix_status_t</span> <span style="color:#00a000">simpleComponentActivator_start</span>(<span style="color:#0b0;font-weight:bold">simple_component_activator_t</span> <span style="color:#666">*</span>act, <span style="color:#0b0;font-weight:bold">celix_bundle_context_t</span> <span style="color:#666">*</span>ctx) {
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//creating component
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">simple_component_t</span><span style="color:#666">*</span> impl <span style="color:#666">=</span> <span style="color:#00a000">simpleComponent_create</span>(); <span style="color:#080;font-style:italic">// &lt;--------------------------------------------------------&lt;2&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//create and configuring component and its lifecycle callbacks using the Apache Celix Dependency Manager
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_dm_component_t</span><span style="color:#666">*</span> dmCmp <span style="color:#666">=</span> <span style="color:#00a000">celix_dmComponent_create</span>(ctx, <span style="color:#b44">&#34;simple_component_1&#34;</span>); <span style="color:#080;font-style:italic">// &lt;--------------------------&lt;3&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">celix_dmComponent_setImplementation</span>(dmCmp, impl); <span style="color:#080;font-style:italic">// &lt;-----------------------------------------------------------&lt;4&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">CELIX_DM_COMPONENT_SET_CALLBACKS</span>(
</span></span><span style="display:flex;"><span> dmCmp,
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">simple_component_t</span>,
</span></span><span style="display:flex;"><span> simpleComponent_init,
</span></span><span style="display:flex;"><span> simpleComponent_start,
</span></span><span style="display:flex;"><span> simpleComponent_stop,
</span></span><span style="display:flex;"><span> simpleComponent_deinit); <span style="color:#080;font-style:italic">// &lt;----------------------------------------------------------------------------&lt;5&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION</span>(
</span></span><span style="display:flex;"><span> dmCmp,
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">simple_component_t</span>,
</span></span><span style="display:flex;"><span> simpleComponent_destroy); <span style="color:#080;font-style:italic">// &lt;---------------------------------------------------------------------------&lt;6&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//Add dm component to the dm.
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_dependency_manager_t</span><span style="color:#666">*</span> dm <span style="color:#666">=</span> <span style="color:#00a000">celix_bundleContext_getDependencyManager</span>(ctx);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_dependencyManager_add</span>(dm, dmCmp); <span style="color:#080;font-style:italic">// &lt;---------------------------------------------------------------------&lt;7&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#a2f;font-weight:bold">return</span> CELIX_SUCCESS;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#00a000">CELIX_GEN_BUNDLE_ACTIVATOR</span>(<span style="color:#0b0;font-weight:bold">simple_component_activator_t</span>, simpleComponentActivator_start, <span style="color:#a2f">NULL</span>) <span style="color:#080;font-style:italic">// &lt;------------------&lt;8&gt;
</span></span></span></code></pre></div><h2 id="example-create-and-configure-components-lifecycle-callbacks-in-c-1">Example: Create and configure component&rsquo;s lifecycle callbacks in C++</h2>
<p>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.</p>
<p>Remarks for the C++ example:</p>
<ol>
<li>For C++ the DM can directly work on classes and as result lifecycle callback can be class methods.</li>
<li>Creates a component implementation using a unique_ptr.</li>
<li>Create a C++ DM Component and directly add it to the DM. For C++ DM Component needs to be &ldquo;build&rdquo; first, before the
DM will manage them. This way C++ components can be build using a fluent api and marked complete with a <code>build()</code>
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. <code>ctx-&gt;getDependencyManager()-&gt;createComponent&lt;CmpWithDefaultCTOR&gt;()</code>).</li>
<li>Configures the component lifecycle callbacks as class methods. The DM will call these callbacks using the
component implementation raw pointer as object instance (<code>this</code>).</li>
<li>&ldquo;Builds&rdquo; 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.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-C++" data-lang="C++"><span style="display:flex;"><span><span style="color:#080;font-style:italic">//src/SimpleComponentActivator.cc
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix/BundleActivator.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080"></span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">class</span> <span style="color:#00f">SimpleComponent</span> {
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">public</span><span style="color:#666">:</span>
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">void</span> init() { <span style="color:#080;font-style:italic">// &lt;-----------------------------------------------------------------------------------------------&lt;1&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> std<span style="color:#666">::</span>cout <span style="color:#666">&lt;&lt;</span> <span style="color:#b44">&#34;Initializing simple component. Transition nr &#34;</span> <span style="color:#666">&lt;&lt;</span> transitionCount<span style="color:#666">++</span> <span style="color:#666">&lt;&lt;</span> std<span style="color:#666">::</span>endl;
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">start</span>() {
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>cout <span style="color:#666">&lt;&lt;</span> <span style="color:#b44">&#34;starting simple component. Transition nr &#34;</span> <span style="color:#666">&lt;&lt;</span> transitionCount<span style="color:#666">++</span> <span style="color:#666">&lt;&lt;</span> std<span style="color:#666">::</span>endl;
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">stop</span>() {
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>cout <span style="color:#666">&lt;&lt;</span> <span style="color:#b44">&#34;Stopping simple component. Transition nr &#34;</span> <span style="color:#666">&lt;&lt;</span> transitionCount<span style="color:#666">++</span> <span style="color:#666">&lt;&lt;</span> std<span style="color:#666">::</span>endl;
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">deinit</span>() {
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>cout <span style="color:#666">&lt;&lt;</span> <span style="color:#b44">&#34;De-initializing simple component. Transition nr &#34;</span> <span style="color:#666">&lt;&lt;</span> transitionCount<span style="color:#666">++</span> <span style="color:#666">&lt;&lt;</span> std<span style="color:#666">::</span>endl;
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">private</span><span style="color:#666">:</span>
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">int</span> transitionCount <span style="color:#666">=</span> <span style="color:#666">1</span>; <span style="color:#080;font-style:italic">//not protected, only updated and read in the celix event thread.
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">class</span> <span style="color:#00f">SimpleComponentActivator</span> {
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">public</span><span style="color:#666">:</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">explicit</span> SimpleComponentActivator(<span style="color:#a2f;font-weight:bold">const</span> std<span style="color:#666">::</span>shared_ptr<span style="color:#666">&lt;</span>celix<span style="color:#666">::</span>BundleContext<span style="color:#666">&gt;&amp;</span> ctx) {
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">auto</span> cmp <span style="color:#666">=</span> std<span style="color:#666">::</span>make_unique<span style="color:#666">&lt;</span>SimpleComponent<span style="color:#666">&gt;</span>(); <span style="color:#080;font-style:italic">// &lt;---------------------------------------------------------&lt;2&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> ctx<span style="color:#666">-&gt;</span>getDependencyManager()<span style="color:#666">-&gt;</span>createComponent(std<span style="color:#666">::</span>move(cmp), <span style="color:#b44">&#34;SimpleComponent1&#34;</span>) <span style="color:#080;font-style:italic">// &lt;------------------------&lt;3&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> .setCallbacks(
</span></span><span style="display:flex;"><span> <span style="color:#666">&amp;</span>SimpleComponent<span style="color:#666">::</span>init,
</span></span><span style="display:flex;"><span> <span style="color:#666">&amp;</span>SimpleComponent<span style="color:#666">::</span>start,
</span></span><span style="display:flex;"><span> <span style="color:#666">&amp;</span>SimpleComponent<span style="color:#666">::</span>stop,
</span></span><span style="display:flex;"><span> <span style="color:#666">&amp;</span>SimpleComponent<span style="color:#666">::</span>deinit) <span style="color:#080;font-style:italic">// &lt;---------------------------------------------------------------&lt;4&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> .build(); <span style="color:#080;font-style:italic">// &lt;---------------------------------------------------------------------------------------&lt;5&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> }
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>CELIX_GEN_CXX_BUNDLE_ACTIVATOR(SimpleComponentActivator)
</span></span></code></pre></div><h1 id="components-provided-services">Component&rsquo;s Provided Services</h1>
<p>Components can be configured to provide services. These provided services will result in service registrations
when a component is <code>Starting</code> or <code>Resuming</code> (i.e. when a component goes to the <code>Tracking Optional</code> state).</p>
<p>If a component provide services, these services will have an additional automatically added service property - named &ldquo;component.uuid&rdquo; - next to its configured provided service properties. The &ldquo;component.uuid&rdquo; service property can be
used to identify if a service is provided by a component and which component.</p>
<h2 id="example-component-with-a-provided-service-in-c">Example: Component with a provided service in C</h2>
<p>The following example shows how a component that provide a <code>celix_shell_command</code> service.</p>
<p>Remarks for the C example:</p>
<ol>
<li>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 &ldquo;outlives&rdquo; the component, because all components are removed before a bundle
is completely stopped.</li>
<li>Configures a provided service (interface) for the component. The service will not directly be registered, but
instead will be registered in the component states <code>Starting</code> and <code>Resuming</code>.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-C" data-lang="C"><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//src/component_with_provided_service_activator.c
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#080">#include</span> <span style="color:#080">&lt;stdlib.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix_bundle_activator.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix_shell_command.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080"></span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">//********************* COMPONENT *******************************/
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">typedef</span> <span style="color:#a2f;font-weight:bold">struct</span> component_with_provided_service {
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">int</span> callCount; <span style="color:#080;font-style:italic">//atomic
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>} <span style="color:#0b0;font-weight:bold">component_with_provided_service_t</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">component_with_provided_service_t</span><span style="color:#666">*</span> <span style="color:#00a000">componentWithProvidedService_create</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">component_with_provided_service_t</span><span style="color:#666">*</span> cmp <span style="color:#666">=</span> <span style="color:#00a000">calloc</span>(<span style="color:#666">1</span>, <span style="color:#a2f;font-weight:bold">sizeof</span>(<span style="color:#666">*</span>cmp));
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> cmp;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">componentWithProvidedService_destroy</span>(<span style="color:#0b0;font-weight:bold">component_with_provided_service_t</span><span style="color:#666">*</span> cmp) {
</span></span><span style="display:flex;"><span> <span style="color:#00a000">free</span>(cmp);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">bool</span> <span style="color:#00a000">componentWithProvidedService_executeCommand</span>(
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">component_with_provided_service_t</span> <span style="color:#666">*</span>cmp,
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">const</span> <span style="color:#0b0;font-weight:bold">char</span> <span style="color:#666">*</span>commandLine,
</span></span><span style="display:flex;"><span> FILE <span style="color:#666">*</span>outStream,
</span></span><span style="display:flex;"><span> FILE <span style="color:#666">*</span>errorStream CELIX_UNUSED) {
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">int</span> count <span style="color:#666">=</span> <span style="color:#00a000">__atomic_add_fetch</span>(<span style="color:#666">&amp;</span>cmp<span style="color:#666">-&gt;</span>callCount, <span style="color:#666">1</span>, __ATOMIC_SEQ_CST);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">fprintf</span>(outStream, <span style="color:#b44">&#34;Hello from cmp. command called %i times. commandLine: %s</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">&#34;</span>, count, commandLine);
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> <span style="color:#a2f">true</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">//********************* ACTIVATOR *******************************/
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">typedef</span> <span style="color:#a2f;font-weight:bold">struct</span> component_with_provided_service_activator {
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">celix_shell_command_t</span> shellCmd; <span style="color:#080;font-style:italic">// &lt;-----------------------------------------------------------------------------&lt;1&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>} <span style="color:#0b0;font-weight:bold">component_with_provided_service_activator_t</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">celix_status_t</span> <span style="color:#00a000">componentWithProvidedServiceActivator_start</span>(<span style="color:#0b0;font-weight:bold">component_with_provided_service_activator_t</span> <span style="color:#666">*</span>act, <span style="color:#0b0;font-weight:bold">celix_bundle_context_t</span> <span style="color:#666">*</span>ctx) {
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//creating component
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">component_with_provided_service_t</span><span style="color:#666">*</span> impl <span style="color:#666">=</span> <span style="color:#00a000">componentWithProvidedService_create</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//create and configuring component and its lifecycle callbacks using the Apache Celix Dependency Manager
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_dm_component_t</span><span style="color:#666">*</span> dmCmp <span style="color:#666">=</span> <span style="color:#00a000">celix_dmComponent_create</span>(ctx, <span style="color:#b44">&#34;component_with_provided_service_1&#34;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_dmComponent_setImplementation</span>(dmCmp, impl);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION</span>(
</span></span><span style="display:flex;"><span> dmCmp,
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">component_with_provided_service_t</span>,
</span></span><span style="display:flex;"><span> componentWithProvidedService_destroy);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//configure provided service
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> act<span style="color:#666">-&gt;</span>shellCmd.handle <span style="color:#666">=</span> impl;
</span></span><span style="display:flex;"><span> act<span style="color:#666">-&gt;</span>shellCmd.executeCommand <span style="color:#666">=</span> (<span style="color:#0b0;font-weight:bold">void</span><span style="color:#666">*</span>)componentWithProvidedService_executeCommand;
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">celix_properties_t</span><span style="color:#666">*</span> props <span style="color:#666">=</span> <span style="color:#00a000">celix_properties_create</span>();
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_properties_set</span>(props, CELIX_SHELL_COMMAND_NAME, <span style="color:#b44">&#34;hello_component&#34;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_dmComponent_addInterface</span>(
</span></span><span style="display:flex;"><span> dmCmp,
</span></span><span style="display:flex;"><span> CELIX_SHELL_COMMAND_SERVICE_NAME,
</span></span><span style="display:flex;"><span> CELIX_SHELL_COMMAND_SERVICE_VERSION,
</span></span><span style="display:flex;"><span> <span style="color:#666">&amp;</span>act<span style="color:#666">-&gt;</span>shellCmd,
</span></span><span style="display:flex;"><span> props); <span style="color:#080;font-style:italic">// &lt;---------------------------------------------------------------------------------------------&lt;2&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//Add dm component to the dm.
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_dependency_manager_t</span><span style="color:#666">*</span> dm <span style="color:#666">=</span> <span style="color:#00a000">celix_bundleContext_getDependencyManager</span>(ctx);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_dependencyManager_add</span>(dm, dmCmp);
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> CELIX_SUCCESS;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#00a000">CELIX_GEN_BUNDLE_ACTIVATOR</span>(
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">component_with_provided_service_activator_t</span>,
</span></span><span style="display:flex;"><span> componentWithProvidedServiceActivator_start,
</span></span><span style="display:flex;"><span> <span style="color:#a2f">NULL</span>)
</span></span></code></pre></div><h2 id="example-component-with-a-provided-service-in-c-1">Example: Component with a provided service in C++</h2>
<p>The following example shows how a C++ component that provide a C++ <code>celix::IShellCommand</code> service
and a C <code>celix_shell_command</code> service. For a C++ component it&rsquo;s possible to provide C and C++ services.</p>
<p>Remarks for the C++ example:</p>
<ol>
<li>If a component provides a C++ services, it also expected that the component implementation inherits the service
interface.</li>
<li>The overridden <code>executeCommand</code> method of <code>celix::IShellCommand</code>.</li>
<li>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.</li>
<li>Creating a component using only a template argument. The DM will construct - using a default constructor - a
component implementation instance.</li>
<li>Configures the component to provide a C++ <code>celix::IShellCommand</code> service. Note that because the component
implementation is an instance of <code>celix::IShellCommand</code> no additional storage is needed. The service will not
directly be registered, but instead will be registered in the components states <code>Starting</code> and <code>Resuming</code>.</li>
<li>Set the C <code>executeCommand</code> function pointer of the <code>celix_shell_command_t</code> service interface struct to a
capture-less lambda expression. The lambda expression is used to forward the call to the <code>executeCCommand</code>
class method. Note the capture-less lambda expression can decay to C-style function pointers.</li>
<li>Configures the component to provide a C <code>celix_shell_command_t</code> service. Note that for a C service, the
<code>createUnassociatedProvidedService</code> must be used, because the component does not inherit <code>celix_shell_command_t</code>.
The service will not directly be registered, but instead will be registered in the component states <code>Starting</code> and
<code>Resuming</code>.</li>
<li>&ldquo;Build&rdquo; the component so the DM will manage the component.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-C++" data-lang="C++"><span style="display:flex;"><span><span style="color:#080;font-style:italic">//src/ComponentWithProvidedServiceActivator.cc
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix/BundleActivator.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix/IShellCommand.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix_shell_command.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080"></span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">class</span> <span style="color:#00f">ComponentWithProvidedService</span> <span style="color:#666">:</span> <span style="color:#a2f;font-weight:bold">public</span> celix<span style="color:#666">::</span>IShellCommand { <span style="color:#080;font-style:italic">// &lt;----------------------------------------------&lt;1&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#a2f;font-weight:bold">public</span><span style="color:#666">:</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">~</span>ComponentWithProvidedService() <span style="color:#a2f;font-weight:bold">noexcept</span> <span style="color:#a2f;font-weight:bold">override</span> <span style="color:#666">=</span> <span style="color:#a2f;font-weight:bold">default</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">executeCommand</span>(
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">const</span> std<span style="color:#666">::</span>string<span style="color:#666">&amp;</span> commandLine,
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">const</span> std<span style="color:#666">::</span>vector<span style="color:#666">&lt;</span>std<span style="color:#666">::</span>string<span style="color:#666">&gt;&amp;</span> <span style="color:#080;font-style:italic">/*commandArgs*/</span>,
</span></span><span style="display:flex;"><span> FILE<span style="color:#666">*</span> outStream,
</span></span><span style="display:flex;"><span> FILE<span style="color:#666">*</span> <span style="color:#080;font-style:italic">/*errorStream*/</span>) <span style="color:#a2f;font-weight:bold">override</span> {
</span></span><span style="display:flex;"><span> fprintf(outStream, <span style="color:#b44">&#34;Hello from cmp. C++ command called %i times. commandLine is %s</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">&#34;</span>,
</span></span><span style="display:flex;"><span> cxxCallCount<span style="color:#666">++</span>, commandLine.c_str());
</span></span><span style="display:flex;"><span> } <span style="color:#080;font-style:italic">// &lt;-----------------------------------------------------------------------------------------------------------&lt;2&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">executeCCommand</span>(<span style="color:#a2f;font-weight:bold">const</span> <span style="color:#0b0;font-weight:bold">char</span><span style="color:#666">*</span> commandLine, FILE<span style="color:#666">*</span> outStream) {
</span></span><span style="display:flex;"><span> fprintf(outStream, <span style="color:#b44">&#34;Hello from cmp. C command called %i times. commandLine is %s</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">&#34;</span>, cCallCount<span style="color:#666">++</span>, commandLine);
</span></span><span style="display:flex;"><span> } <span style="color:#080;font-style:italic">// &lt;-----------------------------------------------------------------------------------------------------------&lt;3&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#a2f;font-weight:bold">private</span><span style="color:#666">:</span>
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>atomic<span style="color:#666">&lt;</span><span style="color:#0b0;font-weight:bold">int</span><span style="color:#666">&gt;</span> cxxCallCount{<span style="color:#666">1</span>};
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>atomic<span style="color:#666">&lt;</span><span style="color:#0b0;font-weight:bold">int</span><span style="color:#666">&gt;</span> cCallCount{<span style="color:#666">1</span>};
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">class</span> <span style="color:#00f">ComponentWithProvidedServiceActivator</span> {
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">public</span><span style="color:#666">:</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">explicit</span> ComponentWithProvidedServiceActivator(<span style="color:#a2f;font-weight:bold">const</span> std<span style="color:#666">::</span>shared_ptr<span style="color:#666">&lt;</span>celix<span style="color:#666">::</span>BundleContext<span style="color:#666">&gt;&amp;</span> ctx) {
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">auto</span><span style="color:#666">&amp;</span> cmp <span style="color:#666">=</span> ctx<span style="color:#666">-&gt;</span>getDependencyManager()<span style="color:#666">-&gt;</span>createComponent<span style="color:#666">&lt;</span>ComponentWithProvidedService<span style="color:#666">&gt;</span>(); <span style="color:#080;font-style:italic">// &lt;---------------&lt;4&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span> cmp.createProvidedService<span style="color:#666">&lt;</span>celix<span style="color:#666">::</span>IShellCommand<span style="color:#666">&gt;</span>()
</span></span><span style="display:flex;"><span> .addProperty(celix<span style="color:#666">::</span>IShellCommand<span style="color:#666">::</span>COMMAND_NAME, <span style="color:#b44">&#34;HelloComponent&#34;</span>); <span style="color:#080;font-style:italic">// &lt;-----------------------------&lt;5&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">auto</span> shellCmd <span style="color:#666">=</span> std<span style="color:#666">::</span>make_shared<span style="color:#666">&lt;</span>celix_shell_command_t<span style="color:#666">&gt;</span>();
</span></span><span style="display:flex;"><span> shellCmd<span style="color:#666">-&gt;</span>handle <span style="color:#666">=</span> <span style="color:#a2f;font-weight:bold">static_cast</span><span style="color:#666">&lt;</span><span style="color:#0b0;font-weight:bold">void</span><span style="color:#666">*&gt;</span>(<span style="color:#666">&amp;</span>cmp.getInstance());
</span></span><span style="display:flex;"><span> shellCmd<span style="color:#666">-&gt;</span>executeCommand <span style="color:#666">=</span> [](<span style="color:#0b0;font-weight:bold">void</span><span style="color:#666">*</span> handle, <span style="color:#a2f;font-weight:bold">const</span> <span style="color:#0b0;font-weight:bold">char</span><span style="color:#666">*</span> commandLine, FILE<span style="color:#666">*</span> outStream, FILE<span style="color:#666">*</span>) <span style="color:#666">-&gt;</span> <span style="color:#0b0;font-weight:bold">bool</span> {
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">auto</span><span style="color:#666">*</span> impl <span style="color:#666">=</span> <span style="color:#a2f;font-weight:bold">static_cast</span><span style="color:#666">&lt;</span>ComponentWithProvidedService<span style="color:#666">*&gt;</span>(handle);
</span></span><span style="display:flex;"><span> impl<span style="color:#666">-&gt;</span>executeCCommand(commandLine, outStream);
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> <span style="color:#a2f">true</span>;
</span></span><span style="display:flex;"><span> }; <span style="color:#080;font-style:italic">// &lt;------------------------------------------------------------------------------------------------------&lt;6&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span> cmp.createUnassociatedProvidedService(std<span style="color:#666">::</span>move(shell.html), CELIX_SHELL_COMMAND_SERVICE_NAME)
</span></span><span style="display:flex;"><span> .addProperty(CELIX_SHELL_COMMAND_NAME, <span style="color:#b44">&#34;hello_component&#34;</span>); <span style="color:#080;font-style:italic">// &lt; -------------------------------------&lt;7&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span> cmp.build(); <span style="color:#080;font-style:italic">// &lt;--------------------------------------------------------------------------------------------&lt;8&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> }
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">private</span><span style="color:#666">:</span>
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>CELIX_GEN_CXX_BUNDLE_ACTIVATOR(ComponentWithProvidedServiceActivator)
</span></span></code></pre></div><h1 id="components-service-dependencies">Component&rsquo;s Service Dependencies</h1>
<p>Components can be configured to have service dependencies. These service dependencies will influence the component&rsquo;s
lifecycle. Components can have optional and required service dependencies. When service dependencies are required the
component can only be active if all required dependencies are available; where available means at least 1 matching
service dependency is found.</p>
<p>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.</p>
<p>Service dependency callbacks can be configured with 3 different types of argument signatures:</p>
<ul>
<li>A single argument for the service pointer (raw pointer or shared_ptr);</li>
<li>A service pointer (raw pointer or shared_ptr) as first argument and the service properties as second argument.</li>
<li>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.</li>
</ul>
<p>Service dependency callbacks will always be called from the Celix event thread.</p>
<p>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:</p>
<ul>
<li>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.</li>
<li>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&rsquo; <code>stop</code> callback). This should mean
that there are no active users - through the provided services or active threads - of the service dependencies
anymore and that service changes can safely be handling without locking. The component implementation must ensure
that after a <code>stop</code> callback there are no active threads, thread pools, timers, etc - that use service dependencies -
are active anymore.</li>
</ul>
<h2 id="example-component-with-a-service-dependencies-in-c">Example: Component with a service dependencies in C</h2>
<p>The following example shows how a C component that has two service dependency on the <code>celix_shell_command_t</code> service.</p>
<p>One service dependency is a required dependency with a suspend-strategy and uses a <code>set </code> 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 <code>NULL</code> if there are no other matching services.</p>
<p>The other dependency is an optional dependency with a locking-strategy and uses a <code>addWithProps</code> and
<code>removeWithProps</code> callback. These callbacks will be called for every <code>celix_shell_command_t</code> service being added/removed
and will be called with not only the service pointer, but also the service properties.</p>
<p>Remarks for the C example:</p>
<ol>
<li>Creates a mutex to protect the <code>cmdShells</code> field which is configured with a locking-strategy service dependency.</li>
<li>Updates the <code>highestRankingCmdShell</code> field without locking. Note that because the service dependency is
configured with a suspend-strategy the <code>componentWithServiceDependency_setHighestRankingShellCommand</code> function
will only be called when the component is in the <code>Suspended</code> state or when it is not in the <code>Active</code> compound state.</li>
<li>Locks the mutex and adds the newly added service to the <code>cmdShells</code> list. Note that because the service dependency
is configured with a locking-strategy the <code>componentWithServiceDependency_addShellCommand</code> and
<code>componentWithServiceDependency_removeShellCommand</code> functions can be called from any component lifecycle state.</li>
<li>Creates a new DM service dependency object. Note that the DM service dependency is not yet known to the DM Component.</li>
<li>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.</li>
<li>Configures the update strategy for the service dependency to suspend-strategy.</li>
<li>Configures the service dependency as a required service dependency.</li>
<li>Creates an empty service dependency callback options struct. This struct can be used to configure different
service dependency callbacks.</li>
<li>Configures the <code>set</code> service dependency callback to <code>componentWithServiceDependency_setHighestRankingShellCommand</code></li>
<li>Configures the dependency manager to use the callbacks configures in opts.</li>
<li>Adds the DM service dependency object to the DM component object.</li>
<li>Configures the update strategy for the service dependency to locking-strategy.</li>
<li>Configures the service dependency as an optional service dependency.</li>
<li>Configures the <code>addWithProps</code> service dependency callback to <code>componentWithServiceDependency_addShellCommand</code>.</li>
</ol>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#080;font-style:italic">//src/component_with_service_dependency_activator.c
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#080">#include</span> <span style="color:#080">&lt;stdlib.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix_bundle_activator.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix_shell_command.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080"></span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">//********************* COMPONENT *******************************/
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">typedef</span> <span style="color:#a2f;font-weight:bold">struct</span> component_with_service_dependency {
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">celix_shell_command_t</span><span style="color:#666">*</span> highestRankingCmdShell; <span style="color:#080;font-style:italic">//only updated when component is not active or suspended
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_thread_mutex_t</span> mutex; <span style="color:#080;font-style:italic">//protects cmdShells
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_array_list_t</span><span style="color:#666">*</span> cmdShells;
</span></span><span style="display:flex;"><span>} <span style="color:#0b0;font-weight:bold">component_with_service_dependency_t</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">component_with_service_dependency_t</span><span style="color:#666">*</span> <span style="color:#00a000">componentWithServiceDependency_create</span>() {
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">component_with_service_dependency_t</span><span style="color:#666">*</span> cmp <span style="color:#666">=</span> <span style="color:#00a000">calloc</span>(<span style="color:#666">1</span>, <span style="color:#a2f;font-weight:bold">sizeof</span>(<span style="color:#666">*</span>cmp));
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_create</span>(<span style="color:#666">&amp;</span>cmp<span style="color:#666">-&gt;</span>mutex, <span style="color:#a2f">NULL</span>); <span style="color:#080;font-style:italic">// &lt;-----------------------------------------------------------------&lt;1&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> cmp<span style="color:#666">-&gt;</span>cmdShells <span style="color:#666">=</span> <span style="color:#00a000">celix_arrayList_create</span>();
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> cmp;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">componentWithServiceDependency_destroy</span>(<span style="color:#0b0;font-weight:bold">component_with_service_dependency_t</span><span style="color:#666">*</span> cmp) {
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_arrayList_destroy</span>(cmp<span style="color:#666">-&gt;</span>cmdShells);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_destroy</span>(<span style="color:#666">&amp;</span>cmp<span style="color:#666">-&gt;</span>mutex);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">free</span>(cmp);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">componentWithServiceDependency_setHighestRankingShellCommand</span>(
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">component_with_service_dependency_t</span><span style="color:#666">*</span> cmp,
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">celix_shell_command_t</span><span style="color:#666">*</span> shell.html) {
</span></span><span style="display:flex;"><span> <span style="color:#00a000">printf</span>(<span style="color:#b44">&#34;New highest ranking service (can be NULL): %p</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">&#34;</span>, shell.html);
</span></span><span style="display:flex;"><span> cmp<span style="color:#666">-&gt;</span>highestRankingCmdShell <span style="color:#666">=</span> shellCmd; <span style="color:#080;font-style:italic">// &lt;---------------------------------------------------------------------&lt;2&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">componentWithServiceDependency_addShellCommand</span>(
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">component_with_service_dependency_t</span><span style="color:#666">*</span> cmp,
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">celix_shell_command_t</span><span style="color:#666">*</span> shellCmd,
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">const</span> <span style="color:#0b0;font-weight:bold">celix_properties_t</span><span style="color:#666">*</span> props) {
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">long</span> id <span style="color:#666">=</span> <span style="color:#00a000">celix_properties_getAsLong</span>(props, CELIX_FRAMEWORK_SERVICE_ID, <span style="color:#666">-</span><span style="color:#666">1</span>);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">printf</span>(<span style="color:#b44">&#34;Adding shell command service with service.id %li</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">&#34;</span>, id);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_lock</span>(<span style="color:#666">&amp;</span>cmp<span style="color:#666">-&gt;</span>mutex); <span style="color:#080;font-style:italic">// &lt;-------------------------------------------------------------------------&lt;3&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">celix_arrayList_add</span>(cmp<span style="color:#666">-&gt;</span>cmdShells, shell.html);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_unlock</span>(<span style="color:#666">&amp;</span>cmp<span style="color:#666">-&gt;</span>mutex);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">componentWithServiceDependency_removeShellCommand</span>(
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">component_with_service_dependency_t</span><span style="color:#666">*</span> cmp,
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">celix_shell_command_t</span><span style="color:#666">*</span> shellCmd,
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">const</span> <span style="color:#0b0;font-weight:bold">celix_properties_t</span><span style="color:#666">*</span> props) {
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">long</span> id <span style="color:#666">=</span> <span style="color:#00a000">celix_properties_getAsLong</span>(props, CELIX_FRAMEWORK_SERVICE_ID, <span style="color:#666">-</span><span style="color:#666">1</span>);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">printf</span>(<span style="color:#b44">&#34;Removing shell command service with service.id %li</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">&#34;</span>, id);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_lock</span>(<span style="color:#666">&amp;</span>cmp<span style="color:#666">-&gt;</span>mutex);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_arrayList_remove</span>(cmp<span style="color:#666">-&gt;</span>cmdShells, shell.html);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_unlock</span>(<span style="color:#666">&amp;</span>cmp<span style="color:#666">-&gt;</span>mutex);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">//********************* ACTIVATOR *******************************/
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">typedef</span> <span style="color:#a2f;font-weight:bold">struct</span> component_with_service_dependency_activator {
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//nop
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>} <span style="color:#0b0;font-weight:bold">component_with_service_dependency_activator_t</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">static</span> <span style="color:#0b0;font-weight:bold">celix_status_t</span> <span style="color:#00a000">componentWithServiceDependencyActivator_start</span>(<span style="color:#0b0;font-weight:bold">component_with_service_dependency_activator_t</span> <span style="color:#666">*</span>act, <span style="color:#0b0;font-weight:bold">celix_bundle_context_t</span> <span style="color:#666">*</span>ctx) {
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//creating component
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">component_with_service_dependency_t</span><span style="color:#666">*</span> impl <span style="color:#666">=</span> <span style="color:#00a000">componentWithServiceDependency_create</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//create and configuring component and its lifecycle callbacks using the Apache Celix Dependency Manager
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_dm_component_t</span><span style="color:#666">*</span> dmCmp <span style="color:#666">=</span> <span style="color:#00a000">celix_dmComponent_create</span>(ctx, <span style="color:#b44">&#34;component_with_service_dependency_1&#34;</span>);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_dmComponent_setImplementation</span>(dmCmp, impl);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION</span>(
</span></span><span style="display:flex;"><span> dmCmp,
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">component_with_service_dependency_t</span>,
</span></span><span style="display:flex;"><span> componentWithServiceDependency_destroy);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//create mandatory service dependency with cardinality one and with a suspend-strategy
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_dm_service_dependency_t</span><span style="color:#666">*</span> dep1 <span style="color:#666">=</span> <span style="color:#00a000">celix_dmServiceDependency_create</span>(); <span style="color:#080;font-style:italic">// &lt;-----------------------------------&lt;4&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">celix_dmServiceDependency_setService</span>(dep1, CELIX_SHELL_COMMAND_SERVICE_NAME, <span style="color:#a2f">NULL</span>, <span style="color:#a2f">NULL</span>); <span style="color:#080;font-style:italic">// &lt;-------------------&lt;5&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">celix_dmServiceDependency_setStrategy</span>(dep1, DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND); <span style="color:#080;font-style:italic">// &lt;------------------------&lt;6&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">celix_dmServiceDependency_setRequired</span>(dep1, <span style="color:#a2f">true</span>); <span style="color:#080;font-style:italic">// &lt;----------------------------------------------------------&lt;7&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_dm_service_dependency_callback_options_t</span> opts1 <span style="color:#666">=</span> CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; <span style="color:#080;font-style:italic">// &lt;--&lt;8&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> opts1.set <span style="color:#666">=</span> (<span style="color:#0b0;font-weight:bold">void</span><span style="color:#666">*</span>)componentWithServiceDependency_setHighestRankingShellCommand; <span style="color:#080;font-style:italic">// &lt;----------------------------&lt;9&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">celix_dmServiceDependency_setCallbacksWithOptions</span>(dep1, <span style="color:#666">&amp;</span>opts1); <span style="color:#080;font-style:italic">// &lt;-------------------------------------------&lt;10&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">celix_dmComponent_addServiceDependency</span>(dmCmp, dep1); <span style="color:#080;font-style:italic">// &lt;-------------------------------------------------------&lt;11&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//create optional service dependency with cardinality many and with a locking-strategy
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_dm_service_dependency_t</span><span style="color:#666">*</span> dep2 <span style="color:#666">=</span> <span style="color:#00a000">celix_dmServiceDependency_create</span>();
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_dmServiceDependency_setService</span>(dep2, CELIX_SHELL_COMMAND_SERVICE_NAME, <span style="color:#a2f">NULL</span>, <span style="color:#a2f">NULL</span>);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_dmServiceDependency_setStrategy</span>(dep2, DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING); <span style="color:#080;font-style:italic">// &lt;----------------------&lt;12&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#00a000">celix_dmServiceDependency_setRequired</span>(dep2, <span style="color:#a2f">false</span>); <span style="color:#080;font-style:italic">// &lt;--------------------------------------------------------&lt;13&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_dm_service_dependency_callback_options_t</span> opts2 <span style="color:#666">=</span> CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS;
</span></span><span style="display:flex;"><span> opts2.addWithProps <span style="color:#666">=</span> (<span style="color:#0b0;font-weight:bold">void</span><span style="color:#666">*</span>)componentWithServiceDependency_addShellCommand; <span style="color:#080;font-style:italic">// &lt;-------------------------------&lt;14&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> opts2.removeWithProps <span style="color:#666">=</span> (<span style="color:#0b0;font-weight:bold">void</span><span style="color:#666">*</span>)componentWithServiceDependency_removeShellCommand;
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_dmServiceDependency_setCallbacksWithOptions</span>(dep2, <span style="color:#666">&amp;</span>opts2);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_dmComponent_addServiceDependency</span>(dmCmp, dep2);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">//Add dm component to the dm.
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> <span style="color:#0b0;font-weight:bold">celix_dependency_manager_t</span><span style="color:#666">*</span> dm <span style="color:#666">=</span> <span style="color:#00a000">celix_bundleContext_getDependencyManager</span>(ctx);
</span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_dependencyManager_add</span>(dm, dmCmp);
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">return</span> CELIX_SUCCESS;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#00a000">CELIX_GEN_BUNDLE_ACTIVATOR</span>(
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">component_with_service_dependency_activator_t</span>,
</span></span><span style="display:flex;"><span> componentWithServiceDependencyActivator_start,
</span></span><span style="display:flex;"><span> <span style="color:#a2f">NULL</span>)
</span></span></code></pre></div><h2 id="example-component-with-a-service-dependencies-in-c-1">Example: Component with a service dependencies in C++</h2>
<p>The following example shows how a C++ component that has two service dependency. One
service dependency for the C++ <code>celix::IShellCommand</code> service and one for the C <code>celix_shell_command_t</code> service.</p>
<p>The <code>celix::IShellCommand</code> service dependency is a required dependency with a suspend-strategy and uses a
<code>set</code> 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.</p>
<p>The <code>celix_shell_command_t</code> service dependency is an optional dependency with a locking-strategy and uses a
<code>addWithProperties</code> and <code>removeWithProperties</code> callback.
These callbacks will be called for every <code>celix_shell_command_t</code> service being added/removed
and will be called with not only the service shared_ptr, but also the service properties.</p>
<p>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++ <code>celix::Properties</code> and <code>celix::Bundle</code>.</p>
<p>Remarks for the C++ example:</p>
<ol>
<li>Creates a mutex to protect the <code>shellCommands</code> field which is configured with a locking-strategy service dependency.</li>
<li>Updates the <code>highestRankingShellCmd</code> field without locking. Note that because the service dependency is
configured with a suspend-strategy the <code>ComponentWithServiceDependency::setHighestRankingShellCommand</code> method
will only be called when the component is in the <code>Suspended</code> state or when it is not in the <code>Active</code> compound state.</li>
<li>Locks the mutex and adds the newly added service to the <code>shellCommands</code> list. Note that because the service
dependency is configured with a locking-strategy the <code>ComponentWithServiceDependency::addCShellCmd</code> and
<code>ComponentWithServiceDependency::removeCShellCmd</code> methods can be called from any component lifecycle state.</li>
<li>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 <code>celix::dm::Component::createServiceDependency</code> method
is called without provided a service name, the service name will be inferred using the <code>celix::typeName</code>.</li>
<li>Configures the service dependency set callback.</li>
<li>Configures the service dependency as a required service dependency.</li>
<li>Configures the update strategy for the service dependency to suspend-strategy.</li>
<li>Creates another new DM service dependency object and in this case also explicitly provides the service name
to use (<code>CELIX_SHELL_COMMAND_SERVICE_NAME</code>).</li>
<li>Builds the component and as result also builds the components&rsquo; service dependencies (i.e. marking them as complete).</li>
</ol>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-C++" data-lang="C++"><span style="display:flex;"><span><span style="color:#080;font-style:italic">//src/ComponentWithServiceDependencyActivator.cc
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix/BundleActivator.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix/IShellCommand.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080">&lt;celix_shell_command.h&gt;</span><span style="color:#080">
</span></span></span><span style="display:flex;"><span><span style="color:#080"></span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">class</span> <span style="color:#00f">ComponentWithServiceDependency</span> {
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">public</span><span style="color:#666">:</span>
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">void</span> setHighestRankingShellCommand(<span style="color:#a2f;font-weight:bold">const</span> std<span style="color:#666">::</span>shared_ptr<span style="color:#666">&lt;</span>celix<span style="color:#666">::</span>IShellCommand<span style="color:#666">&gt;&amp;</span> cmdSvc) {
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>cout <span style="color:#666">&lt;&lt;</span> <span style="color:#b44">&#34;New highest ranking service (can be NULL): &#34;</span> <span style="color:#666">&lt;&lt;</span> (intptr_t)cmdSvc.get() <span style="color:#666">&lt;&lt;</span> std<span style="color:#666">::</span>endl;
</span></span><span style="display:flex;"><span> highestRankingShellCmd <span style="color:#666">=</span> cmdSvc; <span style="color:#080;font-style:italic">// &lt;------------------------------------------------------------------------&lt;2&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">addCShellCmd</span>(
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">const</span> std<span style="color:#666">::</span>shared_ptr<span style="color:#666">&lt;</span>celix_shell_command_t<span style="color:#666">&gt;&amp;</span> cmdSvc,
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">const</span> std<span style="color:#666">::</span>shared_ptr<span style="color:#666">&lt;</span><span style="color:#a2f;font-weight:bold">const</span> celix<span style="color:#666">::</span>Properties<span style="color:#666">&gt;&amp;</span> props) {
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">auto</span> id <span style="color:#666">=</span> props<span style="color:#666">-&gt;</span>getAsLong(celix<span style="color:#666">::</span>SERVICE_ID, <span style="color:#666">-</span><span style="color:#666">1</span>);
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>cout <span style="color:#666">&lt;&lt;</span> <span style="color:#b44">&#34;Adding shell command service with service.id: &#34;</span> <span style="color:#666">&lt;&lt;</span> id <span style="color:#666">&lt;&lt;</span> std<span style="color:#666">::</span>endl;
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>lock_guard lck{mutex}; <span style="color:#080;font-style:italic">// &lt;-----------------------------------------------------------------------------&lt;3&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> shellCommands.emplace(id, cmdSvc);
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">removeCShellCmd</span>(
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">const</span> std<span style="color:#666">::</span>shared_ptr<span style="color:#666">&lt;</span>celix_shell_command_t<span style="color:#666">&gt;&amp;</span> <span style="color:#080;font-style:italic">/*cmdSvc*/</span>,
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">const</span> std<span style="color:#666">::</span>shared_ptr<span style="color:#666">&lt;</span><span style="color:#a2f;font-weight:bold">const</span> celix<span style="color:#666">::</span>Properties<span style="color:#666">&gt;&amp;</span> props) {
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">auto</span> id <span style="color:#666">=</span> props<span style="color:#666">-&gt;</span>getAsLong(celix<span style="color:#666">::</span>SERVICE_ID, <span style="color:#666">-</span><span style="color:#666">1</span>);
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>cout <span style="color:#666">&lt;&lt;</span> <span style="color:#b44">&#34;Removing shell command service with service.id: &#34;</span> <span style="color:#666">&lt;&lt;</span> id <span style="color:#666">&lt;&lt;</span> std<span style="color:#666">::</span>endl;
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>lock_guard lck{mutex};
</span></span><span style="display:flex;"><span> shellCommands.erase(id);
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">private</span><span style="color:#666">:</span>
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>shared_ptr<span style="color:#666">&lt;</span>celix<span style="color:#666">::</span>IShellCommand<span style="color:#666">&gt;</span> highestRankingShellCmd{};
</span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>mutex mutex{}; <span style="color:#080;font-style:italic">//protect shellCommands // &lt;-----------------------------------------------------------------&lt;1&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> std<span style="color:#666">::</span>unordered_map<span style="color:#666">&lt;</span><span style="color:#0b0;font-weight:bold">long</span>, std<span style="color:#666">::</span>shared_ptr<span style="color:#666">&lt;</span>celix_shell_command_t<span style="color:#666">&gt;&gt;</span> shellCommands{};
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">class</span> <span style="color:#00f">ComponentWithServiceDependencyActivator</span> {
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">public</span><span style="color:#666">:</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">explicit</span> ComponentWithServiceDependencyActivator(<span style="color:#a2f;font-weight:bold">const</span> std<span style="color:#666">::</span>shared_ptr<span style="color:#666">&lt;</span>celix<span style="color:#666">::</span>BundleContext<span style="color:#666">&gt;&amp;</span> ctx) {
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">using</span> Cmp <span style="color:#666">=</span> ComponentWithServiceDependency;
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">auto</span><span style="color:#666">&amp;</span> cmp <span style="color:#666">=</span> ctx<span style="color:#666">-&gt;</span>getDependencyManager()<span style="color:#666">-&gt;</span>createComponent<span style="color:#666">&lt;</span>Cmp<span style="color:#666">&gt;</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> cmp.createServiceDependency<span style="color:#666">&lt;</span>celix<span style="color:#666">::</span>IShellCommand<span style="color:#666">&gt;</span>() <span style="color:#080;font-style:italic">// &lt;-----------------------------------------------------&lt;4&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> .setCallbacks(<span style="color:#666">&amp;</span>Cmp<span style="color:#666">::</span>setHighestRankingShellCommand) <span style="color:#080;font-style:italic">// &lt;----------------------------------------------&lt;5&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> .setRequired(<span style="color:#a2f">true</span>) <span style="color:#080;font-style:italic">// &lt;------------------------------------------------------------------------------&lt;6&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> .setStrategy(DependencyUpdateStrategy<span style="color:#666">::</span>suspend); <span style="color:#080;font-style:italic">// &lt;------------------------------------------------&lt;7&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span>
</span></span><span style="display:flex;"><span> cmp.createServiceDependency<span style="color:#666">&lt;</span>celix_shell_command_t<span style="color:#666">&gt;</span>(CELIX_SHELL_COMMAND_SERVICE_NAME) <span style="color:#080;font-style:italic">// &lt;--------------------&lt;8&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> .setCallbacks(<span style="color:#666">&amp;</span>Cmp<span style="color:#666">::</span>addCShellCmd, <span style="color:#666">&amp;</span>Cmp<span style="color:#666">::</span>removeCShell.html)
</span></span><span style="display:flex;"><span> .setRequired(<span style="color:#a2f">false</span>)
</span></span><span style="display:flex;"><span> .setStrategy(DependencyUpdateStrategy<span style="color:#666">::</span>locking);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> cmp.build(); <span style="color:#080;font-style:italic">// &lt;--------------------------------------------------------------------------------------------&lt;9&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> }
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>CELIX_GEN_CXX_BUNDLE_ACTIVATOR(ComponentWithServiceDependencyActivator)
</span></span></code></pre></div><h1 id="when-will-a-component-be-suspended">When will a component be suspended</h1>
<p>Components will only suspend if:</p>
<ul>
<li>The component is in the state <code>Tracking Optional</code>;</li>
<li>The component has at least 1 service dependency where the update strategy is configured as suspend-strategy;</li>
<li>There is a service update event ongoing, where the update service event matches 1 of the components'
suspend-strategy service dependencies;</li>
<li>And least one of the component&rsquo;s matching suspend-strategy service dependency has a configured service injection/
removal callback configured.</li>
</ul>
<h1 id="the-celixdm-shell-command">The <code>celix::dm</code> shell command</h1>
<p>To interactively see the available components, their current lifecycle state, provided service and service dependencies
the <code>celix::dm</code> shell command can be used.</p>
<p>Examples of supported <code>dm</code> command lines are:</p>
<ul>
<li><code>celix::dm</code> - Show an overview of all components in the Celix framework. Only shows component lifecycle state.</li>
<li><code>dm</code> - Same as <code>celix::dm</code> (as long as there is no colliding other <code>dm</code> commands).</li>
<li><code>dm full</code> - Show a detailed overview of all components in the Celix framework. This also shows the provided
services and service dependencies of each component.</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<footer class="py-3 bg-secondary">
<div class="container">
<div class="row">
<div class="col-md-8 text-center">
<p class="m-0 text-white">
Copyright &copy; 2024 The Apache Software Foundation, Licensed under
the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
<br>
Apache Celix, Celix, Apache, the Apache feather logo and the Apache Celix logo are trademarks of The Apache Software Foundation.
</p>
</div>
<div class="col-md-4 text-center">
<a href="https://www.apache.org/events/current-event.html" target="_blank">
<img src="https://www.apache.org/events/current-event-234x60.png" title="Apache Event" width="234" height="60" border="0">
</a>
</div>
</div>
</div>
</footer>
<script src="/assets/js/jquery.min.js"></script>
<script src="/assets/js/bootstrap.bundle.min.js"></script>
</body>
</html>