Suppose I have the below OSGi component which is supposed to send an event every time a new implementation of SomeInterface
is registered in the run-time.
For that I bind EventAdmin
into eventAdmin
variable and then use it inside bindSomeInterface
method.
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
@Component
public class Sender {
private EventAdmin eventAdmin;
@Reference
public void bindEventAdmin(EventAdmin eventAdmin) {
this.eventAdmin = eventAdmin;
}
public void unbindEventAdmin(EventAdmin eventAdmin) {
this.eventAdmin = null;
}
@Reference(cardinality = ReferenceCardinality.MULTIPLE)
public void bindSomeInterface(SomeInterface instance) {
// var prop create here... (non relevant code)
Event event = new Event("topic", prop);
// it is NULL!
eventAdmin.sendEvent(event);
}
public void unbindSomeInterface(SomeInterface instance) {
}
}
Generated xml file:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.package.Sender">
<reference bind="bindSomeInterface" cardinality="0..n" interface="com.package.bindSomeInterface" name="SomeInterface" policy="static" unbind="unbindSomeInterface"/>
<reference bind="bindEventAdmin" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static" unbind="unbindEventAdmin"/>
<implementation class="com.package.Sender"/>
</scr:component>
The PROBLEM
bindSomeInterface
is being called first (getting a "notification" that a new instance of SomeInterface
was registered in the run-time) and after that bindEventAdmin
is called. This is not the desired effect.
Expected Behavior
I would like to get bind first the EventAdmin
instance, and then the SomeInterface
instances.
How can I do that?
Very close question (BUT not the same): Bind order of OSGi declarative services
PS: I'm trying to avoid ServiceTraker
s and that sort of stuff.
While you can control the order of injection using either lexical ordering (as suggested by Peter) or by manually ordering the XML elements, I would recommend against relying on this.
In your example you want to send an event to EventAdmin
when both the EventAdmin
and SomeInterface
services are bound. The perfect place to do this, along with any other required initialization, is in the activate method of the component. The activate method is guaranteed to be invoked after all static references are bound. In your case the cardinality of SomeInterface
is 0..n
so it may be called zero to many times. You can accumulate all the instances into a List and iterate that list from the activate method.
You don't even need to worry about making the List thread-safe or using synchronization, because SCR makes sure there is a "happens-before" relationship between the last service binding and the start of the activate method.