Project1 COP5615 Operating System Principles Summer 2004 Project 3 Date Assigned: June 26th, 2004 Date Due: Midnight, July 9th, 2004 The purpose of this project is for you to learn Java Remote Method Invocation (RMI) instead of sockets. We will use the same solution to the Customer-Worker system. So, we will be developing another distributed Client/Server version of this solution this time, using a service-oriented request/reply scheme. We will see how communication transparency is achieved with RMI and how it is possible to develop elegant distributed programs. Since we already implemented this solution in previous projects, we will not need to write new code except a few lines for RMI implementation. Unless otherwise specified in this document, Project 2 specification is valid for this project. RMI Implementation RMI Registry RMI registry is a Naming Service that acts like a broker. RMI servers register their objects with the RMI registry to make them publicly available. RMI clients look up the registry to locate an object they are interested in and then obtain a reference to that object in order to use its remote methods. Of course, servers register only their remote objects, which have remote methods. Details using the registry are given in the next section. The Remote Interface Remote methods that will be available to clients over the network should be declared. This is accomplished by defining a remote interface. This interface must extend java.rmi.Remote class and must be defined as public to make it accessible to clients. The body of this interface definition consists of only the declaration of remote methods. The declaration is nothing more than the signatures of methods namely method name, parameters and return type. Each method declaration must also declare java.rmi.RemoteException as the throws part. Necessary Java packages: java.rmi.Remote Implementation of Remote Interface After defining the remote interface, you need to implement this interface. Implementing the interface means writing the actual code that will form the bodies of your remote methods. For this purpose you define a class from which you create your remote objects that will serve the clients. This class must extend RemoteObject provided by the java.rmi.server package. There is also a subclass UnicastRemoteObject which is also provided by the same package that provide sufficient basic functionality for our purpose. When you call its constructor, necessary steps are taken for you so that you will not need to deal with them. An RMI server registers its remote objects by using bind() or rebind() method of Naming class. The latter is preferable even for the first time, since you can run your system as many times as you want without touching the registry. Necessary Java packages: java.rmi.*, java.rmi.server.* RMI Clients RMI clients are mostly ordinary Java programs. The only difference is that they use the remote interface. As you now know remote interface declares the remote methods to be used. In addition, the clients need to obtain a reference to the remote object, which includes the methods declared in remote interface. The clients obtain this reference by using lookup() method of Naming class. Necessary Java packages: java.rmi.* Project Implementation Details In this project we will use the distributed solution to the Customer Worker system. Therefore, we will use the same code we have written for project 2. But we do not need the code for sockets (since RMI takes care of all communication necessary) and the server side threads (since RMI also takes care of threads for us by creating threads necessary at the server). But we still need to provide the synchronization necessary. Therefore all the code we have written for this purpose will be useful and can be reused. The major difference from Project 2 is that service requesting and task assignment of clients will be remote method invocations. RMI registry RMI registry can be started on a Unix machine by typing: /usr/local/java/bin/rmiregistry & is the port number we want the registry to listen for connections from RMI servers and clients. This port number is optional and if not specified, registry is started on default port 1099. A host that provides continuous RMI support should use this port number for convenience and standardization. But we will specify our own port number by starting our own RMI registry. This port number should match the one in the system.properties file. Note that "&" is to run the registry as a background process. Important Note: The full path name above for the RMI commands are necessary in the CISE environment. Otherwise you may end up using some other version of RMI which is not compatible with the JDK. Compiling programs Compile your server and client code as usual. After successfully compiling all the source code, you need to create the stubs needed. The stubs are similar to the RPC stubs and used for the same purpose. To create the stubs you need to use rmic compiler as below. (Note that server stub is called the skeleton in RMI terminology and rmic is similar to rpcgen of RPC) /usr/local/java/bin/rmic The class-name above is the name of the class from which we create instances of remote objects. Clearly it is the server side class. Since you compile first your source code as explained above, the .class file will be available to the rmic compiler at this point. The output of rmic is two class files, one for the client stub and the other for server skeleton. For example, if the name of your class for remote objects is CoordinatorImpl, then you should have Coordinatormpl.java as your source file and CoordinatorImpl.class as the class file for your remote object. Type /usr/local/java/bin/rmic CoordinatorImpl and the output of this command is two files: CoordinatorImpl_Skel.class // server skeleton CoordinatorImpl_Stub.class // client stub In general, an RMI server needs both stub and skeleton classes as well as remote object class. The client needs to access the stub only. You will put all classes into the same directory and run all your programs from that directory. Also, you should put this command in your makefile. Running the System You need to follow the steps below to run the system: 1- Start rmiregistry manually as a background process as explained above. Specify an arbitrary port number that is large enough to avoid collisions with the well-known port numbers. This port number should match the one in the system.properties file. Use ps to make sure the rmiregistry is running. 2- Start your system with java Start Check the outputs and processes running and repeat this step as many times as you need to test your system. Note: a)Different from Project 2, even after your server thread is completed, the server process, which makes the remote object available, will keep running. To terminate the process, you should use System.exit() method (in the server thread) immediately after the server thread finishes counting the specified number of accesses. b) RMI does not wait for the return of a remote void method call to return before proceeding on to the next statement. This can cause some strange behaviors if the code assumes a certain order of execution based on the assumption that the call to the void method waits for it to finish, as normally happens in a non-RMI, single-threaded situation. 3- Terminate the rmiregistry using kill, manually. Note on Registering and Looking up Remote Objects As we now know, the server needs to register its remote object to the RMI registry to make its own remote methods publicly available to the clients. In turn, clients need to look up the RMI registry to obtain a reference to that object and then to call its remote methods. You must use your CISE login name as the name of the service for registering the remote object to the registry. Similarly the clients must look up the object by giving your CISE login name. The reason for this restriction is to prevent possible name collisions by making the names unique, since we will use the same RMI registry to grade all the projects. Format of the configuration file system.properties The format is exactly the same with that of Project 2. However, we will use the port number now for the RMI registry. This port number must match the one you specify when you start the rmiregistry. Requirements/Reminder Please remember that Project Overview and Requirements page is valid for all projects. Service requests and work assignments should be implemented using are Remote Method Invocations. Necessary parameters or return value should be specified in these invocations. The command to start the system must be java Start The format of the system.properties and output files must exactly be the same with project 2. Your Makefile should have a line to invoke the rmic compiler. In addition to the general report guidelines, your report should have a section that compares sockets implementation of project 2 with this one. You must use your CISE login name to register and lookup your remote object. You should NOT put any lines in your makefile to run the system or to start the rmiregistry. We use a script to do them. Failure to follow the requirements will result in points loss.