dev@glassfish.java.net

Re: Classloading strategy for OSGi <was> Fwd: [Jersey] Jersey in Felix

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Fri, 05 Dec 2008 10:53:45 +0100

Hi Roberto,

Thanks, that is exactly the kind of thing i was looking for. I need to
update Jersey to do exactly the same and we need to update the 311 jar
as well.

Paul.

On Dec 4, 2008, at 9:23 AM, Roberto Chinnici wrote:

> Paul,
>
> Section EE.8.2.5 of the platform spec contains a code snippet
> showing how to load a class dynamically.
> This snippet was updated in the Java EE 6 spec (Early Draft)
> following some experiments I ran with different OSGi implementations.
> For your convenience, here's the code:
>
> Helper method:
>
> public ClassLoader getContextClassLoader() {
> return AccessController.doPrivileged(
> new PrivilegedAction<ClassLoader>() {
> public ClassLoader run() {
> ClassLoader cl = null;
> try {
> cl =
> Thread.currentThread().getContextClassLoader();
> } catch (SecurityException ex) { }
> return cl;
> }
> });
> }
>
> Code snippet to be used by libraries:
>
> ClassLoader cl = getContextClassLoader();
> if (cl != null) {
> try {
> clazz = Class.forName(name, false, cl);
> } catch (ClassNotFoundException ex) {
> clazz = Class.forName(name);
> }
> } else {
> clazz = Class.forName(name);
> }
>
> Please let me know whether this works for you.
>
> --Roberto
>
> Paul Sandoz wrote:
>>
>> Hi,
>>
>> In the email below Richard is attempting to:
>>
>>> embed the Jersey jars within my bundle
>>> and not have any of the Jersey services exported, just have the
>>> bundle
>>> be a self contained module that registers a Servlet as a service
>>> to be
>>> picked up by the web container.
>>
>>
>> In the JSR-311 jar the method:
>>
>> javax.ws.rs.ext.RuntimeDelegate.getInstance()
>>
>> will attempt to obtain an instance of RuntimeDelegate by loading a
>> class using the class loader returned from
>> Thread.currentThread().getContextClassLoader().
>>
>> Richard states:
>>
>>> The problem
>>> is that the Thread class loader is the application classloader, not
>>> the bundle class loader.
>>
>> proposes a work around:
>>
>>> The
>>> simplest solution is to wrap the initialization code in something
>>> that
>>> sets the threads context class loader to the bundles class loader.
>>
>>
>> and a possible solution:
>>
>>> In situations like this I've often seen a
>>> policy of trying to find a classloader that can load the requested
>>> class by starting with the getClass().getClassLoader() class loader,
>>> then trying the Thread class loader and finally trying the system
>>> class loader.
>>
>>
>>
>> Do any OSGi experts on the list have any advice w.r.t. to the such
>> strategies.
>>
>> Paul.
>>
>> Begin forwarded message:
>>
>>> From: Richard Wallace <rwallace_at_thewallacepack.net>
>>> Date: December 1, 2008 10:19:45 PM CEST
>>> To: users_at_jersey.dev.java.net
>>> Subject: Re: [Jersey] Jersey in Felix
>>> Reply-To: users_at_jersey.dev.java.net
>>>
>>> On Mon, Dec 1, 2008 at 2:40 AM, Paul Sandoz <Paul.Sandoz_at_sun.com>
>>> wrote:
>>>> Hi Richard,
>>>>
>>>> On Nov 30, 2008, at 1:14 AM, Richard Wallace wrote:
>>>>
>>>>> Hey all,
>>>>>
>>>>> I'm trying to get Jersey working in Felix and I'm running into a
>>>>> few
>>>>> problems.
>>>>
>>>> Is w.r.t. to utilizing Jersey without specific support in GF v3
>>>> prelude? for
>>>> example i understand that GF has support for META-INF/services.
>>>>
>>>> We realize we have to do some more work to improve on the OSGi
>>>> integration.
>>>> For example currently for GF we rely on the jersey-bundle.jar and
>>>> IIRC
>>>> pretty much every package is exported. The reason being is that
>>>> although
>>>> Jersey was split into several maven modules the package
>>>> boundaries between
>>>> them were not cleanly defined. This has been fixed now so that
>>>> modules only
>>>> depend on API/SPI packages of other modules and there is no
>>>> package names
>>>> shared between modules. For the 1.0.2 release we hope to add
>>>> proper OSGI
>>>> information to each module.
>>>>
>>>> If there is any overlap between what you have done and what we
>>>> would like to
>>>> do perhaps we can share the details on what additional work you
>>>> needed to
>>>> do?
>>>>
>>>
>>> Sorry. I should have described the use-case a bit more clearly.
>>> What
>>> I'm trying to accomplish is to embed the Jersey jars within my
>>> bundle
>>> and not have any of the Jersey services exported, just have the
>>> bundle
>>> be a self contained module that registers a Servlet as a service
>>> to be
>>> picked up by the web container.
>>>
>>>>
>>>>> I've solved most of them but the one I'm running into now
>>>>> is possibly a showstopper. In the FactoryFinder.find() method
>>>>> of the
>>>>> jsr311-api jar there is this call to get the class loader.
>>>>>
>>>>> classLoader =
>>>>> Thread.currentThread().getContextClassLoader();
>>>>>
>>>>
>>>> The context class loader is used consistently throughout Jersey to
>>>> dynamically load classes: stuff from META-INF/services and
>>>> classes from
>>>> names when class scanning for root resource and provider classes.
>>>>
>>>
>>> My question was more meant to find out if it is used outside the
>>> scope
>>> of the initialization? I don't think it is (except for maybe on
>>> reload which I'm not worried about at the moment) because I've
>>> managed
>>> to get things up and running pretty well.
>>>
>>>>
>>>>> The problem is that the thread class loader is not the bundle
>>>>> class
>>>>> loader so this fails to find the RuntimeDelegationImpl class.
>>>>
>>>> And the RuntimeDelegationImpl will be in another bundle?
>>>>
>>>
>>> No, everything that Jersey needs is in the same bundle. The problem
>>> is that the Thread class loader is the application classloader, not
>>> the bundle class loader. In situations like this I've often seen a
>>> policy of trying to find a classloader that can load the requested
>>> class by starting with the getClass().getClassLoader() class loader,
>>> then trying the Thread class loader and finally trying the system
>>> class loader. It seems that that would make sense here as well.
>>>
>>>>
>>>>> The
>>>>> simplest solution is to wrap the initialization code in
>>>>> something that
>>>>> sets the threads context class loader to the bundles class loader.
>>>>> I'm worried that even if this works for the startup code, it may
>>>>> cause
>>>>> problems down the line. Any tips?
>>>>>
>>>>
>>>> Hmm... i must admit to not being an expert in the class loading
>>>> esoteric
>>>> nature of the JVM and how OSGi works in this respect. So it is
>>>> hard for me
>>>> to know what problems, if any, this might induce. What types of
>>>> problem
>>>> might you expect? What should i be looking for?
>>>>
>>>
>>> I was just wondering if the Thread class loader is used past
>>> initialization is all. It doesn't look like it is and this could be
>>> easily fixed by using the class loader searching I described above.
>>>
>>> Another thing that would be nice, while I'm on the subject, is to
>>> split any implementations up. For instance, I'm using the Grizzly
>>> web
>>> server but because the httpserver integration code is bundled in the
>>> same jar I have no way of excluding it and have to specifically
>>> configure the maven-bundle-plugin to ignore anything that imports
>>> com.sun.net.httpserver.* which is rather annoying.
>>>
>>> I look forward to seeing how things turn out with Jersey 1.0.2 and
>>> making Jersey work better in an OSGi environment. I do have a
>>> use-case coming up where it would be very nice to have a Jersey
>>> bundle
>>> deployed which uses the whiteboard pattern so other bundles could
>>> register resources to have them picked up automatically, rather than
>>> having to have to create a separate ServletContainer instance for
>>> each
>>> bundle that will want to use Jersey.
>>>
>>> Thanks,
>>> Rich
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>
>