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

RMI with Multiple Objects of Different Types Having Multiple Methods

Java Programming, Lecture Notes 602, Revised 2/11/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 different types each of which has multiple methods.
 
 

Introduction

Previous lesson have given you an introduction to RMI.  I am going to assume that you have read those lessons and skip most of the introductory and overview material.

Briefly, Java's Remote Method Invocation (RMI) makes it possible for code running in one Java Virtual Machine (JVM) to invoke methods in an object running in another JVM which may be on the same or a different computer.

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

After some preliminaries, the invocation of methods on the remote objects is essentially no different from the invocation of methods on local objects.

A previous lesson illustrated RMI by exposing two different remote objects of the same type, each of which exposed two different methods.  This lesson upgrades the process by exposing two remote objects of different types, each of which exposes two methods.

Overview

The implementation of RMI for a minimal application in an earlier lesson required me to write and compile four source code files and to execute two different utility programs.  In general, the minimum number of source code files consists of a server file, a client file, and two files for each type of object being exposed by the server.  The two files required for each type of exposed object consist of an interface definition file and a class definition file.

Therefore, for the sample program in this lesson that exposes two different types of objects, six files are required.  The six files are:

As before, the two utility programs are:

This process produces a minimum of ten class files that must be installed on the client and the server.  I will discuss those ten files briefly in the next section.

Once you work through the material in this lesson, you should be able to see patterns emerge that you can use to write RMI applications invoking any number of methods on any number of different types of exposed objects.

Sample Program

The biggest challenge with a program of this sort is keeping track of which class files must be installed where.  As in the previous lessons, I made the process semi-automatic by encapsulating the 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 names of the six source files required by this application are listed below.

The ten class files produced by the process were:

The Batch file

The name of the batch file is Rmi04.bat.  A complete listing of the file is provided near the end of this lesson.  Because of the greater number of class files involved, a number of changes to the batch file were required in order to install those files in the correct folder.  Most of that should be pretty obvious.

However, it may not be obvious that the rmic.exe program must be executed twice in this case, once for each different type of remote object being exposed.  Each time this program is executed, it creates two new class files of the stub and skeleton variety.  I have highlighted those files using Italics in the above list of class files.

The lines in the batch file that accomplish this are shown below.
 

rmic Rmi04RemoteObjA
rmic Rmi04RemoteObjB

I'm not going to go over all the changes in the batch file in detail.  You can probably figure out what changes were required by taking a look at it.  If that doesn't do it, compare it in detail with the batch file in an earlier lesson and highlight the differences.  The important thing is for you to be able to produce a similar batch file for any number of objects of different types being exposed.

The Interface Files

Since this program exposes two different types of objects, it needs two different interface files to declare the methods that can be remotely invoked for each type of exposed object.

Except for the fact that there are now two different interface files with different names, there is nothing significantly different between these two files and the single interface file used in the earlier lesson.  Therefore, I won't bother to show them here.

The Remote Object Files

Because this program exposes two different types of objects, it needs a class definition for each type of object being exposed.

Again, except for the fact that there are two of them, and they have different names, there is nothing significantly different between these two class definitions and the single class definition used in the earlier lesson.  Therefore, I won't show them here.  You can view them in the program listings near the end of the lesson.

The Server Code File

The server code for this program differs from the earlier version in that the two objects that it instantiates are of two different types instead of being of the same type.  I have highlighted these differences in boldface below.
 

/*File Rmi04Server.java
Rev 10/09/98.
**********************************************************/
//snip
      Rmi04RemoteObjA remoteObjA 
                           = new Rmi04RemoteObjA("objA-1");
      Rmi04RemoteObjB remoteObjB 
                           = new Rmi04RemoteObjB("objB-2");
//snip
      Naming.rebind("helloObjA", remoteObjA);
      Naming.rebind("helloObjB", remoteObjB);
//snip

The Client Code File

That brings us to the client code shown below.

As in the earlier lesson, this code goes to the registry on the server twice and obtains references to two different remote objects: refToObjA and refToObjB.  However, in this case, the references are of two different types instead of being of the same type as was the case in the earlier lesson.

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

/*File Rmi04Client.java
**********************************************************/
//snip   
    String partOfUrl = "rmi://localhost/"; 
    try{
      Rmi04RemoteIntfcA refToObjA = 
                         (Rmi04RemoteIntfcA)Naming.lookup(
                                  partOfUrl + "helloObjA");
      Rmi04RemoteIntfcB refToObjB = 
                         (Rmi04RemoteIntfcB)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

Now you've seen an RMI application that supports multiple methods on multiple remote objects of different types.  Hopefully you can extend this to apply to any number of methods on any number of different remote object types.

Complete listings of all of the code are provided in the next section.

Program Listings

rem File Rmi04.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 Rmi04*.class
del Client\*.class
del Server\*.class

echo Compile files required by Server
jvc Rmi04Server.java

echo Compile files required by Client
jvc Rmi04Client.java

echo Run rmic utility to create skeleton and stub classes
rmic Rmi04RemoteObjA
rmic Rmi04RemoteObjB

echo Put a copy of the stub class in the Serverfolder
copy Rmi04RemoteObjA_Stub.class Server
copy Rmi04RemoteObjB_Stub.class Server

echo Put a copy of the skeleton class in the Server folder
copy Rmi04RemoteObjA_Skel.class Server
copy Rmi04RemoteObjB_Skel.class Server

echo Put a copy of the remote obj class file in Server
copy Rmi04RemoteObjA.class Server
copy Rmi04RemoteObjB.class Server

echo Put a copy of the remote server class file in Server
copy Rmi04Server.class Server

echo Put copy of remote interface class file in Server
copy Rmi04RemoteIntfcA.class Server
copy Rmi04RemoteIntfcB.class Server

echo Put copy of client class file in Client folder
copy Rmi04Client.class Client

echo Put a copy of the stub class in the Client folder
copy Rmi04RemoteObjA_Stub.class Client
copy Rmi04RemoteObjB_Stub.class Client

echo Put copy of remote interface class file in Client
copy Rmi04RemoteIntfcA.class Client
copy Rmi04RemoteIntfcB.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 Rmi04Server
cd ..

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

echo Manually terminate the remote object.

.

/*File Rmi04RemoteIntfcA.java
Rev 10/10/98.
This is the interface for an RMI Hello World program
that declares two methods.
**********************************************************/

import java.rmi.*;

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

  String goodbye(String client) throws RemoteException;

}//end Rmi04RemoteIntfcA definition

.

/*File Rmi04RemoteIntfcB.java
Rev 10/10/98.
This is the interface for an RMI Hello World program
that declares two methods.
**********************************************************/

import java.rmi.*;

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

  String goodbye(String client) throws RemoteException;

}//end Rmi04RemoteIntfcB definition

.

/*File Rmi04RemoteObjA.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 Rmi04RemoteObjA extends UnicastRemoteObject
                             implements Rmi04RemoteIntfcA{

  String objID;
  
  public Rmi04RemoteObjA(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 Rmi04RemoteObjA

.

/*File Rmi04RemoteObjB.java
Rev 10/09/98.
This is the remote object for an RMI hello world program
that defines two methods..
**********************************************************/

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

public class Rmi04RemoteObjB extends UnicastRemoteObject
                             implements Rmi04RemoteIntfcB{

  String objID;
  
  public Rmi04RemoteObjB(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 Rmi04RemoteObjB

.

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

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

public class Rmi04Server{
  
  public static void main(String args[]){
    System.setSecurityManager(new RMISecurityManager());
      
    try{
      Rmi04RemoteObjA remoteObjA 
                           = new Rmi04RemoteObjA("objA-1");
      Rmi04RemoteObjB remoteObjB 
                           = new Rmi04RemoteObjB("objB-2");

      //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 Rmi04Server

.

/*File Rmi04Client.java
Rev 10/09/98.
This program is the client for an RMI hello world program
that invokes two different methods on each of two 
different objects of different types.
**********************************************************/

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

public class Rmi04Client{
  
  public static void main(String[] args){
    System.setSecurityManager(new RMISecurityManager()); 
    String partOfUrl = "rmi://localhost/"; 
    try{
      Rmi04RemoteIntfcA refToObjA = 
                         (Rmi04RemoteIntfcA)Naming.lookup(
                                  partOfUrl + "helloObjA");
      Rmi04RemoteIntfcB refToObjB = 
                         (Rmi04RemoteIntfcB)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 Rmi04Client

-end-