wiley-logo-sm.gif
> wiley.com

JAVA PROGRAMMING WITH CORBA, 3E

Sample: Chapter 4

Chapter 4
A First Java ORB Application 

In this chapter we will use two Hello World examples to introduce the principles of building distributed applications with Java ORBs. Those examples expand the Hello World example introduced in Chapter 3, "Overview of Java and Java ORBs." We will implement a client that is a Java application, a client that is a Java applet, and a server hosting an object implementation. Figure 4.1 illustrates the components of our examples.
figure4.1

Figure 4.1 Hello World application.

All code is available in electronic form from the companion web site for this book at www.wiley.com/compbooks/brose. The examples use only standard CORBA features so the ORB you choose to run this code on does not matter - as long as it complies to CORBA version 2.3. Various ORB products that conform to the CORBA specification differentiate themselves with implementation details that have an impact on performance and scalability. Most also have extensions to the CORBA core.

This chapter starts with a summary of the development process for CORBA applications in Java (section 4.1). We give detailed explanations of the development of a simple example application (sections 4.2 through 4.8) and then extend this to include more features (section 4.9). In Chapter 9, "Advanced Features," we will return to application development with a substantial example.

4.1 Summary of the CORBA Development Process

The examples presented in this chapter follow roughly the same steps:
  • Write some IDL that describes the interfaces to the object or objects that will be used or implemented.
  • Compile the IDL file. This produces the stub and skeleton code that provides location transparency. That is, it will cooperate with the ORB library to convert an object reference into a network connection to a remote server and then marshal the arguments we provide to an operation on the object reference, convey them to the correct method in the object denoted by our object reference, execute the method, and return the results.
  • Identify the IDL compiler-generated interfaces and classes that we need to use or specialize in order to invoke or implement operations.
  • Write code to initialize the ORB and inform it of any CORBA objects that we have created.
  • Compile all the generated code and our application code with a Java compiler.
  • Run the distributed application.
Figure 4.2 shows the use of IDL and the IDL compiler when building the application. 
figure4.2

Figure 4.2 Building the Hello World application.

When you execute the IDL compiler for the Java ORB you have installed, it will generate two sets of Java code files: stub code to create proxy objects that a client can use for making invocations on object references of the interface types defined in the IDL file, and skeleton code for access to objects that support those interfaces.

4.2 Environment Setup

Before we can start with the examples we have to set up a working environment. We implemented the examples with Visibroker for Java 4.1, and Sun Microsystems' Java Development Kit (JDK) version 1.2. Because our example code relies on only standardized interfaces and does not use any proprietary ORB extensions it will run unchanged on any CORBA 2.3 compliant Java ORB. Code portability was verified by also running all code on JacORB 1.2. For setups in different environments, the reader is referred to the installation manuals for the particular products and platforms.

We use JDK 1.2, assuming that the path is set appropriately and that the Java compiler javac and that the Java run-time system java isare  installed. We also use Inprise Corp.'s  Visibroker for Java version 4.10, assuming that the path and classpath are set appropriately. Visibroker’s IDL compiler is called idl2java. Note that we need to overcome applet sandbox and firewall restrictions unless the server is running on the Wweb server from which the applet is downloaded from. To do this, we run the gatekeeper, Visibroker’s IIOP gateway, and HTTP tunneling mechanisms:

prompt> gatekeeper    &
Many Java ORBs provide a similar IIOP gateway as part of their applet support. OrbixWeb’s, for example, is called Wonderwall. In JacORB, it would be started as appligator. The interface between the ORB and this gateway is not standardized, so using a different ORB with applets also requires using this ORB's IIOP gateway mechanism. The code itself remains unchanged, however.

4.3 Interface Specification

Our first example provides the same functionality as the one introduced in Chapter 3. A client invokes an operation hello() on the interface of a potentially remote object of type GoodDay. The result of the invocation is a message that is printed by the client.

For any CORBA application we must write an IDL specification that defines data types and interfaces, including attributes and operations. For our example, we defined an IDL interface called HelloWorld which resembles the Java interface of the Hello World example from Chapter 3. We place the IDL file HelloWorld.idl, containing this definition, in a directory which represents its location in the book: com/wiley/compbooks/brose/chapter4/simple.

//HelloWorld.idl 
module com   {
module wiley { 
module compbooks { 
module brose {
module chapter4 { 
module simple { 
   module helloWorld { 
      interface  GoodDay  { 
      string  hello(); 
   };
};};};};};};}; 
 
 

The file contains the specification of a hierarchy of modules. It is good specification style to use modules to create a separate name space for an application or its major components, and to follow the same naming conventions that have been introduced for Java packages. To align with Java coding conventions, we recommend using module names that begin with lower case letters and interface names beginning with capital letters.

Within the module helloWorld we define one interface: GoodDay. The interface is not in any inheritance relationship. It provides one operation hello(). This operation does not have any parameters and returns a result of type string.

As we will see in the implementation, the object returns a string describing its locality as part of the result of the operation, hello(). The operation returns a message saying: "Hello World, from location."

4.4 Compiling the IDL

The next step in the application development is to compile the IDL to generate the stub and skeleton code. The compile command in Visibroker for Java is
prompt> idl2java -strict -root_dir generated HelloWorld.idl

The IDL compiler maps each module to a Java package and uses Java conventions for putting packages in directories. Both directory and package are named after the IDL module. The Java package contains Java interfaces and classes implementing stub, skeleton, and other code to support your distributed application. To distinguish between generated code and handwritten code we direct the compiler to place its output in a different directory tree by supplying it with the name of root directory for the generated code. This directory is called generated. The -strict switch tells the compiler that it must not include any proprietary extensions in the generated code but abide by the letter of the specification, in particular the Java ORB Portability Interfaces, which we explain in Chapter 5, "OMG IDL to Java Mapping." These interfaces ensure the portability of code from one ORB to another.

While the names of compiler switches depend on which vendor's compiler is used, the files generated by any compliant IDL compiler are always the same. These are:

GoodDay.java       GoodDayHolder.java GoodDayHelper.java
GoodDayStub.java   GoodDayPOA.java    GoodDayOperations.java
GoodDayPOATie.java

The IDL interface GoodDay is mapped to a Java interface of the same name in the file GoodDay.java. The class GoodDayHolder provides support to handle IDL inout and out parameters, as you will see toward the end of this chapter. The class GoodDayHelper contains miscellaneous static methods, most importantly the narrow() method. In Chapter 5 we explain the complete mapping from OMG IDL to Java and also the meaning of the generated Java classes and interfaces.

The remaining files that are generated by the IDL compiler contain classes that have general functionality. The class _GoodDayStub contains the stub code that allows us to create a client-side proxy for the object implementation. The class GoodDayPOA contains the skeleton code that is used with the POA. The interface GoodDayOperations and the class GoodDayPOATie are used for the Tie mechanism on the server side. This is explained in Chapter 5 and demonstrated by an example in Chapter 9.

4.5 A Client as a Java Application

When implementing a client as a Java application, we don’t have to worry about the restrictions that exist for applets, and so we can explain CORBA programming in its usual form. A client implementation follows these steps:
  • Initialize the CORBA environment; that is, obtain a reference to the ORB.
  • Obtain an object reference for the object on which to invoke operations.
  • Invoke operations and process the results.
4.5.1 Generated Java Interface
The Java interface which corresponds to the interface defined in IDL is an empty interface. It extends two base classes for CORBA Objects and IDL entities and the Java interface GoodDayOperations, which contains the actual operation signatures
// generated Java - GoodDay.java
package com.wiley.compbooks.brose.chapter4.simple.helloWorld;

public interface GoodDay extends GoodDayOperations,
org.omg.CORBA.Object,
org.omg.CORBA.portable.IDLEntity
{
}

The GoodDayOperations interface defines a Java method hello() which returns a Java string. The reason for this division of labour between GoodDay and GoodDayOperations is that in some cases it is necessary to use an operations interface that does not extend org.omg.CORBA.Object. This will be explained in more detail in Chapter 6, "ORB Run-Time System."
// generated Java - GoodDayOperations.java
package com.wiley.compbooks.brose.chapter4.simple.helloWorld;

public interface GoodDayOperations {
    public java.lang.String hello();
}

4.5.2 Initializing the ORB
We define a Java class Client our implementation package and define the main() method for this class. Initializing an ORB means obtaining a reference to the ORB pseudo-object. The ORB is called a pseudo-object because its methods will be provided by a library in communication with the run-time system, and its pseudo-object reference cannot be passed as a parameter to CORBA interface operations. Excluding that restriction, however, a reference to an ORB looks like any other object reference.
package com.wiley.compbooks.brose.chapter4.simple.helloWorld;
import java.io.*;
import org.omg.CORBA.*;

public class Client {
    public static void main(String args[]) {
        try {
            // initialize the ORB
            ORB orb = ORB.init (args, null);

After we have declared the package to which our client class belongs, imported the appropriate classes, and declared the class and the main method, we initialize the ORB. The static method init() on the class org.omg.CORBA.ORB returns an instance of an ORB.
4.5.3 Obtaining an Object Reference
References to objects can be obtained by various means, as explained in Chapter 7, "Discovering Services." Here we use a rather unsophisticated method. Object references are opaque data structures; however, an object reference can be converted into a string (as we show when explaining the server). This is known as stringifying an object reference. The resulting string is called a stringified object reference. Stringified object references are reconvertible into "live" object references. This is done using the two corresponding operations, object_to_string() and string_to_object() defined on the CORBA::ORB interface. Stringified interoperable object references can be converted into working object references by any CORBA-compliant ORB.
        // get object reference from command-line     argument
        org.omg.CORBA.Object obj =
            orb.string_to_object( args[0] );

For this example client we assume that a stringified object reference is provided as the first argument to the client program. It is then provided as the argument to the method string_to_object(), which is invoked on the ORB pseudo-object. The method returns an object reference of type CORBA::Object, the base type of all CORBA objects, which is mapped to the interface org.omg.CORBA.Object. You have to use the fully qualified name to avoid confusion with java.lang.Object. To make use of the object it needs to be narrowed to the appropriate type. Narrowing is equivalent to down-casting in some object-oriented programming languages. The narrow operation is type safe because it returns a null object reference if the object reference passed to it is not of a correct type. If it successfully returns a non-null reference then we can be sure that the reference is valid and of the correct type. It can also raise the exception CORBA::BAD_PARAM.

The narrow method is defined in the class GoodDayHelper.

        GoodDay goodDay = GoodDayHelper.narrow( obj );
        if( goodDay == null ) {
           System.err.println(
                "stringified object reference is of wrong type");
           System.exit( -1 );
        }

Note that you should always use a narrow() operation when you have to down-cast a CORBA object and never the Java casting mechanism.
4.5.4 Invoking the Operation
Once the ORB is initialized and an object reference is obtained, CORBA programming looks very much like standard object-oriented programming. Invoking methods on objects looks exactly the same for remote and local objects.
            System.out.println( goodDay.hello() );

Our simple client invokes the method hello() on the object goodDay, and the result is printed to standard output.

The last thing to consider is handling exceptions that might occur. Because there are no user exceptions raised by the hello() operation, we only have to catch and process CORBA system exceptions, which can be thrown by any CORBA-related method including the initialization of the ORB, the narrow call, and the hello() method.

        }
        catch(SystemException ex) {
            System.err.println(ex);
        }
    }
}

Note that the SystemException class is defined in the package org.omg.CORBA.
4.5.5 Compiling and Executing the Client
To make the client program executable by a Java virtual machine it needs to be compiled. This is done by calling the Java compiler.
prompt> javac Client.java

We execute the client by calling the Java run-time system with two arguments: the name of the client class and a stringified object reference. You will see how to generate this string when we consider the server implementation.
prompt> java com.wiley.compbooks.brose.chapter4.helloWorld.Client
IOR:000000000000002149444c3a53696d706c6548656c6c6f576f726c642f476f6f
644461793a312e300000000000000001000000000000004c000100000000000e3133
302e3130322e3137362e3900fc7d0000003000504d43000000010000001a53696d70
6c6548656c6c6f576f726c643a3a476f6f6444617900000000000002febddb22

The client then prints the expected message.
Hello World, from Brisbane

4.6 A Client as an Applet

When writing a client as an applet you have to follow the same steps as for the application client. You also have to make the following additions and alterations:
  • Anchor the applet in an HTML page to make it addressable and loadable.
  • Provide a GUI to enable interaction through a Web browser.
  • Extend the Java applet class and override some of its methods.
  • Use a different ORB initialization.
4.6.1 Anchoring the Applet into HTML
To make an applet accessible over the Web it needs to be anchored in an HTML page. When a browser downloads such a document, the Java byte code representing the anchored applet will also be received and executed by the Java Virtual Machine in the browser. Here is an example HTML file:
<html>
<header>
<title>
Hello World Example
</title>
<body>
<center><h1>
Hello World Example
</h1></center>
<center>
<applet code=com/wiley/compbooks/brose/chapter4/simple/helloWorld/Applet.class
width=400 height=80>
</applet>
</center>
</body></html>

For our simple applet we have an HTML file HelloWorldApplet.html that contains only a header and a reference to our applet class com.wiley.compbooks.brose.chapter4.helloWorld.Applet. There may be a need for parameter tags in the applet tag. These are very ORB and browser dependent, and you should look up details in the relevant reference manuals.
4.6.2 Initializing the Applet
We define our applet as a class Applet that extends the Java applet class java.applet.Applet. Within the class we declare a number of private variables:
  • goodDay - to hold the object reference of the remote object
  • helloWorldButton - a button to enable users to invoke the method
  • textField - a text field to display the result of the method.
Then we override the method init() inherited from the applet base class. First, we initialize the GUI components, that is, we create a Button and a TextField object and set some properties of these objects. Then we define the layout of the user interface using the Java layout manager GridLayout and add the two GUI components to the layout. We also register the applet as an event listener at our Hello World button according to the Java event model and set the action command to "invoke."
package com.wiley.compbooks.brose.chapter4.simple.helloWorld;

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import org.omg.CORBA.*;

public class Applet
    extends java.applet.Applet
    implements ActionListener {

    private ORB orb;
    private GoodDay goodDay;
    private Button helloWorldButton;
    private TextField textField;

    public void init() {
        helloWorldButton = new Button("Invoke remote method");
        helloWorldButton.setFont( new Font( "Helvetica",
            Font.BOLD, 20));
        helloWorldButton.setActionCommand( "invoke" );
        helloWorldButton.addActionListener( (ActionListener) this );
        textField = new TextField();
        textField.setEditable( false );
        textField.setFont( new Font( "Helvetica", Font.BOLD, 14));
        setLayout( new GridLayout( 2,1 ));
        add( helloWorldButton );
        add( textField );

4.6.3  Locating Objects
In the next step we locate an object implementation. In the application client we did this using a stringified object reference. Because stringified IORs are rather inconvenient to use in applet parameters, we use the following convention to access initial IORs. We expect that a file containing the target IOR is supplied in the same directory where the HTML page containing the applet was found on the Web server. Details on how to locate an object more flexibly are provided in Chapter 7.

To initialize the ORB we again call the method init(), this time with the applet object itself as the first argument (using the Java keyword this to do so). This initialization changes the behavior of the stub. As part of its bootstrap code the stub will establish a connection to an instance of the IIOP gateway, which it expects to be running on the machine from which the applet has been downloaded. Details of the problems related to IIOP gateways and their solutions are discussed in Chapter 12, "Security." If your ORB does not provide an IIOP gateway, you must make sure that the server that hosts the remote object is running on the machine from which the applet was downloaded; otherwise, it won&rsquo;t be reachable from within the applet.

To obtain a reference to the remote object we use the following method readIOR(). This method constructs a URL for the location where the IOR file is expected. It then opens a connection to this resource and reads a line of text that is assumed to contain the stringified object reference. Because applets are allowed to connect to their Web server this operation will succeed if the IOR has been properly provided.

    private String  readIOR() {
        try {
            URL iorURL = new URL( getCodeBase().toString()+"ior" );
            BufferedReader in = new BufferedReader(
                new InputStreamReader( iorURL.openStream() ) );
            String line = in.readLine();
            in.close();
            return line;
        }
        catch(  Exception ex  ) {
            System.err.println( ex );
        }
        return  null;
    }

Applet initialization is finished with the catching and processing of exceptions.
        try  {
            // initialize  the ORB (using  this applet)
            orb  = ORB.init( this, null );
            org.omg.CORBA.Object obj = orb.string_to_object(
                readIOR());
            goodDay = GoodDayHelper.narrow( obj );
        }
        catch(  SystemException ex )  {
            System.err.println( "ORB is not initialized" );
            System.err.println( ex );
        }
    }

4.6.4 Handling Applet Events
To handle events from the graphical user interface, in our case from the Hello World button, we implement the method actionPerformed() of the interface java.applet.awt.event.ActionListener. This method handles GUI events of type ActionEvent. In this case we have to deal with only one event, which is fired when the Hello World button is pressed. This event is associated with the command "invoke."
    public  void actionPerformed( ActionEvent e ) {
        if( e.getActionCommand().equals("invoke") ) {
            // invoke   the    operation
            try {
                textField.setText( goodDay.hello() );
            }
            // catch CORBA   system exceptions
            catch( SystemException ex) {
                System.err.println(ex);
            }
        }
    }

We check if the action command of the event was "invoke." If not, we do nothing. Otherwise we invoke the method hello() on the object goodDay. We display the result of the invocation in the text field. Again we watch for possible CORBA system exceptions and print them if they occur.
4.6.5 Compiling and Executing the Applet
To make the applet executable it needs to be compiled. This is done by calling the Java compiler.
prompt> javac Applet.java

To execute the applet we have to point a Java-enabled Web browser to the URL of the HTML document that anchors our applet. Figure 4.3 shows the initial state of the applet&rsquo;s execution in the browser.
figure4.3

Figure 4.3 Hello World applet - initial state.

Once the button has been clicked, the result of the operation invocation is displayed in the text field as shown in Figure 4.4.
figure4.4

Figure 4.4 Hello World applet - invoked method.

4.7 An Object Implementation

Now we turn to the implementation of the object whose interface has been specified in IDL. This implementation is also known as the servant class. The IDL/Java mapping specification defines a servant base class that is named after the IDL interface: InterfaceNamePOA. This base class is a skeleton generated by the IDL compiler. There are alternatives to this implementation style. The two main ways of associating object implementation classes with a skeleton class are by inheritance or delegation.

The inheritance approach involves a Java implementation class extending the servant base class. The servant base class is an abstract implementation of the Java interface that corresponds to the IDL interface. The object implementation is an extension of the base class and implements the methods. The delegation approach is also known as the Tie method. This is done by providing the skeleton with a reference to an implementation object. This is explained in detail in Chapter 9.

In our example we have an implementation class GoodDayImpl that extends the servant base class GoodDayPOA. As in the implementation of the GoodDayImpl class shown in Chapter 3, we declare a private variable, location, that will hold a string identifying the location of the service. Here we mean the geographical location, as shown in the previous client examples.

We also have to implement the constructor of the class. The constructor has one parameter which it assigns to the private variable location.

package com.wiley.compbooks.brose.chapter4.simple.helloWorld;

import org.omg.CORBA.*;

public class GoodDayImpl extends GoodDayPOA {

    private String location;

    // constructor
    GoodDayImpl( String location  ) {
        // initialize location
        this.location = location;
    }

    //  method
    public String hello()  {
        return "Hello  World, from "  + location;
    }
}

We implement the method hello(), which returns a string composed of the message "Hello World, from" and the value of the variable location.
Again we have to compile the Java source into byte code:
prompt> javac GoodDayImpl.java

4.8 A Server

Now we have to implement a server class. This class initializes the environment, creates the implementation object, makes it available to clients, and listens for events. The server class for our example is called Server. We only implement the main() method in this class. We check for the right number of arguments, one of which indicates the location of the server. A server is responsible for initializing the ORB, creating the object, and making the object accessible.

We initialize the ORB in the same way we did on the client side by calling ORB.init(), which returns a reference to the ORB pseudo-object. We then create an instance of the servant class goodDayImpl by calling Java&rsquo;s new operator and supply one argument to the constructor that we copy from the command-line argument.

package com.wiley.compbooks.brose.chapter4.simple.helloWorld;

import java.io.*;
import org.omg.CORBA.*;
import org.omg.PortableServer.*;

public class Server  {
    public static void main(String[] args) {
        if( args.length != 1 ) {
            System.out.println(
               "Usage: java com.wiley.compbooks.brose.chapter4.
                simple.helloWorld <location>");
            System.exit( 1 );
        }
        try  {
            //init ORB
            ORB orb  = ORB.init( args, null );
            // create a GoodDay  object
           GoodDayImpl  goodDayImpl = new GoodDayImpl( args[0] );

At this stage we have only a Java object. To make it incarnate a CORBA object we must enable the object to act as a servant and to receive CORBA operation invocations. This is done via an object adapter. To create a CORBA object reference that we can later export, we first need to obtain a reference to an instance of a POA and initialize it. We do not need any advanced object adapter features here, so it is sufficient to use the ORB's root POA, which can be obtained by calling resolve_initial_references("RootPOA") on the ORB. After narrowing the result to type POA we need to activate the object adapter because, as explained in Chapter 2, "CORBA Overview," object adapters are initially in a holding state and do not process incoming requests.
            //init POA
            POA poa  = POAHelper.narrow(
            orb.resolve_initial_references("RootPOA"));
            poa.the_POAManager().activate();

Now that we have set up the POA we can create an object reference from our goodDayImpl servant. Note that the servant incarnates a transient CORBA object. The object reference of a transient object is valid only for the lifetime of a particular instance of its POA. We explain and compare transient and persistent object references in detail in Chapter 5. Creating an object reference from a servant object is done by calling servant_to_reference() on the POA, supplying the servant object as an argument.
            // create   the  object reference
            org.omg.CORBA.Object obj =
                poa.servant_to_reference( goodDayImpl );
            // print stringified object reference
            System.out.println( orb.object_to_string( obj ) );
            // wait  for  requests
            orb.run();
        }
        catch(InvalidName e ) {
            System.err.println( e );
        }
        // POA  exceptions WrongPolicy  and ServantNotActive
        catch(UserException  e ) {
            System.err.println(e);
        }
        catch(SystemException  e) {
            System.err.println(e);
        }
    }
}

After creating the object reference, we print its stringified reference to the standard output. Note that we have implicitly activated the new CORBA object with the call to , so it is ready to receive requests now. Finally, we call run() on the ORB that blocks the server's main thread waiting for incoming requests.

Again we catch possible exceptions. Two more exceptions can occur here. The first of these is InvalidName, which can be thrown by resolve_initial_references() if an invalid string argument is supplied. The other kind of possible exceptions are two UserExceptions defined for the POA's servant_to_reference() method. We handle both of them by defining a catch clause for UserExceptions. The exact types of these exceptions are WrongPolicy and ServantNotActive, and they are both declared in the org.omg.PortableServer package.

4.8.1 Compiling and Starting the Server
We have to compile the Java source into byte code:
prompt> javac  Server.java
We now start the server:
prompt> java
com.wiley.compbooks.brose.chapter4.simple.helloWorld.Server Brisbane

This prints out a stringified IOR which looks like this:
IOR:000000000000002149444c3a53696d706c6548656c6c6f576f726c642f476f6f64
4461793a312e300000000000000001000000000000004c000100000000000e3133302e
3130322e3137362e3900fc7d0000003000504d43000000010000001a53696d706c6548
656c6c6f576f726c643a3a476f6f6444617900000000000002febddb22

It&rsquo;s probably a good idea to redirect standard output to a file. In our example we call this file shw.ior:
prompt> java com.wiley.compbooks.brose.chapter4.simple.helloWorld.Server
   Brisbane > shw.ior
Now we can really run our clients as we have shown earlier. A client can be conveniently started using the IOR file:
prompt> java
com.wiley.compbooks.brose.chapter4.simple.helloWorld.Client
    `cat shw.ior`

4.9 Extending the Hello World Example

In this section we will modify the simple Hello World example to introduce another feature. In this example the server will return not only a message but also the current time at the server&rsquo;s location. We will look at some new aspects of application development and revisit some of the issues discussed in the earlier version of this example application. Specifically we deal with the following:
  • Further aspects of the specification of interfaces
  • Parameter mapping and the semantics of parameter passing
  • The development of a client
  • Applet implementations
  • The implementation of an object

4.9.1 Interface Specification

We again specify an interface GoodDay with an operation hello(). The module is again called helloWorld. But to avoid name clashes with the previous example, all code will be developed in the package com.wiley.compbooks.brose.chapter4.extended.

The signature of the operation is different. Its result is still a string, but this time the operation has parameters, and it returns the description of the server&rsquo;s location. The parameters are tagged as out, meaning that their values will be supplied by the invoked object. They are both of type short, and their intended meaning is that they hold the current time at the server&rsquo;s location: hour holds the hour and minute the minute.

module com {
module wiley {
&hellip;
module extended {
module helloWorld {
    interface GoodDay {
        string hello(
            out short hour,
            out short minute );
        };
    };&hellip;};

4.9.2 Parameter Mapping
An out parameter in an IDL operation has pass-by-result semantics. This means that a value for this parameter will be supplied by the invoked object. The value will be available to the client after the invocation is completed.

The parameters in Java operations have pass-by-value semantics, meaning that a value is passed from the caller to the invoked object. There is a mismatch in the semantics of parameter passing between IDL and Java for IDL&rsquo;s out and inout parameters. The solution is provided by Holder objects. Instead of passing an argument itself, an object is used as an argument to the Java method. The Holder object contains a variable value of the type of the IDL parameter. This way the Java object&rsquo;s reference passed need not change, but contents may change as a result of the invocation (see Figure 4.5).

Figure 4.5 Holder objects
figure4.5

Holder classes for predefined IDL types are provided in the package org.omg.CORBA, as listed in Chapter 5. The IDL compiler generates Holder classes TypeNameHolder for user-defined types. In our examples we use the predefined Holder class org.omg.CORBA.ShortHolder.

4.9.3 A Client
The main difference to the previous example is that we create two objects, minute and hour, of the class org.omg.CORBA.ShortHolder for the out parameters of the hello() operation.
package com.wiley.compbooks.brose.chapter4.extended.helloWorld;

import java.io.*;
import org.omg.CORBA.*;

public class Client {
    public static void main(String args[]) {
        // create Holder objects for out parameters
        ShortHolder minute = new ShortHolder();
        ShortHolder hour = new ShortHolder();
        try {
            // initialize the ORB
            ORB orb = ORB.init(args, null);
            // get object reference from command-line argument
            org.omg.CORBA.Object obj =
                orb.string_to_object( args[0] );
            // and narrow it to GoodDay
            GoodDay goodDay = GoodDayHelper.narrow( obj );
            if( goodDay == null ) {
                System.err.println(
                   "stringified object reference is of wrong type");
                System.exit( -1 );
            }

4.9.3.1 Invoking the Operation

After we initialize the ORB and obtain a narrowed object reference, we invoke the operation. We assign the result of the operation to a string location. After the successful return of the invocation, the variables named value in the two holder objects will carry values set by the invoked object.

            // invoke the operation
            String location = goodDay.hello( hour, minute );
            // print results to stdout
            System.out.println("Hello World!");
            if( minute.value < 10 )
                System.out.println("The local time in " + location +
                    " is " + hour.value + ":0" + minute.value + "." );
            else
                System.out.println("The local time in " + location +
                    " is " + hour.value + ":" + minute.value + "." );
        }
        // catch exceptions
        catch(SystemException ex) {
            System.err.println(ex);
        }
    }
}

When we print out the results we obtain the time at the remote location from the variable value of the holder objects hour.value and minute.value. We compile the client as before and execute it. The stringified object reference must refer to an object that provides the extended Hello World interface. The following is a typical result:
prompt> java
com.wiley.compbooks.brose.chapter4.extended.helloWorld.Client
IOR:000000000000001b49444c3a48656c6c6f576f726c642f476f6f64446
1793a312e30000000000001000000000000004c000100000000000e313330
2e3130322e313762e390083040000003000504d4300000000000000144865
6c6c6f576f726c643a3a476f6f64446179000000000c476f6f64446179496
d706c00 Hello World!
The local time in Brisbane is 16:42.

4.9.4 An Applet
The applet implementation does not add much new. We have the same structure as in the simple example, and we make additions and modifications as in the aforementioned client. We add two private variable declarations to the class and create the corresponding objects within the method init().
>package com.wiley.compbooks.brose.chapter4.extended.helloWorld;

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import org.omg.CORBA.*;

public class Applet
    extends java.applet.Applet
    implements ActionListener {

    private ShortHolder minute;
    private ShortHolder hour;
    private GoodDay goodDay;
    private String text;
    private String locality;
    private Button helloWorldButton;
    private TextField textField;

    public void init() {
        minute = new ShortHolder();
        hour = new ShortHolder();
        helloWorldButton = new Button("Invoke remote method");
        helloWorldButton.setFont(
            new Font( "Helvetica", Font.BOLD, 20 ));
        helloWorldButton.setActionCommand("invoke");
        helloWorldButton.addActionListener( (ActionListener)this );
        textField = new TextField();
        textField.setEditable(false);
        textField.setFont(new Font("Helvetica", Font.BOLD, 14));
        setLayout( new GridLayout(2,1);
        add( helloWorldButton );
    }

4.9.4.1  Invoke the Operation

In the method actionPerformed(), we invoke the operation and display the result in the text field.

    public void actionPerformed( ActionEvent e ) {
        if( e.getActionCommand().equals("invoke") ) {
            // invoke the operation
            try {
                locality = new String(goodDay.hello(hour, minute ));
            }
            // catch exceptions
            catch(SystemException ex) {
                System.err.println(ex);
            }
            if( minute.value < 10 )
                text = new String("The local time in " +
                    locality + " is " +
                    hour.value + ":0" + minute.value + "." );
            else
                text = new String("The local time in " +
                    locality + " is " +
                    hour.value + ":" + minute.value + "." );
            textField.setText( text );
        }
    }
}

When the applet is compiled and loaded into a browser via an HTML page, we see a user interface, as shown in Figure 4.3. When the button is clicked and the operation invoked we see the following text in the display.
Hello World! The local time in Brisbane is 16:44.

4.9.5 Object Implementation
The variable declarations and the constructor are as in the class GoodDayImpl of the first example, but the signature of the method hello() has changed. There are now two short holder objects as parameters.

We create an object date that holds the time information of the system. The corresponding class is defined in java.util.Date. We retrieve the hour and the minute by invoking the methods getHours() and getMinutes() on the object. We assign the values to the corresponding value variables of the container objects. We return the locality as in the earlier example.

package com.wiley.compbooks.brose.chapter4.extended.helloWorld;

import java.util.Date;
import org.omg.CORBA.*;

public class GoodDayImpl extends GoodDayPOA {
    private String location;

    // constructor
    GoodDayImpl( String location ) {
        this.location = location;
    }

    // method
    public String hello( ShortHolder hour, ShortHolder minute ) {
        // get local time of the server
        Date date = new Date();
        hour.value = (short) date.getHours();
        minute.value = (short) date.getMinutes();
        return location;
    }
}

The server implementation in the class Server again uses the POA. Once the ORB is initialized, we obtain a reference to the root POA instance by calling resolve_initial_references("RootPOA") on the ORB pseudo-object, activate the POA, and create an instance of the servant as before. To make it a CORBA object, we call the method servant_to_reference() on the POA. This again creates an object reference and implicitly activates the CORBA object; that is, it associates it with the servant goodDayImpl. The new object is now accessible by CORBA clients. Again we print out the stringified object reference. Finally we call run() on the ORB which puts the server in an infinite loop waiting for incoming calls.
package com.wiley.compbooks.brose.chapter4.extended.helloWorld;

import org.omg.CORBA.*;
import org.omg.CORBA.ORBPackage.*;
import org.omg.PortableServer.*;

public class Server {

    public static void main(String[] args) {
        try {
            //init orb
            ORB orb = ORB.init( args, null );
            //init basic object adapter
            POA poa = POAHelper.narrow(
                orb.resolve_initial_references("RootPOA"));
            poa.the_POAManager().activate();
            // create a GoodDay object
            GoodDayImpl goodDayImpl = new GoodDayImpl( args[0] );
            // export the object reference
            org.omg.CORBA.Object obj =
                poa.servant_to_reference( goodDayImpl );
            System.out.println( orb.object_to_string( obj ) );
            // wait for requests
            orb.run();
        }
        catch( InvalidName e ) {
            System.err.println( e );
        }
        // POA exceptions WrongPolicy and ServantNotActive
        catch( UserException e ) {
            System.err.println( e );
        }
        catch(SystemException e) {
            System.err.println(e);
        }
    }
}
In this chapter, you have seen all the basics of programming with Java ORBs and are now ready to start with experiments of your own. We have explained the basic steps that you need to follow, and how the various development stages fit together. You will see that we go through these steps even in the more advanced examples later in this book.
[ Home ] [ Table of Contents ] [ Code ] [ Updates ] [ Java ORBs ] [ The Authors ]
spacer Cover

arrowBack

ISBN 0-471-376817

WCP Home Page