7.5.2 ServantLocator

POAのアクティブオブジェクトマップがきわめて大きくなりメモリを消費するような状況はよくあります。メモリ消費量を減らすために,サーバントとオブジェクトの対応をアクティブオブジェクトマップに格納しないという意味のRequestProcessingPolicy::USE_SERVANT_MANAGERとServantRetentionPolicy::NON_RETAIN(C++)設定,またはRequestProcessingPolicy.USE_SERVANT_MANAGERとServantRetentionPolicy.NON_RETAIN(Java)設定でPOAを作成できます。対応が格納されないので,ServantLocatorサーバントマネージャをリクエストごとに起動できます。

サーバントロケータを使用したリクエストの処理中には,次のようなイベントが発生します。

  1. クライアントリクエストを受信します(クライアントリクエストにはPOA名およびオブジェクトIDが含まれます)。
  2. ServantRetentionPolicy::NON_RETAIN(C++),またはServantRetentionPolicy.NON_RETAIN(Java)を使用しているので,POAはアクティブオブジェクトマップのオブジェクトIDを探しません。
  3. POAはサーバントマネージャのpreinvokeを呼び出します。preinvokeはオブジェクトID,オブジェクトを活性化しているPOAなどのパラメタを渡します。
  4. サーバントロケータは適切なサーバントを探します。
  5. サーバントに対するオペレーションが実行され,クライアントに応答が返されます。
  6. POAはサーバントマネージャのpostinvokeを呼び出します。
preinvokeメソッドとpostinvokeメソッドはユーザが指定するコードです。
コードサンプル7-17 サーバントロケータタイプのサーバントマネージャを示すサーバコードサンプル(C++)

int main(int argc, char* const* argv) {
  try {
     // Initialize the ORB.
     CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

     // And the Data source
     DataStore::_create();

     // get a reference to the rootPOA
     CORBA::Object_var obj =
           orb->resolve_initial_references("RootPOA");
     PortableServer::POA_var rootPOA =
           PortableServer::POA::_narrow(obj);

     CORBA::PolicyList policies;
     policies.length(3);

     // Create a child POA with Persistence life span policy
     // that uses servant manager with non-retain retention
     // policy ( no Active Object Map ) causing the POA to use
     // the servant locator.
     policies[(CORBA::ULong)0] =
           rootPOA->create_lifespan_policy
           (PortableServer::PERSISTENT);
     policies[(CORBA::ULong)1] =
           rootPOA->create_servant_retention_policy
           (PortableServer::NON_RETAIN);
     policies[(CORBA::ULong)2] =
           rootPOA->create_request_processing_policy
           (PortableServer::USE_SERVANT_MANAGER);
     PortableServer::POAManager_var rootManager =
           rootPOA->the_POAManager();
     PortableServer::POA_var myPOA =
           rootPOA->create_POA("bank_servant_locator_poa",
           rootManager, policies);
     // Create the servant locator
     AccountManagerLocator servant_locator_impl;
     myPOA->set_servant_manager(&servant_locator_impl);

     // Generate two references - one for checking and another
     // for savings.Note that we are not creating any
     // servants here and just manufacturing a reference which
     // is not yet backed by a servant
     PortableServer::ObjectId_var an_oid =
           PortableServer::string_to_ObjectId
           ("CheckingAccountManager");
     CORBA::Object_var cref = myPOA->create_reference_with_id
           (an_oid.in(), "IDL:Bank/AccountManager:1.0");

     an_oid = PortableServer::string_to_ObjectId
           ("SavingsAccountManager");
     CORBA::Object_var sref = myPOA->create_reference_with_id
           (an_oid.in(), "IDL:Bank/AccountManager:1.0");

     // Activate the POA Manager
     rootManager->activate();

     // Write out Checking reference
     CORBA::String_var string_ref =
           orb->object_to_string(cref.in());
     ofstream crefFile("cref.dat");
     crefFile << string_ref << endl;
     crefFile.close();
     // Now write out the Savings reference
     string_ref = orb->object_to_string(sref.in());
     ofstream srefFile("sref.dat");
     srefFile << string_ref << endl;
     srefFile.close();

     // Wait for incoming requests
     cout << "Bank Manager is ready" << endl;
     orb->run();
     // Destroy the accounts database
     DataStore::_destroy();
  }
  catch(const CORBA::Exception& e) {
     cerr << e << endl;
  }
  return 1;
}

コードサンプル7-18 サーバントロケータタイプのサーバントマネージャを示すサーバコードサンプル(Java)

import org.omg.PortableServer.*;
  public class Server {
     public static void main(String[ ] args) {
        try {
           // Initialize the ORB.
           org.omg.CORBA.ORB orb =
                         org.omg.CORBA.ORB.init(args,null);
           // get a reference to the rootPOA
           POA rootPOA = POAHelper.narrow(
              orb.resolve_initial_references("RootPOA"));
           // Create policies for our POA.
           // We need persistence life span,
           // use servant manager request processing
           // policies and non retain retention policy.
           // This non retain policy will let us use the

           // servant locator instead of servant activator
           org.omg.CORBA.Policy[ ] policies = {
              rootPOA.create_lifespan_policy(
                   LifespanPolicyValue.PERSISTENT),
              rootPOA.create_servant_retention_policy(
                   ServantRetentionPolicyValue.NON_RETAIN),
              rootPOA.create_request_processing_policy(
                   RequestProcessingPolicyValue.
                   USE_SERVANT_MANAGER)
           };
           // Create myPOA with the right policies
           POA myPOA = rootPOA.create_POA(
                 "bank_servant_locator_poa",
                 rootPOA.the_POAManager(),
                 policies );
           // Create the servant locator servant
           // and get its reference
           ServantLocator sl =
                    new AccountManagerLocator()._this(orb);
           // Set the servant locator on our POA
           myPOA.set_servant_manager(sl);
           org.omg.CORBA.Object ref ;
           // Activate the POA manager
           rootPOA.the_POAManager().activate();
           // Generate the reference and write it out.
           // One for each Checking and Savings
           // account types .Note that we are not creating
           // any servants here and just manufacturing a
           // reference which is not yet backed by a servant.
           try {
             ref = myPOA.create_reference_with_id(
                     "CheckingAccountManager".getBytes(),
                     "IDL:Bank/AccountManager:1.0");
             // Write out checking object ID
             java.io.PrintWriter pw =
             new java.io.PrintWriter(
                       new java.io.FileWriter("cref.dat"));
             pw.println(orb.object_to_string(ref));
             pw.close();
             ref = myPOA.create_reference_with_id(
                     "SavingsAccountManager".getBytes(),
                     "IDL:Bank/AccountManager:1.0");
             // Write out savings object ID
             pw = new java.io.PrintWriter(
                 new java.io.FileWriter("sref.dat"));
             System.gc();
             pw.println(orb.object_to_string(ref));
             pw.close();
          } catch ( java.io.IOException e ){
             System.out.println(
                          "Error writing the IOR to file");
             return;
          }
          System.out.println("BankManager is ready.");
          // Wait for incoming requests
          orb.run();
       } catch (Exception e) {
          e.printStackTrace();
       }
    }
}

このサンプルのサーバントマネージャは,次のとおりです。

コードサンプル7-19 サーバントロケータのサンプルのサーバントマネージャ(C++)

// Servant Locator
class AccountManagerLocator :
     public PortableServer::ServantLocator {
  public:
     AccountManagerLocator (){}

     // preinvoke is very similar to ServantActivator 's
     // incarnate method but gets called every time a
     // request comes in unlike incarnate() which gets called
     // every time the POA does not find a servant in the
     // active object map
     virtual PortableServer::Servant preinvoke
           (const PortableServer::ObjectId& oid,
           PortableServer::POA_ptr adapter,
           const char* operation,
           PortableServer::ServantLocator::
                 Cookie& the_cookie) {
        CORBA::String_var s =
              PortableServer::ObjectId_to_string (oid);
        cout << "¥nAccountManagerLocator.preinvoke called
              with ID = " << s << endl;
        PortableServer::Servant servant;

        if ( VISPortable::vstricmp( (char *)s,
              "SavingsAccountManager" ) == 0 )
           //Create CheckingAccountManager Servant
           servant = new SavingsAccountManagerImpl;
        else if ( VISPortable::vstricmp( (char *)s,
              "CheckingAccountManager" ) == 0 )
        // Create CheckingAccountManager Servant
           servant = new CheckingAccountManagerImpl;
        else
           throw CORBA::OBJECT_NOT_EXIST();

        // Note also that we do not spawn of a thread to
        // explicitly deactivate an object unlike a servant
        // activator , this is because the POA itself calls
        // post invoke after the request is complete.In the
        // case of a servant activator the POA calls
        // etherealize() only if the object is deactivated  
        // by calling poa->de_activate object or the POA
        // itself is destroyed.

        //return the servant
        return servant;
     }

  virtual void postinvoke (const PortableServer::ObjectId& oid,
        PortableServer::POA_ptr adapter,
        const char* operation,
        PortableServer::ServantLocator::Cookie the_cookie,
        PortableServer::Servant the_servant) {
     CORBA::String_var s =
           PortableServer::ObjectId_to_string (oid);
     cout << "¥nAccountManagerLocator.postinvoke called
           with ID = " << s << endl;
     delete the_servant;
  }
};

コードサンプル7-20 サーバントロケータのサンプルのサーバントマネージャ(Java)

import org.omg.PortableServer.*;
import org.omg.PortableServer.
                        ServantLocatorPackage.CookieHolder;
public class AccountManagerLocator extends
                                        ServantLocatorPOA {
  public Servant preinvoke (byte[ ] oid,POA adapter,
        java.lang.String operation,
        CookieHolder the_cookie) throws ForwardRequest {
     String accountType = new String(oid);
     System.out.println(
           "¥nAccountManagerLocator.
            preinvoke called with ID = " +
           accountType + "¥n");
     if ( accountType.equalsIgnoreCase
                                 ("SavingsAccountManager"))
        return new SavingsAccountManagerImpl();
     return new CheckingAccountManagerImpl();
  }
  public void postinvoke (byte[ ] oid,
        POA adapter,
        java.lang.String operation,
        java.lang.Object the_cookie,
        Servant the_servant) {
     System.out.println(
          "¥nAccountManagerLocator.postinvoke called
           with ID = " +
          new String(oid) + "¥n");
  }
}