Java Programming, Lecture Notes 602, Revised 2/11/99.
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.
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.
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.
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 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.
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.
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 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 |
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.
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-