02152  Concurrent Systems - RMI Details
Technical University of Denmark DTU
02152 Concurrent Systems        Fall 2008
RMI Details
Home Plan Material  
 
For those of you who wish to get a little more insight to the workings of RMI, here follows a short recap and some alternatives to the approch given in the Java RMI Lab.

All the following is from the Java 1.5.0 specification and thus may require Java version 1.5 (5.0) or above.

1: Create a remote interface

First of all, an application that serves methods through RMI, must implement a remote interface of type java.rmi.Remote. This interface defines the methods that will be served through RMI and all methods must be declared to throw a java.rmi.RemoteException. E.g.,

2: Create a class implementing the remote interface

In general, a class that implements a remote interface should at least do the following:

An RMI server program needs to create the initial remote objects and export them to the RMI runtime, which makes them available to receive incoming remote invocations. The general setup procedure should do the following:

This setup procedure could be performed by a main method in the remote object itself, as in the exercise.

Declare the remote interfaces being implemented

This declaration states that the class implements the SomeRemoteInterface and therefore can be used for a remote object. The class definition could also be declared to extend the UnicastRemoteObject, as done in the exercise. Here another approach is shown, which does not require the remote object to extend this class.

Define the constructor for each remote object

E.g.,

Which creates an instance of SomeClass and invokes the parent constructor with super();

NOTE: In the exercise we extend the remote object from UnicastRemoteObject. If you choose to follow that method, instead of the alternative that is applied here, then the empty parent constructor super() will make the remote object listen to a dynamic port. In case you are behind a firewall, it most likely does not let the dynamic ports through and therefore you should instead call the parent constructor with an integer argument, being the port the server will listen for connections on and then open that port in your firewall! So, if your remote object extends the UnicastRemoteObject, remember to invoke the super constructor with an integer argument:

For remote objects extending UnicastRemoteObject, this creates a SomeClass remote object which serves port 42000.

Provide an implementation for each remote method in the remote interfaces

Sort of self-explanatory. Implement all methods required by the <remote interface> being implemented.

Create and install a security manager

The main method's first task is to create and install a security manager which protects access to system resources from untrusted downloaded code running within the Java virtual machine. A security manager determines whether downloaded code has access to the local file system or can perform any other privileged operations.

If an RMI program does not install a security manager, RMI will not download classes (other than from the local class path) for objects received as arguments or return values of remote method invocations. This restriction ensures that the operations performed by downloaded code are subject to a security policy.

Here's the code that creates and installs a security manager:

Create and export one or more remote objects

In the lab exercise, we created a remote object implementing the UnicastRemoteObject. That is not the method we apply here. Instead, the UnicastRemoteObject offers a static method, exportObject(Remote obj, int port) which returns a Remote object that may be casted to the type of the interface implemented. The port argument specifies the port the server will be listening on and the special value 0 makes it listen to a dynamic port, chosen at runtime. Beware using a dynamic port for listening, if you are behind a firewall. If so, rather choose a specific port and make sure you open that port in your firewall! So we may create our remote objects as follows:

The static UnicastRemoteObject.exportObject method exports the supplied remote object so that it can receive invocations of its remote methods from remote clients. The second argument, an int, specifies which TCP port to use to listen for incoming remote invocation requests for the object, here 42000.

Note that the type of the variable stub must be SomeRemoteInterface, not SomeClass, because the stub for a remote object only implements the remote interfaces that the exported remote object implements. Register at least one remote object with the RMI registry. In the exercise, the RMI registry is started externally by the rmiregistry command, optionally called with an argument, being the port used for listening for queries for remote objects. This may be done within the remote objects main method as well, by using the java.rmi.registry.LocateRegistry and java.rmi.registry.Registry APIs. Thus, to start the registry, we may write:

Create a registry listening on port 42000

It is not required that the registry is running on the same port as the remote object; it is however convenient, as we may then only open up a single port in our firewall, in case such is present.

In case one prefers to run the registry externally, e.g., with the rmiregistry command, we should still get a reference to the registry in our code. We may do so by instead writing:

getRegistry may also be called without an integer argument, thus requiring the registry to be running on the default port, 1099. So make sure you request the registry on the port it is actually serving.

Once we have a reference to the registry running, we may bind our server to the registry, to allow stubs to be requested and downloaded by clients. We do so, by introducing a name the remote object is identified by in the registry, and pass the remote object to the registry as follows:  

For security reasons, an application can only bind, unbind, or rebind remote object references with a registry running on the same host. This restriction prevents a remote client from removing or overwriting any of the entries in a server's registry. A lookup, however, can be requested from any host, local or remote.

Overview

That was an overview of the behavior of the remote object and its implementation. For reference, a suggestion for the implementation of the remote object might be:

3: Create a client application

A client that uses the methods of some remote object, served by RMI, can be divided into three basic steps:

Here, these tasks are thought of as computed in the main method of the client.

Create a security manager

Similar to the server, we may initially create a security manager:

Locate the registry running remotely

For a client to utilize the methods of the remote object, again the registry should be obtained, now accessed remotely, using the java.rmi.registry.LocateRegistry and java.rmi.registry.Registry APIs. Say the registry and the remote object are running on the URL rmi.served.somewhere.com:

The port must of course match the port on which the registry is running on the remote host and any firewall on/before the remote host must allow connections on that specific port.

Lookup the remote object

Finally, a stub for the remote object, serving the methods defined by the interface, e.g., SomeRemoteInterface, is obtained with:

Note, that the remote object must be handled as the interface SomeRemoteInterface, not SomeClass which is not a known type to the client application. After the remote object is obtained, the methods offered by the interface, may then be invoked, causing remote method invocations on the object residing on the remote host.

4: Compiling and running the applications

To compile the server and client classes, do so as usual with java.

The server and client programs run with a security manager installed. When you run either program, you need to specify a security policy file so that the code is granted the security permissions it needs to run. Here is an example policy file to use with the server program:

and for the client application For both example policy files, all permissions are granted to the classes in the program's local class path, because the local application code is trusted, but no permissions are granted to code downloaded from other locations. It is possible with RMI to make methods available on a server, which takes some task written and submitted by the client and executes it, without knowing the contents of the submitted task. Therefore, it is convenient to only grant permission to code which is known to the server, whereas downloaded code from other locations should not be allowed executing anything which requires security permissions. Here we name the files server.policy and client.policy respectively.

If the server does not create a registry it self, then start the RMI registry with:

where [portno] is optional and specifies the port the registry will be listening on.

Then start the server with

The first property specified is the codebase.  The property specifies the location, a codebase URL, from which the definitions for classes originating from this server can be downloaded. If the codebase specifies a directory hierarchy, you must include a trailing slash at the end of the codebase URL. The next property specifies the policy-file to use with the security manager. The last property, the server hostname is important to specify to make the whole thing work distributed, that is with the server accessed remotely from the client. Use either the external IP of the server host (e.g., find it with http://whatismyip.com) or the hostname which identifies the server host on the network on which the client is also available.

When the server is running, it's time to start the client. Do so by typing:

The client should now be able to connect and execute remote methods served by the server!

Final remarks

For most of you, you will probably not require the security files and the property java.security.policy on the command line, when executing. Although, it is mentioned here, to make it less probable that you will struggle with the security managers, should you require them in your assignment.

Similarly the java.rmi.server.codebase property is mentioned here, to make it less probable that it should cause errors, if you do not specify this property. You may want to strip down the server and client commands to:

and ,respectivily, and see if it works without the codebase property and the security-policy files.

References

http://java.sun.com/docs/books/tutorial/rmi/index.html
http://java.sun.com/j2se/1.5.0/docs/guide/rmi/

Written by:
   Bjarne Wahlgreen

Hans Henrik Løvengreen, Nov 7, 2008