Introduction - Improving the Server

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.

Child POA Creation

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 ();
 

Activating Objects in the child POA

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 ();
 

Exercise

Modify the server.cpp in the simple server to create the persistent child POA. You can use the same Quoter.idl Stock_i.h Stcok_i.cpp Stock_Factory_i.h Stock_Factory_i.cpp You can use this MPC file.

Solution

Compare your server.cpp with server.cpp file.

Testing

You can use the client.cpp to check the results, as follows:
    $ ./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.

More Reading

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.


Priyanka Gontla
Last modified: Sun Apr 1 18:09:33 PDT 2001