| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width,initial-scale=1"> |
| <title>Dependency Manager Annotations :: Apache Felix</title> |
| <link rel="canonical" href="https://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/reference/dm-annotations.html"> |
| <meta name="generator" content="Antora 2.3.4"> |
| <link rel="stylesheet" href="../../../../_/css/site.css"> |
| <link rel="icon" href="../../../../_/img/favicon.png" type="image/x-icon"> |
| </head> |
| <body class="article"> |
| <header class="header"> |
| <nav class="navbar"> |
| <div class="navbar-brand"> |
| <a class="navbar-item" href="https://felix.apache.org/index.html"> |
| <span> |
| <img src="../../../../_/img/logo.png"> |
| </span> |
| </a> |
| <button class="navbar-burger" data-target="topbar-nav"> |
| <span></span> |
| <span></span> |
| <span></span> |
| </button> |
| </div> |
| <div id="topbar-nav" class="navbar-menu"> |
| <div class="navbar-end"> |
| <a class="navbar-item" href="https://felix.apache.org/index.html">Home</a> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Subprojects</a> |
| <div class="navbar-dropdown"> |
| <a class="navbar-item" href="../../apache-felix-dependency-manager.html">Dependency Manager</a> |
| <a class="navbar-item" href="../../apache-felix-event-admin.html">Event Admin</a> |
| <a class="navbar-item" href="../../apache-felix-file-install.html">File Install</a> |
| <a class="navbar-item" href="../../apache-felix-framework.html">Framework</a> |
| <a class="navbar-item" href="../../apache-felix-gogo.html">Gogo Shell</a> |
| <a class="navbar-item" href="../../apache-felix-healthchecks.html">Health Checks</a> |
| <a class="navbar-item" href="../../apache-felix-inventory.html">Inventory</a> |
| <a class="navbar-item" href="../../apache-felix-log.html">Log</a> |
| <a class="navbar-item" href="../../apache-felix-logback.html">Logback</a> |
| <a class="navbar-item" href="../../apache-felix-maven-bundle-plugin.html">Maven bundle plugin</a> |
| <a class="navbar-item" href="../../apache-felix-maven-scr-plugin.html">Maven SCR plugin</a> |
| <a class="navbar-item" href="../../apache-felix-metatype-service.html">Metatype Service</a> |
| <a class="navbar-item" href="../../apache-felix-preferences-service.html">Preferences Service</a> |
| <a class="navbar-item" href="../../apache-felix-remote-shell.html">Remote Shell</a> |
| <a class="navbar-item" href="../../apache-felix-script-console-plugin.html">Script console plugin</a> |
| <a class="navbar-item" href="../../apache-felix-shell.html">Lightweight shell</a> |
| <a class="navbar-item" href="../../apache-felix-shell-tui.html">Shell TUI</a> |
| <a class="navbar-item" href="../../apache-felix-web-console.html">Web Console</a> |
| </div> |
| </div> |
| <div class="navbar-item"> |
| <span class="control"> |
| <a class="button is-primary" href="../../../downloads.html">Downloads</a> |
| </span> |
| </div> |
| </div> |
| </div> |
| </nav> |
| </header> |
| <div class="body"> |
| <div class="nav-container" data-component="documentation" data-version="master"> |
| <aside class="nav"> |
| <div class="panels"> |
| <div class="nav-panel-menu is-active" data-panel="menu"> |
| <nav class="nav-menu"> |
| <h3 class="title"><a href="../../../index.html">Documentation</a></h3> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="../../../documentation.html">Documentation</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="../../../downloads.html">Downloads</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="../../../getting-started.html">Getting Started</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="../../../news.html">News</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Community</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../community/project-info.html">Apache Felix Project Info</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../community/contributing.html">Contributing</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../community/projects-using-felix.html">Projects Using Felix</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Development</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../development/coding-standards.html">Coding Standards</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../development/dependencies-file-template.html">DEPENDENCIES file template</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../development/provisional-osgi-api-policy.html">Provisional OSGi API Policy</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../development/release-management-nexus.html">Release Management</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../development/site-how-to.html">Site How To</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../development/using-the-osgi-compliance-tests.html">Using the OSGi Compliance Tests</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../../faqs.html">FAQS</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../faqs/apache-felix-bundle-plugin-faq.html">Apache Felix Bundle Plugin Frequently Asked Questions</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../faqs/apache-felix-scr-plugin-faq.html">Apache Felix SCR Plugin Frequently Asked Questions</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../../subprojects.html">Subprojects</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../apache-felix-dependency-manager.html">Apache Felix Dependency Manager</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Guides</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/migrating-from-earlier-versions.html">Apache Felix Dependency Manager - Migrating from earlier versions</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/annotations.html">Dependency Manager - Annotations</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/background.html">Dependency Manager - Background</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/bundles-and-dependencies.html">Dependency Manager - Bundles and Dependencies</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/design-patterns.html">Dependency Manager - Design Patterns</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/development.html">Dependency Manager - Development</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/history.html">Dependency Manager - History</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/javadocs.html">Dependency Manager - JavaDocs</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/migrating-from-other-solutions.html">Dependency Manager - Migrating from other solutions.</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/performance-tuning.html">Dependency Manager - Performance Tuning</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/resources.html">Dependency Manager - Resource adapters</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/whatsnew.html">Dependency Manager - What’s new in version 4?</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/dm-lambda.html">Dependency Manager Lambda</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../guides/whatsnew-r15.html">What’s New in R15</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Reference</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="component-adapter.html">Dependency Manager - Adapter</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="component-aspect.html">Dependency Manager - Aspect</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="component-bundle-adapter.html">Dependency Manager - Bundle Adapter</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="dependency-bundle.html">Dependency Manager - Bundle Dependency</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="components.html">Dependency Manager - Components</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="dependency-configuration.html">Dependency Manager - Configuration Dependency</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="dependencies.html">Dependency Manager - Dependencies</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="external-links.html">Dependency Manager - External Links</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="component-factory-configuration-adapter.html">Dependency Manager - Factory Configuration Adapter Service</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="component-resource-adapter.html">Dependency Manager - Resource Adapter</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="dependency-resource.html">Dependency Manager - Resource Dependency</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="dependency-service.html">Dependency Manager - Service Dependency</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="service-scopes.html">Dependency Manager - Service Scopes</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="component-singleton.html">Dependency Manager - Singleton Component</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="thread-model.html">Dependency Manager - Thread Model</a> |
| </li> |
| <li class="nav-item is-current-page" data-depth="4"> |
| <a class="nav-link" href="dm-annotations.html">Dependency Manager Annotations</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Tutorials</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../tutorials/working-with-annotations.html">Dependency Manager - Annotations</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../tutorials/getting-started.html">Dependency Manager - Getting Started</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../tutorials/leveraging-the-shell.html">Dependency Manager - Leveraging the shell</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../tutorials/sample-code.html">Dependency Manager sample projects</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-event-admin.html">Apache Felix Event Admin</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-file-install.html">Apache Felix File Install</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../apache-felix-framework.html">Apache Felix Framework</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../apache-felix-framework/apache-felix-framework-bundle-cache.html">Apache Felix Framework Bundle Cache</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../apache-felix-framework/apache-felix-framework-configuration-properties.html">Apache Felix Framework Configuration Properties</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../apache-felix-framework/apache-felix-framework-faq.html">Apache Felix Framework Frequently Asked Questions</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../apache-felix-framework/apache-felix-framework-launching-and-embedding.html">Apache Felix Framework Launching and Embedding</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../apache-felix-framework/apache-felix-framework-usage-documentation.html">Apache Felix Framework Usage Documentation</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-framework-security.html">Apache Felix Framework Security</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../apache-felix-gogo.html">Apache Felix Gogo</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../apache-felix-gogo/rfc-147-overview.html">RFC 147 Overview</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-healthchecks.html">Apache Felix Health Checks</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-inventory.html">Apache Felix Inventory Printer</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-log.html">Apache Felix Log</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-logback.html">Apache Felix Logback</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-maven-bundle-plugin-bnd.html">Apache Felix Maven Bundle Plugin (BND)</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-metatype-service.html">Apache Felix Metatype Service</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-osgi-bundle-repository.html">Apache Felix OSGi Bundle Repository (OBR)</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-preferences-service.html">Apache Felix Preferences Service</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-remote-shell.html">Apache Felix Remote Shell</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-shell.html">Apache Felix Shell</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../apache-felix-shell-tui.html">Apache Felix Shell TUI</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../apache-felix-web-console.html">Apache Felix Web Console</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../apache-felix-web-console/extending-the-apache-felix-web-console.html">Extending the Apache Felix Web Console</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../apache-felix-web-console/web-console-restful-api.html">Web Console RESTful API</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../apache-felix-web-console/web-console-security-provider.html">Web Console Security Provider</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Extensions</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../../apache-felix-web-console/extending-the-apache-felix-web-console/branding-the-web-console.html">Branding the Web Console</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../../apache-felix-web-console/extending-the-apache-felix-web-console/providing-resources.html">Providing Resources</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../../apache-felix-web-console/extending-the-apache-felix-web-console/providing-web-console-plugins.html">Providing Web Console Plugins</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../../apache-felix-web-console/extending-the-apache-felix-web-console/web-console-logging.html">Web Console Logging</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../../apache-felix-web-console/extending-the-apache-felix-web-console/web-console-output-templating.html">Web Console Output Templating</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations.html">Tutorials</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-application-demonstration.html">Apache Felix Application Demonstration</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial.html">Apache Felix OSGi Tutorial</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-faq.html">OSGi Frequently Asked Questions</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">OSGI Tutorial</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial/apache-felix-tutorial-example-1.html">Apache Felix Tutorial Example 1 - Service Event Listener Bundle</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial/apache-felix-tutorial-example-2.html">Apache Felix Tutorial Example 2</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial/apache-felix-tutorial-example-2b.html">Apache Felix Tutorial Example 2b</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial/apache-felix-tutorial-example-3.html">Apache Felix Tutorial Example 3</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial/apache-felix-tutorial-example-4.html">Apache Felix Tutorial Example 4</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial/apache-felix-tutorial-example-5.html">Apache Felix Tutorial Example 5</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial/apache-felix-tutorial-example-6.html">Example 6 - Spell Checker Service Bundle</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial/apache-felix-tutorial-example-7.html">Example 7 - Spell Checker Client Bundle</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial/apache-felix-tutorial-example-8.html">Example 8 - Spell Checker Service using Service Binder</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../tutorials-examples-and-presentations/apache-felix-osgi-tutorial/apache-felix-tutorial-example-9.html">Example 9 - Spell Checker Service using Declarative Services</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="../../../license.html">Apache License 2.0</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="../../../site-map.html">Site map</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </nav> |
| </div> |
| <div class="nav-panel-explore" data-panel="explore"> |
| <div class="context"> |
| <span class="title">Documentation</span> |
| <span class="version">master</span> |
| </div> |
| <ul class="components"> |
| <li class="component is-current"> |
| <span class="title">Documentation</span> |
| <ul class="versions"> |
| <li class="version is-current is-latest"> |
| <a href="../../../index.html">master</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </aside> |
| </div> |
| <main class="article"> |
| <div class="toolbar" role="navigation"> |
| <button class="nav-toggle"></button> |
| <a href="../../../index.html" class="home-link"></a> |
| <nav class="breadcrumbs" aria-label="breadcrumbs"> |
| <ul> |
| <li><a href="../../../index.html">Documentation</a></li> |
| <li><a href="../../../subprojects.html">Subprojects</a></li> |
| <li><a href="../../apache-felix-dependency-manager.html">Apache Felix Dependency Manager</a></li> |
| <li>Reference</li> |
| <li><a href="dm-annotations.html">Dependency Manager Annotations</a></li> |
| </ul> |
| </nav> |
| <div class="edit-this-page"><a href="https://github.com/apache/felix-antora-site/edit/main/modules/ROOT/pages/subprojects/apache-felix-dependency-manager/reference/dm-annotations.adoc">Edit this Page</a></div> |
| </div> |
| <div class="content"> |
| <article class="doc"> |
| <h1 class="page">Dependency Manager Annotations</h1> |
| <div id="preamble"> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>This section presents an overview and a reference guide of the capabilities and usage of the DependencyManager annotations.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_overview"><a class="anchor" href="#_overview"></a>Overview</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Instead of writing Activators which extends the DependencyActivatorBase class, service components can also be annotated using the annotations provided by the <em>org.apache.felix.dependencymanager.annotation</em> bundle. |
| Annotations are not reflectively parsed at runtime; |
| but we use a BND plugin which scans annotations at compilation phase and generates a compact json metadata file in the bundle’s META-INF/dependencymanager subdirectory. |
| This has the following benefits: JVM startup speed is not affected, and class files are not parsed when the framework is starting. |
| Moreover, since the annotations are not retained by the VM at runtime, it is not necessary to load the annotation API bundle at runtime.</p> |
| </div> |
| <div class="paragraph"> |
| <p>At runtime, the metadata generated during the compilation phase are processed by a specific DependencyManager Runtime bundle, which is in charge of managing the service component lifecycle and dependencies. |
| This Runtime bundle actually uses the DependencyManager programmatic API in order to manage the annotated components. |
| Annotated components can then be inspected with the DependencyManager Gogo shell, as it is the case with DM components declared through the programmatic DM API.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To register a service, your can annotate your class with a <em>@Component</em> annotation, and an instance of your class will be registered under all directly implemented interfaces into the OSGi registry. |
| You can however take control on the interfaces to be exposed, and in this case, you can use the <em>provides</em> attribute, which takes a list of classes to expose from the registry:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| class WebServiceImpl implements WebService { |
| ... |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>To illustrate this, we are now introducing a SpellChecker application which provides a Felix "spellcheck" Gogo shell command. |
| Our "spellcheck" command is implemented by the SpellChecker component which accepts a string as parameter. |
| This string is then checked for proper existence. |
| To do the checking, the SpellChecker class has a required/multiple (1..N) dependency over every available DictionaryService services. |
| Such DictionaryService represents a real dictionary for a given language (it has a <em>lang</em> service property).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Now we have introduced the background, let’s define our SpellChecker component:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component(provides=SpellChecker.class) |
| @Property(name=CommandProcessor.COMMAND_SCOPE, value="dmsample.annotation") |
| @Property(name=CommandProcessor.COMMAND_FUNCTION, values={"spellcheck"}) |
| public class SpellChecker { |
| // --- Gogo Shell command |
| |
| public void spellcheck(String word) { |
| // Check the proper existence of the word parameter, using injected DictionaryService instances |
| // ... |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In the code above, you see that the SpellCheck is annotated with the <em>@Component</em> annotation. |
| Gogo runtime does not required shell commands to implement a specific interface. |
| Commands just have to register some Pojos in the OSGi registry, but the only thing required is to provide the Pojos with two service properties ( COMMAND_SCOPE, and COMMAND_FUNCTION) which will be used by the Gogo runtime when instropecting the Pojo for invoking the proper functions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>So, coming back to the sample code, the SpellChecker class registers itself into the OSGi registry, using the <em>provides</em> attribute, which just refer to our SpellChecker class, and the two mandatory Gogo service properties are also specified using the <em>@Property</em> annotation. |
| It is not shown here, but service properties can also be provided dynamically from a method that can return a Map, and annotated with the <em>@Start</em> lifecycle callback, but we will see this feature in a another section.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Our SpellChecker component can expose itself as a Gogo shell command, but before being registered into the OSGi registry, we also need to be injected with two dependencies: one required dependency (at minimum) on a DictionaryService, and another optional one on a LogService. |
| First, let’s look at the DictionaryService, which is a simple interface:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> public interface DictionaryService { |
| /** |
| * Check for the existence of a word. |
| * @param word the word to be checked. |
| * @return true if the word is in the dictionary, false otherwise. |
| */ |
| public boolean checkWord(String word); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>And here is our previous SpellChecker component, augmented with two new ServiceDependency annotations:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component(provides=SpellChecker.class) |
| @Property(name=CommandProcessor.COMMAND_SCOPE, value="dmsample.annotation") |
| @Property(name=CommandProcessor.COMMAND_FUNCTION, values={"spellcheck"}) |
| public class SpellChecker { |
| @ServiceDependency(required = false) |
| private LogService m_log; |
| |
| private final CopyOnWriteArrayList<DictionaryService> m_dictionaries = new CopyOnWriteArrayList<DictionaryService>(); |
| |
| @ServiceDependency(removed = "removeDictionary") |
| protected void addDictionary(DictionaryService dictionary) { |
| m_dictionaries.add(dictionary); |
| } |
| |
| protected void removeDictionary(DictionaryService dictionary) { |
| m_dictionaries.remove(dictionary); |
| } |
| |
| // --- Gogo Shell command |
| |
| public void spellcheck(String word) { |
| m_log.log(LogService.LOG_INFO, "Checking spelling of word \"" + word |
| + "\" using the following dictionaries: " + m_dictionaries); |
| |
| for (DictionaryService dictionary : m_dictionaries) { |
| if (dictionary.checkWord(word)) { |
| System.out.println("word " + word + " is correct"); |
| return; |
| } |
| } |
| System.err.println("word " + word + " is incorrect"); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>There are many things to describe in the code above:</p> |
| </div> |
| <div class="paragraph"> |
| <p>First, we define an optional dependency on the LogService, by defining a <em>@ServiceDependency(required=false)</em> annotation on our m_logService field: This means that our component will be provided into the OSGi registry even if there is no available LogService, and in this case, a NullObject will be injected in our class field; |
| This will avoid to check for nullability, when using the m_logService field. |
| All optional dependencies applied on class fields are injected with a NullObject (when not available). |
| The NullObject can be invoked and will do nothing. |
| For a lot of cases that is good enough to handle optional dependencies. |
| But when you really want to check if an optional service is there or not, then you have to apply the optional dependency on a callback method, which will be called when the optional service is available.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Next comes the dependency on the DictionaryService. |
| Here, we use a <em>ServiceDependency</em> annotation, but this time we apply it on a method (<em>add/removeDictionary</em>). |
| There is no need to specify the "<em>required=true</em>" flag because it is the default value. |
| Notice that this behavior is different from the API, where service dependencies are optional by default . We use a callback method, because we just need to register all available DictionaryService services in our dictionary list, which is used when checking word existence. |
| This list is a copy on write list because the dependency may be injected at any time, possibly from another thread. |
| So, using a copy on write list avoid us to use synchronized methods.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Notice that the @ServiceDependency could also have been applied on the m_dictionaries field, and in this case, no need to define callback methods (addDictionary/removeDictionary). |
| So, in this case the dictionaries will be automatically added in the collection field.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_component_types"><a class="anchor" href="#_component_types"></a>Component types</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The following types of components are supported when using annotations:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Component: Allows to define osgi services</p> |
| </li> |
| <li> |
| <p>Aspect Service: A service that provides a non-functional aspect on top of an existing service</p> |
| </li> |
| <li> |
| <p>Service Adapter: A Service that adapts another existing service into a new one</p> |
| </li> |
| <li> |
| <p>Bundle Adapter: Allows to provide an osgi service on top of an existing bundle</p> |
| </li> |
| </ul> |
| </div> |
| <div class="sect2"> |
| <h3 id="_component"><a class="anchor" href="#_component"></a>Component</h3> |
| <div class="paragraph"> |
| <p>Components are the main building blocks for OSGi applications and can be annotated with @Component. |
| They can publish themselves as a service, and/or they can have dependencies. |
| These dependencies will influence their life cycle as component will only be activated when all required dependencies are available. |
| To define a component, you can use the @Component annotation (see <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/Component.html">@Component javadoc</a>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Applying this annotation on top of a java class let it be a service component. |
| All directly implemented interfaces will be registered in the osgi registry, but you can control the provided interfaces using the <code>provides</code> attribute. |
| Sometimes, your class implements some interfaces, but yet you don’t want them to be registered, in this case, declaring <code>provides={}</code> ensures that no services will be registered. |
| However, the component can still define service dependencies and it will be invoked in the @Start callback when all required dependencies are satisfied.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The default public constructor is used to initialize the component, but you can also specify a static method that will be used to instantiate the component (using the <code>factoryMethod</code> attribute). |
| This allows for example to create the component instance using a dynamic proxy.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Here is a sample showing a Hello component:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> /** |
| * This component will be activated once the bundle is started. |
| */ |
| @Component |
| class Hello implements HelloService { |
| @Start |
| void start() { |
| // Our component is starting and is about to be registered in the OSGi registry as a HelloService service. |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>By default, components are created automatically, when the Components' bundle is started and when the Component dependencies are satisfied. |
| But certain software patterns require the creation of Services on demand. |
| For example, a Service could represent an application that can be launched multiple times and each Service instance can then quit independently. |
| Such a pattern requires a factory that creates the instances, and <code>Managed Service Factories</code> can be used to implement this use case. |
| it is based on OSGi Configuration Admin service. |
| Using the configuration admin service, you can create multiple dictionaries , and for each one a new service will be created The mapping between the dictionaries and the services are done using a so called <code>PID</code>. |
| So, if you need your component to be instantiated multiple times, you first need to define the PID using the <code>factoryPid</code> attribute.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">/** |
| * All component instances will be created/updated/removed by the "HelloFactory" component |
| */ |
| @Component(factoryPid="my.factory.pid") |
| class Hello implements HelloService { |
| void updated(Dictionary conf) { |
| // Configure or reconfigure our component. The conf is provided by the factory, |
| } |
| |
| @Start |
| void start() { |
| // Our component is starting and is about to be registered in the OSGi registry as a Hello service. |
| } |
| } |
| |
| /** |
| * This class will instantiate some Hello component instances |
| */ |
| @Component |
| class HelloFactory { |
| @ServiceDependency |
| void bind(ConfigurationAdmin cm) { |
| // instantiate a first instance of Hello component |
| Configuration c1 = cm.createFactoryConfiguration("my.factory.pid", "?"); |
| Hashtable props = new Hashtable(); |
| props.put("key", "value1"); |
| c1.update(props); |
| |
| // instantiate another instance of Hello component |
| Configuration c2 = cm.createFactoryConfiguration("my.factory.pid", "?"); |
| props = new Hashtable(); |
| props.put("key", "value2"); |
| c2.update(props); |
| |
| // destroy the two instances of X component |
| c1.delete(); |
| c2.delete(); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In the above example, the PID is "my.factory.pid", and the HelloFactory component uses the <code>ConfigurationAdmin</code> service in order to create some factory configurations using the "my.factory.pid". |
| This pattern allows to programatically create/update/remove multiple instances of the same Component.</p> |
| </div> |
| <div class="paragraph"> |
| <p>By default, the HelloComponent can define an <code>updated(Dictionary)</code> callback: it will be called when the component is created, but you can override the method which receives the configuraiton using the <code>updated</code> attribute.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When you want to propagate the configuration to the provided service properties, you can also define the <code>propagate</code> attribute. |
| Notice that when you propagate the configuration to the provided service properties, then the the configuration takes precedence over the service properties, meaning that if a given property is declared in the service properties, then it will be overriden if the configation also contains the property.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_aspect_component"><a class="anchor" href="#_aspect_component"></a>Aspect component</h3> |
| <div class="paragraph"> |
| <p>An aspect service in DM provides a non-functional aspect on top of an existing service. |
| In aspect oriented programming, an aspect, or interceptor can sit between a client and another target service used by the client. |
| An Aspect Service first tracks a target service and is created once the target service is detected. |
| Then the Aspect Service is provided, but with a higher ranking, and the client is transparently updated with the aspect. |
| Aspects can be chained and may apply to the same target service (and in this case, the ranking of the Aspect service is used to chain aspects in the proper order).</p> |
| </div> |
| <div class="paragraph"> |
| <p>You can define an aspect service using the @AspectService annotation (see <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/AspectService.html">@AspectService javadoc</a>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Usage example:</p> |
| </div> |
| <div class="paragraph"> |
| <p>Here, the <code>Aspect</code> class is registered into the OSGI registry each time an InterceptedService is found from the registry.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @AspectService(ranking=10)) |
| class Aspect implements InterceptedService { |
| // The service we are intercepting (injected by reflection) |
| volatile InterceptedService intercepted;</code></pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> public void doWork() { |
| intercepted.doWork(); |
| } |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The Aspect class intercepts the original InterceptedService, and decorates its "doWork()" method. |
| This aspect uses a rank with value "10", meaning that it will intercept some other eventual aspects with lower ranks. |
| It will also inherit of the original InterceptedService service properties.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_adapter_component"><a class="anchor" href="#_adapter_component"></a>Adapter component</h3> |
| <div class="paragraph"> |
| <p>An adapter service component (@AdapterService) adapts another existing service into a new one. |
| Like with aspects, sometimes you want to create adapters for certain services, which add certain behavior that results in the publication of (in this case) a different service. |
| Adapters can dynamically be added and removed and allow you to keep your basic services implementations clean and simple, adding extra features on top of them in a modular way.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You can define an aspect service using the @AdapterService annotation (see <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/AdapterService.html">@AdapterService javadoc</a>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Here, the AdapterService is registered into the OSGI registry each time an AdapteeService is found from the registry.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> interface AdapteeService { |
| void method1(); |
| void method2(); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>@Component |
| @Property(name="p1", value="v1") |
| class Adaptee implements AdapteeService { |
| ... |
| }</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>interface AdapterService { |
| void doWork(); |
| }</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>@AdapterService(adapteeService = AdapteeService.class) |
| @Property(name="p2", value="v2") |
| class AdapterImpl implements AdapterService { |
| // The service we are adapting (injected by reflection) |
| volatile AdapteeService adaptee;</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> public void doWork() { |
| adaptee.method1(); |
| adaptee.method2(); |
| } |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The AdapterImpl class adapts the AdapteeService to the AdapterService. |
| The AdapterService will also have the following service property: p1=v1, p2=v2 :</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_bundle_adapter_component"><a class="anchor" href="#_bundle_adapter_component"></a>Bundle adapter component</h3> |
| <div class="paragraph"> |
| <p>Bundle adapters are similar to Adapter Components, but instead of adapting a service, they adapt a bundle with a certain set of states (STARTED|INSTALLED|…​), and provide a service on top of it.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You can define a bundle adapter service using the @BundleAdapterService annotation (see <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/BundleAdapterService.html">@BundleAdapterService javadoc</a>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>The bundle adapter will be applied to any bundle that matches the specified bundle state mask and filter conditions, which may match some of the bundle OSGi manifest headers. |
| For each matching bundle an adapter will be created based on the adapter implementation class. |
| The adapter will be registered with the specified interface and with service properties found from the original bundle OSGi manifest headers plus any extra properties you supply here. |
| If you declare the original bundle as a member it will be injected.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In the following example, a "VideoPlayer" Service is registered into the OSGi registry each time an active bundle containing a "Video-Path" manifest header is detected:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @BundleAdapterService(filter = "(Video-Path=*)", stateMask = Bundle.ACTIVE, propagate=true) |
| public class VideoPlayerImpl implements VideoPlayer { |
| volatile Bundle bundle; // Injected by reflection</code></pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> void play() { |
| URL mpegFile == bundle.getEntry(bundle.getHeaders().get("Video-Path")); |
| // play the video provided by the bundle ... |
| } |
| }</pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_component_lifecycle"><a class="anchor" href="#_component_lifecycle"></a>Component lifecycle</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>A component has a lifecycle that controls when it is started or stopped. |
| A bundle must be started before the DM Runtime can process its components. |
| When the bundle is started, the DM Runtime then parses a specific <em>DependencyManager-Component</em> manifest header, which points to a list of descriptors describing all annotated components. |
| Such descriptors are actually generated at compilation time, and annotation are not reflectively parsed at runtime. |
| Only the descriptor is used to process the components.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For each component, the DM Runtime first ensures that all dependencies are satisfied before activating it. |
| Likewise, the component is deactivated when some of the required dependencies are not available anymore or when the bundle is stopped. |
| Unless the bundle is stopped, components may be deactivated and reactivated, depending on the departure and arrival of required dependencies. |
| The manager which is in charge of maintaining the state of components is implemented in the DM Runtime bundle (org.apache.felix.dm.runtime bundle).</p> |
| </div> |
| <div class="paragraph"> |
| <p>So, during activation, the component goes through a number of states, where each transition includes the invocation of the following lifecycle method callbacks on the service implementation:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/Init.html">@Init</a>: this callback is invoked after all required dependencies have been injected. |
| In this method, you can yet add more dynamic dependencies using the DM API, or you can possibly configure other dependencies filter and required flags (see <a href="#_dynamic_dependency_configuration">Dynamic dependency configuration</a>).</p> |
| </li> |
| <li> |
| <p><a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/Start.html">@Start</a>: this callback is invoked after all required dependencies added in the @Init method have been injected.</p> |
| </li> |
| <li> |
| <p><a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/Registered.html">@Registered</a>: this callback is invoked after the service component is registered (if the component provides a service). |
| The callback can takes as argument a ServiceRegistration parameter.</p> |
| </li> |
| <li> |
| <p><a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/Stop.html">@Stop</a>: this method is called when a required dependency is lost or when the bundle is stopped</p> |
| </li> |
| <li> |
| <p><a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/Destroy.html">@Destoy</a> annotations: the component is about to be destroyed</p> |
| </li> |
| </ul> |
| </div> |
| <div class="sect2"> |
| <h3 id="_component_activation"><a class="anchor" href="#_component_activation"></a>Component activation</h3> |
| <div class="paragraph"> |
| <p>Activating a component consists of the following steps:</p> |
| </div> |
| <div class="paragraph"> |
| <p>1) Wait for all required dependencies to be available. |
| When all required dependencies are available:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>instantiate the component</p> |
| </li> |
| <li> |
| <p>inject all required dependencies (on class fields using reflection, or by invoking callback methods)</p> |
| </li> |
| <li> |
| <p>inject all optional dependencies defined on class fields, possibly with a <em>NullObject</em> if the dependency is not available.</p> |
| </li> |
| <li> |
| <p>call the component init method (annotated with <em>@Init</em>, see (see <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/Init.html">@Init javadoc</a>).). |
| In the init method, you are yet allowed to add some additional dependencies using the Dependency Manager API or DM Lambda). |
| Alternatively, you can also configure some dependencies dynamically (explained later, in <a href="#_dynamic_dependency_configuration">Dynamic Dependency Configuration</a>.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>2) Wait for extra required dependencies optionally configured from the init() method. |
| When all extra required dependencies are available:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>inject extra required dependencies (if some were defined in init() method).</p> |
| </li> |
| <li> |
| <p>invoke the start method annotated with <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/Start.html">@Start annotation</a>. |
| The start method may return a Map<String, Object> that will be appended to the provided service properties (the the component provides a service).</p> |
| </li> |
| <li> |
| <p>start tracking optional dependencies applied on method callbacks (invoke optional dependency callbacks). |
| Notice that NullObject pattern is not applied to optional callback dependencies. |
| In other words, if the dependency is not there, your callback won’t be invoked at all. |
| If you need the NullObject pattern, then apply optional dependencies on class fields, not on callback methods.</p> |
| </li> |
| <li> |
| <p>register the OSGi service, if the component provides one.</p> |
| </li> |
| <li> |
| <p>invoke the method annotatated with <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/Registered.html">@Registered annotation</a>. |
| The method, if declared, takes as argument a <code>ServiceRegistration</code> which corresponds to the registered service.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_component_deactivation"><a class="anchor" href="#_component_deactivation"></a>Component deactivation</h3> |
| <div class="paragraph"> |
| <p>Deactivating a component consists of the following steps:</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the bundle is stopped or if some required dependencies are unavailable, or if the component has declared a factoryPid and the factory configuration has been delete, then:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Unbind optional dependencies (defined on callback methods). |
| Notice that any optional dependency unavailability does not trigger the component deactivation; |
| the <em>removed</em> callbacks are just invoked, if declared in the annotation.</p> |
| </li> |
| <li> |
| <p>Invoke the stop method (annotated wit <em>@Stop</em>), and unregister some OSGi services (if the components provides some services).</p> |
| </li> |
| <li> |
| <p>invoke destroy method (annotated with <em>@Destroy</em>).</p> |
| </li> |
| <li> |
| <p>invoke <em>removed</em> callbacks for required dependencies, if any.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_example"><a class="anchor" href="#_example"></a>Example</h3> |
| <div class="paragraph"> |
| <p>The following example shows a basic component, which uses the @Start annotation:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> /** |
| * A Component Using lifecyce callbacks |
| */ |
| @Component |
| class X implements Y { |
| @ServiceDependency |
| void bindOtherService(OtherService other) { |
| // Will be injected before we are started (because it's a required dependency). |
| }</code></pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> @Start |
| void start() { |
| // All required dependencies are injected: initialize our component. |
| } |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The following example shows a component, which returns some service properties from its start method, and the component also defines the @Registered annotation in order to get the actual ServiceRegistration for the provided service:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">/** |
| * A Component Using lifecyce callbacks |
| */ |
| @Component |
| @Property(name="p1", value="v1") // service properties |
| class X implements Y { |
| @ServiceDependency |
| void bindOtherService(OtherService other) { |
| // Will be injected before we are started (because it's a required dependency). |
| } |
| |
| @Start |
| Map<String, Object> start() { |
| // All required dependencies are injected: initialize our component. |
| // Once we return, our Y service will be published in the OSGi registry, using the following |
| // service properties appended to the ones specified on top of the class with the @Property |
| // annotation (notice that returning a map is optional and our start() method could be |
| // declared as void). |
| Map<String, Object> additionalServiceProperties = new HashMap<>(); |
| additionalServiceProperties.put("p2", "v2"); |
| return additionalServiceProperties; |
| } |
| |
| @Registered |
| void registered(ServiceRegistration registration) { |
| // once our service is registered, we can obtainer here the corresponding ServiceRegistration ... |
| } |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_lifecycle_control"><a class="anchor" href="#_lifecycle_control"></a>Lifecycle control</h3> |
| <div class="paragraph"> |
| <p>As explained in the <em>Component Activation</em> section, a component which provides a service is automatically registered into the OSGi registry, after the @Start method returns. |
| But it is sometimes required to control when the service is really started/published or + unpublished/stopped.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This can be done using the <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/LifecycleController.html">@LifecycleController</a> annotation. |
| This annotation injects a Runnable object that can be invoked when you want to trigger your service startup and publication. |
| The @LifecycleController is like a required dependency and is injected before the @Init method is called.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For instance, imagine that your component publishes an OSGi service, but before, it needs to register into a DHT (Distributed Hash Table), whose API is asynchronous: that is: the DHT API will callback you once you are inserted into a node in the DHT. |
| In this case, what you would like to do is to publish your OSGi service, but only after you are + inserted into the DHT (when the DHT callbacks you) …​ |
| Such a case is supported using the @LifecyceController annotation, which gives you + full control of when your component is <em>started/published</em> and <em>unpublished/stopped</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Let’s illustrate this use case with a concrete example: First here is the DHT asynchronous API:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">/** |
| * This is an element which can be inserted into the distributed hash table. |
| */ |
| public interface DHTElement { |
| void inserted(); // callback used to notify that the element is inserted into the DHT |
| } |
| |
| /** |
| * This is the DHTService, which registers a DHTElement asynchronously. |
| */ |
| public interface DHTService { |
| void insert(DHTElement element); // will callback element.inserted() later, once registered into the DHT. |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Next, here is our service, which uses the @LifecycleController in order to take control of when the service is published into the OSGi registry:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component(provides={MyService.class}) |
| public class MyServiceImpl implements MyService, DHTElement { |
| @ServiceDependency |
| DHTService m_dht; |
| |
| @LifecycleController |
| Runnable m_start; // will fire component startup, once invoked. |
| |
| @Init |
| void init() { |
| m_dht.insert(this); // asynchronous, will callback once registered into the DHT |
| } |
| |
| public void inserted() { |
| // We are inserted into the DHT: we can now trigger our component startup. |
| // We just invoke the runnable injected by our @LifecycleController annotation, which will trigger our |
| // service publication (we'll be called in our @Start method before) |
| m_start.run(); |
| } |
| |
| @Start |
| void start() { |
| // method called only once we invoke our trigger Runnable (see inserted method). |
| // Our Service will be published once this method returns. |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Same example as above, using java8 method reference:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component |
| public class MyServiceImpl implements MyService { |
| @ServiceDependency |
| DHTService m_dht; |
| |
| @LifecycleController |
| Runnable m_start; // will fire component startup, once invoked. |
| |
| @Init |
| void init() { |
| m_dht.insert(m_start::run); // asynchronous, will callback m_registered.run() once registered into the DHT |
| } |
| |
| @Start |
| void start() { |
| // method called after the m_dht service has called the m_registered.run() method. |
| } |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_dependencies"><a class="anchor" href="#_dependencies"></a>Dependencies</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_service_dependencies"><a class="anchor" href="#_service_dependencies"></a>Service dependencies</h3> |
| <div class="paragraph"> |
| <p>Service Dependencies can be defined using the <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/ServiceDependency.html">@ServiceDependency</a> annotation.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Dependencies can either be required or optional. |
| Required dependencies need to be resolved before the service can even become active. |
| Optional dependencies can appear and disappear while the service is active. |
| <strong>Please notice that, unlike with the DM API, service dependencies are required by default.</strong></p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_field_injection"><a class="anchor" href="#_field_injection"></a>Field injection</h4> |
| <div class="paragraph"> |
| <p>The dependency manager will automatically fill in any references to required @ServiceDependency that are applied on attributes. |
| The same goes for optional dependencies if they are available. |
| If not, those will be implemented by a null object [NULLOBJ]. |
| In short, this allows you to simply use these interfaces as if they were always available. |
| A good example of this is the LogService. |
| If it’s available, we want to use it for logging. |
| If not, we want to simply ignore log messages. |
| Normally, you’d need to check a reference to this service for null before you can use it. |
| By using a null object, this is not necessary anymore.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When the @ServiceDependency annotation is defined on a class field, the following field types are supported:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>a field having the same type as the dependency. |
| If the field may be accessed by any thread, then the field should be declared volatile, in order to ensure visibility when the field is auto injected concurrently.</p> |
| </li> |
| <li> |
| <p>a field which is assignable to an <code>Iterable<T></code> where T must match the dependency type. |
| In this case, an Iterable will be injected by DependencyManager before the start callback is called. |
| The Iterable field may then be traversed to inspect the currently available dependency services. |
| The Iterable can possibly be set to a final value so you can choose the Iterable implementation of your choice (for example, a CopyOnWrite ArrayList, or a ConcurrentLinkedQueue).</p> |
| </li> |
| <li> |
| <p>a Map<K,V> where K must match the dependency type and V must exactly equals Dictionary class. |
| In this case, a ConcurrentHashMap will be injected by DependencyManager before the start callback is called. |
| The Map may then be consulted to lookup current available dependency services, including the dependency service properties (the map key holds the dependency services, and the map value holds the dependency service properties). |
| The Map field may be set to a final value so you can choose a Map of your choice (Typically a ConcurrentHashMap). |
| A ConcurrentHashMap is "weakly consistent", meaning that when traversing the elements, you may or may not see any concurrent updates made on the map. |
| So, take care to traverse the map using an iterator on the map entry set, which allows to atomically lookup pairs of Dependency service/Service properties.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This is an example where you inject a <code>Dependency</code> service on a class field:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| class MyComponent { |
| @ServiceDependency |
| volatile Dependency m_dependency; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Another example, were we inject multiple dependencies to an Iterable field</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| class MyComponent { |
| @ServiceDependency |
| final Iterable<Dependency> dependencies = new CopyOnWriteArrayList<>(); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>And next, we inject multiple dependencies to a Map field, allowing to inspect service dependency properties (the keys hold the services, and the values hold the associated service properties):</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| class MyComponent { |
| @ServiceDependency |
| final Map<MyDependency, Dictionary<String, Object>> dependencies = new ConcurrentHashMap<>; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Optional dependencies applied on class fields will inject a NullObject when the dependency is unavailable. |
| This allows you to avoid to check if the optional dependency is not null using a "if" statement, and invoking the NullObject will result in a No Op method call. |
| When the optional dependency type is not an interface, then NullObject won’t work because internally, the NullObject is implemented using a dynamic proxy. |
| In this case you can use the ServiceDependency.defaultImpl attribute which allows to specify a default implementation when the optional dependency is unavailable.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| public class MyComponent { |
| @ServiceDependency(required=false, defaultImpl=MyDefaultImpl.class) |
| volatile Dependency m_dependency; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>in the above example, the MyDefaultImpl class will be injected on the m_dependency class field in case the dependency is unavailable.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_callback_injection"><a class="anchor" href="#_callback_injection"></a>Callback injection</h4> |
| <div class="paragraph"> |
| <p>Optionally, a service can define callbacks for each dependency. |
| These callbacks are invoked whenever a new dependency is discovered or an existing one is disappearing. |
| They allow you to track these dependencies. |
| This can be very useful if you, for example, want to implement the white board pattern.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The callbacks allows to get notified when a service is added, and support the following signatures:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>(Component comp, ServiceReference ref, Service service) |
| (Component comp, ServiceReference ref, Object service) |
| (Component comp, ServiceReference ref) |
| (Component comp, Service service) |
| (Component comp, Object service) |
| (Component comp) |
| (Component comp, Map properties, Service service) |
| (ServiceReference ref, Service service) |
| (ServiceReference ref, Object service) |
| (ServiceReference ref) |
| (Service service) |
| (Service service, Map properties) |
| (Map properties, Service, service) |
| (Service service, Dictionary properties) |
| (Dictionary properties, Service service) |
| (Object service) |
| (ServiceReference<T> service) |
| (ServiceObjects<T> service)</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| class MyComponent { |
| @ServiceDependency |
| void bind(MyDependency dependency) {} |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Same example as before, but the callback signatures includes service properties:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| class MyComponent { |
| @ServiceDependency |
| void bind(MyDependency dependency, Map<String, Object> serviceProperties) {} |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Same example as before, but this time we track service change:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component |
| class MyComponent { |
| @ServiceDependency(change="updated") |
| void bind(MyDependency dependency, Map<String, Object> serviceProperties) {} |
| |
| void updated(MyDependency dependency, Map<String, Object> serviceProperties) {} |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Example where you track added/changed/removed service:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component |
| class MyComponent { |
| @ServiceDependency(change="updated", remove="unbind") |
| void bind(MyDependency dependency, Map<String, Object> serviceProperties) {} |
| |
| void updated(MyDependency dependency, Map<String, Object> serviceProperties) {} |
| |
| void unbind(MyDependency dependency, Map<String, Object> serviceProperties) {} |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_whiteboard_pattern"><a class="anchor" href="#_whiteboard_pattern"></a>Whiteboard pattern</h4> |
| <div class="paragraph"> |
| <p>Required service dependency are always invoked before the start (@Start) callback is invoked. |
| However, Optional dependency <strong>callbacks</strong> are always invoked <strong>after</strong> the start (@Start) callbacks. |
| This allows to easily implement the whiteboard patter, because you can first make sure your component is fully initialized before it can start to track other services (whiteboard pattern).</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example, assume you write a <code>TaskExecutor</code> component which tracks <code>Task</code> services. |
| So, each time a Task is found from the registry, then you want to schedule the Task in an Executor, and you also want to maitain statistics on executed tasks. |
| So, your <code>TaskExecutor</code> depends on two required services: an <code>Executor</code> service (used to schedule the tasks), as well as a <code>TaskMetrics</code> service which is used to maintain Task execution statistics. |
| So what you need is to make sure your are injected with the TaskMetrics and the Executor service before you can actually start to handle Tasks. |
| To do so, simply define two required dependencies on the <code>Executor</code> and the <code>TasksMetrics</code>, and define an optional dependency on the Task services. |
| This will ensure that the Tasks callbacks are invoked after your component is started:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">interface Task extends Runnable { |
| } |
| |
| @Component |
| TaskExecutor { |
| @ServiceDependency |
| volatile Executor m_executor; |
| |
| @ServiceDependency |
| volatile TaskMetrics m_taskMetrics; |
| |
| @Start |
| void start() { |
| // at this point, all required dependencies have been injected and we can now start to track |
| // the Task services |
| } |
| |
| @ServiceDependency(required=false) |
| void bind(Task task) { |
| m_executor.execute(task); |
| m_taskMetrics.taskScheduled(); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_tracking_any_services_matching_a_given_filter"><a class="anchor" href="#_tracking_any_services_matching_a_given_filter"></a>Tracking any services matching a given filter</h4> |
| <div class="paragraph"> |
| <p>Sometimes, you may want to be injected with any service objects matching a given filter, without any additional filter on the class service interface. |
| In this case, you need to use the <code>service=ServiceDependency.ANY</code> attribute</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.apache.felix.dm.annotation.ServiceDependency; |
| import org.apache.felix.dm.annotation.api.ServiceDependency.Any; |
| |
| @Component |
| public class MyService { |
| @ServiceDependency(service=Any.class, filter="(property=true)") |
| void bind(Object allServices) { |
| } |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_service_dependency_properties_propagation"><a class="anchor" href="#_service_dependency_properties_propagation"></a>Service dependency properties propagation</h4> |
| <div class="paragraph"> |
| <p>It is possible to propagate the dependency service properties, using the ServiceDependency.propagate attribute. |
| When the service dependency properties are propagated, they will be appended to the component service properties, but won’t override them (the component service properties takes precedence over the propagated service dependencies).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| @Properties(name="p1", value="v1") |
| public class MyServiceImpl implements MyService { |
| @ServiceDependency(propagate=true) |
| void bind(OtherService other) { |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The service above will be registered with the p1=v1 service properties, as well as with any service properties which come from the Service Dependency.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_defining_a_swap_aspect_callback"><a class="anchor" href="#_defining_a_swap_aspect_callback"></a>defining a swap aspect callback</h4> |
| <div class="paragraph"> |
| <p>When you define a service dependency, it is possible to define a swap callback in case an original service dependency is replaced by an aspect, and you then want to be called back at the time the service dependency is replaced.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component |
| public class MyServiceImpl { |
| @ServiceDependency(swap="swap") |
| void bind(OtherService other) { |
| } |
| |
| void swap(OtherService old, OtherService replace) { |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>So, if an aspect service is registered for the OtherService service, then your swap method will be called so you can take the service replacement into account.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The swap callback supports the following signatures:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> (Service old, Service replace) |
| (Object old, Object replace) |
| (ServiceReference old, Service old, ServiceReference replace, Service replace) |
| (ServiceReference old, Object old, ServiceReference replace, Object replace) |
| (Component comp, Service old, Service replace) |
| (Component comp, Object old, Object replace) |
| (Component comp, ServiceReference old, Service old, ServiceReference replace, Service replace) |
| (Component comp, ServiceReference old, Object old, ServiceReference replace, Object replace) |
| (ServiceReference old, ServiceReference replace) |
| (Component comp, ServiceReference old, ServiceReference replace) |
| (ServiceObjects old, ServiceObjects replace) |
| (Component comp, ServiceObjects old, ServiceObjects replace)</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_blocking_a_service_invocation_while_it_is_updating"><a class="anchor" href="#_blocking_a_service_invocation_while_it_is_updating"></a>Blocking a service invocation while it is updating.</h4> |
| <div class="paragraph"> |
| <p>When an injected service dependency is an interface, it is possible to block the service invocation while it is being updated. |
| Only useful for required stateless dependencies that can be replaced transparently. |
| A Dynamic Proxy is used to wrap the actual service dependency (which must be an interface). |
| When the dependency goes away, an attempt is made to replace it with another one which satisfies the service dependency criteria. |
| If no service replacement is available, then any method invocation (through the dynamic proxy) will block during a configurable timeout. |
| On timeout, an unchecked IllegalStateException exception is raised (but the service is not deactivated).</p> |
| </div> |
| <div class="paragraph"> |
| <p>To use this feature, you need to specify a <code>timeout</code> attribute like this:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| class MyServer implements Runnable { |
| @ServiceDependency(timeout=15000) |
| MyDependency dependency;.</code></pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>@Start |
| void start() { |
| (new Thread(this)).start(); |
| }</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>public void run() { |
| try { |
| dependency.doWork(); |
| } catch (IllegalStateException e) { |
| t.printStackTrace(); |
| } |
| } }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Notice that the changed/removed callbacks are not used when the timeout parameter is greater than -1. |
| -1 means no timeout at all (default). |
| 0 means that invocation on a missing service will fail immediately. |
| A positive number represents the max timeout in millis to wait for the service availability.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_configuration_dependencies"><a class="anchor" href="#_configuration_dependencies"></a>Configuration dependencies</h3> |
| <div class="paragraph"> |
| <p>A configuration dependency is required by default, and allows you to depend on the availability of a valid configuration for your component. |
| Use the <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/ConfigurationDependency.html">@ConfigurationDependency annotation</a> to define a configuration dependency.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This dependency requires the OSGi Configuration Admin Service. |
| Configuration Dependency callback is always invoked before any service dependency callbacks, and before init/start callbacks. |
| The annotation can be applied on a callback method which accepts the following parameters:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>callback(Dictionary) |
| callback(Component, Dictionary) |
| callback(Component, Configuration ... configTypes) // type safe configuration interface(s) |
| callback(Configuration ... configTypes) // type safe configuration interface(s) |
| callback(Dictionary, Configuration ... configTypes) // type safe configuration interfaces(s) |
| callback(Component, Dictionary, Configuration ... configTypes) // type safe configuration interfaces(s)</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Configuration can be simply injected in the form of dictionaries, or in the form of type-safe configuration interfaces.</p> |
| </div> |
| <div class="paragraph"> |
| <p>the annotation attributes are the following:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>pid: Returns the pid for a given service (by default, the pid is the service class name).</p> |
| </li> |
| <li> |
| <p>propagate: Returns true if the configuration properties must be published along with the service. |
| The configuration properties takes precedence over the component service properties.</p> |
| </li> |
| <li> |
| <p>pidClass: Returns the pid from a class name.</p> |
| </li> |
| <li> |
| <p>required: Sets the required flag which determines if this configuration dependency is required or not.</p> |
| </li> |
| <li> |
| <p>name: used to dynamically configure the pid from an @Init method.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="sect3"> |
| <h4 id="_type_safe_configuration"><a class="anchor" href="#_type_safe_configuration"></a>Type safe configuration</h4> |
| <div class="paragraph"> |
| <p>Configuration types allows you to specify a Java interface that is implemented by DM and such interface is then injected to your callback instead of the actual Dictionary. |
| Using such configuration interface provides a way for creating type-safe configurations from a actual Dictionary that is normally injected by Dependency Manager. |
| The callback accepts in argument an interface that you have to provide, and DM will inject a proxy that converts method calls from your configuration-type to lookups in the actual map or dictionary. |
| The results of these lookups are then converted to the expected return type of the invoked configuration method. |
| As proxies are injected, no implementations of the desired configuration-type are necessary!</p> |
| </div> |
| <div class="paragraph"> |
| <p>The lookups performed are based on the name of the method called on the configuration type. |
| The method names are "mangled" to the following form:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[lower case letter] [any valid character]*.</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Method names starting with get or is (JavaBean convention) are stripped from these prefixes. |
| For example: given a dictionary with the key "foo" can be accessed from a configuration-type using the following method names:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>foo(), getFoo() and isFoo().</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The return values supported are:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>primitive types (or their object wrappers);</p> |
| </li> |
| <li> |
| <p>strings;</p> |
| </li> |
| <li> |
| <p>enums;</p> |
| </li> |
| <li> |
| <p>arrays of primitives/strings;</p> |
| </li> |
| <li> |
| <p>Collection types;</p> |
| </li> |
| <li> |
| <p>Map types;</p> |
| </li> |
| <li> |
| <p>Classes and interfaces.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>When an interface is returned, it is treated equally to a configuration type, that is, a proxy is returned.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Arrays can be represented either as comma-separated values, optionally enclosed in square brackets. |
| For example: [ a, b, c ] and a, b,c are both considered an array of length 3 with the values "a", "b" and "c". |
| Alternatively, you can append the array index to the key in the dictionary to obtain the same: a dictionary with "arr.0" => "a", "arr.1" => "b", "arr.2" => "c" would result in the same array as the earlier examples.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Maps can be represented as single string values similarly as arrays, each value consisting of both the key and value separated by a dot. |
| Optionally, the value can be enclosed in curly brackets. |
| Similar to array, you can use the same dot notation using the keys. |
| For example, a dictionary with:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>map={key1.value1, key2.value2}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>and a dictionary with:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>map.key1=value1 |
| map.key2=value2</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>result in the same map being returned. |
| Instead of a map, you could also define an interface with the methods getKey1() and getKey2() and use that interface as return type instead of a Map.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In case a lookup does not yield a value from the underlying map or dictionary, the following rules are applied:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>primitive types yield their default value, as defined by the Java Specification;</p> |
| </li> |
| <li> |
| <p>string, Classes and enum values yield null;</p> |
| </li> |
| <li> |
| <p>for arrays, collections and maps, an empty array/collection/map is returned;</p> |
| </li> |
| <li> |
| <p>for other interface types that are treated as configuration type a Null-object is returned.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_examples"><a class="anchor" href="#_examples"></a>Examples</h4> |
| <div class="paragraph"> |
| <p>In the following example, the "Printer" component depends on a configuration with "org.apache.felix.sample.Printer" PID:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">package org.apache.felix.sample; |
| |
| @Component |
| public class Printer { |
| @ConfigurationDependency |
| void updated(Dictionary config) { |
| // load printer ip/port from the provided dictionary. |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Here is the same example using a type safe configuration:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> package sample;</code></pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>public interface PrinterConfiguration { |
| String ipAddress(); |
| int portNumber(); |
| }</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>@Component |
| public class Printer { |
| @ConfigurationDependency // Will use pid "sample.PrinterConfiguration" |
| void updated(PrinterConfiguration cnf) { |
| if (cnf != null) { |
| // load configuration from the provided dictionary, or throw an exception of any configuration error. |
| String ip = cnf.ipAddress(); |
| int port = cnf.portNumber(); |
| ... |
| } |
| } |
| }</pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_bundle_dependency"><a class="anchor" href="#_bundle_dependency"></a>Bundle dependency</h3> |
| <div class="paragraph"> |
| <p>A bundle dependency allows you to depend on a bundle in a certain set of states (INSTALLED|RESOLVED|STARTED|…​), as indicated by a state mask. |
| You can also use a filter condition that is matched against all manifest entries. |
| When applied on a class field, optional unavailable dependencies are injected with a NullObject.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Use the <a href="http://felix.apache.org/apidocs/dependencymanager.annotations/r13/org/apache/felix/dm/annotation/api/BundleDependency.html">@BundleDependency annotation</a> to define a bundle dependency.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Attributes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>changed: Returns the callback method to be invoked when the service have changed.</p> |
| </li> |
| <li> |
| <p>removed: Returns the callback method to invoke when the service is lost.</p> |
| </li> |
| <li> |
| <p>required: Returns whether the dependency is required or not.</p> |
| </li> |
| <li> |
| <p>filter: Returns the filter dependency</p> |
| </li> |
| <li> |
| <p>stateMask: Returns the bundle state mask (Bundle.INSTALLED | Bundle.ACTIVE etc …​).</p> |
| </li> |
| <li> |
| <p>propagate: Specifies if the manifest headers from the bundle should be propagated to the service properties.</p> |
| </li> |
| <li> |
| <p>name: The name used when dynamically configuring this dependency from the init method. |
| Specifying this attribute allows to dynamically configure the dependency filter and required flag from the Service’s init method. |
| All unnamed dependencies will be injected before the init() method; |
| so from the init() method, you can then pick up whatever information needed from already injected (unnamed) dependencies, and configure dynamically your named dependencies, which will then be calculated once the init() method returns.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>In the following example, the "SCR" Component allows to track all bundles containing a specific "Service-Component" OSGi header, in order to load and manage all Declarative Service components specified in the SCR xml documents referenced by the header:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component |
| public class SCR { |
| @BundleDependency(required = false, |
| removed = "unloadServiceComponents", |
| filter = "(Service-Component=*)" |
| stateMask = Bundle.ACTIVE) |
| void loadServiceComponents(Bundle b) { |
| String descriptorPaths = (String) b.getHeaders().get("Service-Component"); |
| // load all service component specified in the XML descriptorPaths files ... |
| } |
| |
| void unloadServiceComponents(Bundle b) { |
| // unload all service component we loaded from our "loadServiceComponents" method. |
| } |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_dynamic_dependency_configuration"><a class="anchor" href="#_dynamic_dependency_configuration"></a>Dynamic dependency configuration</h3> |
| <div class="paragraph"> |
| <p>We have seen that a component may declare some dependencies and is started when all required dependencies are available. |
| But there are some cases when you may need to define some dependencies filters (and required flag) dynamically, possibly from data picked up from other dependencies.</p> |
| </div> |
| <div class="paragraph"> |
| <p>So, all this is possible using <em>named</em> dependencies: When you assign a name to a dependency; |
| for instance <em>@ServiceDependency(name="foo")</em>, then this has an impact on how the dependency is handled. |
| Indeed, all named dependencies are calculated <em>after</em> the @Init method returns. |
| So from your @Init method, you can then configure your named dependencies, using data provided by already injected dependencies.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To do so, your @Init method is allowed to return a Map containing the filters and required flags for each named dependencies. |
| For a given named dependency, the corresponding filter and required flag must be stored in the Map, using the "<em>filter</em>" and "<em>required</em>" keys, prefixed with the name of the dependency.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For instance, if you define a Dependency like this:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @ServiceDependency(name="foo") |
| FooService fooService;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Then you can return this map from your @Init method:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Init |
| Map init() { |
| Map m = new HashMap(); |
| m.put("foo.filter", "(foo=bar)"); |
| m.put("foo.required", "false"); |
| return m; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>So, after the init method returns, the map will be used to configure the dependency named "foo", which will then be evaluated. |
| And once the dependency is available, then it will be injected and your @Start callback will be invoked.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Usage example of a dynamic dependency:</p> |
| </div> |
| <div class="paragraph"> |
| <p>In this sample, the "PersistenceImpl" component dynamically configures the "storage" dependency from the "init" method. |
| The dependency "required" flag and filter string are derived from an xml configuration that is already injected before the init method.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component |
| public class PersistenceImpl implements Persistence { |
| // Injected before init. |
| @ConfigurationDependency |
| void updated(Dictionary conf) { |
| if (conf != null) { |
| _xmlConfiguration = parseXmlConfiguration(conf.get("xmlConfiguration")); |
| } |
| } |
| |
| // Parsed xml configuration, where we'll get our storage service filter and required dependency flag. |
| XmlConfiguration _xmlConfiguration; |
| |
| // Dynamically configure the dependency declared with a "storage" name. |
| @Init |
| Map<String, String> init() { |
| Map<String, String> props = new HashMap<>(); |
| props.put("storage.required", Boolean.toString(_xmlConfiguration.isStorageRequired())) |
| props.put("storage.filter", "(type=" + _xmlConfiguration.getStorageType() + ")"); |
| return props; |
| } |
| |
| // Injected after init (dependency filter is defined dynamically from our init method). |
| @ServiceDependency(name="storage") |
| Storage storage; |
| |
| // All dependencies injected, including dynamic dependencies defined from init method. |
| @Start |
| void start() { |
| log.log(LogService.LOG_WARNING, "start"); |
| } |
| |
| @Override |
| void store(String key, String value) { |
| storage.store(key, value); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Notice that you can also add dynamic dependencies using the Dependency Manager API, or using DM-Lambda. |
| In this case, no need to define service dependencies with annotations. |
| Here is the same example as above, but this time, the dependency on the Storage service is defined from the init method using the DM API:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Component |
| public class PersistenceImpl implements Persistence { |
| // Injected before init. |
| @ConfigurationDependency |
| void updated(Dictionary conf) { |
| if (conf != null) { |
| _xmlConfiguration = parseXmlConfiguration(conf.get("xmlConfiguration")); |
| } |
| } |
| |
| // Parsed xml configuration, where we'll get our storage service filter and required dependency flag. |
| XmlConfiguration _xmlConfiguration; |
| |
| // Dynamically configure the dependency declared with a "storage" name. |
| @Init |
| void init(org.apache.felix.dm.Comppnent myComponent) { |
| boolean required = _xmlConfiguration.isStorageRequired(); |
| String filter = _xmlConfiguration.getStorageType(); |
| DependencyManager dm = myComponent.getDependencyManager(); |
| myComponent.add(dm.createServiceDependency().setService(Storage.class, filter).setRequired(required)); |
| } |
| |
| // Injected after init, later, when the dependency added from the init() method is satisfied |
| volatile Storage storage; |
| |
| // All dependencies injected, including dynamic dependencies defined from init method. |
| @Start |
| void start() { |
| log.log(LogService.LOG_WARNING, "start"); |
| } |
| |
| @Override |
| void store(String key, String value) { |
| storage.store(key, value); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Same example as above, but this time the dependency is added from the init method using the Dependency Manager Lambda API:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import static org.apache.felix.dm.lambda.DependencyManagerActivator.component; |
| |
| @Component |
| public class PersistenceImpl implements Persistence { |
| // Injected before init. |
| @ConfigurationDependency |
| void updated(Dictionary conf) { |
| if (conf != null) { |
| _xmlConfiguration = parseXmlConfiguration(conf.get("xmlConfiguration")); |
| } |
| } |
| |
| // Parsed xml configuration, where we'll get our storage service filter and required dependency flag. |
| XmlConfiguration _xmlConfiguration; |
| |
| // Dynamically configure the dependency declared with a "storage" name. |
| @Init |
| void init(org.apache.felix.dm.Comppnent myComponent) { |
| boolean required = _xmlConfiguration.isStorageRequired(); |
| String filter = _xmlConfiguration.getStorageType(); |
| component(myComponent, comp -> comp.withSvc(Storage.class, filter, required)); |
| } |
| |
| // Injected after init, later, when the dependency added from the init() method is satisfied |
| volatile Storage storage; |
| |
| // All dependencies injected, including dynamic dependencies defined from init method. |
| @Start |
| void start() { |
| log.log(LogService.LOG_WARNING, "start"); |
| } |
| |
| @Override |
| void store(String key, String value) { |
| storage.store(key, value); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_component_composition"><a class="anchor" href="#_component_composition"></a>Component Composition</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>When implementing more complex services, you often find yourself using more than one instance for a given service. |
| However, several of these instances might want to have dependencies injected. |
| In such cases you need to tell the dependency manager which instances to consider. |
| Within a Component (or an Aspect/Adapter), you can annotate a method with the @Composition annotation. |
| This method is meant to return such composition of service instances, and the objects will be considered as part of the service implementation. |
| So, all dependencies, as well as lifecycle annotations (@Init, @Start, @Stop, @Destroy) will be applied on every objects returned by the method annotated with the @Composition annotation.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The following example illustrates a composition of two object instances, which are part of the implementation of a <em>MyService</em> service:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">/** |
| * Main implementation for the MyService Service |
| */ |
| @Component |
| public class MyServiceImpl implements MyService { |
| // This object instance is also used to implement the service. |
| private Helper helper = new Helper(); |
| |
| // MyServiceImpl, and Helper objects are part of the composition |
| @Composition |
| Object[] getComposition() { |
| return new Object[] { this, helper }; |
| } |
| |
| // This dependency is also applied to the Helper |
| @ServiceDependency |
| Dependency dep; |
| |
| // Same thing for this dependency |
| @ServiceDependency |
| void bind(Dependency2 dep2) {} |
| |
| // Lifecycle callbacks also applied on the Helper ... |
| |
| @Start |
| void start() {} |
| |
| } |
| |
| public class Helper { |
| // Also injected, since we are part of the composition |
| volatile Dependency dep; |
| |
| // But since we are not interested by the Dependency2, we don't have to declare the bind(Dependency2) method ... |
| |
| // We only specify the start lifecycle callback because we need to return some extra service properties which will be published |
| // along with the provided service ... |
| |
| Map start() { |
| Map extraServiceProperties = new HashMap(); |
| extraServiceProperties.add("foo", "bar"); |
| return extraServiceProperties; |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Here, MyServiceImpl is the main component implementation, but is composed of the Helper object instance. |
| So all Dependencies defined in MyServiceImpl will be also injected to the Helper (if the Helper declares the fields or methods). |
| The Helper may also define annotated lifecycle callbacks (optionally).</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_service_scopes"><a class="anchor" href="#_service_scopes"></a>Service scopes</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>By default service providers are registered once in the osgi registry, and all service consumers share the same service provider instance. |
| Now, you can control the scope of the provided services: From the provider side, a "scope" parameter is available for all types of DM components and allows to define the scope of the registered service.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>scope</code> attribute has three enum values: SINGLETON, BUNDLE, PROTOTYPE</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>SINGLETON: it’s as before: your registered service is a singleton, meaning that the service must be instantiated and registered once, and all using services will share the same service instance of your component.</p> |
| </li> |
| <li> |
| <p>BUNDLE: the service will be registered as a ServiceFactory, meaning an instance of the component must be created for each bundle using the service.</p> |
| </li> |
| <li> |
| <p>PROTOTYPE: the service will be registered as a PrototypeServiceFactory, meaning the service is registered as a prototype scope service and an instance of the component must be created for each distinct service requester.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Scoped Services are supported by all kind of DM service components:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Component</p> |
| </li> |
| <li> |
| <p>Aspect Service</p> |
| </li> |
| <li> |
| <p>Adapter Service</p> |
| </li> |
| <li> |
| <p>Bundle Adapter service</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>When a consumer requests a service (using ServiceDependency), then DM will automatically dereference the service like this:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>if the service has a SERVICE_SCOPE service property matching SCOPE_PROTOTYPE, the DM will internally derefence the service using the ServiceObject API: so, the consumer will get its own copy of the requested service instance.</p> |
| </li> |
| <li> |
| <p>else, DM will internally dereference the service, as before. |
| When defining scoped component implementation, you can optionally define two special class fields in order to get injected with the client Bundle requesting the service, and the ServiceRegisgtration Object. |
| Just use @Inject annotations in order to get injected with the client Bundle or the ServiceRegistration. |
| You can also define a constructor which takes as argument the client bundle as well as the service registration.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="paragraph"> |
| <p>Here is a MyService component with PROTOTYPE scope, each requester will get its own copy of MyService instance, and the MyServiceImpl.start() method will be called for each instance:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.apache.felix.dm.annotation.api.Component; |
| import org.apache.felix.dm.annotation.api.ServiceScope; |
| |
| @Component(scope=ServiceScope.PROTOTYPE) |
| public class MyServiceImpl implements MyService { |
| @Start |
| void start() { |
| // called on each MyService instance |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The above service will then automatically be instantiated for each service requester:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.apache.felix.dm.annotation.api.Component; |
| import org.apache.felix.dm.annotation.api.ServiceScope; |
| |
| @Component |
| public class Client1 { |
| @ServiceDependency |
| void bind(MyService service) { |
| // Client1 will be injected with its own MyService instance |
| } |
| } |
| |
| @Component |
| public class Client2 { |
| @ServiceDependency |
| void bind(MyService service) { |
| // Client2 will be injected with its own MyService instance |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The two Client1/Client2 above will be injected with two distinct component instances for the MyService service (each MyServiceImpl instance will be invoked in its start callback). |
| Now, if you want to control the creation of the MyService, you can then define a bind method which takes as argument a ServiceObjects parameter like this:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.apache.felix.dm.annotation.api.Component; |
| import org.apache.felix.dm.annotation.api.ServiceScope; |
| |
| @Component |
| public static class Client { |
| @ServiceDependency |
| void bind(ServiceObject<MyService> serviceObjects) { |
| MyService service; |
| try { |
| service = serviceObjects.getService(); |
| } finally { |
| serviceObjects.ungetService(service); |
| } |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Internally, DM will use the PrototypeServiceFactory.getService(Bundle clientBundle, ServiceRegistration reg) method in order to instantiate the MyServiceImpl component. |
| So, the MyServiceImpl component can optionally use the @Inject annotation in order to get injected with the clientBundle and/or the service registration, like this:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.apache.felix.dm.annotation.api.Component; |
| import org.apache.felix.dm.annotation.api.ServiceScope; |
| |
| @Component(scope=ServiceScope.PROTOTYPE) |
| public static class MyServiceImpl implements MyService { |
| |
| @Inject |
| Bundle m_clientBundle; |
| |
| @Inject |
| ServiceRegisration m_registration; |
| |
| @Start |
| void start() { |
| // called on each MyService instance. |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The Bundle and ServiceRegistration can also be injected in the component Constructor:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.apache.felix.dm.annotation.api.Component; |
| import org.apache.felix.dm.annotation.api.ServiceScope; |
| |
| @Component(scope=ServiceScope.PROTOTYPE) |
| public static class MyServiceImpl implements MyService { |
| |
| public MyServiceImpl(Bundle clientBundle, ServiceRegistration registration) { |
| ... |
| } |
| |
| @Start |
| void start() { |
| // called on each MyService instance. |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Notice that when defining a scoped service with annotations, it is not possible to return service properties dynamically from the start method (annotated with @Start).</strong></p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_service_property_types"><a class="anchor" href="#_service_property_types"></a>Service property types</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>So far, you could define component service properties using DM @Property annotation, and component configuration could be declared as user defined interfaces. |
| You can now declare user-defined annotations which can be used to specify both service properties and component configuration. |
| It means that instead of declaring service properties using @Property annotation, you can now use your own annotations (which must be annotated with the new @PropertyType annotation, or possibly using the standard @ComponentPropertyType annotation).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Usage example:</p> |
| </div> |
| <div class="paragraph"> |
| <p>Let’s assume your write an OSGi r7 jaxrs servlet context which needs the two following service properties:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>osgi.http.whiteboard.context.name</code></p> |
| </li> |
| <li> |
| <p><code>osgi.http.whiteboard.context.path</code></p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Then you can first define your own annotation (but you could also reuse the default annotations provided by the new upcomming jaxrs whiteboard r7 api, from the org.osgi.service.jaxrs.whiteboard.propertytypes package):</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.apache.felix.dependencymanager.annotation.PropertyType; |
| |
| @PropertyType |
| @interface ServletContext { |
| String osgi_http_whiteboard_context_name() default AppServletContext.NAME; |
| String osgi_http_whiteboard_context_path(); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In the above, the underscore is mapped to ".", and you can apply the above annotation on top of your component like this:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| @ServletContext(osgi_http_whiteboard_context_path="/game") |
| public class AppServletContext extends ServletContextHelper { |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>You can also use configuration admin service in order to override the default s ervice properties:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| @ServletContext(osgi_http_whiteboard_context_path="/game") |
| public class AppServletContext extends ServletContextHelper { |
| @ConfigurationDependency(propagate=true, pid="my.pid") |
| void updated(ServletContext cnf) { |
| // if some properties are not present in the configuration, then the ones used in the |
| // annotation will be used. |
| // The configuration admin properties, if defined, will override the default configurations |
| // defined in the annotations |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>You can also define multiple property type annotations, and possibly single valued annotation, like it is the case with standard r7 DS. |
| In this case, you can use the standard R7 PREFIX_ constants in order to specify the property prefix, and the property name will be derived from the single valued annotation (using camel case convention):</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @PropertyType |
| @interface ContextName { // will map to "osgi.http.whiteboard.context.name" property name |
| String PREFIX_="osgi.http.whiteboard."; |
| String value(); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>@PropertyType |
| @interface ContextPath { // will map to "osgi.http.whiteboard.context.path" property name |
| String PREFIX_="osgi.http.whiteboard."; |
| String value(); |
| }</pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>@Component |
| @ContextName(AppServletContext.NAME) |
| @ContextPath("/game") |
| public class AppServletContext extends ServletContextHelper { |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Same example as above, but also using configuration admin service in order to override default service properties: Here, as in OSGi r7 declarative service, you can define a callback method which accepts as arguments all (or some of) the defined property types:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| @ContextName(AppServletContext.NAME) |
| @ContextPath("/game") |
| public class AppServletContext extends ServletContextHelper { |
| @ConfigurationDependency(propagate=true, pid="my.pid") |
| void updated(ContextName ctxName, ContextPath ctxPath) { |
| // if some properties are not present in the configuration, then the ones used in the annotation will be used. |
| // The configuration admin properties, if defined, will override the default configurations defined in the annotations |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The following is the same example as above, but this time the configuration callback can also define a Dictionary in the first argument (in case you want to also get the raw configuration dictionary:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component |
| @ContextName(AppServletContext.NAME) |
| @ContextPath("/game") |
| public class AppServletContext extends ServletContextHelper { |
| @ConfigurationDependency(propagate=true, pid="my.pid") |
| void updated(Dictionary<String, Object> rawConfig, ContextName ctxName) { |
| // if some properties are not present in the configuration, then the ones used in the annotation will be used. |
| // The configuration admin properties, if defined, will override the default configurations defined in the annotations |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Empty Marker annotations can also be used: when you define an empty annotation, it will be mapped to a java.lang.Boolean property type with Boolean.TRUE value. |
| For example, the following component will be registered with "osgi.jaxrs.resource" service property with Boolean.TRUE value:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @PropertyType |
| @interface JaxrsResource { // will map to "osgi.jaxrs.resource" property name |
| String PREFIX_="osgi."; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>@Component(provides = MyResource.class) |
| @JaxrsResource |
| public class MyResource { |
| @Path(“foo”) |
| @GET |
| public void getFoo() { |
| ... |
| } }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>User defined property types can also be applied on factory components, for example, in the following, the service properties are declared using the user-defined annotations (they will be overriden from the factory configuratin, if present in the config):</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java"> @Component(factoryPid="my.factory.pid", propagate=true) |
| @ContextName(AppServletContext.NAME) |
| ContextPath("/game") |
| class Hello implements HelloService { |
| void updated(ContextName ctxName, ContextPath ctxPath) { |
| // Configure or reconfigure our component. the default service |
| // properties will be overriden by the factory configuration (if the |
| // service properties are defined in the config) |
| } |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </article> |
| <aside class="toc sidebar" data-title="Contents" data-levels="2"> |
| <div class="toc-menu"></div> |
| </aside> |
| </div> |
| </main> |
| </div> |
| <footer class="footer"> |
| <p>Content licensed under AL2. UI licensed under MPL-2.0 with extensions licensed under AL2</p> |
| </footer> |
| <script src="../../../../_/js/site.js"></script> |
| <script async src="../../../../_/js/vendor/highlight.js"></script> |
| </body> |
| </html> |