Java RMI

This talk summarizes material from

1 Introduction

Client Server
Stub Skeleton
Remote Reference Remote Reference
Transport
Note:

The purpose of this presenation is to provide the step-by-step instructions and low-level implementation details needed to understand Java's RMI implementation, so you can get started on your programming. As always, these slides only serve to highlight the most important points in the readings. You should read the cited tutorials while sitting in front of a computers and taking the steps they indicate. It is the best way to get comfortable with this (and any) new technology.

1.1 Hello World Example

Hello UML diagram

1.2 Hello.java

package examples.hello;

import java.rmi.Remote; 
import java.rmi.RemoteException; 

public interface Hello extends Remote { 
    String sayHello() throws RemoteException; 
}

1.3 Exporting and Binding Remote Objects

1.4 HelloImpl.java

package examples.hello;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;

/** This class serves both as the remote object implementation and the
    object server main. These two functions could be separated. */
public class HelloImpl extends UnicastRemoteObject
  implements Hello {
  
  public HelloImpl() throws RemoteException {
    super();
  }
  
  public String sayHello() {
    return  "Hello World!";
  }
  
  public static void main(String args[]) { 
    
    // Create and install a security manager 
    if (System.getSecurityManager() == null) { 
      System.setSecurityManager(new RMISecurityManager()); 
    } 
    try { 
      HelloImpl obj = new HelloImpl(); 
      // Bind this object instance to the name "HelloServer" 
      Naming.rebind("HelloServer", obj); 
      System.out.println("HelloServer bound in registry"); 
    } catch (Exception e) { 
      System.out.println("HelloImpl err: " + e.getMessage()); 
      e.printStackTrace(); 
    } 
  } 
}

1.5 HelloImpl.java Security and Registration

Note:

The requirement that the registry run on the same machine as the server is a heavy-handed way of eliminating a man-in-the-middle attack. In this attack, a hostile client could find a registry, ask it to list() all its registered services, then proceed to rebind() all those services so they point to him. By forcing the registry to run on the same machine as the server this possibility is eliminated assuming, of course, that we trust all the users of the machine!

A better solution to this problem would be for the registry to only service those clients that have authenticated with it using, for example, a public key encryption algorithm. In fact, we could use HTTP's TLS for this purpose. (Has anyone done this already?).

1.6 HelloApplet.java

package examples.hello; 

import java.applet.Applet; 
import java.awt.Graphics; 
import java.rmi.Naming; 
import java.rmi.RemoteException; 

public class HelloApplet extends Applet { 

  String message = "blank"; 
  
  // "obj" is the identifier that we'll use to refer 
  // to the remote object that implements the "Hello" 
  // interface 
  Hello obj = null; 

  public void init() { 
    try { 
      obj = (Hello)Naming.lookup("//" + 
                                 getCodeBase().getHost() + "/HelloServer"); 
      message = obj.sayHello(); 
    } catch (Exception e) { 
      System.out.println("HelloApplet exception: " + 
                         e.getMessage()); 
      e.printStackTrace(); 
    } 
  } 

  public void paint(Graphics g) { 
    g.drawString(message, 25, 50); 
  } 
}

1.7 hello.html

<html> 
<head>
<title>Hello World</title> 
</head>
<body>
<center> <h1>Hello World</h1> </center> 

The message from the HelloServer is: 
<p> 
<applet codebase="." 
        code="examples.hello.HelloApplet" 
        width=500 height=120> 
</applet> 
</body>
</html>

1.8 Running

  1. Compile sources:
    javac -d . *.java
  2. Use rmic (not in JDK 1.5) to generate stub and skeleton .class files from the implementation and interface:
    rmic -d . examples.hello.HelloImpl
  3. Move hello.html to a webserver (along with the .class files), or use the appletviewer.
  4. Start the rmi registry on the server:
    rmiregistry &
  5. Start the server. Specify the codebase and policy to the stub class can be dynamically downloaded to registry.
    java  -Djava.rmi.server.codebase=http://myhost/~myusrname/myclasses/  
        -Djava.security.policy=$HOME/mysrc/policy  examples.hello.HelloImpl
  6. Run the applet (from a browser or with the appletviewer).

2 Using Factories in RMI

The Factory Pattern

2.1 RMI Factory

A Factory in RMI

3 Dynamic Code Downloading

Downloading RMI stubs

3.1 Dynamic Code Downloading of Arguments

Downloading RMI stubs
  1. If its a primitive type, there is nothing to do.
  2. If its an object whose class in on the remote object's CLASSPATH, then it loads it from there.
  3. If its not on the CLASSPATH then the object must be either an implementation of the interface that is declared as the method parameter or a subclass of the class that is declared as method parameter. (Why? Otherwise it would not have compiled.) It gets downloaded from the codebase.

3.2 Setting the Codebase

4 The Registry

5 Activatable Remote Objects

5.1 ActivatableImplementation.java

package examples.activation; 

import java.rmi.*;
import java.rmi.activation.*;

public class ActivatableImplementation extends Activatable 
  implements examples.activation.MyRemoteInterface {

  // The constructor for activation and export; this constructor is
  // called by the method ActivationInstantiator.newInstance during
  // activation, to construct the object.
  //
  public ActivatableImplementation(ActivationID id, MarshalledObject data) 
    throws RemoteException {

    // Register the object with the activation system
    // then export it on an anonymous port
    //
    super(id, 0);
  }
  
  // Implement the method declared in MyRemoteInterface
  //
  public Object callMeRemotely() throws RemoteException {

    return "Success";
  }
}

5.2 Setup.java

package examples.activation; 

import java.rmi.*;
import java.rmi.activation.*;
import java.util.Properties;

public class Setup {

  // This class registers information about the ActivatableImplementation
  // class with rmid and the rmiregistry
  //
  public static void main(String[] args) throws Exception {

    System.setSecurityManager(new RMISecurityManager());

    // Because of the 1.2 security model, a security policy should 
    // be specified for the ActivationGroup VM. The first argument
    // to the Properties put method, inherited from Hashtable, is 
    // the key and the second is the value 
    // 
    Properties props = new Properties(); 
    props.put("java.security.policy", 
              "/home/rmi_tutorial/activation/policy");

    ActivationGroupDesc.CommandEnvironment ace = null; 
    ActivationGroupDesc exampleGroup = new ActivationGroupDesc(props, ace);
 
    // Once the ActivationGroupDesc has been created, register it 
    // with the activation system to obtain its ID
    //
    ActivationGroupID agi = 
      ActivationGroup.getSystem().registerGroup(exampleGroup);

    // The "location" String specifies a URL from where the class   
    // definition will come when this object is requested (activated).
    // Don't forget the trailing slash at the end of the URL 
    // or your classes won't be found.
    //       
    String location = "file:/home/rmi_tutorial/activation/";

    // Create the rest of the parameters that will be passed to
    // the ActivationDesc constructor
    //
    MarshalledObject data = null;

    // The location argument to the ActivationDesc constructor will be used 
    // to uniquely identify this class; it's location is relative to the  
    // URL-formatted String, location.
    //
    ActivationDesc desc = new ActivationDesc 
      (agi, "examples.activation.ActivatableImplementation", 
       location, data);
  
    // Register with rmid
    //
    MyRemoteInterface mri = (MyRemoteInterface)Activatable.register(desc);
    System.out.println("Got the stub for the ActivatableImplementation");
        
    // Bind the stub to a name in the registry running on 1099
    // 
    Naming.rebind("ActivatableImplementation", mri);
    System.out.println("Exported ActivatableImplementation");

    System.exit(0);
  }

}

5.3 Compile and Run Activatable

RMI machines
  1. Compile
    javac -d . *.java
  2. Run rmic
    rmic -d . examples.activation.ActivatableImplementation
  3. Start the registry. Make sure the CLASSPATH does not contain any classes that you want to download to client.
    rmiregistry &
  4. Start the activation daemon.
    rmid -J -Djava.security.policy=rmid.policy &
  5. Run the setup program. The codebase is a URL indicating where the stub code lives. Usually you will want this to be an http.
    java  -Djava.security.policy=/home/rmi_tutorial/activation/policy
     -Djava.rmi.server.codebase=http://dilbert.usc.edu/rmi_tutorial/activation/
     examples.activation.Setup
  6. Run the client.
    java -Djava.security.policy=/home/rmi_tutorial/activation/policy 
     examples.activation.Client vector

5.4 Converting UnicastRemoteObject to Activatable

5.5 Object Into Activatable

Object Info Activatable

6 Custom RMI Socket Factory

URLs

  1. Getting Started Using RMI, http://java.sun.com/j2se/1.4/docs/guide/rmi/getstart.doc.html
  2. Dynamic Code Downloading using RMI, http://java.sun.com/j2se/1.4/docs/guide/rmi/codebase.html
  3. Creating an Activatable Object, http://java.sun.com/j2se/1.4/docs/guide/rmi/activation/activation.1.html
  4. Making a UnicastRemoteObject Activatable, http://java.sun.com/j2se/1.4/docs/guide/rmi/activation/activation.2.html
  5. Activating an object that does not extend java.rmi.activation.Activatable, http://java.sun.com/j2se/1.4/docs/guide/rmi/activation/activation.3.html
  6. Using a Custom RMI Socket Factory, http://java.sun.com/j2se/1.4/docs/guide/rmi/socketfactory/index.html
  7. wikipedia:Factory_method_pattern, http://www.wikipedia.org/wiki/Factory_method_pattern
  8. GoF, http://www.amazon.com/exec/obidos/ASIN/0201633612/multiagentcom
  9. ClassServer.java, http://jmvidal.cse.sc.edu/talks/javarmi/ClassServer.java

This talk available at http://jmvidal.cse.sc.edu/talks/javarmi/
Copyright © 2009 José M. Vidal . All rights reserved.

17 February 2004, 12:15PM