![]() ![]() ![]() ![]() ![]() ![]() ![]() |
この章では、Basic Universityサンプル・アプリケーションを例として使用して、CORBAサーバー・アプリケーションを設計および実装する方法について説明します。この章の内容は、実装するアプリケーションの設計が完了し、OMG IDLに定義されていることを前提にしています。この章では、サーバー・アプリケーション向けの設計および実装の選択肢に焦点を当てます。
Basic Universityサンプル・アプリケーションを使用すると、学生は中央のUniversityデータベースからコース情報を参照できます。このBasicサンプル・アプリケーションでは、学生は次のことを行うことができます。
Basic Universityサンプル・アプリケーションのOMG IDLファイルには、次のインタフェースが定義されます。
図3-1に、Basic Universityサンプル・アプリケーションを示します。
Basic Universityサンプル・アプリケーションで何が発生するかを説明するために、次のイベント・グループについて説明します。
次に、Basicクライアント・アプリケーションおよびサーバー・アプリケーションが起動し、クライアント・アプリケーションがRegistrar
オブジェクトのオブジェクト参照を取得するときに行われる一般的な一連のイベントを示します。
RegistrarFactory
オブジェクトのオブジェクト参照を取得します。RegistrarFactory
オブジェクトの参照を使用して、クライアント・アプリケーションはRegistrarFactory
オブジェクトのfind_registrar()
オペレーションを呼び出します。RegistrarFactory
はメモリー内に存在しません(このオブジェクトに対するリクエストが以前にサーバー・プロセスに到着していないため)。このため、TPフレームワークはServerオブジェクトのServer::create_servant()
オペレーションを呼び出してRegistrarFactoryオブジェクトをインスタンス化します。 RegistrarFactory
オブジェクトのfind_registrar()
オペレーションが呼び出されます。RegistrarFactory
オブジェクトは、Registrar
のオブジェクト参照を作成してクライアント・アプリケーションに戻します。次に、学生がコース概要のリストを参照するときに発生する一連のイベントを順番に示します。
Registrar
オブジェクトのオブジェクト参照を使用して、クライアント・アプリケーションはget_courses_synopsis()
オペレーションを呼び出し、次のものを指定します。Registrar
オブジェクトはメモリー内に存在しないため(このオブジェクトに対するリクエストが以前にサーバー・プロセスに到着していないため)、TPフレームワークはServerオブジェクトに実装されているServer::create_servant()
オペレーションを呼び出します。これにより、Registrar
オブジェクトがサーバー・マシンのメモリー内にインスタンス化されます。Registrar
オブジェクトはクライアント・リクエストを受信し、CourseSynopsisEnumerator
オブジェクトのオブジェクト参照を作成します。CourseSynopsisEnumerator
オブジェクトは、データベースからコース概要をフェッチするためにRegistrar
オブジェクトによって呼び出されます。 CourseSynopsisEnumerator
オブジェクトのオブジェクト参照を作成するために、Registrar
オブジェクトは次のことを行います。
CourseSynopsisEnumerator
オブジェクトの一意のIDを生成します。CourseSynopsisEnumerator
オブジェクトのオブジェクトIDを生成します。このIDは、前のステップで生成された一意のIDとクライアントによって指定された検索文字列を連結したものです。CourseSynopsisEnumerator
オブジェクトのインタフェース・リポジトリIDをそのインタフェース・タイプ・コードから取得します。TP::create_object_reference()
オペレーションを呼び出します。このオペレーションにより、最初のクライアント・リクエストに必要なCourseSynopsisEnumerator
オブジェクトのオブジェクト参照が作成されます。Registrar
オブジェクトはCourseSynopsisEnumerator
オブジェクトに対するget_next_n()
オペレーションを呼び出して、リスト・サイズを渡します。ステップ1で説明したように、このリスト・サイズはパラメータnumber_to_get
によって表されます。Server::create_servant()
オペレーションを呼び出して、CourseSynopsisEnumerator
オブジェクトをインスタンス化します。 CourseSynopsisEnumerator
オブジェクトのactivate_object()
オペレーションを呼び出します。このオペレーションは、次の2つのことを行います。CourseSynopsisEnumerator
オブジェクトは、Registrar
オブジェクトに次の情報を返します。Registrar
オブジェクトは、クライアント・アプリケーションにCourseSynopsisEnumerator
オブジェクト参照を返します。また、そのオブジェクトから取得した次の情報も返します。CourseSynopsisEnumerator
オブジェクトに送信します。CourseSynopsisEnumerator
オブジェクトはそのクライアント・リクエストを満たすと共に、更新したnumber_remaining
変数を返します。CourseSynopsisEnumerator
オブジェクトとのやり取りを終了すると、CourseSynopsisEnumerator
オブジェクトに対してdestroy()
オペレーションを呼び出します。この結果、CourseSynopsisEnumerator
オブジェクトはTP::deactivateEnable()
オペレーションを呼び出します。 CourseSynopsisEnumerator
オブジェクトに対するdeactivate_object()
オペレーションを呼び出します。この結果、CourseSynopsisEnumerator
オブジェクトが保持しているコース概要のリストがサーバー・コンピュータのメモリーから削除されるため、CourseSynopsisEnumerator
オブジェクトのサーバントを別のクライアント・リクエストのために再利用できるようになります。次に、クライアント・アプリケーションがコース詳細を参照するときに行われる一連のイベントを示します。
Basic Universityサンプル・アプリケーションには、Universityサーバー・アプリケーションが含まれます。このサーバー・アプリケーションは、CORBAサーバー・アプリケーションの基本的な設計問題を処理します。この節では、以下のトピックについて説明します。
Basicクライアント・アプリケーションでは、Universityサーバー・アプリケーションによって管理される次のオブジェクトの参照が必要です。
次の表に、これらの参照がどのように生成されて返されるかを示します。
Universityサーバー・アプリケーションがオブジェクト参照を生成する方法について、以下のことに注意してください。
RegistrarFactory
オブジェクトをFactoryFinderに登録します。この方法により、クライアント・アプリケーションはサーバー・アプリケーション内の基本オブジェクトのオブジェクト参照を取得するために必要なファクトリを検索できます。Registrar
オブジェクトのオブジェクト参照は、RegistrarFactory
オブジェクトによって作成される。これは、クライアント・アプリケーションにオブジェクト参照を返すためのきわめて一般的かつ基本的な方法を示します。つまり、クライアント・アプリケーションがビジネス・ロジックを実行するために必要な基本オブジェクトの参照を作成して返すための専用ファクトリが存在するということです。 CourseSynopsisEnumerator
オブジェクトへのオブジェクト参照は、登録されているファクトリの外部で作成されます。Universityサンプル・アプリケーションでは、CourseSynopsisEnumerator
オブジェクトが使用されるのに適しているため、ファクトリ外部での作成は優れた設計となります。つまり、その存在が特定のクライアント・アプリケーション・オペレーションに固有となります。CourseSynopsisEnumerator
オブジェクトは固有のリストと、その他の問合せからの結果とは関連性のない結果を返します。Registrar
オブジェクトは、オペレーションの一環として別のオブジェクトへのオブジェクト参照を作成するため、Registrar
オブジェクトはファクトリとなります。ただし、Registrar
オブジェクトはFactoryFinderを持つファクトリとして登録されません。そのため、クライアント・アプリケーションはRegistrar
オブジェクトへの参照をFactoryFinderから取得できません。Basicサンプル・アプリケーションの3つのオブジェクトには、それぞれ独自の状態管理の要件が存在します。この項では、それぞれのオブジェクト状態管理の要件について説明します。
RegistrarFactory
オブジェクトは、特定のクライアント・リクエストに対して一意である必要はありません。また、このオブジェクトをメモリーに保持しておき、クライアント呼出しごとにこのオブジェクトをアクティブ化および非アクティブ化する負担を回避することは合理的です。したがって、RegistrarFactory
オブジェクトにはprocess
アクティブ化ポリシーが割り当てられます。
Basicサンプル・アプリケーションは、小規模な環境へのデプロイに適しています。Registrar
オブジェクトは、RegistrarFactory
オブジェクトに似た特性を多数備えています。つまり、このオブジェクトは特定のクライアント・リクエストに一意である必要はありません。また、呼出しのたびにオブジェクトのアクティブ化/非アクティブ化を継続して行う必要をなくすためにも合理的です。そのため、Basicサンプル・アプリケーションでは、Registrar
オブジェクトはprocess
アクティブ化ポリシーを持ちます。
Universityサーバー・アプリケーションの基本的な設計上の問題は、大きすぎて1回のレスポンスではクライアント・アプリケーションに返すことができないコース概要リストをどのように処理するかです。したがって、この問題の解決策は、次のことが中心となります。
Universityサーバー・アプリケーションは、この解決策を実装するCourseSynopsisEnumerator
オブジェクトを備えています。このオブジェクトは最初に呼び出されたときに最初の概要リストを返しますが、その後もメモリー内コンテキストに保持されるので、クライアント・アプリケーションは後続のリクエストで概要の残りを取得できます。メモリー内コンテキストを保持するには、CourseSynopsisEnumeratorオブジェクトはステートフルでなければなりません。つまり、このオブジェクトは複数のクライアント呼出しにわたってメモリー内に常駐します。
クライアントがCourseSynopsisEnumerator
オブジェクトとの会話を終了するときに、このオブジェクトにはメモリーからフラッシュされるための手段が必要です。このため、CourseSynopsisEnumerator
オブジェクトの適切な状態管理の方法は、process
アクティブ化ポリシーを割り当て、CORBAアプリケーション制御の非アクティブ化機能を実装することです。
アプリケーション制御の非アクティブ化は、そのオブジェクトのdestroy()
オペレーションによって実装されます。
次のサンプル・コードに、CourseSynopsisEnumerator
オブジェクトのdestroy()
オペレーションを示します。
void CourseSynopsisEnumerator_i::destroy()
{
// When the client calls "destroy" on the enumerator,
// then this object needs to be "destructed".
// Do this by telling the TP framework that we're
// done with this object.
TP::deactivateEnable();
}
次のサンプル・コードに、Basicサンプル・アプリケーション用のICFファイルを示します。
module POA_UniversityB
{
implementation CourseSynopsisEnumerator_i
{
activation_policy ( process );
transaction_policy ( optional );
implements ( UniversityB::CourseSynopsisEnumerator );
};
implementation Registrar_i
{
activation_policy ( process );
transaction_policy ( optional );
implements ( UniversityB::Registrar );
};
implementation RegistrarFactory_i
{
activation_policy ( process );
transaction_policy ( optional );
implements ( UniversityB::RegistrarFactory );
};
};
永続状態情報の処理とは、オブジェクトのアクティブ化中またはアクティブ化後のある時点でディスクから永続状態情報を読み取り、必要な場合、非アクティブ化前または非アクティブ化中のある時点でそれを書き込むことです。Basicサンプル・アプリケーションでは、次の2つのオブジェクトが永続状態情報を処理します。
以降の2つの項では、この2つのオブジェクトが永続状態情報を処理する方法に関する設計上の考慮事項を説明します。
Registrar
オブジェクトのオペレーションの1つによって、クライアント・アプリケーションにコース情報の詳細が返されます。一般的なシナリオでは、数多くのコース概要を参照した学生は、通常2つか3つのコースに関する詳細情報を一度に参照しようとします。
このシナリオを効率的に実装するために、Registrar
オブジェクトにはget_course_details()
オペレーションが定義されています。このオペレーションは、コース番号のリストを指定するパラメータを入力として受け付けます。次にこのオペレーションは、データベースからコースの詳細を検索し、その詳細をクライアント・アプリケーションに返します。このオペレーションが実装されるオブジェクトはプロセス・バウンドなので、このオペレーションはその呼出しの完了後に状態データをメモリーに保持するのを避ける必要があります。
Registrar
オブジェクトは、永続状態をメモリーに保持しません。クライアント・アプリケーションがget_course_details()
オペレーションを呼び出すと、このオブジェクトは関連するコース情報をUniversityデータベースからフェッチしてクライアントに送信します。このオブジェクトは、コース・データをメモリー内に保持しません。このオブジェクトに対するactivate_object()
オペレーションまたはdeactivate_object()
オペレーションでは永続状態は処理されません。
CourseSynopsisEnumerator
オブジェクトは、自身がUniversityデータベースから検索するコース概要を処理します。状態処理に関する設計上の考慮事項は、ディスクから状態を読み取る方法です。このオブジェクトは、状態をディスクに書き込みません。
CourseSynopsisEnumerator
オブジェクトの機能には、次の3つの重要な側面があります。これらの側面は、このオブジェクトがその永続状態を読み取る方法に影響を与えます。
この3つの側面を考えたとき、このオブジェクトでは次のことを行うのが合理的です。
したがって、CourseSynopsisEnumerator
オブジェクトがアクティブ化されるときに、そのオブジェクトのactivate_object()
オペレーションは次のことを行います。
注意: | オブジェクトに対するTobj_ServantBase::activate_object() オペレーションまたはTobj_ServantBase::deactivate_object() オペレーションを実装する場合は、実装ヘッダー・ファイル(つまり、application _i.h ファイル)を編集し、これらのオペレーションの定義をそのオブジェクトのインタフェースのクラス定義テンプレートに追加してください。 |
Universityサンプル・アプリケーションがUniversityデータベースを使用する方法について、次のことに注意してください。
utils
ディレクトリ内のsamplesdb.h
ファイルには、これらのクラスの定義が記述されています。これらのクラスは、Universityデータベース内のコース・レコードと学生レコードを読み書きするために必要なすべてのSQL呼出しを行います。注意: | WrapperおよびProductionサンプル・アプリケーションのOracle Tuxedo Tellerアプリケーションは、Universityデータベース内の口座情報に直接アクセスし、samplesdb.h ファイルを使用しません。 |
Basicサーバー・アプリケーションに組み込むファイルの詳細は、『CORBA Universityサンプル・アプリケーション・ガイド』を参照してください。
CourseSynopsisEnumerator
オブジェクトは、データベース・カーソルを使用してUniversityデータベースから一致するコース概要を検索します。データベース・カーソルは複数のトランザクションにまたがることができないため、CourseSynopsisEnumerator
オブジェクトに対するactivate_object()
オペレーションは一致するすべてのコース概要をメモリーに読み込みます。カーソルはイテレータ・クラスによって管理されているため、CourseSynopsisEnumerator
オブジェクトからは見えないことに注意してください。Universityサンプル・アプリケーションがトランザクションを使用する方法の詳細は、「トランザクションのCORBAサーバー・アプリケーションへの統合」を参照してください。 Basicサンプル・アプリケーションは、次のデザイン・パターンを使用します。
この項では、この2つのデザイン・パターンがBasicサンプル・アプリケーションに適している理由と、Basicサンプル・アプリケーションがこれらのパターンを実装する方法について説明します。
「Process-Entityデザイン・パターン」で説明したように、このデザイン・パターンは、クライアント・アプリケーションによって必要とされるデータ・エンティティを処理する1つのプロセス・オブジェクトが存在する場合に適しています。データ・エンティティは、クライアント・アプリケーションではなくこのプロセス・オブジェクトによって操作されるCORBA struct
としてカプセル化されます。
Process-Entityデザイン・パターンをBasicサンプル・アプリケーションに適用すると、Basicサンプル・アプリケーションは細粒度オブジェクトの実装を回避できます。たとえば、Registrar
オブジェクトは、同じような多数のコース・オブジェクト・セットの有効な代替となります。単一の粗粒度Registrar
オブジェクトを管理する負荷は、何百、何千もの細粒度のコース・オブジェクトを管理するオーバーヘッドに比べれば、それほど大きくはありません。
Process-Entityデザイン・パターンの詳細は、デザイン・パターンに関する技術情報を参照してください。
このデザイン・パターンは、大きすぎて1つのレスポンスでクライアント・アプリケーションに返すことができないデータの内部リストをオブジェクトが生成した場合に適しています。このため、オブジェクトは1回のレスポンスで最初のデータ・リストをクライアント・アプリケーションに返し、後続のレスポンスで残りのデータを返すことができなければなりません。
また、List-Enumeratorオブジェクトは、すでに返されたデータの量を同時に追跡して、後続のリストを正確に返すことができるようにする必要があります。List-Enumeratorオブジェクトは常にステートフルであり(クライアント呼出しにまたがってアクティブ化され、メモリーに常駐する)、サーバー・アプリケーションはそれらが不要になったときにそれらを非アクティブ化できます。
List-Enumeratorデザイン・パターンは、CourseSynopsisEnumerator
オブジェクトに最適です。このデザイン・パターンを実装すると、次のメリットが得られます。
CourseSynopsisEnumerator
オブジェクトは一意で、その内容はこのオブジェクトが作成される原因となったリクエストによって決まります。(また、各CourseSynopsisEnumerator
のオブジェクトIDも一意です。)クライアントがRegistrar
オブジェクトに対してget_courses_synopsis()
オペレーションを呼び出すと、Registrar
オブジェクトは次のものを戻します。CourseSynopsisEnumerator
オブジェクトのオブジェクト参照 このため、後続のすべての呼出しは適切なCourseSynopsisEnumerator
オブジェクトに対して行われます。これは、サーバー・プロセスにCourseSynopsisEnumerator
クラスのアクティブ・インスタンスが複数存在する場合に重要です。
get_courses_synopsis()
オペレーションは一意のCourseSynopsisEnumerator
オブジェクト参照を返すので、クライアント・リクエストどうしが衝突することはありません。つまり、クライアント・リクエストが間違ったCourseSynopsisEnumerator
オブジェクトに誤って送られることはありません。
Registrar
オブジェクトはget_courses_synopsis()
オペレーションを備えていますが、データベース問合せと概要リストの知識はすべてCourseSynopsisEnumerator
オブジェクトに埋め込まれます。この場合、Registrar
オブジェクトは単にクライアントが次のデータを取得するための手段として機能します。
Oracle Tuxedoシステムは、同じサーバー・プロセス内の2つのオブジェクト間のデータ・マーシャリングを自動的に無効化することによって、性能の効率化を実現します。この効率化は、次の環境が存在するときに得られます。
この例には、Registrar
オブジェクトがCourseSynopsisEnumerator
オブジェクトのオブジェクト参照を作成し、それによってそのオブジェクトがインスタンス化された場合などがあります。この2つのオブジェクト間のリクエストとレスポンスでは、データ・マーシャリングは行われません。
状態を持つオブジェクトの事前アクティブ化機能を使用すると、クライアント・アプリケーションがオブジェクトを呼び出す前にそのオブジェクトをアクティブ化できます。この機能は、UniversityサンプルのCourseSynopsisEnumerator
オブジェクトなどのイテレータ・オブジェクトを作成するときに特に役立ちます。
状態を持つオブジェクトの事前アクティブ化では、TP::create_active_object_reference()
オペレーションを使用します。通常、クライアントがあるオブジェクトに対する呼出しを発行するまで、CORBAサーバー・アプリケーションでそのオブジェクトは作成されません。ただし、オブジェクトを事前アクティブ化し、TP::create_active_object_reference()
オペレーションを使用してそのオブジェクトへの参照をクライアントに渡すことによって、クライアント・アプリケーションは、すでにアクティブ化され、状態を持っているオブジェクトを呼び出すことができます。
注意: | 状態を持つオブジェクトの事前アクティブ化の機能は、WebLogic Enterpriseバージョン4.2で最初に導入されました。 |
事前アクティブ化の機能を使用するためのプロセスは、サーバー・アプリケーションに次のコードを記述することです。
このように、事前アクティブ化オブジェクトは、TPフレームワークがそのオブジェクトのServer::create_servant()
オペレーションとTobj_ServantBase::activate_object()
オペレーションを呼び出さずに作成されます。
事前アクティブ化機能を使用するときには、以下のことに注意してください。
process
アクティブ化ポリシーが割り当てられている必要があります。このため、これらのオブジェクトは、プロセスの終了時か、それらのオブジェクトに対するTP::deactivateEnable()
オペレーションの呼出しによってのみ非アクティブ化できます。TP::create_active_object_reference()
オペレーションによって作成されるオブジェクト参照は一時的なもの。これは、事前アクティブ化オブジェクトは自身が作成されたプロセスの存続期間にわたって存在し、別のサーバー・プロセスで再びアクティブ化してはならないためです。ある一時オブジェクト参照が作成されたプロセスの停止後にクライアント・アプリケーションがそのオブジェクト参照を呼び出した場合、TPフレームワークは次の例外を返します。
CORBA::OBJECT_NOT_EXIST
サーバーがクラッシュし、そのときに削除されたオブジェクトをクライアント・アプリケーションが呼び出そうとする状況を回避するには、事前アクティブ化されるオブジェクトに対するTobj_ServantBase::activate_object()
オペレーションの実装にTobjS::ActivateObjectFailed
例外を追加します。クライアントがサーバー・クラッシュ後にこのようなオブジェクトを呼び出そうとし、TPフレームワークがそのオブジェクトに対してTobj_ServantBase::activate_object()
オペレーションを呼び出した場合、TPフレームワークはクライアント・アプリケーションに次の例外を戻します。
CORBA::OBJECT_NOT_EXIST
![]() ![]() ![]() |