| # RMI-IIOP Programmer's Guide Copyright © 1999 Sun Microsystems, Inc. Copyright © 1999 International Business Machines Corporation. All Rights Reserved. | Documentation Contents

## Table of Contents

- Introduction
- Background Reading
- What is RMI-IIOP?
- The New rmic Compiler
- The New idlj Compiler
- How to Make RMI Programs Use IIOP
- Restrictions When Running RMI Programs Over IIOP
- Converting the RMI Hello World Program to RMI-IIOP
- Other Things You Should Know

## Introduction

This document will teach you how to write Java Remote Method Invocation (RMI) programs that can access remote objects by using the Internet Inter-ORB Protocol (IIOP). By making your RMI programs conform to a small set of restrictions, your RMI programs can access CORBA objects. RMI-IIOP gives you RMI ease-of-use coupled with CORBA/IIOP language interoperability. This document is for RMI programmers who want to write RMI-IIOP programs, or convert existing RMI programs to RMI-IIOP.

## Background Reading

Here are some sites to get you up to speed with this technology:

- The RMI-IIOP home page contains links to RMI-IIOP documentation, sample code, specifications, news, other related web sites, and more. Check it out!
- The RMI-IIOP FAQ page answers many basic RMI-IIOP questions.
- The Java RMI home page contains links to RMI documentation, examples, specification, and more. Make sure you read this.
- The RMI trail in the Java Tutorial.
- The RMI API documentation.
- The Java IDL web page will familiarize you with Sun's CORBA/IIOP implementation.
- The Java IDL trail in the Java Tutorial.
- The Java Language to IDL Mapping document is a detailed technical specification of RMI-IIOP.

## What is RMI-IIOP?

### RMI

With RMI you can write distributed programs in the Java programming language. RMI is easy to use, you don't need to learn a separate interface definition language (IDL), and you get Java's inherent "write once, run anywhere" benefit. Clients, remote interfaces, and servers are written entirely in Java. RMI uses the Java Remote Method Protocol (JRMP) for remote Java object comunication. To get a quick introduction to writing RMI programs, see the RMI Tutorial web page. That document describes writing a simple "Hello World" RMI program.

RMI lacks interoperability with other languages, and, because it uses a non-standard communication protocol, cannot communicate with CORBA objects.

### IIOP, CORBA, and Java IDL

IIOP is CORBA's communication protocol. It defines the way the bits are sent over a wire between CORBA clients and servers. CORBA is a standard distributed object architecture developed by the Object Management Group (OMG). Interfaces to remote objects are described in a platform-neutral interface definition language (IDL). Mappings from IDL to specific programming languages are implemented, binding the language to CORBA/IIOP.

The JDK's CORBA/IIOP implementation is known as Java IDL. Along with the `idltojava` compiler, Java IDL can be used to define, implement, and access CORBA objects from the Java programming language.

The Java IDL web page gives you a good, Java-centric view of CORBA/IIOP programming. To get a quick introduction to writing Java IDL programs, see the Getting Started: Hello World web page.

### RMI-IIOP

Previously Java programmers had to choose between RMI and CORBA/IIOP (Java IDL) for distributed programming solutions. Now, by adhering to a few restrictions, RMI objects can use the IIOP protocol, and communicate with CORBA objects. This solution is known as RMI-IIOP. RMI-IIOP combines RMI-style ease of use with CORBA cross-language interoperability.

## The New rmic Compiler

The RMI-IIOP software comes with a new `rmic` compiler that can generate IIOP stubs and ties, and emit IDL.

Here are the new `rmic` flags:

> `-iiop` -- Generates IIOP stubs/ties.
> `-idl` -- Generates IDL.
> `-noValueMethods` -- Stops generation of IDL for methods and constructors within IDL `valuetype`s.
> `-always` -- Forces re-generation even when existing stubs/ties/idl are newer than the input class. Only valid when -iiop and/or -idl flags are present.
> `-factory` -- Uses factory keyword.
> `-idlModule <fromJavaPackage<.class>> <toIDLModule>` -- Specifies IDLEntity package mapping. For example: `-idlModule foo.bar my::real::idlmod`
> `-idlFile <fromJavaPackage<.class>> <toIDLFile>` -- Specifies IDLEntity file mapping. For example: `-idlFile test.pkg.X TEST16.idl`

The new `rmic` behaves differently than previous versions when no output directory (`-d` option) is specified. In the JDK, the stub and tie files are always written into the current working directory when no `-d` option is specifed, regardless of package. The new `rmic` writes the files into subdirectories of the current directory that correspond to their packages.

### The -iiop Flag

Using `rmic` with the `-iiop` option generates stub and tie classes. A stub class is a local proxy for a remote object. Stub classes are used by clients to send calls to a server. Each remote interface requires a stub class, which implements that remote interface. The client's reference to a remote object is actually a reference to a stub. Tie classes are used on the server side to process incoming calls, and dispatch the calls to the proper implementation class. Each implementation class requires a tie class.

Stub classes are also generated for abstract interfaces. An abstract interface is an interface that does not extend `java.rmi.Remote`, but whose methods all throw either `java.rmi.RemoteException` or a superclass of `java.rmi.RemoteException`. Interfaces that do not extend `java.rmi.Remote` and have no methods are also abstract interfaces.

### The -idl Flag

Using `rmic` with the `-idl` option generates OMG IDL for the classes specified and any classes referenced.
IDL provides a purely declarative, programming language independent means for specifying the API for an object.
The IDL is used as a specification for methods and data that can be written in and invoked from any language that provides CORBA bindings. This includes Java and C++ among others. See the Java Language to IDL Mapping (OMG) document for a complete description.

Note: The generated IDL can only be compiled using an IDL compiler that supports the CORBA 2.3 extensions to IDL.

### The -noValueMethods Flag

The `-noValueMethods` option, when used with `-idl`, ensures that methods and initializers are not included in `valuetype`s emitted during IDL Generation. These are optional for `valuetype`s and are otherwise omitted.

See the RMIC tool page (Solaris Version/Windows version) for a complete `rmic` description.

## The New idlj Compiler

The RMI-IIOP software includes a new IDL-to-Java compiler. This compiler supports the new CORBA Objects By Value feature, which is required for interoperation with RMI-IIOP. It is written in Java, and so can run on any platform. See the IDL-to-Java Compiler User's Guide for details of how to use this compiler.

## How to Make RMI Programs Use IIOP

The following steps are a general guide to converting an RMI application to RMI-IIOP.

1. If you are using the RMI registry for naming services, you need to switch to JNDI with the `CosNaming` plugin. You need to do the following:

1. In both your client and server code, you need to create an `InitialContext` for JNDI using the following code:

             import javax.naming.*;
             ...
             Context initialNamingContext = new InitialContext();

2. Modify all uses of RMI registry `lookup()` and `bind()` to use JNDI `lookup()` and `bind()`instead. For example, instead of your RMI server using:

             import java.rmi.*;
             ...
             Naming.rebind("MyObject", myObj);

use:

             import javax.naming.*;
             ...
             initialNamingContext.rebind("MyObject", myObj);

3. If the client is an applet, the client applet needs to pass `this` to the JNDI `CosNaming` plugin. Replace the above code with the following:

            import java.util.*;
            import javax.naming.*;
            ...
            Hashtable env = new Hashtable();
            env.put("java.naming.applet", this);
            Context ic = new InitialContext(env);

2. If you are not using the RMI registry for naming services, you have some other way of bootstrapping your initial remote object reference. For example, your server code may be using Java serialization to write an RMI object reference to an `ObjectOutputStream` and passing this to your client code for deserializing into an RMI stub.

On the server side, use the `PortableRemoteObject.toStub()` call to obtain a stub, then use `writeObject()` to serialize this stub to an `ObjectOutputStream`. The code to do this looks something like:

>     org.omg.CORBA.ORB myORB = org.omg.CORBA.ORB.init(new String[0], null);
>     Wombat myWombat = new WombatImpl();
>     javax.rmi.CORBA.Stub myStub = (javax.rmi.CORBA.Stub)PortableRemoteObject.toStub(myWombat);
>     myStub.connect(myORB);
>     // myWombat is now connected to myORB.  To connect other objects to the
>     // same ORB, use PortableRemoteObject.connect(nextWombat, myWombat);
>     FileOutputStream myFile = new FileOutputStream("t.tmp");
>     ObjectOutputStream myStream = new ObjectOutputStream(myFile);
>     myStream.writeObject(myStub);

On the client side, use `readObject()` to deserialize a remote reference to the object from an `ObjectInputStream`, with code like:

>     FileInputStream myFile = new FileInputStream("t.tmp");
>     ObjectInputStream myStream = new ObjectInputStream(myFile);
>     Wombat myWombat = (Wombat)myStream.readObject();
>     org.omg.CORBA.ORB myORB = org.omg.CORBA.ORB.init(new String[0], null);
>     ((javax.rmi.CORBA.Stub)myWombat).connect(myORB);
>     // myWombat is now connected to myORB.  To connect other objects to the
>     // same ORB, use PortableRemoteObject.connect(nextWombat, myWombat);

3. Either change your remote implementation classes to inherit from `javax.rmi.PortableRemoteObject`, or explicitly export implementation objects after creation by calling `PortableRemoteObject.exportObject()`.
4. Change all the places in your code where there is a Java cast of a remote interface to use `javax.rmi.PortableRemoteObject.narrow()`.
5. Don't depend on distributed garbage collection or use any of the RMI DGC facilities. Use `PortableRemoteObject.unexportObject()` to unexport objects that are no longer in use. This has no effect for objects exported to JRMP on 1.1.6.
6. Regenerate the RMI stubs and ties using the `rmic` command with the `-iiop` option. This will produce stub and tie files with the following names:

         _<implementionName>_Tie.class
         _<interfaceName>_Stub.class

7. Before starting the server, start the `CosNaming` server (in its own process) using the following command:

         tnameserv

This uses the default port number of 900. If you want to use a different port number (for example, port 1050), use the ORBInitialPort modifier:

         tnameserv -ORBInitialPort 1050

8. When starting client and server applications, specify the following system properties:

         java -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory
              -Djava.naming.provider.url=iiop://<hostname>:900
               <appl_class>

This example uses the default name service port number of 900. If you specified a different port in step 7, you need to use the same port number in the provider URL here. The <hostname> in the provider URL is the host name that was used to start the `CosNaming` server in step 7.
9. If the client is an applet, specify the following properties in the applet tag:

         java.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory
         java.naming.provider.url=iiop://<hostname>:900

This example uses the default name service port number of 900. If you specified a different port in step 7, you need to use the same port number in the provider URL here. The <hostname> in the provider URL is the host name that was used to start the `CosNaming` server in step 7.

## Restrictions When Running RMI Programs Over IIOP

To make existing RMI programs run over IIOP, you need to observe the following restrictions.

1. Make sure all constant definitions in remote interfaces are of primitive types or String and evaluated at compile time.
2. Don't use Java names that conflict with IDL mangled names generated by the Java to IDL mapping rules. See section 28.3.2 of the Java Language to IDL Mapping specification for the Java to IDL name mapping rules.
3. Don't inherit the same method name into a remote interface more than once from different base remote interfaces.
4. Be careful when using names that differ only in case. The use of a type name and a variable of that type whose name differs from the type name only in case is supported. Most other combinations of names that differ only in case are not supported.
5. Don't depend on runtime sharing of object references to be preserved exactly when transmitting object references across IIOP. Runtime sharing of other objects is preserved correctly.
6. Don't use the following features of RMI:

- `RMISocketFactory`
- `UnicastRemoteObject`
- `Unreferenced`
- The DGC interfaces

## Converting the RMI Hello World Program to RMI-IIOP

In the following example you'll convert the RMI Hello World example to RMI-IIOP. You will also convert RMI Hello World applet client to an application.

Here's the RMI Hello World players:

- `HelloImpl.java` is the RMI server.
- `Hello.java` is the remote interface implemented by `HelloImpl`.
- `HelloApplet.java` is the RMI client.
- `Hello.html` loads `HelloApplet`.

The RMI Hello World example uses a development directory of `$HOME/jdk1.1/mysrc/example/hello` and a deployment directory of `$HOME/public_html/codebase`, where `$HOME` is your home directory. Though you don't have to, the following example assumes that you use these directories.

If you haven't already, go through the RMI Hello World example. Once you've completed this example, take the following steps.

Adapt the Implementation Class (Server) to RMI-IIOP:

1. Import `javax.rmi.server.PortableRemoteObject` rather than `javax.rmi.server.UnicastRemoteObject`:

         //Goodbye
         //import java.rmi.server.UnicastRemoteObject;

         //Hello
         import javax.rmi.PortableRemoteObject;

2. Import the JNDI naming package:

         import javax.naming.*;

3. Make `HelloImpl` extend `PortableRemoteObject` rather than `UnicastRemoteObject`:

         public class HelloImpl
                      extends PortableRemoteObject
                      ...

4. Use the JNDI registry, rather than the RMI registry, by adding the following code:

         Context initialNamingContext = new InitialContext();

This step provides an initial JNDI naming context (and will also need to be done in the client).
5. Use JNDI `rebind()`, rather than the RMI version:

Old code:

         HelloImpl obj = new HelloImpl("HelloServer");
         Naming.rebind("HelloServer", obj);

New code:

         HelloImpl obj = new HelloImpl("HelloServer"); //unchanged
         initialNamingContext.rebind("HelloServer",obj);

Here are the changes you need to make to `HelloApplet.java`:

1. Import the `PortableRemoteObject` package:

         import javax.rmi.PortableRemoteObject;

2. Create a JNDI initial naming context, and pass this to the CosNaming plugin:

         import java.util.*;
         import javax.naming.*;
         ...
         Hashtable env = new Hashtable();
         env.put("java.naming.corba.applet", this);
         //The next two values will be specifiable
         //By applet tag params in future releases
         env.put("java.naming.factory.initial",
                 "com.sun.jndi.cosnaming.CNCtxFactory");
         env.put("java.naming.provider.url", "iiop://<hostname>:900");
         Context ic = new InitialContext(env);

3. Use JNDI `lookup()`, rather than the RMI version, AND replace the Java remote interface cast with a call to `javax.rmi.PortableRemoteObject.narrow()`:

Old code:

         import java.rmi.*;
         ...
         Hello obj = (Hello)Naming.lookup("//" +
                         getCodeBase().getHost() + "/HelloServer");

New code:

         import javax.naming.*;
         ...
         Hello obj =
          (Hello)PortableRemoteObject.narrow(
                             initialNamingContext.lookup("HelloServer"),
                             Hello.class);

Specify Naming Properties in the Applet Tag

Add the following properties to `Hello.html` applet tag:

>     <param name="java.naming.factory.initial" value="com.sun.jndi.cosnaming.CNCtxFactory">
>     <param name="java.naming.provider.url" value="iiop://<hostname>:900">

Compile the Java Source Files

>     javac -d $HOME/public_html/codebase Hello.java HelloImpl.java HelloApplet.java

Generate the Stub and Tie Classes

Make sure that your search path finds the `rmic` command in the `$RMI_IIOP_HOME/bin` directory.

>     rmic -iiop -d $HOME/public_html/codebase examples.hello.HelloImpl

This will generate the files `Hello_Stub.class` (the client-side proxy) and `HelloImpl_Tie.class` (the server-side proxy) in the `$HOME/public_html/codebase/examples/hello` directory.

Start the JNDI Name Server

>     tnameserv

This starts the JNDI name server with the default port of 900. If you want to use a different port number (Solaris users must use a port above 1024), use a command line such as:

>     tnameserv -ORBInitialPort 1050

Start the Hello Server

>     java -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory
>          -Djava.naming.provider.url=iiop://<hostname>:900
>          examples.hello.HelloImpl

Start the Hello Client

Use `appletviewer` to load `Hello.html`.

>     appletviewer Hello.html

As a reminder, here's what `Hello.html` looks like:

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

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

>     </applet>
>     </HTML>

If all goes according to plan, `appletviewer` will echo the `HelloServer`'s message.

## Converting the Client Applet to an Application

Here's how to change the applet client to an application client:

Adapt the Client Application to RMI-IIOP:

1. Convert `HelloApplet` to an application:

- Copy `HelloApplet.java` (the original RMI version) to `HelloApp.java`.
- Change the class name (for example, to `HelloApp`).
- Remove the `extends Applet` clause.
- Change `init()` to `main()`.
- Move `String message ="";`.
- Eliminate the `paint()` method.

2. Use the JNDI registry, rather than the RMI registry:

         import javax.naming.*;
         ...
         Context initialNamingContext = new InitialContext();

3. Use JNDI `lookup()`, rather than the RMI version, AND replace the Java remote interface cast with a call to `javax.rmi.PortableRemoteObject.narrow()`:

Old code:

         import java.rmi.*;
         ...
         Hello obj = (Hello)Naming.lookup("//" +
                         getCodeBase().getHost() + "/HelloServer");

New code:

         import javax.naming.*;
         ...
         Hello obj = (Hello)PortableRemoteObject.narrow(
                             initialNamingContext.lookup("HelloServer"),
                             Hello.class);

The host and port will be designated when starting the server.

Compile the HelloApp Source

>     javac -d $HOME/public_html/codebase HelloApp.java

You don't need to regenerate your stub and tie.

Start the Name Server and Hello Server

Start these the same as in the applet example.

Start the Hello Application Client

Here's how:

>     java -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory
>          -Djava.naming.provider.url=iiop://<hostname>:900
>           examples.hello.HelloApp

You'll see the server's message printed to the client console.

## Other Things You Should Know

### Servers Need to be Thread Safe

Since remote method invocation on the same remote object may execute concurrently, a remote object implementation needs to make sure its implementation is thread-safe.

### Hashtables with Identical Vector Keys

When a hashtable containing identical vector keys is passed from a JDK 1.1 RMI application to a Java 2 Platform-based RMI application (using either IIOP or JRMP), the identical keys are "coalesced" into one key because of Java 2 Platform deserialization rules. For example:

1. A 1.1 RMI application creates a hashtable.
2. The application puts a value into the hashtable using a vector key A.
3. The application puts another value into the hashtable using a vector key B. Vector B is structurally identical to vector A, but is a different object.
4. The hashtable now has two entries with keys A and B.
5. The 1.1 RMI application sends the hashtable, by value, to a 1.2 RMI application.
6. The hashtable on the 1.2 side has one entry with key B. This is because the deserialization code for the hashtable uses 1.2 rules to populate it, and these rules compare vector keys by value instead of by object identity.
7. If the hashtable is ever sent back across RMI from 1.2 to 1.1, it will still have one entry with key B.

### Interoperating with Other ORBs

RMI-IIOP will interoperate with other ORBS that support the CORBA 2.3 specification. It will not interoperate with older ORBs, because these are unable to handle the IIOP encodings for Objects By Value. This support is needed to send RMI value classes (including strings) over IIOP. At present, no other CORBA 2.3 ORBs are commercially available, but it is expected that these will appear soon.

### Known Problems

- JNDI 1.1 does not support `java.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory` as an Applet parameter. Instead, it must be explicitly passed as a property to the InitialContext constructor. This capability is supported in JNDI 1.2.

- Port 900 is reserved on Solaris. You must use a port number greater than 1024 when running on Solaris.

- On Solaris, you may experience an "out of file descriptors" problem when running RMI-IIOP applications. This may occur if you are using too many file descriptors, which can happen because each JAR file in the classpath consumes one file descriptor and the JDK 1.1.6 setup adds numerous JAR files to the classpath. Before running applications, set the file descriptor limit to a number greater than its default value of 64. For example, set the ulimit number to 90 or higher, as follows:

    ulimit -n 90

RMI-IIOP FCS Release - version 1.00 -
Send your comments to rmi-iiop@sun.com.