Professional Documents
Culture Documents
CORBA Example: Description of The Example
CORBA Example: Description of The Example
This example illustrates the basic tasks in building a CORBA distributed application
using Java IDL. You will build the classic Hello World program as a distributed
application. The Hello World program has a single operation that returns a string to be
printed.
Getting started
You will need two things: version 1.2 of the JDK software and the idltojava compiler.
The JDK provides the API and ORB needed to enable CORBA-based distributed object
interaction. The idltojava compiler uses the IDL-to-Java mapping to convert IDL
interface definitions to corresponding Java interfaces, classes, and methods, which you
can then use to implement your client and server code.
In this section, you will write a simple IDL interface for the Hello World program. The
IDL interface defines the contract between the client and server parts of your application,
specifying what operations and attributes are available. OMG IDL is programming-
language independent. You must map it to Java before writing any of the implementation
code. (Running idltojava on the IDL file does this for you automatically.) Here's the
complete Hello.idl file:
module HelloApp
{
interface Hello
{
string sayHello();
};
};
Steps needed to write the IDL for the Hello World application
A CORBA module is a namespace that acts as a container for related interfaces and
declarations. It corresponds closely to a Java package. Each module statement in an
IDL file is mapped to a Java package statement.
module HelloApp {
// Add subsequent lines of code here.
};
Like Java interfaces, CORBA interfaces declare the API contract that an object has with
other objects. Each interface statement in the IDL maps to a Java interface statement
when mapped.
module HelloApp {
interface Hello // Add
{ // these
// four
}; // lines.
};
When you compile the IDL, this statement will generate an interface statement in the
Java code. Your client and server classes will implement the Hello interface in different
ways.
CORBA operations are the behavior that servers promise to perform on behalf of clients
that invoke them. Each operation statement in the IDL generates a corresponding
method statement in the generated Java interface.
module HelloApp {
interface Hello
{
string sayHello(); // Add this line.
}; // notice the semicolon
}; //notice the semicolon
Because our little Hello World application has only a single operation, Hello.idl is now
complete.
The tool idltojava reads OMG IDL files and creates the required Java files. The idltojava
defaults are set up so that if you need both client and server files (as you do for our Hello
World program), you simply enter the tool name and the name of your IDL file:
idltojava Hello.idl
If you list the contents of the directory, you will see that a directory called HelloApp has
been created and that it contains five files. Open Hello.java in your text editor. It looks
like this:
The single surprising item is the extends statement. All CORBA objects are derived from
org.omg.CORBA.Object to ensure required CORBA functionality. The required code is
generated by idltojava; you do not need to do any mapping yourself.
The idltojava compiler generates a number of files, based on the options chosen on the
command line. Because these provide standard functionality, you can ignore them until it
is time to deploy and run your program. The five files generated by idltojava are:
_HelloImplBase.java
This abstract class is the server skeleton, providing basic CORBA functionality for
the server. It implements the Hello.java interface. The server class HelloServant extends
_HelloImplBase.
_HelloStub.java
This class is the client stub, providing CORBA functionality for the client. It
implements the Hello.java interface.
Hello.java
This interface contains the Java version of our IDL interface. It contains the single
method sayHello. The Hello.java interface extends org.omg.CORBA.Object, providing
standard CORBA object functionality as well.
HelloHelper.java
This final class provides auxiliary functionality, notably the narrow method
required to cast CORBA object references to their proper types.
This narrow() operation highlights one of the differences between RMI and
CORBA. An RMI client can automatically download the class bytecodes for a remote
stub reference from the object server, if the class for the stub object cannot be found
locally. CORBA is a language-independent remote object scheme, so there is no portable
way to specify a remote object’s type when a client obtains a stub reference. So the stub
reference is initially represented a basic ObjectImpl object that knows how to forward
method requests to its server methods. The client application is forced to cast this stub
reference to the correct local type, using the narrow() method. In the Java mapping of the
IDL, this means calling the narrow() method on the corresponding helper class.
HelloHolder.java
This final class holds a public instance member of type Hello. It provides
operations for out and inout arguments, which CORBA has but which do not map easily
to Java's semantics.
When you write the IDL interface, you do all the programming required to generate all
these files for your distributed application. The only additional work required is the
actual implementation of client and server classes.
Troubleshooting
} catch(Exception e) {
System.out.println("ERROR : " + e);
e.printStackTrace(System.out);
}
}
}
Importing Required Packages
Every Java application needs a main method. Declare it within the scope of the
HelloClient class, as follows:
Because all CORBA programs can throw CORBA system exceptions at runtime, you
will place all of the main functionality within a try-catch block. CORBA programs throw
system exceptions whenever trouble occurs during any of the processes involved in
invoking the server from the client.
Our exception handler simply prints the name of the exception and its stack trace to
standard output so you can see what kind of thing has gone wrong.
try {
// Add the rest of the HelloClient code here.
} catch(Exception e) {
System.out.println("ERROR : " + e);
e.printStackTrace(System.out);
}
Creating an ORB Object
A CORBA client needs a local ORB object to perform all of its marshaling and IIOP
work. Every client instantiates an org.omg.CORBA.ORB object and initializes it by
passing to the object certain information about itself.
The call to the ORB's init method passes in your application's command line
arguments, allowing you to set certain properties at runtime.
Once the application has an ORB, it can ask the ORB to locate the actual service it
needs, in this case the Hello server. There are a number of ways for a CORBA client to
get an initial object reference; our client application will use the COS Naming Service
specified by OMG and provided with Java IDL.
(See Using Stringified Object References for information on how to get an initial object
reference when no naming service is available).
The first step in using the naming service is to get the initial naming context. In the
try-catch block, below your ORB initialization, call orb.resolve_initial_references to get
an object reference to the name server:
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
The string "NameService" is defined for all CORBA ORBs. When you pass in that
string, the ORB returns the initial naming context, an object reference to the name
service.
As with all CORBA object references, objRef is a generic CORBA object. To use it as
a NamingContext object, you must narrow it to its proper type. Add the call to narrow
just below the previous statement.
Here we see the use of an idltojava -generated helper class, similar in function to
HelloHelper. The ncRef object is now an org.omg.CosNaming.NamingContext and you
can use it to access the naming service and find other services.
Finding a Service in Naming
Names can have different structures depending upon the implementation of the
naming service. Consequently, CORBA name servers handle complex names by way of
NameComponent objects. Each NameComponent holds a single part, or element, of the
name. An array of NameComponent objects can hold a fully specified path to an
object on any computer file or disk system.
To find the Hello server, you first need a NameComponent to hold an identifying
string for the Hello server. Add this code directly below the call to narrow.
This statement sets the id field of nc, the new NameComponent, to "Hello" and the
kind field to an empty string.
Because the path to the Hello object has just one element, create a single-element
array out of nc. The NamingContext.resolve method requires this array for its work:
Finally, pass path to the naming service's resolve method to get an object reference to
the Hello server and narrow it to a Hello object:
Here you see the HelloHelper helper class at work. The resolve method returns a
generic CORBA object as you saw above when locating the name service itself.
Therefore, you immediately narrow it to a Hello object, which is the object reference you
need to perform the rest of your work.
CORBA invocations look like a method call on a local object. The complications of
marshaling parameters to the wire, routing them to the server-side ORB, unmarshaling,
and placing the upcall to the server method are completely transparent to the client
programmer. Because so much is done for you by generated code, invocation is really the
easiest part of CORBA programming.
2.Finally, add code to print the results of the invocation to standard output:
System.out.println(hello);
Because all CORBA programs can throw CORBA system exceptions at runtime, you
will place all of the main functionality within a try-catch block. CORBA programs throw
runtime exceptions whenever trouble occurs during any of the processes (marshaling,
unmarshaling, upcall) involved in invocation. The exception handler simply prints the
exception and its stack trace to standard output so you can see what kind of thing has
gone wrong.
try {
// Add the rest of the HelloServer code here.
} catch(Exception e) {
System.err.println("ERROR: " + e);
e.printStackTrace(System.out);
}
Creating an ORB Object
Just like a client, a CORBA server also needs a local ORB object. Every server
instantiates an ORB and registers its servant objects so that the ORB can find the server
when it receives an invocation for it.
The call to the ORB's init method passes in the server's command line arguments,
allowing you to set certain properties at runtime.
A server is a process that instantiates one or more servant objects. The servant
implements the interface generated by idltojava and actually performs the work of the
operations on that interface. Our HelloServer needs a HelloServant.
Inside the try-catch block, just below the call to init, instantiate the servant object:
This servant class isn't defined yet; you will do that in a later step. Next, connect the
servant to the ORB, so that the ORB can recognize invocations on it and pass them along
to the correct servant:
orb.connect(helloRef);
At the end of HelloServer.java, outside the HelloServer class, define the class for the
servant object.
The HelloServer works with the naming service to make the servant object's
operations available to clients. The server needs an object reference to the name service,
so that it can register itself and ensure that invocations on the Hello interface are routed to
its servant object.
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
The string NameService is defined for all CORBA ORBs. When you pass in that
string, the ORB returns a naming context object that is an object reference for the name
service.
As with all CORBA object references, objRef is a generic CORBA object. To use it as
a NamingContext object, you must narrow it to its proper type. Add the call to narrow
just below the previous statement:
Here you see the use of an idltojava -generated helper class, similar in function to
HelloHelper. The ncRef object is now an org.omg.CosNaming.NamingContext and you
can use it to access the naming service and register the server. You will do that in the next
step.
3.Finally, pass path and the servant object to the naming service, binding the servant
object to the "Hello" id:
ncRef.rebind(path, helloRef);
Now, when the client calls resolve("Hello") on the initial naming context, the naming
service returns an object reference to the Hello servant.
The server is ready; it simply needs to wait around for a client to request its service.
To achieve that, enter the following code at the end of (but within) the try-catch block:
This form of Object.wait requires HelloServer to remain alive (though quiescent) until
an invocation comes from the ORB. Because of its placement in main, after an invocation
completes and sayHello returns, the server will wait again.
1.Compile HelloClient.java:
1.From an MS-DOS system prompt (Windows) or command shell (UNIX), start the
Java IDL name server:
Note that nameserverport is the port on which you want the name server to run. If
you do not specify this, port 900 will be chosen by default. Also note that using Solaris
software, you must become root to start a process on a port under 1024. For this reason,
we recommend that you use a port number greater than or equal to 1024.
Note that nameserverhost is the host on which the IDL name server is running. You
can omit -ORBInitialHost nameserverhost if the name server is running on the same host
as the Hello server.
You can leave out -ORBInitialPort nameserverport if the name server is running on
the default port.
Note that nameserverhost is the host on which the IDL name server is running. You
can omit -ORBInitialHost nameserverhost if the name server is running on the same host
as the Hello client.
You can leave out -ORBInitialPort nameserverport if the name server is running on
the default port.
4.The client prints the string from the server to the command line:
Hello world!!
Remember to stop both the tnameserv and the HelloServer processes after the client
application returns successfully.
Troubleshooting
} catch(Exception e) {
System.out.println("HelloApplet exception: " + e);
e.printStackTrace(System.out);
}
}
String message = "";
Tutorial.html is provided for displaying your finished applet, but you need to
customize a few attributes and
parameters.