Corba Lab & Reference
Corba Lab & Reference
The Java 2 Platform, Standard Edition 1.4 (J2SE 1.4) has introduced several new features and
enhancements for the Common Object Request Broker Architecture (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 detailed description of the POA and shows you how to use it to develop
more portable CORBA applications. It then:
1
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 part 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.
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 the
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 created POA. You
can use:
p[0] = rootPOA.createt_thread_policy(
ThreadPolicyValue.ORB_CTRL_MODEL)
2
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 show 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 is 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
active (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 transparent 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:
o TRANSIENT: The objects cannot outlive the POA instance in which they are
created (this is the default policy).
o PERSISTENT: 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.PERSISTENT);
As you can see from the above two example policies, to create a policy use the
create_nameOf_policy(policNameValue.value) syntax.
This policy can be used to specify whether the servants must have unique object identities.
The value for this policy can be:
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);
3
• ID Assignment Policy
This policy can be used to specify whether object IDs are generated by the application or by
the ORB. The options are:
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);
This policy specifies whether the created POA retains active servants in an object map. The
options are:
o RETAIN: Indicates the POA will retain active object in a map (this is the default).
o 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);
Use this policy to specify how you wish requests to be processed by the created POA. The
options are:
The following snippet of code shows how to create a request processing policy where
requests are dispatched to the default servant:
4
p[5] = create_request_processing_policy(
RequestProcessingPolicyValue.USE_DEFAULT_SERVANT);
This policy specifies whether implicit activation of servants is supported in the created POA.
The options are (the default is none):
Note that the root POA always has the following policies:
1. Name of the POA, which must be unique with respect to all other POAs with the same
parent.
2. POA Manager to be associated 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.
5
When a POAManager object is created, 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();
Without this statement, all calls to a servant will hang in a queue because the POAManager is in a
HOLD state.
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 ways:
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.
1. Explicitly activate a servant and associate it with an object reference: 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");
NamingContextExt rootctx =
NamingContextExtHelper.narrow(obj);
NameComponent nc[] = rootctx.to_name(
"PersistentMathServer");
rootctx.rebind(nc,
6
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.
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 skeletons. 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:
7
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 or 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 implement 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 am
using an array holder simply because I am using the out parameter as a holder for the output
array.
import ArithApp.*;
import org.omg.CORBA.*;
The next step is to develop the server. A sample server is shown in Code Sample 3. The server
performs the following tasks:
8
import ArithApp.*;
import org.omg.CORBA.*;
import org.omg.CosNaming.*;
import org.omg.PortableServer.*;
import org.omg.PortableServer.POA;
import org.omg.CosNaming.NamingContextPackage.*;
System.out.println("AddServer
ready to add up your arrays ....");
Now, implement the client. A sample client is shown in Code Sample 4. The client code
performs the following tasks:
9
import ArithApp.*;
import org.omg.CORBA.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
System.out.println("Handle
obtained on server object: " + impl);
} catch (Exception e) {
System.out.println("ERROR : " + e) ;
e.printStackTrace(System.out);
}
}
}
Now you can compile the classes AddImpl, AddServer, AddClient, and the stubs and skeletons
that were generated by the idlj compiler. This is done using the javac compiler as follows:
The number 2500 is the port number where you want the orbd to run. Note that the
-ORBInitialPort is a require command-line argument.
10
2. Start the AddServer:
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, use the -ORBInitialHost argument to inform the server
where to find the orbd.
You should see the sum of the two arrays as shown in Figure 3.
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 naming 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.
11
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 tnameserv 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
that 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 NamingContextExt and NamingContextExtHelper 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 bootstrap 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:
corbaloc:iiop:[email protected]:3000/TraderService
12
shows how to get an object reference for TraderService from the host SomeDomain.com on
port 3000.
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.
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.
The next step is to implement the interface. The implementation is similar to that in Code
Sample 2. Here, however, we call the implementation the AddServant. The servant is shown in
Code Sample 5.
import ArithApp.*;
import org.omg.CORBA.ORB;
13
The next step is to implement the persistent server. My implementation is shown in Code Sample
6. This server performs the following tasks:
import ArithApp.*;
import org.omg.CORBA.ORB;
import org.omg.CORBA.Object;
import org.omg.CosNaming.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;
14
// Resolve RootNaming 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 =
NamingContextExtHelper.narrow(obj);
The last step is to implement the client. A Sample client is shown in Code Sample 7. The client
performs the following tasks;
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;
15
Add impl = AddHelper.narrow(obj);
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 again 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:
The number 2900 is the port number where you want the orbd to run. Note that the
-ORBInitialPort is a required command-line argument.
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.
16
The servertool can be started as follows (it must be started on the same port number as the
orbd):
As 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 servertool commands, type help at the command prompt as shown in
Figure 5.
To learn more about the servertool, please see the Java IDL Server Tool.
You should see the client printing the sum of the two arrays.
17
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.
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 about 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.
18