Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The dependency handler manages OSGi service dependencies/requirements. It allows a component to consume service without managing service discovery, tracking and binding. The handler manages all this interaction and injects required service in the component.

...

Requirement

What's a

...

requirement?

A dependency requirement represents a required service. Therefore, it manages the service lookup and the service binding. When an instance requires a service, the handler injects directly a service object inside a field, or invokes a method when a consistent service appears (or disappears). Dependencies Requirements have several attribute. A dependency can be:

...

Code Block
<component classname="...HelloConsumer">
<dependency ><requires>
    <callback type="bind" method="bindHello">
    <callback type="unbind" method="unbindHello">
</dependency>requires>
...
</component>

Note, that the bind the unbind method can be have different signature. By using this mechanism, you need to be sure to manage the dynamism correctly.

...

Code Block
<component classname="...HelloConsumer">
<dependency<requires  field="m_hello">
    <callback type="bind" method="bindHello">
    <callback type="unbind" method="unbindHello">
</dependency>requires>
...
</component>

Injection mechanisms & lazzy object creation

IPOJO creates objects only when required. When needed, iPOJO invokes the constructor of the implementation class. The implementation class can use field dependency requirement because values are already injected. However, method dependencies are called just after the constructor. If the service already presents, the invocation of the methods are delayed after the constructor invocation.

Some Examples

Simple

...

Requirement

By default, a dependency is mandatory, non-filtered and simple (non-aggregate). The two previous examples illustrate this kind of dependency. When services goes away and appears, the service substitution is hidden.

Field attached to simple dependency points always a consistent service object. For a simple dependency, the bind method is called once time at the beginning. If the service disappear the unbind method is called. The bind method is re-invoked as soon as another service provider is available. If another service provider is presents when the used one disappears, the instance is not invalidated.

Aggregate

...

Requirement

When a component requires several providers of the same service, it declares an aggregate dependency.

...

Code Block
<component classname="...HelloConsumer">
<dependency<requires field="m_hellos"/>
...
</component>

To declare an aggregate field for field dependencyrequirement, you only need to declare an array (instead of a simple type). IPOJO will create and inject the service object array.

...

Optional Dependency (non-aggregate)

An optional dependency requirement does not invalidate the instance if it is not resolved.

Optional

...

Requirement with field injection

Code Block
public class HelloConsumer {
         private Hello m_hello;
         public doSomething() {  System.out.println(m_hello.getMesage());  }
}

...

Code Block
<component classname="...HelloConsumer">
<dependency field="m_hello" optional="true"/>
...
</component>

To declare an optional dependencyrequirement, you need to add the 'optional' attribute. To avoid null pointer exception, iPOJO injects a Nullable object in the field when no service provider is available. The nullable object implements the service interface, but does nothing. For further information see the note about nullable object.

...

Code Block
<component classname="...HelloConsumer">
<dependency<requires optional="true">
    <callback type="bind" method="bindHello">
    <callback type="unbind" method="unbindHello">
</dependency>requires>
...
</component>

As for field dependencyrequirement, the dependency metadata needs to contain the optional attribute. IPOJO invokes the method only when a 'real' service is available, so you need to test if m_hello is null before to use it.

...

Code Block
<component classname="...HelloConsumer">
<dependency<requires field="m_hellos" optional="true"/>
...
</component>

To declare an optional & aggregate field dependency requirement you need to write the optional attrbiute in the dependency metadata and to point on a field array. If no service available, iPOJO injects an empty array.

Note: To avoid array modification during the loop, you need synchronized the block.

Aggregate & Optional

...

Requirement with method invocation

Code Block
public class HelloConsumer {
     private List m_hellos<Hello> = new ArrayList<Hello>();
     private void bindHello(Hello h) { m_hellos.add(h); }
     private void unbindHello(Hello h) { m_hellos.remove(h); }
     public doSomething() {
        synchronized(m_hellos) {
               for(int I = 0; I < m_hellos.size(); i++) { System.out.println(m_hellos.get(i).getMessage());}
        }
     }
}

For this component, metadata could be:

Code Block
<dependency<requires aggregate="true" optional="true">
     <callback type="bind" method="bindHello">
     <callback type="unbind" method="unbindHello">
</dependency>requires>

In this case, you need to add the 'aggregate' attribute and the 'optional' attribute. The bindHello and unbindHello will be called each time a Hello service appears or disappears.

Note: To avoid the list modification during the loop, you need synchronized the block.

Filtered

...

Requirement

A filtered dependency applies an LDAP filter on service provider. IPOJO reuses OSGi LDAP filter ability. The following metadata illustrates how to use filters:

Code Block
<component classname="...HelloConsumer">
<dependency<requires filter="(language=fr)">
     <callback type="bind" method="bindHello">
     <callback type="unbind" method="unbindHello">
</dependency>requires>
...
</component>

To add a filter, just add a 'filter' attribute in your dependency containing the LDAP filter. IPOJO will select only provider matching with this filter.

Note: to use the & operator in your filter, you need to use '&'.

...

Requires Metadata

A dependency requires element metadata can contains :

  • Field : name of the field representing the dependency in the component class
  • Interface : type of the Field
  • Optional: is the dependency an optional dependency?
  • Aggregate: is the dependency an aggregate dependency?
  • Filter : filter selecting service provider
  • Callback : allow to call a method on the component instances when a service provider (matching with the dependency) appears or disappears

...