OHSWG 12.15.97
OHSWG logo

Open Hypermedia Systems Working Group

Beans, RMI, Voyager


Java RMI Example

This simple example is (in slightly modified form) from Client/Server Programming with Java and CORBA by Robert Orfali and Dan Harkey. The goal of the example is to develop a simple counter application. The server object maintains a counter which can be incremented by its clients. In the book, the example serves several purposes. First, it is easily understood and allows the reader to focus on the component technology being used. Second, round-trip network performance (e.g. a ping) for the component technology can be roughly measured by having the client invoke the server n times and computing the elapsed time divided by n.

We start out by defining the interface for the serverside program:


CountRMI.java
public interface CountRMI extends java.rmi.Remote {
    public int sum() throws java.rmi.RemoteException;
    public void sum(int _val) throws java.rmi.RemoteException;
    public int increment() throws java.rmi.RemoteException;
}
       

This file defines an interface called CountRMI, which is used to define the behaviour expected from a CountRMI server. Just as a Corba IDL file describes the interface a server implements, RMI server classes require that the methods they make available to the world are defined (as public) in an interface definition. As presented the interface defines a clas, which has an integer attribute, which can be retrieved and set. The attribute is incremented by the method increment. The class implements a noteworthy interface, java.rmi.Remote, which indicates that classes implementing CountRMI will be residing on a server. The Remote interface does not define methods - rather it is used to flag that this is an remote class.

The server is in:


CountRMIImpl.java
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class CountRMIImpl extends UnicastRemoteObject implements CountRMI {
  private int sum;
  
  public CountRMIImpl(String name) throws RemoteException {
    super();
    try {
      Naming.rebind(name, this);
      sum = 0;
    } catch (Exception e) { 
      System.out.println("Exception: " + e.getMessage());
      e.printStackTrace();
    }
  }

  public int sum() throws RemoteException { 
    return sum;
  }

  public void sum(int _val) throws RemoteException { 
    sum = _val;
  }

  public int increment() throws RemoteException { 
    return ++sum;
  }
}
       

There are several interesting things in this program. The CountRMIImpl not only implements CountRMI as could be expected, but also extends java.rmi.UnicastRemoteObject. UnicastRemoteObject implements the semantics a remote object with the following characteristics:

  1. A reference to an UnicastRemoteObject is only valid while the creator process exists
  2. Communication between client and server is done through streams over a TCP connection

In order to enable this implementation for RMI use, stub and skeleton classes must be created, which is done in the following manner:


$ rmic CountRMIImpl
$ dir CountRMIImpl*
-rw-r--r--   1 544      everyone     1109 Dec 15 00:08 CountRMIImpl.class
-rw-r--r--   1 544      everyone      725 Dec 15 00:06 CountRMIImpl.java
-rw-r--r--   1 544      everyone     1975 Dec 15 01:23 CountRMIImpl_Skel.class
-rw-r--r--   1 544      everyone     2465 Dec 15 01:23 CountRMIImpl_Stub.class

The client looks like this:
CountRMIClient.java
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;

public class CountRMIClient { 
  public static void main(String args[]) { 
    try { 
      CountRMI myCount = (CountRMI)Naming.lookup("rmi://" + args[0] + "/" + "my CountRMI"); 

      // Set Sum to initial value of 0
      System.out.println("Setting Sum to 0");
      myCount.setSum(0);

      // Calculate Start time
      long startTime = System.currentTimeMillis();

      // Increment 1000 times
      System.out.println("Incrementing");
      for (int i = 0 ; i < 1000 ; i++ ) { 
	myCount.increment();
      }

      // Calculate stop time; print out statistics
      long stopTime = System.currentTimeMillis();
      System.out.println("Avg Ping = " + ((stopTime - startTime)/1000f) + " msecs");
      System.out.println("Sum = " + myCount.getSum());
    } catch(Exception e) { 
      System.err.println("System Exception" + e);
    }
   System.exit(0);
  }
}
       

CountRMIClient starts out by locating a remote object implementing the CountRMI interface. The program is given the machine name whereon this object resides as parameter, and thus proceeds to get a reference to an object called 'my CountRMI' on the aforementioned machine. Once this has been accomplished the rest of the program is quite simple ordinary Java code, calculating the mean time of incrementing a counter.

Given the interface, the object implementing it, and the client to use it, we now only need the server to instantiate the remote object:


CountRMIServer.java
// CountRMIServer.java

import java.rmi.*;
import java.rmi.server.*;

public class CountRMIServer
{
  
  public static void main(String args[]) {
    
    // Create and install the security manager
    System.setSecurityManager(new RMISecurityManager());
    
    try {
      // Create CountRMIImpl
      CountRMIImpl myCount = new CountRMIImpl("my CountRMI");
      System.out.println("CountRMI Server ready.");
    } catch (Exception e) { 
      System.out.println("Exception: " + e.getMessage());
      e.printStackTrace();
    }
  }
}

The CountRMIServer starts out by installing a RMI security manager to protect itself from (possibly hostile) foreign classes. It then instantiates the implementation of CountRMI and gives it name 'my CountRMI'.

In order to run this under Windows NT, a developer would write the following:


$ start rmiregistry
$ start CountRMIServer
$ start java CountRMIServer
$ java CountRMIClient talisker.daimi.aau.dk
Symantec Java! JustInTime Compiler Version 210.063 for JDK 1.1.3
Copyright (C) 1996-97 Symantec Corporation

Setting Sum to 0
Incrementing
Avg Ping = 1.016 msecs
Sum = 1000

This example is thus completed.


Home Description Example Availability Recommendations References

Please send feedback to Niels Olof Bouvin. Last modified: Mon Dec 15 02:46:50 1997


Niels Olof Bouvin
U Aarhus, Denmark
bouvin@daimi.aau.dk
---