Locating CORBA objects using Java IDL

Learn how to use stringification and the COS Naming Service to find CORBA objects spread around the enterprise

One of the longest weeks in my programming career was the one I spent attempting to combine a CORBA object implemented using Visigenic's VisiBroker for Java with a client using JDK 1.2 beta 2.

Obviously, this was a while ago since Java 2 was released very recently and Visigenic subsequently has been swallowed by Borland, which morphed into Inprise. Anyway, ever the one who likes to stick to standard protocols and APIs, I originally implemented the server and client applications using the Java IDL API integrated into the JDK. Playing safe, the server and client relied on the standard CORBA naming service for locating the CORBA object. All went according to schedule until the server's default Java IDL ORB was replaced with Visigenic's ORB. If I used the VisiBroker Naming Service implementation, the client could not locate the naming service, and if I used the Java IDL implementation, the server could not locate the naming service. Pow-- instant headache!

Had I finally been let down by open standards? Had IIOP really not made it possible for multiple ORBs to interoperate? Yes and No turned out to be the respective answers to those questions. As usual, the Templar Knight in me ran off to do battle without first stopping to read the specification's fine print or performing adequate prototyping. A little food, sleep and research quickly solved the problem once all possible hacking (and I, myself) was exhausted.

I hope this article will prevent you from experiencing one of those dreaded weeks in which your progress report simply says: "Fixed a bug by writing three lines of code."

Interoperable Object Reference (IOR)

The CORBA market provides many strategies, standards, and products for locating CORBA objects, but only one mechanism works for all IIOP-compliant CORBA implementations: Interoperable Object References (IORs). When working in a multiple-ORB environment, an IOR usually provides the only means to obtain an initial reference to an object, be it a naming service, transaction service, or customized CORBA servant.

ORBs supporting IIOP identify and publish object references using IORs. An IOR contains the information required for a client ORB to connect to a CORBA object or servant. Specifically, an IOR contains the following:

IIOP version -- Describes the IIOP version implemented by the ORB

Host -- Identifies the TCP/IP address of the ORB's host machine

Port -- Specifies the TCP/IP port number where the ORB is listening for client requests

Key -- Value uniquely identifies the servant to the ORB exporting the servant

Components -- A sequence that contains additional information applicable to object method invocations, such as supported ORB services and proprietary protocol support

In short, an IOR specifies the wire protocol for talking to an object as well as specifying the object's network location.

The IOR structure isn't important to programmers, since an IOR is represented through a String instance by a process known as stringification. Stringification is the process of converting a servant reference to and/or from a string representation of an IOR. Once an object reference has been stringified, it can be used by other applications to obtain a remote servant reference.

IORs are convenient because they are easy to use and are ORB-implementation-independent, but they present a small challenge: How does a client obtain a copy of the stringified IOR? Although this article won't present any "real" solutions to this problem, let me offer a few possibilities:

Distributed filesystem -- The server process writes the stringified IOR to a known mount point, or shared folder, to be read by client applications, assuming every system supports a common distributed filesystem (NFS, Novell, Windows networking)

Web publishing -- The server process writes the stringified IOR to a known location in the server's document root using a servlet or CGI script, enabling client programs to easily retrieve stringified references from the Web server using the HTTP protocol

Database -- The server process writes the IOR to a table of IORs using a symbolic name as the primary key value and client programs retrieve the IOR using any suitable database API

A future column will demonstrate how to use Java Naming and Directory Interface (JNDI) to access naming and directory services, and then provide several techniques to publish CORBA objects and IORs.

Using stringification

A CORBA object is uniquely identified by an object reference. The IIOP specification defines an IOR as an ORB-independent object reference. Given a stringified object reference, a client can create a proxy that enables requests to be forwarded to the remote CORBA object. Java IDL, along with the underlying OMG CORBA standard, defines two org.omg.CORBA.ORB methods used for stringification:

  • String object_to_string(org.omg.CORBA.Object o) -- Converts the given CORBA object reference to a stringified IOR. Note: the string returned by this method is not designed to be human readable, as is the case with the Object toString() method.

  • org.omg.CORBA.Object string_to_object(String ior) -- Converts a stringified IOR produced by the method object_to_string() back to a CORBA object reference.

The stringification process is illustrated in Figure 1.

Figure 1. The stringification process

Example code

The following code sample creates a SimpleObject implementation, generates a stringified IOR, and writes it to a file called simple.ior.

package ior;
import org.omg.CORBA.ORB;
import java.io.*;
public class IorServer {
   public static void main(String args[]) throws IOException {
      //create object and register with ORB
      SimpleObjectImpl simple = new
      //initialize ORB and stringify object
      ORB orb = ORB.init(args, null);
      String ior = orb.object_to_string(simple);
      System.out.println("IOR: " + ior);
      //write stringified object to file
      FileWriter fw = new FileWriter("simple.ior");
      //block to prevent application from terminating
      //CORBA does not create any user threads to service clients
      System.out.println("Ready for client requests to simple
 object...");try {
      } catch(InterruptedException ex) {}

After using the command-line parameters to initialize the ORB, a stringified IOR is generated using the object_to_string(). The IOR is written to a file which the client program will read to obtain the IOR. Java IDL does not create any user threads to service client requests, so the program deadlocks the interpreter's thread to prevent the application from terminating. Running the application yields the following output:

> java ior.IorServer
Ready for client requests to simple object...

The IOR may be a String, but it certainly is not human readable.

For this simple example, I am going to run the client application from the same directory as the IorServer application. The client application initializes the ORB, reads in the stringified IOR from the simple.ior file, and converts the IOR to a SimpleObject CORBA reference (proxy).

package ior;
import org.omg.CORBA.ORB;
import java.io.*;
public class IorClient {
   public static void main(String args[])'
throws IOException {
      //initialize ORB and stringify object
 ORB orb = ORB.init(args, null);
      //read stringified object to file
      FileReader fr = new
      BufferedReader br = new
      String ior = br.readLine();
      org.omg.CORBA.Object obj = orb.string_to_object(ior);
      SimpleObject proxy = SimpleObjectHelper.narrow(obj);
      //invoke methods
      System.out.println("Invoked method on simple object");

In CORBA, the org.omg.CORBA.Object interface defines a CORBA proxy (object reference). It is analogous to java.rmi.Remote in RMI. The choice of the interface name is unfortunate, since it collides with the java.lang.Object class name if the org.omg.CORBA package is imported. But I digress.

The string_to_object() method returns a CORBA Object implementation, which refers to a SimpleObject servant. In Java, a program would typically down-cast the reference to a SimpleObject and invoke the reference's methods.

When using CORBA, however, a narrow must be performed. Narrowing is performed using the IDL-to-Java-compiler-generated XXXHelper class -- SimpleObjectHelper in this case. Attempting a simple cast will cause a ClassCastException. Strange, but true.

COS Naming Service

The COS Naming Service is an OMG-specified extension to the core CORBA standard, where COS stands for Common Object Service. This naming service allows an object to be published using a symbolic name, and it allows client applications to obtain references to the object using a standard API. The COS Naming Service can reside on any host accessible within the network and enables applications to publish, lookup and list CORBA object references from any network host.

A namespace is the collection of all names bound to a naming service. A name space may contain naming context bindings to contexts located in another server. In such a case, the name space is said to be a federated name space since it is a collection of name spaces from multiple servers. An interesting point is that the location of each context is transparent to the client applications; they will have no knowledge that multiple servers are handling the resolution requests for an object.

Java 2 ships with a compliant implementation of the COS Naming Service, called tnameserv. The command-line syntax for running tnameserv is:

> tnameserv [-ORBInitialPort ####]

The tnameserv runs on port 900 unless specified otherwise using the -ORBInitialPort command-line parameter.

The Java IDL COS Naming Service implementation supports transient bindings only, which means objects must be reregistered each time the naming service is restarted. The COS Naming Service implementations for Iona and Inprise are much more sophisticated and scalable, since they support persistent bindings, load balancing, and customization. The JDK tnameserv naming service is more than adequate to get developers started on a project. When rolling out your applications, you will want to purchase a commercial implementation to gain persistent naming and load balancing capabilities.

A COS Naming Service stores object references in a hierarchical name space; much like a filesystem uses a directory structure to store files. Specifically, bindings maintain the association between a symbolic name and an object reference, while naming contexts are objects that organize the bindings into a naming hierarchy. Like the root directory in a filesystem, the initial naming context provides a known point to build binding hierarchies. To complete the filesystem analogy, a binding maps to a file and a naming context maps to a directory. Thus, a naming context can contain multiple bindings and other naming contexts.

Consider a company that maintains an administrative database of devices on the network. These devices implement an administrative CORBA interface that defines attributes for querying current state and performing basic configuration tasks. Figure 2 depicts a possible naming hierarchy and illustrates that the same object may occur in multiple places within a naming hierarchy. For example, each printer is listed under a building and under printers.

Figure 2. Example naming hierarchy

In this article, a dash (-) is used to separate each naming component. For example, building-461-fax 1 would denote the fax 1 node located under the 461 context, which happens to be bound to the building context. The name building-461-fax 1 is known as a compound name because it consists of more than a single binding.

Getting the initial naming context

Before performing any tasks using the COS Naming Service, you must obtain a reference to the initial naming context. There are two standard ways to get the initial naming context:

1 2 Page 1
Page 1 of 2