Java RMI

RMI is used to call methods on a server from another JVM.

A typical server program creates some remote objects, makes references to these objects accessible, and waits for clients to invoke methods on these objects. A typical client program obtains a remote reference to one or more remote objects on a server and then invokes methods on them.

An application can register its remote objects with RMI's simple naming facility, the RMI registry. Alternatively, an application can pass and return remote object references as part of other remote invocations.

One of the central and unique features of RMI is its ability to download the definition of an object's class if the class is not defined in the receiver's Java virtual machine (either server or client - see example below - this is different from a remote object concept)

Objects with methods that can be invoked across Java virtual machines are called remote objects. An object becomes remote by implementing a remote interface.

RMI treats a remote object differently from a non-remote object when the object is passed from one JVM to another. Rather than making a copy of the implementation object in the receiving JVM, RMI passes a remote stub for a remote object. The stub acts as the local representative, or proxy, for the remote object and basically is, to the client, the remote reference. The client invokes a method on the local stub, which is responsible for carrying out the method invocation on the remote object.

//server side
public interface Compute extends Remote {
    <T> T executeTask(Task<T> t) throws RemoteException;
}
 
public interface Task<T> {
    T execute();
}
 
//Compute and Task interfaces should be compiled and given to client and server developers first.
 
//this is placed in the registry in the server side by a string name
public class ComputeEngine implements Compute {
}
 
//put in the registry
String name = "Compute";
Compute engine = new ComputeEngine();
Compute stub = (Compute) UnicastRemoteObject.exportObject(engine, port);
Registry registry = LocateRegistry.getRegistry();
registry.rebind(name, stub);
 
//The client then looks up the remote object from the remote registry by name and calls its methods.
 
String name = "Compute";
Registry registry = LocateRegistry.getRegistry(remote_host);
Compute comp = (Compute) registry.lookup(name);
Pi task = new Pi(Integer.parseInt(args[1]));
BigDecimal pi = comp.executeTask(task);
 
/*
Implementations of the Task object that were previously unknown to the compute engine are 
downloaded by RMI into the compute engine's Java virtual machine as needed.
Classes that implement Task should be Serializable.
*/
 
public class Pi implements Task<BigDecimal>, Serializable {
}

Passing Objects

The rules governing how arguments and return values are passed are as follows:

  • Remote objects are essentially passed by reference. A remote object reference is a stub, which is a client-side proxy that implements the complete set of remote interfaces that the remote object implements.
  • Local objects are passed by copy, using object serialization. By default, all fields are copied except fields that are marked static or transient. Default serialization behavior can be overridden on a class-by-class basis.

Passing a remote object by reference means that any changes made to the state of the object by remote method invocations are reflected in the original remote object. When a remote object is passed, only those interfaces that are remote interfaces are available to the receiver. Any methods defined in the implementation class or defined in non-remote interfaces implemented by the class are not available to that receiver.

In the parameters and return values of remote method invocations, objects that are not remote objects are passed by value. Thus, a copy of the object is created in the receiving Java virtual machine. Any changes to the object's state by the receiver are reflected only in the receiver's copy, not in the sender's original instance. Any changes to the object's state by the sender are reflected only in the sender's original instance, not in the receiver's copy.

Security

  • An application can only bind, unbind, or rebind remote object references with a registry running on the same host.
  • For RMI to download classes, a security manager must be in force.

Serializaiton

Note that all serializable classes, whether they implement the Serializable interface directly or indirectly, must declare a private static final field named serialVersionUID to guarantee serialization compatibility between versions. If no previous version of the class has been released, then the value of this field can be any long value, similar to the 227L used by Pi, as long as the value is used consistently in future versions. If a previous version of the class has been released without an explicit serialVersionUID declaration, but serialization compatibility with that version is important, then the default implicitly computed value for the previous version must be used for the value of the new version's explicit declaration. The serialver tool can be run against the previous version to determine the default computed value for it.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License