Persistent Objects

### 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 Makefile.

### 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.

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