95-702 Organizational Communication and Distributed Object Technologies Homework 4 Due: Friday, Midnight, July 17, 2009 Lab Topics: Synchronous and asynchronous Java RMI This project has three parts: First, code is presented that acts as a scaffolding for the remaining parts. A complete Java RMI solution is presented and the student is asked to build and run the system using the directions provided. The student is taught exactly how to use the rmi regsitry and the rmic tool. Second, using Java RMI, the student builds a distributed but synchronous chat server. Several clients must be shown to be running and chatting. The solution is modeled after the distributed whiteboard application that is found in the Coulouris text. Third, the student is required to add asynchronicity to the chat server. This amounts to providing a call back handler that runs on each client. This improvement makes for a livelier user interaction and illustrates the importance of event handling. The project is demonstrated in class and naturally leads to discussions concerning synchronous and asynchronous calls, event handling, remote interfaces, remote interface compilation and interface definition languages. Part 0. Simple Java RMI Getting Started ======================================= Part 0 is not to be turned in. It is a very simple Java RMI application that you may want to use to get started. Create two directories from a DOS or Unix prompt. Name one directory 'server' and the other directory 'client' Within the server directory, save the following three classes. //************************************************************ // Calculator.java Interface for a Calculator import java.rmi.*; public interface Calculator extends Remote { // this method will be called from remote clients int add (int x, int y) throws RemoteException; } //************************************************************* // CalculatorServant.java // A Remote object class that implements Calculator. import java.rmi.*; import java.rmi.server.UnicastRemoteObject; public class CalculatorServant extends UnicastRemoteObject implements Calculator { public CalculatorServant() throws RemoteException { } public int add(int x, int y) throws RemoteException { System.out.println("Got request to add " + x + " and " + y); return x + y; } } //************************************************************** // CalculatorServer.java Serve remote Calculator // Creates a calculator object and gives // it a name in the registry. import java.rmi.*; public class CalculatorServer { public static void main(String args[]){ System.out.println("Calculator Server Running"); try{ // create the servant Calculator c = new CalculatorServant(); System.out.println("Created Calculator object"); System.out.println("Placing in registry"); // publish to registry Naming.rebind("CoolCalculator", c); System.out.println("CalculatorServant object ready"); }catch(Exception e) { System.out.println("CalculatorServer error main " + e.getMessage()); } } } Compile all the code with javac *.*. Run RMIC on the servant class with rmic -v1.2 CalculatorServant. Copy the interface Calculator.hava and the stub class to the client. The stub will be called CalculatorServant_Stub.class. Within the server directory, start the rmiregistry with the command rmiregistry & (Unix) or start rmiregistry (DOS). Run the server with the command java CalculatorServer. In the client directory, enter the following program: //******************************************************* // CalculatorClient.java // This client gets a remote reference from the rmiregistry // that is listening on the default port of 1099. // It allows the client to quit with a "!". // Otherwise, it computes the sum of two integers // using the remote calculator. import java.rmi.*; import java.rmi.server.*; import java.io.*; import java.util.StringTokenizer; public class CalculatorClient { public static void main(String args[]) throws Exception { BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); // connect to the rmiregistry and get a remote reference to the Calculator object Calculator c = (Calculator) Naming.lookup("//localhost/CoolCalculator"); System.out.println("Found calculator. Enter ! to quit"); while(true) { try { // prompt the user System.out.print("client>"); // get a line String line = in.readLine(); // if a "!" is entered just exit if(line.equals("!")) System.exit(0); // if it's not a return get the two integers and call add // on the remote calculator. if(!line.equals("")) { StringTokenizer st = new StringTokenizer(line); String v1 = st.nextToken(); String v2 = st.nextToken(); int i = Integer.parseInt(v1); int j = Integer.parseInt(v2); int sum = c.add(i,j); System.out.println(sum); } } catch(RemoteException e) { System.out.println("allComments: " + e.getMessage()); } } } } Compile the code on the client and run with the command java CalculatorClient. Part I. Synchronous Java RMI ============================ (1) Chapter 5 of the Coulouris text contains a Java RMI case study. The code implements a distributed white board. Modify the code so that it acts as a distributed chat server. Rather than moving graphical objects about we would like to move simple text. The execution of one client program follows: C:>java MyChatClient client>Hello There Hello There This is cool Hello There This is cool I'm talking to myself Hello There This is cool I'm talking to myself ! C:> The explanation mark means quit. In this example, there were no other clients running. Your solution will allow for more than one client. Note that every time a client sends a message to the server the client receives an entire list of comments previously made. This is, of course, not ideal. The client may already be in possession of earlier comments and so there is no need for this extra data to be transferred. However, for this first part of the project, this approach will do fine. Two or more users must be able to use the system to converse. Notes on rmic are available on the course slides. You are required to separate your files into two different directories. One will be called clientcode and the other will be called servercode. We will be copying relevant files to the two directories and will not use a security manager. Post your documented java files to Blackboard. Also, to show that you have a working system, post to Blackboard a few console screen shots showing two or more clients talking. So that the registry has access to necessary files, be sure to start your rmiregistry from within your server directory. In DOS, use the command "start rmiregistry". In Unix use the command "rmiregistry &". Part II. Asynchronous Java RMI and Distributed Event Handling ============================================================= (2) The problem with the solution to problem 1 is that the client waits until the user enters a line of text before contacting the server. It would be far better to allow the server to make calls on the clients whenever any user enters a line of text. This is the popular publish subscribe design pattern. This is also called the observer pattern. Write one client program called ReaderClient.java and another called WriterClient.java. WriterClient.java will read from the console (one line at a time) and send each comment to the server. It writes to the server. Unlike the previous exercise, WriterClient will not read from the server at all. That is, unlike the solution to question 1, it will not bother to read comments posted by others from the server and write them to the console. It simply reads from the user and writes to the server. ReaderClient.java will run in a separate console window and wait for calls from the server. It reads from the server. These calls from the server will pass to the reader recent comments that have been entered. This client will call the rmi registry to get a remote reference to the CommentList. This client will then need to call a registration method on the server. The registration method will be passed a remote reference to an object that lives on the client and whose class extends UnicastRemoteObject. A working solution will have at least six open console sceens. One will be for the rmiregistry. The second will be for the CommentListServer. The third and fourth will be for user input (two executions of WriterClient.java) from two different users. The fifth and sixth will be two separate executions of ReaderClient (again, for two different users). These last two consoles will show the content of the comment list. We will not use a security manager so feel free to copy the server side stubs to the client and the client stub to the server. Nor will we concern ourselves with concurrency issues. So that the registry has access to necessary files, be sure to start your rmiregistry from within your server directory. The client stub will be generated from running rmic on the ReaderClient.class file. The command is "rmic -v1.2 ReaderClient" without the ".class". Post all of your documented source code to Blackboard. Also, to show that you have a working system, post to Blackboard a few DOS screen shots showing two or more clients talking. Working, documented solutions will be worth 97%. For 100%, you must identify the person who made the comment on every Reader that displays the comment. This will require the client to collect the user's unique screen name.