Annotation Type ServiceDependency


@Retention(CLASS) @Target({METHOD,FIELD}) public @interface ServiceDependency
Annotates a method or a field for injecting a Service Dependency. When applied on a class field, optional unavailable dependencies are injected with a NullObject.

For "add", "change", "remove" callbacks, the following method signatures are supported:


 (Component comp, ServiceReference ref, Service service)
 (Component comp, ServiceReference ref, Object service)
 (Component comp, ServiceReference ref)
 (Component comp, Service service)
 (Component comp, Object service)
 (Component comp)
 (Component comp, Map properties, Service service)
 (ServiceReference ref, Service service)
 (ServiceReference ref, Object service)
 (ServiceReference ref)
 (Service service)
 (Service service, Map properties)
 (Map properties, Service, service)
 (Service service, Dictionary properties)
 (Dictionary properties, Service service)
 (Object service)
 (ServiceReference<T> service)
 (ServiceObjects<T> service)
 

For "swap" callbacks, the following method signatures are supported:


 (Service old, Service replace)
 (Object old, Object replace)
 (ServiceReference old, Service old, ServiceReference replace, Service replace)
 (ServiceReference old, Object old, ServiceReference replace, Object replace)
 (Component comp, Service old, Service replace)
 (Component comp, Object old, Object replace)
 (Component comp, ServiceReference old, Service old, ServiceReference replace, Service replace)
 (Component comp, ServiceReference old, Object old, ServiceReference replace, Object replace)
 (ServiceReference old, ServiceReference replace)
 (Component comp, ServiceReference old, ServiceReference replace)
 (ServiceObjects old, ServiceObjects replace)
 (Component comp, ServiceObjects old, ServiceObjects replace)
 

When the dependency is injected on a class field, the following field types are supported:

  • a field having the same type as the dependency. If the field may be accessed by any thread, then the field should be declared volatile, in order to ensure visibility when the field is auto injected concurrently.
  • a field which is assignable to an Iterable<T> where T must match the dependency type. In this case, an Iterable will be injected by DependencyManager before the start callback is called. The Iterable field may then be traversed to inspect the currently available dependency services. The Iterable can possibly be set to a final value so you can choose the Iterable implementation of your choice (for example, a CopyOnWrite ArrayList, or a ConcurrentLinkedQueue).
  • a Map<K,V> where K must match the dependency type and V must exactly equals Dictionary class. In this case, a ConcurrentHashMap will be injected by DependencyManager before the start callback is called. The Map may then be consulted to lookup current available dependency services, including the dependency service properties (the map key holds the dependency services, and the map value holds the dependency service properties). The Map field may be set to a final value so you can choose a Map of your choice (Typically a ConcurrentHashMap). A ConcurrentHashMap is "weakly consistent", meaning that when traversing the elements, you may or may not see any concurrent updates made on the map. So, take care to traverse the map using an iterator on the map entry set, which allows to atomically lookup pairs of Dependency service/Service properties.

Usage Examples

Here, the MyComponent component is injected with a dependency over a "MyDependency" service
 @Component
 class MyComponent {
     @ServiceDependency
     volatile MyDependency dependency;
 }
 
The dependency can also be injected using a method callback:
 @Component
 class MyComponent {
     @ServiceDependency
     void bind(MyDependency dependency) {}
 }
 
Same example as before, but the callback signatures includes service properties:
 @Component
 class MyComponent {
     @ServiceDependency
     void bind(MyDependency dependency, Map<String, Object> serviceProperties) {}
 }
 
Another example, were we inject multiple dependencies to an Iterable field
 @Component
 class MyComponent {
     @ServiceDependency
     final Iterable<Dependency> dependencies = new CopyOnWriteArrayList<>();
 }
 
Another example, were we inject multiple dependencies to a Map field, allowing to inspect service dependency properties (the keys hold the services, and the values hold the associated service properties):
 @Component
 class MyComponent {
     @ServiceDependency
     final Map<MyDependency, Dictionary<String, Object>> dependencies = new ConcurrentHashMap<>;
 }
 
Author:
Felix Project Team
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static interface 
    Marker interface used to match any service types.
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    The callback method to be invoked when the service is available.
    The callback method to be invoked when the service properties have changed.
    Sets the default implementation for an optional service dependency.
    The Service dependency OSGi filter.
    The name used when dynamically configuring this dependency from the init method.
    boolean
    Returns true if the dependency service properties must be published along with the service.
    The callback method to invoke when the service is lost.
    boolean
    Whether the Service dependency is required or not.
    The type if the service this dependency is applying on.
    the method to call when the service was swapped due to addition or removal of an aspect
    long
    The max time in millis to wait for the dependency availability.
  • Element Details

    • service

      Class<?> service
      The type if the service this dependency is applying on. By default, the method parameter (or the class field) is used as the type. If you want to match all available services, you can set this attribute to the ServiceDependency.Any class. In this case, all services (matching the filter() attribute if it is specified) will be returned.
      Returns:
      the service dependency
      Default:
      java.lang.Object.class
    • filter

      String filter
      The Service dependency OSGi filter.
      Returns:
      the service filter
      Default:
      ""
    • defaultImpl

      Class<?> defaultImpl
      Sets the default implementation for an optional service dependency. You can use this to supply your own implementation that will be used instead of a Null Object when the dependency is not available. This is also convenient if the service dependency is not an interface (which would cause the Null Object creation to fail) but a class. Only use this attribute on an optional service dependency applied on a class field.
      Returns:
      the default implementation class
      Default:
      java.lang.Object.class
    • required

      boolean required
      Whether the Service dependency is required or not. When the dependency is optional and if the annotation is declared on a class field, then a Null Object will be injected in case the dependency is unavailable.
      Returns:
      the required flag
      Default:
      true
    • added

      String added
      The callback method to be invoked when the service is available. This attribute is only meaningful when the annotation is applied on a class field.
      Returns:
      the add callback
      Default:
      ""
    • changed

      String changed
      The callback method to be invoked when the service properties have changed.
      Returns:
      the change callback
      Default:
      ""
    • removed

      String removed
      The callback method to invoke when the service is lost.
      Returns:
      the remove callback
      Default:
      ""
    • swap

      String swap
      the method to call when the service was swapped due to addition or removal of an aspect
      Returns:
      the swap callback
      Default:
      ""
    • timeout

      long timeout
      The max time in millis to wait for the dependency availability. Specifying a positive number allow to block the caller thread between service updates. Only useful for required stateless dependencies that can be replaced transparently. A Dynamic Proxy is used to wrap the actual service dependency (which must be an interface). When the dependency goes away, an attempt is made to replace it with another one which satisfies the service dependency criteria. If no service replacement is available, then any method invocation (through the dynamic proxy) will block during a configurable timeout. On timeout, an unchecked IllegalStateException exception is raised (but the service is not deactivated).

      Notice that the changed/removed callbacks are not used when the timeout parameter is greater than -1. -1 means no timeout at all (default). 0 means that invocation on a missing service will fail immediately. A positive number represents the max timeout in millis to wait for the service availability. Sample Code:

       @Component
       class MyServer implements Runnable {
         @ServiceDependency(timeout=15000)
         MyDependency dependency;.
         
         @Start
         void start() {
           (new Thread(this)).start();
         }
         
         public void run() {
           try {
             dependency.doWork();
           } catch (IllegalStateException e) {
             t.printStackTrace();
           }
         }   
       
      Returns:
      the wait time when the dependency is unavailable
      Default:
      -1L
    • name

      String name
      The name used when dynamically configuring this dependency from the init method. Specifying this attribute allows to dynamically configure the dependency filter and required flag from the Service's init method. All unnamed dependencies will be injected before the init() method; so from the init() method, you can then pick up whatever information needed from already injected (unnamed) dependencies, and configure dynamically your named dependencies, which will then be calculated once the init() method returns.

      See Init annotation for an example usage of a dependency dynamically configured from the init method.

      Returns:
      the dependency name used to dynamically configure the filter and required flag from the init callback.
      Default:
      ""
    • propagate

      boolean propagate
      Returns true if the dependency service properties must be published along with the service. Any additional service properties specified directly are merged with these. The component provided service properties take precedence over the propagated service dependency properties, meaning that a give component service property overrides the same property included in the propagated service dependency properties.
      Returns:
      true if dependency service properties must be published along with the service, false if not.
      Default:
      false