Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

CORBA, Introduction to Common Object Request Broker Architecture

Java Programming, Lecture Notes 620, Revised 2/13/99.


Preface

Students in Prof. Baldwin's Advanced Java Programming classes at ACC will be responsible for knowing and understanding all of the material in this lesson beginning with the spring semester of 1999.

This lesson was originally written on October 23, 1998. The sample program was tested using the JDK 1.2beta4 download package. The purpose of this lesson is to illustrate CORBA using a very simple example program.

In February 1999, the sample program in this lesson was successfully tested using the released version of JDK 1.2.

Introduction

As you learned in an earlier lesson, Java's Remote Method Invocation (RMI) makes it possible for code in an object running in one Java Virtual Machine (JVM) to invoke methods on an object running in another JVM.  The two JVMs may be running as separate processes on the same computer, or may be running on different computers connected by a TCP/IP network.

However, RMI is not the only approach to distributed objects in common use as of October 1998. Two other common approaches are the DCOM approach from Microsoft, and the Common Object Request Broker Architecture (CORBA) approach from the Object Management Group (OMG).

As of October 1998, Java JDK 1.2beta4 supports CORBA with some limitations. As far as I know, Java from JavaSoft does not support DCOM, at least not to the degree that it supports RMI and CORBA. It seems fairly safe to assume that Microsoft's blend of Java does support DCOM, but as of this writing, I haven't investigated that possibility.

As you are aware, RMI is platform independent, but is not language independent. The code on both the client and server must be written in Java.

As of October 1998, DCOM is language independent, but is not platform independent. Although the programs can be written in many different languages, the scheme only works with the Microsoft family of operating systems.

CORBA, on the other hand, is both platform independent and language independent. The code at either end may be written in any language for which there is an OMG Interface Definition Language (IDL) mapping. This includes most of the major programming languages in use today. Client software written in any of the available languages can invoke methods on server objects (servants) written in any of the available languages.

Since this is a Java tutorial, I will concentrate on the use of Java with CORBA. You need to be aware, however, that the same programs could be written and executed successfully across a network in other languages as well.

This means that a client machine anywhere in the world has the capability of invoking methods on an object on a server anywhere in the world, and the programs at the two ends can be developed using different programming languages.  The potential benefits of such operation are very significant.

The roles of client and server can switch back and forth between the two machines. The machine with the object whose methods are invoked remotely is the server, and the machine invoking the methods on the remote object is the client.

Special code is required in the program on the client side to get a reference to the remote object.  Once the client code has a reference to the remote object, the invocation of methods on the remote object is very similar to the invocation of methods on local objects.

The code on the server side must define the class and instantiate the remote object of that class.  Beyond this, special code is required on the server side to register the object and expose its methods to client machines so that those methods can be invoked remotely.

Both the client code and the server code have access to an IDL file, which declares the methods that can be invoked remotely. This is the key to the whole process and the glue that holds it all together.

If all of this sounds very similar to what you learned about RMI, it is. The implementation of CORBA in Java is very similar to the implementation of RMI in Java. However, the implementation of CORBA is a little more complicated than the implementation of RMI.

When invoking methods on the remote object using RMI, the client can pass objects as parameters, and the method on the remote object can return objects.  This is accomplished through the object serialization capability of Java. CORBA doesn't support object serialization, so with CORBA, parameter passing can only be accomplished by reference.

This lesson attempts to explain how to use CORBA with Java, but does not attempt to explain how and why it works.  Subsequent lessons will attempt to provide some insight into how it works.

Overview

The implementation of CORBA for this minimal application requires you to write three short source code files and to execute two different utility programs.  Executing one of the utility programs produces several additional Java source files including stub and skeleton files similar to those used with RMI.

It is necessary to compile all of the source files and make the class files available to the client code and the server code.

The entire process can be tedious, so I prefer to encapsulate the process in a batch file. Then I don't have to remember from one run to the next exactly what I need to do and the order in which I need to do it.

Sample Program

Thinking in terms of the Java Virtual Machine, CORBA makes it possible for a method in an object running under one virtual machine to invoke a method in an object running under a different virtual machine just as if it were a method in a local object.  The two virtual machines can be running as different processes on the same hardware platform.  Or, they can be running on different machines, of the same or different types, on different parts of the Earth, connected by a TCP/IP network.

This is a Java/CORBA application that makes it possible for code in a client object running under one JVM to access a method in a servant object running under a different JVM on the same platform to get the date and time. It is a minimal program.  It requires three separate source files and two utility programs to compile and execute.  The source files are:

The two utility programs are:

As mentioned earlier, given so many files and utility programs and a complex sequencing requirement associated with compiling and executing them, I decided to make the process semi-automatic by encapsulating the process in an MS-DOS batch file.  If you are not running under Windows or NT, you will need to figure out how to produce an equivalent script file for the platform that you are running on.

I also find that having this batch file available makes it easier to explain the mechanics of making the whole process work.

I am going to discuss the batch file and the sequence of events and explain how you can run this CORBA application on a single hardware platform by running the name server in one process, the server in a second process, and the client in a third process. 

Here is the scenario.  I have a folder on my computer that contains the following four source files:

Only the last three files are required. The batch file is optional, but is useful for managing the whole process.

Initially, this folder doesn't have any sub folders. However, execution of the program idltojava creates a package to contain the source files that it generates. By default, it makes that package reside in a sub folder of the folder from which it is executed. To avoid cluttering up my disk with generated files (or more properly to make it easier to find and delete the generated files), I forced the package to be in a tree that begins with a folder named junk. As a result, a junk folder is automatically generated that contains another folder named TheDateApp, which is the actual package name.

As the programmer for both the client and the server, it was my responsibility to write the code in the IDL file as well as the code in the two Java source files in the above list. I will have more to say about IDL files later.

Normally, the code in the IDL file and the server file is written by the server programmer. A copy of the IDL file is provided to the client programmer whose job it is to write the code in the client file

I will discuss the overall operation of this system running in separate processes on a single platform when I discuss the batch file later.

The Interface Definition Language (IDL) File

The IDL file is the glue that holds the system of programs together and makes it possible for code in a client to invoke methods in a remote object on a basis that is both platform and language independent.

I will begin by showing you the source code contained in the IDL file for this simple application.

/*File Corba02.idl
**********************************************************/
module TheDateApp{
  interface TheDate{
    string getTheDate();
  };//end interface TheDate
};//end module TheDateApp

The OMG Interface Definition Language is not a language that is intended to be compiled into executable code. Rather, it is a language that is used to declare the interface to one or more operations (similar to methods in Java) on an object. The programmer is then responsible for translating the declaration of those operations into another language such as Java or C++, and then implementing the operations in that language.

Fortunately for Java programmers, an executable program named idltojava became available with JDK 1.2 that automates the process of translating the declarations from the IDL file into Java source code, thus relieving us of that burdensome responsibility. (Note that as of October 1998, the idltojava program must be downloaded separately from the JDK 1.2 download.)

It is doubtful that I will have the time to go into any detail regarding the format requirements of the OMG IDL in any of these lessons. A host of documentation on the IDL can be found at the following URL: http://www.omg.org/corba/

Now let's turn our attention to the simple IDL file used for this application. Again, fortunately for Java programmers, the concept involved here isn't much different from the concept of the interface used routinely in Java. The module specification in the above file translates into a package specification in Java. Hence, the source files produced by the idltojava program will be stored in a package (folder) named TheDateApp. When you run the program, you can specify the path to that folder as a command-line parameter. If you don't provide a path, it will default into creating a sub folder of the folder from which the program is run.

Inside the module, and highlighted in boldface, we see a single interface specification named TheDate. Again, particularly for this simple case, this is very similar to an interface in Java. This CORBA interface declares a single operation (method) named getTheDate() which receives no parameters and returns a string.

From its name, we might surmise that the string that is returned contains date information, but there is no technical requirement for this. All that is technically required is that the implementation of this interface into a Java method (or a C++ function or whatever) receives no parameters when called and returns a string. That also is similar to the declaration of a method in a Java interface. The Java interface simply declares the interface to a method and says nothing about the behavior of that method.

In this application, the Java method corresponding to this CORBA interface will return date information as a String object.

During the discussion of the operational steps executed by the batch file, I will show and partially explain to you the results of running the idltojava program against this IDL file.

The Batch file

The name of the batch file is Corba02.bat.  A complete listing of the file is provided near the end of this lesson.  I will show and discuss the individual parts in this section and you can refer to the entire file later. In this discussion, I have omitted statements in the batch file that simply display progress on the screen.

The first statement in the batch file executes the idltojava program against the file named Corba02.idl.

idltojava -fno-cpp -p junk Corba02.idl

The idltojava program will accept several optional command-line parameters. I am simply going to ask that you accept the need for providing -fno-cpp to cause the program to run successfully. Briefly, this parameter overrides a default requirement for the availability of a C++ style header file.

I use the optional -p junk argument to cause the package/folder created by the program to be a sub folder of a folder named junk. As mentioned earlier, this makes it easy for me to search the disk for folders named junk and delete them rather than to let my disk fill up with generated source files during development and experimentation. You can either leave this in or take it out. For this application, the name of the package/folder that will contain the generated files is TheDateApp (because that was the name of the module in the IDL file).

For this application, the following Java source files are created in the folder named TheDateApp by execution of this statement.

Similar files will always be created by execution of idltojava, but their names will be different. Some of the descriptive information for these files will make a lot more sense when we discuss the overall process in much more detail in a subsequent lesson.

The next statement in the batch file simply compiles all of the source files including those in the package/folder named junk.TheDateApp. There should be no surprises here.

javac Corba02*.java junk/TheDateApp/*.java

A client object can learn of a server object and its methods in several different ways. This application uses a name server that is delivered as an executable program named tnameserv in the JDK 1.2 download package. I will discuss this in more detail and will also discuss other ways of doing the same thing in subsequent lessons.

For now, suffice it to say that the following statement in the batch file executes tnameserv in a separate process that makes the name server available. Under Win95, this will cause a new MS-DOS window to appear, and after a short pause, some fairly cryptic text will be displayed in that window by the program.

Note that it is necessary to manually terminate this program (Ctrl-C under Win95) when you are finished with it.

start tnameserv -ORBInitialPort 1050

By default, this name server operates on port 900. The above usage overrides the default and specifies that it operates on port 1050.

The next statement starts the server program running in a process of its own, and as you have probably surmised, causes it to use port 1050 for certain aspects of its communication. Under Win95, this also will cause a new MS-DOS window to appear, and after a short pause, a message will appear in that window indicating that the server is ready.

When we examine the code for the server, you will see that it goes into an infinite wait state waiting for requests from clients. Therefore, it is necessary to manually terminate it when you are finished with it.

start java Corba02Server -ORBInitialPort 1050

The final statement in the batch file starts the client running in a process of its own. Under Win95, this will cause a new MS-DOS window to appear. After a short pause, the date and time will be displayed, having been obtained from the servant object on the server by the code in the client program.

Then a message will appear asking you to press Ctrl-Z to terminate the program. Without this last step, the client program will terminate automatically as soon as it displays the date and time. This causes the MS-DOS window to close and makes it very difficult to see what is happening.

start java Corba02Client -ORBInitialPort 1050

Note that on my Win95 system, after each of the new MS-DOS windows appear, it is necessary for me to click on and return focus to the main MS-DOS window to cause the next statement in the batch file to execute. Note also that occasionally the entire system simply hangs up while executing these programs and it is necessary for me to reboot to restore it to operational condition.

The Server File

The name of the file containing the server code is Corba02Server.java.

Of necessity, the code for a CORBA server or a CORBA client includes quite a bit of code that is essentially the same from one application to the next. This is the code that is necessary to get everything initially set up so that all the pieces work together in a cooperative manner. In this lesson, I am going to ignore that code and discuss only the code that may differ from one application to the next. You can view a complete listing of the program near the end of this lesson. Also, I will come back and discuss this boilerplate code in a subsequent lesson.

I will discuss this file in fragments. The first fragment shows the import statements that are required. The first import statement was required to access the class files produced by compiling the source code files in the package named TheDateApp. These are the files that were discussed earlier, produced by running idltojava on the IDL file.

The next three import statements were required to incorporate various CORBA libraries into the program. These are libraries that are part of the JDK 1.2 download package.

The last import statement was required because this program instantiates a Java Date object.

/*File Corba02Server.java
**********************************************************/
import junk.TheDateApp.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import java.util.Date;

CORBA documentation and books abound in the use of acronyms and jargon. I have been trying very hard to spare you the need to deal with that up to this point. However, the time always comes when you have to learn the language to understand the conversation.

On a couple of occasions I have used both the words server and servant. In CORBA-speak, the server is the program that owns one or more objects whose operations (methods) can be invoked by code in other objects running in a different process. Each of those objects is referred to as a servant. In other words, servers provide servants whose methods can be invoked by code in other objects in other processes.

This simple application has only one servant object. The class definition, named TheDateServant, from which this servant object was instantiated is shown below. As you can see, this class extends one of the classes that resulted from compiling one of the source files that was automatically generated by executing idltojava on the IDL file as discussed above.

This is the class that implements the method named getTheDate() that was declared in the interface in the IDL file. Hence, this is the method that the code in the remote client objects can invoke. They know about it because they also have access to the IDL file.

This method is very simple in this application, simply returning the date and time as a String object. However, the method could be as complex as it needs to be to accomplish its objectives.

class TheDateServant extends _TheDateImplBase{
  public String getTheDate(){
    return new Date() + "\n";
  }//end getTheDate()
}//end TheDateServent class

The next fragment shows the definition of the class named Corba02Server from which the server object was instantiated. All of the code in this class is contained in the main() method. As explained earlier, I have omitted quite a lot of the boilerplate code from this fragment and replaced it by comments.

public class Corba02Server{
 
  public static void main(String args[]){
    try{
      //Create and initialize the Object Request 
      // Broker (ORB) object
 
      //Instantiate servant object 
      TheDateServant theDateRef = new TheDateServant();

      //Register the servant object with the ORB

      //Do everything necessary to register and expose
      // the servant object with the name service under
      // the name "TheDate".

      System.out.println("Server is running");
 
      //Wait indefinitely for invocations from clients
 
    }catch (Exception e) {//Exception handler goes here
    }//End catch block
  }//end main()
}//end Corba02Server class

As you can see, once I eliminated the boilerplate code that essentially repeats from one application to the next, there wasn't very much to the server code. About all that differs from one application to the next is the instantiation of the servant object (or objects), and the usage of a reference to that object inside the boilerplate code. Once you learn the scheme, this is cut and paste programming.

Most of the functionality that differs from one application to the next goes into writing the methods that implement the interfaces in the IDL file. In practice, you could write a lot of CORBA applications without ever understanding the boilerplate code that I omitted from the above listing. However, since it is usually better to understand what you are doing than to work in the blind, I will try to provide an understanding of the omitted code in a subsequent lesson. You can view the code that was omitted in the listing of the server file that is provided near the end of this lesson. 

The Client File

The file containing the client code is named Corba02Client.java.

As is the case with the server code, quite a lot of boilerplate code is required when writing a client that is essentially unchanged from one application to the next. As before, I will not discuss the details of the boilerplate code in this lesson. Rather, I will discuss that code in a subsequent lesson.

Also as before, it is necessary to import class files resulting from the execution of idltojava and the compilation of source files generated by that program. It is also necessary to import packages from the CORBA libraries.

/*File Corba02Client.java
**********************************************************/
import junk.TheDateApp.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;

Most of the code in this client is contained inside the main() method. I have omitted code that changes little from one application to the next and replaced it with comments.

 
public class Corba02Client{
  public static void main(String args[]){
    try{
      //Create and initialize the ORB for the client
 
      //Do everything necessary to get a reference to the
      // servant object with the name theDateRef
 
      //Use theDateRef to invoke the method on the 
      // remote object
      String theDate = theDateRef.getTheDate();
      //Display the value returned by the method
      System.out.println(theDate);

      //Delay program termination so that the console
      // won't disappear from the screen when running
      // under control of a batch file.
      
    }catch (Exception e) {//Exception handler goes here
    }//End catch block
  }//end main() method
}//end Corba02Client class

As before, once I eliminated the boilerplate code that repeats from one application to the next, there wasn't very much to the code for this client object. Of course, a great deal more functionality could be programmed into this client, since all this client does is to invoke the method on the remote object and display the String object that is returned.

Again, however, the boilerplate code can almost be implemented on a "cut and paste" basis, and once you know the scheme, you could write a lot of CORBA applications without even understanding the boilerplate code.

Summary

Here are the steps for writing a CORBA application using Java under JDK 1.2 that runs as separate processes on the same platform using the name service. It is also possible to build a system that doesn't use a name service. I will discuss that possibility in a subsequent lesson.

Program Listings

Complete listings for the IDL file, the batch file and the source code files that you must create are provided in this section. Listings are not provided for the Java source code files that are automatically generated by the idltojava program.

/*File Corba02.idl
**********************************************************/
module TheDateApp{
  interface TheDate{
    string getTheDate();
  };//end interface TheDate
};//end module TheDateApp

.

rem File Corba02.bat
rem See Corba02Server.java for description of program

echo off

echo Convert the idl file to the required set of java files
idltojava -fno-cpp -p junk Corba02.idl

echo Compile all of the java files
javac Corba02*.java junk/TheDateApp/*.java

echo Start the transient name server on port 1050 as
echo  a new process
start tnameserv -ORBInitialPort 1050

echo Start the server as a new process
start java Corba02Server -ORBInitialPort 1050

echo Start the client as a new process
start java Corba02Client -ORBInitialPort 1050

.

/*File Corba02Server.java
This is a simple CORBA server that provides a servent
object to return the date and time as a string.
**********************************************************/
import junk.TheDateApp.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import java.util.Date;
 
class TheDateServant extends _TheDateImplBase{
  public String getTheDate(){
    return new Date() + "\n";
  }//end getTheDate()
}//end TheDateServent class
//=======================================================//
 
public class Corba02Server   {
 
  public static void main(String args[]){
    try{
      // create and initialize the ORB
      ORB orb = ORB.init(args, null);
 
      // create servant and register it with the ORB
      TheDateServant theDateRef = new TheDateServant();
      orb.connect(theDateRef);
 
      // get the root naming context
      org.omg.CORBA.Object objRef = 
             orb.resolve_initial_references("NameService");
      NamingContext ncRef 
                      = NamingContextHelper.narrow(objRef);
 
      // bind the Object Reference in Naming
      NameComponent nc = new NameComponent("TheDate", "");
      NameComponent path[] = {nc};
      ncRef.rebind(path, theDateRef);

      System.out.println("Server is running");
 
      // wait for invocations from clients
      java.lang.Object sync = new java.lang.Object();
      synchronized (sync) {
        sync.wait();
      }//end synchronized block
 
    }catch (Exception e) {
       System.err.println("ERROR: " + e);
       e.printStackTrace(System.out);
    }//end catch block
  }//end main()
}//end Corba02Server class

.

/*File Corba02Client.java
See Corba02Server.java for information on this program.
**********************************************************/
import junk.TheDateApp.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
 
public class Corba02Client{
  public static void main(String args[]){
    try{
      // create and initialize the ORB
      ORB orb = ORB.init(args, null);
 
      // get the root naming context
      org.omg.CORBA.Object objRef = 
             orb.resolve_initial_references("NameService");
      NamingContext ncRef = 
                        NamingContextHelper.narrow(objRef);

      // resolve the Object Reference in Naming
      NameComponent nc = new NameComponent("TheDate", "");
      NameComponent path[] = {nc};
      TheDate theDateRef = 
                   TheDateHelper.narrow(ncRef.resolve(path));
 
      // call the TheDate server object and print results
      String theDate = theDateRef.getTheDate();
      System.out.println(theDate);
      
      
      //Delay program termination so that the console
      // won't disappear from the screen when running
      // under control of a batch file.
      int ch1 = '0';
      System.out.println("Press Ctrl-z to terminate");
      while( (ch1 = System.in.read() ) != -1);      
    }catch (Exception e) {
      System.out.println("ERROR : " + e) ;
      e.printStackTrace(System.out);
    }//end catch block
  }//end main() method
}//end Corba02Client class

-end-