Sunday, January 24, 2010

Multiple RMI Services on a Single Port

I recently learned of a solution to a problem I've struggled with using java remote method invocation (RMI) to implement client-server applications. I've used RMI for several years, and I think it's a great technology. RMI makes it easy to implement fast and secure remote procedure call between java clients and servers. RMI has two disadvantages compared to REST over HTTP or CORBA as a network computing platform. First, RMI is tied to java, so non-java clients cannot directly access network services via RMI. A second disadvantage of RMI is that RMI exports each of a server's remote objects on a separate TCP network port, so it's difficult to setup firewall rules for an RMI server that dynamically exports distributed objects as different clients request different services.

It turns out that there's an easy workaround to configure RMI to export all of a server's remote objects through a single firewall-friendly network port. I've known for some time that RMI allows server code to specify the port on which to export a remote object. For example, the HelloService below can pass a network port number to its UnicastRemoteObject super class constructor. However, I did not realize that multiple remote objects can specify the same network port to the RMI engine as long as a single RMISocketFactory manages every object on that port (which is the default behavior).

A contrived example below shows a simple scenario where an application dynamically exports multiple remote objects. At boot time, the server initializes a DirectoryService object, and registers the object with an RMI name service. The DirectoryService dynamically creates a HelloService object for each client call to login(). Because DirectoryService and HelloService both specify port 12345 in their constructor, clients access every service object via the same network port.


public class DirectoryService extends UnicastRemoteObject implements Directory {
    public DirectoryService() {
        super( 12345 );
    }

   public login( String name ) throws RemoteObject {
        return new HelloService( name );
   }
}

…

public class HelloService extends UnicastRemoteObject implements Hello {
    private  final String name;

    public HelloService ( String name ) {
        super( 12345 );
        this.name = name;
    }

    public String sayHell() {
        return “Hello, “ + name + “!”;
   }
}


No comments: