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.