Introduction to Java Programming-Comprehensive Version (6th Edition)
[Page 1246 ( continued )]
36.3. Developing RMI Applications
Now that you have a basic understanding of RMI, you are ready to write simple RMI applications. The steps in developing an RMI application are shown in Figure 36.4.
[Page 1247]
Figure 36.4. The steps in developing RMI applications.
1.
Define a server object interface that serves as the contract between the server and its clients , as shown in the following outline:
public interface ServerInterface extends Remote { public void service1(...) throws RemoteException; // Other methods }
A server object interface must extend the java.rmi.Remote interface.
2.
Define a class that implements the server object interface, as shown in the following outline:
public class ServerInterfaceImpl extends UnicastRemoteObject implements ServerInterface { public void service1(...) throws RemoteException { // Implement it } // Implement other methods }
The server implementation class must extend the java.rmi.server.UnicastRemoteObject class. The UnicastRemoteObject class provides support for point-to-point active object references using TCP streams.
3.
Create a server object from the server implementation class and register it with an RMI registry:
ServerInterface server = new ServerInterfaceImpl(...); Registry registry = LocateRegistry.getRegistry(); registry.rebind( "RemoteObjectName" , obj);
4.
Develop a client that locates a remote object and invokes its methods, as shown in the following outline:
The example that follows demonstrates the development of an RMI application through these steps.
36.3.1. Example: Retrieving Student Scores from an RMI Server
This example creates a client that retrieves student scores from an RMI server. The client, shown in Figure 36.5, displays the score for the specified name .
Figure 36.5. You can get the score by entering a student name and clicking the Get Score button.
(This item is displayed on page 1248 in the print version)
1.
Create a server interface named StudentServerInterface in Listing 36.1. The interface tells the client how to invoke the server's findScore method to retrieve a student score.
[Page 1248]
Listing 36.1. StudentServerInterface.java
1 import java.rmi. * ; 2 3 public interface StudentServerInterface extends Remote { 4 /** 5 * Return the score for the specified name 6 * @param name the student name 7 * @return an double score or -1 if the student is not found 8 */ 9 public double findScore(String name) throws RemoteException; 10 }
Any object that can be used remotely must be defined in an interface that extends the java.rmi.Remote interface (line 3). StudentServerInterface , extending Remote , defines the findScore method that can be remotely invoked by a client to find a student's score. Each method in this interface must declare that it may throw a java.rmi.RemoteException (line 9). Therefore your client code that invokes this method must be prepared to catch this exception in a try-catch block.
2.
Create a server implementation named StudentServerInterfaceImpl (Listing 36.2) that implements StudentServerInterface . The findScore method returns the score for a specified student. It returns “1 if the score is not found.
Listing 36.2. StudentServerInterfaceImpl.java
(This item is displayed on pages 1248 - 1249 in the print version)
1 import java.rmi. * ; 2 import java.rmi.server. * ; 3 import java.util. * ; 4 5 public clas s StudentServerInterfaceImpl extends UnicastRemoteObject 6 implements StudentServerInterface { 7 // Stores scores in a map indexed by name 8 private HashMap scores = new HashMap(); 9 10 public StudentServerInterfaceImpl() throws RemoteException { 11 initializeStudent(); 12 } 13 14 /** Initialize student information */ 15 protected void initializeStudent() { 16 scores.put( "John" , new Double( 90 . 5 )); 17 scores.put( "Michael" , new Double( 100 )); 18 scores.put( "Michelle" , new Double( 98 . 5 )); 19 } 20
[Page 1249]
21 /** Implement the findScore method from the Student interface */ 22 public double findScore(String name) throws RemoteException { 23 Double d = (Double)scores.get(name); 24 25 if (d == null ) { 26 System.out.println( "Student " + name + " is not found " ); 27 return -1 ; 28 } 29 else { 30 System.out.println( "Student " + name + "\'s score is " 31 + d.doubleValue()); 32 return d.doubleValue(); 33 } 34 } 35 }
The StudentServerInterfaceImpl class implements StudentServerInterface . This class must also extend the java.rmi.server.RemoteServer class or its subclass. RemoteServer is an abstract class that defines the methods needed to create and export remote objects. Often its subclass java.rmi.server.UnicastRemoteObject is used (line 5). This subclass implements all the abstract methods defined in RemoteServer .
StudentServerInterfaceImpl implements the findScore method (lines 22 “34) defined in StudentServerInterface . For simplicity, three students, John, Michael, and Michelle, and their corresponding scores are stored in an instance of java.util.HashMap named scores . HashMap is a concrete class of the Map interface in the Java Collections Framework, which makes it possible to search and retrieve a value using a key. Both values and keys are of Object type. The findScore method returns the score if the name is in the hash map, and returns -1 if the name is not found (line 27).
3.
Create a server object from the server implementation and register it with the RMI server (Listing 36.3).
RegisterWithRMIServer contains a main method, which is responsible for starting the server. It performs the following tasks : (1) create a server object (line 7); (2) obtain a reference to the RMI registry (line 8), and (3) register the object in the registry (line 9).
4.
Create a client as an applet named StudentServerInterfaceClient in Listing 36.4. The client locates the server object from the RMI registry and uses it to find the scores.
[Page 1250]
Listing 36.4. StudentServerInterfaceClient.java
(This item is displayed on pages 1250 - 1251 in the print version)
StudentServerInterfaceClient invokes the findScore method on the server to find the score for a specified student. The key method in StudentServerInterfaceClient is the initializeRMI method (lines 56 “69), which is responsible for locating the server stub.
The initializeRMI() method treats standalone applications differently from applets. The host name should be the name where the applet is downloaded. It can be obtained using the Applet 's getCodeBase().getHost() . For standalone applications, the host name should be specified explicitly.
The lookup(String name) method (line 63) returns the remote object with the specified name. Once a remote object is found, it can be used just like a local object. The stub and the skeleton are used behind the scenes to make the remote method invocation work.
5.
Follow the steps below to run this example.
5.1. Start the RMI Registry by typing " start rmiregistry" at a DOS prompt from the c:\book directory. By default, the port number 1099 is used by rmiregistry. To use a different port number, simply type the command " start rmiregistry portnumber" at a DOS prompt.
5.2. Start the server RegisterWithRMIServer using the following command at c:\book directory:
C:\book> java RegisterWithRMIServer
5.3. Run the client StudentServerInterfaceClient as an application. A sample run of the application is shown in Figure 36.6.
Figure 36.6. To run an RMI program, first start the RMIRegistry, then register the server object with the registry. The client locates it from the registry.
(This item is displayed on page 1252 in the print version)
5.4. Run the client StudentServerInterface.html from the appletviewer. A sample run is shown in Figure 36.5.
Note
You must start rmiregistry from the directory where you will run the RMI server. Otherwise, you will receive the error ClassNotFoundException on StudentServerInterfaceImpl_Stub .
[Page 1252]
Note
Server, registry, and client can be on three different machines. If you run the client and the server on separate machines, you need to place StudentServerInterface on both machines. If you deploy the client as an applet, place all client files on the registry host.
Caution
If you modify the remote object implementation class, you need to restart the server class to reload the object to the RMI registry. In some old versions of rmiregistry, you may have to restart rmiregistry.