Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3
Include Page
apache-felix-ipojo-header
apache-felix-ipojo-header

HTML

<div class="content">

...

Providing OSGi services

This

...

pages explains how to publish OSGi services with iPOJO. It

...

presents:

  • 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
classtoc
Table of Contents
maxLevel4
minLevel2
Image Removed

A simple example

The following code snippet shows a simple class implementing the FooService interface:

Code Block

@Component
@Provides
public class FooProviderType1 implements FooService {
            private String m_foo = "foo";

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

}

To provide a service, the implementation class

...

MUST implement the service interface.

...

In XML, to

...

provide the service, the component type needs to

...

contain the <provides/> element:

Code Block
xml
xml

<component className="...FooProviderType1">
        <provides/>
</component>

Image Modified

The <provides/>

...

or @Provides suffice to declare that each instance of this type will provide the FooService

...

(for more info about instances see How-to use iPOJO factories). The provided specifications 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.

Service Publication

The provided service handler manages

...

service publication

...

. For each declared

...

<provides/>, the handler

...

registers a service. Since the @Provides annotation can be used only once, only one service is registered that provides 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

...

explicitly declare which service specifications are published with the

...

specifications attribute, such as:

Code Block

@Component
@Provides(specifications={FooService.class})
public class FooProviderType1 implements FooService, Runnable {
    // ...
}
Info
titleChange in the 1.2.0

In the 1.0.0 version and before, the specifications attribute was named interface.

If the implementation class implements several interfaces, all these interfaces are published by default in the same service publication. You can use the interface attribute to set exactly published interfaces. If you want to publish several interfaces, you can use the following syntax:

Image Removed

Note: if you use the interface attribute, the handler check that all declared interface

are really implemented by the implementation class. If an interface is not implemented, the handler

throws an error.

logs a warning.

Info
titleSpecification checking

If you use the specifications attribute, the handler checks that all declared interfaces

xmlxml

<component className="...FooProviderType1">
            <provides interface="...FooService "/>
</component>
Code Block
xmlxml

<component className="...FooProviderType1">
            <provides interface="{...FooService, ...BarService}"/>
</component>
Info
titleNo service

If

Note: if

the implementation class does not implement any interface, you cannot provide a service. In this case, the handler throws an error.

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 Block

@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";
	}
}
Remark that the m_foo field does not have any value. The following snippet shows a component publishing the FooServicewith two properties

Using XML, it gives:

Code Block
xml
xml

<component 
className
classname="...FooProviderType1">
            <provides>
                        <property name="foo" field="m_foo" value="Foo"
> <property name="intProps" type="int" value="5"
/>
            </provides>
</component>

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

...

Image Removed

...

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):

<instance component="...FooProviderType1" name="myFooServiceProvider"> <property name="foo" value="baz"/>
        
<property
m_foo 
name
=
"intProps"
 
value=
"
2"/> </instance>

Image Removed

Properties can be attached to a method too. When a property receive a new value, this method is called with the new value in parameter. For example, when the foo property receive a new value (at instance creation or when the instance is reconfigured), the fooMethod is called. The fooMethod must have only one argument of the Foo type (String in the example).

bar";
	}
}
Code Block

@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);

Image Removed

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 Block
xmlxml

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 Block
xml
xml

<component 
className
classname="...FooProviderType1">
            <provides>
                        <property name="foo" 
method
field="
fooMethod
m_foo" value="Foo"/>
                        <property name="
intProps
static" type="
int
java.lang.String" value="
5"
this is a static property"/>
            </provides>
</component>
Code Block

public class FooProviderType1 implements FooService {
	private String m_foo;
	public void foo() {
		System.out.println("foo  " + m_foo);
	}	        void fooMethod(String newFoo) {
		m_foo = newFoo;
	}

A property can declare both a field and a method. In this case, the field receive the value and then the method is called. 

Properties may have a default value (set using the value attribute). This value will be used as initial value. The value can be given in the instance configuration. The default value will be overridden in this case:

<component className
="...FooProviderType1">
   
<provides>
<property name="foo" 
method
value="
fooMethod" field="m_foo" value="Foo">
My New Foo Value"/>
   <property name="
intProps
static" 
type="int"
value="
5">
My Value 
</provides>
For Static"/>
</
component>
instance>
Code Block
xml
xml

<instance component
Code Block

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:

public class 
FooProviderType1
MyComponent implements 
FooService
MyService {

private
 
String
 
m_foo; public
 
void
 
foo() { System.out.println("foo " + m_foo); } void fooMethod(String newFoo) { System.out.println("Update foo : " + m_foo); }
@ServiceProperty(name="username", mandatory=true)
    private String m_username;

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

    //...
}
Code Block

@Component
@Provides
Code Block

For the previous components:

  • (name=myname, password=****) is a valid configuration
  • (password=****) is an invalid configuration that will be rejected by iPOJO

Advanced features

Service Serving & Object Creation

When a consumer requires the published service, the handler sends an object (

...

from 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 Block

@Component
@Provides(strategy="SERVICE")
public class MyComponent implements MyService {
    //...
}

or:

Code Block
xml
xml

<provides 
factory
strategy="SERVICE"/>

Other strategies are available:

  • strategy="instance" allows creating one service object per iPOJO instance using the service
  • 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 Block
    
    @Component
    @Provides(strategy="org.acme.foo.MyCreationStrategy")
    public class MyComponent implements MyService {
        //...
    }
    

Several Service Providing

...

Providing Several Services (XML only)

In XML, you can declare several provides inside the same component. All

...

those provided

...

services will be

...

managed individually, so will be published

...

using several publication (i.e. org.osgi.frameowrk.ServiceRegistration). This case is useful when service properties are different for the different services.

Code Block
xml
xml

<component 
className
classname="...FooProviderType1">
                <provides 
interface
specifications="...Foo"/>
                <provides 
interface
specifications="...Bar">
                               <property name="foo" value="baz"/>
                </provides>
</component>

Image Modified

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

...

services. If some properties are mapped on methods, these methods are invoked with the new value in argument.

Image Modified

If an instance configuration contains properties starting with service., they are automatically propagated. In the following example, the service.pid is automatically propagated.

Code Block
xml
xml

<instance component="...">
    <property name="service.pid" value="my.pid"/>
</instance>

Instance reconfiguration

...

iPOJO supports instance reconfiguration. When an instance is dynamically reconfigured

...

and if the instance published service properties, the values are updated with the new configuration. For example, let's take the following component.

Code Block
java
java

@Component
@Instantiate
@Provides
public class MyComponent implements MyService {

    @ServiceProperty(name="prop", value="initial")
    private String myProp;

    //...
    
}

The previous code also declares an instance (created without any configuration). This instance registers MyService with the service property prop=initial. If this instance is reconfigured using a configuration like: {prop="my value"}, the published properties will be updated with the new value, so prop=my value.

Publishing an abstract or concrete class as a Service

It is also possible to expose an abstract or concrete class as a service. To to this, just specify the published class in the specifications attribute:

Code Block

@Component
@Provides(specifications=MyComponent.class)
public class MyComponent {
    // ...
}

or in XML:

Code Block
xml
xml

<component classname="...FooProviderType1">
                <provides specifications="...AbstractFoo"/>
</component>
<component classname="...FooBarProviderType1">
                <provides specifications="[...AbstractFoo, ...Bar]"/>
</component>

As illustrated with the example using annotation, the component can also publish itself as a service. However, such practice is not recommended.

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 Block
java
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;
    }

}

Using XML, the previous component description is:

Code Block
xml
xml

  <component classname="org.apache.felix.ipojo.test.scenarios.component.controller.ControllerCheckService"
    name="PS-Controller-1-default">
    <provides>
      <controller field="controller"/>
    </provides>
  </component>

The controller may have a value attribute setting the initial value. Setting this value to false disables the initial service registration:

Code Block

@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;
    }

}

If several interfaces are exposed, the controller may have a specification attribute indicating the impacted service:

Code Block

@Component
@Provides
public class ControllerCheckService implements FooService, CheckService {
    
    @ServiceController(value=false, specification=FooService.class)
    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;
    }

}

In XML, each provides can have one controller element.

Code Block
xml
xml

  <component classname="org.apache.felix.ipojo.test.scenarios.component.controller.ControllerCheckService"
    name="PS-Controller-1-false">
    <provides>
      <controller field="controller" value="false"/>
    </provides>
  </component>

Being notified of the service registration and unregistration

You can also be notified when the service is published and unpublished. This is done by specifying the two callbacks in the <provides/> element:

Code Block
xml
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>

Or by using the @PostRegistration and @PostUnregistration annotations:

Code Block
java
java

	@PostRegistration
	public void registered(ServiceReference ref) {
		System.out.println("Registered");
	}

        @PostUnregistration
	public void unregistered(ServiceReference ref) {
		System.out.println("Unregistered");
	}
  • 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 Page
apache-felix-ipojo-footer
apache-felix-ipojo-footer

...

width20%

...