«^»
2.2. How do you use RMI?

Suppose that we want an object that looks after an integral value. We want the ability for any Java application/applet running on any computer to get the latest value, or to set it to some new value:

To use RMI, we need an interface that defines the services that will be available from the object:

0001: package RMI.Count;                                           // CountIF.java
0002: public interface CountIF extends java.rmi.Remote {
0003:    int getCount() throws java.rmi.RemoteException;
0004:    void setCount(int vCount) throws java.rmi.RemoteException;
0005: }
We now need to define what happens when getCount and setCount get called. We do this by defining a class that implements the interface:
0006: package RMI.Count;                                      // CountServant.java
0007: import java.rmi.RemoteException;
0008: import java.rmi.server.UnicastRemoteObject;
0009: public class CountServant extends UnicastRemoteObject implements CountIF {
0010:    public CountServant() throws RemoteException {
0011:       super();
0012:       System.out.println("CountServant: constructor called");
0013:       iCount = 0;
0014:    }
0015:    public synchronized int getCount() throws RemoteException {
0016:       System.out.println("CountServant: getCount called");
0017:       return iCount;
0018:    }
0019:    public synchronized void setCount(int vCount) throws RemoteException {
0020:       System.out.println("CountServant: setCount called with " + vCount);
0021:       iCount = vCount;
0022:    }
0023:    private int iCount;
0024: }

On the server computer, we need a Java application that creates an object that is of the CountServant class. The CountServer program creates an object called realCount and then registers the object with the RMI-Registry. It does this by using the rebind method from the class java.rmi.Naming passing to it the name first Count that will allow any client to refer to the object:

0025: package RMI.Count;                                       // CountServer.java
0026: import java.rmi.Naming;
0027: import java.rmi.RMISecurityManager;
0028: public class CountServer {
0029:    public static void main(String[] args) {
0030:       System.setSecurityManager(new RMISecurityManager());
0031:       try {
0032:          CountServant realCount = new CountServant();
0033:          Naming.rebind("first Count", realCount);
0034:       }
0035:       catch(Exception rException) {
0036:          rException.printStackTrace();
0037:       }
0038:    }
0039: }

Finally, on the client computer, we want a Java application that accesses the methods of this object:

0040: package RMI.Count;                                       // CountClient.java
0041: import java.io.DataInputStream;
0042: import java.rmi.Naming;
0043: import java.rmi.RMISecurityManager;
0044: public class CountClient {
0045:    public static void main(String[] args) {
0046:       DataInputStream stdin = new DataInputStream(System.in);
0047:       System.setSecurityManager(new RMISecurityManager());
0048:       try {
0049:          CountIF stubCount = 
0050:                (CountIF) Naming.lookup("rmi://" + args[0] + "/first Count");
0051:          System.out.println("before loop");
0052:          while (true) {
0053:             String stdinLine = stdin.readLine();
0054:             if ( stdinLine.equals("quit") ) break;
0055:             if ( stdinLine.equals("show") )
0056:                System.out.println(stubCount.getCount());
0057:             else {
0058:                int intVal = Integer.parseInt(stdinLine);
0059:                stubCount.setCount(intVal);
0060:             }
0061:          }
0062:          System.out.println("after loop");
0063:       } 
0064:       catch(Exception rException) {
0065:          rException.printStackTrace();
0066:       }
0067:    }
0068: }
The CountClient program uses the lookup method from the class java.rmi.Naming to locate the remote object:
0049:          CountIF stubCount = 
0050:                (CountIF) Naming.lookup("rmi://" + args[0] + "/first Count");
It needs to be passed a string like "rmi://hercules.dur.ac.uk/first Count". This string looks like a URL: it specifies the name of the server and the name of the object. In the CountClient program, the name of the server is actually obtained from args[0], the first argument on the command line used to run the program.

The call of lookup communicates with the RMI-Registry on the server. It returns a value that can be used as an object of the interface CountIF. So, we can use the reference variable stubCount to refer to the remote object. In fact, the CountClient program contains a call of both stubCount.setCount and stubCount.getCount.