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.
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.
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’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’s execution in the browser.
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.

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’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’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’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’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’s location: hour holds the hour and
minute the minute.
module com {
module wiley {
…
module extended {
module helloWorld {
interface GoodDay {
string hello(
out short hour,
out short minute );
};
};…};
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’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’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

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