RMI Resource
Resin 3.0

Features
Installation
Configuration
Web Applications
IOC/AOP
Resources
JSP
Quercus
Servlets and Filters
Databases
Admin (JMX)
CMP
EJB
Amber
EJB 3.0
Security
XML and XSLT
XTP
JMS
Performance
Protocols
Third-party
Troubleshooting/FAQ

Library
Tutorials
Resource FAQ

CronResource
RMI
CronResource
Library
Tutorials

Resin supports the use of RMI with the resource class class com.caucho.resources.rmi.RmiRegistry .

  1. RMI concepts
    1. Registry
  2. The Hessian alternative
  3. Requirement: security-manager
  4. com.caucho.resources.rmi.RmiRegistry
    1. com.caucho.resources.rmi.RmiRegistry
    2. rmi-service
  5. Implementing a service
    1. Interface and Implementaion
    2. Making Stubs
    3. Deploying the service with Resin
      1. Choosing a name
    4. An example build file
  6. Implementing a client
  7. Scenarios
    1. A Resin server that provides the Registry and the service
    2. A Registry on a different server
    3. A Registry in a different JVM

RMI concepts

The goal of RMI is to provide services to remote clients. A remote client obtains and uses a proxy object that implements an interface. The interface is the contract for the service, it is the definition of the methods that the service provides.

Because the client is using a proxy object, the actual execution of code occurs on the server. A proxy object is placeholder that the client uses to cause execution of code on a server.

Registry

The RMI registry is used to store a list of available services. A client uses the registry to make it's proxy object, and the Registry is responsible for giving appropriate information to the client so that it can hook up with the server that implements the service.

In many scenarios, the Registry and the server for the services are in the same JVM. It is possible, however, for the Registry to run in a different JVM or even on a different machine than the server or servers that implement the services.

A registry has a TCP port that it uses to listen to incoming requests, typically this is port 1099. The RMI registry is a global resource, each JVM can have only one Registry on a particular port. This has important ramifications for the naming of services.

The Hessian alternative

If you are considering RMI as a mechanism for publishing services, you may want to consider using Hessian instead. Hessian offers the following advantages:

  • it does not have a global namespace, separate web-app's can provide services with the same name without conflict
  • it supports the use of clients written in languages other than Java
  • it does not require the manual generation of stubs
  • it does not require a security-manager
More information is available in the Hessian section of the documentation.

Requirement: security-manager

The JDK requires that a security manager be in place for the use of RMI. This is true for both clients and servers. A security manager is enabled in Resin using the <security-manager> configuration:

enabling security-manager in resin.conf
<resin xmlns="http://caucho.com/ns/resin"
       xmlns:resin="http://caucho.com/ns/resin/core">

  <security-manager/>

  ...

For clients that are applets, the developer does not need to enable the security manager; the browser provides the security manager.

More information is available in the Security section of the documentation.

com.caucho.resources.rmi.RmiRegistry

Resin provides the resource class class com.caucho.resources.rmi.RmiRegistry to define an RMI Registry and register services with it. If the Registry is on the `localhost' server, then Resin will also start the RMI Registry if needed.

Example use of RMI Registry
<web-app>
  <resource type="com.caucho.resources.rmi.RmiRegistry">
    <init>
      <server>localhost</server>  
      <port>1099</port>           

      <rmi-service service-name="HelloWorld" 
                      service-class="example.HelloWorldImpl"/>
      <rmi-service .... >
    </init>
  </resource>
</web-app>

com.caucho.resources.rmi.RmiRegistry

Resin 3.0.6

AttributeMeaningdefault
serverthe ip address of the server with the Registrylocalhost
portthe port of the Registry1099
rmi-servicean rmi service (see below) 

RmiRegistry is used to define the location of an RMI Registry to use. If server is `localhost', then the Registry will be started on the specified port, if it has not already been started.

If server is something other than `localhost', then it is assumed that the Registry has been started by some other JVM , and is treated as remote Registry to register any services defined with rmi-server.

rmi-service

Resin 3.0.6

child of: com.caucho.resources.rmi.RmiRegistry

Each RmiRegistry can have rmi-service children, which causes the service to be instantiated and registered with the RMI Registry defined by the containing RmiRegistry.

AttributeMeaningdefault
service-namethe name of the service, used for registration in the Registry and also used by clients to locate the service.required
server-classthe name of the implementation class for the servicerequired

Implementing a service

Interface and Implementaion

An RMI service requires the developer to create two classes - an interface and an implementation. The interface defines the contract for the service, it is given to the client and it is the client view of the service. The implementation class implements the functionality; it implements the interface and is used on on the server.

The following is a simple hello world example.

interface - WEB-INF/classes/example/HelloWorld.java
package example;

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


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

implementation - WEB-INF/classes/example/HelloWorldImpl.java
package example;

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


public class HelloWorldImpl extends UnicastRemoteObject implements HelloWorld
{
  public HelloWorldImpl()
    throws RemoteException
  {
    super();
  }

  public String sayHello()
    throws RemoteException
  {
    return "Hello, World";
  }
}

Making Stubs

When the client uses a service, it uses a proxy object. The proxy object is a placeholder, it implements the interface defined for the service, and call's through to the server so that the code is executed on the server.

RMI calls proxy objects Stubs, and the stubs must be manually generated. The generation of stubs is done using the rmic tool.

using rmic to generate Stubs
rmic -v1.2 -d WEB-INF/classes/  example.HelloWorldImpl 

This call to rmic will use the file WEB-INF/classes/example/HelloWorldImpl.class to generate the class file WEB-INF/classes/example/HelloWorldImpl_Stub.class.

It is tedious to perform this step manually, an ant build script (as shown in a later section) can be used to expediate the process.

Deploying the service with Resin

Once the work of making an interface, an implementation, and generating a stub is complete, it is a simple process to deploy the service in Resin.

Deploying the service with Resin
<web-app>
  <resource type="com.caucho.resources.rmi.RmiRegistry">
    <init>
      <server>localhost</server>  
      <port>1099</port>           

      <rmi-service service-name="HelloWorld" service-class="example.HelloWorldImpl"/>
    </init>
  </resource>
</web-app>

More than once service is easily deployed with the use of multiple rmi-service tags:

Deploying more than once service with Resin
<web-app>
  <resource type="com.caucho.resources.rmi.RmiRegistry">
    <init>
      <server>localhost</server>  
      <port>1099</port>           

      <rmi-service service-name="HelloWorld" service-class="example.HelloWorldImpl"/>
      <rmi-service service-name="HelloAgainWorld" service-class="example.HelloAgainWorldImpl"/>
    </init>
  </resource>
</web-app>

Choosing a name

By convention, the name chosen for the service often matches the name of the interface class. For example, if the interface name is "example.HelloWorld" then service-name is "HelloWorld" or even "example.HelloWorld" to match.

The RMI Registry has a global namespace. If two different web-app's try to publish the same service, with the same name, there will be conflicts.

An example build file

An ant build file is useful for completing the rmic step, and for preparing a jar for use by the client. The client jar contains the interfaces and the stubs.

The following build file, placed in /WEB-INF/build, creates the jar file /rmiclient.jar.

WEB-INF/build.xml
<project name="rmiexample" default="dist" basedir=".">

<property file="local.properties"/>
<property file="build.properties"/>
<property environment="env"/> 

<property name="build.compiler.emacs" value="true"/> 
<property name="resin.home" value="${env.RESIN_HOME}"/> 

<property name="rmiclient.jar" value="../rmiclient.jar"/>

<!-- NOTE: new RMI interfaces must have corresponding entries addeed
   -       in the rmiclient.jar taget
   -->

<path id="compile.classpath">
  <fileset dir="${resin.home}/lib">
    <include name="**/*.jar" />
  </fileset>
</path>

<target name="init">
  <tstamp/>
</target>

<target name="compile" depends="init">
  <mkdir dir="classes"/>
  <javac classpathref="compile.classpath"
         destdir="classes"
         debug="true">
    <src path="classes"/>
  </javac>
</target>

<target name="rmic" depends="init,compile">
  <rmic base="classes"
        classpathref="compile.classpath"
        includes="**/*Impl.class"/>
</target>


<target name="rmiclient.jar" depends="init,rmic">
  <jar destfile="${rmiclient.jar}">
    <fileset dir="classes">
      <patternset>
        <include name="**/HelloWorld.class"/>
        <include name="**/*_Stub.class"/>
      </patternset>
    </fileset>
  </jar>
</target>

<target name="dist" depends="rmiclient.jar"/>

</project>

Implementing a client

The client is usually on a different machine, or at least in a different JVM, than the server. That is the point of RMI, it enables the execution of code on a remote machine.

In order to use the RMI service, the client needs the interface classes and the Stubs. The easiest way to provide these to the client is to provide a jar; the ant build file above provides an example of using ant to automate the creation of the jar file for the client.

Once the jar file is available to the client, using the RMI service id fairly simple.

An RMI client
  String server = "//server-with-registry.com:1099/";
  HelloWorld remote = (HelloWorld) Naming.lookup(server + "HelloWorld");

  System.out.println(remote.sayHello());

Scenarios

A Resin server that provides the Registry and the service

In the most common scenario, the Resin server provides both the RMI Registry and the RMI services. When the registry server is defined as `localhost', Resin will start the rmi registry if has not been started already.

This provides a simple method of using RMI, you don't have to worry about the (somewhat tricky) process of starting the rmi registry yourself.

Scenario: a Resin server that provides the Registry and the service
<web-app>
  <resource type="com.caucho.resources.rmi.RmiRegistry">
    <init>
      <server>localhost</server>
      <port>1099</port>

      <rmi-service service-name="HelloWorld" service-class="example.HelloWorldImpl"/>
      <rmi-service .... >
    </init>
  </resource>
</web-app>

When the Resin server starts, it will start the rmi registry on port 1099 and register the `HelloWorld' service with it.

A Registry on a different server

In this scenario, the rmi registry is located on the machine services.hogwarts.com. The registry is started with a custom (not Resin) server implemented by Hogwarts.

The requirement is for the HelloWorld service, implemented within a Resin server, to be registered with the remote Registry.

In this scenario, the Resin resource RmiRegistry is used to attach to the existing RMI registry running on services.hogwarts.com.

A Registry on a different server
<web-app>
  <resource type="com.caucho.resources.rmi.RmiRegistry">
    <init>
      <server>services.hogwarts.com</server>
      <port>1099</port>

      <rmi-service service-name="HelloWorld" service-class="example.HelloWorldImpl"/>
      <rmi-service .... >
    </init>
  </resource>
</web-app>

When the Resin server starts, it will register the `HelloWorld' service with the RMI Registry on services.hogwarts.com. Since the server is on a remote machine, Resin will not create a registry on the local machine. When the REsin server shuts down, or is restarted, the `HelloWorld' service will be removed from the remote registry.

A Registry in a different JVM

In this scenario, the rmi registry is located on the same machine as the Resin server, but is started with a custom (not Resin) server implemented by Hogwarts.

This is essentially the same scenario as having a Registry on a different szerver. The server name cannot be provided as `localhost', however, because Resin will try to create the RMI registry.

The solution is to use an IP address of `127.0.0.1' as the address of the server. Because the server name is not `localhost', the RMI registry will not be created.

A Registry in a different JVM
<web-app>
  <resource type="com.caucho.resources.rmi.RmiRegistry">
    <init>
      <server>127.0.0.1</server>
      <port>1099</port>

      <rmi-service service-name="HelloWorld" service-class="example.HelloWorldImpl"/>
      <rmi-service .... >
    </init>
  </resource>
</web-app>

When the Resin server starts, it will register the `HelloWorld' service with the RMI Registry on the local machine. Since the server is not `localhost', Resin will not create a registry on the local machine. When the Resin server shuts down, or is restarted, the `HelloWorld' service will be removed from the remote registry.


CronResource
Library
Tutorials
Copyright © 1998-2006 Caucho Technology, Inc. All rights reserved.
Resin® is a registered trademark, and HardCoretm and Quercustm are trademarks of Caucho Technology, Inc.