JAVA PROGRAMMING WITH CORBA, 2E
Sample: Chapter 5
Chapter5
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. We will
implement a client which is a Java application, a client which is a Java applet, and a server hosting an object
implementation. Figure 5.1 illustrates the components of our examples.
Figure 5.1
All code is presented in compact form in the Appendix and is also available in electronic form from
www.wiley.com/compbooks/vogel. We used Visibroker for Java version 3.0 to develop and run our examples. As long as
standard CORBA features are used the ORB you choose does not matter. Various ORB products which 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
1). We give detailed explanations of the development of a simple example application (sections 2–8) and then
extend this to include more features, including the use of the BOA (section 9). In Chapter 9 we will return to
application development with a substantial example. Chapter 13 introduces a number of design patterns for
scalability and performance.
1 Summary of the CORBA Development
Process
The examples presented in this chapter will 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 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 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 5.2 shows the use of IDL and the IDL compiler when building the application.
Figure 5.2
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.
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 and Sun MicroSystem's Java Development Kit (JDK) version 1.1. For setups
in different environments, the reader is referred to the installation manuals for the particular products and
platforms.
We use JDK 1.1, assuming that the path is set appropriately and that the Java compiler javac and the Java run-time
system java are installed. We also use Visigenic Software's Visibroker for Java version 3.0, assuming that the path and
classpath are set appropriately. Visibroker's IDL compiler is called idl2java. To enable persistent CORBA objects we run
Visibroker's directory agent:
unix> osagent &
dos> osagent-C
and to overcome applet sandbox and firewall restrictions we run the gatekeeper, Visibroker's IIOP
gateway and HTTP tunneling mechanisms;
prompt> gatekeeper &.
3 Interface Specification
Our first example provides the same functionality as the one introduced in Chapter 3. However, 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/vogel/chapter5/simple.
//HelloWorld.idl
module com {
module wiley {
module compbooks {
module vogel {
module chapter 5 {
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.
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 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 that creates portable code which complies with the IDL/Java
mapping specification is
classes> idl2java -portable
com/wiley/compbooks/vogel/chapter5/simple/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 create another package called
com.wiley.compbooks.vogel.chapter5.simple.HelloWorldImpl, which contains the client, the applet, the
object implementation, and the server classes.
The following files are generated by the IDL compiler:
GoodDay.java
GoodDayHolder.java GoodDayHelper.java
_portable_st_GoodDay.java _GoodDayImplBase.java
GoodDayOperations.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
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 methods, most importantly the narrow() method. In Chapter 6 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 Visibroker's IDL compiler contain classes which have general
functionality, but have ORB-specific names. The Java ORB Portability Interfaces, which we explain in Chapter 6,
will ensure the portability of code from one ORB to another. The class _portable_st_GoodDay contains the
stub code which forms a client-side proxy for the object implementation. The class _GoodDayImplBase contains
the skeleton code which can be used without an explicit object adapter.
The interface GoodDayOperations and the class _tie_GoodDay are used for the Tie mechanism on
the server side. This is explained in Chapter 6 and demonstrated by an example in Chapter 10.
5 A Client as a 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, obtain a reference to the ORB.
- Obtain an object reference for the object on which to invoke operations.
- Invoke operations and process the results.
5.1 Generated Java Interface
The Java interface which corresponds to the interface defined in IDL extends a base class for CORBA
Object and defines a Java method hello() which returns a Java string.
// generated Java - GoodDay.java
package com.wiley.compbooks.vogel.chapter5.simple.HelloWorld;
public interface GoodDay extends org.omg.CORBA.Object {
public java.lang.String hello();
};
5.2 Initializing the ORB
We define a Java class Client in our implementation package 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 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.vogel.chapter5.simple.HelloWorldImpl;
import java.io.*;
import org.omg.CORBA.*;
import com.wiley.compbooks.vogel.chapter5.simple.HelloWorld.*;
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.
5.3 Obtaining an Object Reference
References to objects can be obtained by various means, as explained in Chapter 8. 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 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 2.0-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.
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. One invokes methods on objects and it looks exactly the same for
remote and local objects.
System.out.println( goodDay.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. Since 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.
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.
HelloWorldImpl> 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.
… > java
com.wiley.compbooks.vogel.chapter5.HelloWorldImpl.Client
IOR:000000000000002149444c3a53696d706c6548656c6c6f576f726c642f4
76f6f644461793a312e300000000000000001000000000000004c0001000000
00000e3133302e3130322e3137362e3900fc7d0000003000504d43000000010
000001a53696d706c6548656c6c6f576f726c643a3a476f6f64446179000000
00000002febddb22
The client then prints the expected message.
Hello World, from Brisbane
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.
6.1 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><title>
Hello World Example
</title>
<center><h1>
Hello World Example
</h1></center>
<center>
<applet code=com/wiley/compbooks/vogel/chapter5/simple/HelloWorldImpl/Applet.class
width=400 height=80>
</applet>
</center>
</body></html>
</pre>
For our simple applet we have an HTML file HelloWorldApplet.html which contains only a header and a
reference to our applet class com.wiley.compbooks.vogel.chapter5.HelloWorldImpl.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.
6.2 Initializing the Applet
We define our applet as a class Applet which 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
JDK 1.1 event model and set the action command to "invoke."
package
com.wiley.compbooks.vogel.chapter5.simple.HelloWorldImpl;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import org.omg.CORBA.*;
import com.wiley.compbooks.vogel.chapter5.simple.HelloWorld.*;
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 );
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. Since the stringified IOR are rather inconvenient for applets, we use Visibroker's proprietary
object location mechanisms provided by the OSAgent. Details on how to locate an object are provided in Chapter
8.
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 changes the behavior of the stub. As part of its bootstrap
code the stub will establish a connection to an instance of Visibroker's Gatekeeper, which it expects to be running on the
machine where the applet has been downloaded from. The Gatekeeper is a CORBA object as well as an HTTP server. Besides
the initial bootstrapping for a CORBA-enabled applet the GateKeeper performs the following tasks:
- reenables CORBA location transparency and callbacks to objects hosted by applets which are
otherwise impossible due to applet sandboxing
- provides an HTTP tunneling mechanism to overcome client-side firewalls
Details of these problems and their solutions are discussed in Chapter 12.
To obtain a reference to the remote object we use Visibroker's OSAgent. The agent provides a proprietary directory
service. The interface to this service is a method called bind(), which is generated for each IDL interface type and is located
in its Helper class, for example, GoodDayHelper. The bind() method returns a reference to an object of the specified
interface type, if one is available. If there are multiple objects of that interface type available, object references are returned in a
round-robin fashion. Applet initialization is finished with the catching and processing of exceptions.
try {
// initialize the ORB (using this applet)
orb = ORB.init( this );
// bind to object
goodDay = GoodDayHelper.bind( orb );
}
catch(SystemException ex) {
System.err.println("ORB is not initialized");
System.err.println(ex);
}
}
Other Java ORBs provide bind() operations of different flavors or use the CORBA Naming Service
(but then there is still the bootstrap problem). In Chapter 8 we explore the details of object discovery.
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 only to deal with 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.
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.
HelloWorldImpl> javac Applet.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 5.3 shows the initial state of the applet's execution in the browser.
Figure 5.3
Once the button has been clicked, the result of the operation invocation is displayed in the text field as
shown in Figure 5.4.
Figure 5.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 which is named after the IDL interface: _InterfaceNameImplBase. This base class is a skeleton. There are
alternatives to this implementation style. We explain one of them later in the chapter. 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 which 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 10.
In our example we have an implementation class GoodDayImpl which extends the servant base class
_GoodDayImplBase. As in the implementation of the GoodDayImpl class shown in Chapter 3, we declare a
private variable, location, which 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.vogel.chapter5.simple.HelloWorldImpl;
import org.omg.CORBA.*;
import com.wiley.compbooks.vogel.chapter5.simple.HelloWorld.*;
public class GoodDayImpl extends _GoodDayImplBase {
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:
HelloWorldImpl> javac GoodDayImpl.java
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 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 which we copy from the command-line argument.
package com.wiley.compbooks.vogel.chapter5.simple.HelloWorldImpl;
import java.io.*;
import org.omg.CORBA.*;
import com.wiley.compbooks.vogel.chapter5.simple.HelloWorld.*;
public class Server {
public static void main(String[] args) {
if( args.length != 1 ) {
System.out.println(
"Usage: java com.wiley.compbooks.vogel.chapter5.simple.HelloWorldImp
");
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 only have a Java object. To make it into a CORBA object we must enable the object to receive
CORBA operation invocations. There are various ways to achieve this. Typically this is done via an object adapter. The
IDL/Java mapping specification, however, allows another, simpler way to do so. The ORB class provides a method,
connect(), which converts the Java object into a CORBA object by making it invokable by CORBA clients. Note that the
servant becomes a transient CORBA object. The object reference of a transient object is only valid for the lifetime of a
particular instance of the servant. We explain and compare transient and persistent object references in detail in Chapter 6.
Objects can be deactivated by calling disconnect() on the ORB.
// export the object reference
orb.connect( goodDayImpl );
// print stringified object reference
System.out.println( orb.object_to_string( goodDayImpl ) );
// wait for requests
java.lang.Object sync = new java.lang.Object();
synchronized (sync) {
sync.wait();
}
}
catch(Exception e) {
System.err.println(e);
}
}
}
Once we connect our object implementation, goodDayImpl, we print its stringified object reference to the standard
output. Finally, the server waits for incoming requests. Again we catch possible exceptions.
8.1 Compiling and Starting the Server
We have to compile the Java source into byte code:
HelloWorldImpl> javac Server.java
We now start the server:
> java com.wiley.compbooks.vogel.chapter5.simple.HelloWorldImpl.Server
Brisbane
This prints out a stringified IOR which looks like this:
IOR:000000000000002149444c3a53696d706c6548656c6c6f576f726c642f476f6f644
461793a312e300000000000000001000000000000004c000100000000000e3133302e31
30322e3137362e3900fc7d0000003000504d43000000010000001a53696d706c6548656
c6c6f576f726c643a3a476f6f6444617900000000000002febddb22
It's probably a good idea to redirect standard output to a file. In our example we call this file shw.ior:
simple> java com.wiley.compbooks.vogel.chapter5.simple.
HelloWorldImpl.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:
simple> java com.wiley.compbooks.vogel.chapter5.simple.
HelloWorldImpl.Client 'cat shw.ior'
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 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 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
- Using a Basic Object Adapter
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.vogel.chapter5.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 );
};
};…};
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 5.5).
Figure 5.5
Holder classes for predefined IDL types are provided in the package org.omg.CORBA, as listed in
Chapter 6. The IDL compiler generates Holder classes TypeNameHolder for user-defined types. In our examples
we use the predefined Holder class org.omg.CORBA.ShortHolder.
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.vogel.chapter5.extended.HelloWorldImpl;
import java.io.*;
import org.omg.CORBA.*;
import com.wiley.compbooks.vogel.chapter5.extended.HelloWorld.*;
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 narrowed it to GoodDay
GoodDay goodDay = GoodDayHelper.narrow( obj );
if( goodDay == null ) {
System.err.println(
"stringified object reference is of wrong type");
System.exit( -1 );
}
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 the client. The stringified object
reference must refer to an object that provides the extended hello world interface. The following is a typical result:
> java com.wiley.compbooks.vogel.chapter5.extended.HelloWorldImpl.Client
IOR:000000000000001b49444c3a48656c6c6f576f726c642f476f6f644461793
a312e30000000000001000000000000004c000100000000000e3133302e313032
2e3137362e390083840000003000504d43000000000000001448656c6c6f576f72
6c643a3a476f6f64446179000000000c476f6f64446179496d706c00
Hello World!
The local time in Brisbane is 16:42.
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 client above. We add two private variable declarations to the
class and create the corresponding objects within the method init().
import java.awt.*;
import java.awt.event.*;
import org.omg.CORBA.*;
import com.wiley.compbooks.vogel.chapter5.extended.HelloWorld.*;
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 );
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 5.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.
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 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.
This time, however, we use the Visibroker skeleton class, which is generated by the IDL compiler in the
class _sk_GoodDay, and the BOA. The BOA is defined in the CORBA specification, but is not complete. ORB
vendors have filled in the gaps in different ways. As a consequence, BOA-based object implementations and
servers are not portable. Given that the BOA was the only standard way to implement CORBA servers, until the
recent introduction of the POA, it became quite popular. As the POA is not yet implemented, BOA
implementations are the only way to get more sophisticated features on the server side other than the connect
operations provided by the ORB. A more detailed overview of object adapters is given in Chapter 2.
package com.wiley.compbooks.vogel.chapter5.extended.HelloWorldImpl;
import java.util.Date;
import org.omg.CORBA.*;
import com.wiley.compbooks.vogel.chapter5.extended.HelloWorld.*;
public class GoodDayImpl extends _sk_GoodDay {
private String location;
// constructor
GoodDayImpl( String location ) {
super( 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 now uses the BOA. Once the ORB is initialized, we obtain a
reference to an instance of the BOA by calling BOA_init() on the ORB object. We then create an instance of the servant as
before. To make it a CORBA object, this time we call the method obj_is_ready() on the BOA. This call makes the servant
accessible by CORBA clients. Again we print out the stringified object reference. Finally we call impl_is_ready() on the
BOA which puts the server in an infinite loop waiting for incoming calls.
package com.wiley.compbooks.vogel.chapter5.extended.HelloWorldImpl;
import org.omg.CORBA.*;
import com.wiley.compbooks.vogel.chapter5.extended.HelloWorld.*;
public class Server {
public static void main(String[] args) {
try {
//init orb
ORB orb = ORB.init (args, null);
//init basic object adapter
BOA boa = orb.BOA_init();
// create a GoodDay object
GoodDayImpl goodDayImpl = new GoodDayImpl( args[0] );
// export the object reference
boa.obj_is_ready( goodDayImpl );
System.out.println( orb.object_to_string( goodDayImpl ) );
// wait for requests
boa.impl_is_ready();
}
catch(SystemException e) {
System.err.println(e);
}
}
}
|