Methods Across the Wire

Though convenient, automatically generating marshalling and demarshalling code is mostly a side effect produced in the service of a much more important goal. In a nutshell:

RMI is designed to make communication between two Java programs, running in separate JVMs, as much like making a method call inside a single process as possible.

This is an ambitious goal. How does RMI achieve it?

Recall that in order to communicate with the printer server, we wrote an object,

ClientNetworkWrapper, which did three things:

  • It opened a socket.
  • It told an instance of DocumentDescription to write itself to the stream.
  • It read and interpreted information from the input stream associated with the socket.

In addition, we wrote a companion object, ServerNetworkWrapper, which played an analogous role on the server side.

RMI relies on two similar types of objects that are automatically generated by the RMI Compiler from an implementation of the server: stubs and skeletons. A stub is a client-side object that represents a single server object inside the client's JVM. It implements the same methods as the server object, maintains a socket connection to the server object's JVM automatically and is responsible for marshalling and demarshalling data on the client side. A skeleton is a server-side object responsible for maintaining network connections and marshalling and demarshalling data on the server side.

The word stub is actually used to mean two different things. Depending on context, it might refer to a stub class that is automatically generated from a server class object.

automatically generated from a server class object. Alternatively, it might refer to an instance of a particular stub class (that is, to a reference to a specific instance of the server class). Because stubs have such a well-defined role in a distributed architecture, the meaning is usually clear from context. Similarly, skeleton can either refer to the skeleton class or to an instance of the skeleton class.

The basic procedure a client uses to communicate with a server is as follows:

  1. The client obtains an instance of the stub class. The stub class is automatically pregenerated from the target server class and implements all the methods that the server class implements.
  2. The client calls a method on the stub. The method call is actually the same method call the client would make on the server object if both objects resided in the same JVM.
  3. Internally, the stub either creates a socket connection to the skeleton on the server or reuses a pre-existing connection. It marshalls all the information associated to the method call, including the name of the method and the arguments, and sends this information over the socket connection to the skeleton.
  4. The skeleton demarshalls the data and makes the method call on the actual server object. It gets a return value back from the actual server object, marshalls the return value, and sends it over the wire to the stub.
  5. The stub demarshalls the return value and returns it to the client code.

Stubs and skeletons are shown in Figure 4-1.

Figure 4-1. A basic RMI call with a stub and skeleton

If this approach seems familiar, it's because the stub and the skeleton are really automatically generated, object-oriented versions of the objects we created for our socket-based printer server.

0 0

Post a comment

  • Receive news updates via email from this site