Home | Papers | Reports | Projects | Code Fragments | Dissertations | Presentations | Posters | Proposals | Lectures given | Course notes |
<< 3. TCP IP Sockets in Java | 5. Borg; message passing, strong mobility, synchronization >> |
4. Java Remote Method Invocation (RMI)Werner Van Belle1* - werner@yellowcouch.org, werner.van.belle@gmail.com Abstract : These are course notes I made to teach distributed systems for the VUB. I used them in 1998-1999, 1999-2000, 2000-2001, 2001-2002, 2002-20003
Reference:
Werner Van Belle; Java Remote Method Invocation (RMI); |
The exercises take place in Java. Some hints to ease the pain:
JAVA WAS ORIGINALLY CONCEIVED BY SUN to be used on embedded systems, but it turned out to be a better language for networks because it offered a virtual machine that could run Java applications on all kinds of different architectures. Java is an object oriented programming language that supports automated memory management (= garbage collection), threads, and interfaces. Libraries like Java RMI (remote method invocation) are available to support semi transparent remote accessibility. This model, a typical thread based, transparent distribution model, is the focus of this exercise.
JAVA PROCESSES can communicate by using Java RMI. Communication happens solely between Java virtual machines, thereby using an interpreted byte code which can run on different machines. Java RMI communication goes from a client process toward a server object. The client requests the name of a certain object at a central registry. Normally it receives a stub object in response. Every call invoked upon this stub object (on the client) will be translated by the RMI architecture to a call on the matching server object (on the server). As long as the server doesn't send a response the client keeps on waiting. This is illustrated in Figure 2.
The protocol between client and server is defined as an interface extending the Remote type (this is comparable to IDL's in CORBA, in this instance however it is a language feature and does not require a special compiler). This interface (the protocol description) is the only class-file that ought to be shared between client and server. The client uses this information to create a stub, the server uses this information to create a skeleton, listing.
import java.rmi.Remote; import java.rmi.RemoteException; public interface Protocol extends Remote { String giveHello() throws RemoteException; }
import java.rmi.Naming; import java.rmi.server.UnicastRemoteObject; public class ServerImpl extends UnicastRemoteObject implements Protocol { public ServerImpl() throws RemoteException { super(); } // implementation of the protocol public String giveHello() { return *blort*; } // instantiate a server object and bind it public static void main(String args[]) { try { ServerImpl obj = new ServerImpl(); Naming.rebind("//7.0.0.1/HelloServer", obj); System.out.println("HelloServer bound in registry"); } catch (Exception e) { System.out.println("ServerImpl err: " + e.getMessage()); e.printStackTrace(); } // the program does not end as long as there is a // background thread running } }
import java.rmi.Naming; public class ClientApplication { static Protocol obj = null; public static void main(String args[]) { try { /* zoek het object op */ obj = (Protocol)Naming.lookup("//7.0.0.1/HelloServer"); /* en gewoon gebruiken */ System.out.println(obj.giveHello()); } catch (Exception e) { System.out.println("ClientApplication exc: " + e.getMessage()); e.printStackTrace(); } } }
Sun's serialization and deserialization interface to Java helps exporting an object (and all the objects it knows and depends on) to a byte stream. The standard behavior for serialization is to serialize the object and all the objects it contains. If we want to modify this behavior we can use an externalizable interface which describes how the object is to be exported.
To be able to contact a remote object as if it were a local object, one should create stubs for all the remote objects which will be contacted (one can do this automatically at compile time using rmic). Such a stub will provide all the methods the remote objects supports and fill in the bodies with code to contact the remote object. The logic within one such a stub body is quite simple:
To run the demo code do the following:
A white-board is an application that allows multiple clients to work on the same shared resource. Clients can Join on the white-board. After Joining they can post a string to the white-board which will be repeated to all connected clients.
Some more advanced questions:
IN ALL ITS ASPECTS JAVA is an innovating language. For example, it introduces garbage collection in the industry. On another note we see how Java introduces a standard threading library (compare this with C which has all kinds of dirty libraries and tricks like setjmp and longjmp to solve multiple sessions.) A thread is an execution context which can run together with other threads in the same environment. The difference with processes is that threads do share memory, while processes don't share memory.
This is important because Java RMI, as already seen, waits before returning an answer. With Java RMI a client can ask the server to execute a method and return the answer. In the meantime the client simply waits. Now, let's have a look at the Java program in algorithm 1.
The FacApp class exports a FacCalcer interface. A FacCalcer is an object that is able to calculate the factorial of a certain number by multiplying that number by the factorial of that number minus one. To do this last step the FacCalcer needs to be supplied another FacCalcer. This can be seen in the definition of the fac method. When we start this application it will first try to lookup an existing FacCalcer. If there is one it will contact that FacCalcer to calculate some factorial, if there is none, it will become the faccalcer itself and announce it in the registry.
To start this program, first an rmiregistry should be started and afterward two times the FacApp. The last facapp (faccalcer2 from now on) requests faccalcer1 to calculate the factorial of 3. In return faccalcer1 will request faccalcer2 to calculate the factorial of 1... But how is this possible ? How can the original requester be interrupted while he is still waiting. The answer lies in the Java threading mechanism. Every time an RMI call comes in, the server-thread will spawn a new thread which handles the request. This can be seen in figure 4.
|
http://werner.yellowcouch.org/ werner@yellowcouch.org |