A Server That Extends UnicastRemoteObject A Server That Does Not Extend UnicastRemoteObject

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

We need to make one RMI-related decision when building our server. We have to decide whether to implement our server objects by subclassing UnicastRemoteObject . UnicastRemoteObject is a class defined in the java.rmi.server package and is intended to be the generic superclass for RMI servers. Simply subclassing UnicastRemoteObject and implementing the appropriate remote interfaces is the simplest and most convenient way of building an RMI server.

8.2.1 A Server That Extends UnicastRemoteObject

Exam ple 8- 1 shows an implementation of Account that subclasses UnicastRemoteObject . One particularly important point is that none of the code, with the possible exception of the class declaration, has anything to do with the network. To an astonishing extent, this is ordinary Java code. It is traditional in client-server circles to give interfaces descriptive names and then tack on an _Impl for the implementation. Thus, we have an interface called Account and an implementation called Account_Impl . This isnt a and an implementation called Account_Impl . This isnt a particularly pleasant naming convention, but it is traditional. Example 8-1. Account_Impl.java public class Account_Impl extends UnicastRemoteObject implements Account { private Money _balance; public Account_ImplMoney startingBalance throws RemoteException { _balance = startingBalance; } public Money getBalance throws RemoteException { return _balance; } public void makeDepositMoney amount throws RemoteException, NegativeAmountException { checkForNegativeAmountamount; _balance.addamount; return; } public void makeWithdrawalMoney amount throws RemoteException, OverdraftException, NegativeAmountException { checkForNegativeAmountamount; checkForOverdraftamount; _balance.subtractamount; return; } private void checkForNegativeAmountMoney amount throws NegativeAmountException { int cents = amount.getCents ; if 0 cents { throw new NegativeAmountException ; } } private void checkForOverdraftMoney amount throws OverdraftException { if amount.greaterThan_balance { throw new OverdraftExceptionfalse; } return; } }

8.2.2 A Server That Does Not Extend UnicastRemoteObject

The alternative implementation of Account , which doesnt extend Unicast - RemoteObject , is substantially the same code. In fact, the code shown in Exam ple 8- 2 has only two differences: • Account_Impl2 doesnt declare that it extends UnicastRemoteObject . • Account_Impl2 implements equals and hashCode directly. These are important points. However you choose to implement your server, whether you choose to extend UnicastRemoteObject or not, the code for the methods defined in the Account interface is almost identical. The difference is in the code that ties your server to the RMI runtime, not in the code that implements your business logic. In other words, the decision to extend UnicastRemoteObject has no impact on that code. Example 8-2. java public class Account_Impl2 implements Account { private Money _balance; public Account_Impl2Money startingBalance throws RemoteException { _balance = startingBalance; } public Money getBalance throws RemoteException { return _balance; } public void makeDepositMoney amount throws RemoteException, NegativeAmountException { checkForNegativeAmountamount; _balance.addamount; return; } public void makeWithdrawalMoney amount throws RemoteException, OverdraftException, NegativeAmountException { checkForNegativeAmountamount; checkForOverdraftamount; _balance.subtractamount; return; } private void checkForNegativeAmountMoney amount throws NegativeAmountException { int cents = amount.getCents ; if 0 cents { throw new NegativeAmountException ; } } private void checkForOverdraftMoney amount throws OverdraftException { if amount.greaterThan_balance { throw new OverdraftExceptionfalse; } return; } public boolean equalsObject object { Three cases. Either its us, o r its our stub, or its not equal. our stub can arise, for example, if one of our methods took an instance of Account. A client could then pass in, as an argument, our stub. if object instanceof Account_Imp l2 { return object == this; } if object instanceof RemoteStub { try { RemoteStub ourStub = RemoteStubRemoteObject.toStubthis; return ourStub.equalsobject; } catchNoSuchObjectException e{ were not listening on a port, therefore its not our stub } } return false; } public int hashCode { try { Remote ourStub = RemoteObject.toStubthis; return ourStub.hashCode ; } catchNoSuchObjectException e{} return super.hashCode ; } }

8.2.3 Extending UnicastRemoteObject