Документ взят из кэша поисковой машины. Адрес оригинального документа : http://rtm-cs.sinp.msu.ru/manual/mico/doc/node47.html
Дата изменения: Mon Jun 7 21:54:58 1999
Дата индексирования: Mon Oct 1 21:22:17 2012
Кодировка:
Persistent Objects next up previous
Next: Reference Counting Up: POA Previous: Using a Servant Manager

Persistent Objects

Our previous examples used ``transient'' objects which cannot outlive the server process they were created in. If you write a server that activates a servant and export its object reference, and then stop and re-start the server, clients will receive an exception that their object reference has become invalid.

In many cases it is desirable to have persistent objects. A persistent object has an infinite lifetime, not bound by the process that implements the object. You can kill and restart the server process, for example to save resources while it is not needed, or to update the implementation, and the client objects will not notice as long as the server is running whenever an invocation is performed.

An object is persistent if the servant that implements them is activated in a POA that has the PERSISTENT lifespan policy.

As an example, we will expand our Bank to create persistent accounts. When the server goes down, we want to write the account balances to a disk file, and when the server is restarted, the balances are read back in. To accomplish this, we use a persistent POA to create our accounts in. Using a servant manager provides us with the necessary hooks to save and restore the state: when etherealizing an account, the balance is written to disk, and when incarnating an account, we check if an appropriately named file with a balance exists.

We also make the Bank itself persistent, but use a different POA to activate the Bank in. Of course, we could use the Accounts' POA for the Bank, too, but then, our servant manager would have to discriminate whether it is etherealizing an Account or a Bank: using a different POA comes more cheaply.

The implementation of the Account object is the same as in the previous examples. The Bank is basically the same, too. One change is that the create operation has been extended to activate accounts with a specific Object Id - we will use an Account's Object Id as the name for the balance file on disk.

We also add a shutdown operation to the Bank interface, which is supposed to terminate the server process. This is accomplished simply by calling the ORB's shutdown method:

  void
  Bank_impl::shutdown (void)
  {
    orb->shutdown (TRUE);
  }

Invoking shutdown() on the ORB first of all causes the destruction of all object adapters. Destruction of the Account's POA next causes all active objects - our accounts - to be etherealized by invoking the servant manager. Consequently, the servant manager is all we need to save and restore our state.

One problem is that the servant manager's etherealize() method receives a PortableServer::Servant value. However, we need access to the implementation's type, Account_impl*, to query the current balance. Since CORBA does not provide narrowing for servant types, we have to find a solution on our own. Here, we use an STL map mapping the one to the other:

  class Account_impl;
  typedef map<PortableServer::Servant,
    Account_impl *,
    less<PortableServer::Servant> > ServantMap;
  ServantMap svmap;

When incarnating an account, we populate this map; when etherealizing the account, we can retrieve the implementation's pointer.

  PortableServer::Servant
  AccountManager::incarnate (/* params */)
  {
    Account_impl * account = new Account_impl;
    CORBA::Long amount = ...  // retrieve balance from disk
    account->deposit (amount);

    svmap[account] = account; // populate map
    return account;
  }

  void
  AccountManager::etherealize (PortableServer::Servant serv,
                               /* many more params */)
  {
    ServantMap::iterator it = svmap.find (serv);
    Account_impl * impl = (*it).second;
    ... // save balance to disk
    svmap.erase (it);
    delete serv;
  }

Please find the full source code in the demo/poa/account-3 directory.

One little bit of magic is left to do. Persistent POAs need a key, a unique ``implementation name'' to identify their objects with. This name must be given using the -POAImplName command line option:gif

  ./server -POAImplName Bank

Now we have persistent objects, but still have to start up the server by hand. It would be much more convenient if the server was started automatically. This can be achieved using the MICO Daemon (micod) (see section 4.3.2).

For POA-based persistent servers, the implementation repository entry must use the ``poa'' activation mode, for example

  imr create Bank poa ./server IDL:Bank:1.0

The second parameter to imr, Bank, is the same implementation name as above; it must be unique within the implementation repository. If a persistent POA is in contact with the MICO Daemon, object references to a persistent object, when exported from the server process, will not point directly to the server but to the MICO Daemon. Whenever a request is received by micod, it checks if your server is running. If it is, the request is simply forwarded, else a new server is started.

Usually, the first instance of your server must be started manually for bootstrapping, so that you have a chance to export object references to your persistent objects. An alternative is to use the MICO Binder: the IDL:Bank:1.0 in the command line above tells micod that bind() requests for this repository id can be forwarded to this server - after starting it.

With POA-based persistent objects, you can also take advantage of the ``iioploc:'' addressing scheme that is introduced by the Interoperable Naming Service. Instead of using a stringified object reference, you can use a much simpler, URL-like scheme. The format for an iioploc address is

  iioploc://<host>:<port>/<object-key>

host and port are as given with the -ORBIIOPAddr command-line option, and the object key is composed of the implementation name, the POA name and the Object Id, separated by slashes. So, if you start a server using

  ./server -ORBIIOPAddr inet:thishost:1234 -POAImplName MyService

create a persistent POA with the name ``MyPOA'', and then activate an object using the ``MyObject'' Object Id, you could refer to that object using the IOR

  iioploc://thishost:1234/MyService/MyPOA/MyObject

These ``iioploc'' addresses are understood and translated by the string_to_object() method and can therefore be used wherever a stringified object reference can be used.

For added convenience, if the implementation name, the POA name and the Object Id are the same, they are collapsed into a single string. An example for this is the NameService implementation, which uses the ``NameService'' implementation name. The root naming context is then activated in the ``NameService'' POA using the ``NameService'' ObjectId. Consequently, the NameService can be addressed using

  iioploc://<host>:<port>/NameService

Please see the Interoperable Naming Service specification for more details.


next up previous
Next: Reference Counting Up: POA Previous: Using a Servant Manager

Arno Puder
Mon Jun 7 10:53:40 PDT 1999