CORBA/IDL


Overview

CORBA, or Common Object Request Broker Architecture, is a standard defined by the Object Management Group for distributed object computing. It defines a set of common services that are used to allow objects to invoke each other's methods without regard for the platform on which they operate, or the language in which they are written. Just as Java provides independence at the platform level, CORBA provides independence at the language level.

Similar to Java's Remote Method Invocation package, CORBA allows a Java client object to communicate with a distributed object and exchange information with it through stub and skeleton objects. Unlike the RMI, which is a pure Java solution, CORBA provides object inter-operability with other programming languages, such as C++ and even COBOL.

The CORBA 2.0 specification includes a language, called the Interface Definition Language (IDL), which is used to describe the public methods and variables contained within an object. IDL is not intended to serve as a programming language, but merely as a language that defines the interface into the object. Through IDL pre-compilers, the object's interface is generated into an actual programming language, such as Java. From that point, the object's implementation is written using the native programming language.

This section will present introductory examples using the Java implementation of CORBA (known as Java IDL). The material that follows will not attempt to explain the CORBA specification or its associated services. If you wish to learn more about CORBA, go to the Object Management Group Web site located at http://www.omg.org.

Recall in the section on RMI that a client object communicates with a server object through the RMI registry. The CORBA equivalent to the registry is referred to as a Naming Service. Using the same analogy at a conceptual level, the CORBA environment can be described as follows:

CORBA Environment Model

The CORBA client interacts with another object running on a remote server (the server object). It does so by accessing a reference to the remote object through the Naming Service. Like the RMI registry, the Naming Service is an application that runs as a background process on a remote server. It holds a table of named services and remote object references used to resolve client requests.

Communications between the client and server objects take place through a new protocol: IIOP. This protocol, which stands for Internet Inter-Orb Protocol, is built into the CORBA 2.0 specification, providing a standard communication path for distributed objects.

The steps involved in setting up a CORBA object are as follows:

  1. Create the object's interface using the Interface Definition Language (IDL).
  2. Convert the interface into stub and skeleton objects in a native programming language (e.g. Java).
  3. Implement the skeleton object, creating the CORBA server object.
  4. Compile and execute the server object, binding it to the Naming Service.
  5. Create and compile a client object which will invoke the methods contained within the server object.
  6. Execute the client object, accessing the server object through the CORBA Naming Service.

Elsewhere in this Web site are examples of other distributed applications using the Common Gateway Interface, the JDBC, network sockets, and Java's Remote Method Invocation classes. In the following pages, we will learn how to create a persistent connection between a Java applet and a multi-user server-side JDBC application, using the Java IDL implementation of CORBA. The concepts presented here should be similar to other commercially available products.


The CORBA Naming Service

As we saw earlier, the CORBA Naming Service is a device that allows a CORBA client to resolve name requests for CORBA server objects (similar to the role that the RMI Registry plays for the Java RMI package). When a client wishes to invoke a CORBA server object, it must first obtain a proxy reference to the object (i.e. its stub) through the Naming Service.

CORBA object references can take on one of two forms: transient and persistent. Transient references are ones that remain active only as long as the CORBA server object is active. When the CORBA server object terminates, the transient reference expires.

Persistent references, on the other hand, remain active even if the CORBA server object is not. When a request is made to the persistent object reference, the CORBA service will automatically start the server object if it is not already running.

The current release of the JavaIDL package only recognizes transient references. Persistent object references are not supported and will not be discussed. (Similarly, the JavaIDL package only recognizes static interfaces at this time. Dynamic invocations are not supported in the current release and will not be explained in the pages to follow.)

CORBA object references are defined to the Naming Service in a structure that's known as Name Components. Name Components consist of two attributes: ID and a kind. The object's ID is the name that is assigned to it as it is registered with the Naming Service. The object's kind is optionally specified to provide additional descriptive information about the object, such as the type of object it is (e.g. source code, executable object, etc.). In our examples, we will not explicitly use the kind attribute.

The CORBA object's name is a sequence that is comprised of one or more Name Components. A name containing a single component is referred to as simple name. Conversely, names that consist of multiple components are called compound names. In our illustrations, we'll restrict ourselves to simple names.

When an object's name is bound to the Naming Service, it is referred to as a name binding. The Naming Context is a collection of unique name bindings. It is through the Naming Context and name bindings that we are able to access the CORBA object.

CORBA Naming Context

When the CORBA object wishes to offer itself to the Naming Service, it does so by binding itself and its name to the Naming Context within the Naming Service. We will see how this is actually accomplished as we create our server object later on.

Similarly, when a CORBA client wishes to access the server object, it does so by resolving the object's name through the Naming Service. This will be illustrated when we create our client object.

We are almost ready to begin building our distributed application. Before we do so, we need to look at the IDL briefly and how it maps to the Java language.


IDL to Java Language Mapping

As described in the overview, the Interface Definition Language (IDL) is used to define the interface into a CORBA object. It is not a true programming language with executable logic. It is used only to provide a "blueprint" into the remote object.

The full IDL specification is modeled after C++. It includes such constructs as typedef, enum, const, attribute, struct, module, and interface. Additionally, it contains several data types, such as byte, long, string, and float.

The Object Management Group has established standards for mapping IDL into the Java language. The full specification maps the entire IDL set into associated Java keywords. A few of the more frequently used ones you are like to run across are provided for you below:

IDL Keyword Java Keyword Data length (if applicable)
module package
interface interface
void void
char char 16 bits
long int 32 bits
long long long 64 bits
boolean boolean
float float
double double
string java.lang.String

IDL numeric data types may also be signed or unsigned. Since Java only supports signed numbers, however, all unsigned IDL numeric identifiers will convert to the Java data type that is one size larger than its signed counterpart. For example, unsigned char values in IDL convert to signed int variables in Java.

Parameters passed to methods can be defined within IDL as input (in), output (out), or both (inout). For example:

void method (in long a, out long b, inout long c);

This is converted to Java as follows:

The input field, a, was converted as a normal 32-bit integer. The output and input/out fields, b and c, were converted to IntHolder objects, permitting them to be modified by the method and returned back to the calling object.

Holder objects exist for each of the valid IDL data types. They contain a constructor which allows you to set an initial value (as in the case of inout fields), and a public variable, value, which can be used to access its internal value.

Our examples will not make use of out or inout fields. If you wish to explore the holder objects more, you may find them in the org.omg.CORBA package found with the JavaIDL product.

A simple example of an IDL interface, converted to Java, is shown below:

Test.idl:

Test.java

Let's begin now with the creation of our own distributed application. We'll use the same distributed JDBC application that we saw earlier in our Sockets and RMI sections.


Distributed Computing Using the JDBC and CORBA

In our previous examples using Sockets and RMI, we created a distributed object application to call a back-end database with the JDBC. CORBA introduces a third environment that can be used to deliver this same kind of application. It is similar to these other solutions in many regards:

CORBA is different, however, in that it provides an industry standard for distributed computing in a heterogenous environment. It doesn't perform as well as native sockets, although it significantly outperforms RMI invocations in most commercial implementations.

In large-scale enterprise solutions, there is often an established infrastructure comprised of different platforms and programming languages that don't work well together. Using CORBA, you can preserve the investment in legacy-type systems and extend them with newer, state-of-the-art technologies. Adding Java to the mix also prepares you for future changes in technology by developing new objects and application extensions in a platform-neutral environment.

The JDBC Application

In order to illustrate a distributed computing model using CORBA, as well as its ability to provide persistency in Internet computing, we will build a simple application using the JDBC. If you are new to the JDBC, then refer to the Java Database Connection section of this site for a quick overview. (This same application is shown in the Sockets and RMI sections for comparison purposes.)

In our example, the applet will appear and function as follows*:

1, Nancy Davolio, Sales Representative
2, Andrew Fuller, Vice President, Sales
3, Janet Leverling, Sales Representative
4, Margaret Peacock, Sales Representative
5, Steven Buchanan, Sales Manager
6, Michael Suyama, Sales Representative
7, Robert King, Sales Representative
8, Laura Callahan, Inside Sales Coordinator
9, Anne Dodsworth, Sales Representative

Upon initial load, the applet will connect to the Microsoft Access 7.0 sample database, Northwind. When the "Begin Search" button is pressed, it will perform a search that returns and displays all employee names and titles from the Employee table. When the "Clear Data" button is pressed, it will clear the search results from the applet. The database connection remains open until the applet is closed and terminated (i.e. shut down).

Key success factors of the process include:

As stated in the overview, we determined that there were three components needed to build a CORBA process:

Similar to the Sockets and RMI examples, CORBA allows an applet to communicate with one instance of a particular remote object that was previously registered with the CORBA Naming Service. Because we need to provide multiuser database support, we will add this capability to our JDBC access. We'll refer to this as our JDBC/CORBA Connection Object.


Creating the Remote Interface

All CORBA applications begin with an interface that defines the methods accessible to the CORBA client. This interface is written in the Interface Definition Language and converted to a native language. In our case, the language is Java.

Our CORBA server will implement four public methods to access the relational database:

Our application will also provide multi-user access to the server object. Consequently, the openDatabase method will return an integer variable representing the connection ID to be used by the client in subsequent calls to the server. Let's create the IDL interface:

JI.idl

module TestIDL {
        interface JI {
                long openDatabase();
                void performSearch (in long id, in string search);
                string getNextRow (in long id);
                void closeDatabase (in long id);
        }
}

Our interface, which we call JI (for Java IDL), is defined within a package called TestIDL. The IDL source shows the definition of our CORBA object with its four methods.


Creating the CORBA/JDBC Connection Object

The JDBC Connection object is where the database connection logic is contained. A new object will be spawned by the CORBA server for every client that opens a connection to it. In this way we will be able to support multiple concurrent users.

The JDBC/CORBA connection object is almost identical to the one we created using the RMI. Our only differences are found in the object's name (JIConnection versus JRConnection), and in the getNextRow() method. (We cannot return a null value from the method using the Java IDL product. Instead, we will return an empty string.)

Create the Connection Class

Let's start by importing the JDBC:

package TestIDL;
import java.sql.*;
public class JIConnection {

Define the Variables and Constructor

     private Connection con;         // Database connection object
     private Statement stmt;         // SQL statement object
     private ResultSet rs;           // SQL query results

     /** Default constructor */
     public JIConnection() {
         // initialize the database objects
         rs = null;
         stmt = null;
         con = null;
     }

Create the Database Access Methods

     /** Open a database connection */
     public void openDatabase() throws SQLException, ClassNotFoundException {

         // Load the JDBC-ODBC bridge driver
         Class.forName ("sun.jdbc.odbc.JdbcOdbcDriver");

         // Connect to the database
         con = DriverManager.getConnection("jdbc:odbc:Northwind", "admin", "");
     }

     /** Issue a SQL query with a WHERE clause */
     public void performSearch() throws SQLException {

         String query;           // SQL select string

         // build the query command
         query = "SELECT EmployeeID, LastName, FirstName, Title " +
                 "FROM Employees";

         stmt = con.createStatement();
         rs = stmt.executeQuery(query);
     }

     /** Fetch the next row in the result set, returning null when done */
     public String getNextRow() throws SQLException {
         if (rs.next()) {
             return rs.getInt("EmployeeId") + ", "
                  + rs.getString("FirstName") + " "
                  + rs.getString("LastName") + ", "
                  + rs.getString("Title");
         }

         // end of result set; close the search
         rs.close();
         rs = null;
         stmt.close();
         stmt = null;
         return "";
     }

     /** Close the database connection and any remaining open objects
     public void closeDatabase() throws SQLException {
         if (rs != null)
             rs.close();

         if (stmt != null)
             stmt.close();

         if (con != null)
             con.close();

         rs = null;
         stmt = null;
         con = null;
     }

As we see by the above, four primary methods happen to be the same as the ones we saw in our JI.IDL interface. These methods perform the actual calls to the database through the server object.

Compile JIConnection

javac JIConnection.java

Now that we have the JDBC/CORBA connection object defined and compiled, let's continue with our distributed application. The pages that follow illustrate how we can implement this using Sun Microsystem's Java IDL product .


Using the Java IDL Package

The Java IDL package, which was originally targeted for release with JDK 1.1, was unbundled from the JDK in order to avoid delaying the release of the JDK. It is considered a core API, however, and is planned to be included in future releases of the JDK. An early access release of Java IDL is available for public review. The following pages make use of this release and are subject to change upon final implementation of the API.

If you wish to use the Java IDL package, you must download it from Javasoft's FTP site:

The classes contained within the Java IDL product can be used with JDK 1.02 and above. The following files are available for immediate download:

HTML Documents and API (Windows 95/NT)
HTML Documents and API (Solaris)
IDL Product (Solaris/SPARC)
IDL Product (Solaris x86)
IDL Product (Windows 95/NT)

Download the documentation and IDL product files that are appropriate to your operating system. Note: Do not download the alpha 2.2 release from the current Java IDL Web site located at http://splash.javasoft.com/JavaIDL/pages/index.html. These pages contain a very early version of the package and no longer reflect the model that is currently implemented in the early access release. Proceed instead to http://www.javasoft.com/products/jdk/idl/index.html, which contains the up-to-date documentation.

The examples in the remaining pages of this section have been tested using the Win32 version of the Java IDL under Windows 95. The approach and implementation under Solaris should be similar. Notes regarding the current release and features of the Java IDL are available in the HTML documents that are available from the links listed above.


Installing and Configuring Java IDL

After you download the document and IDL product files for your operating system (see previous page), you need to install and configure the two for your system. These procedures are specific to the Early Access release of the Java IDL as of May 15, 1997.

Install the IDL Product

If you using Windows 95/NT:

JavaIDL-EA-win32

When this program runs, it will ask you for a location to unzip the product. The default selection of C:\ should be adequate for most uses. The installation wizard automatically creates a subdirectory, C:\JavaIDL, for you at this location.

If you are using Solaris:

zcat JavaIDL-EA-solaris-sparc.tar.Z | tar xvf -

When this command completes, a JavaIDL directory will be created in your current working directory. You may move this directory to another location on your machine that is preferable to you.

Install the IDL Documentation

Installing the documentation is not a requirement of the Java IDL, but it does contain some very useful information as well as the API. The procedure is similar to the one we followed above for the IDL product. If you are using Windows 95/NT:

JavaIDL-EA-docs

Again, the installation wizard will prompt you for a location to unzip the product. The default selection of C:\ should be adequate for most uses. The installation wizard automatically creates a subdirectory, C:\JavaIDL\docs, for you at this location.

If you are using Solaris:

zcat JavaIDL-EA-docs.tar.Z | tar xvf -

When this command completes, a JavaIDL/docs directory will be created for you in your current working directory. You may move this directory to another location on your machine that is preferable to you.

Configuring the System Environment

Your PATH and CLASSPATH system variables need to be modified to include the location of the Java IDL. This is done as follows (insert the appropriate directory names based on the location you specified when installing the product):

If you are using Windows 95/NT:

SET JAVAIDL=C:\JavaIDL
SET PATH=%PATH%;%JAVAIDL%\bin
SET CLASSPATH=%CLASSPATH%;%JAVAIDL%\lib\classes.zip

If you are using Solaris (assuming the Bourne shell is used):

JAVAIDL=/JavaIDL ; export JAVAIDL
PATH=$PATH:$JAVAIDL ; export PATH
CLASSPATH=$CLASSPATH:$JAVAIDL/lib/classes.zip ; export CLASSPATH

Configuring the Name Server

The Name Server is the Java implementation of the CORBA Naming Service we learned about earlier. Now that you have installed the Java IDL and documentation, you need to configure the Name Server in order to activate it. This is done in Windows 95/NT and Solaris the same way. Change over to the JavaIDL/bin directory on your system and execute the following Java command:

java installJavaIDL

You are prompted for the following:

  1. Full path to the Java interpreter executable. E.g. C:\JDK1.1.1\bin\java.exe
  2. Full Java classpath. E.g. C:\JDK1.1.1\lib\classes.zip
  3. Java IDL path. E.g. C:\JavaIDL

Enter the path names that are appropriate to your system. The output of this program is a DOS batch file (nameserv.bat) or UNIX shell script (nameserv) that is used later on to start the Name Server.

Well, that's all there is to installing and configuring the Java IDL. Let's move on and begin creating our distributed application.


Implementing the Remote Interface

When we created the Remote Interface earlier, we used the Interface Definition Language to define the remote object (JI.IDL). This interface is our doorway into the CORBA world. To refresh your memory, our interface was defined as follows:

module TestIDL {
    interface JI {
        long openDatabase();
        void performSearch (in long id, in string search);
        string getNextRow (in long id);
        void closeDatabase (in long id);
    };
};

The first step in implementing this interface is to convert it to Java. The conversion is done by running the idltojava tool delivered with the Java IDL:

idltojava -fserver -fclient -fno-cpp JI.idl

When this command completes, a new directory will be created for you with several Java source files. The directory's name is the module name (TestIDL) specified within the IDL source file.

The -f options on the idltojava command line specify which files are to be generated. The -fserver option is used to create the server-side classes. Conversely, the -fclient option is used to create the client-side classes. The -fno-cpp command is required if you don't have access to a C++ compiler. (If this last option is missing, idltojava will attempt to pre-process the IDL source using the C++ compiler.)

The following new files are generated within the directory indicated by the IDL module:

JI.java: This is the Java equivalent of the IDL source file. It defines the remote object's public methods and attributes. (Created with the -fclient option.)
_JIStub.java: This is the object's stub file. The stub acts as a proxy for the remote object and when the client wishes to invoke one of its methods. The stub is downloaded to the client object through the helper object (see below). It is responsibility for dispatching any parameters to the remote object's skeleton object (see below) and deliver back any return value. (Created with the -fclient option.)
JIHelper.java: The helper object resolves the typecasting needed for the client to access the remote object. It also contains the logic necessary to deliver the remote object's stub to the client. (Created with the -fclient option.)
JIHolder.java: The holder object is used for out and inout parameters that are included in IDL method definitions. Since Java doesn't include direct support for such method parameters, the holder object provides this capability to CORBA objects in Java. (Created with the -fclient option.)
_JIImplBase.java: This file serves as the basis for implementing the server object. It implements the CORBA skeleton interface and the IDL interface for our remote object. As the object's skeleton, it can receive the client invocation request, accept any associated parameter values, and call the remote object's implemented methods. The remote server object extends this class, as we will see later on, in order to implement the logic for each of the interface's defined methods. (Created with the -fserver option.)

All of these objects are used internally by the CORBA implementation and require no modification on your part. You simply need to be aware of them and their purpose.


Creating a CORBA Server Object

After the creation of the IDL interface and the associated Java interface classes, we continue by building the remote object's implementation. The remote object extends the base skeleton object, _JIImplBase, that was created by the idltojava tool. It also incorporates the program logic that will be run when its methods are called by a CORBA client.

Remember that we are building a multi-user database connection process. Keeping this in mind, we will not only construct the remote object, but also perform the task management of the multiple connections with the JIConnection object we created earlier.

Create the Server Object

The server object is also referred to as a servant. We start by specifying the package defined by the IDL source file (TestIDL) and extending the Java skeleton base, _JIImplBase.java, that was generated from the IDL interface.

package TestIDL;
import java.sql.*;
public class JIImpl extends _JIImplBase {

Declare the Servant's Variables

We will be managing multiple database connections, so we define a private array that will contain a link to each connection as it is created. Up to 5 instances of the JIConnection object will be allowed in our example.

private JIConnection jic [] = new JIConnection [5];

Create the Servant's Constructor

The servant looks and acts like any other Java object. We can implement a constructor that will perform certain start-up routines when the object is first instantiated by the CORBA server. In our case, we'll simply create an empty default constructor.

/** Default constructor */
public JIImpl () {
}

Create the Server Object's Methods

It is now time to implement the methods that were declared in our IDL interface. As we build these methods, note that they in turn satisfy our multi-user support requirement by interacting with the JIConnection class. We will also take the opportunity to trap any exceptions that may be thrown by the database access methods.

/** Method to open a database connection */
public synchronized int openDatabase() {
    int connectionId;

    // Loop through connection table until an empty slot is found
    for (connectionId = 0; connectionId < jic.length; connectionId++) {
        if (jic [connectionId] == null)
            break;
    }

    // If no empty slots found, generate an error
    if (connectionId >= jic.length) {
        System.out.println("Out of connections.");
        return -1;
    }

    // Create a connection for the new process
    jic [connectionId] = new JIConnection();

    // Call the new connection's method to open a database connection
    try {
        jic[connectionId].openDatabase();
    } catch (Exception e) {
        connectionId = -1;
    }

    // return the connection identifier
    return connectionId;
}

/** Issue a SQL query with a WHERE clause */
public void performSearch(int id) {
    try {
        jic[id].performSearch();
    } catch (Exception e) {}
}

/** Fetch the next row from the current query result */
public String getNextRow(int id) {
    String s = null;

    try {
        s = jic[id].getNextRow();
    } catch (Exception e) {}
    return s;
}

/** Close the database connection */
public void closeDatabase(int id) {
    try {
        jic[id].closeDatabase();
        jic[id] = null;
    } catch (Exception e) {}
}

Compile the Servant

javac JIImpl.java

All the necessary implementation files created by the idltojava command will automatically be compiled at the same time the servant is compiled.


Creating a CORBA Client Applet

The servant object that we just created will be executed as a background process running on the Web server. It represents the "server" side of the "distributed" computing model. The "client" side can be constructed either as a Java application or as an applet. (In fact, since it is a CORBA object, it can also be called from a C++ or COBOL application as well.)

Create the CORBA Client Applet

The sample code below will only display the logic necessary for the applet to use the CORBA object. The complete set of source code for the applet is available in The Complete JDBC/CORBA Example later on.

The applet begins by importing the appropriate CORBA packages and creating an reference to the remote object through its interface (JI). Once it establishes this link, it can proceed to call the remote object's methods as if they were locally available to the applet. Note: Pay particular attention to the highlighted section in the code shown below. This is where the applet locates the server object through the CORBA Name Service. Note also the use of the JIHelper class to access the object's stub reference.

import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import java.sql.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;

public class JIApplet extends Applet
                      implements ActionListener {

   int connectionId;  // process ID for this connection
   JI  orblet;    // CORBA object's interface

   /** Initialize the applet and remote object */
   public void init() {

       String  orbName;

       // obtain a reference to the remote object through its interface
       try {

           // append the name of the remote object within the registry
           orbName = "jdbcidl";

           // create a name component for the object
           NameComponent nc = new NameComponent(orbName, "");
           NameComponent path[] = {nc};

           // connect to the ORB on the applet's host
           ORB orb = ORB.init(this, null);

           // access the ORB's Naming Context through the Name Server
           NamingContext nctxt = NamingContextHelper.narrow(
                   orb.resolve_initial_references("NameService"));

           // obtain a reference to the remote object through the Naming Context
           orblet = JIHelper.narrow(nctxt.resolve(path));

       } catch (Exception e) {
           showStatus("Cannot connect to ORB for jdbcidl");
           return;
       }

       // open a database connection, receiving the process ID
       try {
           connectionId = orblet.openDatabase();
           if (connectionId == -1) {
               searchResults.addItem("Cannot open database connection.");
           }
       } catch (Exception ex) {
               searchResults.addItem("Cannot open database connection.");
       }
   }

   /** close the remote connection if the applet is terminated */
   public void finalize() {
       try {
           orblet.closeDatabase(connectionId);
       } catch (Exception ex) {}
   }

   /** Issue a SQL query with a WHERE clause */
   public void performSearch() throws Exception {

       // issue the database search
       orblet.performSearch(connectionId);

       // process the results of the search
       result = orblet.getNextRow(connectionId);
       while (result != null) {
           // do whatever you want to the result here...
           result = orblet.getNextRow(connectionId);
       }
   }
}

Invoking the Remote Object's Methods

In our example, the orblet object references the servant object's stub from on the CORBA server. This is done by accessing the Naming Service, through which the Naming Context resolves the servant's registered name, jdbcidl (which we will learn how to set when we bring it all together). All subsequent calls to the servant's methods are performed via our orblet reference, as if the object were local to the applet.

Compile JIApplet

javac JIApplet.java

Now that we have the client applet defined and compiled, let's bring it all together.


Bringing It All Together

At this point we have created the following classes and interfaces:

  1. JI: IDL interface
  2. JIConnection: database access methods using the JDBC
  3. JIImpl: remote object, using JIConnection for multi-user database connectivity
  4. JIApplet: client object, using the RMI to call the methods within JIImpl through the JI interface.

Based on what we've seen so far, JIApplet loads information about the server object from the CORBA Naming Service. Before we can activate our servant object, we must start the Name Server.

Starting the Name Server

The CORBA Naming Service is implemented within the Name Server that we configured when we installed the Java IDL product. Recall that we had created a nameserv.bat (or nameserv for UNIX) script within this process. To start the Name Server as a background process on our CORBA server, we merely execute the script.

Windows 95/NT:

start nameserv.bat

Solaris:

nameserv &

Changing the Default Port

The Name Server automatically runs on TCP port 900. (If you are running under UNIX, you need root access to execute this command.) You can override the default port on the command line as follows:

nameserv -ORBInitialPort 1234

In this example, the Name Server is started on TCP port 1234. If you use a non-default port number, you must be sure to specify this port number as you run the CORBA client. With applets, this is done by inserting a PARAM tag in the HTML document as follows:

<PARAM NAME="org.omg.CORBA.ORBInitialPort" value="1234"> 

With applications, this is done by specifying the -ORBInitialPort value on the command line (like we did when we started the Name Server):

java CorbaClientApp -ORBInitialPort 1234

Accessing a Name Server on a Different Host

Applets automatically access the CORBA Naming Service running on the host from which it was downloaded. The host is determined by ORB.init() through the applet's getCodeBase().getHost() value. Because of the limitations imposed by the applet's security manager, it cannot access Name Servers running on a different host.

By default, applications also access the CORBA Naming Service on the host where the application is running. This can be overridden by specifying a -ORBInitialHost parameter on the command line, similar to the -ORBInitialPort option we saw above:

java CorbaClientApp -ORBInitialHost myhost.domain.com

When the ORB.init() call is executed within the client application, it will use the host specified on the command line to access the CORBA Naming Service.

Through the -ORBInitialHost and -ORBInitialPort options, it is possible for applets to call CORBA servants on the Web server and, through them, invoke CORBA objects running on other machines.

Okay, let's bring everything together now.

Create a Servant Bootstrap Program

The final step in setting up our CORBA server object is to create a bootstrap program for the servant. This is done through a small program that initializes the object to the CORBA server and binds it with the Naming Service. We'll create JIStart to do this:

package TestIDL;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;

public class JIStart {

        /** Main routine to start the object as a background process and
          * bind itself with the Name Server
        **/
        public static void main(String args[]) throws Exception {
                System.out.println("Starting the ORB...");

                // initialize the ORB
                ORB orb = ORB.init(args, null);

                // create and register the object
                JIImpl orblet = new JIImpl();
                orb.connect(orblet);

                // define the object's name component
                NameComponent nc = new NameComponent("jdbcidl", "");
                NameComponent path [] = {nc};

                // get a reference to the Name Server
                NamingContext nctxt = NamingContextHelper.narrow(
                        orb.resolve_initial_references("NameService"));

                // bind the object to the Name Server
                nctxt.rebind(path, orblet);

                System.err.println("JDBCIDL server object ready");

                // wait for client invocations
                java.lang.Object sync = new java.lang.Object();
                synchronized (sync) {
                        sync.wait();
                }
        }
}

First, you see that object initializes itself with the CORBA server (called the ORB, or Object Request Broker). As it does so, it passes any command line arguments to it. This is where the -ORBInitialHost and -ORBInitialPort parameters are passed along in case the servant wishes to register with another host or port number.

Next, we instantiate the implementation of the remote object, JIImpl.

We then create a name component for the object, assigning the name "jdbcidl" to the object, and obtain a reference to the Naming Context on the ORB. Finally, we call the Naming Context's rebind() method to register the object and its name component with the ORB.

The last step in the bootstrap is to await client invocations through a synchronized wait() call to a generic object. Without this call, the bootstrap would terminate and lose the object's reference with the CORBA Naming Service. (This is because the object is held as a transient reference by the Java IDL implementation of the Naming Service.)

Compile JIStart

javac JIStart

Run the Bootstrap Program

Similar to the Name Server, the bootstrap program must be executed as a background process:

Windows 95/NT:

start java TestIDL.JIStart

Solaris:

java TestIDL.JIStart &

Start the Applet

Run the applet now, and you are ready to go!

appletviewer ji.htm

(The ji.htm document contains an <APPLET> tag to run TestIDL.JIApplet.class.)


The Complete CORBA/JDBC Example

The complete source code for each of the objects created in our JDBC/CORBA example is available through the links listed below. You may save each of these objects or copy/paste the code into files on your hard disk and experiment with them. Good luck with your own CORBA applications!

Note: When the IDL source file is processed through idltojava, a TestIDL directory will be created, corresponding to the module statement specified within the IDL. All Java source files must be stored and compiled within this TestIDL directory.

Be sure also that your CLASSPATH setting points to the parent directory of TestIDL.

JI.idl

The IDL interface.

JIConnection.java

The object that connects to a database using the JDBC, allowing multi-user access.

JIImpl.java

The CORBA servant.

JIApplet.java

The CORBA client.

JIStart.java

The CORBA servant's bootstrap program.