Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

RMI with Multiple Objects of the Same Type Having Multiple Methods

Java Programming, Lecture Notes 601, Revised 8/22/99.


Preface

Students in Prof. Baldwin's Advanced Java Programming classes at ACC will be responsible for knowing and understanding all of the material in this lesson beginning with the spring semester of 1999.

This lesson was originally written on October 10, 1998, using the JDK 1.1.6 download package (and sometimes the MS SDK). The purpose of this lesson is to illustrate RMI for the case of multiple remote objects of the same type each having multiple methods.
 
 

Introduction

A previous lesson gave you an introduction to RMI.  Briefly, Java's Remote Method Invocation (RMI) makes it possible for code in an object running in one Java Virtual Machine (JVM) to invoke methods in an object running in another JVM.  The two JVMs may be running as separate processes on the same computer, or may be running on different computers connected by a TCP/IP network.

The machine with the object whose methods are invoked remotely is the server, and the machine invoking the methods on the remote object is the client.

Once the client code has a reference to the remote objects, the invocation of methods on the remote objects is essentially no different from the invocation of methods on local objects (except for speed and some issues having to do with passing and returning objects by value or by reference).  The latter difference having to with value or reference will be discussed in a subsequent lesson.

The previous lesson illustrated RMI by exposing a single remote object, which in turn exposed a single method.  This lesson upgrades the process by exposing two remote objects of the same type, each of which exposes two methods.
 

Overview

The implementation of RMI for a minimal application requires you to write and compile four source code files and to execute two different utility programs.  The four source files are:

The two utility programs are:

This process produces a minimum of six class files that must be installed on the client and the server.  Obviously, your programs could produce many more class files than this minimal number depending on the behavior of the programs.

Execution of one of the utility programs on the server (rmiregistry.exe) creates and maintains a registry of objects on the server whose methods are exposed to clients.

Execution of the other utility program (rmic.exe) produces two special class files known as a stub file and a skeleton file.  These files must be installed on the client and the server machines in the manner described in the previous lesson.
 
 

Sample Program

There are a variety of ways to view the implementation of RMI, each of which leads to a different set of operational procedures.  I am taking the viewpoint that all of the software is compiled at a central location and the appropriate compiled class files are distributed to the client and to the server.

Keeping it all straight can be burdensome.  I have made the process semi-automatic by encapsulating the overall process in an MS-DOS batch file.  If you are not running under Windows or NT, you will need to figure out how to produce an equivalent script file for the platform that you are running on.

The previous lesson explained the batch file and the sequence of events showing how you can run RMI applications on a single hardware platform by running the client in one process and the server in a different process.  I am using that same process in this lesson.

The names of the four files mentioned above are listed below.

The Batch file

The name of the batch file is Rmi03.bat.  A complete listing of the file is provided near the end of this lesson.  With one exception, its structure is the same as the batch file used in the previous lesson.  Furthermore, the exception is of no operational significance.  The following fragment shows the lines in the batch file that are different.

jvc Rmi03Server.java
jvc Rmi03Client.java

What you see here is the substitution of the Microsoft Java compiler named jvc in place of the JavaSoft compiler named javac.  If you aren't running under a Microsoft operating system, or if you haven't downloaded the Java SDK from Microsoft, just change the jvc back to javac.

Why did I do this?  Does this suggest some sort of brand loyalty to Microsoft and Windows?  Not at all.  The reason is that the jvc compiler in the Microsoft SDK is about ten-thousand times faster than the javac compiler in JavaSoft JDK 1.1.6, and this makes a big difference when I repeatedly compile a program to test, debug, and refine it.  Does it always work?  No, I occasionally encounter strange compatibility problems and then I simply revert to the use of the trusty javac.  However, it does work most of the time so I use it a lot.

There is a corresponding JVM in the Microsoft SDK named jview that is a functional replacement for java.exe from JavaSoft.  I haven't found jview to be measurably faster than java.  Therefore, I usually use jvc to compile and java to execute unless I am using activex components, in which case I have no choice but to use jview.
 
 

The Interface File

The modified interface file is shown in the next fragment.  For brevity, I have edited out code (//snip) that is not germane to the discussion.  A complete listing of all the code is provided near the end of this lesson.

The interface now declares two methods named hello() and goodbye() instead of just one as in the previous lesson.  Otherwise, the interface definition hasn't changed.  This is the pattern that you are going to see throughout this lesson.  This expansion to multiple remote objects (of the same type) each having multiple methods doesn't cause any change in the basic structure of the software.  It simply requires expansion of the code within that structure.

If the expansion to multiple objects involved objects of different types, I would need to define a new interface for each different type of remote object.  This would involve a minor change to the overall structure of the software and will be illustrated in a subsequent lesson.
 

/*File Rmi03RemoteIntfc.java
**********************************************************/
//snip
public interface Rmi03RemoteIntfc extends Remote{
  String hello(String client) throws RemoteException;

  String goodbye(String client) throws RemoteException;

}//end Rmi03RemoteIntfc definition

The Remote Object File

The next source file that I will discuss is the one containing the definition of the class from which the remote objects are instantiated.

This code differs from the code in the previous lesson in two respects:

The first difference really has nothing to do with the expansion to two methods.  Rather, I did that to make it more meaningful to instantiate and expose two different objects of the same type.  Even though they are of the same type, they are functionally different because of their different initial states.
 

/*File Rmi03RemoteObj.java
**********************************************************/
//snip
  String objID;
  
  public Rmi03RemoteObj(String objID)
                                   throws RemoteException{
    this.objID = objID;//save the ID
  }//end constructor

  public String hello(String client) 
                                   throws RemoteException{
    return "Hello " + client + " from " + objID;
  }//end hello()
    
  public String goodbye(String client) 
                                   throws RemoteException{
    return "Goodbye " + client + " from " + objID;
  }//end goodbye()
//snip

Other than the differences discussed above, this class definition for remote objects is essentially the same as the one in the previous lesson.  Each of the methods receives a String object as a parameter, constructs and returns a String object.  The String object that is returned includes literal string text, the incoming String object, and the String object received and saved by the constructor when the object was instantiated.
 
 

The Server Code File

The next source code file that I will  discuss is the class defining the server software.  This code differs from the code in the previous lesson in two respects:

These differences are highlighted in boldface in the listing below.
 

/*File Rmi03Server.java
**********************************************************/
//snip
  public static void main(String args[]){
    System.setSecurityManager(new RMISecurityManager());
      
    try{
      Rmi03RemoteObj remoteObjA 
                              = new Rmi03RemoteObj("objA");
      Rmi03RemoteObj remoteObjB 
                              = new Rmi03RemoteObj("objB");

      //Had to register it this way to avoid Win95 error
      LocateRegistry.createRegistry(1099);

      Naming.rebind("helloObjA", remoteObjA);
      Naming.rebind("helloObjB", remoteObjB);
//snip

The Client Code File

That brings us to the final set of code that I will discuss in this lesson:  the client code shown below.  This code goes to the registry on the server twice and obtains references to two different remote objects: refToObjA and refToObjB.

Having obtained references to each of the two objects, the code invokes two methods on each of the objects:  hello() and goodbye().
 

/*File Rmi03Client.java
**********************************************************/
//snip  
  public static void main(String[] args){
    System.setSecurityManager(new RMISecurityManager()); 
    String partOfUrl = "rmi://localhost/"; 
    try{
      Rmi03RemoteIntfc refToObjA = 
                         (Rmi03RemoteIntfc)Naming.lookup(
                                  partOfUrl + "helloObjA");
      Rmi03RemoteIntfc refToObjB = 
                         (Rmi03RemoteIntfc)Naming.lookup(
                                  partOfUrl + "helloObjB");


      System.out.println(refToObjA.hello("Dick"));
      System.out.println(refToObjA.goodbye("Dick"));
      System.out.println(refToObjB.hello("Dick"));
      System.out.println(refToObjB.goodbye("Dick"));
//snip

Because this program sets a security manager, it may not run under JDK 1.2 without taking the necessary steps to comply with the more stringent security requirements of JDK 1.2.

And there you have it,  an RMI application that supports multiple methods on multiple remote objects of the same type.  A listing of the code is provided in the next section.
 

Program Listings

rem File Rmi03.bat
rem Rev 10/09/98
echo off
echo Make certain that you have a Client folder and
echo  a Server folder immediately below this one.

echo Delete residue from previous run
del Rmi03*.class
del Client\*.class
del Server\*.class

echo Compile files required by Server
jvc Rmi03Server.java

echo Compile files required by Client
jvc Rmi03Client.java

echo Run rmic utility to create skeleton and stub classes
rmic Rmi03RemoteObj

echo Put a copy of the stub class in the Serverfolder
copy Rmi03RemoteObj_Stub.class Server
echo Put a copy of the skeleton class in the Server folder
copy Rmi03RemoteObj_Skel.class Server
echo Put a copy of the remote obj class file in Server
copy Rmi03RemoteObj.class Server
echo Put a copy of the remote server class file in Server
copy Rmi03Server.class Server
echo Put copy of remote interface class file in Server
copy Rmi03RemoteIntfc.class Server

echo Put copy of client class file in Client folder
copy Rmi03Client.class Client
echo Put a copy of the stub class in the Client folder
copy Rmi03RemoteObj_Stub.class Client
echo Put copy of remote interface class file in Client
copy Rmi03RemoteIntfc.class Client

echo Should be able to start rmiregistry here, but it gives
echo  fatal error on my Win95 with jdk1.1.6.  Start it
echo  in server program instead.

echo Wait for remote object to become ready.  Then click 
echo  main window to keep things moving.

echo Start the server running in a different MSDOS window
cd Server
start java Rmi03Server
cd ..



echo Run client program twice to demo that remote object
echo  stays alive.
cd Client
java Rmi03Client
java Rmi03Client
cd..

echo Manually terminate the remote object.

/*File Rmi03RemoteIntfc.java
Rev 10/10/98.
This is the interface for an RMI Hello World program
upgraded to declare two methods.
**********************************************************/

import java.rmi.*;

public interface Rmi03RemoteIntfc extends Remote{
  String hello(String client) throws RemoteException;

  String goodbye(String client) throws RemoteException;

}//end Rmi03RemoteIntfc definition

.

/*File Rmi03RemoteObj.java
Rev 10/09/98.
This is the remote object for an RMI hello world program
upgraded to define two methods..
**********************************************************/

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

public class Rmi03RemoteObj extends UnicastRemoteObject
                              implements Rmi03RemoteIntfc{

  String objID;
  
  public Rmi03RemoteObj(String objID)
                                   throws RemoteException{
    this.objID = objID;//save the ID
  }//end constructor

  public String hello(String client) 
                                   throws RemoteException{
    return "Hello " + client + " from " + objID;
  }//end hello()
    
  public String goodbye(String client) 
                                   throws RemoteException{
    return "Goodbye " + client + " from " + objID;
  }//end goodbye()
    
}//end class Rmi03RemoteObj

.

/*File Rmi03Server.java
Rev 10/09/98.
This program is the remote server for an RMI version of
hello world upgraded to support two objects.
**********************************************************/

import java.rmi.*;
import java.rmi.server.*;
import sun.applet.*;
import java.rmi.registry.LocateRegistry;

public class Rmi03Server{
  
  public static void main(String args[]){
    System.setSecurityManager(new RMISecurityManager());
      
    try{
      Rmi03RemoteObj remoteObjA 
                              = new Rmi03RemoteObj("objA");
      Rmi03RemoteObj remoteObjB 
                              = new Rmi03RemoteObj("objB");

      //Had to register it this way to avoid Win95 error
      LocateRegistry.createRegistry(1099);

      Naming.rebind("helloObjA", remoteObjA);
      Naming.rebind("helloObjB", remoteObjB);
      
      System.out.println("Remote obj ready to use");
    }catch(Exception e){System.out.println("Error: " + e);}
  }//end main
}//end class Rmi03Server

.

/*File Rmi03Client.java
Rev 10/09/98.
This program is the client for an RMI hello world program
upgraded to support two remote objects, each with two
methods.
**********************************************************/

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

public class Rmi03Client{
  
  public static void main(String[] args){
    System.setSecurityManager(new RMISecurityManager()); 
    String partOfUrl = "rmi://localhost/"; 
    try{
      Rmi03RemoteIntfc refToObjA = 
                         (Rmi03RemoteIntfc)Naming.lookup(
                                  partOfUrl + "helloObjA");
      Rmi03RemoteIntfc refToObjB = 
                         (Rmi03RemoteIntfc)Naming.lookup(
                                  partOfUrl + "helloObjB");


      System.out.println(refToObjA.hello("Dick"));
      System.out.println(refToObjA.goodbye("Dick"));
      System.out.println(refToObjB.hello("Dick"));
      System.out.println(refToObjB.goodbye("Dick"));

    }catch(Exception e){System.out.println("Error " + e);}
    System.exit(0);
  }//end main
}//end class Rmi03Client

-end-