SDSU CS 596: Client-Server Programming
Spring Semester, 1997
Doc 31, RMI

To Lecture Notes Index
San Diego State University -- This page last updated May 8, 1997

Contents of Doc 31, RMI

RMI

 

This lecture is based mostly on the online documentation available about RMI at http://www.javasoft.com/

Some examples and texts were copied verbatim

 

Background

 

Client-server interaction levels from application perspective

 Lowest: Berkeley sockets 

 

Middle: Java networking library 

 

High: RPC, RMI, CORBA, etc.

 

RPC

 

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

RMI

 

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...

 

CORBA

 

 

Common Object Request Broker Architecture 

To be covered in a future lecture

 

RMI -- The Big Picture

 

Three layers:

  1. stub/skeleton layer -- client-side stubs and server-side skeletons
  2. remote reference layer -- remote reference behavior
  3. transport layer -- connection set up and managements and remote object tracking

 

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.

 

System Description

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.

Stubs

  

A stub implements all the interfaces that are supported by the remote object implementation.

 

Responsibilities:

 

Skeleton

Server-side entity that contains a method which dispatches calls to the actual remote object implementation.

 

Responsibilities:

 

Practical Use of RMI

 

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.

Defining a Remote Object

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;
}

 

Implementation Class

 

Remote objects implement one or more remote interfaces.

Requirements:

  1. Specify the remote interface(s) being implemented
  2. Define the constructor for the remote object
  3. Provide implementations for the methods that can be invoked remotely
  4. Create and install a security manager
  5. Create one or more instances of a remote object
  6. Register at least one of the remote objects with the RMI remote object registry

 

In our example, the implementation will be the server, so it will contain main().

Implementation Code

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();
    }
  }
}

Registering a Remote Object

 

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)

Applet that Uses the Remote Service

 

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);
  }
}

HTML to call the applet

 

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

 

Compiling the files

 

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

Generating Stubs and Skeletons

 

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:

 

 

 

Starting the Object Registry, Server and Applet

 

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

 

Building the Registry into the Server

 

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.