VisiBroker for C++ Developer’s Guide : Using POAs

Using POAs
What is a Portable Object Adapter?
Portable Object Adapters (POAs) replace Basic Object Adapters; they provide portability on the server side.
A POA is the intermediary between the implementation of an object and the VisiBroker ORB. In its role as an intermediary, a POA routes requests to servants and, as a result may cause servants to run and create child POAs if necessary.
Servers can support multiple POAs. At least one POA must be present, which is called the rootPOA. The rootPOA is created automatically for you. The set of POAs is hierarchical; all POAs have the rootPOA as their ancestor.
Servant managers locate and assign servants to objects for the POA. When an abstract object is assigned to a servant, it is called an active object and the servant is said to incarnate the active object. Every POA has one Active Object Map which keeps track of the object IDs of active objects and their associated active servants.
Note
Users familiar with versions of VisiBroker prior to 6.0 should note the change in inheritance hierarchy to support CORBA Specification 2.6, which requires local interfaces. For example, a ServantLocator implementation would now extend from org.omg.PortableServer._ServantLocatorLocalBase instead of org.omg.PortableServer.ServantLocatorPOA.
Figure 6
POA terminology
Following are definitions of some terms with which you will become more familiar as you read through this section.
Steps for creating and using POAs
Although the exact process can vary, following are the basic steps that occur during the POA lifecycle are:
1
2
3
4
5
6
Depending on your needs, some of these steps may be optional. For example, you only have to activate the POA if you want it to process requests.
POA policies
Each POA has a set of policies that define its characteristics. When creating a new POA, you can use the default set of policies or use different values to suit your requirements. You can only set the policies when creating a POA; you can not change the policies of an existing POA. POAs do not inherit the policies from their parent POA.
The following lists the POA policies, their values, and the default value (used by the rootPOA).
Thread policy The thread policy specifies the threading model to be used by the POA.
The thread policy can have the following values:
ORB_CTRL_MODEL: (Default) The POA is responsible for assigning requests to threads. In a multi-threaded environment, concurrent requests may be delivered using multiple threads. Note that VisiBroker uses multi-threading model.
SINGLE_THREAD_MODEL: The POA processes requests sequentially. In a multi-threaded environment, all calls made by the POA to servants and servant managers are thread-safe.
MAIN_THREAD_MODEL: Calls are processed on a distinguished “main” thread. Requests for all main-thread POAs are processed sequentially. In a multi-threaded environment, all calls processed by all POAs with this policy are thread-safe. The application programmer designates the main thread by calling ORB::run() or ORB::perform_work(). For more information about these methods, see “Activating objects”.
Lifespan policy The lifespan policy specifies the lifespan of the objects implemented in the POA.
The lifespan policy can have the following values:
TRANSIENT: (Default) A transient object activated by a POA cannot outlive the POA that created it. Once the POA is deactivated, an OBJECT_NOT_EXIST exception occurs if an attempt is made to use any object references generated by the POA.
PERSISTENT: A persistent object activated by a POA can outlive the process in which it was first created. Requests invoked on a persistent object may result in the implicit activation of a process, a POA and the servant that implements the object.
Object ID Uniqueness policy The Object ID Uniqueness policy allows a single servant to be shared by many abstract objects.
The Object ID Uniqueness policy can have the following values:
UNIQUE_ID: (Default) Activated servants support only one Object ID.
MULTIPLE_ID: Activated servants can have one or more Object IDs. The Object ID must be determined within the method being invoked at run time.
ID Assignment policy The ID assignment policy specifies whether object IDs are generated by server applications or by the POA.
The ID Assignment policy can have the following values:
USER_ID: Objects are assigned object IDs by the application.
SYSTEM_ID: (Default) Objects are assigned object IDs by the POA. If the PERSISTENT policy is also set, object IDs must be unique across all instantiations of the same POA.
Typically, USER_ID is for persistent objects, and SYSTEM_ID is for transient objects. If you want to use SYSTEM_ID for persistent objects, you can extract them from the servant or object reference.
Servant Retention policy The Servant Retention policy specifies whether the POA retains active servants in the Active Object Map.
The Servant Retention policy can have the following values:
RETAIN: (Default) The POA tracks object activations in the Active Object Map. RETAIN is usually used with ServantActivators or explicit activation methods on POA.
NON_RETAIN: The POA does not retain active servants in the Active Object Map. NON_RETAIN must be used with ServantLocators.
ServantActivators and ServantLocators are types of servant managers. For more information on servant managers, see “Using servants and servant managers”.
Request Processing policy The Request Processing policy specifies how requests are processed by the POA.
USE_ACTIVE_OBJECT_MAP_ONLY: (Default) If the Object ID is not listed in the Active Object Map, an OBJECT_NOT _EXIST exception is returned. The POA must also use the RETAIN policy with this value.
USE_DEFAULT_SERVANT: If the Object ID is not listed in the Active Object Map or the NON_RETAIN policy is set, the request is dispatched to the default servant. If no default servant has been registered, an OBJ_ADAPTER exception is returned. The POA must also use the MULTIPLE_ID policy with this value.
USE_SERVANT_MANAGER: If the Object ID is not listed in the Active Object Map or the NON_RETAIN policy is set, the servant manager is used to obtain a servant.
Implicit Activation policy The Implicit Activation policy specifies whether the POA supports implicit activation of servants.
The Implicit Activation policy can have the following values:
IMPLICIT_ACTIVATION: The POA supports implicit activation of servants. There are two ways to activate the servants as follows:
Invoking _this() on the servant.
The POA must also use the SYSTEM_ID and RETAIN policies with this value.
NO_IMPLICIT_ACTIVATION: (Default) The POA does not support implicit activation of servants.
Bind Support policy The Bind Support policy (a VisiBroker-specific policy) controls the registration of POAs and active objects with the VisiBroker osagent. If you have several thousands of objects, it is not feasible to register all of them with the osagent. Instead, you can register the POA with the osagent. When a client request is made, the POA name and the object ID is included in the bind request so that the osagent can correctly forward the request.
The BindSupport policy can have the following values:
BY_INSTANCE: All active objects are registered with the osagent. The POA must also use the PERSISTENT and RETAIN policy with this value.
BY_POA: (Default) Only POAs are registered with the osagent. The POA must also use the PERSISTENT policy with this value.
NONE: Neither POAs nor active objects are registered with the smart agent.
Note
The rootPOA is created with NONE activation policy.
Creating POAs
To implement objects using the POA, at least one POA object must exist on the server. To ensure that a POA exists, a rootPOA is provided during the VisiBroker ORB initialization. This POA uses the default POA policies described earlier in this section.
Once the rootPOA is obtained, you can create child POAs that implement a specific server-side policy set.
POA naming convention
Each POA keeps track of its name and its full POA name (the full hierarchical path name.) The hierarchy is indicated by a slash (/). For example, /A/B/C means that POA C is a child of POA B, which in turn is a child of POA A. The first slash (see the previous example) indicates the rootPOA. If the BindSupport:BY_POA policy is set on POA C, then /A/B/C is registered with the osagent and the client binds with /A/B/C.
If your POA name contains escape characters or other delimiters, VisiBroker precedes these characters with a double back slash (\\) when recording the names internally. For example, if you have coded two POAs in the following hierarchy,
PortableServer::POA_var myPOA1 = rootPOA->create_POA("A/B",
poa_manager,
policies);
PortableServer::POA_var myPOA2 = myPOA1->create_POA("\t",
poa_manager,
policies);
then the client would bind using:
Bank::AccountManager_var manager = Bank::AccountManager::_bind("/A\\/B/\t", managerId);
Obtaining the rootPOA
The following code sample illustrates how a server application can obtain its rootPOA.
// Initialize the ORB.
CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
// get a reference to the root POA
PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);
Note
The resolve_initial_references method returns a value of type CORBA::Object. You are responsible for narrowing the returned object reference to the desired type, which is PortableServer::POA in the previous example.
Setting the POA policies
Policies are not inherited from the parent POA. If you want a POA to have a specific characteristic, you must identify all the policies that are different from the default value. For more information about POA policies, see “POA policies”.
CORBA::PolicyList policies;
policies.length(1);
policies[(CORBA::ULong)0] = rootPOA->create_lifespan_policy(PortableServer::PERSISTENT);
Creating and activating the POA
A POA is created using create_POA on its parent POA. You can name the POA anything you like; however, the name must be unique with respect to all other POAs with the same parent. If you attempt to give two POAs the same name, a CORBA exception (AdapterAlreadyExists) is raised.
To create a new POA, use create_POA as follows:
POA create_POA(POA_Name, POAManager, PolicyList);
The POA manager controls the state of the POA (for example, whether it is processing requests). If null is passed to create_POA as the POA manager name, a new POA manager object is created and associated with the POA. Typically, you will want to have the same POA manager for all POAs. For more information about the POA manager, see “Managing POAs with the POA manager”.
POA managers (and POAs) are not automatically activated once created. Use activate() to activate the POA manager associated with your POA. The following code sample is an example of creating a POA.
CORBA::PolicyList policies;
policies.length(1);
policies[(CORBA::ULong)0] =
rootPOA->create_lifespan_policy(PortableServer::PERSISTENT);
// Create myPOA with the right policies
PortableServer::POAManager_var rootManager = rootPOA->the_POAManager();
PortableServer::POA_var myPOA =
rootPOA->create_POA("bank_agent_poa", rootManager, policies);
Activating objects
When CORBA objects are associated with an active servant, if the POA's Servant Retention Policy is RETAIN, the associated object ID is recorded in the Active Object Map and the object is activated. Activation can occur in one of several ways:
Activating objects explicitly
By setting IdAssignmentPolicy::SYSTEM_ID on a POA, objects can be explicitly activated without having to specify an object ID. The server invokes activate_object on the POA which activates, assigns and returns an object ID for the object. This type of activation is most common for transient objects. No servant manager is required since neither the object nor the servant is needed for very long.
Objects can also be explicitly activated using object IDs. A common scenario is during server initialization where the user invokes activate_object_with_id to activate all the objects managed by the server. No servant manager is required since all the objects are already activated. If a request for a non-existent object is received, an OBJECT_NOT_EXIST exception is raised. This has obvious negative effects if your server manages large numbers of objects.
This code sample is an example of explicit activation using activate_object_with_id.
// Create the servant
AccountManagerImpl managerServant;
// Decide on the ID for the servant
PortableServer::ObjectId_var managerId =
PortableServer::string_to_ObjectId("BankManager");
// Activate the servant with the ID on myPOA
myPOA->activate_object_with_id(managerId,&managerServant);
// Activate the POA Manager
PortableServer::POAManager_var rootManager = rootPOA->the_POAManager();
rootManger->activate();
Activating objects on demand
On-demand activation occurs when a client requests an object that does not have an associated servant. After receiving the request, the POA searches the Active Object Map for an active servant associated with the object ID. If none is found, the POA invokes incarnate on the servant manager which passes the object ID value to the servant manager. The servant manager can do one of three things:
Raise an OBJECT_NOT_EXIST exception that is returned to the client.
The POA policies determine any additional steps that may occur. For example, if RequestProcessingPolicy::USE_SERVANT_MANAGER and ServantRetentionPolicy::RETAIN are enabled, the Active Object Map is updated with the servant and object ID association.
An example of on-demand activation is shown below.
Activating objects implicitly
A servant can be implicitly activated by certain operations if the POA has been created with ImplicitActivationPolicy::IMPLICIT_ACTIVATION, IdAssignmentPolicy::SYSTEM_ID, and ServantRetentionPolicy::RETAIN. Implicit activation can occur with:
POA::servant_to_id member function
_this() servant member function
If the POA has IdUniquenessPolicy::UNIQUE_ID set, implicit activation can occur when any of the above operations are performed on an inactive servant.
If the POA has IdUniquenessPolicy::MULTIPLE_ID set, servant_to_reference and servant_to_id operations always perform implicit activation, even if the servant is already active.
Activating with the default servant
Use the RequestProcessing::USE_DEFAULT_SERVANT policy to have the POA invoke the same servant no matter what the object ID is. This is useful when little data is associated with each object.
This is an example of activating all objects with the same servants
int main(int argc, char* const* argv) {
try {
// Initialize the ORB.
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
PortableServer::Current_var cur = PortableServer::Current::_instance();
// get a reference to the root POA
CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);

CORBA::PolicyList policies;
policies.length(3);
// Create policies for our persistent POA
policies[(CORBA::ULong)0] =
rootPOA->create_lifespan_policy(PortableServer::PERSISTENT);
policies[(CORBA::ULong)1] =
rootPOA>create_request_processing_policy(PortableServer::USE_DEFAULT_SERVANT);
policies[(CORBA::ULong)2] =
rootPOA->create_id_uniqueness_policy(PortableServer::MULTIPLE_ID);
// Create myPOA with the right policies
PortableServer::POAManager_var rootManager = rootPOA->the_POAManager();
PortableServer::POA_var myPOA =
rootPOA->create_POA("bank_default_servant_poa", rootManager,policies);
// Set the default servant
AccountManagerImpl managerServant(cur);
myPOA->set_servant( &managerServant );
// Activate the POA Manager
rootManager->activate();

// Generate two references - one for checking and another for savings.
//Note that we are not creating any
// servants here and just manufacturing a reference which is not
// yet backed by a servant
PortableServer::ObjectId_var an_oid =
PortableServer::string_to_ObjectId("CheckingAccountManager");
CORBA::Object_var cref = myPOA->create_reference_with_id(an_oid.in(),
"IDL:Bank/AccountManager:1.0");
an_oid = PortableServer::string_to_ObjectId("SavingsAccountManager");
CORBA::Object_var sref = myPOA->create_reference_with_id(an_oid.in(),
"IDL:Bank/AccountManager:1.0");
// Write out Checking reference
CORBA::String_var string_ref = orb->object_to_string(cref.in());
ofstream crefFile("cref.dat");
crefFile << string_ref << endl;
crefFile.close();
// Now write out the Savings reference
string_ref = orb->object_to_string(sref.in());
ofstream srefFile("sref.dat");
srefFile << string_ref << endl;
srefFile.close();
cout << "Bank Manager is ready" << endl;
// Wait for incoming requests

orb->run();
}
catch(const CORBA::Exception& e) {
cerr << e << endl;
}
return 1;
}
Deactivating objects
A POA can remove a servant from its Active Object Map. This may occur, for example, as a form of garbage-collection scheme. When the servant is removed from the map, it is deactivated. You can deactivate an object using deactivate_object(). When an object is deactivated, it does not mean that the object is lost forever. It can always be reactivated at a later time.
This is an example of deactivating an object:
// DeActivatorThread
class DeActivatorThread: public VISThread {
private :
PortableServer::ObjectId _oid;
PortableServer::POA_ptr _poa;
public :
virtual ~DeActivatorThread(){}
// Constructor
DeActivatorThread(const PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa ): _oid(oid), _poa(poa) {
// start the thread
run();
}
// implement begin() callback
void begin() {
// Sleep for 15 seconds
VISPortable::vsleep(15);
CORBA::String_var s = PortableServer::ObjectId_to_string (_oid);
// Deactivate Object
cout << "\nDeActivating the object with ID =" << s << endl;
if ( _poa )
_poa->deactivate_object( _oid );
}
};
// Servant Activator
class AccountManagerActivator : public PortableServer::ServantActivator {
public:
virtual PortableServer::Servant incarnate (const
PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa) {
CORBA::String_var s = PortableServer::ObjectId_to_string (oid);
cout << "\nAccountManagerActivator.incarnate called with ID =
                      " << s <<
endl;
PortableServer::Servant servant;
if ( VISPortable::vstricmp( (char *)s, "SavingsAccountManager" )
                       == 0 )
// Create CheckingAccountManager Servant
servant = new SavingsAccountManagerImpl;
else if ( VISPortable::vstricmp( (char *)s,
"CheckingAccountManager")==0)
// Create CheckingAccountManager Servant
servant = new CheckingAccountManagerImpl;
else
throw CORBA::OBJECT_NOT_EXIST();
// Create a deactivator thread
new DeActivatorThread( oid, poa );
// return the servant
return servant;
}
virtual void etherealize (const PortableServer::ObjectId& oid,
PortableServer::POA_ptr adapter,
PortableServer::Servant servant,
CORBA::Boolean cleanup_in_progress,
CORBA::Boolean remaining_activations) {
// If there are no remaining activations i.e. ObjectIds associated
// with the servant delete it.
CORBA::String_var s = PortableServer::ObjectId_to_string (oid);
cout << "\nAccountManagerActivator.etherealize called with ID =
                          " << s
<< endl;
if (!remaining_activations)
delete servant;
}
};
Using servants and servant managers
Servant managers perform two types of operations: find and return a servant, and deactivate a servant. They allow the POA to activate objects when a request for an inactive object is received. Servant managers are optional. For example, servant managers are not needed when your server loads all objects at startup. Servant managers may also inform clients to forward requests to another object using the ForwardRequest exception.
A servant is an active instance of an implementation. The POA maintains a map of the active servants and the object IDs of the servants. When a client request is received, the POA first checks this map to see if the object ID (embedded in the client request) has been recorded. If it exists, then the POA forwards the request to the servant. If the object ID is not found in the map, the servant manager is asked to locate and activate the appropriate servant. This is only an example scenario; the exact scenario depends on what POA policies you have in place.
Figure 7
There are two types of servant managers: ServantActivator and ServantLocator. The type of policy already in place determines which type of servant manager is used. For more information on POA policy, see “POA policies”. Typically, a Servant Activator activates persistent objects and a Servant Locator activates transient objects.
To use servant managers, RequestProcessingPolicy::USE_SERVANT_MANAGER must be set as well as the policy which defines the type of servant manager (ServantRetentionPolicy::RETAIN for Servant Activator or ServantRetentionPolicy::NON_RETAIN for Servant Locator.)
ServantActivators
ServantActivators are used when ServantRetentionPolicy::RETAIN and RequestProcessingPolicy::USE_SERVANT_MANAGER are set.
Servants activated by this type of servant manager are tracked in the Active Object Map.
The following events occur while processing requests using ServantActivators:
1
2
3
If the object ID is not found in the active object map, the POA invokes incarnate on a servant manager. incarnate passes the object ID and the POA in which the object is being activated.
4
5
Note
The etherealize and incarnate method implementations are user-supplied code.
At a later date, the servant can be deactivated. This may occur from several sources, including the deactivate_object operation, deactivation of the POA manager associated with that POA, and so forth. More information on deactivating objects is described in “Deactivating objects”.
This code sample is an example of servant activator-type servant manager:
int main(int argc, char* const* argv) {
try {
// Initialize the ORB.
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

// get a reference to the root POA
CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");

PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);

CORBA::PolicyList policies;
policies.length(2);
policies[(CORBA::ULong)0] = rootPOA->
    create_lifespan_policy(PortableServer::PERSISTENT);
policies[(CORBA::ULong)1] =
rootPOA->create_request_processing_policy(
PortableServer::USE_SERVANT_MANAGER);
// Create myPOA with the right policies
PortableServer::POAManager_var rootManager = rootPOA->the_POAManager();
PortableServer::POA_var myPOA = rootPOA->
     create_POA("bank_servant_activator_poa", rootManager,
policies);
// Create a Servant activator
AccountManagerActivator servant_activator_impl;
// Set the servant activator
myPOA->set_servant_manager(&servant_activator_impl);
// Generate two references - one for checking and another for savings.
// Note that we are not creating any
// servants here and just manufacturing a reference which is not
// yet backed by a servant
PortableServer::ObjectId_var an_oid =
PortableServer::string_to_ObjectId
            ("CheckingAccountManager");
CORBA::Object_var cref = myPOA->
                     create_reference_with_id(an_oid.in(),
"IDL:Bank/AccountManager:1.0");
               an_oid = PortableServer::string_to_ObjectId
                ("SavingsAccountManager");
CORBA::Object_var sref = myPOA->create_reference_with_id(an_oid.in(),
"IDL:Bank/AccountManager:1.0");
// Activate the POA Manager
rootManager->activate();

// Write out Checking reference
CORBA::String_var string_ref =
                         orb->object_to_string(cref.in());
ofstream crefFile("cref.dat");
crefFile << string_ref << endl;
crefFile.close();
// Now write out the Savings reference
string_ref = orb->object_to_string(sref.in());
ofstream srefFile("sref.dat");
srefFile << string_ref << endl;
srefFile.close();
// Waiting for incoming requests
cout << " BankManager Server is ready" << endl;
orb->run();
}
catch(const CORBA::Exception& e) {
cerr << e << endl;
}
return 1;
}
 
 
The servant manager for the servant activator example follows:
// Servant Activator
class AccountManagerActivator : public PortableServer::ServantActivator {

public:
virtual PortableServer::Servant incarnate (const
PortableServer::ObjectId& oid,
PortableServer::POA_ptr poa) {
CORBA::String_var s = PortableServer::ObjectId_to_string (oid);
cout << "\nAccountManagerActivator.incarnate called with ID = "
           << s << endl;
PortableServer::Servant servant;
if ( VISPortable::vstricmp( (char *)s, "SavingsAccountManager" ) == 0 )
// Create CheckingAccountManager Servant
servant = new SavingsAccountManagerImpl;
else if ( VISPortable::vstricmp( (char *)s, "CheckingAccountManager" )         == 0 )
// Create CheckingAccountManager Servant
servant = new CheckingAccountManagerImpl;
else
throw CORBA::OBJECT_NOT_EXIST();
// Create a deactivator thread
new DeActivatorThread( oid, poa );
// return the servant
return servant;
}
virtual void etherealize (const PortableServer::ObjectId& oid,
PortableServer::POA_ptr adapter,
PortableServer::Servant servant,
CORBA::Boolean cleanup_in_progress,
CORBA::Boolean remaining_activations) {
// If there are no remaining activations i.e. ObjectIds associated
// with the servant, delete it.
CORBA::String_var s = PortableServer::ObjectId_to_string (oid);
cout << "\nAccountManagerActivator.etherealize called with ID = " << s
        << endl;
if (!remaining_activations)
delete servant;
}
};
ServantLocators
In many situations, the POA's Active Object Map could become quite large and consume memory. To reduce memory consumption, a POA can be created with RequestProcessingPolicy::USE_SERVANT_MANAGER and ServantRetentionPolicy::.NON_RETAIN, meaning that the servant-to-object association is not stored in the active object map. Since no association is stored, ServantLocator servant managers are invoked for each request.
The following events occur while processing requests using ServantLocators:
1
2
Since ServantRetentionPolicy::NON_RETAIN is used, the POA does not search the active object map for the object ID.
3
The POA invokes preinvoke on a servant manager. preinvoke passes the object ID, the POA in which the object is being activated, and a few other parameters.
4
5
6
The POA invokes postinvoke on the servant manager.
Note
The preinvoke and postinvoke methods are user-supplied code.
This is some example server code illustrating servant locator-type servant managers:
int main(int argc, char* const* argv) {
try {
// Initialize the ORB.
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
// get a reference to the root POA
CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);

CORBA::PolicyList policies;
policies.length(3);
// Create a child POA with Persistence life span policy
// that uses servant manager with non-retain retention policy
// ( no Active Object Map ) causing the POA to use
// the servant locator.
policies[(CORBA::ULong)0] =
        rootPOA->create_lifespan_policy(PortableServer::PERSISTENT);
policies[(CORBA::ULong)1] = rootPOA->
               create_servant_retention_policy(PortableServer::NON_RETAIN);
policies[(CORBA::ULong)2] = rootPOA->
        create_request_processing_policy(PortableServer::USE_SERVANT_MANAGER);
PortableServer::POAManager_var rootManager =
                                              rootPOA->the_POAManager();
PortableServer::POA_var myPOA = rootPOA->
        create_POA("bank_servant_locator_poa",rootManager,policies);
// Create the servant locator
AccountManagerLocator servant_locator_impl;
myPOA->set_servant_manager(&servant_locator_impl);
// Generate two references - one for checking and another for savings.
// Note that we are not creating any
// servants here and just manufacturing a reference which
// is not yet backed by a servant
PortableServer::ObjectId_var an_oid =
PortableServer::string_to_ObjectId("CheckingAccountManager");
CORBA::Object_var cref = myPOA->create_reference_with_id(an_oid.in(),
"IDL:Bank/AccountManager:1.0");
an_oid = PortableServer::string_to_ObjectId("SavingsAccountManager");
CORBA::Object_var sref = myPOA->create_reference_with_id(an_oid.in(),
"IDL:Bank/AccountManager:1.0");
// Activate the POA Manager
rootManager->activate();

// Write out Checking reference
CORBA::String_var string_ref = orb->object_to_string(cref.in());
ofstream crefFile("cref.dat");
crefFile << string_ref << endl;
crefFile.close();

// Now write out the Savings reference
string_ref = orb->object_to_string(sref.in());
ofstream srefFile("sref.dat");
srefFile << string_ref << endl;
srefFile.close();
// Wait for incoming requests
cout << "Bank Manager is ready" << endl;
orb->run();
}
catch(const CORBA::Exception& e) {
cerr << e << endl;
}
return 1;
}
The servant manager for this example follows:
// Servant Locator
class AccountManagerLocator : public PortableServer::ServantLocator {
public:
AccountManagerLocator (){}
// preinvoke is very similar to ServantActivator's incarnate method
// but gets called every time a request comes in unlike incarnate()
      // which gets called every time the POA does not find a servant in the
// active object map
virtual PortableServer::Servant preinvoke
        (const PortableServer::ObjectId& oid,
PortableServer::POA_ptr adapter,
const char* operation,
PortableServer::ServantLocator::Cookie& the_cookie) {
CORBA::String_var s = PortableServer::ObjectId_to_string (oid);
cout << "\nAccountManagerLocator.preinvoke called with ID = " << s
           << endl;
PortableServer::Servant servant;
if ( VISPortable::vstricmp( (char *)s, "SavingsAccountManager" )
           == 0 )
// Create CheckingAccountManager Servant
servant = new SavingsAccountManagerImpl;
else if ( VISPortable::vstricmp( (char *)s,
           "CheckingAccountManager" ) == 0 )
// Create CheckingAccountManager Servant
servant = new CheckingAccountManagerImpl;
else
throw CORBA::OBJECT_NOT_EXIST();
// Note also that we do not spawn of a thread to explicitly
         // deactivate an object unlike a servant activator, this is because
// the POA itself calls post invoke after the request is complete.
// In the case of a servant activator the POA calls
// etherealize() only if the object is deactivated by calling
// poa->de_activateobject or the POA itself is destroyed.

// return the servant
return servant;
}

virtual void postinvoke (const PortableServer::ObjectId& oid,
PortableServer::POA_ptr adapter,
const char* operation,
PortableServer::ServantLocator::Cookie the_cookie,
PortableServer::Servant the_servant) {
CORBA::String_var s = PortableServer::ObjectId_to_string (oid);
cout << "\nAccountManagerLocator.postinvoke called with ID = " << s
        << endl;
delete the_servant;
}
};
Managing POAs with the POA manager
A POA manager controls the state of the POA (whether requests are queued or discarded), and can deactivate the POA. Each POA is associated with a POA manager object. A POA manager can control one or several POAs.
A POA manager is associated with a POA when the POA is created. You can specify the POA manager to use, or specify null to have a new POA Manager created.
The following is an example of naming the POA and its POA Manager:
PortableServer::POAManager_var rootManager = rootPOA->the_POAManager();
PortableServer::POA_var myPOA = rootPOA->create_POA
                       ("bank_servant_locator_poa",rootManager, policies);
PortableServer::POA_var myPOA = rootPOA->create_POA
                        ( "bank_servant_locator_poa",null,policies );
A POA manager is “destroyed” when all its associated POAs are destroyed.
A POA manager can have the following four states:
These states in turn determine the state of the POA. They are each described in detail in the following sections.
Getting the current state
To get the current state of the POA manager, use:
enum State{HOLDING, ACTIVE, DISCARDING, INACTIVE};
State get_state();
Holding state
By default, when a POA manager is created, it is in the holding state. When the POA manager is in the holding state, the POA queues all incoming requests.
Requests that require an adapter activator are also queued when the POA manager is in the holding state.
To change the state of a POA manager to holding, use
void hold_requests (in boolean wait_for_completion)
raises (AdapterInactive);
wait_for_completion is Boolean. If FALSE, this operation returns immediately after changing the state to holding. If TRUE, this operation returns only when all requests started prior to the state change have completed or when the POA manager is changed to a state other than holding. AdapterInactive is the exception raised if the POA manager was in the inactive state prior to calling this operation.
Note
POA managers in the inactive state cannot change to the holding state.
Any requests that have been queued but not yet started will continue to be queued during the holding state.
Active state
When the POA manager is in the active state, its associated POAs process requests.
To change the POA manager to the active state, use
void activate()
raises (AdapterInactive);
AdapterInactive is the exception raised if the POA manager was in the inactive state prior to calling this operation.
Note
POA managers currently in the inactive state can not change to the active state.
Discarding state
When the POA manager is in the discarding state, its associated POAs discard all requests that have not yet started. In addition, the adapter activators registered with the associated POAs are not called. This state is useful when the POA is receiving too many requests. You need to notify the client that their request has been discarded and to resend their request. There is no inherent behavior for determining if and when the POA is receiving too many requests. It is up to you to set-up thread monitoring if so desired.
To change the POA manager to the discarding state, use
void discard_requests(in boolean wait_for_completion)
raises (AdapterInactive);
The wait_for_completion option is Boolean. If FALSE, this operation returns immediately after changing the state to holding. If TRUE, this operation returns only when all requests started prior to the state change have completed or when the POA manager is changed to a state other than discarding. AdapterInactive is the exception raised if the POA manager was in the inactive state prior to calling this operation.
Note
POA managers currently in the inactive state can not change to the discarding state.
Inactive state
When the POA manager is in the inactive state, its associated POAs reject incoming requests. This state is used when the associated POAs are to be shut down.
Note
POA managers in the inactive state cannot change to any other state.
To change the POA manager to the inactive state, use
void deactivate (in boolean etherealize_objects, in boolean wait_for_completion)
raises (AdapterInactive);
After the state changes, if etherealize_objects is TRUE, then all associated POAs that have Servant RetentionPolicy::RETAIN and RequestProcessingPolicy::USE_SERVANT_MANAGER set call etherealize on the servant manager for all active objects. If etherealize_objects is FALSE, then etherealize is not called. The wait_for_completion option is Boolean. If FALSE, this operation returns immediately after changing the state to inactive. If TRUE, this operation returns only when all requests started prior to the state change have completed or etherealize has been called on all associated POAs (that have ServantRetentionPolicy::RETAIN and RequestProcessingPolicy::USE_SERVANT_MANAGER). AdapterInactive is the exception raised if the POA manager was in the inactive state prior to calling this operation.
Listening and Dispatching: Server Engines, Server Connection Managers, and their properties
Note
Policies that cover listener and dispatcher features previously supported by the BOA are not supported by POAs. In order to provide these features, a VisiBroker-specific policy (ServerEnginePolicy) can be used.
VisiBroker provides a very flexible mechanism to define and tune endpoints for VisiBroker servers. An endpoint in this context is a destination for a communication channel for clients to communicate with servers. A Server Engine is a virtual abstraction for connection endpoint provided as a configurable set of properties.
A ServerEngine abstraction can provide control in terms of:
Server Engine and POAs
A POA on VisiBroker can have many-to-many relationship with a ServerEngine. A POA can be associated with many ServerEngines and vice-versa. The manifestation of this fact is that a POA, and hence the CORBA objects on the POA, can support multiple communication channels.
Figure 8
The simplest case is where POAs have their own unique single server engine. Here, requests for different POAs arrive on different ports. A POA can also have multiple server engines. In this scenario, a single POA supports requests coming from multiple input ports.
Notice that POAs can share server engines. When server engines are shared, the POAs listen to the same port. Even though the requests for (multiple) POAs arrive at the same port, they are dispatched correctly because of the POA name embedded in the request. This scenario occurs, for example, when you use a default server engine and create multiple POAs (without specifying a new server engine during the POA creation).
Server Engines are identified by a name and is defined the first time its name is introduced. By default VisiBroker defines three Server Engine names. They are:
Additionally, VisiBroker for C++ defines following Server Engines:
Two more Server Engines, boa_tp and boa_ts, are available for BOA backward compatibility.
Associating a POA with a Server Engine
The default Server Engine associated with POA can be changed by using the property vbroker.se.default. For example, setting
vbroker.se.default=MySE
defines a new server engine with the name MySE. Root POA and all child POAs created will be associated with this Server Engine by default.
A POA can also be associated with a particular ServerEngine explicitly by using the SERVER_ENGINE_POLICY_TYPE POA policy. For example:
// create ServerEngine policy value
CORBA::Any_var se(new CORBA::Any);
CORBA::StringSequence_var engines =
new CORBA::StringSequence(1UL);
engines->length(1UL);
engines[(CORBA::ULong)0] = CORBA::string_dup("MySE");
se <<= engines;

// create POA policies
CORBA::PolicyList_var policies =
new CORBA::PolicyList(2UL);
policies->length(2UL);
policies[(CORBA::ULong)0] =
orb->create_policy(
PortableServerExt::SERVER_ENGINE_POLICY_TYPE,
se);
policies[(CORBA::ULong)1] =
rootPOA->create_lifespan_policy(
PortableServer::PERSISTENT);

// create POA with policies
PortableServer::POA_var myPOA = rootPOA->create_POA(
"bank_se_policy_poa", manager,
policies);
The POA has an IOR template, profiles for which are obtained from the Server Engines associated with it.
If you don't specify a server engine policy, the POA assumes a server engine name of iiop_tp and uses the following default values:
vbroker.se.iiop_tp.host=null
vbroker.se.iiop_tp.proxyHost=null
vbroker.se.iiop_tp.scms=iiop_tp
vbroker.se.liop_tp.host=null
vbroker.se.liop_tp.proxyHost=null
vbroker.se.liop_tp.scms=liop_tp
To change the default server engine policy, enter its name using the vbroker.se.default property and define the values for all the components of the new server engine. For example:
vbroker.se.default=abc,def
vbroker.se.abc.host=cob
vbroker.se.abc.proxyHost=null
vbroker.se.abc.scms=cobscm1,cobscm2
vbroker.se.def.host=gob
vbroker.se.def.proxyHost=null
vbroker.se.def.scms=gobscm1
Defining Hosts for Endpoints for the Server Engine
Since Server Engines help define a connection's endpoints, the following properties are provided to specify their hosts:
vbroker.se.<se-name>.host=<host-URL>: vbroker.se.mySE.host=host.microfocus.com, for example.
vbroker.se.<se-name>.proxyHost=<proxy-host-URL-or-IP-address>: vbroker.se.mySE.proxyHost=proxy.microfocus.com, for example.
The proxyHost property can also take an IP address as its value. Doing so replaces the default hostname in the IOR with this IP address.
The endpoint abstraction of ServerEngine is further fine-grained in terms of configurable set of entities referred to as Server Connection Managers (SCM). A ServerEngine can have multiple SCMs. SCMs are not shareable between ServerEngines. SCMs are also identified using a name and are defined for a ServerEngine using:
vbroker.se.<se-name>.scms=<SCM-name>[,<SCM-name>,...]
Note
the iiop_tp and liop_tp Server Engines have SCMs named iiop_tp and liop_tp created for them, respectively.
Server Connection Managers
The Server Connection Manager defines the configurable components of an endpoint. Its responsibilities are connection resource management, listening for requests, and dispatching requests to its associated POA. Three logical entities, defined through property groups, are provided by the SCM to fulfill these responsibilities:
Each SCM has one Manager, Listener, and Dispatcher. All three, when defined, form a single endpoint definition allowing clients to contact servers.
Manager
Manager is a set of properties defining the configurable portions of a connection resource. VisiBroker provides a manager of type Socket.
Additionally, VisiBroker for C++ defines another manager of type Local. The Local type corresponds to Local IPC connections, while the Socket manager type expects TCP connections. To select either Local or Socket, set the following property:
vbroker.se.<se-name>.scm.<scm-name>.manager.type=Local>Socket
You can specify the maximum number of concurrent connections acceptable to the server endpoint using the connectionMax property:
vbroker.se.<se-name>.scm.<scm-name>.manager.connectionMax=<integer>
Setting connectionMax to 0 (zero) indicates that there is no restriction on the number of connections, which is the default setting.
You specify the maximum number of idle seconds using the connectionMaxIdle property:
vbroker.se.<se-name>.scm.<scm-name>.manager.connectionMaxIdle=<seconds>
Setting connectionMaxIdle to 0 (zero) indicates that there is no timeout, which is the default setting.
Garbage collection time can also be specified for the manager to garbage-collect idled connections. (Connections can idle after the connectionMaxIdle time until they are garbage-collected.) You can use the garbageCollectTimer property to specify the period of garbage collection in seconds:
vbroker.se.<se-name>.scm.<scm-name>.manager.garbageCollectTimer=<seconds>
A value of 0 (zero) means that the connection will never be garbage collected.
Listener
The Listener is the SCM component that determines how and where the SCM listens for messages. Like the Manager, the Listener is also a set of properties. VisiBroker defines a IIOP listener for the TCP connections.
Additionally, VisiBroker for C++ defines a LIOP listener for local IPC connections. You specify which type of listener you want to use with the property:
vbroker.se.<se-name>.scm.<scm-name>.listener.type=LIOP>IIOP
Since listeners are close to the actual underlying transport mechanism, their properties are not portable across listener types. Each listener type has its own set of properties, defined below.
LIOP listener properties
For systems using shared memory Local IPC, the shmSize property is used to control the shared memory size, in bytes:
vbroker.se.<se-name>.scm.<scm-name>.listener.shmSize=<bytes>
If the shared memory-mapped file needs to be hidden in a directory accessible only by the user, the following boolean property needs to be set:
vbroker.se.<se-name>.scm.<scm-name>.listener.userConstrained=true>false
IIOP listener properties
IIOP listeners need to define a port and (if desired) a proxy port in conjunction with their hosts. These are set using the port and proxyPort properties, as follows:
vbroker.se.<se-name>.scm.<scm-name>.listener.port=<port>
vbroker.se.<se-name>.scm.<scm-name>.listener.proxyPort=<proxy-port>
Note
If you do not set the port property (or set it to 0 [zero]), a random port will be selected. A 0 value for the proxyPort property means that the IOR will contain the actual port (defined by the listener.port property or selected by the system randomly). If it is not required to advertise the actual port, set the proxy port to a non-zero (positive) value.
Setting properties to define standard TCP socket options is also supported for send and receive buffer sizes, socket lingering time, and whether or not to keep inactive sockets alive. The following properties are provided for these mechanisms:
vbroker.se.<se-name>.scm.<scm-name>.listener.rcvBuffSize=<bytes>
vbroker.se.<se-name>.scm.<scm-name>.listener.sendBuffSize=<bytes>
vbroker.se.<se-name>.scm.<scm-name>.listener.socketLinger=<seconds>
vbroker.se.<se-name>.scm.<scm-name>.connection.keepAlive=true>false
If for any reason you wish to simply use your system's defaults for the TCP socket properties, set the appropriate property to a value of 0 (zero).
Dispatcher
The Dispatcher defines a set of properties that determine how the SCM dispatches requests to threads. Three types of dispatchers are provided: ThreadPool, ThreadSession, and MainThread. You set the dispatcher type with the type property:
vbroker.se.<se-name>.scm.<scm-name>.dispatcher.type=ThreadPool>ThreadSession>MainThread
Further control is provided through the SCM for the ThreadPool dispatcher type. The ThreadPool defines the minimum and maximum number of threads that can be created in the thread pool, as well as the maximum time in seconds after which an idled thread is destroyed. These values are controlled with the following properties:
vbroker.se.<se-name>.scm.<scm-name>.dispatcher.threadMin=<integer>
vbroker.se.<se-name>.scm.<scm-name>.dispatcher.threadMax=<integer>
vbroker.se.<se-name>.scm.<scm-name>.dispatcher.threadMaxIdle=<seconds>
The ThreadPool dispatcher allows a “cooling time” to be set. A thread is said to be “hot” when the GIOP connection being served is potentially readable, either upon creation of the connection or upon the arrival of a request. After the cooling time (in seconds), the thread can be returned to the thread pool.
The following property is used to set the cooling time:
vbroker.se.<se-name>.scm.<scm-name>.dispatcher.coolingTime=<seconds>
When to use these properties
There are many times where you need to change some of the server engine properties. The method for changing these properties depends on what you need. For example, suppose you want to change the port number. You could accomplish this by:
Changing the default listener.port property
Changing the default listener.port property is the simplest method, but this affects all POAs that use the default server engine. This may or may not be what you want.
If you want to change the port number on a specific POA, then you'll have to create a new server engine, define the properties for this new server engine, and then reference the new server engine when creating the POA. The previous sections show how to update the server engine properties. The following code snippet shows how to define properties of a server engine and create a POA with a user-defined server engine policy:
// static initialization
AccountRegistry AccountManagerImpl::_accounts;
int main(int argc, char* const* argv)
{
try {
// Initialize the orb
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
// Get the property manager; notice the value returned is
             //not placed into a 'var' type.
VISPropertyManager_ptr pm = orb->getPropertyManager();
pm->addProperty("vbroker.se.mySe.host", "");
pm->addProperty("vbroker.se.mySe.proxyHost", "");
pm->addProperty("vbroker.se.mySe.scms", "scmlist");
pm->addProperty("vbroker.se.mySe.scm.scmlist.manager.type",
                               "Socket");
pm->addProperty
                ("vbroker.se.mySe.scm.scmlist.manager.connectionMax",100UL);
pm->addProperty
           ("vbroker.se.mySe.scm.scmlist.manager.connectionMaxIdle", 300UL);
pm->addProperty
                     ("vbroker.se.mySe.scm.scmlist.listener.type", "IIOP");
pm->addProperty
                     ("vbroker.se.mySe.scm.scmlist.listener.port", 55000UL);
pm->addProperty
                    ("vbroker.se.mySe.scm.scmlist.listener.proxyPort", 0UL);
pm->addProperty
              ("vbroker.se.mySe.scm.scmlist.dispatcher.type", "ThreadPool");
pm->addProperty 
                ("vbroker.se.mySe.scm.scmlist.dispatcher.threadMax", 100UL);
pm->addProperty
                 ("vbroker.se.mySe.scm.scmlist.dispatcher.threadMin", 5UL);
pm->addProperty
            ("vbroker.se.mySe.scm.scmlist.dispatcher.threadMaxIdle", 300UL);
// Get a reference to the root POA
CORBA::Object_var obj = orb->
                                     resolve_initial_references("RootPOA");
PortableServer::POA_var rootPOA =
                                         PortableServer::POA::_narrow(obj);
// Create the policies
CORBA::Any_var seAny(new CORBA::Any);
// The SERVER_ENGINE_POLICY_TYPE requires a sequence, even if
// only one engine is being specified.
CORBA::StringSequence_var engines = new
                                               CORBA::StringSequence(1UL);
engines->length(1UL);
engines[0UL] = CORBA::string_dup("mySe");
seAny <<= engines;
CORBA::PolicyList_var policies = new CORBA::PolicyList(2UL);
policies->length(2UL);
policies[0UL] = orb->create_policy(
                     PortableServerExt::SERVER_ENGINE_POLICY_TYPE, seAny);
policies[1Ul] =
               rootPOA->create_lifespan_policy(PortableServer::PERSISTENT);
// Create our POA with our policies
PortableServer::POAManager_var manager =
                                                 rootPOA->the_POAManager();
PortableServer::POA_var myPOA = rootPOA->create_POA(
"bank_se_policy_poa", manager, policies);

// Create the servant
AccountManagerImpl* managerServant = new AccountManagerImpl();
// Activate the servant
PortableServer::ObjectId_var oid =
PortableServer::string_to_ObjectId("BankManager");
myPOA->activate_object_with_id(oid ,managerServant);
// Obtain the reference
CORBA::Object_var ref =
               myPOA->servant_to_reference(managerServant);
CORBA::String_var string_ref = orb->object_to_string(ref.in());
ofstream refFile("ref.dat");
refFile << string_ref << endl;
refFile.close();
// Activate the POA manager
manager->activate();
// Wait for Incoming Requests
cout << "AccountManager Server ready" << endl;
orb->run();
}
catch(const CORBA::Exception& e) {
cerr << e << endl;
return (1);
}
return (0);
}
Adapter activators
Adapter activators are associated with POAs and provide the ability to create child POAs on-demand. This can be done during the find_POA operation, or when a request is received that names a specific child POA.
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 find_POA is called with an activate parameter value of TRUE. An application server that creates all its needed POAs at the beginning of execution does not need to use or provide an adapter activator; it is necessary only for the case in which POAs need to be created during request processing.
While a request from the POA to an adapter activator is in progress, all requests to objects managed by the new POA (or any descendant POAs) will be queued. This serialization allows the adapter activator to complete any initialization of the new POA before requests are delivered to that POA.
For an example on using adapter activators, see the POA adaptor_activator example included with the product.
Processing requests
Requests contain the Object ID of the target object and the POA that created the target object reference. When a client sends a request, the VisiBroker ORB first locates the appropriate server, or starts the server if needed. It then locates the appropriate POA within that server.
Once the VisiBroker ORB has located the appropriate POA, it delivers the request to that POA. How the request is processed at that point depends on the policies of the POA and the object's activation state. For information about object activation states, see “Activating objects”.
If the POA has ServantRetentionPolicy::RETAIN, the POA looks at the Active Object Map to locate a servant associated with the Object ID from the request. If a servant exists, the POA invokes the appropriate method on the servant.
If the POA has ServantRetentionPolicy::NON_RETAIN or has ServantRetentionPolicy::RETAIN but did not find the appropriate servant, the following may take place:
If the POA has RequestProcessingPolicy::USE_DEFAULT_SERVANT, the POA invokes the appropriate method on the default servant.
If the POA has RequestProcessingPolicy::USE_SERVANT_MANAGER, the POA invokes incarnate or preinvoke on the servant manager.
If the POA has RequestProcessingPolicy::USE_OBJECT_MAP_ONLY, an exception is raised.
If a servant manager has been invoked but cannot incarnate the object, the servant manager can raise a ForwardRequest exception.