This lecture is based mostly on the online documentation available about RMI at http://www.javasoft.com/
Some examples and texts were copied verbatim
Client-server interaction levels from application perspective
Lowest: Berkeley sockets
Middle: Java networking library
High: RPC, RMI, CORBA, etc.
Remote Procedure Call
A client can transparently call a function or procedure on the server as if it is a local call.
Issues:
NFS (Network File System) is built using RPC
RCP does not translate well into OOPS
Remote Method Invocation (RMI) is the action of invoking a method of a remote interface on a remote object.
Goals:
RMI is limited to Java, but Java is cross-platform...
Common Object Request Broker Architecture
To be covered in a future lecture
Three layers:
Each layer communicates through well defined interfaces
A layer can be replaced without affecting the other layers
Currently only TCP, but transport layer could be replaced with a UDP version
To transport objects between different machines or address spaces, object serialization is used.
A remote method invocation from a client to a remote server object travels down through the layers to the client-side transport, then up through the server-side transport to the server.
A stub implements all the interfaces that are supported by the remote object implementation.
Responsibilities:
Server-side entity that contains a method which dispatches calls to the actual remote object implementation.
Responsibilities:
The java.rmi package contains all classes, interfaces and sub-packages used by RMI
In general, all calls in the java.rmi hierarchy throw RemoteException exceptions. These need to be caught and dealt with appropriately.
In the example that follows, we will build an RMI client-server application that displays "Hello, World!" in an applet window.
We will assume the use of Solaris, but the example works just as well under other operating systems.
We will assume a directory called '$HOME/java/hello' that we will put all the source files into.
All remote interfaces extend, directly or indirectly, java.rmi.Remote
The java.rmi.Remote interface does not contain any methods or variables.
package hello; import java.rmi.*; public interface Hello extends Remote { String sayHello() throws RemoteException; }
Remote objects implement one or more remote interfaces.
Requirements:
In our example, the implementation will be the server, so it will contain main().
package hello; import java.rmi.*; import java.rmi.server.UnicastRemoteObject; public class HelloImpl extends UnicastRemoteObject implements Hello { private String name; public HelloImpl(String s) throws RemoteException { super(); name = s; } public String sayHello() throws RemoteException { return "Hello, World!"; } public static void main(String[] args) { System.setSecurityManager(new RMISecurityManager()); try { HelloImpl obj = new HelloImpl("HelloServer"); Naming.rebind("//rohan:5154/HelloServer", obj); System.out.println("HelloServer bound in registry"); } catch (Exception e) { System.out.println("HelloImpl error: " + e); e.printStackTrace(); } } }
Note the Naming.rebind() method call.
This will tell the RMI Registry the name of the object that is to provide the remote service.
The first argument is a URL that is very similar to an HTTP URL:
[<protocol>:]// <host> [:<port>]/<object name>
The protocol is 'rmi' and can be safely omitted.
Normally there is only one naming service per host and the registry will use a "well known" port.
For timesharing systems like rohan, use your UID as a port number. (Use the '/usr/bin/id' command to find your UID)
This applet calls the remote Hello object's sayHello() method to get the String to display:
package hello; import java.awt.*; import java.rmi.*; public class HelloApplet extends java.applet.Applet { String message = ""; public void init() { try { Hello obj = (Hello)Naming.lookup("//" + getCodeBase().getHost() + ":5154/HelloServer"); message = obj.sayHello(); } catch (Exception e) { System.out.println("Exception: " + e); e.printStackTrace(); } } public void paint(Graphics g) { g.drawString(message, 25, 50); } }
Simple HTML file to display the applet:
<html> <head><title>Hello, World!</title></head> <body> <h1 align=center>Hello, World!</h1> The message from the HelloServer is: <p> <applet codebase=".." code="hello.HelloApplet" width=500 height=120> </applet> </body> </html>
This will require an HTTP server.
We will assume that you have a public_html directory which can be accessed by the webserver.
The class files will reside in the subdirectory public_html/codebase/hello
There are four files in the 'hello' directory, now:
The CLASSPATH environment variable needs to include both $HOME/public_html/codebase and $HOME/java/hello
Compile the Java source files from the source directory:
java -d $HOME/public_html/codebase Hello.java HelloImpl.java HelloApplet.java
This will put the class files into $HOME/public_html/codebase/hello
The rmic compiler will create the stubs and skeletons from the class file of the implementation.
rmic -d $HOME/public_html/codebase hello.HelloImpl
The '-d' option specifies where the generated files will be placed.
After this command, the following files will be in $HOME/public_html/codebase/hello:
The registry is started using the rmiregistry command:
rmiregistry 5154 &
Note that a port number should be specified (remember your UID?)
The server is started as follows:
java -Djava.rmi.server.codebase=http://host/~username/codebase/ hello.HelloImpl &
The applet is started as follows:
appletviewer http://host/~username/codebase/hello/index.html
It is possible to make all this work without starting a separate rmiregistry process.
Change main() in HelloImpl.java as follows:
public static void main(String[] args) { System.setSecurityManager(new RMISecurityManager()); try { java.rmi.registry.LocateRegistry.createRegistry(5154); HelloImpl obj = new HelloImpl("HelloServer"); Naming.rebind("//rohan:5154/HelloServer", obj); System.out.println("HelloServer bound in registry"); } catch (Exception e) { System.out.println("HelloImpl error: " + e); e.printStackTrace(); } }
This will start a registry daemon thread for the server.