--- layout: developersguide title: OSGi Declarative Services --- # Declarative Services In the [OSGi Overview article](osgi.html) we have mentioned that a bundle can register, unregister, get and unget services from a central point - the Service Registry. In order to simplify the usage of services the [OSGi Alliance](https://www.osgi.org/about-us/) has developed a model of managing services dynamically called _Declarative Services_. [[toc]] ## Model & Terms In order to understand this model, we will have to first explain a few terms, used below: - **Declarative Services Container** (we will use the shorthand **DS**) - a module that is managing the [lifecycle](#component-lifecycle) of a *service component- dynamically. It activates and deactivates different components, basing its decisions on the information contained in the _component description_; - **Service Component** (or also **component**) - an object whose lifecycle is managed, usually by a component framework such as Declarative Services (DS). A component may publish itself as an OSGi service or consume OSGi services. A component can refer to a number of services; - **Component Description** - The declaration of a component. It is contained within an XML document in a bundle. ## DS Container In order to use the Declarative Services functionality you have to start a bundle with an implementation of the DS container. In [Equinox](https://www.eclipse.org/equinox/) (the reference implementation of OSGi that is used in openHAB) this bundle is called `org.eclipse.equinox.ds`. When a bundle that contains a component is added to the framework, DS reads its component description (the XML file that is generated by the Java annotations). If the conditions, described in this file are fulfilled (you will understand more about this in the next chapters), the DS activates the component (more on the that in the [component lifecycle](#component-lifecycle) chapter). More importantly, after some of the requirements are not met anymore, the DS container deactivates the component. This ensures that service components are managed dynamically. ## Components It is important to understand the difference between a _component_* and a _service_. A component is a normal Java class, that can reference services and provide services. What makes a component specific is that it is declared in a XML file and is managed completely by DS. That means that DS instantiates the component, calls method on this component and manages the lifecycle of a component. A component requires the following artifacts in a bundle: - **XML description** of the component; - **Service-Component manifest header**, which contains the location of the XML description; - An **implementation class** that is specified in the component description. Because we do not write the XML files or the manifest ourselves, we will concentrate on the Java annotations in the examples below. A component may use different strategies to access the bound services: _Constructor injection_, _Field injection_ or _Method injection_ (see [OSGi Compendium Release 8, Chapter 112.3: References to Services][OSGi-cmpn]). ### Example - Reference a Service In this example our component needs the openHAB `ItemRegistry` (`org.openhab.core.items.ItemRegistry`). We will use DS to inject an implementation of this service in our class. ### Constructor Injection Bound services and activation objects can be parameters to the constructor. ```java @Component(service = MyService.class, immediate = true) @NonNullByDefault public class MyService { protected final ItemRegistry itemRegistry; @Activate public MyService(final @Reference ItemRegistry itemRegistry) { this.itemRegistry = itemRegistry; } @Activate protected void activate(BundleContext context) { System.out.println("Bundle is activated!"); } @Deactivate protected void deactivate(BundleContext context) { System.out.println("Bundle is deactivated!"); } } ``` ### Field Injection ```java @Component(service = MyService.class, immediate = true) @NonNullByDefault public class MyService { @Reference // you can add some configuration parameters to this annotation protected @NonNullByDefault({}) ItemRegistry itemRegistry; @Activate protected void activate(BundleContext context) { System.out.println("Bundle is activated!"); } @Deactivate protected void deactivate(BundleContext context) { System.out.println("Bundle is deactivated!"); } } ``` Let's take a look at some configuration parameters, that we can apply: - **immediate**: - *true- - the component is activated as soon as all dependencies are satisfied. Adding this option will ensure that the component will be activated right after the bundle is activated and the component is satisfied; - *false- - the component has lazy activation. The activation of the component is delayed(lazy activation) until the service is requested. This is the default value; - **cardinality**: - *1..1- - single service reference, that is mandatory. If your referenced service gets inactive, DS deactivates your service component as well (default value); - *0..1- - single service reference(not mandatory). You have to be aware that you might not have your reference resolved, your component can live with the absence; - *0..n- - multiple service references (not mandatory). The referenced service can be implemented multiple times, so they are added to a list in your component implementation; - *1..n- = like the above, but mandatory; - **policy**: - *static- - the default policy. Component configuration are deactivated every time, when a reference with static policy becomes unavailable. This causes the activating and deactivating of the component. It can be very expensive, when we have multiple bound services, or when a service is often unregistered and re-registered; - *dynamic- - with this policy the component is not deactivated, when a referenced service is changed. It is slightly more complex, as the component implementation has to properly handle changes in the set of bound services. ### Method Injection If you want to react when a service got resolved, you may use annotated methods instead of fields like in the example below. The annotated `activate()` and `deactivate()` methods are called from DS, when the component configuration is activated and deactivated (more about [activation](osgids.html#activation)): ```java @Component(service = MyService.class, immediate = true) @NonNullByDefault public class MyService { protected @NonNullByDefault({}) ItemRegistry itemRegistry; @Activate protected void activate(BundleContext context) { System.out.println("Bundle is activated!"); } @Deactivate protected void deactivate(BundleContext context) { System.out.println("Bundle is deactivated!"); } @Reference public void setItemRegistry(ItemRegistry itemRegistry) { // We store a reference to the ItemRegistry ! this.itemRegistry = itemRegistry; System.out.println("Log service is available!"); } public void unsetItemRegistry(ItemRegistry itemRegistry) { System.out.println("Log service is not available anymore!"); // We have to clean up after ourselves, when the reference is not needed anymore ! this.itemRegistry = null; } } ``` ### Example - Provide a Service Very often you will have to register a service, that implements an interface defined in the framework (e.g [_EventHandler_](https://osgi.org/javadoc/osgi.cmpn/8.0.0/org/osgi/service/event/EventHandler.html)) or interface, that you have defined. An interface allows you to change the implementation easily or register multiple implementations in the Service Registry. We will use DS to register an implementation of the EventHandler service in the OSGi Service Registry. ```java @Component(service = {MyService.class, EventHandler.class}, immediate = true, property = { "event.topics=some/topic" }) @NonNullByDefault public class MyService implements EventHandler { @Activate protected void activate(BundleContext context) { System.out.println("Bundle is activated!"); } @Deactivate protected void deactivate(BundleContext context) { System.out.println("Bundle is deactivated!"); } @Override public void handleEvent(Event event) { String topic = event.getTopic(); System.out.println("Received event with topic: " + topic); } } ``` We are providing some service specific properties as well (the property with name `event.topics`). In this case we tell tell Event Admin Service in which topics we are interested. ## Component types A component lifecycle depends of the type of the component. Three type of components are defined: - **immediate** - with ```immediate``` attribute set to ```true``` - see the [example component description](#example---provide-a-service); - **delayed** - with ```immediate``` attribute set to ```false```; - **factory** - we will not discuss the lifecycle of this type in this article. You can find more information in the [OSGi Compendium Release 8, Chapter 112.2: Components][OSGi-cmpn]. ## Component Lifecycle A component goes through several states in his lifecycle: - **UNSATISFIED** - initial state of the Service Component, after the bundle is started; - **REGISTERED** - temporary state. Only *delayed- components go through this state; - **ACTIVE** - the component is active and component instance is created. Fig.1 Immediate component lifecycle Fig.2 Delayed component lifecycle ### States Like described above, the component lifecycle depends on the lifecycle of the bundle, that includes the component. Component must be enabled before it can be used. A component is **enabled**, when the component's bundle is **started** and **disabled**, when the bundle is **stopped**. After the Component is enabled, it is moved to the UNSATISFIED state. The next step is to satisfy the component configuration. The component **configuration is satisfied** when: - component is **enabled**; - all the **component references are satisfied**. A reference is satisfied when the reference specifies optional cardinality or there is at least one target service for the reference. If the component has lazy initialization (the component is _delayed_), it is moved to the REGISTERED state and it is waiting to be activated, when the service is requested (see Fig.2). Otherwise (the component is _immediate_) as soon as its dependencies are satisfied, the component is activated (see Fig.1). ### Activation Activation consists of following steps: - load the implementation class; - create component instance (constructor is run); - bind `@Reference`d services - The method that is annotated with `@Activate` is called, if present After the activation, the component is in ACTIVE state. From this state the component can go back to the _REGISTERED- state (or to the_UNSATISFIED- state), if the component configuration becomes unsatisfied. ### Deactivation Deactivation consists of the following actions: - The method that is annotated with `@Deactivate` is called, if present - All `@Reference`d services are unbound - Release all references to the component instance. ## Troubleshooting Find a few tips down below if something has gone wrong. Mind that most of the tips below are specific to Equinox as the OSGi Runtime. You might review again the [Equinox commands](equinox.html#iv-commands) before you continue. - Start the runtime and check the log. Do you see any Errors like "MESSAGE [SCR] Error while trying to bind reference"? Read the error message and proceed accordingly. - Make sure that the bundle that is providing the service is in "ACTIVE" state. If that is not the case, start it manually with the "start id" command, where id is the id of the bundle; - [Equinox only] While the runtime is running type the "services" command and search if your service is registered. In case it is not registered, most probably you have missed some of the steps above :); - [Equinox only] While the runtime is running type "ls -c id", where id is the id of the bundle that is providing the service. This will give detailed information about the services that are registered by this bundle, read the information if the component is satisfied carefully; - Is your service in use? In case it is not and you are not seeing it registered, the component might have lazy activation policy (this is the default policy). Add "immediate=true" in your Component Definition if you like to change the activation policy. ## Further Reading - [OSGi Compendium Release 8][OSGi-cmpn] - [Lars Vogel - Declarative services](http://www.vogella.com/tutorials/OSGiServices/article.html#declarativeservices) - [Getting Started with OSGi: Declarative Services](https://www.eclipsezone.com/eclipse/forums/t97690.rhtml) - [OSGi-cmpn]: https://osgi.org/download/r8/osgi.cmpn-8.0.0.pdf