![]() ![]() ![]() ![]() |
Miscellaneous |
The JNDI is an API defined independent of any specific naming or directory service implementation. In order for an application, applet, servlet, or any program unit to make use of the JNDI, it must specify the service provider to use and have access to the class files of the service provider. A single program might use more than one service provider. Furthermore, the program and/or service providers might use object factories, state factories, and control factories, whose class files must also be made available to the JNDI. In addition, the JNDI also needs access to application resource files (see Application Resource FilesSection) provided by the program, service providers, and other components. In all of these cases, the JNDI needs to load in class and resource files. This section explains how the JNDI uses class loaders and how you can affect its use of class loaders.
Background on Class Loaders
The class loader is the means by which Java classes and resources are loaded into the Java runtime environment. It controls the policies ranging from where to load class definitions and the data format of the class definitions. There is a system class loader responsible for loading the Java runtime itself and classes in the class path of the application.In the JDKTM 1.1 and earlier releases, there is no relationship between one class loader and another. There is a system class loader responsible for loading in the Java runtime, the application, and classes and resources in the application's classpath. An applet is loaded by an applet class loader, which is responsible for loading the applet and its related classes and resources, possibly over the network by communicating with a Web server.
In the JavaTM 2 Platform, Standard Edition, v 1.2 and later releases, class loaders have a hierarchical relationship. Each class loader has a parent class loader. When a class loader is asked to load a class or resource, it first consults its parent class loader before attempting to load the item itself. The parent in turn consults its parent, and so on. So it is only when all of the ancestor class loaders cannot find the item that the current class loader gets involved. There is a bootstrap class loader, which is responsible for loading in the Java runtime. It is the "root" in the class loader hierarchy. The system class loader is a descendant of the bootstrap class loader; it is responsible for loading in the application and for loading classes and resources in the application's classpath
The Java 2 Platform also introduced the notion of context class loader. The context class loader of a thread is, by default, set to the context class loader of the thread's parent. The hierarchy of threads is rooted at the primordial thread (the one that runs the program). The context class loader of the primordial thread is set to the class loader that loaded the application. So unless you explicitly change the context class loader of the thread, its context class loader will be that of the application. That is, the context class loader can load the classes that the application can load. The context class loader is used by the Java runtime such as the Java Remote Method Invocation (RMI) to load classes and resources on behalf of the user application. The context class loader, like any Java 2 Platform class loader, has a parent class loader and supports the same delegation model for class loading described above.
Class Loading on the JDK 1.1
When you use the JNDI with the JDK 1.1, you must place the JNDI jars, service provider jars, and jars or class files containing factories in the application's classpath. Or, if you're using an applet, you must place those jars and class files in the applet's codebase directory and/or archive locations. Consequently, the class loader that loads the JNDI jars is typically the same as the one that loads in the application and the factories.Note that you cannot use JNDI application resource files with the JDK 1.1. See the Application Resource Files
Section for details.
Class Loading on the Java 2 Platform
When you use the JNDI with the Java 2 Platform, the class loader that loads the JNDI classes is typically different from the one that loads in the application. For example, in the Java 2 SDK, v 1.3, the JNDI classes are loaded by the bootstrap class loader while the application classes are loaded by the system class loader. In the Java 2 SDK, v 1.2, if you install the JNDI as an installed extension, the JNDI classes are loaded by the class loader responsible for loading installed extensions while the application classes are loaded by the system class loader. As a result, if the JNDI were to use its class loader to load service providers and factories, it might not see the same classes as the application. Therefore, to try to see what the application can see, the JNDI uses the calling thread's context class loader when it is loading in classes for the service providers and factories and application resource files.There are some rare circumstances in which you would want to change a thread's context class loader to affect how the JNDI finds classes. One situation is when the environment that you're working in does not set the context class loader properly. For example, a bug in the Java 2 SDK, Standard Edition, v 1.2.2 causes the Abstract Window Toolkit (AWT) to not set the listener threads' context class loader to be the class loader that loaded the applet. Consequently, callback methods invoked by the listener threads do not have access to service providers and factories that the applet can otherwise load explicitly. Or, you might want to add an additional repository of jars and class files that contains special providers and factories to your applications/applets. To change a thread's context class loader, you use Thread.setContextClassLoader(). Here is an example:
This example creates a URLClassLoader that loads classes from a specified codebase URL. It then creates an initial context and performs other JNDI operations within the context of that class loader. In this particular example, the class loader affects how the initial context was initialized (via an application resource file found by the new class loader), and the result of lookup() (via the object factory named in the application resource file and the class file of the factory found by the new class loader). To run this program, you supply a codebase URL as follows:ClassLoader prevCl = Thread.currentThread().getContextClassLoader(); // Create class loader using given URL // Use prevCl as parent to maintain current visibility ClassLoader urlCl = URLClassLoader.newInstance(new URL[]{new URL(url)}, prevCl); try { // Save class loader so that we can restore later Thread.currentThread().setContextClassLoader(urlCl); // Expect that environment properties are in // application resource file found at "url" Context ctx = new InitialContext(); System.out.println(ctx.lookup("tutorial/report.txt")); // Do something useful with ctx ... } catch (NamingException e) { // Handle exception } finally { // Restore Thread.currentThread().setContextClassLoader(prevCl); }In that codebase, you can specify a jndi.properties file. In this particular example, we have the following jndi.properties file in the codebase directory:#java ChangeClassLoader file:/some/directory/somewhere/In the same codebase directory, we have the class definition for FooObjectFactory, which always returns the string "foo" when given a java.io.File object. When you run this program, you see the output:java.naming.factory.initial=com.sun.jndi.fscontext.FSContextFactory java.naming.provider.url=file:/tmp java.naming.factory.object=FooObjectFactoryIf you do not see this output, check the correctness of the codebase URL argument. Remember, if you are naming a codebase directory, you should include a trailing slash.fooClass Loading from Prespecified Locations
In some cases, the location of class files is specified explicitly. For example, you can specify an object factory's codebase in its Reference. When reading such an object from the naming or directory service, the JNDI will use a class loader for the codebase named in the Reference to obtain the class files for the factory. The parent of that class loader is the thread's context class loader.
![]() ![]() ![]() ![]() |
Miscellaneous |