Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Wiki Markup
{include:apache-felix-ipojo-header}
{html}
<div class="content">
{html}
h1. Providing OSGi services

_This handlerpages allowsexplains publishinghow andto providingpublish OSGi services with iPOJO. It managespresents:_
* _service publication_
* _service properties publication and management_
* _service object creation and creation strategies_
* _service un-registration_
* _configuration property propagation_
* _the management of the exposition from the implementation class_

{div:class=toc}
{toc:maxLevel=4|minLevel=2}
{div}

h2. A simple example

The following code snippet shows a simple class implementing the {{FooService}} interface:
{code}
@Component
@Provides
public class FooProviderType1 implements FooService {
            private String m_foo = "foo";

            public void foo() {
                        System.out.println("foo  " + m_foo);
            }

}
{code}
To provide a service, the implementation class *NEEDSMUST* to implement the service interface. By the way, it guaranties that each methods of the service interface are implemented.

To 

In XML, to provide the service, the component type needs to declarecontain the providing:
{code:{{<provides/>}} element:
{code:xml}
<component className="...FooProviderType1">
        <provides/>
</component>
{code}
!ps-foo.png!

The <provides/> elementor @Provides suffice to declare that each instance of this type will provide the FooService. Indeed, theThe provided specificationspecifications can be discovered by analyzing the implementation class. By default, all implemented interface are published in the same service registration. iPOJO looks down the entire inheritance tree.

h2. Service Publication

The provided service handler manages the service publication and providing. For each declared {{provides<provides/>}}, the handler register a service. As the @Provides annotation can be used only once, only on service is registered (but publishing all interfaces). The service is published as long as the instance is valid. If the instance becomes invalid, the service is removed from the service registry.

By default, it publishes all interfaces implemented by the implementation class of the component class. It collects all super-interfaces (interfaces implemented by implemented interfaces and by the super class). However it is possible to set exposed specifications with the {{specifications}} attribute to avoid to expose all collected interfaces.:

{infocode}
@Component
@Provides(specifications={FooService.class})
public class FooProviderType1 implements FooService, Runnable {
    // ...
}
{code}

{info:title=Change in the 1.2.0}
In the 1.0.0 version and before, the {{specifications}} attribute was named {{interface}}.
{info}

The following xml snippet is equivalent to the previous example:
{code:xml}
<component classname="...FooProviderType1">
            <provides specifications="...FooService "/>
</component>
{code}
If the implementation class implements several interfaces, all these interfaces are published by default in the same service publication. You can use the {{specifications}} attribute to set published service interfaces. If you want to publish several interfaces, you can use the following syntax:
{code:xml}
<component classname="...FooProviderType1">
            <provides specifications="{...FooService, ...BarService}"/>
</component>
{code}
!ps-foobar.png!

{info:title=Specification checking}
If you use the {{specifications}} attribute, the handler checks that all declared interfaces are really implemented by the implementation class. If an interface is not implemented, the handler log a warning.
{info}

{info:title=No service}
If the implementation class does not implement any interface, you cannot provide a service. In this case, the handler throws an error.
{info}

h2. Service Properties

The handler can manage service properties. Service properties are attached to published service and allow consumer filtering providers. A property can be attached to a field (contained in the component implementation class), and so by handle dynamically.

Let's take a new example very closed of the last one:
{code}
public class FooProviderType1 implements FooService {
	private String m_foo;
	public void foo() {
		System.out.println("foo  " + m_foo);
     {info:title=Specification checking}
If you use the {{specifications}} attribute, the handler checks that all declared interfaces are really implemented by the implementation class. If an interface is not implemented, the handler logs a warning.
{info}

{info:title=No service}
If the implementation class does not implement any interface, you cannot provide a service. In this case, the handler throws an error.
{info}

h2. Service Properties

You can also attach properties to a service registration. Service properties are attached to published service and allow consumer filtering/selecting providers. A property can be attached to a field (contained in the component implementation class), and so can be handle dynamically.

Let's take a new example very closed of the last one:
{code}
@Component
@Provides
public class FooProviderType1 implements FooService {

    @ServiceProperty(name="foo", value="Foo")
	private String m_foo;

	public void foo() {
		System.out.println("foo  " + m_foo);
        m_foo = "bar";
	}
}
{code}
Using XML, it gives:
{code:xml}
<component classname="...FooProviderType1">
            <provides>
                        <property name="foo" field="m_foo" value="Foo"/>
            </provides>
</component>
{code}

The declared property is attached to the {{m_foo}} field. This property is published with the name {{foo}}. This property has a default value "Foo". This value will be injected into the {{m_foo}} field, when this field asks for a value. A property with a field attribute does not need to declare a type (the type can be discovered by analyzing the implementation class).

The implementation class set a new value to the {{m_foo}} field in the code. When this action occurs, the service publication is updated. If a published property value becomes {{null}}, the property is unpublished since it has a new value.


You can also publish 'static' properties (not attached to a field):
{code}
{code}
@Component
@Provides(properties= {
			@StaticServiceProperty(name="static", type="java.lang.String", value="this is a static property")
	})
public class FooProviderType1 implements FooService {

    @ServiceProperty(name="foo", value="Foo")
	private String m_foo;

	public void foo() {
		System.out.println("foo  " + m_foo);
        m_foo = "bar";
	}
}
{code}

The second property ({{Static}}) is published as a static property. This property is not attached to a field, so, we need to declare the property type. All primitive types or objects can be used has property type (for object, the qualified name of the class is used as java.lang.String).

In XML, this can also be done:
{code:xml}
<component classname="...FooProviderType1">
            <provides>
                        <property name="foo" field="m_foo" value="Foo"/>
                        <property name="static" type="java.lang.String" value="this is a static property"/>
           m_foo = "bar";
	}
} </provides>
</component>
{code}
Remark that
Properties may have a default value (set using the {{m_foovalue}} field does not have any value attribute). This value will be used as initial value. The value can be given in the instance configuration. The followingdefault snippetvalue showswill abe componentoverridden publishingin the {{FooService}} with two propertiesthis case:
{code:xml}
<component<instance classnamecomponent="...FooProviderType1">
   <property name="foo" value="My New Foo Value"/>
   <property name="static" value="My Value   <provides>
                        <property name="foo" field="m_foo" value="Foo"/>
                        <property name="intProps" type="int" value="5"/>
            </provides>
</component>
{code}
The first declared property will be attached to the {{m_foo}} field. This property is published with the name {{foo}}. This property has a default value "Foo". This value will be injected in the {{m_foo}} field, when this field asks for a value. A property with a field attribute does not need to declare a type (the type can be discovered by analyzing the implementation class).

The second property is published with the name {{intProps}}. This property is not attached to a field, so, we need to declare the property type. All primitive types or objects can be used has property type (for object, the qualified name of the class is used as java.lang.String).

!ps-foo2.png!

The implementation class set a new value to the {{m_foo}} field in the code. When this action occurs, the handler will modify the service publication to update the {{foo}} property published value. If a published property value becomes {{null}}, the property is unpublished since it has a new value.

!ps-foo3.png!

If property does not have default value, the instance configuration needs to set a value for each unvalued property. Moreover, the instance can override the property value. The following xml snippet shows the declaration of an instance overriding the property values:
{code:xml}
<instance component="...FooProviderType1" name="myFooServiceProvider">
            <property name="foo" value="baz"/>
            <property name="intProps" value="2"/>
</instance>
{code}
!ps-foo4.png!

h2. Advanced features

h3. Service Serving & Object Creation

When a consumer requires the published service, the handler sends an object (instance) of the implementation class. By default, it is always the same instance. If no instance already exists, an instance is created.

However, the handler supports the OSGi _Service Factory_. In this case, for each requester bundle, the handler sends a new object. To activate this policy, add the {{strategy}} attribute in the {{provides}} element:
{code:xml}
<provides strategy="SERVICE"/>
{code}

Other strategies are available:
 * {{strategy="instance"}} allows creating one service object per asking iPOJO instance (despite they are in the same bundle)
 * it is possible to create your own creation strategy by extending the {{org.apache.felix.ipojo.handlers.providedservice.CreationStrategy}} class and by indicating the qualified class name in the {{strategy}} attribute.

h3. Several Service Providing

You can declare several {{provides}} inside the same component. All this provided service will be manage by the same handler but separately. Several services will be published (with different service registrations). This case is useful when service properties are different for the different services.
{code:xml}
<component classname="...FooProviderType1">
                <provides specifications="...Foo"/>
                <provides specifications="...Bar">
                               <property name="foo" value="baz"/>
                </provides>
</component>
{code}
!ps-foobar2.png!

h3. Service Property Propagation

The configuration handler has the possibility to propagate received properties to service publication. So, when the propagation is activated (on the {{properties}} elelmenet or on the {{@Component}} annotation), all properties received by the configuration handler will be propagated to all published service. If some properties are mapped on methods, these methods are invoked with the new value in argument.

!ps-propagation.png!

If an instance configuration contains properties starting with {{service.}}, they are automatically propagated. In the following example, the {{service.pid}} is automatically propagated.
{code:xml}
<instance component="...">
    <property name="service.pid" value="my.pid"/>
</instance>
{code}

h3. Instance reconfiguration

The handler supports instance reconfiguration. When an instance is dynamically reconfigured, if the new configuration updates property values, these value are take into account (both for field, and service publication). If some of these properties have methods, these methods are invoked with the new value in argument.

h3. Publishing abstract and concrete class as services

It is also possible to expose concrete and abstract class as services. To to this, just specify the published class in the {{specification}} attribute:
{code:xml}
<component classname="...FooProviderType1">
                <provides specifications="...AbstractFoo"/>
</component>
<component classname="...FooBarProviderType1">
                <provides specifications="[...AbstractFoo, ...Bar]"/>
</component>
{code}
The component can also publish itself as a service. However, such practice are not recommended.

h3. Controlling the service exposition from the implementation class

This handler also allows the injection of a 'service controller'. The injected boolean field allows the code to impact the service publication. Setting the field to {{false}} unregisters the service from the service registry. Setting it back to {{true}} re-publishes the service.

{code:java}
For Static"/>
</instance>
{code}

Properties can also be 'mandatory'. Mandatories properties must receive a value from the instance configuration. If the instance configuration _forgets_ a mandatory properties, the configuration is rejected. Mandatory attribute let you be sure to receive the complete set of initialization values:
{code}
@Component
@Provides
public class MyComponent implements MyService {

    @ServiceProperty(name="username", mandatory=true)
    private String m_username;

    @Property(name="password", mandatory=true)
    private String m_password;

    //...
}
{code}

For the previous components:
* {{(name=myname, password=****)}} is a valid configuration
* {{(password=****)}} is an invalid configuration that will be rejected by iPOJO


h2. Advanced features

h3. Service Serving & Object Creation

When a consumer requires the published service, the handler sends an object (form the component class) of the implementation class. By default, it is always the same POJO object. If no objects already exists, an instance is created.

However, the handler supports the OSGi _Service Factory_. In this case, for each requester bundle, the handler sends a new object. To activate this policy, add the {{strategy}} attribute in the {{provides}} element:

{code}
@Component
@Provides(strategy="SERVICE")
public class MyComponent implements MyService {
    //...
}
{code}
or:
{code:xml}
<provides strategy="SERVICE"/>
{code}

Other strategies are available:
 * {{strategy="instance"}} allows creating one service object per asking iPOJO instance (despite they are in the same bundle)
 * it is possible to create your own creation strategy by extending the {{org.apache.felix.ipojo.handlers.providedservice.CreationStrategy}} class and by indicating the qualified class name in the {{strategy}} attribute:
{code}
@Component
@Provides(strategy="org.acme.foo.MyCreationStrategy")
public class MyComponent implements MyService {
    //...
}


h3. Several Service Providing (XML only)
In XML, you can declare several {{provides}} inside the same component. All this provided service will be manage by the same handler but separately. Several services will be published (with different service registrations). This case is useful when service properties are different for the different services.
{code:xml}
<component classname="...FooProviderType1">
                <provides specifications="...Foo"/>
                <provides specifications="...Bar">
                               <property name="foo" value="baz"/>
                </provides>
</component>
{code}
!ps-foobar2.png!

h3. Service Property Propagation

The configuration handler has the possibility to propagate received properties to service publication. So, when the propagation is activated (on the {{properties}} element or on the {{@Component}} annotation), all properties received by the configuration handler will be propagated to all published service. If some properties are mapped on methods, these methods are invoked with the new value in argument.

!ps-propagation.png!

If an instance configuration contains properties starting with {{service.}}, they are automatically propagated. In the following example, the {{service.pid}} is automatically propagated.
{code:xml}
<instance component="...">
    <property name="service.pid" value="my.pid"/>
</instance>
{code}

h3. Instance reconfiguration

iPOJO supports instance reconfiguration. When an instance is dynamically reconfigured, if the new configuration updates property values, these value are taken into account (both for field, and service publication). If some of these properties have methods, these methods are invoked with the new value in argument.

h3. Publishing abstract and concrete class as services

It is also possible to expose concrete and abstract class as services. To to this, just specify the published class in the {{specifications}} attribute:
{code}
@Component
@Provides(specifications={...MyComponent})
public class MyComponent {
    // ...
}
{code}
or in XML:
{code:xml}
<component classname="...FooProviderType1">
                <provides specifications="...AbstractFoo"/>
</component>
<component classname="...FooBarProviderType1">
                <provides specifications="[...AbstractFoo, ...Bar]"/>
</component>
{code}
As illustrated with the example using annotation, the component can also publish itself as a service. However, such practice are not recommended.

h3. Controlling the service exposition from the implementation class

To control the exposition of the published service, you can use a {{service controller}}. A service controller is a boolean field of the component class. The injected boolean field allows the code to impact the service publication. Setting the field to {{false}} unregisters the service from the service registry. Setting it back to {{true}} re-publishes the service.

{code:java}
@Component
@Provides
public class ControllerCheckService implements FooService, CheckService {
    
    @ServiceController
    private boolean controller; // Service Controller

    public boolean foo() {
        return controller;
    }

    public boolean check() {
        System.out.println("Before : " + controller);
        controller = ! controller; // Change the publication
        System.out.println("After : " + controller);
        return controller;
    }

}
{code}

Using XML, the previous component description is:
{code:xml}
  <component classname="org.apache.felix.ipojo.test.scenarios.component.controller.ControllerCheckService"
    name="PS-Controller-1-default">
    <provides>
      <controller field="controller"/>
    </provides>
  </component>
{code}

The {{controller}} may have a value attribute setting the initial value. Setting this value to {{false}} disables the initial service registration:
{code}
@Component
@Provides
public class ControllerCheckService implements FooService, CheckService {
    
    @ServiceController(value=false)
    private boolean controller; // Service Controller

    public boolean foo() {
        return controller;
    }

    public boolean check() {
        System.out.println("Before : " + controller);
        controller = ! controller; // Change the publication
        System.out.println("After : " + controller);
        return controller;
    }

}
{code}

For the previous component, the metadata may be :
{code:xml}
  <component classname="org.apache.felix.ipojo.test.scenarios.component.controller.ControllerCheckService"
    name="PS-Controller-1-default">
    <provides>If several interfaces are exposed, the controller may have a {{specification}} attribute indicating the impacted service:
{code}
@Component
@Provides
public class ControllerCheckService implements FooService, CheckService {
    
    @ServiceController(value=false, specification=FooService.class)
    private boolean controller; // Service Controller

    public boolean foo() {
      <controller field="controller"/>  return controller;
    </provides>
  </component>
{code}

Each {{provides}} can have one {{controller}} element. The {{controller}} element must have a field attribute and may have a value attribute setting the initial value. Setting this value to false disables the initial service registration:
{code:xml}
  <component classname="org.apache.felix.ipojo.test.scenarios.component.controller.ControllerCheckService"
    name="PS-Controller-1-false">
    <provides>
public boolean check() {
        System.out.println("Before : " + controller);
        controller = ! controller; // Change the publication
        System.out.println("After : " + controller);
        <controllerreturn field="controller" value="false"/>controller;
    </provides>
  </component>}

}
{code}

If you're using annotations, the

In XML, each {{@ServiceControllerprovides}} annotation creates a service controller. However, you can have only one service {{controller}} per classelement. 
{code:javaxml}
@Component
@Provides
public class PSServiceController implements FooService, BarService {
  <component classname="org.apache.felix.ipojo.test.scenarios.component.controller.ControllerCheckService"
    name="PS-Controller-1-false">
    @ServiceController(value=false)
<provides>
     public boolean<controller controller;field="controller" value="false"/>
  
  </provides>
  <// ...component>
{code}

h3. Being notified of the service registration and unregistration
This handler also proposed a way to the implementation class toYou can also be notified when the servicesservice ais published and unpublished. This is done byuby specifying the two callbackcallbacks in the {{<provides/>}} element:
{code:xml}
<component
     classname="org.apache.felix.ipojo.test.scenarios.component.callbacks.CallbacksCheckService"
     name="PS-Callbacks-both-1">
    <provides
	specifications="org.apache.felix.ipojo.test.scenarios.ps.service.FooService"
	post-unregistration="unregistered" post-registration="registered"/>
    <provides
	specifications="org.apache.felix.ipojo.test.scenarios.ps.service.CheckService"
	post-unregistration="unregistered" post-registration="registered"/>
</component>
{code}

Each {{provides}} element can specify:
* a {{post-registration}} callback : called after the service publication
* a {{post-unregistration}} callback : called after the service unpublication

Those attributes specify the method name to call. Those method must have the following signature: {{public void name(ServiceReference ref)}}. So they receive the published / unpublished service reference. The callbacks are called in the same thread as the publication / unpublication itself. 

It is also possible to use annotations to specify such callbacks:
{code:java}
	@PostRegistration
	public void registered(ServiceReference ref) {
		System.out.println("Registered");
	}

        @PostUnregistration
	public void unregistered(ServiceReference ref) {
		System.out.println("Unregistered");
	}
{code}or by using the @PostRegistration and @PostUnregistration annotation:
{code:java}
	@PostRegistration
	public void registered(ServiceReference ref) {
		System.out.println("Registered");
	}

        @PostUnregistration
	public void unregistered(ServiceReference ref) {
		System.out.println("Unregistered");
	}
{code}

* The {{post-registration}} callback is called after the service publication
* The {{post-unregistration}} callback is called after the service unpublication

Those callback methods must have the following signature: {{public void name(ServiceReference ref)}}. So they receive the published / unpublished service reference. The callbacks are called in the *same thread* as the publication / unpublication itself. 

\\
\\
{include:apache-felix-ipojo-footer}