dev@glassfish.java.net

Re: [v3] exporting all Metro packages for OSGi

From: Richard S. Hall <heavy_at_ungoverned.org>
Date: Wed, 27 Aug 2008 08:59:00 -0400

Fabian Ritzmann wrote:
> On 27. Aug 2008, at 15:28, Richard S. Hall wrote:
>> Fabian Ritzmann wrote:
>>> On 27. Aug 2008, at 13:49, Sahoo wrote:
>>>
>>>> No, I still don't understand why we are seeing failures. My
>>>> understanding is that Metro is a OSGi bundle and some code in that
>>>> OSGi bundle is attempting to load another non-exported class from
>>>> the same OSGi bundle using a variant of Class.forName() that does
>>>> not take any classloader as argument. In such a case,
>>>> Class.forName() uses caller's classloader, which is the classloader
>>>> of the Metro bundle. Such a class loader should be able to load any
>>>> class that's part of Metro bundle.
>>>>
>>>> There are two assumptions here:
>>>> 1. Class being loaded is part of Metro OSGi bundle.
>>>> 2. No classloader is passed to Class.forName().
>>>>
>>>> Is any of them wrong?
>>>
>>> Both assumptions are correct. I better leave it to Richard to
>>> explain why Class.forName(String name) is not doing what we are
>>> expecting.
>>
>> It is not my understanding of the situation, but I could be incorrect.
>>
>> I understood the situation to be something like this:
>>
>> Bundle A has a non-public service impl class. Bundle B tries to load
>> that class using Class.forName() using a class loader that tries to
>> load from all exported packages. Since Bundle A's class is not
>> imported, Bundle B does not find it. Failure. However, if Bundle A
>> exports the service impl class, then the class loader from Bundle B
>> can find it. Success.
>>
>> I agree with Sahoo, if it is the same bundle (or you are using
>> Bundle.loadClass()), you should be able to find the class no matter
>> what, which is why I called into question this situation and started
>> investigating it in the first place. But obviously the situation must
>> be different than this, otherwise we wouldn't be seeing the issue.
>
> The stack trace we were looking at was this:
>
> Aug 25, 2008 4:00:46 PM
> [com.sun.xml.ws.policy.privateutil.ServiceFinder] access$100
> SEVERE: [failed to localize]
> WSP_0025_SPI_FAIL_SERVICE_MSG(com.sun.xml.ws.policy.spi.PolicyAssertionValidator,
> [failed to localize]
> WSP_0027_SERVICE_PROVIDER_NOT_FOUND(com.sun.xml.ws.transport.tcp.wsit.TCPTransportPolicyValidator))
>
> java.lang.ClassNotFoundException:
> com.sun.xml.ws.transport.tcp.wsit.TCPTransportPolicyValidator
> at
> org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1504)
>
> at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
> at java.lang.Class.forName0(Native Method)
> at java.lang.Class.forName(Class.java:247)
> at
> com.sun.xml.ws.policy.privateutil.ServiceFinder$LazyIterator.next(ServiceFinder.java:378)
>
> at
> com.sun.xml.ws.policy.privateutil.ServiceFinder.toArray(ServiceFinder.java:228)
>
> at
> com.sun.xml.ws.policy.privateutil.PolicyUtils$ServiceProvider.load(PolicyUtils.java:445)
>
> at
> com.sun.xml.ws.policy.AssertionValidationProcessor.<clinit>(AssertionValidationProcessor.java:55)
>
>
>
> All the com.sun.xml.ws.policy and com.sun.xml.ws.transport classes as
> well as the META-INF/services file are in the same bundle.
>
> FWIW, it's quite possible that we will bump into service instantiation
> scenarios across bundles sooner or later, but in that case I guess an
> export is the only and proper solution anyway.

Still, and correct me if I am wrong, I was told yesterday that this uses
Class.forName() with org.glassfish.web.loader.WebappClassLoader, so for
this to be successful it depends on how WebappClassLoader works, which I
was told loads from all exported packages.

Thus, the fact that it only works if it is exported makes sense if
WebappClassLoader only loads from exported classes.

-> richard

>
> Fabian
>
>
>>>> Fabian Ritzmann wrote:
>>>>> Hi,
>>>>>
>>>>> Richard has had a look at some of the class loading issues we have
>>>>> had with the Metro bundles. Here is my summary as I understand it
>>>>> and some more comments and questions:
>>>>>
>>>>> Metro code is using Class.forName(String className) to dynamically
>>>>> load classes. In an OSGi environment, these classes usually can
>>>>> not be found unless the packages are explicitly imported. We
>>>>> bumped into this issue when doing META-INF/services look-ups but
>>>>> there are almost certainly other scenarios where this will lead to
>>>>> ClassNotFoundExceptions. GlassFish implemented the
>>>>> WebappClassLoader, which in addition to the OSGi classloaders is
>>>>> loading all classes that are exported. That is why an export of
>>>>> all classes solves the issue for us [1].
>>>>>
>>>>> Richard suggested a few approaches to solve this issue without
>>>>> exporting everything:
>>>>>
>>>>> 1) Replace calls to Class.forName(String className) with
>>>>> Bundle.loadClass(String name).
>>>>>
>>>>> 2) Create a ClassLoader wrapper for Bundle.loadClass.
>>>>>
>>>>> I believe 2) is already close to what we are doing with the
>>>>> WebappClassLoader. 1) doesn't really work for us because Metro
>>>>> libraries are used in a variety of environments, most of which we
>>>>> don't have any control over, and we can't introduce dependencies
>>>>> on OSGi.
>>>>>
>>>>> I believe another solution could be if we manually added the
>>>>> packages in question to the Import-Package manifest header? I am
>>>>> not very comfortable however with checking dozens of libraries for
>>>>> their use of dynamically created classes. The risk that we will be
>>>>> missing some package and it slips through testing is high.
>>>>>
>>>>>
>>>>> Fabian
>>>>>
>>>>>
>>>>> [1] Plus the bnd tool we are using is creating an import statement
>>>>> for every package that is being exported, i.e. by exporting
>>>>> everything we are making sure that all dynamically loaded classes
>>>>> are getting imported as well.
>>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: dev-help_at_glassfish.dev.java.net
>