There are a few details that we haven't yet covered. These details are not directly related to the security aspects of the class loader, which is why we've saved them until now. If you're interested in the complete details of the class loader, we'll fill in the last few topics here.
Beginning with Java 1.2, class loading follows a delegation model. This new model permits a class loader to be instantiated with this constructor:
Create a class loader that is associated with the given class loader. This class loader delegates all operations to the delegate first: if the delegate is able to fulfill the operation, this class loader takes no action. For example, when the class loader is asked to load a class via the loadClass() method, it first calls the loadClass() method of the delegate. If that succeeds, the class returned by the delegate will ultimately be returned by this class. If that fails, the class loader then uses its original logic to complete its task:
public Class loadClass(String name) { Class cl; cl = delegate.loadClass(name); if (cl != null) return cl; // else continue with the loadClass() logic }
You may retrieve the delegate associated with a class loader with the following method.
Return the class loader to which operations are being delegated. If there is no such class loader, return null.
You'll notice that we used delegation in all of our examples. This is pretty much a requirement: when the virtual machine starts, it creates a URL class loader that is based on the directories and JAR files present in your CLASSPATH. That class loader is the class loader that will be used to load the first class in your application (i.e., the JavaRunner class in our example).
That URL class loader is the only class loader that knows about the CLASSPATH. If the application will reference any other classes that are part of the CLASSPATH, you will be unable to find them unless you use the delegation model of class loading: the JavaRunner loader will first ask the URL class loader to load the class. If the class is on the CLASSPATH, the URL class loader will succeed; otherwise, the Java-Runner loader will end up loading the class itself. This logic is built into the loadClass() method; you do not need to concern yourself with it at a programming level, but it is the reason why you must use delegation.
This URL class loader is known as the system class loader, and it may be retrieved via the following method:
Return the system class loader (the class loader that was used to load the base application classes). If a security manager is in place, you must have the getClassLoader runtime permission to use this method (see Chapter 5, "The Access Controller").
Hence, to set up a delegation class loader, you can use this call:
jrl = new JavaRunnerLoader(ClassLoader.getSystemClassLoader())
instead of the methods we showed earlier.
A class loader can load not only classes, but any arbitrary resource: an audio file, an image file, or anything else. Instead of calling the loadClass() method, a resource is obtained by invoking one of these methods:
Find the named resource and return either a URL reference to it or an input stream from which it can be read. Implementations of class loaders should look for resources according to their internal rules, which are typically (but need not be) the same rules as are used to find classes. In our first JavaRunnerLoader class, that would mean simply constructing a URL based on the urlBase concatenated with the name parameter.
In 1.1, the default behavior for these methods is to return null.
In 1.2, the getResource() method calls the getSystemResource() method; if it does not find a system resource, it returns the object retrieved by a call to the findResource() method (which by default will still be null). The getResourceAsStream() method simply calls the getResource() method and, if a resource is found, open the stream associated with the URL.
Find the named resource and return either a URL reference to it or an input stream from which it can be read. By default, these methods look for the resource on the CLASSPATH and return that resource (if found).
Return an enumeration of resources with the given name. In the first method, an enumeration of the local resources of all delegated class loaders (including the present class loader) is returned; in the second method, only the local resources of the present class loader are returned.
In 1.2, a new method exists in the ClassLoader class:
Return the directory from which native libraries should be loaded.
This method is used by the System.loadLibrary() method to determine the directory in which the native library in question should be found. If this method returns null (the default), the native library must be in one of the directories specified by either the java.library.path or java.sys.library.path property; typically, these properties are set in a platform-specific way (e.g., from the LD_LIBRARY_PATH on Solaris or the PATH on Windows). That mimics the behavior that applies in 1.1 and earlier releases.
However, a 1.2 custom class loader can override that policy and require that libraries be found in some application-defined location. This prevents a user from overriding the runtime environment to specify an alternate location for that library, which offers a slight security advantage. Note that if the user can write to the hardwired directory where the library lives, this advantage no longer exists: the user can simply overwrite the existing library instead of changing an environment variable to point to another library; the end result is the same.
Copyright © 2001 O'Reilly & Associates. All rights reserved.
This HTML Help has been published using the chm2web software. |