Annotation Type 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 ClassesModifier and TypeClassDescriptionstatic interfaceMarker interface used to match any service types. -
Optional Element Summary
Optional ElementsModifier and TypeOptional ElementDescriptionThe callback method to be invoked when the service is available.The callback method to be invoked when the service properties have changed.Class<?> Sets the default implementation for anoptionalservice dependency.The Service dependency OSGi filter.The name used when dynamically configuring this dependency from the init method.booleanReturns true if the dependency service properties must be published along with the service.The callback method to invoke when the service is lost.booleanWhether the Service dependency is required or not.Class<?> 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 aspectlongThe max time in millis to wait for the dependency availability.
-
Element Details
-
service
Class<?> serviceThe 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 theServiceDependency.Anyclass. In this case, all services (matching thefilter()attribute if it is specified) will be returned.- Returns:
- the service dependency
- Default:
java.lang.Object.class
-
filter
String filterThe Service dependency OSGi filter.- Returns:
- the service filter
- Default:
""
-
defaultImpl
Class<?> defaultImplSets the default implementation for anoptionalservice 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 requiredWhether 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 addedThe 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 changedThe callback method to be invoked when the service properties have changed.- Returns:
- the change callback
- Default:
""
-
removed
String removedThe callback method to invoke when the service is lost.- Returns:
- the remove callback
- Default:
""
-
swap
String swapthe method to call when the service was swapped due to addition or removal of an aspect- Returns:
- the swap callback
- Default:
""
-
timeout
long timeoutThe 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 uncheckedIllegalStateExceptionexception 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 nameThe name used when dynamically configuring this dependency from the init method. Specifying this attribute allows to dynamically configure the dependencyfilterandrequiredflag 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
Initannotation 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 propagateReturns 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
-