osgideclarative-services

Bind order of OSGi declarative services using STATIC policy


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 ServiceTrakers and that sort of stuff.


Solution

  • 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.