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 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.