Maintaining Direct Connections The Serialization Algorithm

What the registry actually gets is a stub. The stub for Account_Impl , which was automatically generated by rmic , begins with: public final class Account_Impl_Stub extends java.rmi.server.RemoteStub java.rmi.server.RemoteStub is a class that implements the Serializable interface. The RMI serialization mechanism knows that whenever a remote server is sent over the wire, the server object should be replaced by a stub that knows how to communicate with the server e.g., a stub that knows on which machine and port the server is listening. Calling Naming.rebind actually winds up passing a stub to the RMI registry. When clients make calls to Naming.lookup , as in the following code snippet, they also receive copies of the stub. Since the stub is serializable, theres no problem in making a copy of it: _account = AccountNaming.lookup_accountNameField.getText ; In order to enable this behavior, ObjectOutputStream calls enableReplaceObject and replaceObject during the serialization process. In other words, when an instance is about to be serialized, ObjectOutputStream does the following: 1. It calls enableReplaceObject to see whether instance replacement is enabled. 2. If instance replacement is enabled, it calls replaceObject , passing in the instance it was about to serialize, to find out which instance it should really write to the stream. 3. It then writes the appropriate instance to the stream.

10.4.4 Maintaining Direct Connections

A question that frequently arises as distributed applications get more complicated involves message forwarding. For example, suppose that we have three communicating programs: A , B , and C . At the start, A has a stub for B , B has a stub for C , and C has a stub for A . See Figur e 10- 6 . Figure 10-6. Communication between three applications Now, what happens if A calls a method, for example, getOtherServer , on B that returns C ? The answer is that A gets a deep copy of the stub B uses to communicate with C . That is, A now has a direct connection to C ; whenever A tries to send a message to C , B is not involved at all. This is illustrated in Figur e 10- 7 . Figure 10-7. Improved communication between three applications This is very good from a bandwidth and network latency point of view. But it can also be somewhat problematic. Suppose, for example, B implements load balancing. Since B isnt involved in the A to C communication, it has no direct way of knowing whether A is still using C , or how heavily. Well revisit this in Chapt er 16 and Chapt er 17 , when we discuss the distributed garbage collector and the Unreferenced interface.

10.5 Versioning Classes

A few pages back, I described the serialization mechanism: The serialization mechanism automatically, at runtime, converts class objects into metadata so instances can be serialized with the least amount of programmer work. This is great as long as the classes dont change. When classes change, the metadata, which was created from obsolete class objects, accurately describes the serialized information. But it might not correspond to the current class implementations.

10.5.1 The Two Types of Versioning Problems

There are two basic types of versioning problems that can occur. The first occurs when a change is made to the class hierarchy e.g., a superclass is added or removed. Suppose, for example, a personnel application made use of two serializable classes: Employee and Manager a subclass of Employee . For the next version of the application, two more classes need to be added: Contractor and Consultant . After careful thought, the new hierarchy is based on the abstract superclass Person , which has two direct subclasses: Employee and Contractor . Consultant is defined as a subclass of Contractor , and Manager is a subclass of Employee . See Figur e 10- 8 . Figure 10-8. Changing the class hierarchy While introducing Person is probably good object-oriented design, it breaks serialization. Recall that serialization relied on the class hierarchy to define the data format.