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

CORBA, Java IDL, Under the Hood

Java Programming, Lecture Notes 624, Revised 08/22/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 25, 1998. The sample program was tested using the JDK 1.2beta4 download package. The purpose of this lesson is to illustrate the inner workings of JavaSoft's Java IDL with CORBA using a very simple example program.

Introduction

Before embarking on this lesson, you need to study and understand the lesson entitled CORBA, Introduction to Common Object Request Broker Architecture. This lesson builds directly upon that lesson, and unless you understand the material in that lesson, you probably won't understand what is going on here.

As you learned in the earlier lesson, as of October 1998, Java JDK 1.2beta4 supports CORBA with some limitations. CORBA 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. Client software written in any of the available languages can invoke methods on server objects (servants) written in any of the available languages.

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 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.

Overview

This lesson contains a minimal CORBA application written in Java. It is essentially the same application that was discussed in the earlier lesson mentioned above with a couple of minor modifications. This 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.

Because the entire process can be tedious, 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

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 machine.  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 machine to get the date and time. (Comments are included which explain how to put the client and the server on different machines.) The application requires three separate source files and two utility programs to compile and execute.  The source files are:

The two utility programs are:

I prefer 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 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 which contains another folder named TheDateApp which is the actual package name.

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. This was discussed in some detail in the earlier lesson that made use of the IDL file named Corba02.idl.

Except for the name (Corba03.idl), the IDL file for this application is identical to the one for the previous application. A complete copy of the IDL file is shown near the end of this lesson, so I won't discuss it any further at this point..

The Batch file

The batch file for this application is named Corba03.bat. It contains two changes relative to the batch file used for the previous program named Corba02.bat. I will discuss only the changes since I explained the remainder of the file in the previous lesson.

The batch file for the application in the previous lesson contained the two statements shown below. These statements started the server and the client programs in their own processes. The command-line argument specified that the ORB object instantiated inside each of the programs should use port 1050 to communicate with the name service.

start java Corba02Server -ORBInitialPort 1050
start java Corba02Client -ORBInitialPort 1050

Information regarding the port (and other configuration information as well) can be specified either on the command line when the program is started (as shown above), or can be specified by the code inside the program. In the revised version of the application used for this lesson, that information is specified by code inside the client and server programs. Therefore, the batch file was modified to that shown below where the port specification was removed from two of the statements. (Note that some cosmetic statements were also omitted from this listing. A complete listing of the batch file can be viewed near the end of this lesson.)

rem File Corba03.bat
idltojava -fno-cpp -p junk Corba03.idl
javac Corba03*.java junk/TheDateApp/*.java
start tnameserv -ORBInitialPort 1050

start java Corba03Server
start java Corba03Client

I will have a lot more to say about this in the discussion of the client and server programs. For now, simply note that there is no port specification when the server and the client programs are started by the statements in the batch file shown above.

The Server File

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

Of necessity, the code for a CORBA server or a CORBA client includes quite a lot of code that is very similar from one application to the next. This is the code that is necessary to get everything initialized so that all the pieces work together in a cooperative manner. In the previous lesson, I ignored that code, which I referred to as boilerplate code, and discussed only the code that usually differs from one application to the next.

The purpose of this lesson is to go back and discuss the boilerplate code in detail and to explain how it works. In this lesson, I won't discuss much of the code that I discussed in the previous lesson.

The name of the server program is Corba03Server.java. I will discuss this program in fragments. You can view a complete listing of the server program near the end of this lesson. Again, in order to understand what is going on, you will need to understand the material in the previous lesson.

Every client and every server working in a CORBA environment must have an object of type ORB to handle communications with the other objects. In the version of the server program in the previous lesson, the ORB object was created by the following single statement..

       ORB orb = ORB.init(args, null); 

This invocation of the static init() method of the ORB class created an object of type ORB that relies on the command-line arguments for configuration of the ORB object. It was intended by the designers of the class that the first parameter be the array of String references created by the JVM for the command-line arguments. (It is also possible to configure the object by passing a Properties object as the second parameter which I will discuss below.)

For our purposes in this discussion, there are two interesting possibilities for configuration as shown in the following box.

  • org.omg.CORBA.ORBInitialPort - The port the initial name service listens to. The default value is 900.
  • org.omg.CORBA.ORBInitialHost - The host name of a machine running a server or daemon that provides initial bootstrap services, such as a name service. The default value for this property is localhost for applications.

Recall from the earlier discussion about the batch file that the ORBInitialPort was specified in the previous version of the program to be 1050 by the command-line parameters in the batch file. The ORBInitialHost was not specified, causing the system to default to localhost for the location of the name service.

That approach was perfectly satisfactory for the previous version of the program which was intended to run on a single computer. However, it didn't provide any illumination as to how you might go about running the client on one computer and the server on a different computer.

Even though I also wrote and tested this version of the program on a single computer, I decided to explicitly specify the port and the computer on which the name service is running in order to provide such illumination. I also provided comments to indicate how you should be able to modify the program to cause it to run on more than one computer in a network. That was the reason for leaving the port specification off of the two statements in the batch file as discussed earlier.

I began the explicit specification of the computer that the name service is running on and the port that it is listening on in the following fragment. This statement instantiates a Properties object that I will populate and pass as the second parameter to the static init() method of the ORB class to create the ORB object.

      Properties props = new Properties();

When the program is written in this manner, the programmer must know the IP address of the computer that the name service will be running on, and the port that it will be listening on when the program is compiled. (The command-line argument approach makes it possible to delay those decisions until runtime.)

The following statement was used to populate the property to indicate that the name service will be listening on port 1050.

      props.put("org.omg.CORBA.ORBInitialPort", "1050"); 

The following statement was used to populate the property to indicate that the name service will be running on the same computer.

      props.put("org.omg.CORBA.ORBInitialHost", "localhost"); 

If the name service will not be running on the same computer, you will need to specify the IP address of the computer where the name service will be running as in the following statement. In this statement, the IP address of the computer where the name service will be running is provided as a string to the second argument of the put() method, causing it to be used to populate the Properties object.

//props.put("org.omg.CORBA.ORBInitialHost", "123.213.3.159");

Actually, you can use this formulation and still test your program on a single computer by providing the IP address of that computer as the second argument to put(). In case you don't already know the IP address of the computer, it can be obtained using Java network programming methods as discussed in the lessons on networking programming. Be aware, however, that if you use a commercial dial-up ISP like I do, the IP address will change every time to dial in and log on.

Having instantiated and populated the Properties object, the following statement passes that object as the second parameter to the init() method. This causes the ORB object to later look for the name service on the port and computer specified by the Properties object (provided that the args array doesn't contain that configuration information).

      ORB orb = ORB.init(args, props);

Therefore, even for this simple application, if you happen to have three computers on an IP network, you could test the application with the name service running on one computer, the server running on a second computer, and the client running on a third computer.

The rules governing how the arguments are used to configure the ORB follow:

For applications, the arguments for the init() method are as described below (applets are treated slightly differently):

  • args - Provides the ORB access to the application's arguments or applet's parameters.
  • props - A java.util.Properties object.

The init() method uses these parameters, as well as the system properties, to obtain information it needs to configure the ORB. It searches for ORB configuration properties in the following places and order:

  1. The application parameters (first argument)
  2. A java.util.Properties object (second argument), if one has been supplied
  3. The java.util.Properties object returned by System.getProperties()

The first value found for a particular property is the value the init() method uses. If a configuration property cannot be found in any of these places, the init() method assumes an implementation-specific value for it.

Even though the first argument is intended to pass the application command-line parameters along to the init() method, it is simply an array of references to String objects. It would probably be considered bad programming style to do so, but the configuration information could also be created and passed to the init() method using code such as the following:

      String[] abc = {"-ORBInitialPort","1050",
                      "-ORBInitialHost","localhost"};
      ORB orb = ORB.init(abc, null);  

Once it is called and passed a parameter of type String[] as its first parameter, the init() method has no way of knowing whether that parameter is truly a reference to the array produced by the JVM from the command-line arguments or is a reference to an array produced by program code.

Therefore, there are at least three ways to cause the ORB object to be configured the way you want it to be configured:

Note that either of the first two methods will take precedence over the third method.

An understanding of the above information is probably the most important aspect of this lesson. While the remaining details in this lesson are largely academic, the above information is not academic. It is not likely that you will be writing very many CORBA programs that operate solely within a single machine, so you need to know how to configure the ORB objects when more than one machine is involved.

Having disposed of that matter, I will now discuss the remainder of the code that I ignored in the previous lesson.

In order to be of much use to clients, the server needs to instantiate one or more servant objects and make them available to the clients. That process begins in the next fragment where a servant object is instantiated and passed to the connect() method of the ORB object..

      TheDateServant theDateRef = new TheDateServant();
      orb.connect(theDateRef);

The connect() method can be described as follows:

The connect() method connects the servant object to the ORB so that the ORB can recognize invocations on it and pass them along to the correct servant.

The servant object must be an instance of the server implementation class created by invoking idltojava on the IDL file.

The servant class must extend the ImplBase class corresponding to the interface that is supported by the server. The servant must thus be a CORBA object reference, and inherit from org.omg.CORBA.Object.

Servants created by the user can start receiving remote invocations after the connect() method has been called.

There are several ways to make it possible for a client ORB object to locate the servant object. This lesson uses the name service provided with JDK 1.2. Subsequent lessons will discuss alternative approaches.

Using the name service requires first that the server program locate the name service program. Note that the name service program must already be running. Earlier sections discussed issues involving the port number and the identification of the computer that the name service is running on.

The server needs an object reference to the name service so that it can register itself and ensure that invocations on the interface are routed to its servant object. The reference is obtained by invoking the resolve_initial_references() method on the ORB object as shown in the following fragment.

      org.omg.CORBA.Object objRef = 
             orb.resolve_initial_references("NameService");

CORBA defines services other than the name service, and this method is used to obtain a reference to those other services as well. The string "NameService" is defined for all CORBA ORBs. When you pass in that string, the ORB returns a naming context object that is an object reference for the name service.

As a Java programmer, you should be very familiar with the concept of referring to objects by the generic type Object and later having to downcast them to their true type. For example, when you store and then retrieve objects from a Java Vector container object, they are retrieved as type Object and usually must be downcast to their true type to be useful.

A similar situation exists with CORBA. The object reference obtained by the above code is a generic CORBA object reference and must be downcast before it can be used. However, in CORBA lingo, the process is known as narrowing rather than downcasting. The following statement narrows the generic object reference to one that can be used for its intended purpose.

      NamingContext ncRef 
                      = NamingContextHelper.narrow(objRef);

This is an invocation of the static narrow() method of the NamingContextHelper class passing the generic CORBA object reference as a parameter. It returns an object of the NamingContext class that can be used to access the name service and register the server

There are several steps required to publish or register the servant object via the name service in order to make it available to clients. Those steps involve three statements, the first of which is shown in the following fragment..

      NameComponent nc = new NameComponent("TheDate", "");

First, it is necessary obtain an object of type NameComponent. The statement in the above fragment obtains such an object and assigns it to the reference variable named nc. This statement sets the id field of nc to "TheDate" and the kind field to an empty string. This process is explained in more detail below.

A name is an array of one or more NameComponent objects. A name with a single NameComponent is called a simple name; a name with multiple NameComponent objects is called a compound name.

A NameComponent object consists of two fields:

  • id - a String used as an identifier
  • kind - a String that can be used for any descriptive purpose.

In a name, each NameComponent object except the last denotes a NamingContext object. The last NameComponent object denotes the bound object reference. This is similar to a path name, in which the last name is the file name, and all names before it are directory names.

Two different methods of the NamingContext class can be used to bind the servant object to a name in the name service: bind() and rebind(). The primary difference between the two is that the second method eliminates any previous binding regarding the servant object and the name and then establishes a new binding.

Both methods require two parameters. The first parameter is a reference to an array of NameComponent objects, describing a path, as explained in the box above. The second parameter is a reference to the servant object. The two statements that complete the process of publishing the servant object and making it available to clients are shown in the following fragment.

      NameComponent path[] = {nc};
      ncRef.rebind(path, theDateRef);  

The first of these two statements creates and populates an array of NameComponent object references and assigns a reference to that array object to the reference variable path..

Because the path to the NameComponent containing the published name of the servant object is a single element, the array is created and populated with a single element that is the NameComponent object.

Then that array, along with a reference to the servant object is passed to the rebind() method to complete the process.

After this, when a client's ORB takes the necessary steps to obtain a CORBA reference to the servant object bound to the id known as TheDate, the resolve() method will be invoked on the NamingContext and a reference to the servant object will be returned by the name service. This reference can then be used by the client code to invoke methods on the servant object.

The following box shows the complete server program with the elements that are likely to change from one application to the next highlighted in boldface. Of course, if the server makes more than one servant object available, that will have to be taken into account and additional code will be required to accommodate the additional servant objects.

public class Corba03Server   {
 
  public static void main(String args[]){
    try{      
      Properties props = new Properties();
      props.put("org.omg.CORBA.ORBInitialPort", "1050");
      props.put("org.omg.CORBA.ORBInitialHost", "localhost");
      ORB orb = ORB.init(args, props);
 
      TheDateServant theDateRef = new TheDateServant();
      orb.connect(theDateRef);
 
      org.omg.CORBA.Object objRef = 
             orb.resolve_initial_references("NameService");
      NamingContext ncRef 
                      = NamingContextHelper.narrow(objRef);
 
      NameComponent nc = new NameComponent("TheDate", "");
      NameComponent path[] = {nc};
      ncRef.rebind(path, theDateRef);

      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 Corba03Server class  

The Client File

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

As is the case with the server code, quite a lot of boilerplate code is required when writing a client. This code is very similar from one application to the next. In the previous lesson, I ignored the boilerplate code. The purpose of this lesson is to go back and discuss that code.

As was the case with the server code above, I won't discuss those portions of the code that were discussed in the previous lesson.

The first fragment shows boilerplate code that is essentially the same as was discussed with regard to the server above and the same explanations apply. I have highlighted those portions that are likely to change from one application to the next.

      Properties props = new Properties();
      props.put("org.omg.CORBA.ORBInitialPort", "1050");
      props.put("org.omg.CORBA.ORBInitialHost", "localhost");
      ORB orb = ORB.init(args, props);
 
      org.omg.CORBA.Object objRef = 
             orb.resolve_initial_references("NameService");
      NamingContext ncRef = 
                        NamingContextHelper.narrow(objRef);

I will highlight one caution regarding the use of JDK 1.2beta4 in the following sidebar.

In place of the statement in the previous fragment which establishes localhost as the machine providing startup services such as the name service, the complete listing of the program contains the following comment:

      //If the name service is on a different computer,
      // use something like the following which specifies
      // the IP address of the computer with the name
      // service.
      props.put("org.omg.CORBA.ORBInitialHost", 
                                        "123.213.3.159");

I have demonstrated experimentally that this works very well using two different computers for server and client on an IP network. However, there is one caution.

Apparently the JDK 1.2beta4 version of the Java IDL requires the ORB in the client to use the name of the server as it appears in the internet Domain Name Service (not to be confused with the name service used in this program) instead of the IP address of the server, to connect the client code to the servant object.

Unless the server machine is commonly used as an internet server, it may not have been configured at installation to support this. In particular, a Win95 machine has a network name that is set by entering information in the network setup portion of Win95. There is no guarantee that the person who did the setup on the operating system was careful to make certain that this name was an exact match for the name in the internet Domain Name Service (DNS) that maps to the IP addess of the machine.

If the two names don't match, the JDK 1.2beta4 version of the JavaSoft Java IDL simply won't work when the client and the server are on different machines. Apparently the server generates the object reference containing the "local" name for the machine rather than the DNS name. Then the client asks the DNS for the IP address matching that name but no match is available. This results in a runtime error.

The only way that I have found to resolve this problem is to make certain that the two names match. In some cases this is not possible. For example, some machines receive a new DNS name and IP address every time they log onto the network. In this case, there is no way that I have found to cause the local name to match the DNS name.

In those cases where the DNS name of the machine is stable, the following short program can be used to discover the DNS name if you don't already know it. (You must be online to successfully run this program.) Then, assuming that you have the proper privileges, you can change the local name of the machine to make the two match.

import java.net.*;
import java.util.*;

class Url001{
  public static void main(String[] args){
    try{

      InetAddress address;
      int temp;
      
      System.out.println("Get IP address");
      address = InetAddress.getLocalHost();
      System.out.println(address);

      System.out.println("Do reverse lookup on IP address");
      temp = address.toString().indexOf('/');
      address = InetAddress.getByName(
                     address.toString().substring(temp+1));
      System.out.println(address);

    }catch(UnknownHostException e){
      System.out.println(e);
      System.out.println("Must be online to run properly.");
    }//end catch
  }//end main
}//end class Url001

The output from running this program on my machine on one particular occasion was as follows:

Get IP address
baldwin/129.37.119.74
Do reverse lookup on IP address
slip129-37-119-74.nc.us.ibm.net/129.37.119.74

In this case, the local name for the machine is baldwin. The DNS name for the machine is slip129-37-119-74.nc.us.ibm.net. The IP address for the machine is 129.37.119.74

The rumor in the newsgroups has it that JavaSoft will correct this problem in the final release of JDK 1.2 and cause the ORB in the client to optionally use the IP address of the server. Until this is done, in my opinion, the JavaSoft Java IDL is of very limited usefulness in the real world

Now back to the main thread of this lesson. When programming in this style, the client programmer must know the id value used by the server program to expose or publish a servant object in the name service. In this case, the value was the string "TheDate".

The next fragment shows the resolve() method being invoked on the NamingContext object named ncRef (produced above) to obtain a CORBA reference to the servant object.

Note that TheDate and TheDateHelper are classes that resulted from compiling source code that was generated when the idltojava program was applied to the IDL file.

      NameComponent nc = new NameComponent("TheDate", "");
      NameComponent path[] = {nc};
      TheDate theDateRef = 
                   TheDateHelper.narrow(ncRef.resolve(path));

The following fragment is not boilerplate code. Rather, it is the code that uses the reference to the servant object to invoke a method on that object. I show it here simply for completeness. Of course, the client programmer must also know the signatures for the available methods on the servant object.

      String theDate = theDateRef.getTheDate();
      System.out.println(theDate);  

Summary

The following summary information was provided in the earlier lesson. I am repeating it here for convenience. In the earlier lesson, I restricted the instructions to CORBA applications where the name service, the client, and the server were all running on the same machine. Now that I have showed you how to take different machines into account when instantiating the ORB objects, that restriction no longer applies.

Here are the steps for writing a CORBA application using Java under JDK 1.2 that uses name service. It is also possible to build a system that doesn't use the 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 Corba03.idl
See Corba03Server.java for information on this program.
**********************************************************/
module TheDateApp{
  interface TheDate{
    string getTheDate();
  };//end interface TheDate
};//end module TheDateApp

.

rem File Corba03.bat
rem See Corba03Server.java for description of program

echo off

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

echo Compile all of the java files
javac Corba03*.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. Computer and port
echo  are specified in the server initialization code.
start java Corba03Server

echo Start the client as a new process. Computer and port
echo  are specified in the client initialization code.
start java Corba03Client

.

/*File Corba03Server.java
This is a simple CORBA server that provides a servant
object to return the date and time as a string. This
version is identical to the Corba02 version except that
in this version, a property object is used to initialize
the port and the computer for the name service when
the ORB object is instantiated.  This initialization is
performed for the ORBs for both the client and the server.
**********************************************************/
import junk.TheDateApp.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import java.util.Date;
import java.util.Properties;
 
class TheDateServant extends _TheDateImplBase{
  public String getTheDate(){
    return new Date() + "\n";
  }//end getTheDate()
}//end TheDateservant class
//=======================================================//
 
public class Corba03Server   {
 
  public static void main(String args[]){
    try{      
      // create and initialize the ORB
      Properties props = new Properties();
      //Following assumes that name service is operating
      // on port 1050.
      props.put("org.omg.CORBA.ORBInitialPort", "1050");
      //Following assumes that name service is operating
      // on the same computer.
      props.put("org.omg.CORBA.ORBInitialHost", "localhost");
      //If the name service is on a different computer,
      // use something like the following which specifies
      // the IP address of the computer with the name
      // service.
      //props.put("org.omg.CORBA.ORBInitialHost", 
      //                                  "123.213.3.159");
      ORB orb = ORB.init(args, props);

 
      // 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 Corba03Server class

.

/*File Corba03Client.java
See Corba03Server.java for information on this program.
This version explicitly initializes the ORB for the port
and host computer of the name service.
**********************************************************/
import junk.TheDateApp.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import java.util.Properties;
 
public class Corba03Client{
  public static void main(String args[]){
    try{
      // create and initialize the ORB
      Properties props = new Properties();
      //Following assumes that name service is operating
      // on port 1050.
      props.put("org.omg.CORBA.ORBInitialPort", "1050");
      //Following assumes that name service is operating
      // on the same computer.
      props.put("org.omg.CORBA.ORBInitialHost", "localhost");
      //If the name service is on a different computer,
      // use something like the following which specifies
      // the IP address of the computer with the name
      // service.
      //props.put("org.omg.CORBA.ORBInitialHost", 
      //                                  "123.213.3.159");
      ORB orb = ORB.init(args, props);
 
      // 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 Corba03Client class

-end-