Hi Bartek,

Thanks for responding...

What I'm trying to do at the moment is come up with a mechanism that
is easy to use for the simple case but still having the expressiveness
to handle the more complex cases, so I definitely hope we can support
all the required cases with it, hopefully we can enhance it to cover
your cases too.

On 28 December 2010 21:28, Bartosz Kowalewski
<[email protected]> wrote:
> Hi David,
>
> Sorry for the late response :-).
>
>> There is a more specific variation to this, e.g.:
>> SPI-Consumer: java.util.ServiceLoader#load(java.lang.Class);bundle=impl2,...
>> Says that the ServiceLoader.load() call should only see services
>> provides by impl2.
>
> ServiceLoader is a class/mechanism that is reused by different APIs.
> If we really want to provide the consumer bundle with an ability to
> specify providers for each of APIs, this is probably not the right way
> to go. If consumer uses two APIs that employ ServiceLoader when
> looking up providers and providers that this consumer needs are
> shipped in separate bundles, the consumer would not be able to tell
> SPi-Fly what providers are needed.

I actually did some more work since I wrote my email on Dec 14th :),
with that you have a number of levels that you can specify in a
consumer - I'm listing them all here in increasing order of complexity
to give the full picture:

SPI-Consumer: true
SPI-Consumer: java.util.ServiceLoader#load(java.lang.Class)
These two are synonyms and this is the simplest case and it will
simply enable all available providers for a given ServiceLoader.load()
API. You already said that this is not good enough for your use-case.

SPI-Consumer: 
java.util.ServiceLoader#load(java.lang.Class);bundle=impl2|impl3;bundleId=0
This is a slightly more specific version of the previous one. It still
doesn't specify which API's in ServiceLoader.load() goes where, it
simply specifies that any of them can come from bundle impl2, impl3 or
the system bundle. I understand that this doesn't cover your use-case
either.

SPI-Consumer: 
java.util.ServiceLoader#load(java.lang.Class[org.acme.api.MySPI]);bundle=impl2,java.util.ServiceLoader#load(java.lang.Class[org.acme.alt.MyAltAPI]);bundle=impl3|impl4
This is a new one I've added. This allows you to specify that
ServiceLoader.load() requests for MySPI can only come from impl2 while
ServiceLoader.load() requests for MyAltAPI can only come from impl3 or
impl4.

You can also use the header with legacy API's or add version
information to the Bundle Symbolic Name, e.g.:
SPI-Consumer: 
javax.xml.parsers.DocumentBuilderFactory#newInstance();bundle=apache-xerces:version=2.10,java.util.ServiceLoader#load(java.lang.Class[org.acme.api.MySPI]);bundle=impl2:version=[1.1,2.0)
This would select JAXP (via DocumentBuilderFactory.newInstance()) from
a bundle with BSN apache-xerces and version 2.10. ServiceLoader.load()
requests for MySPI are selected from any bundle with Symbolic Name
impl2 and a bundle-version from 1.1 up to (but not including) 2.0.
(BTW I haven't fully settled on the actual syntax yet...)

I hope that this starts to address the non-simplistic use-cases that
you are thinking of. I think it at least should start to address some
of the examples you are mentioning. If you have any other cases that
aren't covered yet, I'd love to hear them!

Best regards and happy new year!

David

On 28 December 2010 21:28, Bartosz Kowalewski
<[email protected]> wrote:
> Anyway, I think that only implementing the simplistic approach - where
> SPI-Fly decides what provider to choose and consumers cannot influence
> this process - would not be enough. While this is (as far as I
> remember) the way SPI like mechanisms work in ServiceMix specific
> versions of well-known APIs, I can imgaine a situation when somebody
> wants to migrate a set of their Java applications so that they run
> inside a single OSGi container. These apps were previously run as
> separate Java processes and used different providers for some APIs.
> Now they cannot run such a configuration inside a single container.
> I feel that SPI-Fly should provde means to solve such issues. I know
> that the problem is not trivial, however, I hope it will get solved
> :). Some time ago I contributed a sample solution for a situation when
> there are many providers. It was overly complex => the problem is
> definitely not trivial :-).
>
> Kind regards,
>  Bartek
>
> 2010/12/14 David Bosschaert <[email protected]>:
>> Hi all,
>>
>> I have been experimenting a little bit more with the SPI Fly code. In
>> the directory spi-fly/contrib/pilot_using_weavinghook I've created a
>> bunch of new Eclipse projects which use the standard OSGi WeavingHook
>> to weave the code. Additionally I moved from AspectJ to ASM for the
>> bytecode weaving. I have been thinking about what we'd really want in
>> terms of behaviour.
>>
>> For those who don't know about the SPI-Fly component in Aries, it's
>> aimed at making META-INF/services based providers and consumers work
>> in OSGi.
>>
>> * Provider Registration *
>> Provider bundles opt-in using the
>>  SPI-Provider: true
>> header.
>> Once opted in, SPI Fly simply registers any SPI it can find in the
>> bundle, by looking at the META-INF/services directory and registering
>> all the services it can find there in the Service Registry. At the
>> moment it sets one service property: spi.provider.url=<url pointing to
>> the relevant META-INF/services/... file>
>> That property could be useful in that it contains proof of where the
>> service came from and its simple existence shows that it's created
>> from a META-INF/services definition. However, I couldn't think of any
>> other property to add. Any suggestions here?
>> Also, is opting in like this is sufficient? Or do we want to support
>> more details in the SPI-Provider header, maybe the option to limit the
>> SPIs provided by the bundle?
>>
>> * Consumers *
>> Consumers opt-in using the SPI-Consumer header. The main syntax the
>> code currently has is this:
>>  SPI-Consumer: true
>> This means that any call made to ServiceLoader.load(SomeClass) is
>> wrapped with a ThreadContextClassLoader setting code that sets the
>> TCCL to a classloader that has visibility to *any* bundle that
>> provides the SomeClass service requested. This will make the
>> ServiceLoader.load() call work in general*.
>> There is a more specific variation to this, e.g.:
>>  SPI-Consumer: java.util.ServiceLoader#load(java.lang.Class);bundle=impl2,...
>> Says that the ServiceLoader.load() call should only see services
>> provides by impl2.
>> Again, I'm trying to get an idea whether this would be enough. Do we
>> need more expressiveness here?
>>
>> BTW currently I've only tested the this on Equinox, as it's the only
>> framework that I'm aware of that currently supports the Weaving Hooks,
>> as this is part of the OSGi 4.3 core spec I expect other frameworks to
>> start supporting this in the near term.
>> BTW2 I didn't really take 'legacy' service that don't use
>> ServiceLoader.load() yet. That's on the to-do list :)
>>
>> Ideas welcome! Thanks!
>>
>> David
>>
>> * My test consumer looks like this, plain simple ServiceLoader.load() usage:
>>  ServiceLoader<SPIProvider> ldr = ServiceLoader.load(SPIProvider.class);
>>  for (SPIProvider spiObject : ldr) {
>>    spiObject.doit(); // invoke the SPI object
>>  }
>>
>

Reply via email to