next up previous
Next: IDL Compiler Up: POA Previous: Example

Using a Servant Manager

While the previous example did introduce the POA, it did not demonstrate any of its abilities - the example would have been just as simple using the BOA.

As a more complex example, we want to show a server that generates ``virtual'' object references that point to non-existent objects. We then provide the POA with a servant manager that incarnates the objects on demand.

We continue our series of ``Account'' examples. We provide the implementation for a Bank object with a single ``create'' operation that opens a new account. However, the Account object is not put into existence at that point, we just return a reference that will cause activation of an Account object when it is first accessed. This text will only show some code fragments; find the full code in the demo/poa/account-2 directory.

The implementation of the Account object does not differ from before. More interesting is the implementation of the Bank's create operation:

  Account_ptr
  Bank_impl::create ()
  {
    CORBA::Object_var obj = mypoa->create_reference ("IDL:Account:1.0");
    Account_ptr aref = Account::_narrow (obj);
    assert (!CORBA::is_nil (aref));
    return aref;
  }

The create_reference() operation on the POA does not cause an activation to take place. It only creates a new object reference encapsulating information about the supported interface and a unique (system-generated) Object Id. This reference is then returned to the client.

Now, when the client invokes an operation on the returned reference, the POA will first search its Active Object Map, but will find no servant to serve the request. We therefore implement a servant manager, which will be asked to find an appropriate implementation.

There are two types of servant managers: a Servant Activator activates a new servant, which will be retained in the POA's Active Object Map to serve further requests on the same object. A Servant Locator is used to locate a servant for a single invocation only; the servant will not be retained for future use. The type of servant manager depends on the POA's Servant Retention policy.

In our case, we use a servant activator, which will incarnate and activate a new servant whenever the account is used first. Further operations on the same object reference will use the already active servant. Since the create_reference() operation uses a unique Object Id each time it is called, one new servant will be incarnated for each Account - this represents the BOA's Unshared activation mode.

A servant activator provides two operations, incarnate and etherealize. The former one is called when a new servant needs to be incarnated to serve a previously unknown Object Id. etherealize is called when the servant is deactivated (for example in POA shutdown) and allows the servant manager to clean up associated data.

  class AccountManager : public virtual POA_PortableServer::ServantActivator
  { /* declarations */ };

  PortableServer::Servant
  AccountManager::incarnate (/* params */)
  {
    return new Account_impl;
  }

  void
  AccountManager::etherealize (PortableServer::Servant serv,
                               /* many more params */)
  {
    delete serv;
  }

Our servant activator implements the POA_PortableServer::ServantActivator interface. Since servant managers are servants themselves, they must be activated like any other servant (see below).

The incarnate operation has nothing to do but to create a new Account servant. incarnate receives the current POA and the requested Object Id as parameters, so it would be possible to perform special initialization based on the Object Id that is to be served.

etherealize is just as simple, and deletes the servant. In ``real life'', the servant manager would have to make sure that the servant is not in use anywhere else before deleting it. Here, this is guaranteed by our program logic.

The main() code is a little more extensive than before. Because the Root POA has the USE_ACTIVE_OBJECT_MAP_ONLY policy and does not allow a servant manager, we must create our own POA with the USE_SERVANT_MANAGER policy.

  CORBA::ORB_var orb = CORBA::ORB_init (argc, argv, "mico-local-orb");
  CORBA::Object_var poaobj = orb->resolve_initial_references ("RootPOA");
  PortableServer::POA_var poa = PortableServer::POA::_narrow (poaobj);
  PortableServer::POAManager_var mgr = poa->the_POAManager();

  CORBA::PolicyList pl;
  pl.length(1);
  pl[0] = poa->
    create_request_processing_policy (PortableServer::USE_SERVANT_MANAGER);
  PortableServer::POA_var mypoa = poa->create_POA ("MyPOA", mgr, pl);

Note that we use the Root POA's POA Manager when creating the new POA. This means that the POA Manager has now control over both POAs, and changing its state affects both POAs. If we passed NULL as the second parameter to create_POA(), a new POA Manager would have been created, and we would have to change both POA's states separately.

We can now register the servant manager.

  AccountManager * am = new AccountManager;
  PortableServer::ServantManager_var amref = am->_this ();
  mypoa->set_servant_manager (amref);

After creating an instance of our servant manager, we obtain an object reference using the inherited _this() method. This also implicitely activates the servant manager in the Root POA.

  Bank_impl * micocash = new Bank_impl (mypoa);
  PortableServer::ObjectId_var oid = poa->activate_object (micocash);
  mgr->activate ();
  orb->run();

Now the only thing left to do is to activate a Bank object, to change both POAs to the active state, and to enter the ORB's event loop.


next up previous
Next: IDL Compiler Up: POA Previous: Example

MICO
Tue Nov 10 11:04:45 CET 1998