Noel Enete
Remote Method Invocation (RMI)

When the processing load becomes too great to run every Java object on a single PC, it would distribute the load better to move some objects to other computers and establish communication between the machines.

RMI provides the services that allow one object to contact an object on another machine and invoke its methods.

Client Example

This is an example of an RMI client. It gets the handle to a remote object and calls one of its methods. The results are written to standard output.

Figure 1: RmiExample

The trick to using a remote object is securing the object handle. Once the handle is obtained, calls are made to it the same way calls are made to any java object.

To get the handle to a remote object, one makes a call to the Naming.lookup() method. The path to identify the remote object follows common URL syntax (protocol://machine/resourcename). The protocol defaults to "rmi:" and the machine defaults to the local host. The resource name is the name that the remote object used when binding with the RMI registry.

The handle that is returned from this call is cast to the interface that the server implements. Any methods that are defined in this interface can now be sent to the remote object.

For more detail, the Naming class is described in Sun's HTML documentation under the java.rmi package.

Server Example

This server class instantiates itself then notifies the RMI registry that it is available to service incoming method calls. When its single method is called, a notice is written to standard output.

Figure 2: MyServer

In the main() method the server performs some initialization tasks then instantiates and registers itself with the RMI registry. In the call to Naming.rebind() it registers itself under the arbitrary name "MyCoolServer". This is the name by which the client finds the server.

The first initialization task is to install a new security manager that allows references to remote objects. The second task is to make sure an RMI registry object has been created on this machine. If one has been created, it is fetched. If not, one is created.

The RMI registry object is an object that opens a socket on a certain port (usually 1099) and listens for method requests. When one comes in, it routes the request to the identified server (like "MyCoolServer"). To keep track of the server objects, it keeps a hashtable of server objects and names by which they are known.

One does not have to create the RMI registry object from the program. Instead, one could launch the rmiregistry program from a command line. This is a native executable like the java program that creates the registry object after setting some environment variables like the classpath. Unfortunately, it does not include the default directory "." in the classpath so it will complain that it can not find class files even if they are present in the default directory.

To get around this, one must set a classpath in the environment before running the rmiregistry program. Make sure to include the default directory and a path to the file:

  • set classpath=.;c:\jdk1.1.2\lib\
  • rmiregistry

More detail is available in Sun's html documentation. Each RMI class, interface, or exception is documented in one of the following packages java.rmi, java.rmi.dgc, java.rmi.registry, or java.rmi.server.

Server Interface

In the client example above, notice there are no references to MyServer (the server class).

Every time the server object is identified, it is identified by the name of its interface -- MyServerInterface. The way server objects make their methods known to the client is by coding and making available a Java interface.

This interface makes one method available to the client.

Figure 3: MyServerInterface

RMI Server interfaces must all be public and extend the Remote interface. The Remote interface is unusual because it has no methods. It simply sets a bit that identifies itself as a remote object.

All methods in the interface must throw the RemoteException.

For more detail, the Remote interface and the RemoteException are described in Sun's html documentation under the java.rmi package.

Server Middleware

When one object on a machine calls a another object on the same machine there is very little work in making the connection. Parameters are passed as pointers to objects in a common memory space and return objects are passed back the same way.

But when the call is make to a memory space on another computer, the task of making the connection becomes more difficult. Parameters and return values can not be passed as addresses to positions in memory because the two machines do not share the same memory.

The only connection between the two machines is a wire by means of which a stream of bytes can be exchanged. To make a call over this kind of connection, all the parameters must be reduced to a stream of bytes and marshaled over the wire one byte at a time. Return objects must be serialized in the same manner and sent back over the wire.

The code that performs this serialization is specific to the server class and must exist on both sides of the connection.

Java has provided a way to generate the code that performs these middleware services. The JDK includes the rmic program (RMI Compiler). It accepts a server classname as the single parameter.

  • rmic MyServer

As an irritation, this program does not follow the behavior of the java program which includes the default directory "." in the default classpath. To avoid hard coded classpaths, one can use the -classpath option. Remember to include a path to the file.

  • rmic -classpath .;c:\jdk1.1.2\lib\ MyServer

This compiler produces two classes: one that handles the client side of the connection called a Stub and one that handles the server side of the connection called a Skel. The compile above produces the files MyServer_Stub.class (client side) and MyServer_Skel.class (server side).

These classes include the code that is necessary to transform each method call into a stream of bytes and send them across the wire to the remote computer. They are automatically generated and must be present at either side of the connection to make the call possible.

by Noel Enete . . . . . .