In this section, we will improve the simple server which we have developed before. We will use POA policies to create an object with a persistent object reference.
The characteristics of a POA are controlled via POA policies
that are specified when the POA is created.
POA policies all have the same form: their values are specified
at creation time using an enumerated type.
In our example we will use the LifeSpanPolicy
that controls how the lifetime of object references relates to
the lifetime of the POAs that generate the object references
and the IdAssignmentPolicy
that controls how
object ids are assigned.
CORBA Objects that can live irrespective of any particular process in which they are created or activated are called Persistent Objects. Likewise, shorter-lived objects whose lifetimes are bound to the lifetime of the POA in which they are created are called Transient Objects. Notice that this has nothing to do with the state of the object: an application can create transient objects to access some persistent information maintained in a database. For example, such objects can represent a different session or transaction view of the data. Similarly, some persistent object references may have no state or no persistent state. For example, a logging facility is persistent because it is always available, but it may maintain no state or simply cache some state for the current activation. In general, though, objects that have persistent state are accessed throught persistent object references.
The standard life span policy for the RootPOA is
TRANSIENT
.
This means that any application that needs to support persistent
objects must create at least another POA with the Persistent
life span policy.
In our example we will create two policies for this child POA.
One policy is the LifeSpanPolicy
which we will set
to be PERSISTENT
.
Usually applications that create persistent object references
also set the IdAssignmentPolicy
,
so they can assign the object ids in a predictable way,
consistent across server activations.
It is possible, but very unusual, to use system ids with
persistent object references.
For more about POA and its policies,
please refer to
"Advanced CORBA Programming with C++"
by Henning and Vinoski.
The TAO distribution also includes many examples on how to use
the POA and its policies in the
$TAO_ROOT/examples/POA
directory.
As before, we first initialize the ORB, and obtain a reference to the Root POA.
CORBA::ORB_var orb = CORBA::ORB_init (argc, argv); CORBA::Object_var poa_object = orb->resolve_initial_references ("RootPOA"); PortableServer::POA_var poa = PortableServer::POA::_narrow (poa_object.in ());
Next we get the POAManager
of the RootPOA
and use it to activate the RootPOA
PortableServer::POAManager_var poa_manager = poa->the_POAManager (); poa_manager->activate ();
Now we create a LifeSpanPolicy
object with the PERSISTENT
value:
// Create a PERSISTENT LifespanPolicy object PortableServer::LifespanPolicy_var lifespan = poa->create_lifespan_policy (PortableServer::PERSISTENT);
and next we create an IdAssignmentPolicy
object with
the USER_ID
value:
// Create a USER_ID IdAssignmentPolicy object PortableServer::IdAssignmentPolicy_var idassignment = poa->create_id_assignment_policy (PortableServer::USER_ID);
Next we can initialize the sequence of policies:
CORBA::PolicyList polices (2); policies.length (2); policies[0] = PortableServer::IdAssignmentPolicy::_duplicate (idassignment); policies[1] = PortableServer::LifespanPolicy::_duplicate (lifespan);
Child POAs are created using the create_POA
operation on the parent POA.
PortableServer::POA_var child_poa = poa->create_POA ("childPOA", poa_manager.in (), policies);
The values which we pass to this create_POA
operation are
the name of the child POA, the POAManager of the child POA, and the
CORBA::PolicyList
.
We can create a child controlled by a new
POAManager
by passing
a nil
reference,
but commonly the POAManager
of the parent is used.
Finally, we can now destroy the life span policy and id assignment
policy objects, since they are no longer needed. The
create_POA
operation will make a copy of the objects in the
policy list and the newly created POA will refer to the copies of the
objects passed to the create_POA
.
idassignment->destroy (); lifespan->destroy ();
Now that we have created a new POA, let's use this POA to activate the stock objects. The first step would be to create an instance of the stock factory implementation.
// Create a servant of class Quoter_Stock_Factory_i Quoter_Stock_Factory_i stock_factory_i;
Objects can be activated explicitly using the
activate_object_with_id ()
operation.
This operation has two input parameters:
id of the object and a pointer to the servant that implements
it.
We create the id using a helper function:
PortableServer::ObjectId_var oid = PortableServer::string_to_ObjectId ("Stock_Factory");
Next, we can activate the "Stock_Factory" object:
child_poa->activate_object_with_id (oid.in (), &stock_factory_i);
This operation does not return the object reference of the new
object,
but we can use the id_to_reference
operation
to obtain the object reference:
CORBA::Object_var stock_factory = child_poa->id_to_reference (oid.in ());
As before, we convert the object reference into an IOR string so that the client can use it.
CORBA::String_var ior = orb->object_to_string (stock_factory.in ()); std::cout << ior.in () << std::endl;
As we know already, the final step before a client's request can get processed would be to run the ORB event loop. Last, we destroy the POA, waiting until the destruction terminates.
orb->run (); // Destroy the POA poa->destroy (1,1); orb->destroy ();
$ ./server -ORBEndPoint iiop://localhost:12345 > server.ref &
Normally the ORB selects a listening endpoint at random.
This is inadequate for applications with persistent object
references because the references will become invalid if the
server restarts in a new listening endpoint.
In TAO we can control the listening endpont(s) using the
-ORBEndPoint
option.
For example, for the IIOP protocol,
the endpoint information contains the name or IP address of the
host and a free TCP port number.
In the next
tutorial
we will learn how we can use the
Implementation Repository to work with persistent object
references without setting the listening endpoint explicitly.
The client is executed as usual:
$ ./client file://server.ref MSFT RHAT
For testing the persistency of the POA, let's kill the server. Then direct the object reference into a new foo.ref.
$ kill %1 $ ./server -ORBEndPoint iiop://localhost:12345 > foo.ref & [2] 6941
If we run the client again, we must get the result from the server as before.
$ ./client file://server.ref MSFT RHAT
What happens if we don't tell the server to listen from the same port? Let's try to run the new server as usual:
$ ./server > server.ref & [1] 23897 $ ./client file://server.ref MSFT RHAT The price of a stock in "RedHat, Inc." is $210 The price of a stock in "Microsoft, Inc." is $91 $ kill %1 $ ./server > foo.ref & [2] 23908 $ ./client file://server.ref MSFT RHAT CORBA exception raised!TRANSIENT (IDL:omg.org/CORBA/TRANSIENT:1.0)
A CORBA TRANSIENT exception is raised. This indicates that some of the resources required to perform the request are not available. In this case the client ORB cannot find the server on the expected port number. Without an Implementation Repository the client ORB cannot locate the server in its new port. It has to assume that the server is temporarly down, and could be restarted in the future, thus the TRANSIENT exception.
The Henning and Vinoski CORBA book discusses POA policies in detail. Likewise, the Schmidt and Vinoski columns in C++ Report also include several articles about the POA. Finally, the TAO distribution includes several examples that illustrate how to use the POA policies.