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.

Service Requirement

What's a service requirement?

A 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). Requirements have several attribute. A dependency Service requirements can be:

  • Simple / Aggregate : the component can require one or several service providers
  • Mandatory / Optional : a component can declare an optional dependency
  • Filtered : a component can filter available providers

Dynamism & Instance Lifecycle

In OSGi?OSGi™, services can appear and disappear dynamically. This implies dependencies can target a service that provdier which can appear or disappear dynamically.  So, dependencies need to manage this dynamism by tracking every time available serviceservices. At any moment, a dependency can be unresolved (i.e. no more provider can fulfill the requirement).  In the case of a mandatory dependencyrequirement, the instance becomes invalid (an invalid instance is no more accessible externally, for example provided service are unpublished). If a service, resolving the unfilled dependency appears, the instance becomes valid. In consequence, dependencies affect directly the instance state, and must manage correctly the dynamics of OSGi dynamism to allow a complete unloading when a service goes away. As soon a mandatory dependency cannot be fulfilled, the instance is invalidated.

...

Service Requirement Injection Mechanisms

The handler manages two types of injections:

  • Field injection: a field contains the service object. As soon as the field is used, a consistent service object is injected. This injection type fully hides the dynamism
  • Method invocation: when a service appears, or disappears a method in the component is invoked. For each dependency, bind and unbind methods are used invoke to allow the developer to manage the dynamismnotify the component of the event.

Moreover, the two injections type can be merged. A field will contain the value and 'binding' methods will be invokedcomponent can declare a requirement containing both a field and 'binding'.

Field injection

Imagine a Hello service with one method 'getMessage' returning a "Hello Message". The following component implementation can use this service by attaching this service to a field and by using the field:

...

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

The metadata contains a dependency 'requires' element (representing the service dependency). This element has a field attribute. This attribute is the name of the field representing the service dependency in the implementation class. The implementation uses the field as a normal field without managing service interactions.

...

Simple Requirement

By default, a dependency requirement 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 requirement 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.

...

Code Block
public class HelloConsumer {
     private Hello m_hellos[];
     public doSomething() {
            synchronized(m_hellos) {
                     for(int I = 0; I < m_hellos.length; i++) { System.out.println(m_hellos[i].getMessage());}
            }
       }
}

For this component, metadata could be:

...

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

Note: To avoid array modification during the loop, you need synchronized the block The synchronization is managed by iPOJO. As soon as you are 'touching' a dependency in a method, iPOJO ensure that you will keep these objects until the end of the method. Imbricated methods will share the same service object set.

Aggregate Dependency with method invocation

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

...

Note: To avoid the list modification during the loop, you need synchronized the block. Indeed, as the field is not an iPOJO requirement, iPOJO will not manage the synchronization.

Optional Dependency (non-aggregate)

...

Code Block
public class HelloConsumer {
     private Hello m_hellos[];
     public doSomething() {
        synchronized(m_hellos) {
           for(int I = 0; I < m_hellos.length; i++) { System.out.println(m_hellos[i].getMessage());}
        }
     }
}

For this component, metadata could be:

...

To declare an optional & aggregate field requirement you need to write the optional attrbiute attribute 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

...

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:

...

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 requires element metadata can contains :

...

You can check if the returned object is a nullable object with the test: _m_myservice instanceof Nullable._

Note about synchronization

When you want to be sure to have always the same service objects, you can use a synchronized block. It is useful for multiple dependencies. Indeed when you want to be sure that a service does not go away during the iteration on your array, you can put your loop inside a synchronized blocks.

Note about Callbacks

Dependency manages two type of callback: bind and unbind. A callback with a type "bind" is called each type that a service provider arrives and the binding is necessary. According to the cardinality of the dependency it means:

...