An object adapter is the mechanism that connects a
request using an object reference with the proper code to service
that request. The Portable Object Adapter, or POA, is a particular
type of object adapter that is defined by the CORBA specification.
The POA is designed to meet the following goals:
Allow programmers to construct object implementations that are
portable between different ORB products.
Provide support for objects with persistent identities.
Provide support for transparent activation of objects.
Allow a single servant
to support multiple object identities simultaneously.
This document presents an introduction to using the POA with the
Java 2 Platform, Standard Edition. For a more complete description
of the POA, see Chapter 11 of the CORBA 2.3.1
Specification.
Creating and Using the POA
The steps for creating and using a POA will vary according to
the specific application being developed. The following steps
generally occur during the POA life cycle:
Each step is described in more detail in the sections that
follow.
Step 1: Get the root
POA
The first step is to get the first POA, which is called the
rootPOA. The root POA is managed by the ORB and provided
to the application using the ORB initialization interface under the
initial object name "RootPOA".
An example of code that will get the root POA object and cast it
to a POA is:
The Portable Object Adapter (POA) is designed to provide an
object adapter that can be used with multiple ORB implementations
with no rewriting needed to deal with different vendors'
implementations.
The POA is also intended to allow persistent objects -- at
least, from the client's perspective. That is, as far as the client
is concerned, these objects are always alive, and maintain data
values stored in them, even though physically, the server may have
been restarted many times.
The POA allows the object implementer a lot more control over
the object's identity, state, storage, and life cycle. You can
create a POA without defining any policies and the default values
will be used. The root POA has the following policies by
default:
Each policy is discussed briefly in the following topics. For
more information on POA policies, refer to Chapter 11, Portable
Object Adapter of the CORBA/IIOP 2.3.1 Specification at
http://www.omg.org/docs/formal/99-10-07.pdf
Thread Policy
This policy specifies the threading model used with the created
POA. The default is ORB_CTRL_MODEL.
The ThreadPolicyValue can have the following
values:
ORB_CTRL_MODEL - The ORB is responsible for
assigning requests for an ORB-controlled POA to threads.
SINGLE_THREAD_MODEL - Requests for a
single-threaded POA are processed sequentially.
(NOTE: This policy is not supported in the ORB
shipped with Sun's J2SE v.1.4.1 or higher).
Lifespan Policy
This policy specifies the lifespan of the objects implemented in
the created POA. The default is TRANSIENT.
The LifespanPolicyValue can have the following
values:
TRANSIENT - The objects implemented in the POA
cannot outlive the POA instance in which they are first
created.
PERSISTENT - The objects implemented in the POA
can outlive the process in which they are first created.
Object Id Uniqueness Policy
This policy specifies whether the servants activated in the
created POA must have unique object identities. The default is
UNIQUE_ID.
The IdUniquenessPolicyValue can have the following
values:
UNIQUE_ID - Servants activated with that POA
support exactly one Object Id.
MULTIPLE_ID - A servant activated with that POA
may support one or more Object Ids.
Id Assignment Policy
This policy specifies whether Object Ids in the created POA are
generated by the application or by the ORB. The default is
SYSTEM_ID.
The IdAssignmentPolicyValue can have the following
values:
USER_ID - Objects created with that POA are
assigned Object Ids only by the application.
SYSTEM_ID - Objects created with that POA are
assigned a unique object id by the POA. If the POA also has the
PERSISTENT policy, assigned Object Ids must be unique
across all instantiations of the same POA.
Servant Retention Policy
This policy specifies whether the created POA retains active
servants in an Active Object Map. The default is
RETAIN.
The ServantRetentionPolicyValue can have the
following values.
RETAIN - to indicate that the POA will retain
active servants in its Active Object Map.
NON_RETAIN - to indicate Servants are not retained
by the POA.
Request Processing Policy
This policy specifies how requests are processed by the created
POA. The default is USE_ACTIVE_OBJECT_MAP_ONLY.
The RequestProcessingPolicyValue can have the
following values:
USE_ACTIVE_OBJECT_MAP_ONLY - If the object ID is
not found in the Active Object Map, an
OBJECT_NOT_EXIST exception is returned to the client.
The RETAIN policy is also required.
USE_DEFAULT_SERVANT - If the object ID is not
found in the Active Object Map or the NON_RETAIN
policy is present, and a default servant has been registered with
the POA using the set_servant operation, the request
is dispatched to the default servant.
USE_SERVANT_MANAGER - If the object ID is not
found in the Active Object Map or the NON_RETAIN
policy is present, and a servant manager has been registered with
the POA using the set_servant_manager operation, the
servant manager is given the opportunity to locate or activate a
servant or raise an exception.
Implicit Activation Policy
This policy specifies whether implicit activation of servants is
supported in the created POA. The default value is
IMPLICIT_ACTIVATION.
The ImplicitActivationPolicyValue can have the
following values:
IMPLICIT_ACTIVATION - Indicates implicit
activation of servants. This requires SYSTEM_ID and
RETAIN policies to be set.
NO_IMPLICIT_ACTIVATION - Indicates no implicit
servant activation.
Step 3: Create the POA
Creating a new POA allows the application developer to declare
specific policy choices for the new POA and to provide a different
adapter activator and servant manager (these are callback objects
used by the POA to activate POAs on demand and activate servants).
Creating new POAs also allows the application developer to
partition the name space of objects, as Object Ids are interpreted
relative to a POA. Finally, by creating new POAs, the developer can
independently control request processing for multiple sets of
objects.
A POA is created as a child of an existing POA using the
create_POA operation on the parent POA. To create a new
POA, pass in the following information:
Name of the POA. The POA is given a name that must be unique
with respect to all other POAs with the same parent. In the
following example, the POA is named childPOA.
POA Manager. Specify the POA Manager to be associated with the
new POA. If, as is shown in the following example, null is
passed for this parameter, a new POA Manager will be created. The
user can also choose to pass the POA Manager of another POA.
Policy List. Specify the policy list to be associated with the
POA to control its behavior. In the following example, a persistent
lifespan policy has already been defined for this POA.
// Create a POA by passing the Persistent Policy
POA persistentPOA = rootPOA.create_POA("childPOA", null,
persistentPolicy );
Step 4: Activate the POAManager
Each POA object has an associated POAManager object
that controls the processing state of the POAs with which it is
associated, such as whether requests to the POA are queued or
discarded. The POAManager can also deactivate the POA.
A POA Manager may be associated with one or more POA objects.
The POAManager can have the following states:
Holding - In this state, associated POAs will queue incoming
requests.
Active - In this state, associated POAs will start processing
requests.
Discarding - In this state, associated POAs will discard
incoming requests.
Inactive - In this state, associated POAs will reject the
requests that have not begun executing as well as any new
requests.
POA Managers are not automatically activated when they are
created. The following code snippet shows how the
POAManager is activated in the Hello World: Persistent Server
example. If the POA Manager is not activated in this way, all calls
to the Servant will hang because, by default, the POA
Manager is in the HOLD state.
// Activate PersistentPOA's POAManager. Without this step,
// all calls to Persistent Server will hang because POAManager
// will be in the 'HOLD' state.
persistentPOA.the_POAManager().activate( );
Step 5:
Activate the servants
The following information is quoted from section 11.2.5 of the
CORBA Specification.
At any point in time, a CORBA object may or may not be
associated with an active servant.
If the POA has the RETAIN policy, the servant and
its associated Object Id are entered into the Active Object Map of
the appropriate POA. This type of activation can be accomplished in
one of the following ways.
The server application itself explicitly activates individual
objects (via the activate_object or
activate_object_with_id operations).
The server application instructs the POA to activate objects on
demand by having the POA invoke a user-supplied servant manager.
The server application registers this servant manager with
set_servant_manager.
Under some circumstances (when the
IMPLICIT_ACTIVATION policy is also in effect and the
language binding allows such an operation), the POA may implicitly
activate an object when the server application attempts to obtain a
reference for a servant that is not already active (that is, not
associated with an Object Id).
If the USE_DEFAULT_SERVANT policy is also in
effect, the server application instructs 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 this
servant with set_servant.
If the POA has the NON_RETAIN policy, for every
request, the POA may use either a default servant or a servant
manager to locate an active servant. From the POA's point of view,
the servant is active only for the duration of that one request.
The POA does not enter the servant-object association into the
Active Object Map.
When using RMI-IIOP technology, your implementations use
delegation (known as the Tie model) to associate your
implementation with the interface. When you create an instance of
your implementation, you also need to create a Tie object to
associate it with a CORBA interface. The following code snippet
shows how to activate the Tie, if the POA policy is
USE_ACTIVE_OBJECT_MAP_ONLY. This sample code is from
the RMI-IIOP with
POA example.
_HelloImpl_Tie tie = (_HelloImpl_Tie)Util.getTie( helloImpl );
String helloId = "hello";
byte[] id = helloId.getBytes();
tPOA.activate_object_with_id( id, tie );
The CORBA Specification discusses creating object references
(section 11.2.4), activating objects (section 11.2.5), and
processing requests (section 11.2.6) in more detail than is done in
this document. Please refer to the CORBA 2.3.1
Specification for more information.
Step 6:
Create the object reference
Object references are created in servers. Once created, they may
be exported to clients. Object references encapsulate object
identity information and information required by the ORB to
identify and locate the server and the POA with which the object is
associated. References are created in the following ways:
Explicitly activate a servant and associate it with an object
reference.
The following example is from Hello World: Persistent Server. This
example uses the servant_to_reference operation to map
an activated servant to its corresponding object reference.
// Resolve Root Naming context and bind a name for the
// servant.
org.omg.CORBA.Object obj = orb.resolve_initial_references(
"NameService" );
NamingContextExt rootContext = NamingContextExtHelper.narrow( obj );
NameComponent[] nc = rootContext.to_name(
"PersistentServerTutorial" );
rootContext.rebind( nc, persistentPOA.servant_to_reference(
servant ) );
Server application directly creates a reference.
The following example is from the RMI-IIOP with POA
example. In this example, the following code directly creates a
reference. In doing so, they bring the abstract object into
existence, but do not associate it with an active servant.
// Publish the object reference using the same object id
// used to activate the Tie object.
Context initialNamingContext = new InitialContext();
initialNamingContext.rebind("HelloService",
tPOA.create_reference_with_id(id,
tie._all_interfaces(tPOA,id)[0]) );
Server application causes a servant to implicitly activate
itself.
The behavior can occur only if the POA has been created with the
IMPLICIT_ACTIVATION policy, which is the default
behavior.
Once an reference is created in the server, it can be made
available to clients. For more information on creating object
references and exporting to clients, please refer to section 11.2.4
of the CORBA 2.3.1
Specification for more information.
An adapter activator is optional. You would use
an adapter activator if POAs need to be created during request
processing. If all needed POAs are created when the application is
executed, an adapter activator is not required.
An adapter activator supplies a POA with the ability to create
child POAs on demand, as a side-effect of receiving a request that
names the child POA (or one of its children), or when the
find_POA method is called with an activate parameter
value of TRUE. The ORB will invoke an operation on an adapter
activator when a request is received for a child POA that does not
currently exist. The adapter activator can then create the required
POA on demand.
A request must be capable of conveying the Object Id of the
target object as well as the identification of the POA that created
the target object reference. When a client issues a request, the
ORB first locates an appropriate server (perhaps starting one if
needed) and then it locates the appropriate POA within that
server.
If the POA does not exist in the server process, the application
has the opportunity to re-create the required POA by using an
adapter activator. An adapter activator is a user-implemented
object that can be associated with a POA. It is invoked by the ORB
when a request is received for a non-existent child POA. The
adapter activator has the opportunity to create the required POA.
If it does not, the client receives the
ADAPTER_NONEXISTENT exception.
Once the ORB has located the appropriate POA, it delivers the
request to that POA. The further processing of that request depends
both upon the policies associated with that POA as well as the
object's current state of activation.
Servant Managers are optional. You would use a servant manager
to allow the POA to activate servants on demand when a request for
an inactive object is received. If your server loads all objects
when it starts up, you do not need a servant manager.
A servant manager is a callback object that the
application developer can associate with a POA. The ORB will invoke
operations on servant managers to activate servants on demand, and
to deactivate servants. Servant managers are responsible for
managing the association of an object reference (as characterized
by its Object Id value) with a particular servant, and for
determining whether an object reference exists or not. Each servant
manager type contains two operations, the first called to find and
return a servant and the second to deactivate a servant. The
operations differ according to the amount of information usable for
their situation.
To use servant managers, the USE_SERVANT_MANAGER
policy must be set. Once set, the type of servant manager used in a
particular situation depends on other policies in the POA. The two
types of servant managers are:
When the POA has the NON_RETAIN policy, it uses
servant managers that are ServantLocators. Because the
POA knows that the servant returned by this servant manager will be
used only for a single request, it can supply extra information to
the servant manager's operations and the servant manager's pair of
operations may be able to cooperate to do something different than
a ServantActivator. When the POA uses the
ServantLocator interface, immediately after performing
the operation invocation on the servant returned by preinvoke, the
POA will invoke postinvoke on the servant manager, passing the
ObjectId value and the Servant value as parameters (among others).
This feature may be used to force every request for objects
associated with a POA to be mediated by the servant manager.
This type is typically used to activate transient objects.
For more information on Servant Managers, please refer to
section 11.3.4 of the CORBA 2.3.1
Specification.
POA Q&A
Is POAManager.activate() required for a newly created
POA?
POAManager.activate() is required for a newly created
POA if a null is passed for the POAManager parameter to
POA::createPOA . If null is passed, a new
POAManager is created and associated with the created POA.
In this case, POAManager.activate() is needed.
To control several POAs with the same POAManager, you
would:
Create a POA or use the rootPOA
Obtain the POA's manager via POA::the_POAManager
Pass the POAManager to subsequent createPOA
calls
There is no implicit relationship between the Root POA's
POAManager and other POAs unless explicitly programmed by
the programmer as shown above.
For more information about the Portable Object Adapter, read
Chapter 11 of the CORBA/IIOP v.2.3.1 Specification from the Object
Management Group's Web site. At the time of this writing, the
specification can be found at http://www.omg.org/docs/formal/99-10-07.pdf.