17.1.1 DIIの主要な概念
動的起動インタフェースを実装しなければいけないオブジェクトは,CORBAオブジェクト全体から見れば実際には少数でしょう。またDIIは,多くの場合,一つのタスクを実行するのに複数の方法を提供し,プログラミングの単純性を取るか特殊状況での性能を取るかがその選択基準になります。その結果,DIIは理解するのがより難しいCORBA機能の一つとなります。ここでは,主要な概念を簡単に説明します。コードサンプルも交えての詳細な説明は,以降の節で説明します。
DIIを使用するには,最も一般的なことから始めるとして,次の概念を理解しておく必要があります。
-
Requestオブジェクト
-
AnyオブジェクトとTypecodeオブジェクト
-
リクエスト送信オプション
-
応答受信オプション
(1) Requestオブジェクトを使用する
一つのRequestオブジェクトは,一つのCORBAオブジェクトの一つのメソッドの一回の起動を示します。同じCORBAオブジェクトに対して二つのメソッドを起動したい場合,または二つの異なるオブジェクトに対して同じメソッドを起動したい場合は,二つのRequestオブジェクトが必要です。メソッドを起動するには,まず,CORBAオブジェクトを表すオブジェクトリファレンス,つまりターゲットのリファレンスが必要です。ターゲットのリファレンスを使用してRequestを生成し,それに引数を取り込み,Requestを送信し,応答を待ち,Requestからの結果を取得します。
Requestを生成するには,二つの方法があります。このうちの単純な方法は,ターゲットオブジェクトの_requestメソッドを起動することで,このメソッドはすべてのCORBAオブジェクトが継承します。実際には,これはターゲットオブジェクトを起動しません。_requestには,Requestの中で起動したいメソッドのIDLインタフェース名,例えばget_balanceなどを引き渡します。_requestで生成されるRequestに引数値を追加するには,起動するメソッドに必要な引数ごとにRequestのadd_valueメソッドを起動します。ターゲットに一つ以上のContextオブジェクトを引き渡すには,Requestのctxメソッドを使用してそれらのオブジェクトをRequestに追加します。
直感的には気づきませんが,Requestの結果の型をRequestのresultメソッドで指定することも必要です。性能上の理由から,VisiBroker ORB間で交換されるメッセージには型情報が入っていません。Request内でプレースホルダ結果型を指定することで,ターゲットオブジェクトが送信する応答メッセージから結果を正しく抽出するために必要な情報をVisiBroker ORBに与えます。同様に,起動するメソッドがユーザ例外を発生させる可能性がある場合は,Requestを送信する前にプレースホルダ例外をRequestに追加しておかなければなりません。
Requestオブジェクトを生成する複雑な方法は,ターゲットオブジェクトの_create_requestメソッドを起動することで,このメソッドもすべてのCORBAオブジェクトが継承します。このメソッドは幾つかの引数を取り,それらの引数が新しいRequestに引数を取り込み,そのRequestが返す結果とユーザ例外の型があれば,それを指定します。_create_requestメソッドを使用するには,このメソッドが引数として取るコンポーネントを事前に作成しておく必要があります。_create_requestメソッドを使用すれば性能上の利点が見込まれます。複数のターゲットオブジェクトに対して同じメソッドを起動する場合,複数の_create_request呼び出しに引数コンポーネントを再利用できます。
- 注
-
_create_requestメソッドには多重定義された二つの形態があります。一つはContextListパラメタとExceptionListパラメタを含み,もう一つはそれらを含んでいません。呼び出しの中で一つ以上のContextオブジェクトを引き渡したい場合や,起動したいメソッドが一つ以上のユーザ例外を発生させる可能性がある場合は,追加パラメタがある_create_requestメソッドを使用しなければなりません。
(2) 引数をAny型でカプセル化する
ターゲットメソッドの引数,結果,および例外は,Anyと呼ばれる特殊オブジェクトの中でそれぞれ指定されます。Anyは,任意の型の引数をカプセル化する汎用的なオブジェクトです。AnyはIDLで記述できるすべての型を保持できます。Requestへの引数をAnyとして指定すると,Requestに任意の引数型と値を保持させることができ,コンパイラで型の不一致も起きません(同じことが結果と例外にも当てはまります)。
AnyはTypeCodeとvalueで構成されます。valueは単なる値であり,TypeCodeは値の中のビット列をどのように解釈するか(つまり,値の型)を記述したオブジェクトです。longやObjectなど,単純なIDL型用の単純なTypeCode定数は,idl2cppコンパイラまたはidl2javaコンパイラによって生成されるヘッダファイルに組み込まれます。struct,union,typedefなど,IDL構造体のTypeCodeは,作成する必要があります。そのようなTypeCodeは,記述する型が再帰的であってもかまいません。longとstringから成るstructを考えてみてください。このstructのTypeCodeには,long用のTypeCodeとstring用のTypeCodeが含まれます。idl2cppコンパイラは,-type_code_infoオプションを指定して起動されると,IDLファイル内に定義された型用にTypeCodeを生成します。ただし,DIIを使用している場合,ランタイム時にTypeCodeを取得する必要があります。ランタイム時にTypeCodeをIRから取得できます(「16. インタフェースリポジトリの使用」参照)。または,ORB::create_struct_tcまたはORB::create_exception_tcを起動することによって,VisiBroker ORBにTypeCodeを生成させ,TypeCodeを取得できます。
_create_requestメソッドを使用する場合は,Anyにカプセル化したターゲットメソッド引数をNVListという別の特殊なオブジェクトに挿入する必要があります。Requestの生成方法に関係なく,Requestの結果はNVListとしてエンコードされます。ここで引数に関して述べた内容はすべて結果にも当てはまります。NVは名前付きの値を意味し,NVListは項目数と項目番号で構成され,各項目は,名前と値とフラグをそれぞれ一つずつ備えています。名前は引数名であり,値はAnyにカプセル化された引数であり,フラグはその引数のIDLモード(例えば,inかout)を示します。
Requestの結果は,一つの名前付きの値として表されます。
(3) リクエストを送信するオプション
Requestを生成し,それに引数,結果の型,例外の型を取り込んだあと,そのRequestをターゲットオブジェクトへ送信します。Requestを送信するには,次のような複数の方法があります。
-
最も単純な方法は,Requestのinvokeメソッドを呼び出すことです。このメソッドは応答メッセージを受信するまで待ちます。
-
それより複雑で応答を待たない方法は,Requestのsend_deferredメソッドです。これは,並列処理にスレッドを使用することに代わる方法です。多くのオペレーティングシステムで,send_deferredメソッドはスレッドを生成するより効率的です。
-
send_deferredメソッドを使用する目的が複数のターゲットオブジェクトを並行して起動することなら,代わりにVisiBroker ORBオブジェクトのsend_multiple_requests_deferredメソッドを使用できます。このメソッドはRequestオブジェクトのシーケンスを取ります。
-
ターゲットメソッドがIDLでonewayとして定義されている場合,Requestのsend_onewayメソッドを使用してください。
-
VisiBroker ORBのsend_multiple_requests_onewayメソッドを使用して,複数のonewayメソッドを並行して起動できます。
(4) 応答を受信するオプション
Requestのinvokeメソッド呼び出しによってそのRequestを送信する場合,結果を取得する方法は一つしかありません。つまり,Requestオブジェクトのenvメソッドを使用して例外の有無をチェックし,例外がなければ,Requestのresultメソッドを使用してRequestからNamedValueを抽出します。send_onewayメソッドを使用した場合,結果はありません。send_deferredメソッドを使用した場合,Requestのpoll_responseメソッドを呼び出すことによって,処理が完了したかどうかを定期的に検査できます。poll_responseメソッドは,応答を受信したかどうかを示すコードを返します。しばらくポーリングしたあと,遅延送信の完了を待ち続ける場合は,Requestのget_responseメソッドを使用します。
send_multiple_requests_deferredメソッドを使用して複数のRequestを送信した場合は,該当するRequestのget_responseメソッドを起動することによって,そのRequestが完了したかどうかがわかります。Requestが完了するまで待つには,VisiBroker ORBのget_next_responseメソッドを使用します。待ち続けたくない場合は,VisiBroker ORBのpoll_next_responseメソッドを使用します。