Bug 30919 - Plugins don't have access to the extension class loader
Summary: Plugins don't have access to the extension class loader
Status: RESOLVED FIXED
Alias: None
Product: Equinox
Classification: Eclipse Project
Component: Incubator (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows 2000
: P3 enhancement (vote)
Target Milestone: 3.0 M9   Edit
Assignee: User Unknown CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 24837 44470 45726 48808 54921 88467 (view as bug list)
Depends on:
Blocks:
 
Reported: 2003-02-04 18:08 EST by John Arthorne CLA
Modified: 2010-11-15 19:00 EST (History)
11 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description John Arthorne CLA 2003-02-04 18:08:38 EST
Build: I20020129

From conversations with Jed, for consideration post 2.1...

Plugins cannot load classes from JARs in the Java ext directory.  The parent of
a PluginClassLoader is the class loader that loaded the boot plugin, which is a
URLClassLoader that contains only boot.jar.  This URLClassLoader has a null
parent, which means its parent is interpreted to be the Java boot class loader.

In Java, from what I can gather, there are three interesting class loaders that
are always around:  

- the application classloader (aka system loader): knows about the user
classpath (from env var)

- the extension classloader: knows about jars in "ext" directory

- the boot (aka primordial, null) classloader: knows about rt.jar i18n.jar, and
all JARs on the boot classpath.

The application loader's parent is the extension loader, and the extension
loader's parent is the null or boot classloader.  The application loader is
available via ClassLoader.getSystemLoader().

Typically, custom classloaders in java applications are parented at the system
class loader. This means that everything in the user path, the ext directory,
and the boot classpath are available.

In Eclipse, we are not interested in the user classpath, since each plugin
defines its own classpath via plugin.xml.  However, it might be worthwhile to
include the ext directory in our lookup.  This is where common extensions to
java are placed, such as the java cryptography extensions (JCE).

We could enable this by setting the parent of the Eclipse boot plugin loader to
be the extension loader.  This would make a plugin's lookup order as follows:

1) Boot loader
2) Extension loader
3) Eclipse boot.jar
4) JARs in that plugin's runtime section
5) runtime plugin
6) dependent plugins

This is the same as the current order, but with the insertion of 2).

The upside is that Eclipse would work with any extensions added via the java
extension mechanism (i.e., JARs dropped in the ext directory).

The downside is that these JARs would supercede any plugin JARs or pre-requisite
jars.  For example, if someone stuck a different xerces.jar in the ext
directory, we'd fail.
Comment 1 John Arthorne CLA 2003-02-26 15:56:30 EST
For now, closing bugs not planned for 2.1.  Will reopen after 2.1 release.
Comment 2 John Arthorne CLA 2003-04-04 11:37:25 EST
Reopening
Comment 3 John Arthorne CLA 2003-07-22 11:38:33 EDT
*** Bug 24837 has been marked as a duplicate of this bug. ***
Comment 4 John Arthorne CLA 2003-08-14 12:10:55 EDT
Closing.  The Equinox runtime will supply its own classloaders, and we likely
won't have control over whether "ext" is visible.  I don't actually see a
compelling reason to change this.  Adding "ext" to the classpath would pollute
the carefully controlled plugin namespace with extra global libraries.
Comment 5 John Arthorne CLA 2003-10-08 13:49:52 EDT
*** Bug 44470 has been marked as a duplicate of this bug. ***
Comment 6 Rafael Chaves CLA 2003-10-08 13:59:51 EDT
This is being discussed in the context of OSGi: bug 42531.
Comment 7 Mel Martinez CLA 2003-10-09 14:30:13 EDT
picking up comments from pr#44470 and pr#42531

The compelling reason to address this issue is that some security packages need
to be loaded either by the boot loader or the ext loader in order to work
correctly.   In order to develop an application with security in mind from top
to bottom, we need to be able to do this.

It seems to me a reasonable compromise would be to allow the choice to be made
when launching the platform with a command-line option.  The obvious choices for
what the parent loader should be could easily be accounted for like so:

* [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()'

The default behavior would be unmodified, yet this would provide application
assemblers who are in need of more control over the JRE used to do so.
Comment 8 John Arthorne CLA 2003-10-09 14:37:40 EDT
*** Bug 44470 has been marked as a duplicate of this bug. ***
Comment 9 John Arthorne CLA 2003-10-09 14:38:03 EDT
A command line switch sounds like a reasonable compromise.
Comment 10 Jeff McAffer CLA 2003-10-10 00:24:42 EDT
Is the classloader structure tightly spec'd somewhere?  That is, are we 
guaranteed that 
    ClassLoader.getSystemClassLoader().getParent()
is the extension classloader?

And do we think this will change in the future?

Comment 11 Mel Martinez CLA 2003-10-10 16:14:49 EDT
That's a very good question, Jeff.

My interpretation, after much pouring over what specs I can find and understand,
is that 'no', there is not hard statement that the
getSystemClassLoader().getParent() returns the extension classloader, although
it probably is true 99.999% of the time.

However, we can look at the following things that are spec'ed.  According to spec:

1) getSystemClassLoader() ... [returns] "the default delegation parent for new
ClassLoader instances, and is typically the class loader used to start the
application"
2) loadClass() ... "If the class has already been loaded then just return it.
Otherwise, try loading the class from the parent class loader (or virtual
machine's built-in class loader, called the bootstrap class loader, if no parent
was specified)."  Key point here is that the 'null' classloader corresponds to
the bootstrap loader.
3) "Classes for installed optional packages are shared by all code in the same
virtual machine. Thus, installed optional packages are similar to the platform's
core classes (in rt.jar), but with an associated class loader ..."

These three statements tell us a) that installed Java extensions must be loaded
by an associated classloader - NOT the bootstrap class loader. b) that installed
java extension classes must be available to the entire virtual machine - for
those two things to happen they must be loaded by the first non-null classloader
child of the bootstrap loader.

So, to my thinking, the more likely safe way to get the extensions loader is to
walk the getParent() ladder and use the last non-null classloader found.
Comment 12 John Arthorne CLA 2003-10-22 17:28:18 EDT
Not planned for 2.1.2, but leaving open for now.
Comment 13 Mel Martinez CLA 2003-10-27 11:50:14 EST
Extending this topic a bit:

Should the Context Classloader be left as the app (system) classloader?

Current behavior is that plugin code executes in a thread who's context
classloader (Thread.getCurrentThread().getContextClassLoader()) is the system
(application) classloader.

Is this expected / desired behavior?  I would say yes to 'expected' since I'm
not aware of any point where eclipse explicitly sets the context classloader. 
I'm not sure about 'desired'.

This seems to run counter to the philosophy of isolating plugins from the
application classloader.  Or maybe not.   Thoughts?
Comment 14 John Arthorne CLA 2003-10-28 12:42:38 EST
It's a good point.  The default context class loader should probably be either
the primordial loader or the boot class loader. However, this isn't something
we'll be likely to change in a service release and the 3.0 runtime has a
different classloader implementation.  Jeff, it would be worth checking if the
Equinox runtime class loaders do anything with the context class loader.
Comment 15 John Arthorne CLA 2003-12-15 19:16:58 EST
*** Bug 48808 has been marked as a duplicate of this bug. ***
Comment 16 Jeff McAffer CLA 2004-01-26 16:22:08 EST
Very much a friend of bug 3074.

Moving to Equinox
Comment 17 John Arthorne CLA 2004-03-15 19:16:22 EST
*** Bug 54921 has been marked as a duplicate of this bug. ***
Comment 18 Jeff McAffer CLA 2004-03-22 16:13:46 EST
*** Bug 3074 has been marked as a duplicate of this bug. ***
Comment 19 Thomas Watson CLA 2004-05-07 15:01:08 EDT
*** Bug 45726 has been marked as a duplicate of this bug. ***
Comment 20 Pascal Rapicault CLA 2004-05-20 21:09:28 EDT
This has been fixed a couple of days ago by the addition of a system property.
Here is a repost of Tom's message:
The following values are supported for the Java property
osgi.parentClassloader:

"app" - the application classloader

"ext" - the extension classloader

"boot" - the boot classloader

"fwk" - the framework's classloader

The default is to use the boot classloader. I specified a "fwk" option
because as far as I know most all other implementations of the OSGi
framework actually default to using the classloader of the framework as the
parent of all the bundle classloaders. I wanted to at least give us the
option to allow for this if needed.
Comment 21 Rafael Chaves CLA 2005-03-18 10:57:04 EST
*** Bug 88467 has been marked as a duplicate of this bug. ***
Comment 22 Steve Elsemore CLA 2010-11-15 19:00:38 EST
I realize this is a very old bug, but I think the answer to my problem might be here somewhere, if I understood OSGi class loading well enough figure out exactly where.

In my plugin, I need to use a class (SunPKCS11) from the sun.security.pkcs11 package.  Can anybody help?  What is it that I have to do to apply this solution in order to get the class to load?

Thanks!
Steve