Declaring your services to OSGi Declarative Services

You can use a separate XML file to declare each service within a bundle.

About this task

The Declarative Services (DS) support operates on declared components, each of which is defined by an XML file in the bundle. When a bundle containing component declarations is added to the framework, DS reads each component declaration and registers provided services in the service registry. DS then manages the lifecycle of the component: controlling its lifecycle based on a combination of declared attributes and satisfied dependencies.

The XML description of components allows DS to resolve service dependencies without requiring the component to be instantiated, or its implementation classes to be loaded. This facilitates late and lazy resource loading, which helps improve server startup and reduce runtime memory footprint.

The XML files that describe the components are listed in the MANIFEST.MF file of the bundle using the Service-Component header, and by convention are located in the /OSGI-INF directory of the bundle.

There are a number of tools that can be used to generate the required XML; the following examples show the XML itself.

This topic describes a simple OSGi bundle using XML to declare its components to DS.

Procedure

  1. Identify your component through its implementation class name.
    <component>
      <implementation class="com.example.bundle.HelloComponent"/>
    </component>
  2. Declare the service by referencing the name of the interface that it provides. This is the name that will be published to the service registry by DS when the bundle is started.
    <component>
      <implementation class="com.example.bundle.HelloComponent"/>
      <service>
         <provide interface="com.example.HelloService"/>
      </service>
    </component>
  3. Name the component. The component name also acts as the service persisted identity, or PID, which is used to associate configuration properties with the service. Configuration properties with a matching PID will be injected into the component on activation, and whenever the properties are updated.
    <component name="HelloService">
      <implementation class="com.example.bundle.HelloComponent"/>
      <service>
        <provide interface="com.example.HelloService"/>
      </service>
    </component>
    Note: In Liberty, a user can add the following element to the server.xml configuration file, and the properties will be injected into the HelloComponent class.
    <HelloService firstKey="firstValue" secondKey="secondValue" />
  4. Package the XML file into the bundle.
    For example, the XML file is at the location OSGI-INF/HelloService.xml, and you add a header to the bundle manifest MANIFEST.MF file so that DS can locate the file:
    Service-Component: OSGI-INF/HelloService.xml
    If multiple components are packaged in the same bundle, the corresponding XML files must be entered as a comma-separated list. For example:
    Service-Component: OSGI-INF/HelloService.xml, OSGI-INF/GoodbyeService
  5. The Java™ implementation of the HelloService component is as follows:
    package com.example.bundle;
    
    import com.example;
    import org.osgi.service.component.ComponentContext;
    
    /*
     * This class must be public and have a public default constructor for it to be 
     * usable by DS. This class is not required to be exported from the bundle.
     */
    public class HelloComponent implements HelloService {
    	/**
    	 * Optional: DS method to activate this component. If this method exists, it
    	 * will be invoked when the component is activated. Best practice: this
    	 * should be a protected method, not public or private
    	 * 
    	 * @param properties
    	 *            : Map containing service & config properties
    	 *            populated/provided by config admin
    	 */
    	protected void activate(ComponentContext cContext,
    			Map<String, Object> properties) {
    		modified(properties);
    	}
    
    	/**
    	 * Optional: DS method to deactivate this component. If this method exists,
    	 * it will be invoked when the component is deactivated. Best practice: this
    	 * should be a protected method, not public or private
    	 * 
    	 * @param reason
    	 *            int representation of reason the component is stopping
    	 */
    	protected void deactivate(ComponentContext cContext, int reason) {
    	}
    
    	/**
    	 * Optional: DS method to modify the configuration properties. This may be
    	 * called by multiple threads: configuration admin updates may be processed
    	 * asynchronously. This is called by the activate method, and otherwise when
    	 * the configuration properties are modified while the component is
    	 * activated.
    	 * 
    	 * @param properties
    	 */
    	public synchronized void modified(Map<String, Object> properties) {
    		// process configuration properties here
    	}
    
    	/**
    	 * Service method defined by com.example.HelloService interface
    	 */
    	public void sayHello() {
    		System.out.println("Hello");
    	}
    }