aries-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Bartosz Kowalewski <>
Subject Re: SPI-Fly and provider-configuration file names that are different than the abstract service class
Date Mon, 14 Jun 2010 20:56:04 GMT
Hi David,

Your approach is much cleaner than my headache-causing fragment-based
one. It doesn't leave any resources that could be messed up by the
user, while in the approach that I described anybody could uninstall
those fragments. Moreover, the AOP-based solution enables one to use
different implementations simultaneously. This would not be possible
with the fragment based approach which would cause a single provider
to be attached to the API bundle.

A few thoughts off the top of my head (these might potentially be drawbacks):
1. There are many different mechanisms that would need to be wrapped
with aspects: ServiceLoader, FactoryFinders in several packages,
ContextFinder (JAXB), javax.mail.Session which (as far as I know)
loads resources directly from a classloader - without any finder
class. The ugly fragment-based approach would probably handle all
these cases in the same (uniform) way.
2. A general comment to libraries using SPI: Some of them might not be
prepared to cleanly handle a dynamic environment where classes
(bundles, providers) come and go. I think that the javamail library
uses some kind of a caching mechanism to optimize loading
configuration the second time it is called. As far as I remember it
keeps a mapping from context classloader <-> some class.

Best regards,

2010/6/14 David Bosschaert <>:
> Hi all,
> On 11 June 2010 16:25, David Bosschaert <> wrote:
>> The main trick around the FactoryFinder/ServiceLoader is to set the
>> Thread Context classloader to the right classloader when
>> FactoryFinder.find()/ServiceLoader.load() is invoked. Although
>> ServiceLoader.load() has an overload that accepts a classloader we
>> can't assume that all clients use it.
>> You have already provided a fairly painful idea to how an
>> implementation could work (or not as the case might be;). Another idea
>> would be to declare in the bundle manifest what SPIs are being used
>> (remember we *can* modify the bundle manifest, we might be writing an
>> OSGi bundle or bundelizing a non-OSGi jar). Maybe some entity could
>> intercept the ServiceLoader.load() calls using some AOP tricks and set
>> the Thread context classloader to the one specified in the bundle
>> manifest for the duration of that call. The bundle would have to have
>> the right set of imports and this would possibly bind the bundle to
>> one particular SPI impl but then again that would highlight the
>> benefit of using the OSGi Service Registry instead...
>> Again the above is just another wild idea to add to the mix... I might
>> do some experimentation to see how far I can get this...
> I did some experiments with AOP and ended up using AspectJ for my
> prototype because it works with Equinox. Weaving is not supported in a
> standard way yet across all the OSGi frameworks but that's something
> that is being worked on in the OSGi alliance through RFP 139.
> Here's what I was able to do:
> I wrote a simple SPI for use with the JRE java.util.ServiceLoader
> (which are typically realized via an abstract class):
>  public abstract class SPIProvider {
>    public abstract void doit();
>  }
> I put an implementation of this SPI in a bundelized jar that
> advertises this SPI as any JRE SPI would: via a
> META-INF/services/...SPIProvider file which holds the name of the impl
> class.
> Then in the activator of my client bundle I was able to obtain the
> service using normal ServiceLoader calls:
>  public class Activator implements BundleActivator {
>    public void start(BundleContext context) throws Exception {
>      ServiceLoader<SPIProvider> ldr = ServiceLoader.load(SPIProvider.class);
>      for (SPIProvider spiObject : ldr) {
>        spiObject.doit(); // invoke the SPI object
>  } } }
> So you can see, nothing special here. Existing clients can load the
> SPI the way they have always been, which is essential if you're
> integrating a library for which you don't have the source.
> To get ServiceLoader to load the the service through the right
> classloader I wrote an aspect that wraps the actual
> ServiceLoader.load() call and sets the ThreadContext for the duration
> of the call. What it should set the classloader to is figured out via
> an OSGi Service that I introduced: SPIClassloaderAdviceService. The
> aspect invokes on the service to ask it what classloader should be
> used for a particular SPI class. I can get to the Service Registry
> from the aspect through the BundleReference API.
> aspect BundleAspect {
>  pointcut serviceloader(Class cls) :
>    args(cls) && call(ServiceLoader ServiceLoader.load(Class));
>  ServiceLoader around(Class cls) : serviceloader(cls) {
>    /* details ommitted, use cls.getClassLoader() as
>       BundleReference to get to ServiceRegistry... */
>    SPIClassloaderAdviceService svc = ... // obtain from OSGi Service Registry
>    ClassLoader targetLoader = svc.getServiceClassLoader(cls);
>    ClassLoader prevCl =
> Thread.currentThread().getContextClassLoader();
>    try {
>      Thread.currentThread().setContextClassLoader(targetLoader);
>      return proceed(cls);
>    } finally {
>      Thread.currentThread().setContextClassLoader(prevCl);
> } } }
> The SPIClassloaderAdviceService needs to be configured somehow. In my
> prototype I let the SPI wrapper bundle register it, a bit like
> OSGiLocator in the SMX bundles, but it could also be configured purely
> declaratively through an extender that reads specific instructions
> from the manifests of wrapped bundles.
> I can see two disadvantages to the approach:
> 1. It requires weaving support in OSGi. But hopefully that will be
> there in a standard way by the next OSGi release.
> 2. My current strategy is global. However it should be possible to
> create a strategy that takes the calling bundle into account so you
> can say for SPI x bundle a should use x1 and bundle b should use x2...
> Thoughts anyone?
> Best regards,
> David

View raw message