The Artima Developer Community
Sponsored Link

Objects and Java Seminar by Bill Venners
RMI (Remote Method Invocation)
Lecture Handout

Agenda


Remote Method Invocation


Remote Interface


Define a Remote Interface


The Summer Interface

 1 // In file rmi/ex1/Summer.java
 2 import java.rmi.*;
 3
 4 public interface Summer extends Remote {
 5
 6     long sumString(String s)
 7         throws InvalidLongException,
 8         RemoteException;
 9 }
10

 1 // In file rmi/ex1/InvalidLongException.java
 2 public class InvalidLongException
 3     extends Exception {
 4
 5     private String message;
 6     InvalidLongException(String s) {
 7         message = s;
 8     }
 9     public String getMessage() {
10         return message;
11     }
12 }

Define the Implementation


The SummerImpl Class

 1 // In file rmi/ex1/SummerImpl.java
 2 import java.rmi.*;
 3 import java.rmi.server.*;
 4 import java.io.*;
 5 import java.util.StringTokenizer;
 6
 7 public class SummerImpl
 8         extends UnicastRemoteObject
 9         implements Summer {
10
11
12
13     public SummerImpl() throws RemoteException {
14     }
15
16     public long sumString(String s)
17         throws InvalidLongException, RemoteException {
18         long sum = 0;
19         StringTokenizer st = new StringTokenizer(s);
20         String token;
21         while (st.hasMoreTokens()) {
22             token = st.nextToken();
23             try {
24                 sum += Long.parseLong(token);
25             }
26             catch (NumberFormatException e) {
27                 throw new InvalidLongException(
28                     "Invalid number: " + token);
29             }
30         }
31
32         return sum;
33     }
34 }

RMI Registry


Define the Server


The SummerServer

 1 // In file rmi/ex1/SummerServer.java
 2 import java.rmi.*;
 3
 4 public class SummerServer {
 5
 6
 7
 8     public static void main(String[] args) {
 9
10         System.setSecurityManager(
11             new RMISecurityManager());
12         try {
13             SummerImpl summer = new SummerImpl();
14             System.out.println("Ready to rebind");
15             Naming.rebind("SUMMER", summer);
16             System.out.println("Ready to sum");
17         }
18         catch(Exception e) {
19             e.printStackTrace();
20         }
21     }
22 }

Define a Client


The SummerClient

 1 // In file rmi/ex1/SummerClient.java
 2 import java.rmi.*;
 3 import java.rmi.registry.*;
 4 import java.net.*;
 5 import java.io.*;
 6
 7 public class SummerClient {
 8     public static void main(String[] args) {
 9
10         System.setSecurityManager(
11             new RMISecurityManager());
12
13         try {
14
15             Summer summer = (Summer) Naming.lookup(
16                 "rmi://localhost:1099/SUMMER");
17
18             LineNumberReader stdinReader =
19                 new LineNumberReader(new BufferedReader(
20                 new InputStreamReader(System.in)));
21
22             for (;;) {
23
24                 String userLine = stdinReader.readLine();
25                 if (userLine == null
26                     || userLine.length() == 0) {
27                     break;
28                 }
29                 String outString;
30
31                 try {
32                     long sum = summer.sumString(userLine);
33                     outString = Long.toString(sum);
34                 }
35                 catch(InvalidLongException e) {
36                     outString = e.getMessage();
37                 }
38                 System.out.println(outString);
39             }
40         }
41         catch (Exception e) {
42             e.printStackTrace();
43         }
44     }
45 }
46

Generating Stubs and Skeletons


Steps to Run


Dynamic Class Loading


Subtypes


Codebase


Other RMI Features


Network Mobility

Bill Venners: I heard the story that originally Java was envisioned for embedded devices. To what extent was Java designed with what would eventually come to be called Jini in mind? In other words, were you just thinking about embedded devices, or were you thinking about a Jini-like world?

James Gosling: Oddly enough, something very much like the Jini world was in there from day one. The very early version of Java, which was called Oak and ran on the Star Sevens, had a distributed message system in it that was very much like RMI.

Bill Joy: We built the JVM to let objects move around.


Exercises

Problem 1

In the RMI/ex2/server directory, define an implementation of the Worker interface named WorkerImpl that extends UnicastRemoteObject. WorkerImpl's constructor must include RemoteException in its throws clause. The WorkerImpl's doJob() method should invoke doJob() on the passed Job object and pass the Object returned by Job's doJob() method back to its caller of WorkerImpl's doJob() method.

Problem 2

Also in the RMI/ex2/server directory, define a server named WorkerServer, which:

Problem 3

Create the stub and skeleton for WorkerImpl, by running this command in the RMI/ex2/server directory:
rmic WorkerImpl

Start RMIRegistry from RMI/ex2/server (the directory in which you created the stub and skeletons), with this command:

start RMIRegistry

Lastly, start your server with this command from RMI/ex2/server:

java -Djava.security.policy=policy.all WorkerServer

Problem 4

Copy SummerClient from the RMI/ex1 directory to the RMI/ex2/client directory. Change SummerClient so that it grabs the "WORKER" service instead of the "SUMMER" service. When the user types in a string of numbers, create a new Addition object and pass it to the Worker object's doJob() method. Cast the returned Object to Long, convert the Long to a String and print it out.

Addition.class must be in a location where the server can find it locally, which is why it is sitting in the RMI/ex2/server/com/artima/compserv directory. In addition, Addition.class must be available to the client, which is why it is sitting in the REMI/ex2/client/com/artima/compserv directory. Start your client in the RMI/ex2/client directory with the following command:

java -Djava.security.policy=policy.all SummerClient

Type in a few strings of numbers and make sure they get summed correctly.

Problem 5

Now try running your program such that the Addition.class file will be dynamically downloaded by the Worker server. First, place Addition.class in a JAR file named add.jar. To do this, just execute the following command in the RMI/ex2/client directory:

jar cf add.jar com/artima/compserv/Addition.class

Move this JAR file to the directory from which code will be downloaded, C:\client-dl. Remove Addition.class from the server's class path, so that the server can't find Addition.class locally:

del RMI\ex2\server\com\artima\compserv\Addition.class

Start a web server running on RMI/ex2/client-dl, the directory in which you placed add.jar. The following command would be appropriate assuming Jini was installed in c:\jini1_0_1 and the add.jar file was installed in C:\OAJCode\RMI\examples\ex2\client-dl:

start java -jar c:\jini1_0_1\lib\tools.jar -dir C:\OAJCode\RMI\examples\ex2\client-dl -port 8080 -verbose

Kill and restart the Worker server from the same directory (RMI/ex2/server) using the same command:

java -Djava.security.policy=policy.all WorkerServer
Finally, restart the client from RMI/ex2/client, this time specifying the java.rmi.server.codebase property, as in:
java -Djava.security.policy=policy.all -Djava.rmi.server.codebase=http://127.0.0.1:8080/add.jar SummerClient

Try typing in numbers and see if they get added. Once you get this working, make sure you can explain how it is working.

Problem 6

Rearrange things a bit so that the stub for WorkerImpl is downloaded dynamically by RMIRegistry.

Kill RMIRegistry, the WorkerServer and client. Start RMIRegistry from the RMI directory, where it won't be able to load the stub class (WorkerImpl_Stub) locally. Copy WorkerImpl_Stub.class to the RMI/ex2/server-dl directory. Also copy Worker.class, Job.class, and JobException.class to the RMI/ex2/server-dl/com/artima/compserv directory, so that RMIRegistry will be able to find them. Start a web server running on the server-dl directory, using a command such as:

start java -jar c:\jini1_0_1\lib\tools.jar -dir C:\OAJCode\RMI\ex2\server-dl -port 8081 -verbose

Now start your server from RMI/ex2/server again, this time specifying a codebase with a command like:

java -Djava.security.policy=policy.all -Djava.rmi.server.codebase=http://127.0.0.1:8081/ WorkerServer

Make sure you have the trailing slash ('/') on the codebase URL when you start WorkerServer.

Finally, restart the client from RMI/ex2/client, this time specifying the java.rmi.server.codebase property, as in:

java -Djava.security.policy=policy.all -Djava.rmi.server.codebase=http://127.0.0.1:8080/add.jar SummerClient

Problem 7

In the RMI/ex2/client directory, copy your SummerClient.java file to ProductClient.java. Create a class Multiplication that implements Job. Multiplication's constructor should take an array of int's. Its doJob() method should multiply all the ints together, ignoring overflow, and return a Long result. Run ProductClient, making sure that Multiplication.class is downloaded dynamically by WorkerImpl.


Sponsored Links

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us