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">

Service Dependency Management

One of the main iPOJO feature is the service injection. So, a component can consume a service without managing the The dependency handler manages OSGi service dependencies/requirements. It allows a component to consume service without managing service discovery, tracking and binding. The handler iPOJO manages all this interaction these interactions and injects required service in into the component. This page explains how to use services.

Div
classtoc
Table of Contents
maxLevel4
minLevel2

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). 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
  • Dynamic / Static / Dynamic-Priority : the component can specify the binding policy
  • Specific : the dependency targets a specific service provider
  • Proxy : by default, iPOJO injects a smart proxy, but it can also be a dynamic proxy or the direct references

Dynamism & Instance Lifecycle

In OSGi™, services can appear and disappear dynamically. This implies dependencies can target a provdier provider which can appear or disappear dynamically.   So, dependencies need to manage this dynamism by tracking every time available services. At any moment, a dependency can be unresolved (i.e. no more provider can fulfill the requirement).   In the case of a mandatory requirement, the instance becomes invalid (an invalid instance is no more accessible externally, for example provided service services 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 OSGi dynamism to allow a complete unloading when a service goes away. As soon a mandatory dependency cannot be fulfilled, the instance is invalidated.

By default, dependencies are managed dynamically (as previously explained). However, iPOJO supports two other types of binding policies: 

  • Static : if a bound service disappears, the instance is invalidated and cannot be revalidated (binding broken forever)
  • Dynamic-Priority: at each injection, the best provider is injected, or the providers array is sorted according to the OSGi Ranking policy or to a specified sorting algorithm.

Service Requirement Injection Mechanisms

The handler manages two iPOJO support several 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
    Code Block
    
    @Requires
    private LogService log;
    
  • Method invocation: when Method invocation: when a service appears, or disappears a method in the component is invoked. For each dependency, bind and / unbind / modified methods are invoke invoked to notify the component of the event.

    Moreover, the two injections type can be merged. A component 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
    
    public class HelloConsumer {
                    private Hello m_hello;
                    public doSomething() {
                                   System.out.println(m_hello.getMesage());
                    }
    }
    

    For this component, metadata could be:

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

    The metadata contains a '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.

    Method invocation

    The second injection mechanism uses methods in the implementation class. By this way, the dynamics can be managed directly by the developer. Each dependency declares two methods:

    • A bind method called when a service appears
    • An unbind method called when a service disappears
      Moreover, callbacks can be in the component super class (in this case methods must be public).
      These methods can have four signatures:
    • Without any argument: the method is just a notification
    • With the service object : the object is the implicated service object
    • With an OSGi service reference: the service reference appearing or disappearing
    • With the service object and the OSGi service reference

    The following component shows an example of implementation using this mechanism:

    • Code Block
      
      @Bind
      public void bindLogService(LogService log) { /*...*/ }
      @Unbind
      public void unbindLogService(LogService log) { /*...*/ }
      @Modified
      public void modifiedLogService(LogService log) { /*...*/ }
      
    • Constructor injection: services can also be injected as constructor parameter (only if proxies are enabled). 1.7.0-SNAPSHOT
      Code Block
      
      public MyComponent(@Requires LogService log) { /*...*/ }
      

    Moreover, the injections types can be mixed. A component can declare a requirement containing both a field and 'binding' methods.

    Field injection

    Let's 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
    java
    java
    
    @Component
    @Instantiate
    public class HelloConsumer {
        @Requires
        private Hello m_hello;
    
        public doSomething() {
            
    Code Block
    
    public class HelloConsumer {
      private Hello m_hello;
    
      public void bindHello(Hello h) { m_hello = h; }
      public void unbindHello() { m_hello = null; }
      public doSomething() { System.out.println(m_hello.getMesage());
        }
    }
    

    For You can also use XML to describe this component , metadata could betype:

    Code Block
    xml
    xml
    <component classname="...HelloConsumer">
    <requires>
        <callback<requires typefield="bind" method="bindHello"m_hello"/>
        <callback type="unbind" method="unbindHello">
    </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.

    (see note on type discovery)

    Field injections and Method invocations

    The two mechanisms can be merged together. In this case, the field receives the value before the bind method invocation.

    The following component shows an example of implementation using this mechanism:

    Code Block
    
    public class HelloConsumer {
         private Hello m_hello;
    
         public void bindHello() { System.out.println("Hello appears"); }
         public void unbindHello() { System.out.println("Hello disapears"); }
         public doSomething() { System.out.println(m_hello.getMesage()); }
    }
    

    For this component, metadata could be:

    Code Block
    
    <component classname="...HelloConsumer">
    <requires  field="m_hello">
        <callback type="bind" method="bindHello">
        <callback type="unbind" method="unbindHello">
    </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 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 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 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.

    Aggregate Requirement

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

    Aggregate Dependency with field injection

    The metadata contains a 'requires' element (representing the service dependency) and specify a field used to inject the service. The implementation uses the field as a normal field without managing service interactions.

    Method invocation

    The second injection mechanism uses methods in the implementation class. By this way, the dynamics can be managed directly by the developer. Each dependency can declare three methods:

    • A bind method called when a service appears
    • An unbind method called when a service disappears
    • A modified method called when a service is modified (the service properties changed, but the service still matches the requirement)

    Moreover, callbacks can be in the component super class (in this case methods must be public). These methods can have one of these four signatures:

    • Without any argument: the method is just a notification (method())
    • With the service object : the object is the implicated service object (method(Service svc))
    • With an OSGi service reference: the service reference appearing or disappearing (method(ServiceReference ref))
    • With the service object and the OSGi service reference (method(Service svc, ServiceReference ref))
    • With the service object and the service properties inside a Map (method(Service svc, Map properties))
    • With the service object and the service properties inside a Dictionary (method(Service svc, Dictionary properties))

    The following component implementation shows an example of implementation using this mechanism:

    Code Block
    java
    java
    
    @Component
    public class HelloConsumer {
      private Hello m_hello;
    
      @Bind
      public void bindHello(Hello h) { m_hello = h; }
      @Unbind
      public void unbindHello() { m_hello = null; }
      public doSomething() { System.out.println(m_hello.getMesage()); }
    }
    

    The modified callback is not mandatory. The following XML metadata are describing the same component type:

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

    Note, that the different callbacks can be have different signatures. By using this mechanism, you need to be sure to manage the dynamism correctly.
    (See note on type discovery)

    Using the @Modified callback is also quite simple:

    Code Block
    java
    java
    
    @Component
    Code Block
    public class HelloConsumer {
         private Hello m_hellos[]hello;
    
      @Bind
      public publicvoid doSomethingbindHello(Hello h) {
     m_hello = h; }
      @Unbind
      public void unbindHello() {  for(int I = 0; I < m_hellos.length; i++m_hello = null; }
      @Modified
      public void modifiedHello() { System/* .out.println(m_hellos[i].getMessage());. */ }
      public doSomething() {   System.out.println(m_hello.getMesage()); }
    
    }
    

    Using constructor injection (1.7.0-SNAPSHOT)

    Services can also be injected using constructor parametersFor this component, metadata could be:

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

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

    @Component
    public class MyComponent {
        private LogService log;
    
        public MyComponent(@Requires LogService log) {
            this.log = log;
        }
    }
    

    Mixing injections types

    The different mechanisms can be used together. In this case, the field receives the value before the bind method invocation. Constructor parameters get their values during the constructor invocation. So, if the field is used in the method, the returned value will be up to date. The following component implementation uses this mechanism:

    Code Block
    java
    java
    Code Block
    public class HelloConsumer {
         @Requires(id="hello")
         private ListHello m_hellos= new ArrayList();
       hello; // Injected Field
    
       private void bindHello(Hello h@Bind(id="hello")
         public void bindHello() { m_hellos.add(hSystem.out.println("Hello appears"); }
         @Unbind(id="hello")
         privatepublic void unbindHello(Hello h) { m_hellos.remove(hSystem.out.println("Hello disapears"); }
    
          public synchronized doSomething() {
            System.out.println(m_hello.getMesage()); }
    }
    

    In XML, it results in:

    Code Block
    xml
    xml
    
    <component classname="...HelloConsumer">
        <requires  field="m_hello">
            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  aggregate="true">
        <callback type="bind" method="bindHello">
        <callback type="unbind" method="unbindHello">
    </dependency>
    

    In this case, iPOJO cannot detect if the dependency is aggregate or not. So, you need to add the 'aggregate' 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. Indeed, as the field is not an iPOJO requirement, iPOJO will not manage the synchronization.

    Optional Dependency (non-aggregate)

    An optional 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());  }
    }
    

    For this component, metadata could be:

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

    To declare an optional requirement, 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.

    Optional Dependency with method invocation

    <callback type="bind" method="bindHello">
            <callback type="unbind" method="unbindHello">
        </requires>
        ...
    </component>
    

    The id attribute is used to determine which callbacks / fields go together. If ommitted, it is computed automaticcally:

    • for field it uses the field type.
    • for method starting with bind / unbind / modified, it extract the end of the method name (bindFoo => Foo)
    • for constructor parameter, it uses the parameter index

    So, it is strongly recommended to specify the id manually.

    Injection mechanisms & lazy object creation

    iPOJO creates objects only when required. When needed, iPOJO invokes the constructor of the implementation class. The implementation class can use field requirement because values are already injected and obviously constructor parameters. However, method dependencies are called after the constructor. If the service is available before the constructor call, the invocation of the bind methods is delayed until the a component class object is created.

    Examples

    For all examples both annotations and XML forms are given. Just choose what you'd like to use.

    Simple Requirement

    By default, a requirement is mandatory, non-filtered and simple (non-aggregate). The previous examples illustrate this kind of dependency. When services goes away and appears, the service substitution is hidden. Fields attached to simple requirement point always a consistent service object. For a simple dependency, the bind method is called once time when the service appears or just after the POJO constructor invocation is the service is available. When the service disappears the unbind method is called. The bind method is re-invoked as soon as another service provider is available. This invocation occurs immediately if another service provider if available. In this case, the instance is not invalidated.

    Aggregate Requirement

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

    Aggregate Dependency with field injection

    Code Block
    java
    java
    
    @Component
    
    Code Block
    
    public class HelloConsumer {
         @Requires
         private Hello m_hello;hellos[]; // Array => Aggregate
         public void bindHello(Hello h) { m_hello = h; }
    doSomething() {
               public void unbindHello() {for(int I = 0; I < m_hello = null; }
    hellos.length; i++) { 
            public   doSomething() { if(m_hello != null) { System.out.println(m_hello.getMesagehellos[i].getMessage());
      } }           }
           }
    }
    

    For this component, XML metadata should could be:

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

    As To declare an aggregate field for field requirement, 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.

    Aggregate & Optional Dependency

    A dependency can be both aggregate and optional.

    Aggregate & Optional Dependency with field injection

    you only need to declare an array (instead of a scalar type). iPOJO will create and inject the service object array. iPOJO discover that the dependency is aggregate during the bytecode introspection.

    Array types cannot be 'proxied'. Moreover array dependencies cannot be injected as constructor parameter.

    Info
    titleSynchronization

    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. Nested methods will share the same service object set.

    Aggregate Dependency with field injection: list, vector, collection and set

    It is also possible to inject service objects inside fields of the type:

    • list
    • vector
    • collection
    • set
    Code Block
    java
    java
    
    @Component
    
    Code Block
    
    public class HelloConsumer {
         @Requires(specification="org.apache.felix.ipojo.example.Hello")
         private HelloList<Hello> m_hellos[];
         public doSomething() {
                 for(intHello Ih = 0; I < m_hellos.length; i++) {: m_hellos) { 
                     System.out.println(m_hellos[i]h).getMessage());
                 }
           }
    }
    

    For this component, XML metadata could be:

    Code Block
    xml
    xml
    <component classname="...HelloConsumer">
        <requires field="m_hellos" optionalspecification="trueorg.apache.felix.ipojo.example.Hello"/>
    .    ...
    </component>
    

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

    Aggregate & Optional Requirement with method invocation

    In this case, just use the supported type that you want. iPOJO will automatically understand that it is an aggregate dependency, and will create the collection object containing service objects. However, you must specify the service specification. Indeed, generics types cannot be discovered at runtime reliably.

    Info
    titleService specification discovery

    The service specification (i.e. interface) cannot be discovered when using these types as the bytecode does not provide enough information. So, you have to indicate the required service interface (with the 'specification' attribute) in the requirement description.

    Info
    titleHow iPOJO manage the synchronization for you

    As in the previous case, 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. Nested methods will share the same service object set.

    Aggregate Dependency with callbacks

    Code Block
    java
    java
    
    public class HelloConsumer 
    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() {
          private List synchronized(m_hellos) {
    = new ArrayList();
          @Bind(aggregate=true)
          private for(int I = 0; I < m_hellos.size(); i++void bindHello(Hello h) { System.out.println(m_hellos.getadd(ih).getMessage()); }
          @Unbind
      }
        private  }
    }
    

    For this component, metadata could be:

    Code Block
    
    <requires aggregate="true" optional="true">
    void unbindHello(Hello h) { m_hellos.remove(h); }
          public <callback type="bind" method="bindHello">
    synchronized doSomething() {
             <callback type="unbind" method="unbindHello">
    </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.

    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:

             for(Hello h : m_hellos) { 
                        System.out.println(h.getMessage());
                      }
                    }
            }
    }
    

    This dependency can also be described in XML as follow:

    Code Block
    xml
    xml
    
    <requires  aggregate="true
    Code Block
    
    <component classname="...HelloConsumer">
    <requires filter="(language=fr)">
         <callback type="bind" method="bindHello">
         <callback type="unbind" method="unbindHello">
    </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.

    Binding Policies 

    Three binding policies are supported inside iPOJO.

    • Dynamic policy (default) : the binding are managed dynamically. At each injection, the same provider is injected if the provider is always available. Else a new one is chosen. For aggregate dependency, the array order does not change, new providers are placed at the end of the array.
    • Static policy : the binding is static. So, once bound a provider cannot disappear. If it disappears, the instance is invalidated and cannot be revalidated without stopping and restarting the instance.
    • Dynamic-priority policy : the binding is managed dynamically but the injected provider is selected by using the OSGi ranking policy. Two injections can return two different providers, is a new provider is 'better' than the previous one, despite the first one is alway available. For aggregate dependency, the array is sorted.

    A static binding is declared as following :

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

    A dynamic-priority binding is declared as following :

    In this case, iPOJO cannot detect if the dependency is aggregate or not. So, you need to add the 'aggregate' attribute. The bindHello and unbindHello will be called each time a Hello service appears or disappears.

    Info
    titleSynchronization

    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 Requirement (Scalar)

    An optional requirement does not invalidate the instance despite no providers are available. Moreover, it is possible to inject a default service implementation when no real providers are available.

    Optional Requirement with field injection

    Code Block
    java
    java
    
    @Component
    public class HelloConsumer {
             @Requires(optional=true)
             private Hello m_hello;
    
             public doSomething() {  
                System.out.println(m_hello.getMesage());  
             }
    }
    

    For this component, equivalent XML metadata could be:

    Code Block
    xml
    xml
    Code Block
    <component classname="...HelloConsumer">
        <requires field="m_helloshello" policyoptional="dynamic-prioritytrue"/>
        ...
    </component>
    

    Requires Metadata

    A requires element metadata can contains :

    • Field : name of the field representing the dependency in the component class
    • Interface : service interface
    • 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

    Some of these attributes are optional. Indeed, either the component implementation contains the information; either iPOJO uses default behavior.

    The field attribute is optional if callbacks are specified. The field attribute contains the name of the field of the component attached with this dependency.

    The interface attribute describes the required service. This element is optional because the component implementation contains the same information (the type of the field). If the interface attribute has a value, the consistency of the information is checked. However, sometimes this attribute is mandatory if iPOJO cannot discover the type of the dependency.

    The optional attribute describes if the dependency is optional or not. An optional dependency is always valid, and does not interact with the instance state. On the other hand, when a mandatory is no more valid the component state becomes INVALID.

    The aggregate attribute determines if the dependency needs to inject several providers on just one. This attribute is optional if the dependency point on a field array.

    The filter attribute contains the LDAP request on the service provider. By default, iPOJO use no filter, but you can specify a filter. For further information, see the OSGi specification.

    The callback elements contain the name of method to call when a service provider matching with the dependency appears or disappears. This allows the component to be notified when a service provider arrives or goes away.

    Technical details on service discovery and service invocation

    The handler of the registers an OSGi service event listener and listens for interesting events. When an interesting service arrives, it stores the service reference. When the service is used, it obtains the service object and injects the object in the instance. If it is an aggregate dependencies, it returns an array of service object or/and call the bind method for each provider.
    When a service goes away, the handler removes the reference from its list (and call the unget method): the manager does not keep any reference on the old service. This allows a complete unloading of the service.
    Two calls to a service can use two different service providers if the used provider has gone. IPOJO tries to return always the same service object if possible, since the service goes away.

    Note about nullable object & default-implementation

    The instance implementation can use an optional dependency without any checking. Indeed, when an instance declares an optional dependency using field injection, iPOJO create on the fly a Nullable class implementing the service specification but doing nothing (mock object). Therefore, iPOJO cannot return a service to the instance, for an optional dependency, it returns a nullable object.

    A nullable object returns:

    • Null when the method returns an object
    • 0 when the method returns an int, log, byte, short, char, float or a double
    • False when the method return a boolean

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

    However, you can indicates a default-implementation for your optional service. In this case, if no providers are found, iPOJO creates an instance of the default-implementation and injects it. The default-implementation attribute describes the class name of your implementation. The given class MUST implement the required service interface.

    For example, the following componentr uses a default implementation for a Log Service dependency :

    Code Block
    
    <component classname="...LogExample">
    <requires field="m_log" optional="true" default-implementation="org.apache.felix.ipojo.example.default.MyLogService"/>
    ...
    </component>
    

    If the log service is not available, iPOJO creates an object of the 'org.apache.felix.ipojo.example.default.MyLogService' class. This object is injected instead of a Nullable object. For instance, the default implementation can print messages on the System.err stream. The nullable object does no display anything.

    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:

    • Simple dependency : at the firs binding and at each rebinding to another service provider
    • Aggregate dependencies: each time that a service provider arrives

    An unbind callback is called each time that a used service provider goes away. For a simple dependency this method is called each time that the used service provider goes away. For a multiple dependency this method is called each time that a service provider goes away.

    The method can receive in argument the service object or the service reference (in order to obtain service properties). The bind methods are delayed since a component instance is created.

    Note on service interface discovery

    To declare an optional requirement, 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. Moreover, it is possible to set a default-implementation for the service. A default-implementation is a class implementing the service but used only when no others service providers are available. The default-implementation object will be injected instead of the Nullable objet. For further information refer to the note about nullable object.

    Optional Dependency with callbacks invocation

    Code Block
    java
    java
    
    @Component
    public class HelloConsumer {
         private Hello m_hello;
    
         @Bind(optional=true)
         public void bindHello(Hello h) { m_hello = h; }
    
         @Unbind
         public void unbindHello() { m_hello = null; }
    
         public doSomething() { 
              if(m_hello != null) { // Must be checked
                  System.out.println(m_hello.getMesage()); 
              }
        }
    }
    

    For this component, XML metadata could be:

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

    As for field requirement, 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.

    Aggregate & Optional Requirement

    A dependency can be both aggregate and optional.

    Aggregate & Optional Dependency with field injection

    Code Block
    java
    java
    
    @Component
    public class HelloConsumer {
         @Requires(optional=true)
         private Hello m_hellos[];
    
         public doSomething() {
               for(Hello h : m_hellos) { 
                 System.out.println(h.getMessage());
               }
         }
    }
    

    For this component, XML metadata could be:

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

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

    Aggregate & Optional Requirement with callbacks

    Code Block
    java
    java
    
    @Compoent
    public class HelloConsumer {
    
         private List m_hellos<Hello> = new ArrayList<Hello>();
    
         @Bind(aggregate=true, optional=true)
         private void bindHello(Hello h) { m_hellos.add(h); }
    
         @Unbind
         private void unbindHello(Hello h) { m_hellos.remove(h); }
    
         public synchronized doSomething() {
                   for(Hello h : m_hellos) { 
                      System.out.println(h.getMessage());
                   }
         }
    }
    

    For this component, XML metadata could be:

    Code Block
    xml
    xml
    
    <requires aggregate="true" optional="true">
         <callback type="bind" method="bindHello">
         <callback type="unbind" method="unbindHello">
    </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. These bind / unbind methods are not called when binding / unbinding a Nullable object (when both field and method are used).

    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
    
    @Requires(filter="(language=fr)")
    private String DictionaryService dict;
    
    Code Block
    xml
    xml
    
    <requires filter="(language=fr)" field="dict"/>
    

    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.

    When using a filter, you can also use the modified callback invoked when a matching service is modified but still matches the filter:

    Code Block
    
    @Component
    public class MyComponent {
    
        @Bind(filter="(langage=en)")
        public void bindHDictionary(DictionaryService svc) { ... }
    
        @Unbind
        public void unbindDictionary() { ...}
    
        @Modified
        public void modifiedDictionary() { ... }
    
    }
    

    Moreover, filters can be customized instance by instance. It is possible to specialize / change / add the filter of a component in the instance description. It is useful when you want to create different instances of the same component, with different filter. To achieve this customization, you have to identify your dependency with the 'id' attribute. Then, you can adapt the filter of the dependency in the instance description by using the property "requires.filters". In this property you can specify each dependency identified by its id and the new value of the filter.

    Code Block
    xml
    xml
    
    <component 
       className="org.apache.felix.ipojo.example.FilteredDependency">
    	<requires field="m_foo" fiter="(foo.property=FOO)" id="id1">
    		<callback type="bind" method="bind"/>
    		<callback type="unbind" method="unbind"/>
    	</requires>
    </component>
    
    <instance name="FOO1" component="FOO"/>
    
    <instance name="FOO2" component="FOO">
    	<property name="requires.filters">
    		<property name="id1" value="(foo.property=BAR)"/>
    	</property>
    </instance>
    
    <instance name="FOO3" component="FOO">
    	<property name="requires.filters">
    		<property name="id1" value="(foo.property=BAZ)"/>
    	</property>
    </instance>
    

    The component type declares a service dependency with the 'id1' id. This dependency has no filter by default. The first instance is just an instance of the FOO component type and does not modify the dependency. The second one adds a filter to the declared dependency to target providers with foo.property = BAR. The last one adds another filter to the declared dependency. By using instance filter customization, it is possible to create complex applications where you avoid binding problems by filtering dependencies instance by instance.

    Targeting a specific provider

    A service dependency can choose a specific provider. To achieve this, add a 'from' attribute in your requirement description such as in:

    Code Block
    
    @Requires(from="MyHelloProvider")
    private Hello m_hello;
    

    or in XML:

    Code Block
    xml
    xml
    
    <requires from="MyHelloProvider" field="m_hello"/>
    

    iPOJO maps the from attribute to a specific filter : '|(instance.name=MyHelloProvider)(service.pid=MyHelloProvider)'. Then the dependency can only be fulfilled by a service matching this filter.

    Moreover, from attributes can be customized instance by instance. It is possible to specialize / change / add a 'from' attribute of a component in the instance configuration. It is useful when you want to create different instances of the same component, with different 'from' clauses. To do it, you have to identify your dependency with an 'id' attribute. Then, you can adapt the 'from' of the dependency in the instance configuration by using the property "requires.from". In this property you can specify each dependency identified by its id and the 'from' value.

    Code Block
    xml
    xml
    
    <component 
       className="org.apache.felix.ipojo.example.FilteredDependency"
       name="FOO">
    	<requires field="m_foo" id="id1">
    		<callback type="bind" method="bind"/>
    		<callback type="unbind" method="unbind"/>
    	</requires>
    </component>
    
    <instance name="FOO1" component="FOO"/>
    
    <instance name="FOO2" component="FOO">
    	<property name="requires.from">
    		<property name="id1" value="myprovider"/>
    	</property>
    </instance>
    
    <instance name="FOO3" component="FOO">
    	<property name="requires.from">
    		<property name="id1" value="myotherprovider"/>
    	</property>
    </instance>
    

    The FOO component type declares a service dependency with the 'id1' id. This dependency has no 'from' attribute by default. The first instance is just an instance of the FOO component type and does not modify the dependency. The second one adds a 'from' attribute to the declared dependency to target the 'myprovider' provider. The last one adds another 'from' clause to the declared dependency.

    Binding Policies

    Three binding policies are supported inside iPOJO.

    • Dynamic policy (default): the binding are managed dynamically. At each injection, the same provider is injected if the provider is always available. Else a new one is chosen. For aggregate dependency, the array order does not change; new providers are placed at the end of the array.
    • Static policy: the binding is static. So, once bound a provider cannot disappear. If it disappears, the instance is invalidated and cannot be revalidated without stopping and restarting the instance.
    • Dynamic-priority policy: the binding is managed dynamically but the injected provider is selected by using a ranking policy. Two injections can return two different providers, is a new provider is 'better' than the previous one, despite the first one is always available. For aggregate dependency, the array is sorted.

    A static binding is declared as following:

    Code Block
    
    @Requires(policy="static")
    private Hello[] m_hellos;
    

    or

    Code Block
    xml
    xml
    
    <requires field="m_hellos" policy="static"/>
    

    A dynamic-priority binding is declared as following:

    Code Block
    
    @Requires(policy="dynamic-priority")
    private Hello[] m_hellos;
    

    or

    Code Block
    xml
    xml
    
    <requires field="m_hellos" policy="dynamic-priority"/>
    

    By default, the dynamic-priority policy uses the OSGi service ranking policy. However, it is possible to customize the policy by adding the 'comparator' attribute. This attribute indicates the class name of a class implementing the java.util.Comparator interface. iPOJO creates an instance of your comparator and uses it to sort service references (so your customized comparator needs to be able to sort OSGi Service Reference).

    Code Block
    
    @Requires(policy="dynamic-priority", comparator=MyComparator.class)
    private Hello[] m_hellos;
    

    or

    Code Block
    xml
    xml
    
    <requires field="m_hellos" policy="dynamic-priority" comparator="great.MyComparator"/>
    

    Anchor
    nullable
    nullable

    Note about nullable object & default-implementation

    The instance implementation can use an optional dependency without any checking. Indeed, when an instance declares an optional dependency using field injection, iPOJO create on the fly a Nullable class implementing the service specification but doing nothing (mock object). Therefore, iPOJO cannot return a service to the instance, for an optional dependency, it returns a nullable object.

    A nullable object returns:

    • Null when the method returns an object
    • 0 when the method returns an int, log, byte, short, char, float or a double
    • False when the method return a boolean

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

    You can disable the Nullable pattern too (activated by default). In this case, iPOJO injects null instead of a Nullable object. So, you can just test if your field is equals to null to check if the service is available. To disable the Nullable pattern, you need to add the 'nullable="false"' attribute in your service dependency description as follows:

    Code Block
    
    @Requires(optional=true, nullable=false)
    private LogService m_log;
    

    or

    Code Block
    xml
    xml
    
     <requires field="m_log" optional="true" nullable="false"/>
    

    However, you can also indicate a default-implementation for your optional service. In this case, if no providers are found, iPOJO creates an instance of the default-implementation and injects it. The default-implementation attribute describes the class name of your implementation. The given class MUST implement the required service interface.

    For example, the following component uses a default implementation for a Log Service dependency:

    Code Block
    
    @Requires(optional=true, default-implementation=MyLogService.class)
    private LogService m_log;
    

    or

    Code Block
    xml
    xml
    
    <requires field="m_log" optional="true" 
        default-implementation=
           "org.apache.felix.ipojo.example.default.MyLogService"/>
    

    If the log service is not available, iPOJO creates an object of the 'org.apache.felix.ipojo.example.default.MyLogService' class. This object is injected instead of a Nullable object. For instance, the default implementation can print messages on the System.err stream. The nullable object does no display anything.

    Anchor
    callbacks
    callbacks

    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:

    • Simple dependency : at the firs binding and at each rebinding to another service provider
    • Aggregate dependencies: each time that a service provider arrives

    An unbind callback is called each time that a used service provider goes away. For a simple dependency this method is called each time that the used service provider goes away. For a multiple dependency this method is called each time that a service provider goes away.

    The method can receive in argument the service object or the service reference (in order to obtain service properties). The bind methods are delayed since a POJO object is created.

    Proxies

    Since iPOJO 1.6, iPOJO injects proxy objects. Those proxies are by default smart proxies and are design to be lightweight:

    • for scalar requirement : the service object is a proxy
    • for aggregate dependencies : iPOJO injects a smart collections

    The goal of the proxies is to hide the dynamism and more particularly the dynamism. So, you can gives a service dependency to another object, using the service object still supports the dynamism. For collections, you can iterate over the collection without managing the potential departures and arrivals of services. The proxy also manage that the component class and the delegate objects shared the same services is they are accessed in the same Thread.

    By default iPOJO injects proxy except for arrays. Moreover, it is possible to disable the proxy injection by adding proxy=false to the requires element (or to the @Requires and @Bind annotations). It is also possible to inject dynamic proxies (if the platform does not support dynamically generated classes). To enable dynamic proxies, set the system or bundle property ipojo.proxy.type to dynamic-proxy. You can also disable completely the proxy injection by setting the system property ipojo.proxy to disabled.

    Anchor
    discovery
    discovery

    Note on service interface discovery

    The specification The 'interface' attribute is generally optional except when iPOJO cannot discover the type of the service. IPOJO iPOJO cannot infer the type when the dependency has no field and no callbacks do not receive the service object in parameter. In this case, you need to declare must the service specification (i.e. interface).

    Include Page
    apache-felix-ipojo-footer
    apache-felix-ipojo-footer