How RMI Solves the Bootstrapping Problem

is that the definition of RMI is independent of TCPIP. Technically speaking, all an implementation of RMI requires is a streams-based communication protocol. The concrete goal is that sockets get reused. When ref.newCall executes, the transport layer checks to see if an already existing socket is available e.g., has no currently executing remote method invocations on it. If such a socket is available, it reuses the socket. Otherwise, a new socket connection to the server is created and used. This leads to another problem. We effectively have the diagram in Figur e 16- 2 . Figure 16-2. Sharing sockets If a socket is reused by several client stubs, each of which sends messages to a different server, those messages must get differentiated somehow. In RMI, this is managed through the use of the ObjID class, which is defined in the java.rmi.server package. The javadoc for ObjID says the following: An ObjID is used to identify remote objects uniquely in a VM over time. 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. If the java.rmi.server.randomIDs property is true , then the object number component 64 bits of an ObjID created with the no argument constructor will contain a cryptographically strong random number. Thus, an instance of ObjID uniquely identifies a particular server inside the servers JVM. The ObjID class implements the Serializable interface, and instances of it are serialized with every remote method call. Well frequently refer to object identifiers or object identities. These simply refer to instances of ObjID . On the server side, the RMI runtime uses the deserialized instance of ObjID to figure out for which skeleton the remote method invocation is intended.

16.1.1 How RMI Solves the Bootstrapping Problem

Most servers in ordinary use have randomly assigned instances of ObjID . However, there are three reserved identifiers: ACTIVATOR_ID , DGC_ID , and REGISTRY_ID . These three IDs correspond to the three main servers that RMI provides: the activation framework, the distributed garbage collector, and the RMI registry. Well talk about the distributed garbage collector later in this chapter and the activation framework in Chapt er 17 . The RMI registry needs a unique identifier, which is known in advance, in order to fully solve the bootstrapping problem. Recall that the RMI runtime tries to reuse sockets. RMI servers, even the registry, do not get dedicated sockets. But now consider a client attempting to connect to the RMI registry for the first time. Unless it already knows the object identity associated with a server, a client cannot send a message to that server. That is, since the servers RMI runtime requires an instance of ObjID in order to determine the appropriate server for a request, the client needs to know the ObjID of the registry running in the servers JVM in order to connect to the registry. In order to solve this problem, the designers of RMI decided to define a special instance of ObjID that is reserved™if a registry is running in a JVM, it uses REGISTRY_ID . Otherwise, no server is allowed to use REGISTRY_ID . This solves the RMI bootstrapping problem. The static methods defined in the Naming class take a string that contains the address of a computer on the network and a port; the only additional information needed to construct a stub is the object ID of the server to which the stub connects. Since the registry always uses REGISTRY_ID , a stub for the registry can be constructed entirely on the client side, before connecting to the registry. This strategy also means that there can only be one registry exported per JVM, since ObjID s cannot be shared by more than one server. In comparison, we solved the bootstrapping problem for the naming service implemented in Chapt er 15 by defining a second, more primitive protocol that was used only to establish initial connections. Each instance of BaseContextImpl had both its RMI behavior achieved by extending UnicastRemoteObject and a second port, which it used to vend stubs. This second port used a dedicated server socket that enabled our instances of BaseContextImpl to bypass the preceding problem. Since the message that establishes the initial connection doesnt go through RMI, the client doesnt need to know the identity of the BaseContextImpl in advance.

16.2 Distributed Garbage Collection