5
votes

I'm having a problem discovering services that are provided by some OSGi bundles that are not being activated. Let me describe the situation:

  • Bundle A defines interface X
  • Bundles B, C, and D provide services that implement interface X
    • These bundles' services are registered via Spring DM, so they are only created when the bundle is activated and Spring DM initialized the application context defined in the bundle
  • Bundle A is activated and at some point asks the service registry for services for interface X. It doesn't find any, because bundles B, C, and D haven't been moved into the ACTIVE state (they are only RESOLVED).

I cannot seem to get bundles B, C, or D to start, and therefore register their services. Forcing them to start by adding them to the config.ini is not an option, because there can be any number of bundles that are installed in the application (via an Eclipse p2-like update mechanism) that implement interface X.

The application is an Eclipse 3.5-based RCP app, using Spring 2.5.6 and Spring DM 1.2.1.

How do I force these bundles to be activated?

3
Could you provide some informations on the error messages you get? And: Bundle A exports interface X, and Bundle B, C, D import it, right?Andreas Kraft
Yes, interface X is exported by bundle A, and imported by B, C, and D. There aren't any error messages. The query for services implementing X in the service registry just returns an empty list.Paul Schifferer
What's the cardinality you're requesting in A? If it's 1..N you have a circular dependency.Mark Elliot
The cardinality in A is 0..N. Could you elaborate on how 1..N causes a circular dependency? I don't quite understand that.Paul Schifferer
If it were 1..N you'd require an instance from bundles B and C before you could start A, but B and C have a strict dependency on A, so none of the bundles would be able to come up. What happens if you manually refresh A, then B then C?Mark Elliot

3 Answers

6
votes

What you really have is a dependency hierarchy problem, your proposed hacky solution is really just a band-aid over the underlying issue.

What you should really consider is the architecture of your system, as effectively what you have is a circular dependency (re: discussion in comments your original post). You have (like it or not) A requires services from (and in some sense depends on) B and C. Meanwhile, B and C directly depend on A, and as such, cannot start until A comes up.

In the best case, you can write code in B and C to listen for the existence of A, but this at best masks (as I mentioned) the underlying issue. What you should really consider is splitting A into two bundles, let's call them A1 and A2.

A1 should provide the interface which B and C require (depend on). A2 should have listeners for the services B and C depend on. At startup, if B and C are required services, A1 must be run, but A2 may start any time later, and everything should work.

0
votes

I think I've found the solution to this problem, though it feels a bit hackish.

I ran across this thread where Adrian Colyer implied that an external "bundle watcher" could be responsible for activating bundles when they are installed into the framework.

So, my solution was to:

  • Add a custom header to bundle B, C, and D's respective manifests, e.g., "MyApp-AutoStart: true"
  • Create a bundle listener that responds when a bundle is moved into the RESOLVED state, and looks for the header
  • If the header's value is "true," the bundle listener calls bundle.start()

Using this method, the bundles I want to be started are started without having to resort to using config.ini, and they can come and go as they please, but their services are available when queried.

0
votes

Also have a look at felix fileinstall, which watches a directory for bundles and automatically installs and starts them. When a file is deleted, the bundle is stopped and uninstalled as well.