| |
| <!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.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 href="/docs/2.3.0/docs.html" title="back to documentation"><< 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’s lifecycle as a component will only be active when all required |
| dependencies are available.<br> |
| The DM is responsible for managing the component’s service dependencies, the component’s lifecycle and when |
| to register/unregister the component’s provided services.</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’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’s lifecycle callbacks, the following component’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’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’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’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’ 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"><stdio.h></span><span style="color:#080"> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080"><celix_api.h></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">-></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">// <------------------------------------------------------<1> |
| </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">"Initializing simple component. Transition nr %i</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">"</span>, cmp<span style="color:#666">-></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">"Starting simple component. Transition nr %i</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">"</span>, cmp<span style="color:#666">-></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">"Stopping simple component. Transition nr %i</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">"</span>, cmp<span style="color:#666">-></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">"De-initializing simple component. Transition nr %i</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">"</span>, cmp<span style="color:#666">-></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">// <--------------------------------------------------------<2> |
| </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">"simple_component_1"</span>); <span style="color:#080;font-style:italic">// <--------------------------<3> |
| </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">// <-----------------------------------------------------------<4> |
| </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">// <----------------------------------------------------------------------------<5> |
| </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">// <---------------------------------------------------------------------------<6> |
| </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">// <---------------------------------------------------------------------<7> |
| </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">// <------------------<8> |
| </span></span></span></code></pre></div><h2 id="example-create-and-configure-components-lifecycle-callbacks-in-c-1">Example: Create and configure component’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 “build” 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->getDependencyManager()->createComponent<CmpWithDefaultCTOR>()</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>“Builds” the component. C++ components will only be managed by the DM after they are build. This makes it possible |
| to configure a component over multiple method calls before marking the component complete (build). |
| The generated C++ bundle activator will also enable all components created during the bundle activation, this is |
| done to ensure that the build behaviour is backwards compatible with previous released DM implementation. |
| It is preferred that users explicitly build their components when they are completely configured.</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"><celix/BundleActivator.h></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">// <-----------------------------------------------------------------------------------------------<1> |
| </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"><<</span> <span style="color:#b44">"Initializing simple component. Transition nr "</span> <span style="color:#666"><<</span> transitionCount<span style="color:#666">++</span> <span style="color:#666"><<</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"><<</span> <span style="color:#b44">"starting simple component. Transition nr "</span> <span style="color:#666"><<</span> transitionCount<span style="color:#666">++</span> <span style="color:#666"><<</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"><<</span> <span style="color:#b44">"Stopping simple component. Transition nr "</span> <span style="color:#666"><<</span> transitionCount<span style="color:#666">++</span> <span style="color:#666"><<</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"><<</span> <span style="color:#b44">"De-initializing simple component. Transition nr "</span> <span style="color:#666"><<</span> transitionCount<span style="color:#666">++</span> <span style="color:#666"><<</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"><</span>celix<span style="color:#666">::</span>BundleContext<span style="color:#666">>&</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"><</span>SimpleComponent<span style="color:#666">></span>(); <span style="color:#080;font-style:italic">// <---------------------------------------------------------<2> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> ctx<span style="color:#666">-></span>getDependencyManager()<span style="color:#666">-></span>createComponent(std<span style="color:#666">::</span>move(cmp), <span style="color:#b44">"SimpleComponent1"</span>) <span style="color:#080;font-style:italic">// <------------------------<3> |
| </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">&</span>SimpleComponent<span style="color:#666">::</span>init, |
| </span></span><span style="display:flex;"><span> <span style="color:#666">&</span>SimpleComponent<span style="color:#666">::</span>start, |
| </span></span><span style="display:flex;"><span> <span style="color:#666">&</span>SimpleComponent<span style="color:#666">::</span>stop, |
| </span></span><span style="display:flex;"><span> <span style="color:#666">&</span>SimpleComponent<span style="color:#666">::</span>deinit) <span style="color:#080;font-style:italic">// <---------------------------------------------------------------<4> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> .build(); <span style="color:#080;font-style:italic">// <---------------------------------------------------------------------------------------<5> |
| </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’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 “component.uuid” - next to its configured provided service properties. The “component.uuid” service property can be |
| used to identify if a service is provided by a component and which component.</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 “outlives” 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"><stdlib.h></span><span style="color:#080"> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080"><celix_api.h></span><span style="color:#080"> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080"><celix_shell_command.h></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 <span style="color:#00a000">__attribute__</span>((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">&</span>cmp<span style="color:#666">-></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">"Hello from cmp. command called %i times. commandLine: %s</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">"</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">// <-----------------------------------------------------------------------------<1> |
| </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">"component_with_provided_service_1"</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">-></span>shellCmd.handle <span style="color:#666">=</span> impl; |
| </span></span><span style="display:flex;"><span> act<span style="color:#666">-></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">"hello_component"</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">&</span>act<span style="color:#666">-></span>shellCmd, |
| </span></span><span style="display:flex;"><span> props); <span style="color:#080;font-style:italic">// <---------------------------------------------------------------------------------------------<2> |
| </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’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>“Build” 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"><celix/BundleActivator.h></span><span style="color:#080"> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080"><celix/IShellCommand.h></span><span style="color:#080"> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080"><celix_shell_command.h></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">// <----------------------------------------------<1> |
| </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">&</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"><</span>std<span style="color:#666">::</span>string<span style="color:#666">>&</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">"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">"</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">// <-----------------------------------------------------------------------------------------------------------<2> |
| </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">"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">"</span>, cCallCount<span style="color:#666">++</span>, commandLine); |
| </span></span><span style="display:flex;"><span> } <span style="color:#080;font-style:italic">// <-----------------------------------------------------------------------------------------------------------<3> |
| </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"><</span><span style="color:#0b0;font-weight:bold">int</span><span style="color:#666">></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"><</span><span style="color:#0b0;font-weight:bold">int</span><span style="color:#666">></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"><</span>celix<span style="color:#666">::</span>BundleContext<span style="color:#666">>&</span> ctx) { |
| </span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">auto</span><span style="color:#666">&</span> cmp <span style="color:#666">=</span> ctx<span style="color:#666">-></span>getDependencyManager()<span style="color:#666">-></span>createComponent<span style="color:#666"><</span>ComponentWithProvidedService<span style="color:#666">></span>(); <span style="color:#080;font-style:italic">// <---------------<4> |
| </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"><</span>celix<span style="color:#666">::</span>IShellCommand<span style="color:#666">></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">"HelloComponent"</span>); <span style="color:#080;font-style:italic">// <-----------------------------<5> |
| </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"><</span>celix_shell_command_t<span style="color:#666">></span>(); |
| </span></span><span style="display:flex;"><span> shellCmd<span style="color:#666">-></span>handle <span style="color:#666">=</span> <span style="color:#a2f;font-weight:bold">static_cast</span><span style="color:#666"><</span><span style="color:#0b0;font-weight:bold">void</span><span style="color:#666">*></span>(<span style="color:#666">&</span>cmp.getInstance()); |
| </span></span><span style="display:flex;"><span> shellCmd<span style="color:#666">-></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">-></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"><</span>ComponentWithProvidedService<span style="color:#666">*></span>(handle); |
| </span></span><span style="display:flex;"><span> impl<span style="color:#666">-></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">// <------------------------------------------------------------------------------------------------------<6> |
| </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">"hello_component"</span>); <span style="color:#080;font-style:italic">// < -------------------------------------<7> |
| </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">// <--------------------------------------------------------------------------------------------<8> |
| </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’s Service Dependencies</h1> |
| <p>Components can be configured to have service dependencies. These service dependencies will influence the component’s |
| lifecycle. Components can have optional and required service dependencies. When service dependencies are required the |
| component can only be active if all required dependencies are available; where available means at least 1 matching |
| service dependency is found.</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’ <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"><stdlib.h></span><span style="color:#080"> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080"><celix_api.h></span><span style="color:#080"> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080"><celix_shell_command.h></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">&</span>cmp<span style="color:#666">-></span>mutex, <span style="color:#a2f">NULL</span>); <span style="color:#080;font-style:italic">// <-----------------------------------------------------------------<1> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> cmp<span style="color:#666">-></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">-></span>cmdShells); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_destroy</span>(<span style="color:#666">&</span>cmp<span style="color:#666">-></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">"New highest ranking service (can be NULL): %p</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">"</span>, shell.html); |
| </span></span><span style="display:flex;"><span> cmp<span style="color:#666">-></span>highestRankingCmdShell <span style="color:#666">=</span> shellCmd; <span style="color:#080;font-style:italic">// <---------------------------------------------------------------------<2> |
| </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">"Adding shell command service with service.id %li</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">"</span>, id); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_lock</span>(<span style="color:#666">&</span>cmp<span style="color:#666">-></span>mutex); <span style="color:#080;font-style:italic">// <-------------------------------------------------------------------------<3> |
| </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">-></span>cmdShells, shell.html); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_unlock</span>(<span style="color:#666">&</span>cmp<span style="color:#666">-></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">"Removing shell command service with service.id %li</span><span style="color:#b62;font-weight:bold">\n</span><span style="color:#b44">"</span>, id); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_lock</span>(<span style="color:#666">&</span>cmp<span style="color:#666">-></span>mutex); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celix_arrayList_remove</span>(cmp<span style="color:#666">-></span>cmdShells, shell.html); |
| </span></span><span style="display:flex;"><span> <span style="color:#00a000">celixThreadMutex_unlock</span>(<span style="color:#666">&</span>cmp<span style="color:#666">-></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">"component_with_service_dependency_1"</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">// <-----------------------------------<4> |
| </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">// <-------------------<5> |
| </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">// <------------------------<6> |
| </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">// <----------------------------------------------------------<7> |
| </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">// <--<8> |
| </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">// <----------------------------<9> |
| </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">&</span>opts1); <span style="color:#080;font-style:italic">// <-------------------------------------------<10> |
| </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">// <-------------------------------------------------------<11> |
| </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">// <----------------------<12> |
| </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">// <--------------------------------------------------------<13> |
| </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">// <-------------------------------<14> |
| </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">&</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’ 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"><celix/BundleActivator.h></span><span style="color:#080"> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080"><celix/IShellCommand.h></span><span style="color:#080"> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080">#include</span> <span style="color:#080"><celix_shell_command.h></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"><</span>celix<span style="color:#666">::</span>IShellCommand<span style="color:#666">>&</span> cmdSvc) { |
| </span></span><span style="display:flex;"><span> std<span style="color:#666">::</span>cout <span style="color:#666"><<</span> <span style="color:#b44">"New highest ranking service (can be NULL): "</span> <span style="color:#666"><<</span> (intptr_t)cmdSvc.get() <span style="color:#666"><<</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">// <------------------------------------------------------------------------<2> |
| </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"><</span>celix_shell_command_t<span style="color:#666">>&</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"><</span><span style="color:#a2f;font-weight:bold">const</span> celix<span style="color:#666">::</span>Properties<span style="color:#666">>&</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">-></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"><<</span> <span style="color:#b44">"Adding shell command service with service.id: "</span> <span style="color:#666"><<</span> id <span style="color:#666"><<</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">// <-----------------------------------------------------------------------------<3> |
| </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"><</span>celix_shell_command_t<span style="color:#666">>&</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"><</span><span style="color:#a2f;font-weight:bold">const</span> celix<span style="color:#666">::</span>Properties<span style="color:#666">>&</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">-></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"><<</span> <span style="color:#b44">"Removing shell command service with service.id: "</span> <span style="color:#666"><<</span> id <span style="color:#666"><<</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"><</span>celix<span style="color:#666">::</span>IShellCommand<span style="color:#666">></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 // <-----------------------------------------------------------------<1> |
| </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"><</span><span style="color:#0b0;font-weight:bold">long</span>, std<span style="color:#666">::</span>shared_ptr<span style="color:#666"><</span>celix_shell_command_t<span style="color:#666">>></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"><</span>celix<span style="color:#666">::</span>BundleContext<span style="color:#666">>&</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">&</span> cmp <span style="color:#666">=</span> ctx<span style="color:#666">-></span>getDependencyManager()<span style="color:#666">-></span>createComponent<span style="color:#666"><</span>Cmp<span style="color:#666">></span>(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> cmp.createServiceDependency<span style="color:#666"><</span>celix<span style="color:#666">::</span>IShellCommand<span style="color:#666">></span>() <span style="color:#080;font-style:italic">// <-----------------------------------------------------<4> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> .setCallbacks(<span style="color:#666">&</span>Cmp<span style="color:#666">::</span>setHighestRankingShellCommand) <span style="color:#080;font-style:italic">// <----------------------------------------------<5> |
| </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">// <------------------------------------------------------------------------------<6> |
| </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">// <------------------------------------------------<7> |
| </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"><</span>celix_shell_command_t<span style="color:#666">></span>(CELIX_SHELL_COMMAND_SERVICE_NAME) <span style="color:#080;font-style:italic">// <--------------------<8> |
| </span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span> .setCallbacks(<span style="color:#666">&</span>Cmp<span style="color:#666">::</span>addCShellCmd, <span style="color:#666">&</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">// <--------------------------------------------------------------------------------------------<9> |
| </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’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 © 2023 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> |