Hi Rob- I've been struggling with the same problem.
In fact, I'm guessing that this Service Provider classpath/classloader hackery (made into a crazy best-practice by its inclusion in JDK 6 as the java.util.ServiceLoader) is one of the main reasons why OSGi isn't as widely adopted as it should be- OSGi is a little complicated to begin with, and you have to bundle-ize a bunch of other people's libraries, and then you get hit with these situations where some stuff looks like it just won't work at all. I also did some googling. A few people out there are trying to adapt to the Service Provider pattern for use in an OSGi context. This guy's post was discussed in a few places: http://gnodet.blogspot.com/2008/05/jee-specs-in-osgi.html His strategy seems to be to use the "OSGi Extender" pattern, which basically means you write some code which registers a BundleListener with the container, and checks every bundle for specific resources contained within. (This type of thing is used, for instance, by Spring DM (dynamic modules), to look for bean configuration XML files in bundles from which to create Spring contexts from, and to auto-register various osgi services.) As you know, the ServiceLoader API used by a lot of java libraries involves files in META-INF/services/ where the file name is the fully-qualified name of a provider interface or base class, and the contents of the file is class names of implementations or factories. The idea in the linked article above is that his code inspects the jar file of each bundle (not the same as it's classloader, uses bundle.findEntries()) for META-INF/services/*, reads the content, and creates a lookup table (of Provider interfaces to implementation class names) in a static member of a public class. The kicker is that he then modifies the original libraries(!) to check this lookup table before doing their regular discovery process, so that the can find the implementation classes. (specifically he saves information about the original bundle which provides this metadata, and then he uses that bundle, when requested, to load the Class of the provider implementation, to be passed to the provider loader. Then instances of these classes can be created via reflection or Class.newInstance()). This is clever, but not very appealing. And it's not helpful in cases where you can't (or don't want to) create modified versions of standard tool distributions. But there's a bigger problem here. The ServiceLoader model has no lifecycle! It's based on the unchanging static classpaths used by traditionaly executed java programs. This seems fundamentally incompatible with the dynamic lifecycles supported by OSGi, for both bundles and services. Using archive metadata to passively communicate the class names of service implementations doesn't leave room for what happens when, in OSGi, the bundle goes away- the API libraries which use this pattern aren't written to ever _unload_ these implementations. The only times they work is when they happen to be written to simply re-execute the metadata search each time they're asked for an implementation, which probably shouldn't be relied on. In OSGi, the main mechanisms used for sharing functionality across bundles is exporting a package or registering a service. It seems like we should try to use these primary OSGi mechanisms before resorting to code that pilfers the archive entries of other bundles looking for metadata. The only other mechanism which is less frequently discussed is the use of bundle Fragments. (Fragments get folded into the classloader and archive "entries" of a parent bundle at runtime.) I think that the preferable solution in a particular situation (if a solution exists at all) depends on 1) what the relationship is between API and implementation, and 2) which code you have the ability to deploy changes to. If you have the ability to deploy changes to either/both the api and impls, then I think it's more straightforward: If the client code needs to consume potentially more than one implementation of an API, or must choose just one implementation but doesn't care which one, then the API should just be a library and not engage in service discovery at all. Impls should be registered in the OSGi service registry, and client code should use ServiceTrackers (or the like) to select one or more services. This allows for the full dynamism of OSGi. If the client code needs to consume a _specific_ single impl of an API (like choosing an XML parser implementation), then it can just import and use that implementation directly, using package dependency declarations. Another option is to package up the API and the implementation in the same bundle (and allow them to use whatever discovery mechanism they want). A variation of this might be to use bundle Fragments, where the impls become Fragments and the API is the "host" bundle. While they become effectively the same bundle, the fragment method allows deployment-time selection of an implementation without creating a specific dependency in the client code. If you have the ability to change the API bundle but the impl bundles still expect to use the traditional ServiceLoader pattern, then doing something like the blog post above seems okay. If you have the ability to change the Impl bundles, but not the API bundle, then you may be able to write an Activator in each of the impl bundles which manually calls impl-registration methods (if any are available) in the API bundle. For instance, it looks like in Restlet you can manually call engine.getRegisteredServers().add() in order to register a ServerHelper extension. (note: I haven't tried this). If you can't modify either the API or the Impls, but the API has manual registration methods available, you could write a seperate helper bundle which uses the above-mentioned Extender pattern and by-hand registers what it finds with the API bundle. I'm not sure any of what I've written here will be helpful to you, but since we're both struggling with the same thing, I figure it'd be good to get my current thoughts on this typed up. -Dave Fogel ------------------------------------------------------ http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1331460