|
このトピックの情報は CORBA C++ クライアント アプリケーションに適用されます。
呼び出し方式と DII の概要については、「静的起動と動的起動」を参照してください。
このトピックで説明する CORBA メンバー関数の詳細については、『Tuxedo CORBA プログラミング リファレンス』を参照してください。
| 注意 : | Oracle Tuxedo CORBA Java クライアントと Oracle Tuxedo CORBA Java クライアント ORB は Tuxedo 8.1 で非推奨になり、サポートされなくなりました。Oracle Tuxedo CORBA Java クライアントおよび Oracle Tuxedo CORBA Java クライアント ORB のテキスト参照、関連するコード サンプルはすべてサードパーティの Java ORB ライブラリの実装/実行の簡易化とプログラマによる参照だけに使用する必要があります。 |
| 注意 : | サード パーティの CORBA Java ORB のテクニカル サポートは、各ベンダによって提供されます。Oracle Tuxedo では、サード パーティの CORBA Java ORB に関する技術的なサポートやマニュアルは提供していません。 |
CORBA クライアント アプリケーションから要求を送信する際、静的起動と動的起動を使い分けるのには、それ相応の理由があります。しかし、同じ CORBA クライアント アプリケーションで両方の呼び出し方式を使用する必要がある場合もあります。呼び出し方式を選択するには、DII の利点と欠点を理解しておく必要があります。
静的起動と動的起動の大きな違いの 1 つは、どちらも同期 oneway 通信をサポートしているのに対し、動的起動だけが遅延同期通信をサポートしているという点です。
同期通信では、CORBA クライアント アプリケーションは要求を送信し、応答を取得するまで待機します。応答待ちの間、CORBA クライアント アプリケーションはほかの作業を行うことができません。遅延同期通信では、CORBA クライアント アプリケーションは要求を送信し、ほかの作業を自由に行うことができます。CORBA クライアント アプリケーションは、要求が完了したかどうかを定期的にチェックし、完了した場合は、その要求の結果を利用します。
さらに、DII を使用すると、CORBA クライアント アプリケーションは、自身が記述された時点で未知であった CORBA オブジェクト型のメソッドを呼び出すことができます。これは、静的起動とは対照的です。静的起動では、CORBA クライアント アプリケーションには呼び出す CORBA オブジェクトの各型に対するクライアント スタブが含まれている必要があります。ただし、DII では、コードでクライアント スタブの作業を実行する必要があるため、プログラミングが難しくなります。
CORBA クライアント アプリケーションは、DII を使用してより高いパフォーマンスを取得できます。たとえば、CORBA クライアント アプリケーションは複数の遅延同期要求を同時に送信し、それらの完了を処理できます。要求が異なるサーバ アプリケーションに送信された場合、この処理を並列に行うことができます。同期クライアント スタブを使用している場合は、こうした処理を行うことができません。
| 注意 : | クライアント スタブは、最適化機能を備えています。このため、クライアント スタブは、単一の要求を送信し、即座にブロックしてその要求の応答を取得するときに、DII で達成される応答時間より短い応答を達成できます。 |
DII は、単なる CORBA クライアント アプリケーションへのインタフェースです。CORBA サーバ アプリケーションからは、静的起動と動的起動はまったく同じに見えます。
多くの場合、DII はあるタスクを達成するための複数の方法を提供します。それには、プログラミングの簡素化と性能のトレード オフが必要となります。この節では、DII の使い方を理解するのに必要な高度な概念について説明します。このトピックの後半には、サンプル コードなどの詳細を示します。
リクエスト オブジェクトは、ある CORBA オブジェクトの 1 つのメソッドの 1 つの呼び出しを表します。同じメソッドに対して 2 つの呼び出しを行う場合、2 つのリクエスト オブジェクトを作成する必要があります。
メソッドを呼び出すには、そのメソッドが含まれている CORBA オブジェクトへのオブジェクト参照が必要です。オブジェクト参照を使用して、リクエスト オブジェクトを作成し、そのリクエスト オブジェクトに引数を指定し、要求を送信し、応答を待機して、要求の結果を取得します。
CORBA::Object::_request メンバー関数を使用する。
CORBA::Object::_request メンバー関数を使用して、その要求で呼び出すインタフェース名だけを指定する空のリクエスト オブジェクト (get_course_details など) を作成します。リクエスト オブジェクトを作成したら、CORBA サーバ アプリケーションに送信する前に引数を指定する必要があります (存在する場合)。呼び出すメソッドで必要な引数ごとに、CORBA::NVList::add_value メンバー関数を呼び出します。
また、CORBA::Request::result メンバー関数を使用して、要求の結果の型を指定する必要があります。パフォーマンス上の理由から、Object Request Brokers (ORB) 間で交換されるメッセージには型情報は含まれません。結果の型のプレース ホルダを指定することによって、応答から結果を適切に抽出するために必要な情報を ORB に提供します。同様に、呼び出すメソッドによって例外が発生する可能性がある場合、リクエスト オブジェクトを送信する前に例外用のプレース ホルダを追加する必要があります。
CORBA::Object::_create_request メンバー関数を使用する。
CORBA::Object:: _create_request メンバー関数を使用してリクエスト オブジェクトを作成する場合、その要求を行うために必要なすべての引数を受け渡し、その結果の型とその要求が返す可能性のあるユーザ例外を指定します。このメンバー関数を使用することで、空の NVList を作成し、一度に 1 つの引数を NVList に追加し、リクエスト オブジェクトを作成して、完成した NVList をその要求に引数として受け渡します。CORBA::Object::_create_request メンバー関数には、性能上のメリットがあります。複数のオブジェクトの同じオブジェクトを呼び出す場合、これらの引数を複数の CORBA::ORB::_create_request 呼び出しで再利用できます。
CORBA メンバー関数の詳細については、『Tuxedo CORBA プログラミング リファレンス』を参照してください。
リクエスト オブジェクトを作成し、引数、結果の型、および例外の型を追加したら、その要求を CORBA オブジェクトに送信します。要求は、以下の方法で送信できます。
CORBA::Request::invoke メンバー関数を呼び出すことである。この関数は、応答メッセージを取得するまでブロックします。CORBA::Request::send_deferred メンバー関数を使用することである。 CORBA::ORB::send_multiple_requests_deferred メンバー関数を使用する。これは、リクエスト オブジェクトのシーケンスを取る。 CORBA::Request::send_oneway メンバー関数を使用する。CORBA::ORB::send_multiple_requests_oneway メンバー関数を使用する。 | 注意 : | CORBA::Request::send_deferred メンバー関数を使用する場合、対象オブジェクトが呼び出しを発行する CORBA クライアント アプリケーションと同じアドレス空間に存在するときには、リクエスト オブジェクトの呼び出しは同期的に動作します。この動作の結果、CosTransaction::Current::suspend オペレーションを呼び出しても、CORBA::BAD_IN_ORDER 例外は発生しません。トランザクションが完了したからです。 |
CORBA メンバー関数の詳細については、『Tuxedo CORBA プログラミング リファレンス』を参照してください。
呼び出しメソッドを使用して要求を送信した場合、結果を取得する方法は 1 つしかありません。その方法とは、リクエスト オブジェクトの CORBA::Request::env メンバー関数を使用して例外をチェックし、例外が存在しない場合は CORBA::Request::result メンバー関数を使用してリクエスト オブジェクトから NVList を抽出することです。
遅延同期メソッドを使用して要求を送信した場合、次のいずれかのメンバー関数を使用して結果を取得できます。
CORBA::ORB::poll_response
このメンバー関数は、要求が完了し、処理の準備ができているかどうかを調べます。このメンバー関数はブロックしません。要求を処理できる場合、CORBA クライアント アプリケーションは get_response() または get_next_response() メンバー関数を使用して応答を処理する必要があります。このメンバー関数は、応答の処理順序を考慮しない場合、CORBA クライアント アプリケーションが特定の応答を待つ間にほかの要求を処理する場合、またはタイムアウトを設定する場合に使用します。
CORBA::ORB::poll_next_response
このメンバー関数は、未処理の要求が処理できる状態にあるかどうかを調べます。要求を処理できる場合、CORBA クライアント アプリケーションは get_response() または get_next_response() メンバー関数を使用して応答を処理する必要があります。このメンバー関数は、要求の処理順序が重要ではなく、CORBA クライアント アプリケーションが特定の応答を待つ間にほかの要求を処理する場合に使用します。
CORBA::ORB::get_response
このメンバー関数は、特定の要求に対する応答が完了して処理されるまでブロックします。このメンバー関数は、未処理の要求を特定の順序で処理する場合に使用します。
CORBA::ORB::get_next_response
このメンバー関数は、未処理の要求に対する応答が完了して処理されるまでブロックします。このメンバー関数は、要求の処理順序が重要でない場合に使用します。
CORBA::Request::send_oneway メンバー関数を使用する場合、結果は存在しません。
CORBA メンバー関数の詳細については、『Tuxedo CORBA プログラミング リファレンス』を参照してください。
クライアント アプリケーションで DII を使用するための手順は次のとおりです。
以降の節では、これらのステップについて詳しく説明し、C++ のサンプル コードを示します。
DII を使用する CORBA クライアント アプリケーションを作成する前に、CORBA オブジェクトのインタフェースをインタフェース リポジトリにロードしておく必要があります。CORBA オブジェクトのインタフェースがインタフェース リポジトリにロードされていない場合、Oracle Application Builder にはそれらが表示されません。目的の CORBA インタフェースが [Services] ウィンドウに表示されない場合、idl2ir コマンドを使用して、CORBA オブジェクトを定義する OMG IDL をインタフェース リポジトリにロードします。idl2ir コマンドの構文は次のとおりです。
idl2ir [-frepositoryfile.idl] file.idl
idl2ir コマンドの詳細については、『Tuxedo コマンド リファレンス』を参照してください。
Bootstrap オブジェクトを使用して、FactoryFinder オブジェクトを取得します。次に、FactoryFinder オブジェクトを使用して、DII 要求からアクセスする CORBA オブジェクトのファクトリを取得します。Boostrap オブジェクトと FactoryFinder オブジェクトを使用してファクトリを取得する例については、「ステップ 4: CORBA クライアント アプリケーションの記述」を参照してください。
CORBA クライアント アプリケーションが CORBA オブジェクトのメソッドを呼び出す場合、そのメソッド呼び出しのための要求を作成します。この要求はバッファに書き込まれ、CORBA サーバ アプリケーションに送信されます。CORBA クライアント アプリケーションがクライアント スタブを使用する場合、この処理は透過的に発生します。DII を使用するクライアント アプリケーションは、リクエスト オブジェクトを作成し、その要求を送信する必要があります。
次の C++ のサンプル コードに、CORBA::Object::_request メンバー関数の使い方を示します。
Boolean aResult;
CORBA::ULong long1 = 42;
CORBA::Any in_arg1;
CORBA::Any &in_arg1_ref = in_arg1;
in_arg1 <<= long1;// 短縮形式を使用して要求を作成
Request_ptr reqp = anObj->_request(“anOp”);// 引数操作ヘルパー関数を使用
reqp->add_in_arg() <<= in_arg1_ref;// boolean 型の結果が必要
reqp->set_return_type(_tc_boolean);// 結果用の場所を提供
CORBA::Any::from_boolean boolean_return_in(aResult);
reqp->return_value() <<= boolean_return_in;// invoke を実行
reqp->invoke();// エラーがないので、戻り値を取得
CORBA::Any::to_boolean boolean_return_out(aResult);
reqp->return_value() >>= boolean_return_out;
CORBA::Object::create_request メンバー関数を使用してリクエスト オブジェクトを作成する場合、空の NVList を作成し、その NVList に引数を 1 つずつ追加します。次に、リクエスト オブジェクトを作成し、完成した NVList を引数としてそのリクエストに受け渡します。
リクエスト オブジェクトの引数は、名前付き/値オブジェクトを格納する NVList オブジェクトで表されます。このリスト内のオブジェクトの追加、削除、クエリを行うためのメソッドが用意されています。CORBA::NVList の詳細については、『Tuxedo CORBA プログラミング リファレンス』を参照してください。
CORBA::NamedValue メンバー関数は、要求の入力引数と出力引数を表すために使用する名前付き/値オブジェクトを指定します。名前付き/値オブジェクトは、リクエスト オブジェクトの引数として使用されます。また、CORBA::NamedValue のペアは、CORBA クライアント アプリケーションに返される要求の結果を表すためにも使用されます。名前付き/値オブジェクトの名前プロパティは文字列で、値プロパティは CORBA Any によって表されます。
CORBA::NamedValue メンバー関数の詳細については、『Tuxedo CORBA プログラミング リファレンス』を参照してください。
次の C++ のサンプル コードに、CORBA::Object::create_request メンバー関数の使い方を示します。
CORBA::Request_ptr reqp;
CORBA::Context_ptr ctx;
CORBA::NamedValue_ptr boolean_resultp = 0;
Boolean boolean_result;
CORBA::Any boolean_result_any(CORBA::_tc_boolean, & boolean_result);
CORBA::NVList_ptr arg_list = 0;
CORBA::Any arg;// デフォルト コンテキストを取得
orbp->get_default_context(ctx);// 結果の名前付き値ペアを作成
(void) orbp->create_named_value(boolean_resultp);
CORBA::Any *tmpany = boolean_resultp->value();
*tmpany = boolean_result_any;
arg.replace(CORBA::_tc_long, &long_arg, CORBA_FALSE)// NVList を作成
orbp->create_list(1, arg_list);
// IN 引数をリストに追加
arg_list->add_value(“arg1”, arg, CORBA::ARG_IN);
// 長い形式を使用して要求を作成
anObj->_create_request (ctx,
“anOp”,
arg_list,
boolean_resultp,
reqp,
CORBA::VALIDATE_REQUEST );
// invoke を実行
reqp->invoke();
CORBA::NamedValue_ptr result_namedvalue;
Boolean aResult;
CORBA::Any *result_any;
// 結果を取得
result_namedvalue = reqp->result();
result_any = result_namedvalue->value();// any から Boolean を抽出
*result_any >>= aResult;
要求は、使用する通信の方式に応じて複数の方法で呼び出すことができます。この節では、CORBA メンバー関数を使用して要求の送信と結果の取得を行う方法について説明します。
同期通信を行う場合、CORBA::Request::invoke メンバー関数は要求を送信し、その応答が CORBA クライアント アプリケーションに返されるまで待機します。CORBA::Request::result メンバー関数は、戻り値を表す名前付き/値オブジェクトの参照を返すために使用します。結果を取得したら、要求に格納されている NVList から値を読み出します。
要求の送信用として、非ブロッキング メンバー関数の CORBA::Request::send_deferred も用意されています。このメンバー関数を使用すると、CORBA クライアント アプリケーションは要求を送信し、CORBA::Request::poll_response メンバー関数を使用して応答が利用可能であるかどうかを調べることができます。CORBA::Request::get_response メンバー関数は、応答が利用可能になるまでブロックします。
次のサンプル コードに、CORBA::Request::send_deferred、CORBA::Request::poll_response、および CORBA::Request::get_response メンバー関数の使い方を示します。
request->send_deferred ();
if (poll)
{
for ( int k = 0 ; k < 10 ; k++ )
{
CORBA::Boolean done = request->poll_response();
if ( done )
break; }
}
request->get_response();
oneway の要求を送信するには、CORBA::Request::send_oneway メンバー関数を使用します。oneway の要求では、CORBA サーバ アプリケーションから応答が返されません。CORBA::Request::send_oneway メンバー関数の詳細については、『Tuxedo CORBA プログラミング リファレンス』を参照してください。
次のサンプル コードに、CORBA::Request::send_oneway メンバー関数の使い方を示します。
request->send_oneway();
CORBA::Request::send_multiple_requests_deferred メンバー関数を使用してリクエスト オブジェクトのシーケンスを送信する場合、CORBA::ORB::poll_response、CORBA::ORB::poll_next_response、CORBA::ORB::get_response、および CORBA::ORB::get_next_response メンバー関数を使用すると、CORBA サーバ アプリケーションが各要求に対して送信する応答を取得できます。
CORBA::ORB::poll_response メンバー関数と CORBA::ORB::poll_next_response メンバー関数を使用すると、CORBA サーバ アプリケーションから応答を取得したかどうかを調べることができます。これらのメンバー関数は、少なくとも 1 つの応答が利用可能な場合は 1 を返し、利用可能な応答が存在しない場合は 0 を返します。
CORBA::ORB::get_response メンバー関数と CORBA::ORB::get_next_response メンバー関数を使用すると、応答を取得できます。利用可能な応答が存在しない場合、これらのメンバー関数は応答を取得するまでブロックします。CORBA クライアント アプリケーションがブロックしないようにする場合は、最初に CORBA::ORB::poll_next_response メンバー関数を使用して応答が利用可能かどうかを調べてから、CORBA::ORB::get_next_response メソッドを使用してその結果を取得します。
また、CORBA::Request::send_multiple_requests_oneway メンバー関数を使用すると、複数の oneway 要求を送信できます。
次のサンプル コードに、CORBA::Request::send_multiple_requests_deferred、CORBA::Request::poll_next_response、および CORBA::Request::get_next_response メンバー関数の使い方を示します。
CORBA::Context_ptr ctx;
CORBA::Request_ptr requests[2];
CORBA::Request_ptr request;
CORBA::NVList_ptr arg_list1, arg_list2;
CORBA::ULong i, nreq;
CORBA::Long arg1 = 1;
Boolean aResult1 = CORBA_FALSE;
Boolean expected_aResult1 = CORBA_TRUE;
CORBA::Long arg2 = 3;
Boolean aResult2 = CORBA_FALSE;
Boolean expected_aResult2 = CORBA_TRUE
try
{
orbp->get_default_context(ctx);
populate_arg_list ( &arg_list1, &arg1, &aResult1 );
nreq = 0;
anObj->_create_request ( ctx,
“Multiply”,
arg_list1,
0,
requests[nreq++],
0);
populate_arg_list ( &arg_list2, &arg2, &aResult2 );
anObj->_create_request ( ctx,
“Multiply”,
arg_list2,
0,
requests[nreq++],
0 );
// 要求シーケンス変数を宣言
CORBA::ORB::RequestSeq rseq ( nreq, nreq, requests, CORBA_FALSE );
orbp->send_multiple_requests_deferred ( rseq );
for ( i = 0 ; i < nreq ; i++ ){
requests[i]->get_response();
}// ここで結果をチェックif ( aResult1 != expected_aResult1 )
{
cout << “aResult1=” << aResult1 << “ different than expected: “ <<
expected_aResult1;
}if ( aResult2 != expected_aResult2 )
{
cout << “aResult2=” << aResult2 << “ different than expected: “ <<
expected_aResult2;
}aResult1 = CORBA_FALSE;
aResult2 = CORBA_FALSE;// 同じ引数リストを使用して、数値を再び乗算
// 今度は応答をポーリング
orbp->send_multiple_requests_deferred ( rseq );
// ここで応答をポーリングfor ( i = 0 ; i < nreq ; i++ )
{// 最大 10 回ランダムにポーリング
for ( int j = 0 ; j < 10 ; j++ )
{
CORBA::Boolean done = requests[i]->poll_response();
if ( done ) break;
}
}
// ここで応答を実際に取得
for ( i = 0 ; i < nreq ; i++ )
{
requests[i]->get_response();
}// ここで結果をチェック
if ( aResult1 != expected_aResult1 )
{
cout << “aResult1=” << aResult1 << “ different than expected: “ <<
expected_aResult1
}
if ( aResult2 != expected_aResult2 )
{
cout << “aResult2=” << aResult2 << “ different than expected: “ <<
expected_aResult2;
}aResult1 = CORBA_FALSE;
aResult2 = CORBA_FALSE;// 同じ引数リストを使用して、数値を再び乗算
// get_next_response を呼び出し、応答を待機
orbp->send_multiple_requests_deferred ( rseq );
// 応答を取得するまでポーリングし、get_next_response を使用して取得
for ( i = 0 ; i < nreq ; i++ )
{
CORBA::Boolean res = 0;
while ( ! res )
{
res = orbp->poll_next_response();
}
orbp->get_next_response(request);
CORBA::release(request);
}
// ここで結果をチェック
if ( aResult1 != expected_aResult1 )
{
cout << “aResult1=” << aResult1 << “ different than expected: “ <<
expected_aResult1;
}
if ( aResult2 != expected_aResult2 )
{
cout << “aResult2=” << aResult2 << “ different than expected: “ <<
expected_aResult2;
}static void populate_arg_list (
CORBA::NVList_ptr ArgList,
CORBA::Long * Arg1,
CORBA::Long * Result )
{
CORBA::Any any_arg1;
CORBA::Any any_result;
(* ArgList) = 0;
orbp->create_list(3, *ArgList);
any_arg1 <<= *Arg1;
any_result.replace(CORBA::_tc_boolean, Result, CORBA_FALSE);(*ArgList)->add_value(“arg1”, any_arg1, CORBA::ARG_IN);
(*ArgList)->add_value(“result”, any_result, CORBA::ARG_OUT);
return;}
要求が正常に完了したことが通知されたら、既存の要求を削除するか、または次の呼び出しでその一部を再利用するかを決定する必要があります。
要求全体を削除するには、削除する要求に対して CORBA::Release(request) メンバー関数を使用します。このオペレーションにより、要求に関連するすべてのメモリが解放されます。遅延同期通信を使用して発行された要求を削除する場合、その要求が完了していないときはその要求がキャンセルされます。
CORBA クライアント アプリケーションは、その作成時に未知であったオブジェクトの要求を作成、設定、および送信できます。そのために、CORBA クライアント アプリケーションはインタフェース リポジトリを使用して、要求を作成および設定するために必要な情報を取得します。CORBA クライアント アプリケーションは、そのインタフェースのクライアント スタブを持っていないので、DII を使用して要求を送信します。
このテクニックは未知の型の CORBA オブジェクトのオペレーションを呼び出すのに役立ちますが、インタフェース リポジトリとの対話によるオーバーヘッドのため、パフォーマンスが問題となります。このタイプの DII 要求は、オブジェクトを参照する CORBA クライアント アプリケーションを作成する場合か、または管理ツールの CORBA クライアント アプリケーションを作成する場合に使用を検討します。
DII 要求でインタフェース リポジトリを使用するための手順は次のとおりです。
CORBA.h の ORB_INCLUDE_REPOSITORY を、Oracle Tuxedo システム内でのインタフェース リポジトリ ファイルの格納場所に設定します。CORBA::Object::_get_interface メンバー関数を使用して、目的の CORBA オブジェクトを実装する CORBA サーバ アプリケーションと通信します。 CORBA::InterfaceDef_ptr を使用して、インタフェース リポジトリに格納されている CORBA インタフェースの定義を取得します。 FullInterfaceDescription オペレーションで、目的のオペレーション用の OperationDescription を検索します。OperationDescription からリポジトリ ID を取得します。OperationDescription で返されたリポジトリ ID を使用して CORBA::Repository::lookup_id を呼び出して、インタフェース リポジトリ内の OperationDef を検索します。この呼び出しにより、包含オブジェクトが返されます。OperationDef にナロー変換します。OperationDef 引数と CORBA::ORB::create_operation_list メンバー関数を使用して、オペレーションの引数リストを作成します。
|