Community
Participate
Working Groups
Migrated from internal bugzilla: Originator: Jeff McAffer Open Date: 8/20/2003 Original Text: Moving an email discussion to bugzilla for tracking... BJ Hargrave@IBMUS 08/20/2003 10:29 AM To: Jeff McAffer/Ottawa/IBM@IBMCA cc: Pam Tobias/Austin/IBM@IBMUS, Pascal Rapicault/Ottawa/IBM@IBMCA, Thomas Watson/Austin/IBM@IBMUS From: BJ Hargrave/Austin/IBM@IBMUS Subject: Re: resolve issue The SMF system bundle is the framework. The classloader which loads the framework should be the parent classloader for all bundles. The framework export all packages on (1) the Export-Package manifest header in SYSTEMBUNDLE.MF and the property <something>.systempackages so that bundles which import these packages can resolve. The bundles which resolve against package which are exported by the framework do not have reference to the system bundle in there ImportClassLoader because the system bundle is not a real bundle with a real bundle classloader. These bundles find the classes in these package via there parent classloader which should be the classloader of the framework. BJ Hargrave Senior Software Engineer, IBM Pervasive Computing - Austin, TX OSGi Fellow and CTO of the OSGi Alliance mailto:hargrave@us.ibm.com 902/6C-003 T/L 678-9938 Office: +1 512 838 9938 Mobile: +1 512 785 7386 Jeff McAffer@IBMCA 2003-08-20 01:31 AM To: Pam Tobias/Austin/IBM@IBMUS cc: BJ Hargrave/Austin/IBM@IBMUS, Thomas Watson/Austin/IBM@IBMUS, Pascal Rapicault/Ottawa/IBM@IBMCA From: Jeff McAffer/Ottawa/IBM@IBMCA Subject: resolve issue I am unable to log into bugzilla now (some password problems) and want to get this to you asap... I may be wrong in my expectations but it appears that the packages exported by the system bundle are not included in the resolution process. For example, the org.eclipse.core.runtime bundle imports org.osgi.framework. If you look at the ImportClassLoader for that bundle, the imports hashtable does not contain an entry for that package. As a result, I am failing to find any of those classes. An important point to note is that I am implementing the Eclipse semantics of not using the AppClassLoader. As a result, anything you put on -cp is pretty much ignored. The Eclipse boot sequence goes something like. - run main() from startup.jar (this is on the -cp) - main finds org.eclipse.core.boot and makes a new Classloader(null) i..e, null parent. - the new classloader is used to load BootLoader which is run() via reflection - BootLoader constructs another classloader which has all the OSGi stuff on the classpath and a null parent. - It then calls the OSGi main (whatever) to start. I believe that things are just working now because people have the OSGi jars on the app classpath and the AppClassloader is the parent of everything else. Would it be hard/acceptable to add the import entries or the system bundles? This problem prevents the use of PDE to launch target Eclipses. While not tragic in itself, it is one of the points we talked about (around here) as supporting at M3. Jeff ------- Additional Comment #1 From Jeff McAffer 2003-08-20 15:05 ------- I believe I have worked around this issue by changing BundleLoader as follows (I commented out the code in the static init) static { // syscl = ClassLoader.getSystemClassLoader(); // if (syscl==null) syscl = BundleLoader.class.getClassLoader(); if (syscl==null) throw new Error("INTERNAL ERROR: NO CLASS LOADER AT ALL"); } This makes the syscl be the classloader that loaded the framework. I'm not sure what other affects this will have or even if it really solves my problem but I am getting further now... ------- Additional Comment #2 From bhargrav 2003-08-20 15:47 ------- I removed the commented code. It was put in by Olivier when he modified the classloader structure. A bundle's parent classloader should be the framework's classloader. ------- Additional Comment #3 From Jeff McAffer 2003-08-20 23:21 ------- Thanks for the fix... reopening for futher questions... Having the standard parent be the framework loader is less than optimal. Since the parent is consulted first, this means that all bundles will get full access to the framework implementation simply by referencing the approapriate classes. For example, I put the following in one of my bundles new org.eclipse.osgi.framework.internal.core.BundleMetadata("test"); It worked. Ok, so its no big deal that I can create BundleMetadata object but it demonstrates that the implementation is just hanging out there. I can get framework objects and cast them to their implementations objects and twiddle etc. There is also a performance impact. Since we try for the parent first, the vast majority of classloads will be more costly since the desired class is not in the parent (there are very few OSGi classes compared to the 000's of Eclipse and WSAD classes). Time is wasted consulting more classloaders, jars, dirs, ... for a class we actually know is not there. Given that we have all these required imports/exports to hook this up, I propose that framework exports be treated like all other packages and actually show up in the import lists.
According to the spec I should be forced to import org.osgi.framework if I want to use the framework APIs (and any bundle with an activator does that). Right now, bundles have access to OSGi API classes without having to import their packages in the manifest (see org.eclipse.core.applicationrunner bundle manifest).
A fix has been integrated. The System Bundle now has a real BundleLoader that ImportClassLoaders use to load System Bundle packages from. Any bundle that uses framework packages is now forced to do Package-Imports on these packages. Before this fix bundles were allowed access to the System Bundle packages because the ClassLoader of the framework was used as the delegating parent of all BundleClassLoaders. Now this chain has been broken and we now delegate to the system classloader instead.
I have entered a bug report on Eclipse 2.1.1 that relates to this: https://bugs.eclipse.org/bugs/show_bug.cgi?id=44470 Basically, while I will allow that it *might* be a useful performance optimization to ignore the application classloader during plugin class searches (I would be interested to see actual measurements) it is not correct Java 1.2+ JRE behavior to ignore the extensions class loader. Please see the above bug report. The fix is rather simple: Instead of assigning 'null' as the parent of the eclipse platform's boot classloader, it should assign it the extension class loader as the parent.
Investigating the details in bug 44470 there is a concern that we may step over the extension classloader when loading a class or resource if we don't make the application classloader the parent of our classloaders. This is because the extension class loader is the parent of the app classloader. In equinox we currently get the system classloader like this: syscl = ClassLoader.getSystemClassLoader(); And that becomes the parent that all BundleClassLoaders delegate to. As it turns out this actually returns the Application ClassLoader which is a child of the Extension ClassLoader. So we do not currently step over the extension ClassLoader in equinox. But this does mean we do still search the Application ClassLoader each time a class or resource is loaded. I'm not sure if this is going to hurt us too much in performance since all the application classloader has on it path is the startup.jar. Should we consider making the parent of the classloader returned by ClassLoader.getSystemClassLoader() our delegating classloader?
The application classloader may contain more than just the startup.jar depending on the user settings. The problem with getting the app classloader is more a problem of controling what is made visible more than a performance problem. For example if the app classloader contains an xml parsing library, it will be found and so the xerces provided in eclipse will not be picked up. This may result is runtime problem is the apis are not compatible.
The appclassloader and the extension classloader should not be on the classpath at all. There are too many conflicts between these classes and those in the managed bundles etc. see also bug 30919. Recommend that the parent of the classloaders be null. When our classloader does super.loadClass() this will look in the boot classpath.
I strongly disagree with setting he parent to all the classloaders to null. Applications need to be able to deploy with a controlled JRE configuration. Part of this control means utilizing the Java Extension mechanism. Some systems simply do not work correctly unless the classes are loaded by the Ext classloader. In particular, we are finding issues with various security packages. As a compromise I would think that having a command-line option to allow the platform deployer to switch this
Giving access to the app classloader can jeopardize the behavior of the platform as it has already been explained in various bug reports. Regarding the Java extensions, I agree it might be interesting to have acces to some of them (indeed there is an item in the RFP 44 to find a mechanism to filter the extensions). However, as we've recently seen when we moved to IBM jdk 1.4, conflicts are higher with plugin relying on some specificities of plugins that can be overriden but things available in the java extensions.
I think it is a bit extreme to say that enabling the Ext class loader would 'jeopardize the behavior of the platform'. Unless someone _installs_ a conflicting extension, the behavior is unchanged. The only area of conflict people seem to be able to cite seems to be xerces. It doesn't seem like a huge burden to advise platform deployers to avoid adding an extension that conflicts with this. Even without enabling the ext class loader you are already vulnerable to this via the -XBootclasspath. The fact that you are having trouble with 1.4 VMs that include a conflicting xml parser is in fact the latter issue and keeping the Ext loader disabled is not helping you one bit. Basically, I feel this 'protection' is misdirected. It's like cutting off someone's legs to keep them from jaywalking.
I said app class loader not ext.
In equinox the OSGi framework as decided to leave the it up to the FrameworkAdaptor to determine what each Bundle classloader uses as its parent. By default each Bundle classloader will use the bootstrap classloader as its parent. This will cut the application and extension classloader out of the picture. If an environment requires the parent classloader to be something else (extension, application, or whatever) then a FrameworkAdaptor can be developed to specify the parent of each Bundle classloader that gets created. So now it is in the hands of the EclipseAdaptor to decide what to make the parent of each Bundle classloader for eclipse.
re: comment#11 I like this solution because it gives the application assembler the control needed. It would be preferable to have a simple switch to set this (the obvious options for default parent would be 'null'(boot), 'ext' or 'app'. However, so long as there is SOME means for making this decision at the application assembly phase, then we can make it work. This topic is also discussed on pr#30919 (and briefly on pr#44470)because we need a similar option with the current eclipse 2.1.x framework. In that thread I've proposed the command-line switches: * [default], set parent to 'null', equivalent to using boot loader as parent * -enablejreext , set parent to 'ClassLoader.getSystemClassLoader().getParent()' * -enablejreapp , set parent to 'ClassLoader.getSystemCLassLoader()' see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=30919
I feel it really needs to be said that Eclipse is a platform which may run many different "applications" from the same install at the same time. I belive the notion of application you are using is more traditional. While it is still a valid use of Eclipse, it is not "in the Eclipse spirit". It would be better if the code in questoin were properly componentized and managed as plugins or bundles. I understand that there may be some things which need to be available from particular classloaders. There are other ways around this however. Context classloader and private classloaders spring to mind. Suggesting that application assemblers can change the way Eclipse starts the underlying OSGi framework is not particularly practical as it involves writing a new Starter (the current one is not particularly designed to be extensible) and somehow inserting this into the OSGi framework bundle. Then there is the issue of two different "applicatoin assemblers" who want to do the same thing. Clearly my preference is to find a way to solve this problem within the context of strongly defined and managed components. Has anyone looked at context classloaders as a solution to this problem?
I don't want to get into an argument over semantics. In some sense I agree with what you are saying. The 'platform' itself is a more 'traditional' application, but indeed acts as host to multiple 'eclipse applications'. But the fact remains that the nature of the JRE used for platform deployment needs to be in the control of folks further downstream. In a sense, eclipse already concedes this, otherwise the launcher would not support the -vm and -vmargs switches. It is important to note that what I am advocating is not opening up any new namespace vulnerabilities that aren't already there. The same effects can be instigated using the -Xbootclasspath variable. However, use of -Xbootclasspath itself is problematic in terms of packaging and deploying the 'platform'. For another route already taken, one only has to look to WSAD and examine the JRE(s) bundled with that deployment of the platform to see that they have their own uniquely tweaked rt.jar that is necessary for some of the things they are doing. So deploying the platform on different JRE configurations is already possible and unavoidable. Since it can not be avoided, it makes sense to me to at least support the recommended, standard extension mechanism so that deployers can leverage the tools that are supposed to be at their disposal. I don't think the context classloader addresses the particular problem we are trying to address here.
Another approach, I suppose, might be to allow each bundle/plugin state in it's manifest whether it should see the app and/or ext class loaders.
This issue has been resolved thus: - bundles no longer get the framework classloader by default. - A bundle's classloader's parent is the boot classloader by default. It is possible for an adaptor to set change this and use a different parent (e.g., the system classloader)