The RMI implementation

The RMI implementation consists of three abstraction layers.

These abstraction layers are:
  1. The Stub and Skeleton layer, which intercepts method calls made by the client to the interface reference variable and redirects these calls to a remote RMI service.
  2. The Remote Reference layer understands how to interpret and manage references made from clients to the remote service objects.
  3. The bottom layer is the Transport layer, which is based on TCP/IP connections between machines in a network. It provides basic connectivity, as well as some firewall penetration strategies.
This diagram shows the relationship between the client program and the server program through the RMI system. The RMI system comprises the stubs and skeletons and the Remote Reference Layer on both the client and the server side, linked by the Transport Layer.

On top of the TCP/IP layer, RMI uses a wire-level protocol called Java™ Remote Method Protocol (JRMP), which works like this:

  1. Objects that require remote behavior should extend the RemoteObject class, typically through the UnicastRemoteObject subclass.
    1. The UnicastRemoteObject subclass exports the remote object to make it available for servicing incoming RMI calls.
    2. Exporting the remote object creates a new server socket, which is bound to a port number.
    3. A thread is also created that listens for connections on that socket. The server is registered with a registry.
    4. A client obtains details of connecting to the server from the registry.
    5. Using the information from the registry, which includes the hostname and the port details of the server's listening socket, the client connects to the server.
  2. When the client issues a remote method invocation to the server, it creates a TCPConnection object, which opens a socket to the server on the port specified and sends the RMI header information and the marshalled arguments through this connection using the StreamRemoteCall class.
  3. On the server side:
    1. When a client connects to the server socket, a new thread is assigned to deal with the incoming call. The original thread can continue listening to the original socket so that additional calls from other clients can be made.
    2. The server reads the header information and creates a RemoteCall object of its own to deal with unmarshalling the RMI arguments from the socket.
    3. The serviceCall() method of the Transport class services the incoming call by dispatching it
    4. The dispatch() method calls the appropriate method on the object and pushes the result back down the wire.
    5. If the server object throws an exception, the server catches it and marshals it down the wire instead of the return value.
  4. Back on the client side:
    1. The return value of the RMI is unmarshalled and returned from the stub back to the client code itself.
    2. If an exception is thrown from the server, that is unmarshalled and thrown from the stub.