New York University

Computer Science Department

Courant Institute of Mathematical Sciences

 

A Simple Java ORB Application

 

Course Title: Application Servers                                           Course Number: g22.3033-011

Instructor: Jean-Claude Franchitti                                            Session: 4

 

 

This handout explains how to write Java programs and applets with various ORB implementations. One of the goals is to illustrate differences between ORB implementations. As ORB implementations may vary, the syntax may need to be adapted to match the most current version of the system under consideration. We will focus on a simple “HelloWorld” application as illustrated in Figure 1 below.


 

 


Figure 1 - Hello World Application

 

Summary of the CORBA Development Process

 

·        Write some IDL that describes the interfaces to the object or objects that we will use or implement.

·        Compile the IDL using the IDL compiler provided by the particular ORB. This produces the stub and skeleton code that implements location transparency. That is, it will 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 interfaces and classes generated by the IDL compiler 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 the Java compiler.

·        Run the distributed application.

 

Figure 2 shows the use of IDL and the IDL compiler when building the application.

 

Figure 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 which 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. The diagram shows the former code set being used in an applet client, as well as a Java application client.

 

Environment Set-up

Before we can start with the examples we have to set up a working environment. The examples illustrate deployment on a Sun/Solaris platform. For set-ups in different environments, the reader is referred to the installation instructions for the particular products and platforms.

 

We use Sun MicroSystem's Java Development Kit (JDK), assuming that the path is set appropriately and the following are installed:

 

·        the Java compiler, javac

·        the Java run-time system, java

 

To execute applets we used Sun MicroSystem's Appletviewer as well as Netscape Navigator (or IE5).

 

Visibroker for Java

·        Install Visibroker IDL compiler, idl2java.

·        Set the path appropriately to access the IDL compiler.

·        Install Visibroker for Java packages.

·        Set the class-path to access the Visibroker classes.

·        Run Visibroker's directory agent:

prompt> osagent &

·        Run a GateKeeper to let applets talk to CORBA objects via HTTP tunneling:
prompt> java pomoco.iiop.GateKeeper

 

OrbixWeb

·        Install the OrbixWeb IDL compiler idl.

·        Set the path appropriately to access the IDL compiler.

·        Install OrbixWeb Java packages.

·        Set the class-path to access the OrbixWeb classes.

·        Run the Orbix daemon:

prompt> orbixd &

Joe

·        Install the Joe package.

·        Set your path appropriately to access the Joe IDL compiler idltojava.

·        Set your class-path to access the Joe classes.

·        Run the NEO daemon:

prompt> orbd &

·        Re-compile the Apache HTTP server daemon to include the Joe tunnel module, and re-start your httpd. See the Joe documentation for details

 

Interface specification

 

The client invokes an operation hello() on the interface of a potentially remote object of type GoodDay. The result of the invocation is a message, which is printed by the client.

For any CORBA application we must write an IDL specification which defines data types and interfaces, including attributes and operations. For our example, we defined an IDL file called SimpleHelloWorld.idl.

 

// SimpleHelloWorld.idl

 

module SimpleHelloWorld {

    interface GoodDay {

        string hello();

    };

};

 

The file contains the specification of a module SimpleHelloWorld. It is good specification style to:

 

·        Use modules to create a separate name space for an application or its major components.

·        Have one file per module.

·        Name the file after the module.

 

Within the module we define one interface: GoodDay. The interface is in no 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 locality".

 

Compiling the IDL

The next step in the application development is to compile the IDL to generate the stub and skeleton code. There are differences in the code generated by each of the three compilers, so, we will look at the generated code for each separately.

 

Visibroker

Visibroker for Java's compiler is idl2java. The compile command is:

 

                SimpleHelloWorld/Visibroker> idl2java SimpleHelloWorld.idl

 

The IDL compiler creates a new directory, which contains a Java package. 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.

 

The following files are generated by the IDL compiler:

GoodDay.java                          GoodDay_var.java        _st_GoodDay.java

GoodDayOperations.java         _sk_GoodDay.java        _tie_GoodDay.java

 

The IDL interface GoodDay is mapped to a Java interface of the same name in the file GoodDay.java. The class _st_GoodDay contains the stub code, which forms a client-side proxy for the object implementation. The class _sk_GoodDay contains the skeleton code used on the server side. The class GoodDay_var provides miscellaneous methods. The interface GoodDayOperations and the class _tie_GoodDay are used for the Tie mechanisms on the server side.

OrbixWeb

OrbixWeb's IDL compiler is called idl. To enable IIOP the flag interOp has to be set. The compile command is:

 

                SimpleHelloWorld/OrbixWeb> idl -m interOp -jP SimpleHelloWorld

                SimpleHelloWorld.idl

 

The IDL compiler creates a directory, as specified by the -jP option (the default is java_output). In this directory it creates the following files and sub-directories:

 

                SimpleHelloWorld:

                GoodDay/      GoodDay.java

 

                SimpleHelloWorld/GoodDay:

                Holder.java  Ref.java

 

The module SimpleHelloWorld is mapped to a Java package of the same name, and the corresponding directory is created. The IDL interface GoodDay is mapped to a Java interface GoodDay.Ref. The stub code, or client-side proxy, is implemented by the Java class GoodDay.

Joe

The Joe compiler idltojava requires arguments to specify whether you need client stubs, server skeletons or both:

 

                SimpleHelloWorld/Joe> idltojava -fclient -fserver SimpleHelloWorld.idl

 

The compiler creates a package directory called SimpleHelloWorld, and places the following files in that directory:

 

                GoodDayHolder.java       GoodDayRef.java       GoodDaySkeleton.java

                GoodDayOperations.java   GoodDayServant.java   GoodDayStub.java

 

The IDL interface GoodDay is mapped to the Java interface GoodDayRef. It is defined in the SimpleHelloWorld package, which represents the IDL module of the same name. The class GoodDayHolder handles the passing of out and inout parameters.

 

The interface GoodDayOperations defines the signature of the IDL interface in Java. It is implemented on the client side as well as on the server side by the stub and skeleton classes, respectively.

 

The skeleton is implemented by the class GoodDaySkeleton. It has methods to allow the association of the skeleton with an implementation object, which must be of the class that implements the interface GoodDayServant. This is known as the Tie mechanism, which Joe always uses to provide CORBA functionality to implementation objects.

 

A Client as Java application

 

When implementing a client as a Java application, we don't have to worry about the restrictions, which 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, initialize the ORB.

·        Obtain an object reference for the object on which it wants to invoke operations.

·        Invoke operations and process the results.

 

Generated Java Interfaces

Let's have a look at the Java interfaces which correspond to the interface defined in IDL. All these interfaces extend a base class for CORBA Object and define a Java method hello() which returns a Java string and can throw a CORBA System Exception.

Visibroker

Visibroker defines SimpleHelloWorld.GoodDay as:

 

                package SimpleHelloWorld;

                public interface GoodDay extends CORBA.Object

                {

                        public  String  hello() throws CORBA.SystemException;

                };

OrbixWeb

OrbixWeb defines GoodDay.Ref as:

 

                package SimpleHelloWorld.GoodDay;

 

                public interface Ref extends IE.Iona.Orbix2.CORBA.Object.Ref {

                   public String hello()

                   throws IE.Iona.Orbix2.CORBA.SystemException;

                }

Joe

Joe defines hello in GoodDayOperations, and then extends it, along with corba.ObjectRef in GoodDayRef:

 

                package SimpleHelloWorld;

                public interface GoodDayOperations {

                    String hello()

                    throws sunw.corba.SystemException;

                }

 

                public interface GoodDayRef

                    extends sunw.corba.ObjectRef,

                    SimpleHelloWorld.GoodDayOperations {

                }

 

Initializing the ORB

We define a Java class SimpleHelloWorldClient and define the main() method for this class. Initializing an ORB means obtaining a reference to an ORB pseudo-object. The ORB is called a pseudo-object as 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.

 

The corresponding code looks slightly different for the three Java ORBs.

Visibroker

In Visibroker a static method is used to obtain a reference to an ORB pseudo-object.

 

                import java.io.*;

 

                public class SimpleHelloWorldClient {

 

                    public static void main(String args[]) {

 

                                try {

                                // initialize the ORB.

                                CORBA.ORB orb = CORBA.ORB.init();

 

A call is made to the static init() method on the CORBA.ORB class.

OrbixWeb

The pseudo-IDL interface CORBA::ORB is mapped to a Java class _CORBA.Orbix. However, operations on the pseudo-object are implemented as static methods of the class _CORBA.Orbix. The ORB can be considered to be implicitly initialized.

Joe

The Joe class supports all the operations of the CORBA::ORB interface, as well as a number of proprietary naming service methods. A pseudo-object reference to only the ORB part of its functionality can be obtained by calling the method getOrb().

               

                public static void main(String args[])

                {

                                Joe joe = null;

                                try{

                                                joe = new Joe("");

 

There are many constructors for the Joe class, most of them provide different ways of initializing the naming service, or specifying the kind of ORB that you want a reference to.

 

Obtaining an Object Reference

References to objects can be obtained by various means. Here we use a rather unsophisticated method. Object references are opaque data structures. However, an object reference can be made persistent by converting it 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 re-convertible 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 2.0 compliant ORB.

Visibroker

// Visibroker

            // get object reference from command-line argument

            CORBA.Object obj = orb.string_to_object( args[0] );

 

OrbixWeb

// OrbixWeb

            // get object reference from command-line argument

            IE.Iona.Orbix2.CORBA.Object.Ref obj =

                _CORBA.Orbix.string_to_object ( args[0] );

 

Joe

// Joe

            // get object reference from command-line argument

            sunw.corba.ObjectRef obj =

                joe.stringToObject( 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. 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 can raise a CORBA::SystemException if the object reference passed to it is not of a correct type. If it returns successfully then we know that the reference is valid, and of the correct type.

Visibroker

Visibroker generates the narrow method in the class SimpleHelloWorld.GoodDay_var.

 

// Visibroker

        // and narrow it to SimpleHelloWorld.GoodDay

        try {

            SimpleHelloWorld.GoodDay good_day =

                SimpleHelloWorld.GoodDay_var.narrow( obj );

 

OrbixWeb

OrbixWeb generates the narrow method _narrow() in the class SimpleHelloWorld.GoodDay. The Java interface which corresponds to the IDL interface is SimpleHelloWorld.GoodDay.Ref. Leading underscores are generally used to prevent name conflicts with user-defined type names because IDL syntax does not allow leading underscores.

 

// OrbixWeb

        // and narrow it to SimpleHelloWorld.GoodDay

        try  {

            SimpleHelloWorld.GoodDay.Ref good_day =

                SimpleHelloWorld.GoodDay._narrow (obj);

Joe

Joe generates the static narrow() method in the class SimpleHelloWorld.GoodDayStub, and it returns an object of type SimpleHelloWorld.GoodDayRef.

 

// Joe

        // and narrow it to SimpleHelloWorld.GoodDay

        try {

            SimpleHelloWorld.GoodDayRef good_day =

                SimpleHelloWorld.GoodDayStub.narrow(obj);

 

Invoking the Operation

Once the ORB is initialized and an object reference is obtained, CORBA programming looks very much like standard object-oriented programming. One invokes methods on objects and it looks exactly the same for remote and local objects.

 

// Visibroker, OrbixWeb, Joe

            // invoke the operation and print the result

            System.out.println( good_day.hello() );

 

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

 

The last thing to consider is handling exceptions, which might occur. As there are no user exceptions raised by the hello() operation, we only have to catch and process CORBA System Exceptions which can be raised during the initialization of the ORB, the narrow and the hello() operation.

 

// Visibroker, OrbixWeb, Joe

        // catch CORBA system exceptions

        catch(SystemException ex) {

            System.err.println(ex);

        }

    }

}

 

Note that the SystemException class is defined in different packages by different ORBs. The differences have been masked by importing the appropriate packages.

 

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.

 

                SimpleHelloWorld/...> javac SimpleHelloWorldClient.java

 

We execute the client by calling the Java run-time with two arguments, the name of the client class and a stringified object reference. When we consider the server implementation we will see how to generate this string.

 

SimpleHelloWorld/...> java SimpleHelloWorldClient IOR:0000000000000021

49444c3a53696d706c6548656c6c6f576f726c642f476f6f644461793a312e300000000

000000001000000000000004c000100000000000e3133302e3130322e3137362e3900fc

7d0000003000504d43000000010000001a53696d706c6548656c6c6f576f726c643a3a4

76f6f6444617900000000000002febddb22

 

The client then prints the expected message.

 

Hello World, from Brisbane

 

A Client as an Applet

When writing a client as an applet we have to follow the same steps as for the application client. We also have to make the following additions and alterations:

·        Anchor the applet in an HTML page to make it addressable and loadable.

·        Provide a graphical user interface to enable interaction through a WWW browser.

·        Extend the Java Applet class and override some of its methods.

·        Use a different ORB initialization.

 

Anchoring the Applet into HTML

To make an applet accessible over the web it needs to be anchored into 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 browser.

 

Here is an example HTML file:

 

<html>

<header>

<! -- SimpleHelloWorldApplet.html -->

<title>

Simple Hello World Example

</title>

<center>

<pre>

 

</pre>

<h1>

Simple Hello World Example

</h1>

</center>

<pre>

 

</pre>

<center>

<applet code=SimpleHelloWorldApplet.class

        width=400 height=80>

</applet>

</center>

 

</body>

</html>

 

For our simple applet we have an HTML file SimpleHelloWorldApplet.html which contains only a header and a reference to our applet SimpleHelloWorldApplet.class.

 

Initializing the Applet

We define our applet as a class SimpleHelloWorldApplet which extends the Java Applet class java.applet.Applet. Within the class we declare a number of private variables:

·        good_day -- to hold the object reference of the remote object.

·        hello_world_button -- a button to enable users to invoke the method.

·        text_field -- a text field to display the result of the method.

Then we override the method init() inherited from the Applet class. First, we initialize the GUI components, i.e., 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.

The class header is different for each of the three ORBs.

Visibroker

// SimpleHelloWorldApplet.java

import java.awt.*;

 

public class SimpleHelloWorldApplet extends java.applet.Applet {

 

    // Visibroker

    private SimpleHelloWorld.GoodDay good_day;

 

OrbixWeb

// SimpleHelloWorldApplet.java

import java.awt.*;

 

public class SimpleHelloWorldApplet extends java.applet.Applet {

    private SimpleHelloWorld.GoodDay.Ref good_day;

 

Joe

// SimpleHelloWorldApplet.java

import java.awt.*;

import sunw.joe.*;

import sunw.corba.*;

public class SimpleHelloWorldApplet extends JoeApplet {

    private SimpleHelloWorld.GoodDayRef good_day;

 

The remainder of the implementation is the same of the three ORBs.

 

    private Button hello_world_button;

    private TextField text_field;

 

    public void init() {

 

        hello_world_button = new Button("Invoke remote method");

        hello_world_button.setFont(new Font("Helvetica", Font.Bh3D, 20));

        text_field = new TextField();

        text_field.setEditable(false);

        text_field.setFont(new Font("Helvetica", Font.Bh3D, 14));

       

        setLayout( new GridLayout(2,1));

        add( hello_world_button );

        add( text_field );

 

Locating Objects

In the next step we locate an object implementation. In the application client we did this using a stringified object reference. This time we use proprietary object location mechanisms provided by each of the three ORBs.

Visibroker

To initialize the Visibroker ORB we again call the method init(), this time, with one argument, the applet object itself (using the Java keyword this to do so). This initialization causes a change in the underlying protocol mechanism. Instead of pure IIOP, HTTP tunneling is used. Apart from the different initialization, tunneling is hidden from the application programmer.

 

To obtain a reference to the remote object we use Visibroker's Smart Agent. The agent provides a proprietary naming service. The interface to this service is a method called bind() which is generated for each IDL interface type and is located in the _var class, e.g., SimpleHelloWorld.GoodDay_var. The bind() operation returns a reference to an object of the specified interface type, if available. If there are multiple objects of that interface type available, a random choice is made.

 

// Visibroker

 

        try {

            // initialize the ORB (using this applet)

            CORBA.ORB orb = CORBA.ORB.init( this );

 

            // bind to "SimpleHelloWorld.GoodDay"

            good_day = SimpleHelloWorld.GoodDay_var.bind();

        }

OrbixWeb

Orbix provides a similar bind mechanism which is based on the Orbix daemon and its Implementation Repository. The method is similarly called _bind(). However, it is defined in a different class, namely SimpleHelloWorld.GoodDay, and returns an object of type SimpleHelloWorld.GoodDay.Ref.

 

// OrbixWeb

 

        try {

            // bind to "SimpleHelloWorld.GoodDay.Ref"

            good_day = SimpleHelloWorld.GoodDay._bind();

        }

Joe

In Joe the applet is initialized automatically, as the JoeApplet class implements all of the Joe interface (including its ORB functionality). An explicit reference to the ORB pseudo-object can be obtained by calling getORB(). Joe uses the NEO naming service, and has a method called find(), defined in the JoeApplet class. This method returns a CORBA::Object reference, which must then be narrowed. The server, or some other object, must have registered an object reference of the type we want in the NEO naming service beforehand. This is done using the method bind(), which makes an association between a string and an object reference.

 

// Joe

        try{

            ObjectRef obj;

 

            obj = find("MyGoodDay");

            good_day = SimpleHelloWorldStub.narrow(obj);

        }

 

Catching Exceptions

Applet initialization is finished with the catching and processing of exceptions. The code is the same for the three Java ORBs.

 

// Visibroker, OrbixWeb, Joe

        // catch CORBA system exceptions

        catch(SystemException ex) {

            System.err.println(ex);

        }

      }

Catching and Processing Applet Events

To handle applet events we override the method action(), inherited through the class java.applet.Applet (originally defined in java.awt.Component). This method handles GUI events and it is invoked when an event occurs in the GUI element corresponding to the Component class, in our case the applet.

This code is the same for each of the ORBs.

 

// Visibroker, OrbixWeb, Joe

    public boolean action(Event ev, java.lang.Object arg) {

 

        // catch and process events

        if(ev.target == hello_world_button ) {

 

            // invoke the operation

            try {

                text_field.setText( good_day.hello() );

            }

 

            // catch CORBA system exceptions

            catch(CORBA.SystemException ex) {

                System.err.println(ex);

            }

 

            return true;

        }

 

        return false;

    }

}

 

We check if the target of the event was our button hello_world_button. If not, we return false to indicate that no event was processed. Otherwise we invoke the method hello() on the object good_day. 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.

Compiling and Executing the Applet

To make the applet executable it needs to be compiled. This is done by calling the Java compiler.

 

SimpleHelloWorld/...> javac SimpleHelloWorldApplet.java

 

To execute the applet we have to point a Java-enabled Web browser to the URL of the HTML document which anchors our applet. Figure 3 shows the initial state of the applets execution in the browser.


 


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

 


Figure 4 Hello World Applet - Invoked Method

 


An Object Implementation

Now we turn to the implementation of the object whose interface has been specified in IDL. In this section we only consider Visibroker.

 

Object implementation classes must be associated with the skeleton class generated by the IDL compiler. This can be done by inheritance or by delegation.

 

A Java implementation class can extend the skeleton class generated by the IDL compiler. The skeleton class is an implementation of the Java interface, which corresponds to the IDL interface. The object implementation is an extension of this class. This is known as associating the skeleton with its implementation by inheritance.

 

The other way is known as the Tie method, or associating the skeleton with its implementation by delegation. That is, there are separate skeleton and implementation objects, and the skeleton is given a reference to the implementation object.

 

In our example we have an implementation class GoodDayImpl which extends the skeleton class (SimpleHelloWorld._sk_GoodDay). As in the implementation of the equally named class, we declare a private variable locality, which will hold a string identifying the location of the service. Here we mean the geographical location, as shown in the client examples above.

 

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

 

// SimpleGoodDayImpl.java

 

import CORBA.*;

 

// Visibroker

class SimpleGoodDayImpl extends SimpleHelloWorld._sk_GoodDay {

    // variable declaration

    private String locality;

 

    // constructor

    SimpleGoodDayImpl( String m_locality ) {

 

        // calling the constructor of the super class

        super( "SimpleGoodDayImplV1.0" );

 

        // initialize locality

        locality = new String( m_locality );

    }

 

    // method

    public String hello() throws CORBA.SystemException {

 

        return "Hello World, from " + locality;

    }

}

 

We implement the method hello(), which returns a string composed of the message "Hello World, from" and the value of the variable locality.

 

Again we have to compile the Java source into byte-code:

 

                Visibroker> javac SimpleGoodDayImpl.java

 

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 SimpleHelloWorldServer. We only implement the main() method in this class. We check for the right number of arguments, one of which indicates the locality of the server.

 

A server is responsible for the following tasks:

·        Initialize the ORB and the BOA.

·        Create the object.

·        Notify the BOA of the existence of the object.

 

Although the CORBA2.0 specification defines the interfaces of the pseudo-objects ORB and BOA, the various ORB vendors have implemented these pseudo-interfaces differently.

 

Visibroker provides a straightforward mapping of the pseudo-interfaces of ORB and BOA. We initialize the ORB in the same way we did on the client side calling ORB.init() which returns a reference to the ORB pseudo-object. With this reference we invoke the method BOA_init() which initializes the BOA and returns a reference to it. The BOA, like the ORB, is a pseudo-object. The BOA is concerned with the activation and registration of object implementations and servers.

 

To create an implementation object good_day_impl we call Java's new operator and supply one parameter for the constructor which we copy from the command-line argument.

 

import CORBA.*;

 

public class SimpleHelloWorldServer {

 

    public static void main(String[] args) {

 

        if( args.length != 1 ) {

            System.out.println(

                "Usage: java SimpleHelloWorldServer <location>");

            System.exit( 1 );

        }

 

 

        try {

            //init ORB

            CORBA.ORB orb = CORBA.ORB.init();

 

            //init Basic Object Adapter

            CORBA.BOA boa = orb.BOA_init();

   

            // create a SimpleGoodDay object

            SimpleGoodDayImpl simple_good_day_impl =

                new SimpleGoodDayImpl( args[0] );

   

            // export the object reference

            boa.obj_is_ready( simple_good_day_impl );

 

            // print stringified object reference

            System.out.println( orb.object_to_string( simple_good_day_impl ) );

   

            // wait for requests

            boa.impl_is_ready();

        }

        catch(CORBA.SystemException e) {

            System.err.println(e);

        }

    }

}

Once we have created the implementation object we notify the BOA that this object is available by calling the method obj_is_ready(). We also print out the stringified version of the object reference which we obtain by calling object_to_string() on the ORB. This is the object reference we used in the Java-application client to establish a connection with a server.

 

 

We notify the BOA, by calling impl_is_ready(), that the server is ready and that it can receive requests from clients. Finally, we catch and handle any CORBA system exceptions.

 

Compiling and Starting the Server

We have to compile the Java source into byte-code:

 

                Visibroker/SimpleHelloWorld> javac SimpleHelloWorldServer.java

 

We now start the server:

 

                Visibroker/SimpleHelloWorld> java SimpleHelloWorldServer Brisbane

 

This prints out a stringified IOR:

 

IOR:000000000000002149444c3a53696d706c6548656c6c6f576f726c642f476f6f644

461793a312e300000000000000001000000000000004c000100000000000e3133302e31

30322e3137362e3900fc7d0000003000504d43000000010000001a53696d706c6548656

c6c6f576f726c643a3a476f6f6444617900000000000002febddb22

 

Extending the Hello-World Example

In this section we will modify the simple Hello World example from above to introduce another feature. In this example the server will not only return a message but also the current time at the server's location.

 

We will look at some new aspects of application development, and we will also revisit some of the issues discussed in the earlier version of this example application.

 

Specifically, we deal with:

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

 

Interface Specification

We again specify an interface GoodDay with an operation hello(). However, this time the module is called HelloWorld to avoid name clashes with the previous example. Also the signature of the operation is different. The operation's result is still a string. This time it returns the locality description of the server and has parameters. Those 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's location: hour holds the hour and minute the minute.

 

module HelloWorld {

    interface GoodDay {

        string hello(

                out short hour,

                out short minute );

    };

};

 

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, with respect to IDL's out and inout parameters. The solution is provided by container objects. Instead of passing an argument itself, an

object is used as an argument to the Java method. The object contains a variable value of the type of the IDL parameter. See Figure 5.

 

Figure 5 Container Objects

 

Container classes for pre-defined data types are provided by a class library. The IDL compiler generates container classes for user-defined types.

 

Although the three Java ORBs follow the same approach there are some differences in the notation. Visibroker calls the containers _var objects. In our examples we use Visibroker's predefined container class CORBA.short_var. OrbixWeb and Joe call the container objects Holder objects, in our example we use the pre-defined class ShortHolder.

 

A Client

The main difference to the previous example is that we create two objects minute and hour of the class CORBA.short_var (ShortHolder) for the out parameters of the hello() operation.

 

import java.io.*;

 

public class HelloWorldClient {

 

    public static void main(String args[]) {

 

Visibroker

// Visibroker

        // create _var objects for out parameters

          CORBA.short_var minute = new CORBA.short_var();

          CORBA.short_var hour = new CORBA.short_var();

 

OrbixWeb and Joe

// OrbixWeb, Joe

        // create Holder objects for out parameters

          ShortHolder minute = new ShortHolder();

          ShortHolder hour = new ShortHolder();

 

Invoking the operation

After we initialize the ORB and obtain a narrowed object reference as above, we invoke the operation. We construct a string locality from the result of the operation. After the successful return of the invocation, the variables named value in the two container objects will carry values set by the invoked object. Again, this code looks the same for each of the ORBs.

 

            // invoke the operation

            String locality = new String(

                good_day.hello( hour, minute ) );

 

            // print results to stdout

            System.out.println("Hello World!");

            if( minute.value < 10 )

                System.out.println("The local time in " + locality +

                    " is " + hour.value + ":0" + minute.value + "." );

            else

                System.out.println("The local time in " + locality +

                    " is " + hour.value + ":" + minute.value + "." );

 

When we print out the results we obtain the time at the remote side via the variable value of the container objects hour.value and minute.value. We compile the client as before and when we execute the client we get the following result:

 

HelloWorld/...> java HelloWorldClient IOR:000000000000001b49444c3a4865

6c6c6f576f726c642f476f6f644461793a312e30000000000001000000000000004c000

100000000000e3133302e3130322e3137362e390083840000003000504d430000000000

00001448656c6c6f576f726c643a3a476f6f64446179000000000c476f6f64446179496

d706c00

 

Hello World!

The local time in Brisbane is 16:42.

 

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 client above. We add two private variable declarations to the class and create the corresponding objects within the method init().

Visibroker

public class HelloWorldApplet extends java.applet.Applet {

 

// Visibroker

    private CORBA.short_var minute;

    private CORBA.short_var hour;

 

    public void init() {

        minute = new CORBA.short_var();

        hour = new CORBA.short_var();

 

OrbixWeb and Joe

public class HelloWorldApplet extends java.applet.Applet {

// OrbixWeb, Joe

    private ShortHolder minute;

    private ShortHolder hour;

 

    public void init() 

          minute = new ShortHolder();

          hour = new ShortHolder();

 

Invoke the operation

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

            // invoke the operation

            try {

                locality = new String( good_day.hello( hour, minute ) );

            }

            // catch CORBA system exceptions

            catch(CORBA.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 + "." );

            text_field.setText( text );

 

When the applet is compiled and loaded into a browser via an HTML page as shown above, we see a user interface. When the button is clicked and the operation invoked we see text in a display similar to the one in the client above,

 

Hello World! The local time in Brisbane is 16:44.

 

Object Implementation

The variable declarations and the constructor are as in the class SimpleGoodDayImpl, but the signature of the method hello() has changed. There are now two short container objects as parameters.

 

We create an object date which 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.

 

import java.util.Date;

 

class GoodDayImpl extends HelloWorld._sk_GoodDay {

 

    // declarations and constructor as in SimpleGoodDayImpl

 

    // method

    public String hello(

        // Visibroker

            CORBA.short_var hour, CORBA.short_var minute

        // OrbixWeb, Joe

         // ShortHolder hour, ShortHolder minute

        ) throws CORBA.SystemException {

 

        // get local time of the server

        Date date = new Date();

        hour.value = (short) date.getHours();

        minute.value = (short) date.getMinutes();

 

        return locality;

    }

}

 

The server implementation is almost unchanged. We simply substitute GoodDayImpl for SimpleGoodDayImpl.