RMI SPECIFICATION IN A NUTSHELL:
 
1. Java Distributed Object Model 2. RMI System Overview 3. Client Interfaces
4. Server Interfaces 5. Registry Interface 6. Stub and Skeleton Interfaces
7. Garbage Collector Interface 8. Activatable Remote Objects 


1. Java Distributed Object Model

RMI and Distributed Computing Applications:

Locate Remote Objects: Applications can locate remote objects in one of two ways: Either register the remote objects with RMI's simple naming registry called "rmiregistry" and use methods from the class java.rmi.Naming to lookup, bind, rebind and unbind OR pass/return a reference of the remote object as a part of the application's normal operation.
Communicate with Remote Objects: RMI provides the mechanism for communication between the client and the server; to the programmer everything is like any other java method invocation.
Load Class bytecodes for objects that are passed or returned: RMI allows java objects to be passed/returned, and provides necessary mechanisms to load the object's code and transmit its data. This mechanism may use already existing Web Server on the client and the server sides.

The Following diagram shows a distributed application using RMI. Pre-existing web-servers are used to load class bytecodes.

Differences between Java Distributed Object Model and Java Object Model:

The Java distributed object model is similar to the Java object model in the following ways:

The Java distributed object model differs from the Java object model in these ways: java.rmi package interface and classes Hierarchy:


 

java.rmi.Remote interface
It list a number of remote methods that can be invoked by a remote virtual machine. It has the following features:

When a remote interface is implemented by a concrete class, the class can have methods not declared in the remote interface. Such methods are not accessible to remote clients and could only be used locally.

rmi server
The Rmi server functions are provided by java.rmi.server.RemoteObject and its subclasses : java.rmi.server.RemoteServer, java.rmi.server.UnicastRemoteObject, java.rmi.activation.Activatable.

Important features about parameter transmission in RMI:
Referential Integrity : Within the same RMI invocation, 2 references to the same object in the sending virtual machine, will refer to the same copy in the receiving virtual machine also.

Class Annotation: When an object is sent from one VM to another in a remote method call, the RMI system annotates the class descriptor in the call stream with information (the URL) of the class so that the class can be loaded at the receiver. It is a requirement that classes be downloaded on demand during remote method invocation.

Parameter Transmission: RMI serializes its parameters by using a subclass of ObjectOutputStream. The subclass overrides the replaceObject method. All objects are written by calling the writeObject method. The replaceObject is called to each of the written object. The replaceObject returns the stub of the object if the object was remote else it returns the object itself. The subclass also implements the annotateClass() method which annotates the call stream with location of the class. All other default behavior of  ObjectOutputStream are maintained.
The same mechanism applies for return values and exception transmission.
While unmarshalling a subclass of ObjectInputStream is used. It overrides the replaceObject method. The method does the necessary task of dynamic class loading, if required, by using the class annotation sent in the marshalled object.



2. RMI System Overview

Stub and Skeleton

Stub: is the client's local representative or proxy for the remote object. The caller invokes method on the local stub which is responsible for carrying out the method call on the remote object. When a stub method is called the stub does the following activities:

Skeleton: is responsible for dispatching the call to the actual object implementation. When the skeleton receives a call it does the following activities: In JDK1.2 an additional stub protocol was introduced that eliminated the use of skeletons. Stub and Skeleton are generated by rmic compiler.

Thread and RMI
RMI does not guarantee a one-one mapping of a remote method invocation to a thread. As methods of the same remote object may be executing concurrently, the methods must be made thread-safe.

Distributed Garbage Collection
Distributed garbage collector uses references counting for garbage collection. A reference count of all live references is maintained in the java virtual machine. Whenever a live reference enter the JVM, the reference count is incremented. When the first live reference to an object is made a "referenced" message is sent to the server. As live references are unreferenced the count is decremented and when there are no live references a "unreferenced" message is sent. When the remote object is no longer referenced by any client, a weak reference is maintained. The distributed GC can call the local GC to ensure that no local references exists and can then garbage collect the remote object.

If there is a network partition between the client and remote server there is possibility of premature collection (the server believes that the client has crashed) and hence remote references cannot guarantee referential integrity.

Clients Accessing Through Firewalls:
The RMI transport layer by default tries to make a direct socket connection between the client and the server. If the client is under a firewall protection then, this is not possible. The alternative is to go through firewall-trusted HTTP protocol.

The transport layer embeds the RMI call as a HTTP POST request. The return value/exception of the remote call comes in as the body of the response. The HTTP post is formulated as:

The RMI transport layer uses the socket factory java.rmi.server.RMISocketFactory to generate default sockets for the clients and server. The sockets created by this factory automatically provides the firewall tunnelling mechanism: Configuring the client and server for communication across firewall:
Client: No extra configuration is needed for client.
Server:

3. Client Interfaces

java.rmi.RemoteException : The embedded I/O Exception of a RemoteException can be obtained by accessing the public detail field if the RemoteException class. It is of type Throwable.

java.rmi.Naming : provides methods for storing and obtaining references to remote objects in the remote object registry.
The methods has a string arguments of the form: //host:port/name .
Here, host is the host where the registry is located and port is the port number on which the registry accepts calls, name is uninterpreted by the registry. host and port are optional in which case they defaults to localhost and 1099 ( the port rmiregistry uses).

A registry can be shared by all servers in a host (by using rmiregistry) or a server can have its own registry by calling java.rmi.registry.LocateRegistry.createRegistry method.

Important methods of java.rmi.Naming class includes: bind, rebind, unbind, lookup, list. This methods can throw java.rmi.AccessException at any time.



4. Server Interfaces

java.rmi.server.RemoteObject: Abstract class
An abstract class that gives implementation of java.lang.Object methods -- hashCode, equals and toString for remote objects. equals checks  on references equality.
The remoteObjects embeds a remote reference as a field. It has the toStub(remote) methods that can return the stub of a remote object that was already exported.
Serialization: the remoteObject implements the writeObject() and readObject() methods of serializable interface.

java.rmi.server.RemoteServer: Abstract class
It is the superclass of java.rmi.server.UnicastRemoteObject and java.rmi.activation.Activatable.
It contains setLog method that allows logging of calls to the server. The getClientHost method is used to get the name of the host that invoked the current active method in the thread.

java.rmi.UnicastRemoteObject: class
Features:

Constructing and exporting a UnicastRemoteobject:
Remote objects that are created by extending UnicastRemoteObject are by default exported.
If the remote object does not extend UnicastRemoteObject then, it need to be exported by using any one of the exportObject methods of UnicastRemoteObject. Otherwise, client's reference to unexported remote objects will return a stubNotFoundException.

Serializing UnicastRemoteObjects:
Information contained in uniCastRemoteObjects are transient and hence are not serialized to any outputStream. By informations of subclasses will be written to outputStream. When a UnicastRemoteException object is deserialized from an inputStream the object is automatically exported.

Unexporting a UnicastRemoteObject:
unexportObject method of UnicastRemoteObject can be called to unexport a remote object. If the boolean argument to this methods is true then the remote object is forcibly unexported even if there are some pending calls.

Clone:
UnicastRemoteObject does not implement the Cloneable interface and hence in itself cannot be cloned. But it defines the clone method so that if a subclass implements the cloneable interface, the parent part is also cloned correctly.

java.rmi.server.Unreferenced interface
Server remote objects that implement this interface has the unreferenced method invoked when there is no references to the remote object. This method could be called many times in a lifetime of the remote object

java.rmi.RMISecurityManager class
It has the same security restriction as java.lang.SecurityManager except that it overrides the checkPackageAccess method. In RMI, if a security manager is not provided only stub and classes loaded from the local classpath are allowed. This allows for protection against classes downloaded as a result of remote method invocation.

java.rmi.server.RMIClassLoader class
Provides static methods that RMI uses internally to download class bytecodes for parameters and return types.

RMI Socket Factories:
The new JDK1.2 RMI provides 2 interfaces java.rmi.server.RMIClientSocketFactory and java.rmi.server.RMIServerSocketFactory that allows customizes socket and serverSocket to be used in the new RMI wire. They are specified as arguments to the new constructors and exportObject methods of UnicastRemoteObject.
The implementation of RemoteRef and ServerRef used in stubs and skeletons for remote object exported are the new classes -- UnicastRef2 and UnicastServerRef2. The endpoint of contact represented in UnicastRef is different from that of UnicastRef2. In UnicastRef it is simply the hostname in UTF followed by the port number. Whereas in UncastRef2 it is a format byte (that says what the content is) followed by the UTF string of the host, port number and an optional serialized representation of the RMIClientSocketFactory that the client uses to establish connection to the server (i.e the endpoint).

java.rmi.server.RMISocketFactory:
It implemets the RMIClientScocketFactory and RMIServerSocketFactory interfaces. The static method setSocketFactory can be invoked to set the socket factory by the application. But this could be done only once in the application.
The transport invokes the createSocket and createServerSocket when the RMI needs sockets to establish a communication.

When a remoteSocketFactory is specified while exporting the remote object, it will be downloaded at the time and used to create a custom client socket by calling the RMISocketFactory.createSocket() method.

java.rmi.server.RMIFailureHandler interface
Contains a method that determines whether a retry has to be made in case a server socket creation was a failure. It must be registered first with the RMISocketFactory by calling the setFailureHandler method. If not registered a failurehandler, the default is to retry creation after a short time.



5. Registry Interface

Registry is a remote object that maps names to remote objects. Any server can have its own registry or a single registry can serve a host.
The java.rmi.registry.Registry interface provides methods for looking up, binding, unbinding, rebinding and listing the contents of a registry. The java.rmi.Naming calls LocateRegistry.getRegistry method to get a remote object that implement the Registry interface and call methods of that remote object. java.rmi.Naming uses URL-based naming.

java.rmi.registry.Registry interface: Provides bind, unbind, rebind, lookup and list methods.
java.rmi.registry.LocateRegistry class: provides getRegistry and createRegistry methods.
getRegistry can be used to get a reference (stub) to a bootstrap remote object registry on a host, including local host, on a particular port or a default port.
createRegistry creates a local registry at a specified port.



6. Stub and Skeleton Interfaces

java.rmi.server.RemoteStub: is the superclass of all remote stubs in RMI. Stubs are client side surrogates for remote objects and has exactly the same set of remote interfaces defined by the remote object's class; the stub class does not include the non-remote portions of the class hierarchy that constitutes the object's type graph.

Using wait, notify and notifyAll on the stub reference does not act on the actual remote object but on the client's local reference.

java.rmi.server.RemoteRef: all stubs contains a remoteRef which is a handle to the remote object. It is used to carry out remote calls to the remote object for which it is a reference.The remote call is carried out by using the new ivoke method of RemoteRef.

java.rmi.server.ServerRef: The server side handle for the remote object. It has methods to export remote object and also to get the current client using the remote object.

java.rmi.server.Skeleton: Deprecated in JDK1.2. It is used by skeleton generated by rmic. It contains methods to dispatch a method call to the actual remote object and also to get the list of all the operations/methods found in the remote object.



7. Garbage Collector Interface

java.rmi.dgc.DGC interface:

package java.rmi.dgc;
import java.rmi.server.ObjID;
public interface DGC extends java.rmi.Remote {
     Lease dirty(ObjID[] ids, long sequenceNum, Lease lease) throws java.rmi.RemoteException;
    void clean(ObjID[] ids, long seqNum, VMID vmid, boolean strong) throws java.rmi.RemoteException;
}

A client trying to get  remote object references calls the dirty method with the ids of the remote objects for which refrences are sought of. The DGC  puts the VMID of the client to reference list of the remote object and returns a Lease object. The lease object contains the VMID of the client that the DGC has used and a lease time which could be different from what the client requested.
The client need to increase the lease by making more dirty calls, if it wants the reference for more than the initial lease time. For dirty calls that fails the correponding clean call must have the strong argument as true, indicating the DGC that the sequence number must be remembered.
A client need to make only one dirty call even if it has multiple reference to the same remote object.
When the client has finished using the reference it must call the call method so that DGC can reduce the client VMID from the reference list.

java.rmi.dgc.Lease class:

package java.rmi.dgc;
public final class Lease implements java.io.Serializable {
       public Lease(VMID id, long duration);
       public VMID getVMID();
       public long getValue();
}

The lease class stores the client VMID and the lease  duration.

java.rmi.server.ObjID class

package java.rmi.server;
public final class ObjID implements java.io.Serializable {
public ObjID ();
public ObjID (int num);
public void write(ObjectOutput out) throws java.io.IOException;
public static ObjID read(ObjectInput in)
throws java.io.IOException;
public int hashCode()
public boolean equals(Object obj)
public String toString()
}

The ObjId represents a unique remote object in a virtual machine.Each identifier contains an object number and an address space identifier that is unique with respect to a specific host. An object identifier is assigned to a remote object when it is exported.

java.rmi.server.UID class:

The class UID is an abstraction for creating identifiers that are unique with respect to the host on which it is generated. A UID is contained in an ObjID as an address space identifier. A UID consists of a number that is unique on the host (an int), a time (a long), and a count (a short).

java.rmi.dgc.VMID:

The class VMID provides a universally unique identifier among all Java virtual machines. A VMID contains a UID and a host address. A VMID can be used to identify client virtual machines.



8. Activatable Remote Objects

An active object is a remote object that is instantiated and exported in a Java VM on some system. A passive object is one that is not yet instantiated (or exported) in a VM, but which can be brought into an active state. Transforming a passive object into an active object is a process known as activation. Activation requires that an object be associated with a VM, which may entail loading the class for that object into a VM and the object restoring its persistent state (if any).

RMI uses Lazy Activation. In this, activation of remote object is deferred until the client's first use.

Lazy Activation: uses "faulting" remote references. A remote object's stub contains a "faulting" reference which contains both:

Activation Protocol:

Components:
Faulting reference, Activator, Activation Group (one per  JVM) and the remote Object.
Activator: One per host, and does the following --

The Activator maintains a mapping of activation identifiers to active object in a cache so that it does not to always consult the groups for every activation request.

Activation Group is the entity per JVM that receives request to activate a remote object and returns the activated object to the activator.

The protocol:
A faulting reference uses an activation identifier and calls the activator (an internal RMI interface) to activate the object associated with the identifier. The activator looks up the object’s activation descriptor (registered previously). The object’s descriptor contains:

If the activation group in which this object should reside exists, the activator forwards the activation request to that group. If the activation group does not exist, the activator initiates a VM executing an activation group and then forwards the activation request to that group.
The activation group loads the class for the object and instantiates the object using a special constructor that takes several arguments, including the activation descriptor registered previously.
When the object is finished activating, the activation group passes back a marshalled object reference to the activator that then records the activation identifier and active reference pairing and returns the active (live) reference to
the faulting reference. The faulting reference (inside the stub) then forwards method invocations via the live reference directly to the remote object.

An Activable Remote Object:
An activatable remote object must have:

ActivationDesc Class : An ActivationDesc contains the information necessary to activate an object. It contains the object’s activation group identifier, the class name for the object, a codebase path (or URLs) from where the object’s code can be loaded, and a MarshalledObject that may contain object-specific initialization data used during each activation.

ActivationID class : it denotes remote objects that can be activated over time. It contains: remote reference to its activator and a unique id for remote object. The activationId of a remote object is obtained by registering the remote object to the activation system.
RMI provides an activation system implementation: rmid daemon. It should be started before registering any activatable remote object.

Activatable class:
The simplest way to make a remote object activatable is to subclass java.rmi.activation.Activatable class. The concrete subclass must call the constructor of the Activatable class to automatically register itself with the acticvation system and also to be exported.

An Example Activatable Remote Object:

package examples;
public interface Server extends java.rmi.Remote {
public void doImportantStuff()
throws java.rmi.RemoteException;
}
public class ServerImpl extends Activatable implements Server
{
// Constructor for initial construction, registration and export
public ServerImpl(String codebase, MarshalledObject data)
throws ActivationException, java.rmi.RemoteException
{
// register object with activation system, then
// export on anonymous port
super(codebase, data, false, 0);
}
// Constructor for activation and export; this constructor
// is called by the ActivationInstantiator.newInstance
// method during activation in order to construct the object.
public ServerImpl(ActivationID id, MarshalledObject data)
throws java.rmi.RemoteException
{
// call the superclass’s constructor in order to
// export the object to the RMI runtime.
super(id, 0);
// initialize object (using data, for example)
}
public void doImportantStuff() { ... }
}

If the Activatable remote object does not extend the Activatable class, then it must take the task of exporting and registering itself in both the initial constructor and the activation constructor:

package examples;
public class ServerImpl extends SomeClass implements Server
{
// constructor for initial creation
public ServerImpl(String codebase, MarshalledObject data)
throws ActivationException, java.rmi.RemoteException
{
// register and export the object
Activatable.exportObject(this, codebase, data, false, 0);
}
// constructor for activation
public ServerImpl(ActivationID id, MarshalledObject data)
throws java.rmi.RemoteException
{
// export the object
Activatable.exportObject(this, id, 0);
}
public void doImportantStuff() { ... }
}

Registering an Activation Descriptor without creating an object:

Server server;
ActivationDesc desc;
String codebase = “http://zaphod/codebase/”;
MarshalledObject data = new MarshalledObject(“some data”);
desc = new ActivationDesc(“examples.ServerImpl”, codebase, data);
server = (Server)Activatable.register(desc);

The remote stub returned by register method implements the same set of remote interfaces as the Server class and can be used where a Server reference is used.

The Activator Interface:
package java.rmi.activation;
public interface Activator extends java.rmi.Remote
{
java.rmi.MarshalledObject activate(ActivationID id,
boolean force)
throws UnknownObjectException, ActivationException,
java.rmi.RemoteException;
}

The activate method activates the object associated with the activation identifier, id. If the activator knows the object to be active already and the force parameter is false, the stub with a “live” reference is returned immediately to the caller; otherwise, if the activator does not know that corresponding the remote object is active or the force parameter is true, the activator uses the activation descriptor information (previously registered to obtain the id)to
determine the group (VM) in which the object should be activated. If an ActivationInstantiator corresponding to the object’s group already exists, the activator invokes the activation instantiator’s newInstance method
passing it the id and the object’s activation descriptor.

If the activation instantiator (group) for the object’s group descriptor does not yet exist, the activator starts a new incarnation of an ActivationInstantiator executing (by spawning a child process, for example). When the activator re-creates an ActivationInstantiator for a group, it must increment the group’s incarnation number. Note that the incarnation number is zero-based. The activation system uses incarnation numbers to detect late ActivationSystem.activeGroup and ActivationMonitor.inactiveGroup calls. The activation system discards calls with an earlier incarnation number than the current number for the group.

When the activator receives the activation group’s call back (via the ActivationSystem.activeGroup method) specifying the activation group’s reference and incarnation number, the activator can then invoke that activation instantiator’s newInstance method to forward each pending activation request to the activation instantiator and return the result (a marshalled remote object reference, a stub) to each caller. Note that the activator receives a MarshalledObject instead of a Remote object so that the activator does not need to load the code for that object, or participate in distributed garbage collection for that object. If the activator kept a strong reference to the remote object, the activator would then prevent the object from being garbage collected under the normal distributed garbage collection mechanism.

The ActivationSystem Interface:
The ActivationSystem provides a means for registering groups and activatable objects to be activated within those groups. The ActivationSystem works closely with both the Activator, which activates objects registered via the ActivationSystem, and the ActivationMonitor, which obtains information about active and inactive objects and inactive groups.

rmid -stop [-port] is used to stop the activation system [at the specified port].

The ActivationMonitor Class:
An ActivationMonitor is specific to an ActivationGroup and is obtained when a group is reported via a call to ActivationSystem.activeGroup (this is done internally by the ActivationGroup.createGroup method). An activation group is responsible for informing its ActivationMonitor when either: its objects become active, inactive or the group as a whole becomes inactive.

The ActivationInstantiator Class:
The ActivationInstantiator is responsible for creating instances of activatable objects. A concrete subclass of ActivationGroup implements the newInstance method to handle creating objects within the group.

The ActivationGroupDesc Class:
An activation group descriptor (ActivationGroupDesc) contains the information necessary to create or re-create an activation group in which to activate objects in the same Java VM.
Such a descriptor contains: