More POA architecture

POAManagers

POAs are used to dispatch the requests to their servants. However, there must be one way to handle the load on POAs and servants because we may have huge amounts of objects making requests to one object at the same time. This is achieved through the use of POAManagers. Each POA is associated to a POAManager.

POAManagers receive requests and send them to their POAs depending on their running state. A POAManager may be in one of 4 running states: active , inactive, holding or discarding. If in the active state, requests are send to POAs, in the holding state, requests are queued till the POAManager gets back to the active state and in the discarding state, request are simply thrown out.

Generally, there is no need to write your own implementation of a POAManager: you can use the POAManager of the RootPOA thanks to the following interface:

module PortableServer {
interface POA {

	POA create_POA (in string adapter_name, 
			in POAManager a_POAManager,
			in CORBA::PolicyList policies)
		raises (AdapterAllreadyExists, 
			InvalidPolicy);
	void destroy (in boolean etherealize_objects,
			in boolean wait_for_completion);
	POA find_poa (in string adapter_name, 
			in POAManager a_POAManager
			in CORBA::PolicyList ListPolicies);

	readonly attribute POA the_parent;
	readonly attribute string the_name;
	readonly attribute POAManager the_POAManager;
};
};

with:

PortableServer_POA root_poa;
PortableServer_POAManager root_poa_manager;
root_poa = CORBA_ORB_resolve_initial_references (orb, 
	"RootPOA", 
	&ev);
root_poa_manager = PortableServer_POA_get_the_POAManager (root_poa, 
	&ev);

PortableServer_POA_create_poa (root_poa, "my_own_poa", 
	root_poa_manager, 
	NULL, 
	&ev);

a POA is always created as the child of another POA: the RootPOA is the root of the POA tree. It is possible to find a particular child provided you know its name with the find_poa method. The the_parent attribute holds the parent POA, and the the_name attribute holds the POA name assigned with the create_poa method. destroy_poa will destroy the POA passed as parameter but also all of its children.

To hold your servants, it is thus a good idea to create a child POA of the RootPOA and use it as the default_poa member of the _base_epv of your servants. You must also make sure that the POAManager used for your POA (as i already said, generally the RootPOA's own POAManager) is in the active state as POAManagers are initialized in the holding state. Sample code for this is presented in the chapter's last section.

POA Policies

To each POA is also associated a set of Policies. Policies allow you to control very precisely the way your POA lives, dies, re-births...

Each POA is given its policies upon creation through the in CORBA::PolicyList policies parameter of the PortableServer_POA_createPOA function.

If a NULL parameter is passed, the default policies are used. Here is the list of the policy types and their possible values. Default values are like this.

Table 4-2. POA Policies

Policy typePossible valuesPolicy use
ThreadPolicyORB_CTRL_MODEL, SINGLE_THREAD_MODELIn SINGLE_THREAD, only one POA thread may exist.
LifespanPolicyTRANSIENT, PERSISTENTIn TRANSIENT mode, object implementations will disappear with their POA. Otherwise, a new POA is created when necessary.
ObjectIdUniquenessUNIQUE_ID, MULTIPLE_IDEach object within a given POA has a unique ObjectId.
IdAssignmentPolicyUSER_ID, SYSTEM_IDObjectId are either given by the user or the system. ie: you may use only one of the 2 functions for a given POA: activate_object or activate_object_with_id .
ServantRetentionPolicyRETAIN, NON_RETAINIn NON RETAIN mode, a request to a servant already processing another request will throw an ObjectNotExist exception.
RequestProcessingPolicyUSE_ACTIVE_OBJECT_MAP_ONLY, USE_DEFAULT_SERVANT, USE_SERVANT_MANAGERAny request to a servant not found in the POA map will result in either a call to a default servant, an ObjectNotExist exception or a request to the Servant Manager to create the requested servant.
ImplicitActivationPolicyIMPLICIT_ACTIVATION, NO_IMPLICIT_ACTIVATION If NO_IMPLICIT_ACTIVATION is used, the programmer will need to activate all the created servants.

These policy objects should be created with the following calls which are part of the POA interface.

module PortableServer {
interface POA {

ThreadPolicy create_thread_policy (in ThreadPolicyValue value);
LifespanPolicy create_lifespan_policy (in LifespanPolicyValue value);
IdUniquenessPolicy create_id_uniqueness_policy 
	(in IdUniquenessPolicyValue value);
IdAssignementPolicy create_id_assignment_policy 
	(in IdAssignmentPolicyValue value);
ImplicitActivationPolicy create_implicit_activation_policy 
	(in ImplicitActivationPolicyValue value);
ServantRetentionPolicy create_servant_retention_policy 
	(in ServantRetentionPolicyValue value);
ProcessingPolicy create_processing_policy 
	(in ProcessingPolicyValue value);
};
};

Then these policies should be put together in a CORBA::PolicyList and passed to the create_poa function to create the POA with the correct policies. This set of policies gives the programmer great power on server programming as they very precisely describe the server behavior and allow the programmer to control the server load. Here is some sample code to create a new POA using these policies. Note that when a policy type is not present in the PolicyList, the policy type is defaulted to the default value stated in the precedent table.

// idl Policy Object 
module CORBA {
typedef unsigned long PolicyType;
interface Policy
{
	readonly attribute PolicyType policy_type;
	Policy copy();
	void destroy();
};

typedef sequence <Policy> PolicyList;
};
/* C code building a PolicyList object */

CORBA_Policy policies[2];
CORBA_PolicyList list = {2, 2, policies};

policies[1] = PortableServer_POA_create_Id_Uniqueness_Policy (MULTIPLE_ID, 
	&ev);
policies[2] = PortableServer_POA_create_Id_Assignment_Policy (USER_ID, 
	&ev);
PortableServer_POA_create_poa (poa, 
	"my_poa", 
	poa_manager, 
	list, 
	&ev);

CORBA_Policy_destroy (policies[1]);
CORBA_Policy_destroy (policies[2]);

A nice trick/hack

It is often necessary to pass to your implementation functions some common parameters. The idea is that all your functions receive as first parameter a pointer to a PortableServer_Servant structure. Look at the following code:

typedef struct {
	PortableServer_Servant servant;
	long my_field;
	long my_second_field;
	void *pointer_to_my_structure;
} my_POA_FruitsBasket_Apple

my_POA_FruitsBasket_Apple Apple;

It happens that &Apple is a pointer to the Apple structure but also to the first field of the structure as C assures that (&Apple == &Apple.servant) is true. This means that if you register your servant with a pointer to Apple, this pointer will be passed to all the implementation functions. This is possible because a my_POA_FruitsBasket_Apple pointer is also a pointer to a PortableServer_Servant structure.