CORBA Programming with J2SE 1.4

estrapadesherbetSoftware and s/w Development

Nov 18, 2013 (3 years and 10 months ago)

291 views


1

http://java.sun.com/developer/technicalArticles/releases/corba/







Article
COR
BA Programming with J2SE 1.4


1.4

Programming Transient and Persistent Servers

Qusay Mahmoud

May 2002

The Java 2 Platform, Standard Edition 1.4 (J2SE 1.4) has introduced several new features and enhancements
for the Common Object Request Broker Architect
ure (CORBA). The new features and enhancements either
address changes in the standard CORBA specifications, or improve the performance of existing features. One
of the important new features is the Portable Object Adapter (POA).

This article presents a de
tailed description of the POA and shows you how to use it to develop more portable
CORBA applications. It then:



Shows how to develop CORBA applications with the new POA



Shows how to develop transient and persistent servers



Explains how to use the new CO
RBA tools

CORBA New Features

Since its inception in the early 1990's, CORBA has had to evolve to remain viable as a basis for distributed
applications. As part of this continuing evolution, several significant new features have been added to CORBA
2.2 and

above. One of these features is the Portable Object Adapter (POA) which has been defined in the
CORBA 2.2 specification. For information about the other new features, please see
New CORBA Features in
J2SE 1.4
.

Portable Object Adapter

Up to CORBA 2.1, the only standard object adapter defined by the Object Management Group (OMG) is the
Basic Object Adapter (BOA), which provides basic services to allow a variety of COR
BA objects to be created.
ORB vendors and developers, however, discovered that the BOA is ambiguous and missing some features.
This led vendors develop their own proprietary extensions, which resulted in poor portability between different
ORB implementatio
ns. The new standard object adapter is the Portable Object Adapter (POA), which provides
new features that allow developers to construct object implementations that are portable between different
ORB products supplied by different vendors. The POA acts as
a mediator between the ORB and the server
application as shown in Figure 1.


Figure 1: Request dispatching based on POA


The client invokes th
e request using a reference that refers to the target object. The request is then received
by the ORB, which will dispatch the request to the POA that hosts the target object. The POA will then dispatch
the request to the servant, which subsequently carrie
s the request and sends the results back to the POA, to
the ORB, and finally to the client. Since an application may have multiple POAs, in order for the ORB to
dispatch the request to the right POA, it uses an object key, which is an identifier that is pa
rt of the request that
is kept in the object reference. One part of the object key called the object ID is used by the POA to determine
an association (such associations might be stored in a map) between the target object and a servant.


2

Programming with t
he POA

In order to create and use a POA, several steps are required. These steps may vary, however depending on
the type of application being developed. The POA life cycle contains the following steps:

1. Get the Root POA

The first step is to get the root

POA, which is managed by the ORB and provided to the application using the
initial object name
RootPOA
. This is done as follows:

ORB orb = ORB.init(argv, null);

POA rootPOA = POAHelper.narrow(


orb.resolve_initial_references("RootPOA"));

2. Define the P
OA Policies

As I mentioned earlier, the POA is an object adapter that can be used with multiple ORB products without the
need for rewriting code. It is also designed to allow persistent objects (objects that are always alive even
though the server that is
hosting them may have been restarted). As a result, the developer is given control
over the object's identity, state, storage, and life cycle. This is done through the use of policies related to
threads, lifespan, object uniqueness, activation, and others.


There are seven policies that you have control over. These are:



Thread Policy



The appropriate thread usage technique for an application depends on several factors, including the
number of objects the application will have, multi
-
threading support by t
he operating system, and the
expect load on the system. In the BOA, multi
-
threading issues weren't addressed. The POA, however,
has addressed this problem by providing a threading policy that can be used to specify the threading
model to be used with the c
reated POA. You can use:



ORB_CTRL_MODEL
: This model allows multiple requests to be processed concurrently by
multiple threads, and the ORB is responsible for assigning requests to threads (this is the
default threading model).



SINGLE_THREAD_MODEL
: In thi
s model applications don't need to be thread
-
aware, and
therefore all requests are processed sequentially (this however is not supported in J2SE
1.4).



Here is how you create a policy:

Policy p[] = new Policy[7];

p[0] = rootPOA.createt_thread_policy(


ThreadPolicyValue.ORB_CTRL_MODEL)

In this example, we create an array of seven policy items. In the first item we have created a thread
policy. Note however that the thread policy we created is the default anyway. This is a hypothetical
example just to sho
w you how to create policies.



Lifespan Policy



The POA supports two types of CORBA objects: the
persistent

object that was originally specified by
CORBA, and a new object called a
transient
. A transient object cannot live beyond the process in
which it i
s created; it can be used in situations where temporary objects are required (as in callbacks).
A persistent object, on the other hand, can live beyond the process that created it. For example, if a
client sends a request to a target object that isn't acti
ve (not running), the ORB will activate a server
process for the object (if necessary) and then activate the object itself. It is important to note that (as
you will see in the programming examples later in the article) the activation process is transparen
t to
the client.


The lifespan policy can be used to specify the type of objects implemented in the created POA. You
can make an object:


3



TRANSIENT
: The objects cannot outlive the POA instance in which they are created (this is
the default policy).



PERSI
STENT
: The objects can outlive the process in which they are created.



As an example, the following snippet of code shows how to create a lifespan policy where the objects
are persistent:

p[1] = rootPOA.create_lifespan_policy(


LifespanPolicyValue.PERS
ISTENT);

As you can see from the above two example policies, to create a policy use the
create_nameOf_policy(policNameValue.value)

syntax.



Object ID Uniqueness Policy



This policy can be used to specify whether the servants must have unique object identi
ties. The value
for this policy can be:



UNIQUE_ID
: Servants support exactly one object ID (this is the default).



MULTIPLE_ID
: A servant may support one or more object IDs.


The following snippet of code shows an example of a policy that allows a servant

to have one or more
object IDs:

p[2] = rootPOA.create_id_uniqueness_policy(


IdUniquenessPolicyValue.MULTIPLE_ID);



ID Assignment Policy



This policy can be used to specify whether object IDs are generated by the application or by the ORB.
The options a
re:



USER_ID
: Objects are assigned unique IDs only by the application.



SYSTEM_ID
: Objects are assigned unique IDs by the POA (this is the default). Note that if
the lifespan policy is set to
PERSISTENT

then assigned object IDs must be unique across all
in
stantiations of the same POA.


As an example, the following snippet of code shows how to create an assignment policy where object
IDs are generated by the application:

p[3] = rootPOA.create_id_assignment_policy(


IdAssignmentPolicyValue.USER_ID);



Servan
t Retention Policy



This policy specifies whether the created POA retains active servants in an object map. The options
are:



RETAIN
: Indicates the POA will retain active object in a map (this is the default).



NON_RETAIN
: Active objects are not retained.



The following snippet of code shows an example of a servant retention policy specifying that active
objects are not retained by the POA in an object map:

p[4] = rootPOA.create_servant_retention_policy(


ServantRetentionPolicyValue.NON_RETAIN);



Request

Processing Policy



Use this policy to specify how you wish requests to be processed by the created POA. The options
are:



USE_ACTIVE_OBJECT_MAP_ONLY
: An
OBJECT_NOT_EXIST

exception is thrown if the
object ID is not found in the active object map (this is
the default). Note however, in order to
use this you must set the
ServantRetentionPolicyValue

to
RETAIN
.



USE_DEFAULT_SERVANT
: If the object ID is not found in the active object map or the servant
retention policy is set to
NON_RETAIN

then the request is d
ispatched to the default servant.


4



USE_SERVANT_MANAGER
: If the object ID is not found in the active object map or the
NON_RETAIN

server retention policy is present, the servant manager is given the opportunity
to locate or activate a servant or raise an ex
ception.


The following snippet of code shows how to create a request processing policy where requests are
dispatched to the default servant:

p[5] = create_request_processing_policy(


RequestProcessingPolicyValue.USE_DEFAULT_SERVANT);



Implicit Activatio
n Policy
:


This policy specifies whether implicit activation of servants is supported in the created POA. The
options are (the default is none):



IMPLICIT_ACTIVATION
: Implicit activation of servants. Note however that this requires
SYSTEM_ID

and
RETAIN

po
licies to be present.



NO_IMPLICIT_ACTIVATION
: No implicit servant activation.


Note that the root POA always has the following policies:



Thread policy:
ORB_CTRL_MODEL
.



Lifespan policy:
TRANSIENT
.



Object ID uniqueness:
UNIQUE_ID
.



ID assignment policy:

SYSTEM_ID
.



Servant retention policy:
RETAIN
.



Request processing policy:
USE_ACTIVE_OBJECT_MAP_ONLY
.



Implicit activation policy:
IMPLICIT_ACTIVATION
.


3. Create the POA

Create a new POA to allow you to define specific policies. A new POA is created as
a child of an existing POA
using the
create_POA

on the parent POA. When creating a new POA, you need to pass the following
information:

1.

Name of the POA, which must be unique with respect to all other POAs with the same parent.

2.

POA Manager to be associate
d with the new POA. If
null

is passed then a new POA manager will
be created.

3.

A policy list to be associated with the new POA.

The following snippet of code shows how a POA is created:

POA poa = rootPOA.create_POA(


"childPOA", null, policy);


4. Activ
ate the POAManager

A
POAManager

is associated with one or more POA objects. It is responsible for controlling the processing
state of the POAs. The
POAManager

may have one of the following states:



Holding: Associated POAs queue incoming requests (this is
the default).



Active: Associated POAs start processing requests.



Inactive: Associated POAs rejects new requests as well as requests that haven't begun executing.



Discarding: Associated POAs will discard incoming requests.

When a
POAManager

object is cr
eated, it is in a
HOLD

state by default. In other words, it is not automatically
activated. It is activated as follows:

poa.the_POAManager().activate();



5

Without this statement, all calls to a servant will hang in a queue because the
POAManager

is in a
HO
LD

state.

5. Activate the Servants

If the
USE_DEFAULT_SERVANT

policy is set, the server application requests the POA to activate unknown
objects by having the POA invoke a single servant no matter what the object ID is. The server application
registers th
is servant with
set_servant
.

If, on the other hand, the
RETAIN

policy is in effect, the servant and its associated object ID are entered into
the active object map of the appropriate POA. This activation can be accomplished in one of the following three
w
ays:

1.

The server application explicitly activates individual objects through the
activate_object

or
activate_object_with_id

operations.

2.

The server application instructs the POA to activate objects on demand by having the POA invoke a
user
-
supplied servant

manager. The server manager is registered using the
set_servant_manager

operation.

3.

If the
IMPLICIT_ACTIVATION

policy is also set, the POA may implicitly activate an object when the
server application attempts to obtain a reference for a servant that is n
ot already active.

If, however, the
NON_RETAIN

policy is in effect, the POA may use either a default servant or a servant
manager to locate an active servant. Note, however, that from the POA's point of view, the servant is active
only for the duration of

that one request. The POA doesn't enter the servant
-
object association into the active
object map.

6. Create the Object Reference

Once an object reference is created in a server, it can be exported to clients. An object reference contains
information rel
ated to object identity and others required by the ORB to identify and locate the server and the
POA with which the object is associated. Object references can be created in three ways:

1.

Explicitly activate a servant and associate it with an object referen
ce
: the following snippet of code
shows how this can be done using the
servant_to_reference

operation to map an activated
servant to its corresponding object reference:

org.omg.CORBA.Object obj =


orb.resolve_initial_references("NameService");

NamingCon
textExt rootctx =


NamingContextExtHelper.narrow(obj);

NameComponent nc[] = rootctx.to_name(


"PersistentMathServer");

rootctx.rebind(nc,


poa.servant_to_reference(servant));

2.

Server application directly creates a reference
: this can be done as shown
in the following snippet of
code:

3.

Context ctx = new InitialContext();

4.

ctx.rebind("MathServer",

5.


poa.create_reference_with_id(

6.


id, tie._all_interfaces(poa, id)[0]));

7.

Server application causes a servant to implicitly activate itself
: this is possible
when the POA has
been created with the
IMPLICIT_ACTIVATION

policy set.

Programming Example: Array Adder

Now let's see how to use the POA to develop a CORBA application. The application that we will develop here
is an array adder: the client provides two a
rrays and the server adds them together and sends the result back
to the client. We will develop two versions of the application: a transient server and a persistent server.


6

Array Adder: Transient Server

The first step in developing any CORBA application
is to define the interface in the OMG Interface Definition
Language (IDL). The IDL interface for the array adder is shown in Code Sample 1. Here I define a module
ArithApp

(which is equivalent to a Java package), an interface
Add

that contains a constant,
a new data type
array

(which is a synonym for an array of
long
s and an operation
addArrays

that takes in two arrays as
input (specified using the
in
) and another array as the output holder (specified using the
out
).

Code Sample 1
: Add.idl

module ArithApp

{


interface Add {


const unsigned short SIZE=10;


typedef long array[SIZE];


void addArrays(in array a, in array b,


out array result);


};

};



You can now compile this IDL interface to map it to Java and generate stubs and s
keletons. This can be done
using the
idlj

compiler. When you run this tool you can request it to generate client stubs only, server side
skeletons only, or both. Here you want to generate both, client stubs and server skeletons. To do so use the
following
command:

prompt>

idlj
-
fall Add.idl

This command will generate several files. Check the local directory where you run the command from to see
the files. You will notice that a new subdirectory with the name
ArithApp

has been created. This is because
an OM
G IDL
module

is mapped to a Java
package
. For more information on the
idlj

compiler and the
options you can use, please see the
IDL
-
to
-
Java Compiler
.


Note
: The new
idlj

compiler in J2SE 1.4 generates server
-
side mappings for the Portable
Object Adapter (POA). The new compiler is, however, backward compatible with earlier
releases since it

provides the
-
ImplBase

flag that can be used to generate server
-
side
mappings for existing applications that have been created using J2SE 1.3 or earlier versions.
Therefore, in order to talk to existing applications that have been created using J2SE 1.3 o
r
earlier, you need to use the
-
ImplBase

flag to generate server
-
side mappings. New
applications do not need to generate these deprecated server
-
side mappings.


The next step is to imp
lement the IDL interface in Code Sample 1. An implementation is shown in Code
Sample 2. The
AddImpl

class is a subclass of
AddPOA
, which is generated by the
idlj

compiler from the IDL
interface. Note the third parameter to the
addArrays

operation. Here I a
m using an array holder simply
because I am using the
out

parameter as a holder for the output array.

Code Sample 2
: AddImpl.java

import ArithApp.*;

import org.omg.CORBA.*;


class AddImpl extends AddPOA {


private ORB orb;




public AddImpl(ORB orb) {


this.orb = orb;


7


}



// implement the addArrays() method


public void addArrays(int a[], int b[],


ArithApp.AddPackage.arrayHolder result) {



result.value = new int[ArithApp.Add.SIZE];



for(int i=0; i<ArithApp.Add.SIZE; i++) {


resu
lt.value[i] = a[i] + b[i];


}


}

}



The next step is to develop the server. A sample server is shown in Code Sample 3. The server performs the
following tasks:



Creates and initializes the ORB.



Creates an instance of the interface implementation
and registers it with the ORB.



Gets a reference to the
RootPOA

and activates the
POAManager
.



Gets an object reference from the servant.



Gets the root naming context from the naming service and registers the new object under the name
"Add".



Waits for in
vocations from clients.

Code Sample 3
: AddServer.java

import ArithApp.*;

import org.omg.CORBA.*;

import org.omg.CosNaming.*;

import org.omg.PortableServer.*;

import org.omg.PortableServer.POA;

import org.omg.CosNaming.NamingContextPackage.*;


public clas
s AddServer {



public static void main(String args[]) {


try{


// create and initialize the ORB


ORB orb = ORB.init(args, null);



// create an implementation and register it with the ORB


AddImpl impl = new AddImpl(orb);



//

get reference to rootpoa & activate the POAManager


POA rootpoa = POAHelper.narrow(


orb.resolve_initial_references("RootPOA"));


rootpoa.the_POAManager().activate();



// get object reference from the servant


org.omg.CORBA.Obj
ect ref =


rootpoa.servant_to_reference(impl);


Add href = AddHelper.narrow(ref);





// get the root naming context


// NameService invokes the name service


org.omg.CORBA.Object objRef =


orb.resolve_initial_reference
s("NameService");


// Use NamingContextExt which is part of the Interoperable


8


// Naming Service (INS) specification.


NamingContextExt ncRef =


NamingContextExtHelper.narrow(objRef);



// bind the Object Reference in Naming



String name = "Add";


NameComponent path[] = ncRef.to_name( name );


ncRef.rebind(path, href);



System.out.println("AddServer


ready to add up your arrays ....");



// wait for invocations from clients


orb.run();


}

catch (Exception e) {


System.err.println("ERROR: " + e);


e.printStackTrace(System.out);


}


System.out.println("AddServer Exiting ....");


}

}



Now, implement the client. A sample client is shown in Code Sample 4. The client code
performs the following
tasks:



Creates and initializes the ORB.



Obtains a reference to the root naming context.



Looks up the "Add" object in the naming context and obtains a reference to it.



Invokes the
addArrays

method and prints the results.

Code Sam
ple 4
: AddClient.java

import ArithApp.*;

import org.omg.CORBA.*;

import org.omg.CosNaming.*;

import org.omg.CosNaming.NamingContextPackage.*;


public class AddClient {



public static void main(String args[]) {


try {


// create and initialize th
e ORB


ORB orb = ORB.init(args, null);



// get the root naming context


org.omg.CORBA.Object objRef =


orb.resolve_initial_references("NameService");



// Use NamingContextExt instead of NamingContext. This is


// part of

the Interoperable Naming Service.


NamingContextExt ncRef =


NamingContextExtHelper.narrow(objRef);




// resolve the Object Reference in Naming


String name = "Add";


Add impl = AddHelper.narrow(ncRef.resolve_str(name));




System.out.println("Handle


obtained on server object: " + impl);


9



// the arrays to be added


int a[] = {6, 6, 6, 6, 6, 6, 6, 6, 6, 6};


int b[] = {7, 7, 7, 7, 7, 7, 7, 7, 7, 7};




// the result will be saved in thi
s new array


ArithApp.AddPackage.arrayHolder c =


new ArithApp.AddPackage.arrayHolder();



// invoke the method addArrays()


impl.addArrays(a, b, c);


// print the new array


System.out.println("The sum of the two arrays is
: ");


for(int i=0;i<ArithApp.Add.SIZE;i++) {


System.out.println(c.value[i]);


}



} catch (Exception e) {


System.out.println("ERROR : " + e) ;


e.printStackTrace(System.out);


}


}

}



Now you can compile the class
es
AddImpl
,
AddServer
,
AddClient
, and the stubs and skeletons that were
generated by the
idlj

compiler. This is done using the
javac

compiler as follows:

prompt>

javac *.java ArithApp/*.java

To run the application
:

1.

Start the
orbd
, which is a name server:


prompt>

orbd
-
ORBInitialPort 2500

The number 2500 is the port number where you want the
orbd

to run. Note that the
-
ORBInitialPort

is a require command
-
line argument.

2.

Start the
AddServer
:

prompt>

java AddServer
-
ORBInitialPort 2500

This command starts
the server as shown in Figure 2.


Figure 2: Start
ing the AddServer

(click to enlarge)


Here we are assuming that both the
AddServer

and
orbd

are running on the same host. If the
orbd

is running on a different host, us
e the
-
ORBInitialHost

argument to inform the server where to
find the
orbd
.

3.

Start the
AddClient
:


10

prompt>

java AddClient
-
ORBInitialPort 2500

You should see the sum of the two arrays as shown in Figure 3.


Figure 3: Starting the AddClient

(click to enlarge)


The ORBD Name Server

The CORBA Common Object Services (or COS Naming Service) provides a tree
-
like directory of object
references much like a filesystem provides a directory of files. In the previous version of th
e JDK, the
tnameserv

was part of the release. The
tnameserv

is a transient naming service that retains naming
contexts as long as it is running. If the naming service is shutdown, all naming contexts are lost. The
tnameserv

is shipped with J2SE 1.4 for bac
kward compatibility.

In the J2SE 1.4, the ORBD (ORB Daemon) includes a transient naming service and a persistent naming
service. Both of these services are an implementation of the COS Naming Service. Unlike the transient naming
service, the persistent na
ming service provides a persistent storage for naming contexts. In other words, in
case the ORBD is restarted, the persistent naming service will restore all naming contexts.

Both the client and the server starts by obtaining the root naming context. This

can be done as shown in the
following snippet of code:

org.omg.CORBA.Object objRef =


orb.resolve_initial_references("NameServce");

NamingContextExt ctx =


NamingContextExtHelper.narrow(objRef);


If you are using the transient naming service
tnameser
v

of a release prior to J2SE 1.4, the first line of the
above segment of code returns an object reference to the transient naming service. This object reference,
objRef
, is a generic CORBA object, and in order for it to be used as a
NamingContextExt

object
, you must
cast it to the proper type. This casting is done using the
narrow

method in CORBA. On the other hand, if you
are using the
orbd

of the J2SE 1.4, the above segment of code returns an object reference to the persistent
naming service. To specify t
hat you want to use the transient naming service with the
orbd
, pass in the string
TNameService

instead of
NameService
:

org.omg.CORBA.Object objRef =


orb.resolve_initial_references("TNameServce");

NamingContextExt ctx =


NamingContextExtHelper.narrow
(objRef);

Note that the
NamingContext
Ext

and
NamingContext
Ext
Helper

are new classes in the J2SE 1.4. This
extension is part of the Interoperable Naming Service (INS), which is a URL
-
based naming system on top of
the CORBA Naming Service and a common bootst
rap that allows applications to share a common initial
naming context. The INS, which is an extension of the COS Naming Service, provides new features including:



Capability to resolve using stringified names (such as
Company/Department/HumanResources/Expe
nses).



URLs for CORBA object references (
corbaloc:

and
corbaname:

formats).



Standard APIs in
NamingContextExt

for converting between CosNames, URLs, and Strings.

The INS allows the following stringified object reference formats:


11

1.

Interoperable Object Re
ference

(IOR): it is an object reference that is understood by the ORBs that
can interoperate using General Inter
-
ORB Protocol (GIOP) and Internet Inter
-
ORB Protocol (IIOP). An
object reference can be obtained by a client using the
orb.object_to_string(obj
Ref)

method.

2.

Human Readable URL format
: the
corbaloc

and
corbaname

enable you to provide a URL to
access CORBA objects. The
corbaloc

can be used to resolve to a particular CORBA service
without the need to go through a naming service, and the
corbaname

ca
n be used to resolve a
stringified name from a specific naming context. For example, the following snippet of code


corbaloc:iiop:1.2@SomeDomain.com:3000/TraderService



shows how to get an object reference for
TraderService

from the host
SomeDomain.com

o
n port
3000.


And the following snippet of code


corbaname::SomeDomain.com:4000#conference/speakers



can be used to resolve stringified name from the root naming context. In this example the URL is used
to locate the naming service and resolve the name
conference/speakers
. SomDomain.com is the
host and the port number is 4000.

Array Adder: Persistent Server

We will now see how to develop a persistent server where the objects outlive the process that created them.
We will follow the same steps as in the
previous examples: develop an IDL interface, implement the interface,
develop the server and client.

If you wish to run this application, you may want to create a new directory and copy the
Add.idl

file, of Code
Sample 1, to it. We will be using the same
IDL interface in this example.

Compile the
Add.idl

interface using the
idlj

compiler:

prompt>

idlj
-
fall Add.idl


This command generates client stubs and server skeletons.

The next step is to implement the interface. The implementation is similar to tha
t in Code Sample 2. Here,
however, we call the implementation the
AddServant
. The servant is shown in Code Sample 5.

Code Sample 5
: AddServant.java

import ArithApp.*;

import org.omg.CORBA.ORB;


class AddServant extends AddPOA {



private ORB orb;



pub
lic AddServant(ORB orb) {


this.orb = orb;


}




// implement the addArrays() method


public void addArrays(int a[], int b[],


ArithApp.AddPackage.arrayHolder result) {


result.value = new int[ArithApp.Add.SIZE];


for(int i=0; i<ArithAp
p.Add.SIZE; i++) {


result.value[i] = a[i] + b[i];


}


12


}



}



The next step is to implement the persistent server. My implementation is shown in Code Sample 6. This
server performs the following tasks:



Creates an initializes an ORB instance.




Creates a servant.



Gets a reference to the root POA.



Creates the policy that makes the server persistent.



Creates a persistent POA.



Activates the persistent POA's POAManager.



Associates the servant with the persistent POA.



Gets a CORBA object refer
ence for the root naming context and registers the object reference under
the name "AddServer".



Waits for invocations from clients.

Code Sample 6
: AddServer3.java

import ArithApp.*;

import org.omg.CORBA.ORB;

import org.omg.CORBA.Object;

import org.omg.C
osNaming.NameComponent;

import org.omg.CosNaming.NamingContextExt;

import org.omg.CosNaming.NamingContextExtHelper;

import org.omg.CORBA.Policy;

import org.omg.PortableServer.Servant;

import org.omg.PortableServer.*;

import org.omg.PortableServer.POA;


pub
lic class AddServer3 {



public static void main(String args[]) {


try {


// create and initialize the ORB


ORB orb = ORB.init(args, null);



// create servant and instantiate it


AddServant servant = new AddServant(orb);



//
get reference to rootpoa and activate the POAManager


POA rootpoa = POAHelper.narrow(


orb.resolve_initial_references("RootPOA"));




// Create the Persistent Policy


Policy[] policy = new Policy[1];


policy[0] = rootpoa.crea
te_lifespan_policy(


LifespanPolicyValue.PERSISTENT);



// Create a persistent POA by passing the policy


POA poa = rootpoa.create_POA("childPOA", null, policy );



// Activate PersistentPOA's POAManager. Without this


// all ca
lls to persistent server will hang


// because POAManager


// will be in the 'HOLD' state.


poa.the_POAManager().activate( );



13


// Associate the servant with PersistentPOA


poa.activate_object( servant );



// Resolve RootNam
ing context and bind a name


// for the servant.


// "NameService" is used here....persistent name service.


org.omg.CORBA.Object obj =


orb.resolve_initial_references("NameService" );


NamingContextExt rootContext =


N
amingContextExtHelper.narrow(obj);




//bind the object reference in the naming context


NameComponent[] nc =


rootContext.to_name("AddServer");


rootContext.rebind(nc, poa.servant_to_reference(servant));



// wait for client re
quests


orb.run();


} catch (Exception e) {


System.err.println("Exception


in AddServer3 Startup " + e);


}


}

}



The last step is to implement the client. A Sample client is shown in Code Sample 7. The client performs the
fol
lowing tasks;



Creates and initializes an ORB.



Resolves the
AddServant

by using the Interoperable Naming Service
corbaname

URL. The URL
locates the Naming Service running on the localhost and listening on port 2900. When located, it
resolves "AddServer" f
rom the Naming Service.



Invokes the object's
addArrays

and prints the result. In this example, the client calls the
addArrays

method every 6 seconds. If the server is down the next time the client makes the request, the client
will restart the server beca
use of the persistence lifespan.

Code Sample 7
: AddClient3.java

import ArithApp.*;

import org.omg.CORBA.ORB;

import org.omg.CORBA.OBJ_ADAPTER;

import org.omg.CosNaming.NamingContext;

import org.omg.CosNaming.NamingContextHelper;

import org.omg.CosNaming.
NameComponent;

import org.omg.PortableServer.POA;


public class AddClient3 {



public static void main(String args[]) {


try{


// create and initialize the ORB


ORB orb = ORB.init(args, null);



org.omg.CORBA.Object obj = orb.string_to_o
bject(


"corbaname::localhost:2900#AddServer");



Add impl = AddHelper.narrow(obj);



// the arrays to be added


14


int a[] = {6, 6, 6, 6, 6, 6, 6, 6, 6, 6};


int b[] = {7, 7, 7, 7, 7, 7, 7, 7, 7, 7};




// the result wi
ll be saved in this new array


ArithApp.AddPackage.arrayHolder c =


new ArithApp.AddPackage.arrayHolder();



while(true) {


System.out.println("Calling


the persistent AddServer3..");


impl.addArrays(a, b, c);



// print the new array


System.out.println("The sum of the two arrays is: ");


for(int i=0;i<ArithApp.Add.SIZE;i++) {


System.out.println(c.value[i]);


}



System.out.println("...will


call the server agai
n in a few seconds....");


System.out.println("...if the


server is down, it will be automatically restarted...");


Thread.sleep(6000);


}


} catch ( Exception e ) {


System.err.println( "Exception in AddClient3..." +
e );


e.printStackTrace( );


}


}

}



Now you can compile the classes
AddServant
,
AddServer3
,
AddClient3
, and the stubs and skeletons
that were generated by the
idlj

compiler. This is done using the
javac

compiler as follows:

prompt>

javac *.ja
va ArithApp/*.java

To run the application
:

1.

Start the
orbd
, which is a name server:

prompt>

orbd
-
ORBInitialPort 2900

The number 2900 is the port number where you want the
orbd

to run. Note that the
-
ORBInitialPort

is a required command
-
line argument.

2.

St
art the
AddServer3
:


In order to register a persistent server with the ORBD, the server must be started using the
servertool
, which is a command
-
line interface for developers to register, unregister, startup, and
shutdown a persistent server.


The
server
tool

can be started as follows (it must be started on the same port number as the
orbd
):

prompt>

servertool
-
ORBInitialPort 2900

You should see the
servertool

command line appears as follows:



15

servertool>



Again, here we are assuming that both the
orbd

and
servertool

are running on the same host. If
you wish to run the
servertool

on a different host, use the
-
ORBInitialHost

command
-
line
argument to specify the host where the
orbd

is running.


Now you can register the
AddServer3

using the
register

comman
d. You need to specify the
name of the server, the name of the application, and the classpath to the server class as shown in
Figure 4.


Figure 4: Registering a persistent server using servertool

(click to enlarge)


A
s you can see, the
servertool

registers the server and assigns it a unique ID (257 in this case)
that can be used later on for housekeeping activities. If you try to register a server that is already
registered, the ID will be 0.


To see a list of
servert
ool

commands, type
help

at the command prompt as shown in Figure 5.


Figure 5: Servertool commands

(click to enlarge)


To learn more about the
servertool
, please see the
Java IDL Server Tool
.

3.

Start the
AddClient3
:

prompt>

java AddClient3
-
ORBInitialPort 2900

You should see the client printing the sum of the two arrays.


To demonstrate persistence
, shut down the server as shown in Figure 6.


Figure 6: Shut down server

(click to enlarge)


In this example we first list the servers that are registered, find the ID for our server, and then use the
shutdown

command to shut it down.


16


Even though the server is
shut down, if you monitor the client console it will print the sum of the two
arrays six seconds later. This is because the server is a persistent server and in the case of failure it
will be reactivated automatically. All this is transparent to the client
.

Information about servers and their states is maintained by the
orbd
. When you run the
orbd
, it creates a
subdirectory under the directory it was started from. The name of the subdirectory is, by default,
orb.db
. This
subdirectory contains information a
bout servers that have been registered and log files for them. For example,
if you look under the
orb.db/logs

subdirectory you will see files with names such as
257.out

and
257.err
. These files are used to record the starting and shutdown time for servers
as well as any errors
encountered by the server.

Conclusion


Now that you've seen an example of how to develop CORBA applications with the new POA and seen how to
develop transient and persistent servers, you can explore the new CORBA features in J2SE 1.4

more fully on
your own.

If you have existing CORBA applications that use the BOA, you may want to rewrite them using the POA. The
end result will be that your applications are portable across ORBs from different vendors.

For more information

-

CORBA Specification (OMG)


-

Distributed Programming with Java book

(Chapter 11: Overview of CORBA):

-

Java IDL Documentation


-

Distributed Java Programming with CORBA and RMI


-

New Feat
ures in CORBA 3.0


-

Changes in CORBA Features between J2SE 1.3 and 1.4



Abo
ut the author

Qusay H. Mahmoud

has published dozens of articles for the Java Developer Connection and
Java Wireless Developer Initiative. He has also presented tutorials at a number of
international conferenc
es. He is the author of Distributed Programming with Java (Manning
Publications, 1999) and Wireless Java (O'Reilly & Associates, 2002).