|
この章では、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 サーバ アプリケーションの基本的な設計問題を処理します。この節では、以下のトピックについて説明します。
この節では、さらに次の 2 つのトピックについても説明します。
Basic クライアント アプリケーションでは、University サーバ アプリケーションによって管理される次のオブジェクトの参照が必要です。
次の表に、これらの参照がどのように生成されて返されるかを示します。
University サーバ アプリケーションがオブジェクト参照を生成する方法について、以下のことに注意してください。
RegistrarFactory
オブジェクトを FactoryFinder に登録する。この方法により、クライアント アプリケーションはサーバ アプリケーション内の基本オブジェクトのオブジェクト参照を取得するために必要なファクトリを検索できます。Registrar
オブジェクトのオブジェクト参照は、RegistrarFactory
オブジェクトによって作成される。これは、クライアント アプリケーションにオブジェクト参照を返すためのきわめて一般的かつ基本的な方法を示します。つまり、クライアント アプリケーションがビジネス ロジックを実行するために必要な基本オブジェクトの参照を作成して返すための専用ファクトリが存在するということです。 CourseSynopsisEnumerator
オブジェクトのオブジェクト参照は、登録されたファクトリの外部で作成される。University サンプル アプリケーションの場合、これは優れた設計です。これは、CourseSynopsisEnumerator
オブジェクトの使い方のためです。つまり、その存在が特定のクライアント アプリケーション オペレーションに固有であるからです。CourseSynopsisEnumerator
オブジェクトは、特定のリストと、ほかのクエリの結果とは関連性のない結果を返します。Registrar
はそのオペレーションの 1 つで別のオブジェクトのオブジェクト参照を作成するので、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()
{
// クライアントが列挙子の「破棄」を呼び出すと、
// このオブジェクトは「消滅」する必要がある。
// そのためには、TP フレームワークに
// このオブジェクトとの会話が完了したことを通知する
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 サーバ アプリケーションに組み込むファイルの詳細については、『Tuxedo 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