Chapter 6 POA Policies
Section 5.6 discussed several different kinds of POA, such as “simple”, “lazy loader”, “cache” and “default servant”. However, that section did not explain how to create a POA of a specific kind. How to create a POA of a specific kind is the topic of this chapter.
CORBA uses the term policy to mean quality of service (QoS). A POA is created by calling the create_POA() operation. One of the parameters to this operation is a sequence of policy objects. Section 6.1 discusses the different sub-types of Policy object that are available, and how some of them combine together to create different kinds of POA. Finally, Section 6.2 briefly outlines the APIs that are used to create a policy object.
6.1 Available POA Policies
Some of the POA policies determine what kind of POA is created; these policies are discussed in Section 6.1.1. Some other POA policies are used to specify other QoS offered by the POA, and these are discussed in Sections 6.1.2–6.1.6.
6.1.1 Policies that Determine the POA’s Kind
A policy object is a “wrapper” around an enum value. In this section, I discuss the enum values; a discussion of how to create object wrappers around these values is deferred until Section 6.2.
The following three enum types, when combined together, determine a POA’s kind:
enum ServantRetentionPolicyValue {RETAIN, NON_RETAIN}; enum IdUniquenessPolicyValue {UNIQUE_ID, MULTIPLE_ID}; enum RequestProcessingPolicyValue {USE_ACTIVE_OBJECT_MAP_ONLY, USE_DEFAULT_SERVANT, USE_SERVANT_MANAGER};
The first enum determines whether or not object ids are retained in the POA by an active object map (AOM). Many developers find these enum values difficult to remember. More meaningful names might have been HAS_AN_AOM and DOES_NOT_HAVE_AN_AOM instead of RETAIN and NON_RETAIN, respectively.
The second enum determines whether there is a one-to-one mapping (the UNIQUE_ID value) or a many-to-one mapping (MULTIPLE_ID) between object ids and servants. The MULTIPLE_ID policy allows one servant to represent many CORBA objects. You must use the MULTIPLE_ID policy for the “default servant” POA kind (Section 5.6.4). For the other kinds of POA, you can use either policy, but the UNIQUE_ID policy is what is desired most of the time.
The third enum determines whether the POA has an AOM, a default servant and/or a servant manager:
- The USE_ACTIVE_OBJECT_MAP_ONLY policy value is used to obtain the “simple” kind of POA (Section 5.6.1). You must combine this policy with RETAIN. You typically also combine this with UNIQUE_ID, but this is not required.
- The USE_DEFAULT_SERVANT policy value is used to obtain the “default servant” kind of POA (Section 5.6.4). You must combine this policy with MULTIPLE_ID. You typically also combine this with NON_RETAIN, but this is not required.
- If you combine USE_SERVANT_MANAGER with RETAIN then you obtain a “lazy loader” POA (Section 5.6.2). If, instead, you combine it with NON_RETAIN then you obtain a “cache” POA (Section 5.6.3). The USE_SERVANT_MANAGER policy is also typically combined with UNIQUE_ID, but this is not required.
6.1.2 Multi- and Single-threaded Policy Values
The following enum is used to specify how a POA utilizes threads to dispatch incoming requests:
enum ThreadPolicyValue {ORB_CTRL_MODEL, SINGLE_THREAD_MODEL, MAIN_THREAD_MODEL};
These policy values are discussed in the following sub-subsections.
6.1.2.1 The ORB_CTRL_MODEL Policy Value
The ORB_CTRL_MODEL policy specifies that the ORB runtime system has control over how incoming requests are dispatched. This policy value has very under-specified semantics:
- Most CORBA products use multiple threads to dispatch requests with this policy. However, the details of how the multiple requests are used varies widely from one CORBA product to another. For example, a CORBA product might: (1) use a pool of threads to dispatch incoming requests; (2) use a thread-per-request model; (3) use a separate thread per (socket) connection for dispatching requests; or (4) some other strategy.
- The MICO freeware implementation of CORBA was originally implemented without multi-threading support. In MICO, ORB_CTRL_MODEL used to employ a single-threaded dispatch algorithm, and this was considered to be a compliant implementation. Multi-threading support (and a multi-threaded dispatch algorithm) has since been retrofitted to MICO.
The under-specified semantics of ORB_CTRL_MODEL hinder the portability of CORBA applications. Many people hope that the OMG will add better-defined multi-threading policy values in the future.
6.1.2.2 The SINGLE_THREAD_MODEL and MAIN_THREAD_MODEL Policy Values
You would think that the SINGLE_THREAD_MODEL policy would have obvious semantics. However, it is actually ambiguous:
- Some CORBA vendors interpreted this policy to mean that all incoming requests are dispatched through the application’s main thread. With this interpretation, there is serialization of request dispatch across all the SINGLE_THREAD_MODEL POAs within a process.
- Other CORBA vendors interpreted this policy to mean that there is concurrency between multiple SINGLE_THREAD_MODEL POAs, but serialization within a POA.
When the OMG became aware of this ambiguity, they resolved it by declaring that SINGLE_THREAD_MODEL had the latter set of semantics, and they introduced a new enum value, called MAIN_THREAD_MODEL that had the first set of semantics.
Readers should note that some CORBA products that ascribed the “wrong” semantics to SINGLE_THREAD_MODEL have not yet added support for the (newer) MAIN_THREAD_MODEL policy value. For this reason, it is important to carefully read the documentation of a CORBA product to check what semantics it provides for SINGLE_THREAD_MODEL POAs.
6.1.3 Policy Values for Object Lifetimes and Naming
The following enum types are used to specify the lifetimes of objects and how they are assigned object ids:
enum LifespanPolicyValue {TRANSIENT, PERSISTENT}; enum IdAssignmentPolicyValue {USER_ID, SYSTEM_ID};
CORBA uses the term transient to mean temporary. Thus, the TRANSIENT policy value specifies that object references (for objects within the POA) are valid only for the duration of the server process. In other words, the object references are not valid if the server is killed and restarted. How a CORBA product enforces this is an implementation detail, but it is typically done by embedding a timestamp into IORs. The CORBA runtime system can use this timestamp information to differentiate between references to objects that are “similar” but have been created in different runs of a server process.
The PERSISTENT policy value specifies that object references (for objects within the POA) are valid even if the server is killed and restarted.
It is important to note that the TRANSIENT and PERSISTENT policies determine the lifetimes of object references. These policies do not determine whether data associated with an object is maintained in volatile RAM or in a persistent store, such as a file or database. The following are typical examples of how these policy values are used:
- Some CORBA objects, such as Customer or Account, are associated with records in a database. It makes sense that such objects are kept in a PERSISTENT POA, so that a client’s reference to such an object/data will be valid if the server process dies and is restarted.
- Some objects in a server process—such as an administration or factory object—are not associated with records in a database. However, these “stateless” objects are also normally held in a PERSISTENT POA. This ensures that a client’s reference to such an object will be valid if the server process dies and is restarted.
- Some objects in a server process are intended to be temporary. One example is CosNaming::BindingIterator in the Naming Service, which is used to traverse over a collection of values. Another example is a LoginSession object that holds details specific to a client that is currently “logged in”. Although such objects are stateful, they typically maintain their state in RAM, rather than in a database. Because of the temporary nature of these objects, there is no requirement for a client reference to such an object to remain valid if the server process dies and is restarted. In fact, it is preferable for the object reference to not be valid across restarts of the server. For this reason, such objects should be held in a TRANSIENT POA.
In CORBA terminology, programmers are referred to as users. Hence, the USER_ID policy value indicates that the programmer specifies the object id when activating (inserting) a servant into a POA. In this case, the programmer uses the activate_object_with_id() operation, as shown below:
poa.activate_object_with_id(obj_id, sv);
The SYSTEM_ID policy indicates that the CORBA runtime system picks a unique object id when a servant is activated into a POA. In this case, the programmer uses the activate_object() operation, as shown below:
obj_id = poa.activate_object(sv);
Technically, the TRANSIENT and PERSISTENT policies are independent of the USER_ID and SYSTEM_ID policies. However, PERSISTENT is almost always combined with USER_ID, for the following reasons:
- If a programmer wishes to maintain the state of an object in a database then he or she can use the primary key of a row in a database table as the object id. This provides a very simple way to map between a CORBA object and the corresponding data in the database.
- A stateless singleton—such as an administration or factory object—should be in a POA with the USER_ID policy so that the same object id can be used for the object every time the server process starts. In this way, a client’s reference to the object will be valid across restarts of the server.
The TRANSIENT policy is usually combined with SYSTEM_ID because programmers are rarely concerned with assigning meaningful names to temporary objects.
6.1.4 Transactional Object Policy Values
Some client-server systems require the ability for a database transaction to span multiple operation calls from a client to one server and/or the ability for a transaction to span multiple databases. Such client-server interactions require use of the CORBA Object Transaction Service (OTS), which is discussed in Chapter 21.
A POA policy is used to indicate whether or not the objects within that POA can take part in distributed transactions.1 The policy can have one of the following values:
- REQUIRES
- This policy value indicates that all invocations on objects within the POA must be part of a transaction.2
- FORBIDS
- This policy value indicates that all invocations on objects within the POA must not be part of a transaction.
- ADAPTS
- This policy value indicates that objects are sensitive to the presence or absence of a transaction and can “adapt” to either style of invocation.
6.1.5 Implicit and Explicit Activation Policy Values
Most policy values used with POAs have some effect that either is visible to clients or affects the high-level architecture of the server program. The ImplicitActivationPolicyValue is different in that it controls a relatively minor aspect of coding a server.
enum ImplicitActivationPolicyValue {IMPLICIT_ACTIVATION, NO_IMPLICIT_ACTIVATION};
To make a servant represent a CORBA object requires three steps:
- You create a servant.
- You activate (insert) the servant into a POA.
- You call _this() on the servant to obtain the object reference of the CORBA object that it represents.
If you use the NO_IMPLICIT_ACTIVATION policy then you must execute all three steps. However, if you use the IMPLICIT_ACTIVATION policy then you can optionally omit step 2 because step 3 will implicitly activate the servant if it is not already activated. So the benefit of IMPLICIT_ACTIVATION is that can optimize away one line of code associated with the creation of CORBA objects. This is a relatively minor benefit, and many people have religious feelings over whether the IMPLICIT_ACTIVATION policy is a good policy or one to be avoided. On the one hand, some people like being able to optimize away a line of code in several places within a server application. On the the hand, the steeper learning curve associated with yet-another policy value arguably outweighs this benefit.
Note that if you use IMPLICIT_ACTIVATION then you must combine it with SYSTEM_ID.
6.1.6 Proprietary Policy Values
The preceding subsections have discussed CORBA-compliant policy values that can be used when creating POAs. A CORBA product is allowed to define additional, proprietary policies. Some CORBA products do this in order to give programmers greater control over choosing the QoS offered by objects. You have to consult the documentation of a particular CORBA product to find out what, if any, proprietary policies it provides.
6.2 Creating Policy Objects and POAs
Policy objects were first introduced with the POA specification. The POA specification initially defined 7 types of policy and defined a separate operation for creating each of these 7 kinds of policy object. For example, you can create a ThreadPolicy object by invoking the following operation on an existing POA:
ThreadPolicy create_thread_policy( in ThreadPolicyValue value);
The parameter to this operation is an enum value, and the operation creates a (subtype of) policy “wrapper” around it.
Having defined the POA specification, the OMG then realized that the concept of policy objects could be applied to other parts of CORBA too. However, having to add a new create-style operation to an existing interface for each new type of policy would create a versioning problem. Because of this, the OMG decided to define a “generic” API that could be used to create any kind of policy object. The work on defining this generic API was performed as part of CORBA Messaging (Chapter 16). Creation of transactional policy values (Section 6.1.4) is performed using this newer, generic API.
Overall, the CORBA APIs for creating POA policy objects and then using these to create POAs are quite verbose. The Creation of POA Hierarchies Made Simple chapter of the CORBA Utilities package [McH] discusses a utility class (available in C++ and Java) that dramatically reduces the amount of code required to create POAs.