Whole document tree
Table of Contents
IntroductionThis 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 ReadingHere are some sites to get you up to speed with this technology:
What is RMI-IIOP?RMIWith 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 IDLIIOP 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-IIOPPreviously 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 CompilerThe 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.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 FlagUsing 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 FlagUsing 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 FlagThe -noValueMethods option, when used with -idl, ensures that methods and initializers are not included in valuetypes emitted during IDL Generation. These are optional for valuetypes and are otherwise omitted.See the RMIC tool page (Solaris Version/Windows version) for a complete rmic description. The New idlj CompilerThe 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 IIOPThe following steps are a general guide to converting an RMI application to RMI-IIOP.
import javax.naming.*; ... Context initialNamingContext = new InitialContext(); import java.rmi.*; ... Naming.rebind("MyObject", myObj);use: import javax.naming.*; ... initialNamingContext.rebind("MyObject", myObj); import java.util.*; import javax.naming.*; ... Hashtable env = new Hashtable(); env.put("java.naming.applet", this); Context ic = new InitialContext(env); 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: On the client side, use readObject() to deserialize a remote reference to the object from an ObjectInputStream, with code 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); 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); _<implementionName>_Tie.class _<interfaceName>_Stub.class tnameservThis 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 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. java.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory java.naming.provider.url=iiop://<hostname>:900This 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 IIOPTo make existing RMI programs run over IIOP, you need to observe the following restrictions.
Converting the RMI Hello World Program to RMI-IIOPIn 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:
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:
//Goodbye //import java.rmi.server.UnicastRemoteObject; //Hello import javax.rmi.PortableRemoteObject; import javax.naming.*; public class HelloImpl extends PortableRemoteObject ... Context initialNamingContext = new InitialContext();This step provides an initial JNDI naming context (and will also need to be done in the client). Old code: HelloImpl obj = new HelloImpl("HelloServer"); Naming.rebind("HelloServer", obj);New code: HelloImpl obj = new HelloImpl("HelloServer"); //unchanged initialNamingContext.rebind("HelloServer",obj);
import javax.rmi.PortableRemoteObject; 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); 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); 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 Generate the Stub and Tie Classesjavac -d $HOME/public_html/codebase Hello.java HelloImpl.java HelloApplet.java Make sure that your search path finds the rmic command in the $RMI_IIOP_HOME/bin directory. 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.rmic -iiop -d $HOME/public_html/codebase examples.hello.HelloImpl Start the JNDI Name Server 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 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. As a reminder, here's what Hello.html looks like:appletviewer Hello.html If all goes according to plan, appletviewer will echo the HelloServer's message.<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> Converting the Client Applet to an ApplicationHere's how to change the applet client to an application client:Adapt the Client Application to RMI-IIOP:
import javax.naming.*; ... Context initialNamingContext = new InitialContext(); 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. You don't need to regenerate your stub and tie.javac -d $HOME/public_html/codebase HelloApp.java Start the Name Server and Hello Server Start these the same as in the applet example. Start the Hello Application Client Here's how: You'll see the server's message printed to the client console.java -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory -Djava.naming.provider.url=iiop://<hostname>:900 examples.hello.HelloApp
Other Things You Should KnowServers Need to be Thread SafeSince 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 KeysWhen 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:
Interoperating with Other ORBsRMI-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
ulimit -n 90 Send your comments to rmi-iiop@sun.com. |