dev@glassfish.java.net

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

From: Roberto Chinnici <Roberto.Chinnici_at_Sun.COM>
Date: Thu, 04 Dec 2008 09:23:29 +0100

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
>> <mailto:rwallace_at_thewallacepack.net>>
>> *Date: *December 1, 2008 10:19:45 PM CEST
>> *To: *users_at_jersey.dev.java.net <mailto:users_at_jersey.dev.java.net>
>> *Subject: **Re: [Jersey] Jersey in Felix*
>> *Reply-To: *users_at_jersey.dev.java.net <mailto:users_at_jersey.dev.java.net>
>>
>> On Mon, Dec 1, 2008 at 2:40 AM, Paul Sandoz <Paul.Sandoz_at_sun.com
>> <mailto: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
>> <mailto:users-unsubscribe_at_jersey.dev.java.net>
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>> <mailto:users-help_at_jersey.dev.java.net>
>>
>