The Structure of a Server

2. The client application sends the request to the server. 3. Before the request gets to the server, Larry the rodent bites through the server power cord, thus shutting down the server. 4. After a while, the client application times out. 5. Later, when the network comes back up, Sue tries to withdraw money again. The client application has no way of differentiating between these two scenarios™all it knows is that, after it sent the request, the server became unreachable. But from the servers point of view, these are very different scenarios. In the first case, Sues account has to be credited. In the second case, the server should not credit Sues account. This means that, when the server receives a request from a client for a transaction to be cancelled, the server must double check to make sure the transaction actually occurred. Thus, it is very important for data objects to correctly implement equals and hashCode . A given server may store objects in a container that relies on equals to test for membership for example, an ArrayList . Or it may use a container such as HashMap , which relies on hashCode . Another aspect of this is that the server should also check incoming requests to make sure the same request hasnt been issued twice. Because of this, its fairly common to explicitly use an identity field inside a data object. For example, two print requests may have identical data fields simply because the user wanted to print two copies of a document before a big meeting. It would be really annoying if the printer arbitrarily rejected such requests. So, DocumentDescription can be modified to add a request_identity field, which contains a unique integer. This is extra information that has nothing to do with the actual printing functionality but lets the printer server tell whether it is receiving the same request, or a new request that just happens to result in the same document being printed again.

Chapter 8. Implementing the Bank Server

In the previous chapter, we discussed the interfaces and data objects for the bank example. In this chapter, well continue with the development cycle by building the servers and discussing the various design options that are available. This chapter is much shorter than the previous two because most of the intellectual heavyweight lifting has already been done. Nonetheless, by the end of this chapter, we will have fully implemented the servers for the bank example.

8.1 The Structure of a Server

The server objects you write in RMI are just the tip of the iceberg. When you add the automatically generated code and the pre-existing libraries and runtime, every RMI server has the layered structure at runtime shown in Figur e 8- 1 . Figure 8-1. Runtime structure for RMI servers These components have the following roles: Actual sockets These are just instances of Socket and ServerSocket , exactly as discussed in Chapt er 1 . The number of sockets is explicitly controlled by the RMI runtime and is usually proportional to the number of RMI clients connected to a JVM. RMI runtime This listens and receives any data coming in over the socket. Because it knows the wire protocol that RMI uses, the RMI runtime can take the data that comes in from the socket and break it apart into distinct method calls encapsulated as instances of java.rmi.server.RemoteCall . It looks at each of these distinct method calls and forwards them to the appropriate skeletons dispatch method. There is only one RMI runtime per JVM. Skeletons The skeleton is a piece of automatically generated code responsible for implementing dispatch . As part of the implementation of dispatch , the skeleton demarshalls the invocation arguments and performs validation checks related to class versions. It then calls the correct method on the server object. There is a single skeleton per server instance. Using different skeletons for different classes is not, strictly speaking, necessary. Well talk about why you want to get rid of them, and how to do so, later in this chapter. Application-specific server objects This is the code that you write. It implements the remote interface for the server and usually has no other behavior. There are as many instances of these as are required by the application. Note that the first three layers can all throw instances of RemoteException . Generally speaking, this means that something went wrong in the RMI infrastructure shown earlier. So your server code should never throw a RemoteException .

8.2 Implementing the Server