CONTENTS | PREV | NEXT | Java Remote Method Invocation |
In RPC (remote procedure call) systems, client-side stub code must be generated and linked into a client before a remote procedure call can be done. This code can be either statically linked into the client or linked in at runtime via dynamic linking with libraries available locally or over a network file system. In the case of either static or dynamic linking, the specific code to handle an RPC must be available to the client machine in compiled form.RMI generalizes this technique, using a mechanism called dynamic class loading to load at runtime (in the Java language's architecture neutral bytecode format) the classes required to handle method invocations on a remote object. These classes are:
- The classes of remote objects and their interfaces.
- The stub and skeleton classes that serve as proxies for remote objects. (Stubs and skeletons are created using the rmic compiler.)
- Other classes used directly in an RMI-based application, such as parameters to, or return values from, remote method invocations.
This section describes:
In addition to class loaders, dynamic class loading employs two other mechanisms: the object serialization system to transmit classes over the wire, and a security manager to check the classes that are loaded. The object serialization system is discussed in the Object Serialization Specification. Security issues are discussed in Section 3.9, "Security".
In Java, the class loader that initially loads a Java class is subsequently used to load all the interfaces and classes that are used directly in the class:
- The AppletClassLoader is used to download a Java applet over the net from the location specified by the codebase attribute on the web page that contains the <applet> tag. All classes used directly in the applet are subsequently loaded by the AppletClassLoader.
- The default class loader is used to load a class (whose
main
method is run by using the java command) from the local CLASSPATH. All classes used directly in that class are subsequently loaded by the default class loader from the local CLASSPATH.- The RMIClassLoader is used to load those classes not directly used by the client or server application: the stubs and skeletons of remote objects, and extended classes of arguments and return values to RMI calls. The RMIClassLoader looks for these classes in the following locations, in the order listed:
a. | The local CLASSPATH. Classes are always loaded locally if they exist locally. |
b. | For objects (both remote and nonremote) passed as parameters or return values, the URL encoded in the marshal stream that contains the serialized object is used to locate the class for the object. |
c. | For stubs and skeletons of remote objects created in the local virtual machine, the URL specified by the local java.rmi.server.codebase property is used. |
For objects passed as parameters or return values (the second case above), the URL that is encoded in the stream for an object's class is determined as follows:
Thus, if a class was loaded from CLASSPATH, the codebase URL will be used to annotate that class in the stream if that class is used in an RMI call.The application can be configured with the property java.rmi.server.useCodebaseOnly, which disables the loading of classes from network hosts and forces classes to be loaded only from the locally defined codebase. If the required class cannot be loaded, the method invocation will fail with an exception.
For the RMI runtime to be able to download all the classes and interfaces needed by a client application, a bootstrapping client program is required which forces the use of a class loader (such as RMI's class loader) instead of the default class loader. The bootstrapping program needs to:
- Create an instance of the RMISecurityManager or user-defined security manager.
- Use the method
RMIClassLoader.loadClass
to load the class file for the client. The class name cannot be mentioned explicitly in the code, but must instead be a string or a command line argument. Otherwise, the default class loader will try to load the client class file from the local CLASSPATH.- Use the newInstance method to create an instance of the client and cast it to Runnable. Thus, the client must implement the java.lang.Runnable interface. The Runnable interface provides a well-defined interface for starting a thread of execution.
- Start the client by calling the
run
method (of the Runnable interface).
For example:
import java.rmi.RMISecurityManager; import java.rmi.server.RMIClassLoader; public class LoadClient { public static void main() { System.setSecurityManager(new RMISecurityManager()); try { Class cl = RMIClassLoader.loadClass("myclient"); Runnable client = (Runnable)cl.newInstance(); client.run(); } catch (Exception e) { System.out.println("Exception: " + e.getMessage()); e.printStackTrace(); } } }
In order for this code to work, you need to specify the java.rmi.server.codebase property when you run the bootstrapping program so that theloadClass
method will use this URL to load the class. For example:
java -Djava.rmi.server.codebase=http://host/rmiclasses/ LoadClient
Instead of relying on the property, you can supply your own URL:
Class cl = RMIClassLoader.loadClass(url, "myclient");
Once the client is started and has control, all classes needed by the client will be loaded from the specified URL. This bootstrapping technique is exactly the same technique Java uses to force the AppletClassLoader to download the same classes used in an applet.Without this bootstrapping technique, all the classes directly referenced in the client code must be available through the local CLASSPATH on the client, and the only Java classes that can be loaded by the RMIClassLoader over the net are classes that are not referred to directly in the client program; these classes are stubs, skeletons, and the extended classes of arguments and return values to remote method invocations.