|
この章では、Wrapperサンプル・アプリケーションを例にして、CORBAサーバー・アプリケーションによって管理されているオブジェクトの内部からOracle Tuxedoサービスを呼び出す方法の1つを概説します。
Wrapperサンプル・アプリケーションは、一連の請求オペレーションをOracle Tuxedo ATMI Tellerアプリケーションに委任します。このアプリケーションは、基本的な請求手続きを実行する一連のサービスを含んでいます。この章で紹介するアプローチは、Oracle TuxedoアプリケーションをOracle Tuxedoドメインに組み込むテクニックの一例です。
この章で示されている例では、CORBAオブジェクトの操作と、アプリケーション内の特定のサービスへの呼出しとの1対1の対応が示されます。つまり、Oracle Tuxedoサービスへの呼出しがCORBAオブジェクトの操作としてラッピングされるともいえます。これは、オブジェクトが処理機能をOracle Tuxedoアプリケーションに委任することです。Oracle TuxedoサービスのセットをCORBAサーバー・アプリケーションで使用する必要があるときには、この章で説明されるテクニックを試みてください。
この章では、Oracle Tuxedo ATMIアプリケーションの詳細は説明しません。Oracle Tuxedo ATMIアプリケーションをビルドおよび構成する方法、および動作の詳細は、Oracle Tuxedoのオンライン・マニュアルに含まれているOracle Tuxedo ATMIの情報を参照してください。
この章で説明される、Oracle Tuxedoサービスのセットをラッピングする処理には以下のステップがあります。
次の図は、クライアント・アプリケーション、CORBAサーバー・アプリケーションに管理されているCORBAオブジェクト、およびOracle Tuxedo ATMIアプリケーションの間の関係を簡単に示します。Oracle Tuxedo ATMIアプリケーションは、CORBAオブジェクトから呼び出されるサービスを実装します。

この章で説明する第一のステップは、Oracle Tuxedo ATMIアプリケーションへの呼出しをラッピングするオブジェクトの設計です。たとえば、Wrapperサンプル・アプリケーションの目的は、学生の登録プロセスに請求機能を追加することで、これは既存のOracle Tuxedo ATMI Tellerアプリケーションに請求オペレーションのセットを委任すれば実現できます。
Wrapperサンプル・アプリケーションで使用されているOracle Tuxedo ATMI Tellerアプリケーションには、次のサービスが含まれています。
これらのサービスをラッピングするために、Wrapperサンプル・アプリケーションには新しいインタフェースTellerを定義する別個のOMG IDLファイルが含まれています。このインタフェースには、次の操作があります。
Tellerオブジェクトのこれらの各操作は、Oracle Tuxedo ATMI Tellerアプリケーションにあるサービスへの呼出しと1対1でマップされています。
Tellerオブジェクトの一般的な使用のシナリオは、以下のようになります。
Registrarオブジェクトのregister_for_courses()操作が呼び出されて、このときに学生IDが要求されます。RegistrarオブジェクトによってTellerオブジェクトのget_balance()操作が呼び出されて、口座番号が渡されます。Tellerオブジェクトのget_balance()操作によって、口座番号がメッセージ・バッファに格納され、このバッファがOracle Tuxedo ATMI TellerアプリケーションのCURRBALANCEサービスに送信されます。 CURRBALANCEサービスに対して適切な呼出しが行われます。CURRBALANCEサービスによって、口座の現在の残高がUniversityデータベースから取得されて、Oracle Tuxedo ATMI Tellerアプリケーションに渡されます。Tellerオブジェクトに返されます。Tellerオブジェクトによって、現在の残高の合計がメッセージ・バッファから取り出された上で、現在の残高がRegistrarオブジェクトに返されます。 TellerオブジェクトおよびWrapperサンプル・アプリケーションの設計の詳細は、「Wrapperサンプル・アプリケーションの設計上の考慮事項」を参照してください。
この章で説明される次のステップは、オブジェクトとOracle Tuxedoサービスの間でメッセージの送信に使用されるバッファの作成です。様々なOracle Tuxedo ATMIアプリケーションで使用可能なバッファ型は複数あり、この章の例ではFMLバッファ型に基づいたバッファを使用します。Oracle Tuxedoシステムのバッファ型の詳細は、Oracle Tuxedoの情報を参照してください。
使用するアプリケーション実装ファイルで、選択したバッファ・タイプを割り当てる必要があります。割り当てるバッファはTellerオブジェクトの特定のインスタンスについて一意である必要がないため、オブジェクトのコンストラクタで割り当てることができます。この割当ての操作には、一般に、バッファ・タイプの指定、Oracle Tuxedoサービスへのプロシージャ・コールに適した任意のフラグの受渡し、バッファ・サイズの指定などが含まれます。
また、使用する実装のヘッダー・ファイルには、バッファを表す変数の定義を追加する必要もあります。
次のサンプル・コードではWrapperアプリケーションのTellerオブジェクトのコンストラクタに、Oracle Tuxedoのバッファm_tuxbufが割り当てられています。
Teller_i::Teller_i() :
m_tuxbuf((FBFR32*)tpalloc("FML32", "", 1000))
{
if (m_tuxbuf == 0) {
throw CORBA::INTERNAL();
}
}
FMLバッファを割り当てる行については、次のことに注意してください。
また、オブジェクトの実装ファイルは、Wrapperアプリケーションの実装ファイルにある次の文のようにして、デストラクタでバッファの割当てを解除する必要があります。
tpfree((char*)m_tuxbuf);
次のステップは、Oracle Tuxedo ATMIアプリケーションへの呼出しをラッピングするオブジェクトでの操作を実装することです。このステップでは、オブジェクトからOracle Tuxedoサービスを呼び出す方法の実装を選択します。Wrapperサンプル・アプリケーションでは、tpcall実装が使用されます。
Oracle Tuxedoサービスをラッピングするオブジェクトでの操作には、次のことをする文が一般に含まれます。
次の例は、WrapperアプリケーションのTellerオブジェクトでのget_balance()操作の実装を示します。この操作では特定の口座の残高が取得され、Oracle TuxedoサービスCURRBALANCEが呼び出されます。
CORBA::Double Teller_i::get_balance(BillingW::AccountNumber account)
{
// "marshal" the "in" parameters (account number)
Fchg32(m_tuxbuf, ACCOUNT_NO, 0, (char*)&account, 0);
long size = Fsizeof32(tuxbuf);
// Call the CURRBALANCE Tuxedo service
if (tpcall("CURRBALANCE", (char*)tuxbuf, 0,
(char**)&tuxbuf, &size, 0) ) {
throw CORBA::PERSIST_STORE();
}
// "unmarshal" the "out" parameters (current balance)
CORBA::Double currbal;
Fget32(m_tuxbuf, CURR_BALANCE, 0, (char*)&currbal, 0);
return currbal;
}
次のサンプル・コードにある文は、メッセージ・バッファm_tuxbufを学生の口座番号で満たします。FMLの詳細は、『Oracle Tuxedo ATMI FML関数リファレンス』を参照してください。
Fchg32(m_tuxbuf, ACCOUNT_NO, 0, (char*)&account, 0);
次の文は、tpcallの実装を通じてCURRBALANCE Oracle Tuxedoサービスを呼び出し、メッセージ・バッファを渡します。また、この文は、Oracle Tuxedoサービスのレスポンスが格納される場所も指定します。この例では、リクエストの送信元となったバッファと同じバッファです。
if (tpcall("CURRBALANCE", (char*)tuxbuf, 0,
(char**)&tuxbuf, &size, 0) ) {
throw CORBA::PERSIST_STORE();
}次の文は、返されたOracle Tuxedoメッセージ・バッファから残高を取り出します。
Fget32(m_tuxbuf, CURR_BALANCE, 0, (char*)&currbal, 0);
get_balance()操作の最後の行で、クライアント・アプリケーションへ結果が返されます。
return currbal;
Oracle Tuxedoドメイン内にOracle Tuxedoサービスを組み込む方法については、次の制限事項に注意してください。
Wrapperサンプル・アプリケーションの基本的な設計上の考慮事項は、この項で説明するシナリオに基づいています。学生がコースを登録するとき、Registrarオブジェクトが登録プロセスの一部としてTellerオブジェクトの呼出しを実行し、Tellerオブジェクトは学生の口座にコースの課金をします。
ここでは、Wrapperサンプル・アプリケーションの設計について説明し、Billingというサーバー・アプリケーションを構成に追加します。このため、Wrapperサンプル・アプリケーションには次の4つのサーバー・アプリケーションがあります。
さらに、Wrapperサンプル・アプリケーションのUBBCONFIGファイルで、次のグループが指定されます。
次の図に、Wrapperサンプル・アプリケーションでのOracle Tuxedoドメインの構成を示します。

Oracle Tuxedo ATMIアプリケーションをUniversityサンプル・アプリケーションに組み込むことは、Process-Entityデザイン・パターンを使用する観点からは合理的です。一般にOracle Tuxedo ATMIアプリケーションはProcess-Entityデザイン・パターンを実装しますが、このデザイン・パターンはUniversityサンプル・アプリケーションでも使用されています。
Universityデータベースが更新されて、各学生の口座情報が格納されている新しい表が含まれます。このため、Oracle Tuxedo ATMI Tellerアプリケーションのサービスで課金データを処理する際には、Universityデータベースを使用してトランザクションが実行されます。
Wrapperサンプル・アプリケーションでの一般的な使用シナリオでは、以下のようなイベントのシーケンスを経ます。
Registrarオブジェクトのget_student_details()操作が呼び出されます。get_student_details()操作の実装に含まれているコードによって、次の内容が取得されます。Registrarオブジェクトにリクエストを送信してregister_for_courses()操作を呼び出します。このリクエストにコース番号と学生IDのみが含められる点も同じです。register_for_courses()操作は次の処理を呼び出します。Tellerオブジェクトのget_balance()およびdebit()操作のそれぞれが、Oracle Tuxedo ATMI Tellerアプリケーションへのリクエストを送信します。このリクエストには、適切な呼出しが格納されたFMLバッファがカプセル化されています(これには、Oracle Tuxedo ATMI TellerアプリケーションのCURRBALANCEおよびDEBITサービスそれぞれへの口座番号呼出しも含まれます)。CURRBALANCEおよびDEBITサービスは、それぞれ、適切なデータベース呼出しを実行して、現在の残高を取得し、学生が登録したコースの課金を反映するように学生の口座から引き落とします。 学生の口座に滞納があれば、Registrarオブジェクトはクライアント・アプリケーションにDelinquentAccount例外を返します。その際、クライアント・アプリケーションはトランザクションをロールバックします。
debit()操作が失敗した場合、TellerオブジェクトはTransactionCurrentオブジェクトのrollback_only()操作を呼び出します。TellerおよびRegistrarオブジェクトは同一のトランザクション内にスコープ指定されているため、このロールバックは、登録プロセスの全体に影響することで、データベースの不整合(たとえば、学生がコースに登録したのに、学生の口座残高からコースの分が引き落とされていないなど)を防ぎます。
Registrarオブジェクトによって学生は希望のコースに登録されます。以下のインタフェース定義が、Billingサーバー・アプリケーション用に定義されています。
次の追加考慮事項が、Wrapperサンプル・アプリケーションの設計に影響します。
こうした考慮事項の両方により、Wrapperサンプル・アプリケーションのUBBCONFIGファイルが重要になります。以後の項では、これに関係する設計上の追加考慮事項を詳細に説明します。
ここまでは、Universityサーバー・アプリケーションのすべてのオブジェクトは同じサーバー・プロセス内で定義されていました。そのため、1つのオブジェクトが他のオブジェクトにリクエストを送信する処理は単純でした(この処理を、次のステップでRegistrarオブジェクトおよびCourseSynopsisEnumeratorオブジェクトを例にして示します)。
しかし、2つのサーバー・プロセスが実行中で、1つのプロセスにあるオブジェクトが2つめのプロセスによって管理されているオブジェクトにリクエストを送信する必要がある場合、その手順はやや複雑です。たとえば、別のサーバー・プロセスにあるオブジェクトへのオブジェクト参照を取得するには、重要な前提があります。1つは、2番目のサーバー・プロセスの実行中にリクエストを行うことです。さらに、別のサーバー・プロセスにあるオブジェクト用のファクトリが利用可能である必要があります。
Wrapperサンプル・アプリケーションでは、これを解決するために以下の構成および設計の要素を組み込んでいます。
Server::initialize()操作にあるTellerFactoryオブジェクトへのオブジェクト参照を取得します。次に、Universityサーバー・アプリケーションはTellerFactoryへのオブジェクト参照をキャッシュします。これにより、RegistrarオブジェクトがTellerFactoryオブジェクトを必要とするたびに次の処理を実行せずに済むため、パフォーマンスの最適化に貢献します。RegistrarオブジェクトによってTellerFactoryオブジェクトが呼び出されるとき、RegistrarオブジェクトはServer::initialize()操作(前項で説明した操作)によって取得されたオブジェクト参照を使用します。UBBCONFIGファイルで、各サーバー・プロセスの起動順序を指定します。Registrarオブジェクトのregister_for_courses()およびget_student_details()操作は、Tellerオブジェクトの操作を呼び出すコードを含むように変更されます。 Wrapperサンプル・アプリケーションは、学生による課金の総額が限度を超えた状況を処理できるように設計されています。学生がUniversityで許される限度を超えてコースを登録しようとした場合、Registrarオブジェクトはユーザー定義のDelinquentAccount例外を生成します。この例外がクライアント・アプリケーションに戻されると、クライアント・アプリケーションによってトランザクションがロールバックされます。ユーザー定義例外を実装する方法の詳細は、「ユーザー定義の例外」を参照してください。
Wrapperサンプル・アプリケーションのパフォーマンスに影響するもう1つの考慮事項は、アプリケーションのオブジェクトのインタフェースに適したトランザクション・ポリシーを設定することです。Registrar、CourseSynopsisEnumeratorおよびTellerオブジェクトは、alwaysトランザクション・ポリシーによって構成されます。RegistrarFactoryおよびTellerFactoryオブジェクトはignoreトランザクション・ポリシーによって構成されます(トランザクションに含まれる必要のないこれらのオブジェクトには、トランザクションのコンテキストが伝播されないようになります)。
前述のように、Billingサーバー・アプリケーションは、UniversityデータベースおよびUniversityアプリケーション、Oracle Tuxedo ATMI Tellerアプリケーション、およびOracleトランザクション・マネージャ・サーバー(TMS)アプリケーションを含むグループとは別のグループで構成されます。
しかし、Billingサーバー・アプリケーションは学生をコースに登録するトランザクションに参加するので、Billingサーバー・アプリケーションはServerオブジェクトのTP::open_xa_rm()およびTP::close_xa_rm()操作への呼出しを含む必要があります。これは、任意のトランザクションに含まれるオブジェクトを管理するあらゆるサーバー・アプリケーションに対する要件です。そのようなオブジェクトがデータベースに対する読み取りまたは書込みの操作を一切実行しない場合は、次の場所にNULLリソース・マネージャを指定することができます。
Wrapperサンプル・アプリケーションの構築、設定、および実行の詳細は、『CORBA Universityサンプル・アプリケーション・ガイド』を参照してください。
|