29.3.2 サービスの遅延オブジェクト活性化のサンプル

ここでは,サービス活性化のodbのサンプルについて説明します。サンプルはBorland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/boa/odbに入っています。このディレクトリには,表29-1のファイルも含まれます。

表29-1 サービス活性化用odbのサンプルファイル

ファイル名説明
odb.idlDBインタフェースとDBObjectインタフェースのIDL
Server.C(C++)
Server.java(Java)
サービスアクティベータを使用してオブジェクトを生成し,オブジェクトのIORを返し,オブジェクトを非活性化します。
Creator.C(C++)
Creator.java(Java)
100個のオブジェクトを生成するためにDBインタフェースを呼び出し,結果として生じた文字列化オブジェクトリファレンスをファイル(objref.out)に格納します。
Client.C(C++)
Client.java(Java)
オブジェクトの文字列化オブジェクトリファレンスをファイルから読み出して,それらに対する呼び出しを行い,サーバ内のアクティベータにオブジェクトを生成させます。
Makefilemakeまたはnmake(Windowsの場合)がodbサブディレクトリ内で呼び出された時に,次に示すクライアントプログラムとサーバプログラムを生成します。
  • Server.exe(C++)またはServer(Java)
  • Creator.exe(C++)またはCreator(Java)
  • Client.exe(C++)またはClient(Java)

odbのサンプルは,一つのサービスから任意の数のオブジェクトがどのように作成できるかを示します。サービス単体は,IORの一部として格納された各オブジェクトのリファレンスデータとともに,各オブジェクトではなくBOAに登録されます。これによって,オブジェクトキーをオブジェクトリファレンスの一部として格納できるので,OODB(オブジェクト指向データベース)統合を簡易化できます。未生成のオブジェクトをクライアントが呼び出す場合,BOAはユーザが定義したActivatorを呼び出します。すると,アプリケーションは適切なオブジェクトをパーシステント記憶領域からロードできます。

このサンプルでは,「DBService」という名前のサービスに対してオブジェクトを活性化し,非活性化する責任のあるActivatorが生成されます。このActivatorが生成するオブジェクトのリファレンスには,VisiBroker ORBがDBServiceサービスのActivatorを再検索し,Activatorが要求に応じてこれらのオブジェクトを再生成するために十分な情報が含まれています。

DBServiceサービスはDBObjectインタフェースをインプリメントするオブジェクトに対して責任があります。インタフェース(odb.idlに含まれる)はこれらのオブジェクトの手動生成をできるようにするために提供されます。

<この項の構成>
(1) odb.idlインタフェース
(2) サービス活性化オブジェクトのインプリメント(C++)
(3) サービスアクティベータのインプリメント
(4) サービスアクティベータの実体化
(5) サービスアクティベータを使用したオブジェクトの活性化(C++)
(6) サービスアクティベータを使用したオブジェクトの活性化(Java)

(1) odb.idlインタフェース

odb.idlインタフェースはDBObject odbインタフェースをインプリメントするオブジェクトの手動生成をできるようにします。

IDLサンプル29-1 odb.idlインタフェース

interface DBObject {
  string get_name();
};

typedef sequence<DBObject> DBObjectSequence;

interface DB {
  DBObject create_object(in string name);
};

DBObjectインタフェースはDBインタフェースが生成したオブジェクトを表し,サービスオブジェクトとして取り扱えます。

DBObjectSequenceはDBObjectのシーケンスです。サーバはこのシーケンスを使って,現在活性化しているオブジェクトを把握します。

DBインタフェースはcreate_objectオペレーションを使って一つ以上のDBObjectを生成します。DBインタフェースが生成したオブジェクト群は,サービスとして一つにまとめることができます。

(2) サービス活性化オブジェクトのインプリメント(C++)

idl2cppコンパイラは,boa/odb/odb.idlからスケルトンクラス_sk_DBObject用に2種類のコンストラクタを生成します。最初のコンストラクタは手動実体化オブジェクトで使用します。二つ目のコンストラクタはオブジェクトをサービスの一部にします。コードサンプル29-5に示すように,DBObjectのインプリメンテーションは,手動実体化オブジェクトで一般に使用されるobject_nameコンストラクタではなく,サービスコンストラクタを使用してベースの_sk_DBObjectメソッドを構築します。この種のコンストラクタを起動して,DBObjectはそれ自身をDBServiceというサービスの一部として構築します。

コードサンプル29-5 サービス活性化オブジェクトのインプリメント例

class DBObjectImpl: public _sk_DBObject {
  private:
     CORBA::String_var_name;
  public:
     DBObjectImpl(const char *nm,
           const CORBA::ReferenceData& data)
     : _sk_DBObject("DBService", data), _name(nm) {}
  . . .
}

ベースのコンストラクタは,不明瞭なCORBA::ReferenceData値と同様にサービス名を必要とします。Activatorは,クライアントリクエストによって起動しなければならない場合に,これらのパラメタを使用して該当するオブジェクトを一意に識別します。このサンプルで複数のインスタンスを区別するための参照データは,0から99までの数字で構成されます。

(3) サービスアクティベータのインプリメント

通常,オブジェクトをインプリメントしているC++またはJavaクラスをサーバが実体化し,次にBOA::obj_is_ready(C++),BOA::impl_is_ready(C++)またはobj_is_ready(Java),impl_is_ready(Java)の順で呼び出すと,オブジェクトが活性化されます。オブジェクトの活性化を遅延させるには,BOAがオブジェクト活性化中に呼び出すactivateメソッドの制御を得る必要があります。この制御を得るには,extension::Activator(C++)またはcom.inprise.vbroker.extension.Activator(Java)から新たなクラスを派生させ,activateメソッドを変更し,変更したactivateメソッドを使ってオブジェクト固有のC++クラスまたはJavaクラスを実体化します。

odbのサンプルでは,DBActivatorクラスがextension::Activator(C++)またはcom.inprise.vbroker.extension.Activator(Java)から派生し,activateメソッドとdeactivateメソッドを変更します。DBObjectはactivateメソッド内に構築されます。

コードサンプル29-6 activateメソッドとdeactivateメソッドを変更する例(C++)

class DBActivator: public extension::Activator {
     virtual CORBA::Object_ptr activate(
           CORBA::ImplementationDef_ptr impl);
     virtual void deactivate(CORBA::Object_ptr,
           CORBA::ImplementationDef_ptr impl );
  public:
     DBActivator(CORBA::BOA_ptr boa) : _boa(boa) {}
  private:
     CORBA::BOA_ptr _boa;
};

コードサンプル29-7 activateメソッドとdeactivateメソッドを変更する例(Java)

// Server.java
class DBActivator implements Activator {
  private static int _count;
  private com.inprise.vbroker.CORBA.BOA _boa;
  public DBActivator(com.inprise.vbroker.CORBA.BOA boa) {
     _boa = boa;
  }
  public org.omg.CORBA.Object activate(
        com.inprise.vbroker.extension.ImplementationDef impl) {
     System.out.printIn("Activator called " + ++_count + " times");
     byte[ ] ref_data = ((ActivationImplDef) impl).id();
     DBObjectImpl obj = new DBObjectImpl(new String(ref_data));
     _boa.obj_is_ready(obj);
     return obj;
  }
  public void deactivate(org.omg.CORBA.Object obj, ImplementationDef impl) {
     // nothing to do here...
  }
}

コードサンプル29-8に示すように,DBActivatorクラスはそのCORBA::ReferenceDataパラメタに基づいてオブジェクトを生成します(C++)。コードサンプル29-9では,DBActivatorクラスがReferenceDataパラメタに基づいてオブジェクトを生成する方法を示します(Java)。BOAはActivatorの責任の下でオブジェクトを求めるクライアントリクエストを受信すると,そのActivatorに対してactivateメソッドを起動します。このメソッドを呼び出す時,BOAはActivatorにImplementationDefパラメタを引き渡すことによって,活性化されたオブジェクトインプリメンテーションを一意に識別します。このパラメタから,インプリメンテーションはリクエストされたオブジェクトの一意の識別子であるCORBA::ReferenceData(C++)またはReferenceData(Java)を取得できます。

コードサンプル29-8 サービスアクティベータをインプリメントする例(C++)

CORBA::Object_ptr DBActivator::activate(
     CORBA::ImplementationDef_ptr impl) {
  extension::ActivationImplDef* actImplDef =
        extension::ActivationImplDef::_downcast(impl);
  CORBA::ReferenceData_var id(actImplDef->id());
  cout << "Activate called for object=[" << (char*) id->data()
        << "]" << endl;
  DBObjectImpl *obj = new DBObjectImpl((char *)id->data(), id);
  _impls.length(_impls.length() +1);
  _impls[_impls.length()-1] = DBObject::_duplicate(obj);
  _boa->obj_is_ready(obj);
  return obj;
}

コードサンプル29-9 サービスアクティベータをインプリメントする例(Java)

public org.omg.CORBA.Object activate(ImplementationDef impl) {
  System.out.println("Activator called " + ++_count + " times");
  byte[ ] ref_data = ((ActivationImplDef) impl) .id();
  DBObjectImpl obj = new DBObjectImpl(new String(ref_data));
  _boa.obj_is_ready(obj);
  return obj;
}

(4) サービスアクティベータの実体化

コードサンプル29-10に示すように,DBActivatorサービスアクティベータは,メインサーバプログラムのBOA::impl_is_ready呼び出しを使って生成され,BOAに登録されます(C++)。コードサンプル29-11は,メインサーバプログラムのimpl_is_ready呼び出しによってDBActivatorサービスアクティベータを作成し,登録するJavaの例を示します。

DBActivatorサービスアクティベータは,DBServiceサービスに属するすべてのオブジェクトに対して責任を持ちます。DBServiceサービスのオブジェクトを求めるリクエストはすべてDBActivatorサービスアクティベータを通じて指示されます。このサービスアクティベータによって活性化されたオブジェクトはすべてそれらがDBServiceサービスに属していることをVisiBroker ORBに通知するリファレンスを持っています。

コードサンプル29-10 サービスアクティベータを実体化する例(C++)

int main(int argc, char **argv) {
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
  CORBA::BOA_ptr boa = orb->BOA_init(argc, argv);
  MyDB db("Database Manager");
  boa->obj_is_ready(&db);
  DBObjectImplReaper reaper;
  reaper.start();
  cout << "Server is ready to receive requests" << endl;
  boa->impl_is_ready("DBService", new DBActivator(boa));
  return(0);
}

コードサンプル29-11 サービスアクティベータを実体化する例(Java)

public static void main(String[ ] args) {
  org.omg.CORBA.ORB orb = ORB.init(args, null);
  com.inprise.vbroker.CORBA.BOA boa
             = ((com.inprise.vbroker.orb.ORB )orb).BOA_init();
  DB db = new DBImpl("Database Manager");
  boa.obj_is_ready(db);
  boa.impl_is_ready("DBService", new DBActivator(boa));
}

BOA::impl_is_ready(C++)またはimpl_is_ready(Java)の呼び出しは,通常のBOA::impl_is_ready(C++)またはimpl_is_ready(Java)の呼び出しの変形であり,次のように引数を二つ持つことに注意してください。

(5) サービスアクティベータを使用したオブジェクトの活性化(C++)

オブジェクトが構築されるたびに,BOA::obj_is_readyをDBActivator::activate内で明示的に呼び出す必要があります。サーバプログラムにはBOA::obj_is_readyに対して二つの呼び出しがあります。第一の呼び出しはサーバがサービスオブジェクトを生成し,生成元プログラムにIORを返した時に発生します。

コードサンプル29-12 BOA::obj_is_readyへのサーバの第一の呼び出し(C++)

DBObject_ptr create_object(const char *name) {
  char ref_data[100];
  memset(ref_data,'¥0',100);
  sprintf(ref_data, "%s", name);
  CORBA::ReferenceData id(100, 100, (CORBA::Octet *)ref_data);
  DBObjectImpl *obj = new DBObjectImpl(name, id);
  _boa()->obj_is_ready(obj);
  _impls.length(_impls.length() + 1);
  _impls[_impls.length()-1] = DBObject::_duplicate(obj);
  return obj;
}

BOA::obj_is_readyへの第二の呼び出しは,DBActivator::activate内にあり,これは明示的に呼び出す必要があります。コンテキスト内でのこの第二の呼び出しについては,コードサンプル29-8を参照してください。

(6) サービスアクティベータを使用したオブジェクトの活性化(Java)

オブジェクトが構築されるたびに,obj_is_readyをactivate()メソッド内で明示的に呼び出す必要があります。サーバプログラムにはobj_is_readyに対して二つの呼び出しがあります。第一の呼び出しはサーバがサービスオブジェクトを生成し,生成元プログラムにIORを返した時に発生します。

コードサンプル29-13 obj_is_readyへのサーバの第一の呼び出し(Java)

public DBObject create_object(String name) {
  System.out.println("Creating: " + name);
  DBObject dbObject = new DBObjectImpl(name);
  _boa().obj_is_ready(dbObject, "DBService", name.getBytes());
  return dbObject;
}

obj_is_readyへの第二の呼び出しは,activate内にあり,これは明示的に呼び出す必要があります。コンテキスト内でのこの第二呼び出しについては,コードサンプル29-9を参照してください。