Bug 42531 - 98067: what is the system classloader?
Summary: 98067: what is the system classloader?
Status: RESOLVED FIXED
Alias: None
Product: Equinox
Classification: Eclipse Project
Component: Incubator (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows XP
: P1 normal (vote)
Target Milestone: 3.0 M6   Edit
Assignee: Pam Tobias CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-09-04 10:30 EDT by Pam Tobias CLA
Modified: 2005-09-27 09:12 EDT (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Pam Tobias CLA 2003-09-04 10:30:35 EDT
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.
Comment 1 Rafael Chaves CLA 2003-09-12 12:42:16 EDT
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).
Comment 2 Thomas Watson CLA 2003-10-07 12:28:13 EDT
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.
Comment 3 Mel Martinez CLA 2003-10-08 12:18:36 EDT
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.
Comment 4 Thomas Watson CLA 2003-10-08 13:55:17 EDT
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?
Comment 5 Pascal Rapicault CLA 2003-10-08 15:45:08 EDT
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.
 
Comment 6 Jeff McAffer CLA 2003-10-08 15:58:57 EDT
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.
Comment 7 Mel Martinez CLA 2003-10-08 19:58:40 EDT
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
Comment 8 Pascal Rapicault CLA 2003-10-08 21:22:40 EDT
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.
Comment 9 Mel Martinez CLA 2003-10-09 10:02:33 EDT
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.
Comment 10 Pascal Rapicault CLA 2003-10-09 10:11:40 EDT
I said app class loader not ext.
Comment 11 Thomas Watson CLA 2003-10-09 12:05:35 EDT
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.
Comment 12 Mel Martinez CLA 2003-10-09 17:02:39 EDT
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
Comment 13 Jeff McAffer CLA 2003-10-09 17:57:33 EDT
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?
Comment 14 Mel Martinez CLA 2003-10-09 19:14:56 EDT
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.

Comment 15 Mel Martinez CLA 2003-10-10 16:59:24 EDT
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.

Comment 16 Jeff McAffer CLA 2003-11-28 13:51:56 EST
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)