I am working on an application that is meant to be extensible by the customer. It is based on OSGi (Equinox) and makes heavy use of Declarative Services (DS). Customer-installed bundles provide their own service implementations which my application then makes use of. There is no limit on the number of service implementations that customer-specific bundles may provide.
Is there a way to ensure that, when the application's main function is executed, all customer-provided service implementations have been registered?
To clarify, suppose my application consists of a single DS component RunnableRunner:
public class RunnableRunner
{
private final List<Runnable> runnables = new ArrayList<Runnable>();
public void bindRunnable(Runnable runnable)
{
runnables.add(runnable);
}
public void activate()
{
System.out.println("Running runnables:");
for (Runnable runnable : runnables) {
runnable.run();
}
System.out.println("Done running runnables.");
}
}
This component is registered using a DS component.xml such as the following:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="RunnableRunner" activate="activate">
<implementation class="RunnableRunner"/>
<reference bind="bindRunnable" interface="java.lang.Runnable" name="Runnable"
cardinality="0..n" policy="dynamic"/>
</scr:component>
I understand that there is no guarantee that, at the time activate()
is called, all Runnables have been bound. In fact, experiments I made with Eclipse/Equinox indicate that the DS runtime won't be able to bind Runnables contributed by another bundle if that bundle happens to start after the main bundle (which is a 50/50 chance unless explicit start levels are used).
So, what alternatives are there for me? How can I make sure the OSGi containers tries as hard as it can to resolve all dependencies before activating the RunnableRunner?
Alternatives I already thought about:
- Bundle start levels: too coarse (they work on bundle level, not on component level) and also unreliable (they're only taken as a hint by OSGi)
- Resorting to Eclipse's Extension Points: too Eclipse-specific, hard to combine with Declarative Services.
- Making the RunnableRunner dynamically reconfigure whenever a new Runnable is registered: not possible, at some point I have to execute all the Runnables in sequence.
Any advice on how to make sure some extensible service is "ready" before it is used?