Relates :
|
|
Relates :
|
|
Relates :
|
A thread's context class loader is not always set how one would expect it to be set, such as when callbacks are dispatched, making this new feature useless in a lot of situations and causing class resolution to fail when it should work. (Furthermore, these expectations of how the context class loader should be getting set are based only on an understanding of what this feature was intended for; the actual specificification is extremely vague.) A concrete example of the bug is that when applet code is invoked through an AWT callback, the context class loader is NOT set to the applet's class loader; thus, if the applet then tries to do anything that resolves classes through the context class loader, it will fail. This behavior could be considered an AWT bug, but it's not clear that it would be feasible or even possible to fix AWT to set the context class loader correctly in all cases, and this problem will apply to almost any other callback facility as well. Therefore, perhaps we should consider that this bug is a design flaw in the context class loader mechanism. In addition, it is difficult for code to take matters into its own hands and set the context class loader for a piece of code that it wishes to execute, because modifying any thread's context class loader, even the current thread's only during the current method's execution, requires the coarse-grained "setContextClassLoader" permission (in 1.2beta3, it only required permission to "access" the target thread). [This bug report is being filed to document these couple of problems/issues with the per-thread "context class loader" feature (of the 1.2 extension mechanism) that have been discussed recently in several arenas, but no resolution seems forthcoming.] more details: When an applet's code is executed, it should be able to expect that the context class loader of the thread in which it was invoked will be the class loader that loaded the applet. This applet-related support has seemed to be the most concrete example given for the motiviation behind the design of the current context class loader mechanism. The following applet demonstrates how this expectation is not met (source files are also attached to this bug report): import java.applet.*; import java.awt.*; import java.awt.event.*; public class AppletContextClassLoader extends Applet { public void init() { outputContextLoader("init()"); Button b = new Button("Press Me"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { outputContextLoader("processActionEvent()"); } }); this.add(b); } public void start() { outputContextLoader("start()"); } public void stop() { outputContextLoader("stop()"); } public void destroy() { outputContextLoader("destroy()"); } private static void outputContextLoader(String where) { ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); System.err.println(where + ": context class loader = " + contextLoader); } } When this applet is executed and the "Press Me" button is pressed, the following output is printed to the console: init(): context class loader = sun.applet.AppletClassLoader@7589d67d start(): context class loader = sun.applet.AppletClassLoader@7589d67d processActionEvent(): context class loader = sun.misc.Launcher$AppClassLoader@1301d67c Notice that when the init() and start() methods are executed, the applet's class loader is the context class loader, but when the handler for the button press is executed, the context class loader is the "application" class loader. (Note that this output required that the applet be granted the "getClassLoader" permission, which is unusual; otherwise, the button press would have resulted in a security exception!) The methods called through the methods of java.applet.Applet do see the context class loader properly set because our appletviewer implmentation takes care to set the context class loader to the applet's class loader in the thread that invokes those methods. But when applet code is invoked as part of an AWT callback, the context class loader will just be the base loader that loads classes from CLASSPATH; AWT doesn't do anything to set the context class loader before calling back into the applet. So is this a bug in AWT? Before making any callback, should it figure out the context class loader for the component that it is calling into, perhaps by remembering what the context class loader was when the event listener was registered, and set it to that? Is this even possible (or feasible to implement reliably) given the various layers of event dispatch code? (I don't know.) Furthermore, is this a burden that we want to place on all code that does event dispatching or other sorts of callbacks? What about finalizers, for example? Alternatively, is it responsibility of the callback code itself to set its own context class loader? If this is true, then the other problem regarding the coarse-grained permission required to set a context class loader is particularly serious. For example, if applet code needs to set its own context class loader, then it needs to be granted "setContextClassLoader" permission, which should not be granted to arbitrary applets... The other problem is that the facility is strongly limited by the overly coarse-grained permission required to set one's thread's context class loader. In 1.2beta3, only "access" to the target thread was required to set its context class loader. Perhaps this was too lenient, but now with 1.2beta4, the "setContextClassLoader" RuntimePermission is required to modify *any* thread's context class loader, so code can't even set the context loader for the current thread. I presume that the (quite sensible) worry is that without some security check, any code could code change the context class loader of its caller, which is bad because how could the caller ever be prepared for the ramifications of that occurrence. But there is no problem with an arbitrary method setting its thread's context class loader just for the duration of its execution, which is exactly all that most code will want to do, i.e. something like this: (ignoring for the moment that try/finally is now deemed unreliable...) ClassLoader savedCcl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(otherLoader); // do some stuff in context of "otherLoader" ... } finally { Thread.currentThread().setContextClassLoader(savedCcl); } But we can't grant not-fully-trusted code the ability to set the context class loader only for its own needs like this without giving it the ability to mess up its caller's context, so any code that wants to set the context class loader will need to need to require that it be granted "setContextClassLoader" permission, which is a lot of trust to require, especially if no other explicit permissions are otherwise necessary to grant to it. Some real complaints about the difficulty with this coarse-grained "setContextClassLoader" permission have been reported on 1.2 RMI applications in development that want to supply downloadable proxy classes that need to deserialize a MarhsalledObject received from a remote server using a particular class loader to resolve classes from, and this class loader is not the context class loader, nor is it even on the execution stack. So the context class loader needs to be set during the harmless operation, but the dangerous "setContextClassLoader" permission is required. peter.jones@East 1998-07-08
|