Community
Participate
Working Groups
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.
For now, closing bugs not planned for 2.1. Will reopen after 2.1 release.
Reopening
*** Bug 24837 has been marked as a duplicate of this bug. ***
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.
*** Bug 44470 has been marked as a duplicate of this bug. ***
This is being discussed in the context of OSGi: bug 42531.
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.
A command line switch sounds like a reasonable compromise.
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?
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.
Not planned for 2.1.2, but leaving open for now.
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?
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.
*** Bug 48808 has been marked as a duplicate of this bug. ***
Very much a friend of bug 3074. Moving to Equinox
*** Bug 54921 has been marked as a duplicate of this bug. ***
*** Bug 3074 has been marked as a duplicate of this bug. ***
*** Bug 45726 has been marked as a duplicate of this bug. ***
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.
*** Bug 88467 has been marked as a duplicate of this bug. ***
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