Community
Participate
Working Groups
During startup, EclipseStarter initializes a ContextFinder and sets its parent as the current thread context classloader. However under WebStart, the context classloader at this point is com.sun.jnlp.JNLPClassLoader. That loader has visibility of all downloaded JARs - ie ALL the bundles. Therefore when ContextFinder consults its parent classloader under WebStart, the JNLPClassLoader will always supply it, we never get it from a BundleLoader. This can cause problems when using things like dynamic proxies, because the class loaded by the JNLPClassLoader will not be equal to the one loaded by the BundleLoader (even if they came from the same physical JAR) and therefore you get an exception that looks like this: java.lang.IllegalArgumentException: interface org.springframework.aop.framework.Advised is not visible from class loader at java.lang.reflect.Proxy.getProxyClass(Proxy.java:353) at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:581)
Created attachment 38613 [details] patch relative to tag v20060328 (3.2M6) The attached patch fixes the problem by detecting the JNLPClassLoader and, if seen, calling the no-arg ClassLoader constructor on ContextFinder. Tested with both a standalone app and a WebStart app, but not exhaustively.
*** Bug 110741 has been marked as a duplicate of this bug. ***
Tom could you please take a look at this? I encountered this pb a while back better never had the opportunity to look into a fix (see dup bug). I quickly looked at the patch and I'm a bit worried that everything gets removed from the context finder, since their might be classes (not from plug-ins) that are needed by the app. Moreover we would have a very different behavior when running with jnlp and with not, which we would want to avoid. What about parenting the context finder with a filtered version of what's on the jnlp classloader so that we only get non-bundles. Note that we have the list of bundles in the osgi.bundles. Neil could you help?
Pascal, I will help out wherever I can. The patch is admittedly naive and I didn't understand the full implications - it just got my app working. The filtering classloader is interesting, but sounds difficult to achieve. We would presumably still need JNLPClassLoader as our ultimate parent, because only it knows where all the JARs are. However if we delegate to JNLPClassLoader and it returns a class, how do we know whether it came from a bundle JAR - even given that we know the list of bundles? It sounds like we would have to build a list of classes in all bundles, and only accept a class loaded by our parent if it was not on that list. Note also that the problem only happens with "flat" bundle JARs. JNLPClassLoader can't see into nested JARs.
What if we took a child first approach in the ContextFinder? In other words we would search the OSGi loaders first then the parent (original context loader) as a last resort. This would allow the ContextFinder to get the class from the Framework before the JNLPClassLoader.
Filtering the parent classloader or changing to child-first would be too much change for 3.2 right now ... We should look for a "simple" solution for 3.2. Current thinking is to add an option which can be used specify the parent classloader of ContextFinder. In WebStartMain we would set this property to force boot to be used unless it is already set to some other value in the config.ini. A slight variation would be not to set the property in WebStartMain (this would use the current behavior) and force JNLP apps to set the value explicitly in their config.ini.
Created attachment 38689 [details] patch This patch introduces a new property to specify the context class loader parent "osgi.contextClassLoaderParent". The default is the current behavior (which is to use the current context classloader as the parent). The osgi.contextClassLoaderParent property can be set to the following app - use the application classloader ext - use the extension classloader boot - use the boot classloader fwk - use the framework classloader ccl or <null> or any other value - use the current context class loader There are similar values that can be specified on the osgi.parentClassloader property. This patch makes the default for WebStartMain use osgi.contextClassLoaderParent="app". I do not know all the side-effects of such a change. Maybe we should just leave WebStartMain as-is (default to <null>) and deployments have to option of setting the value to "app" in their config.ini.
(In reply to comment #7) I can confirm that this patch fixes the issue I was having when using dynamic proxies under WebStart. I did not bother applying the patch to WebStartMain, I just put osgi.contextClassLoaderParent=app into my JNLP. Thanks
+1 to only add the optional property osgi.contextClassLoaderParent and leaving WebStartMain unchanged. Jeff, do you approve?
Just a comment... I'm doing something very similar for the CCL with the server-side stuff. I wonder if it would make sense to move the CCL initialization code into the framework?
I think the CCL init code is in the framework. As I understand this proposal it is ot add that code to the framework and leave the webstart main alone. Then people who have webstart prblems can set the right property. +1 for that behaviour See also bug 137608 for some discussion on directions for startup code...
Sorry, yes you're right it's in the framework not the launcher which is what I was hoping for. So... great, I'll use it. Thanks.
Fix released for RC2. (no change to WebStartMain)