VisiBroker Version 5　Borland(R) Enterprise Server VisiBroker(R)　デベロッパーズガイド

解説・手引・文法・操作書

3021-3-J30

前書き

対象製品

●適用OS：Windows Server 2016，Windows Server 2019，Windows 10 x64

P-2964-AF64 Cosminexus TPBroker 05-24-01

●適用OS：AIX V7.1，AIX V7.2

P-1M64-CF61 Cosminexus TPBroker 05-24-01

●適用OS：Red Hat Enterprise Linux 7.1 (AMD/Intel 64)，Red Hat Enterprise Linux 8.1 (AMD/Intel 64)

P-9S64-AF61 Cosminexus TPBroker 05-25

これらのプログラムプロダクトのほかにも，このマニュアルをご利用になれる場合があります。詳細は「リリースノート」でご確認ください。

輸出時の注意

本製品を輸出される場合には、外国為替及び外国貿易法の規制並びに米国輸出管理規則など外国の輸出関連法規をご確認の上、必要な手続きをお取りください。

なお、不明な場合は、弊社担当営業にお問い合わせください。

商標類

HITACHI，Cosminexus，TPBrokerは，株式会社 日立製作所の商標または登録商標です。

IBM，AIXは，世界の多くの国で登録されたInternational Business Machines Corporationの商標です。

IBM，DB2は，世界の多くの国で登録されたInternational Business Machines Corporationの商標です。

Internet Explorerは，米国Microsoft Corporationの米国およびその他の国における登録商標または商標です。

Intelは，アメリカ合衆国および / またはその他の国における Intel Corporation またはその子会社の商標です。

Itaniumは，アメリカ合衆国および / またはその他の国における Intel Corporation またはその子会社の商標です。

Linuxは，Linus Torvalds氏の日本およびその他の国における登録商標または商標です。

Microsoftは，米国Microsoft Corporationの米国およびその他の国における登録商標または商標です。

OracleとJavaは，Oracle Corporation 及びその子会社，関連会社の米国及びその他の国における登録商標です。文中の社名，商品名等は各社の商標または登録商標である場合があります。

UNIXは，The Open Groupの商標です。

VisiBrokerは，英国，米国またはその他の国におけるMicro Focusまたはその子会社もしくは関連会社の商標または登録された商標です。

Visual C++は，米国Microsoft Corporationの米国およびその他の国における登録商標または商標です。

Windowsは，米国Microsoft Corporationの米国およびその他の国における登録商標または商標です。

Windows Serverは，米国Microsoft Corporationの米国およびその他の国における登録商標または商標です。

その他記載の会社名，製品名などは，それぞれの会社の商標もしくは登録商標です。

発行

2020年 3月　3021-3-J30

著作権

All Rights Reserved. Copyright (C) 2020, Hitachi, Ltd.

COPYRIGHT (C) 1992-2004 Borland Software Corporation. All rights reserved.

はじめに

このマニュアルは，Borland Enterprise Server VisiBrokerの基本的な使用方法および高度な機能の取り扱い方法について説明したものです。Borland Enterprise Server VisiBrokerは，分散オブジェクトベースのアプリケーションを，Common Object Request Broker Architecture（CORBA）仕様に従って開発し運用できるようにします。

対象読者

Borland Enterprise Server VisiBrokerを用いて，CORBAの仕様に基づく分散アプリケーションを開発する方を対象としています。また，オブジェクト指向の開発に精通したC++またはJavaプログラマの方を対象としています。

このマニュアルで使用している記号

このマニュアルでは，次に示す表記を使用しています。

表記

意味

＜　＞＋＜　＞

＋の前のキーを押したまま，あとのキーを押すことを意味します。

文法の記号

このマニュアルで使用する文法記述記号を説明します。文法記述記号は文法の記述形式について説明する記号です。

文法記述記号

意味

背景色付きのボールド体（boldface）

背景色付きのボールド体は，記述どおりに構文をタイプすることを示します。また，コードサンプル部分を強調表示する場合にも使用されます。UNIXの場合は，データベース名，ファイル名，および同義語を示すのに使用されます。

|

横に並べられた複数の項目に対し，項目間の区切りを示し，「または」の意味を示します。

（例）

A｜B｜Cは「A，B，またはC」を意味します。

［ ］

この記号で囲まれている項目は省略してもよいことを意味します。複数の項目が横に並べて記述されている場合には，すべてを省略するか，どれか一つを選択します。

（例）

［A｜B］では「何も指定しない」か，「AまたはBと指定する」ことを意味します。

｛ ｝

この記号で囲まれている項目は，一つの構文の要素として扱うことを意味します。

＜ ＞

この記号で囲まれている項目は，該当する要素を指定することを意味します。

...

記述が省略されていることを示します。

第1編　基本概念

1　CORBAモデルの解説

この章では，CORBA 2.5の仕様を実装したBorland Enterprise Server VisiBrokerについて説明します。また，Borland Enterprise Server VisiBrokerの機能とコンポーネントについても説明します。

1.1　CORBAとは

CORBA（Common Object Request Broker Architecture）は，アプリケーションが，書いた言語やアプリケーションの場所に関係なく，分散アプリケーション間のインターオペラビリティ（アプリケーション間の通信）を実現します。

CORBAの仕様は，分散オブジェクトアプリケーションの開発を単純化し，コストを削減するためにOMG（オブジェクトマネージメントグループ）が採用したものです。CORBAでは，オブジェクト指向技術を使用し，アプリケーション間での再利用と共有ができるソフトウェアコンポーネントを作成します。各オブジェクトは，細かな内部処理をカプセル化し，アプリケーションの複雑さを低減する優れたインタフェースを提供します。一度インプリメントしテストしたオブジェクトは，繰り返し使用できるためアプリケーションの開発コストを削減できます。

クライアントプログラムがオブジェクトを処理する流れを図1-1に示します。図1-1のORB（Object Request Broker）は，使用したいオブジェクトにクライアントアプリケーションを接続します。クライアントプログラムは，通信相手のオブジェクトインプリメンテーションが同じコンピュータにあるのか，またはネットワークのどこかにあるリモートコンピュータにあるのかを意識する必要はありません。クライアントプログラムは，オブジェクト名とオブジェクトインタフェースの使用方法だけを知っていればよいのです。オブジェクトの探索，リクエストのルーティング，および結果の応答は，ORBが担当します。

図1‒1　オブジェクトを処理するクライアントプログラム

注

ORBは独立したプロセスではありません。ORBはエンドユーザアプリケーション内で統合されるライブラリとネットワークリソースの集まりで，クライアントアプリケーションがオブジェクトを探して使用できるようにします。

1.2　Borland Enterprise Server VisiBrokerとは

Borland Enterprise Server VisiBrokerは完全なCORBA 2.5の仕様のORBランタイムを提供し，オープンで柔軟かつインターオペラビリティを持ったC++およびJavaの双方で分散オブジェクトを構築し，配置し，管理するための開発環境をサポートします。Borland Enterprise Server VisiBrokerで構築したオブジェクトは，インターネットまたはイントラネットを介した分散オブジェクト間通信用のOMGのIIOP（Internet Inter-ORB Protocol）を使用して通信するWebベースのアプリケーションから容易にアクセスできます。Borland Enterprise Server VisiBrokerはIIOPの組み込みインプリメンテーションを備えており，高性能とインターオペラビリティを約束します。Borland Enterprise Server VisiBrokerのアーキテクチャを図1-2に示します。

図1‒2　Borland Enterprise Server VisiBrokerアーキテクチャ

1.3　Borland Enterprise Server VisiBrokerの機能

Borland Enterprise Server VisiBrokerには，次に示す機能があります。

1.3.1　Borland Enterprise Server VisiBrokerのスマートエージェントアーキテクチャ

Borland Enterprise Server VisiBrokerのスマートエージェント（osagent）は，クライアントアプリケーションとオブジェクトインプリメンテーションの両方に機能を提供する動的な分散ディレクトリサービスです。ネットワーク上の複数のスマートエージェントは，協調動作することで負荷を分散し，クライアントからサーバオブジェクトにアクセスしやすくします。スマートエージェントはネットワークで使用できるオブジェクトを管理し，起動時にクライアントアプリケーションが要求するオブジェクトを探します。Borland Enterprise Server VisiBrokerのスマートエージェントアーキテクチャは，サーバクラッシュやネットワーク障害などのエラーによってクライアントアプリケーションとサーバオブジェクトとのコネクションが失われたかどうかを確認できます。障害を検出すると，（そのような構成であれば）クライアントと別のホスト上のほかのサーバとのコネクションの確立が自動的に試行されます。スマートエージェントの詳細については，「12.　スマートエージェントの使用」および「10.5　Quality of Serviceの使用」を参照してください。

1.3.2　ロケーションサービスを使用した高度なオブジェクト探索

Borland Enterprise Server VisiBrokerはCORBAの仕様の拡張機能である強力なロケーションサービスを提供し，複数のスマートエージェントから情報にアクセスできるようにします。ネットワーク上でスマートエージェントと一緒に使用すると，ロケーションサービスはクライアントがバインドできるオブジェクトの使用可能なインスタンスをすべて参照できます。コールバック機構であるトリガーを使用すれば，クライアントアプリケーションはオブジェクトの可用性に関する変更をすぐに知ることができます。インタセプタと一緒に使用すると，ロケーションサービスは，サーバオブジェクトへのクライアントリクエストの高度な負荷分散の開発に役立ちます。詳細については，「13.　ロケーションサービスの使用」を参照してください。

1.3.3　インプリメンテーションとオブジェクト活性化のサポート

Borland Enterprise Server VisiBrokerのOAD（オブジェクト活性化デーモン）を使用すれば，クライアントが使用したい場合にオブジェクトインプリメンテーションを自動的に起動できます。また，Borland Enterprise Server VisiBrokerは，クライアントリクエストを受信するまでオブジェクトの活性化を遅延できる機能を提供します。活性化の遅延対象は，特定オブジェクトまたはサーバ上のオブジェクトのクラス全体です。サーバントマネージャの詳細については，「7.　POAの使用」を参照してください。

1.3.4　スレッドとコネクションの強力な管理

Borland Enterprise Server VisiBrokerのスレッドパーセッションモデルを使用すると，複数のリクエストにサービスを提供するために，スレッドはクライアントごとにコネクションが自動的に割り当てられ，コネクションの終了とともにスレッドも終了します。スレッドプーリングモデルを使用すると，サーバオブジェクトへのリクエストのトラフィック量に基づいてスレッドが割り当てられます。つまり，非常にアクティブなクライアントは，複数のスレッドからサービスされ，リクエストが迅速に実行されるようにするのに対し，それよりもアクティブではないクライアントは一つのスレッドを共用しながらも，リクエストがすぐにサービスされるようにします。

Borland Enterprise Server VisiBrokerのコネクション管理は，サーバとのクライアントコネクションの数を最小限にします。同じサーバにあるオブジェクトに対するすべてのクライアントリクエストは，別々のスレッドから発行されていても，同じコネクションを通じて多重化されます。また，解放されたクライアントコネクションは，あとで同じサーバに再接続するために再使用され，クライアントが同じサーバへ新たにコネクションを確立するときのオーバヘッドを発生させないようにします。

スレッドとコネクションの動作はすべて設定できます。Borland Enterprise Server VisiBrokerによるスレッドとコネクションの管理方法の詳細については，「8.　スレッドとコネクションの管理」を参照してください。

1.3.5　IDLコンパイラ

Borland Enterprise Server VisiBrokerには，オブジェクト開発を容易にする二つのIDLコンパイラが提供されています。

idl2cpp（C++の場合）

idl2cppコンパイラはIDLファイルを入力として受け取り，必要なクライアントスタブとサーバスケルトンをC++で生成します。

idl2java（Javaの場合）

idl2javaコンパイラはIDLファイルを入力として受け取り，必要なクライアントスタブとサーバスケルトンをJavaで生成します。

idl2ir（C++およびJavaの場合）

idl2irコンパイラはIDLファイルを受け取り，IR（インタフェースリポジトリ）にその内容を格納します。

これらのコンパイラの詳細については，「11.　IDLの使用」および「16.　インタフェースリポジトリの使用」を参照してください。

1.3.6　DIIとDSIを使用した動的起動

動的起動では，Borland Enterprise Server VisiBrokerはDII（動的起動インタフェース）とDSI（動的スケルトンインタフェース）のインプリメンテーションを提供します。DIIは，コンパイル時に定義されていないオブジェクトへの要求を，クライアントアプリケーションが動的に生成できるようにします。DIIについては，「17.　動的起動インタフェースの使用」を参照してください。DSIは，コンパイル時に定義されていないオブジェクトへのクライアントオペレーション要求をサーバがディスパッチできるようにします。DSIについては，「18.　動的スケルトンインタフェースの使用」を参照してください。

1.3.7　インタフェースリポジトリとインプリメンテーションリポジトリ

インタフェースリポジトリ（IR）は，VisiBroker ORBオブジェクトのメタ情報のオンラインデータベースです。オブジェクトに関するメタ情報には，モジュール，インタフェース，オペレーション，属性，および例外についての情報があります。「16.　インタフェースリポジトリの使用」では，IRのインスタンスを起動する方法，IDLファイルからIRに情報を追加する方法，およびIRから情報を取り出す方法を説明します。

インプリメンテーションリポジトリは，VisiBroker ORBオブジェクトのインプリメンテーションについてのメタ情報のオンラインデータベースです。OADは，クライアントがオブジェクトを参照するときにインプリメンテーションを自動的に活性化するための，インプリメンテーションリポジトリとのBorland Enterprise Server VisiBrokerのインタフェースです。「15.　オブジェクト活性化デーモンの使用」を参照してください。

1.3.8　サーバ側のポータビリティ

Borland Enterprise Server VisiBrokerは，BOA（基本オブジェクトアダプタ）の代替機能であるPOA（ポータブルオブジェクトアダプタ）をサポートします。POAは，CORBAの仕様に規定されており，オブジェクトの活性化，トランジェントまたはパーシステントオブジェクトのサポートなどの幾つかのBOA機能を共用します。また，POAは，オブジェクトのインスタンスの作成と管理をするPOAマネージャとサーバントマネージャなどの新機能も持っています。詳細については，「7.　POAの使用」を参照してください。

1.3.9　インタセプタとオブジェクトラッパーを使用したVisiBroker ORBのカスタマイズ

VisiBroker 4.xインタセプタは，クライアントとサーバの間の隠蔽された通信を開発者に見えるようにします。VisiBroker 4.xインタセプタは，Borlandが独自に開発したインタセプタです。このインタセプタを使用すれば，分散アプリケーションの特殊なニーズを満たす負荷分散，監視，およびセキュリティを可能にするカスタマイズされたクライアントコードとサーバコードを使って，VisiBroker ORBを拡張できます。詳細については，「19.　ポータブルインタセプタの使用」を参照してください。

Borland Enterprise Server VisiBrokerにはOMG標準化機能に基づいたポータブルインタセプタもあります。このインタセプタによって，インタセプタに対するポータブルコードの書き込みが可能となり，この機能を各種ベンダORBで使用できます。詳細については，CORBA 2.5の仕様のインタセプタについての記述を参照してください。

Borland Enterprise Server VisiBrokerのオブジェクトラッパーは，クライアントアプリケーションがバインドしたオブジェクトのメソッドを呼び出すとき，またはサーバアプリケーションがオペレーション要求を受信するときに呼び出されるメソッドを定義できるようにします。詳細については，「21.　オブジェクトラッパーの使用」を参照してください。

1.3.10　イベントキュー

サーバ側の唯一の機能としてイベントキューがあります。サーバは，サーバが対象とするイベントのタイプに基づいてイベントキューにリスナーを登録できます。サーバは，必要なときにこのイベントを処理します。

イベントキューの詳細については，「22.　イベントキュー」を参照してください。

1.3.11　ネーミングサービスのバッキングストア（外部記憶装置）

インターオペラビリティがある新しいネーミングサービスは，プラガブルバッキングストア（外部記憶装置）と統合して，ネーミングサービスの状態をパーシステンスにできます。これによって，ネーミングサービスでのフォルトトレランスとフェールオーバー機能を容易にします。詳細については，「14.10　プラガブルバッキングストア」を参照してください。

1.3.12　Webネーミング（Java）

Webネーミング機能によって，URL（ユニフォームリソースロケータ）とオブジェクトを対応させることができます。これによって，URLを指定してそのオブジェクトのリファレンスを取得できます。詳細については，「26.　URLネーミングの使用」を参照してください。

1.3.13　IDLを使用しないインタフェースの定義（Java）

Borland Enterprise Server VisiBrokerのjava2iiopコンパイラによって，IDL（インタフェース定義言語）の代わりにJava言語を使用してインタフェースを定義できます。CORBA分散オブジェクトとインターオペラビリティを持たせたい既存のJavaコードがある場合，またはIDLを利用したくない場合にjava2iiopコンパイラを使用できます。詳細については，「23.　RMI-IIOPの使用」を参照してください。

1.3.14　ゲートキーパー

Borland Enterprise Server VisiBrokerゲートキーパーによって，Webサーバ上にあるオブジェクトに対してクライアントプログラムがオペレーション要求を発行し，Webブラウザが強要するセキュリティ制限に準拠している限り，そのオブジェクトからのコールバックを受信できます。また，ゲートキーパーはファイアウォールを介した通信を処理し，HTTPデーモンとして使用できます。ゲートキーパーはCORBAの仕様に従って実装されていますが，他社CORBA製品との接続はサポートしていません。詳細については，マニュアル「Borland Enterprise Server VisiBroker　ゲートキーパーガイド」を参照してください。

1.4　CORBAに対するBorland Enterprise Server VisiBrokerの準拠

Borland Enterprise Server VisiBrokerは，OMGのCORBA 2.5の仕様に従って実装されています。詳細については，CORBAの仕様を参照してください。

他社CORBA製品との接続の際は，十分な接続検証が必要です。

1.5　Borland Enterprise Server VisiBrokerの開発環境

Borland Enterprise Server VisiBrokerは開発フェーズと配置フェーズの両方で使用します。Borland Enterprise Server VisiBrokerの開発環境には，次のコンポーネントが含まれます。

アドミニストレーションツールとプログラミングツール

VisiBroker ORB

1.5.1　プログラミングツール

開発フェーズで使用するツールを表1-1に示します。

表1‒1　プログラミングツール一覧

ツール

目的

idl2ir

Borland Enterprise Server VisiBrokerのIDLファイルで定義されたインタフェースをIRに格納します。

idl2java

JavaのスタブとスケルトンをIDLファイルから生成します。

idl2cpp

C++のスタブとスケルトンをIDLファイルから生成します。

java2iiop

JavaのスタブとスケルトンをJavaファイルから生成します。このツールによって，使用するインタフェースをIDLではなくJavaで定義できます。

java2idl

Javaバイトコードを格納したファイルからIDLファイルを生成します。

1.5.2　CORBAサービスツール

開発時にVisiBroker ORBを管理するために使用するツールを表1-2に示します。

表1‒2　CORBAサービスツール一覧

ツール

目的

irep

インタフェースリポジトリを管理するのに使用します。「16.　インタフェースリポジトリの使用」を参照してください。

oad

OADを管理するのに使用します。「15.　オブジェクト活性化デーモンの使用」を参照してください。

nameserv

ネーミングサービスのインスタンスを起動するのに使用します。「14.　ネーミングサービスの使用」を参照してください。

1.5.3　アドミニストレーションツール

開発時にVisiBroker ORBを管理するために使用するツールを表1-3に示します。

表1‒3　アドミニストレーションツール一覧

ツール

目的

oadutil list

OADに登録されているVisiBroker ORBオブジェクトインプリメンテーションをリスト出力します。

oadutil reg

OADにVisiBroker ORBオブジェクトインプリメンテーションを登録します。

oadutil unreg

OADからVisiBroker ORBオブジェクトインプリメンテーションを登録解除します。

osagent

スマートエージェントを管理します。「12.　スマートエージェントの使用」を参照してください。

osfind

特定のネットワークで動作しているオブジェクトについて報告します。

1.6　Java開発環境

Borland Enterprise Server VisiBrokerはJavaランタイム環境で次のコンポーネントを使用します。

Java 2標準版

Javaランタイム環境

Borland Enterprise Server VisiBrokerでの必要事項

1.6.1　Java 2標準版

VisiBroker ORBを使用するアプレットやアプリケーションを開発するには，Inprise JBuilderのようなJava開発環境が必要です。JavaSoftのJDK（Java Developer's Kit）もまたJavaランタイム環境を含んでいます。

Sun Microsystemsは，Javaランタイム環境を組み込んだJavaSoftのJDKをSolaris，Windowsプラットフォーム用に用意しました。このJDKはSun MicrosystemsのWebサイトからダウンロードできます。

JDKはIBM AIX，OS/2，SGI IRIX，およびHP-UXにも格納されています。このバージョンのJDKは，それぞれのハードウェアベンダのWebサイトからダウンロードできます。各プラットフォームが使用できるものを確認するには，Sun MicrosystemsのJava Soft Webサイトにアクセスしてください。

1.6.2　Javaランタイム環境

Borland Enterprise Server VisiBrokerの開発環境のサービスおよびツールを実行するすべてのエンドユーザには，Javaランタイム環境が必要です。Javaランタイム環境とは，Javaアプリケーションを解釈して実行するエンジンのことです。一般に，Javaランタイム環境はJava開発環境にバンドルされています。

1.6.3　CORBAに対するBorland Enterprise Server VisiBrokerの準拠での必要事項

ゲートキーパーには，JavaServer Web Development Kit 1.0.1で取得するServlet API 2.1を使用する必要があります。

1.6.4　Java対応Webブラウザ

アプレットは，Netscape Communicator，Netscape Navigator，Microsoft Internet ExplorerなどのJava対応のWebブラウザで実行できます。

1.7　C++またはJavaのBorland Enterprise Server VisiBrokerでのインターオペラビリティ

Borland Enterprise Server VisiBroker（Java）で開発したアプリケーションは，Borland Enterprise Server VisiBroker（C++）で開発したオブジェクトインプリメンテーションにリクエストできます。同じように，Borland Enterprise Server VisiBroker（C++）で作成したアプリケーションもBorland Enterprise Server VisiBroker（Java）で開発したオブジェクトインプリメンテーションにリクエストできます。例えば，Borland Enterprise Server VisiBroker（C++）でJavaアプリケーションを使用する場合，単にJavaアプリケーションを開発するために使用した同じIDLを，Borland Enterprise Server VisiBroker（C++）で提供されているIDLコンパイラへの入力として使用します。これで，結果として生成されたC++スケルトンを使用してオブジェクトインプリメンテーションを開発できます。Borland Enterprise Server VisiBroker（Java）でC++アプリケーションを使用するには，同じ処理を行います。ただし，Borland Enterprise Server VisiBroker（Java）で提供されているIDLコンパイラを使用します。

また，Borland Enterprise Server VisiBroker（Java）で書かれたオブジェクトインプリメンテーションは，Borland Enterprise Server VisiBroker（C++）で作成したクライアントと一緒に動作します。Borland Enterprise Server VisiBroker（Java）で作成したアプリケーションと，他社製CORBAアプリケーションとの接続の際は十分な接続検証が必要です。また，これはBorland Enterprise Server VisiBroker（C++）のオブジェクトインプリメンテーションにも適用されます。

1.8　ほかのORB製品とのインターオペラビリティ

CORBA準拠のソフトウェアオブジェクトはIIOPを使用して通信します。Borland Enterprise Server VisiBrokerがIIOPを使用すれば，Borland Enterprise Server VisiBrokerを使用して開発したクライアントアプリケーションとサーバアプリケーションは，さまざまなベンダのORB製品とのインターオペラビリティを実現できますが，他社CORBA製品と接続の際は十分な接続検証が必要です。

1.9　IDLからC++へのマッピング（C++）

Borland Enterprise Server VisiBrokerは，OMG IDL/C++言語マッピング仕様に従っています。idl2cppコンパイラがインプリメントしている，Borland Enterprise Server VisiBrokerの現在のIDLのC++言語へのマッピングの概要については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「IDLからC++言語へのマッピング」の記述を参照してください。

マッピング仕様の詳細については，OMG IDL/C++言語マッピング仕様を参照してください。

1.10　IDLからJavaへのマッピング（Java）

Borland Enterprise Server VisiBrokerはOMG IDL/Java言語マッピング仕様に従っています。idl2javaコンパイラがインプリメントしているBorland Enterprise Server VisiBrokerの現在のIDLのJava言語へのマッピングの概要については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「IDLからJavaへのマッピング」の記述を参照してください。

マッピング仕様の詳細については，OMG IDL/Java言語マッピング仕様を参照してください。

2　環境設定

この章では，Borland Enterprise Server VisiBrokerを使用する前に設定する環境変数について説明します。

2.1　PATH環境変数の設定

ここでは，PATH環境変数の設定方法を説明します。

注

PATH環境変数は，Borland Enterprise Server VisiBrokerのbinディレクトリを含めるようにインストール中に自動的に設定されます。

環境変数PATHにJavaVMのディレクトリをダブルクォーテーション(" )で囲って設定しないでください。

PATH環境変数の明示的な設定を選択する場合の手順を次に説明します。

2.1.1　WindowsのDOSコマンドによるPATH環境変数の設定

Borland Enterprise Server VisiBrokerがc:¥inprise¥vbrokerにインストールされている場合，次のDOSコマンドでPATH環境変数を設定できます。

prompt> set PATH=c:¥inprise¥vbroker¥bin;%PATH%

Borland Enterprise Server VisiBroker配布内容が，ドライブCのデフォルトのディレクトリBESにインストールされている場合，PATH環境変数を次のように設定できます。

prompt> set PATH=c:¥BES¥vbroker¥bin;%PATH%

2.1.2　WindowsのシステムコントロールパネルによるPATH環境変数の設定

DOSのsetコマンドを使用してWindowsの環境変数を設定できますが，システムコントロールパネルを使用して自動的にPATH環境変数を設定する方が簡単です。Borland Enterprise Server VisiBrokerがc:¥inprise¥vbrokerにインストールされている場合，次に示す手順でシステムコントロールパネルのPATH環境変数を編集します。

システムコントロールパネルを開きます。

システムプロパティウィンドウで環境変数ボタンを選択します。

変数に「PATH」を選択して編集します。

編集ボタンをクリックして変数の値を編集します。

次のパス名をPATHに追加します。

c:¥inprise¥vbroker¥bin

Borland Enterprise Server VisiBrokerがデフォルトのディレクトリにインストールされていれば，PATH環境変数は次のようになります。

c:¥BES¥vbroker¥bin

注

システムコントロールパネルで環境変数を変更しても，現在実行中のアプリケーションには反映されませんが，そのあと起動されたアプリケーションとコマンドプロンプトには新しい設定が反映されます。

2.1.3　UNIXでのPATH環境変数の設定

cshを使用していて，かつBorland Enterprise Server VisiBrokerを/usr/local/vbrokerにインストールしている場合，次に示すコマンドを使用してPATH環境変数を更新できます。

prompt> setenv PATH /usr/local/vbroker/bin:$PATH

Bourneシェルを使用していて，かつBorland Enterprise Server VisiBrokerを/usr/local/vbrokerにインストールしている場合，次に示すコマンドを使用してPATH環境変数を更新できます。

prompt> PATH=$PATH:/usr/local/vbroker/bin
prompt> export PATH

2.2　CLASSPATH環境変数の設定（Java）

CLASSPATH環境変数には，システムで使用している各種Javaパッケージの位置を定義します。Borland Enterprise Server VisiBrokerをインストールしたり構成したりする場合は，CLASSPATH環境変数を設定する必要はありません。

2.3　VBROKER_ADM環境変数の設定

VBROKER_ADM環境変数には，Borland Enterprise Server VisiBrokerのOAD（オブジェクト活性化デーモン）およびスマートエージェントの構成情報が格納されている管理ディレクトリを定義します。

VBROKER_ADM環境変数は，必ず設定してください。

2.3.1　WindowsでのVBROKER_ADM環境変数の設定

自分のディレクトリC:¥my¥admを使用したい場合は，次のようにVBROKER_ADM環境変数を設定します。

prompt> set VBROKER_ADM=c:¥my¥adm

VBROKER_ADM環境変数はvregeditツールを使用してレジストリに設定することもできます。ただし，レジストリと環境変数の両方が設定されている場合，環境変数の設定が有効になります。

2.3.2　UNIXでのVBROKER_ADM環境変数の設定

cshを使用していて，かつBorland Enterprise Server VisiBrokerを/usr/localにインストールしている場合，次のようにVBROKER_ADM環境変数を設定します。

prompt> setenv VBROKER_ADM /usr/local/vbroker/adm

Bourneシェルを使用していて，かつBorland Enterprise Server VisiBrokerを/usr/localにインストールしている場合，次のようにVBROKER_ADM環境変数を設定します。

prompt> VBROKER_ADM=/usr/local/vbroker/adm
prompt> export VBROKER_ADM

2.4　OSAGENT_PORT環境変数の設定

OSAGENT_PORT環境変数には，スマートエージェントが監視するポート番号を定義します。ポート番号は5001から65535の範囲で任意の値を設定できますが，デフォルトではスマートエージェントはポート番号14000で監視します。

2.4.1　WindowsでのOSAGENT_PORT環境変数の設定

スマートエージェントにポート番号10000で監視させたい場合は，次のようにOSAGENT_PORT環境変数を設定します。

prompt> set OSAGENT_PORT=10000

OSAGENT_PORT環境変数はvregeditツールを使用してレジストリに設定することもできます。ただし，レジストリと環境変数の両方が設定されている場合，環境変数の設定が有効になります。

2.4.2　UNIXでのOSAGENT_PORT環境変数の設定

cshを使用していて，スマートエージェントにポート番号10000で監視させたい場合，次のようにOSAGENT_PORT環境変数を設定します。

prompt> setenv OSAGENT_PORT 10000

Bourneシェルを使用していて，スマートエージェントにポート番号10000で監視させたい場合，次のようにOSAGENT_PORT環境変数を設定します。

prompt> OSAGENT_PORT=10000
prompt> export OSAGENT_PORT

2.5　ロギング出力

Borland Enterprise Server VisiBrokerのツールの多くは，実行中のツールに関する情報を表示するバーボースモードを提供しています。またBorland Enterprise Server VisiBrokerライブラリとリンクしたアプリケーションは，出力を生成することもできます。UNIXのシステムでは，この出力はコンソールに書き込まれます。Windowsのシステムでは，この出力は対応するログファイルに書き込まれます。

表2-1はWindowsで生成できるログファイル名をまとめたものです。

表2‒1　Windowsで生成されるログファイル名のまとめ

ファイル名

説明

osagent.log

スマートエージェントによって生成されます。

osagentに-vオプションを指定して起動した場合，このファイルは単調増加します。

viserr.log

スマートエージェントおよび，C++ORB機能を使用したアプリケーションによって生成されます。

vislog.log

visout.log

osagent.logファイルの出力先は，次の規則に従って決定されます。

OSAGENT_LOG_DIR環境変数が指すディレクトリ

<osagentを起動したドライブ>¥vbroker¥log¥

ディレクトリが存在しない場合は，作成を試みます。

カレントディレクトリ

注

osagent.logファイルの出力先に書き込み権限を与えてください。書き込み権限がないと，osagentは起動できません。

viserr.log，vislog.log，visout.logファイルの位置は，次の規則に従って決定されます。

VBROKER_ADM環境変数が指すディレクトリ内のlogディレクトリ

ディレクトリが存在しない場合は，作成を試みます。

カレントディレクトリ

3　プロパティの設定

この章では，プロパティテキストファイルやコマンドライン引数でVisiBroker ORBプロパティを設定する方法を説明します。

3.1　概要

VisiBroker ORBは，その特徴を定義する特定のプロパティのセットを持ちます。例えば，vbroker.agent.debugは，VisiBrokerアプリケーションとスマートエージェントの間の通信についてのデバッグ情報を出力するようVisiBroker ORBに指示します。VisiBroker ORBの各プロパティはstring，unsigned long，booleanなどのあらかじめ定められたデータ型と値を持ちます。例えば，vbroker.agent.enableLocator=falseはVisiBrokerアプリケーションに対してスマートエージェントとの通信を行わないように指示します。

VisiBroker ORBが初期化処理を開始すると，これらのプロパティの多くが読み込まれます。

VisiBroker ORBプロパティは，アプリケーション起動時にプロパティファイルまたはコマンドライン引数に指定できます。プロパティファイルは次のように記述されています。

コードサンプル3-1　プロパティファイルの抜粋

vbroker.agent.enableLocator=false

コマンドライン引数にプロパティを指定すると次のようになります。

コードサンプル3-2　コマンドライン引数によるプロパティ設定例

C++の場合

Server -Dvbroker.agent.port=14999

Javaの場合

vbj Server -vbroker.agent.port 5024

プロパティの優先順位については，「3.3　WindowsおよびUNIXプラットフォームでのプロパティの優先順位」を参照してください。Javaアプレットに関しては，「3.4　アプレットのプロパティの優先順位」を参照してください。

プロパティは，CORBA::ORB_init()（C++の場合）またはORB.init()（Javaの場合）が呼び出されたときに渡された引数から読み込まれます。プロパティマネージャ内のメモリにプロパティが格納されると，ファイルまたはコマンドライン引数は参照されません。

作成したクライアントアプリケーションをjavaコマンドで起動する場合には，次のプロパティ一覧で示したプロパティ情報を，JavaVMに渡して起動する必要があります。各プロパティ値に指定する値はアプリケーション起動時に-VBJdebugオプションを指定して出力されるデバッグ情報を参考にしてください。

表3‒1　プロパティ一覧

＃

プロパティ名

1

javax.rmi.CORBA.StubClass

2

javax.rmi.CORBA.UtilClass

3

javax.rmi.CORBA.PortableRemoteObjectClass

4

org.omg.CORBA.ORBClass

5

org.omg.CORBA.ORBSingletonClass

6

vbroker.agent.port

7

vbroker.orb.admDir

8

java.endorsed.dirs

9

application.home

10

java.class.path

3.2　Borland Enterprise Server VisiBrokerのプロパティの設定

Borland Enterprise Server VisiBrokerのプロパティは，次の方法で設定できます。

シェル／コンソールの環境変数

Windowsレジストリ

コマンドライン引数

プロパティファイル（ORBpropStorageオプションを使用）

アプレットのパラメタ（ORB.initの第1パラメタ）（Javaの場合）

システムプロパティ（Javaの場合）

プロパティ（Javaの場合）

3.2.1　シェル／コンソールの環境変数

環境変数は，プログラムが起動するときに自動的に読み込まれます。環境変数は，次の表に示すとおりにプロパティに変換されます。

表3‒2　シェル／コンソール環境から設定できるプロパティ

環境変数

プロパティ名

OSAGENT_ADDR

vbroker.agent.addr

OSAGENT_ADDR_FILE

vbroker.agent.addrFile

OSAGENT_PORT

vbroker.agent.port

VBROKER_ADM

vbroker.orb.admDir

注

Javaの場合，VisiBroker ORBが提供するvbjコマンドやネーミングサービス（nameservプロセス）などを使用しないで，JavaコマンドによってJavaアプリケーションを起動したときは，環境変数からプロパティへの変換は行われません。

次に示すのは，環境変数の設定例です。

コードサンプル3-3　環境変数の設定

UNIX（cshの場合）

setenv OSAGENT_PORT 10000
setenv VBROKER_ADM /usr/local/vbroker/adm

Windows

set OSAGENT_PORT=10000
set VBROKER_ADM=c:¥Borland¥VBroker¥adm

注

Borland Enterprise Server VisiBrokerの環境変数の設定の詳細については，「2.　環境設定」を参照してください。

3.2.2　Windowsレジストリ

環境変数はWindowsレジストリに設定できます。レジストリの設定はvregeditツールを使用して容易に変更できます。

Windowsレジストリに設定した環境変数は，通常の環境変数と同じようにシステムプロパティに変換されます（Javaの場合）。ただし，環境変数の設定がレジストリの設定よりも優先されます。

3.2.3　コマンドライン引数

プロパティファイルに記載される任意のプロパティは，コマンドライン引数によっても設定できます。CORBA::ORB_init()（C++の場合）またはORB.init()（Javaの場合）へコマンドライン引数を渡してください。

コードサンプル3-4　コマンドラインからのプロパティ設定

C++の場合

Server -Dvbroker.agent.port=1024

注

ORBで始まるVisiBroker 3.x形式のプロパティには，-Dを指定する必要はありません。例を次に示します。

Server -ORBxxxx yyyy

Javaの場合

vbj Server -vbroker.agent.port 1024

注

コマンドラインで設定したプロパティは，デフォルトプロパティをオーバーライドします。

コマンドラインの引数は，パラメタとしてアプリケーションクラスに渡されます。例えば，次のコマンドを実行すると，プロパティvbroker.agent.portに値15000が設定され，Serverというアプリケーションに渡されます。

vbj Server -vbroker.agent.port 15000

パラメタリストには二つ以上のプロパティを指定できます。

vbj Server -ORBagent.Port 15000などのように，ORBまたはvbroker.で始まるプロパティだけがこの方法で指定できます。また，ORBで始まるプロパティは適切なvbroker.プロパティに変換します（ORBpropStorageは例外です）。

これらの設定はORB.initの第1パラメタとして渡されることで有効になります。

3.2.4　プロパティファイル（ORBpropStorageオプションを使用）

プロパティ名ORBpropStorageを使用して，コマンドライン引数でシステムプロパティとして指定します。

なお，Javaの場合は，アプレットのパラメタで指定する方法もあります。詳細については，「3.2.5　アプレットのパラメタ（ORB.initの第1パラメタ）（Javaの場合）」を参照してください。

プロパティファイルはテキストファイルで，次の形式でプロパティを1行ずつ記述します。

<property name>=<property value>

VisiBroker ORBはあらかじめ定義されたプロパティ名のセットを持ちます。プロパティ名は大文字と小文字が区別されるため，リスト表示された名前をそのまま正確に入力するよう注意してください。正しい形式であれば，各プロパティをどの順番で入力してもかまいません。ただし，プロパティを論理グループに分割した方がファイルは読みやすくなります。各グループはコメント行（「#」で始まる行）でラベルづけできます。空行とコメント行は無視されます。

コードサンプル3-5　プロパティのグループ化

#OSAgent properties
vbroker.agent.debug=false
vbroker.agent.addr=null
vbroker.agent.port=14000
vbroker.agent.addrFile=null
vbroker.agent.enableLocator=true

プロパティのデータ型には，次の三つがあります。

string

unsigned long

boolean

文字列の値がnullであれば，プロパティの値にnullと入力できます。

コードサンプル3-6　null値の設定

vbroker.repository.name=null

値がboolean値の場合は，trueまたはfalseを入力します。

コードサンプル3-7　boolean値の設定

vbroker.agent.enableLocator=true

プロパティを使用するには，プロパティをファイルに格納し，次のコマンドライン引数によって参照します。

C++の場合

-ORBpropStorage filename

Javaの場合

-DORBpropStorage=filename

filenameは，相対パスまたは絶対パスのどちらでも指定できます。

コードサンプル4-8　プロパティファイルの指定

C++の場合

Server -ORBpropStorage myprops

Javaの場合

vbj -DORBpropStorage=myprops Server

注

Javaの場合，-Dは必須であり，-Dに続く文字列がプロパティであることを示します。

3.2.5　アプレットのパラメタ（ORB.initの第1パラメタ）（Javaの場合）

アプレットのパラメタは，HTMLの<param>タグを使って指定します。

<applet ...>
   <param name="vbroker.agent.port" value="15000">
</applet>

一つのparamタグで一つのプロパティを定義します。ここでは，ORBで始まるプロパティから適切なvbroker.プロパティへの変換は行いません。これらの設定はORB.initの第1パラメタとして渡されます。

コードサンプル3-9　HTMLからのプロパティの設定

...
<applet class="MyCORBAApplet.class"
      codebase="."
      archive="my Lib.jar">
   <param name="vbroker.orb.alwaysTunnel" value="true">
   <param name="vbroker.orb.gatekeeper.ior" value="">
</applet>
...

3.2.6　システムプロパティ（Javaの場合）

-Dを使って定義したプロパティは，JavaVMによってシステムプロパティとして設定されます。

vbj -Dvbroker.agent.port=15000 Server

-Dの代わりに，次の形式でも指定できます。

-J-D<name>=<value>
-VBJprop <name>=<value>

コマンドラインの引数と異なる形式を使用できるのは，VisiBrokerではなくJavaVMによって構文解析されるためです。環境変数とレジストリの設定はシステムプロパティに変換され，JavaVMに渡されます。

注

VisiBroker ORBが提供するvbjコマンドやネーミングサービス（nameservプロセス）などを使用しないで，JavaコマンドによってJavaアプリケーションを起動した場合は，環境変数とレジストリの設定からシステムプロパティへの変換は行われません。

3.2.7　プロパティ（Javaの場合）

ORB.initはjava.util.Properties型のパラメタを受け取ります。このパラメタを使用して，プロパティのセットを渡すことができます。

3.3　WindowsおよびUNIXプラットフォームでのプロパティの優先順位

WindowsおよびUNIXプラットフォームでの，C++およびJavaのプロパティは次の優先順位で設定されます。

コマンドライン引数（C++およびJavaの場合）

システムプロパティ（Javaの場合）

プロパティファイル（ORBpropStorageオプションを使用）（C++およびJavaの場合）

プログラムでORB.initの第2パラメタに渡されるプロパティ（Javaの場合）

3.4　アプレットのプロパティの優先順位

アプレットのプロパティは次の優先順位で設定されます。

アプレットのパラメタ（ORB.initの第1パラメタ）

プロパティファイル（ORBpropStorageオプションを使用）

URLで指定する場合もあります。

プログラムでORB.initの第2パラメタに渡されるプロパティ

3.5　Borland Enterprise Server VisiBrokerプロパティ

Borland Enterprise Server VisiBrokerで使用できるプロパティのリストについては，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「Borland Enterprise Server VisiBrokerプロパティ」を参照してください。

サーバエンジンプロパティについては，「7.7.1　サーバエンジンプロパティの設定」を参照してください。

4　Borland Enterprise Server VisiBrokerによるサンプルアプリケーションの開発

この章では，C++およびJava用のオブジェクトベースの分散アプリケーションの開発手順を，サンプルアプリケーションを使用して説明します。

4.1　開発手順

この節では，サンプルアプリケーションのコードの位置と開発手順の概要について説明します。

4.1.1　サンプルアプリケーションのパッケージの位置

サンプルアプリケーションのC++およびJavaのコードは，Borland Enterprise Server VisiBrokerのパッケージがインストールされているexamples/vbe/basic/bank_agentディレクトリ（Windowsの場合は，"/"を"¥"に読み替えてください）下のbank_agent.htmlファイルにあります。各パッケージの位置がわからない場合は，システム管理者に問い合わせてください。

4.1.2　開発手順の概要

Borland Enterprise Server VisiBrokerで分散アプリケーションを開発する場合，まずアプリケーションに必要なオブジェクトを識別する必要があります。図4-1に，サンプルのバンクアプリケーションを開発する手順を示します。バンクサンプルを開発する手順の概要を次に示します。

IDL（インタフェース定義言語）を使用して各オブジェクトの仕様を記述します。

IDLは，オブジェクトが提供するオペレーションとその起動方法を指定するために実装者が使用する言語です。この例では，balance()メソッドを使用してAccountインタフェースを，open()メソッドを使用してAccountManagerインタフェースをそれぞれIDLで定義します。

IDLコンパイラを使用してクライアントのスタブコードとサーバPOAのサーバントコードを生成します。

手順1.のインタフェース仕様で，idl2java（Java）コンパイラまたはidl2cpp（C++）コンパイラを使用して，クライアント側のスタブ（AccountオブジェクトメソッドとAccountManagerオブジェクトメソッドとのインタフェースを提供する）とサーバ側のクラス（リモートオブジェクトのインプリメンテーションのクラスを提供する）を作成します。

クライアントプログラムコードを記述します。

クライアントプログラムのインプリメンテーションを完成させるには，VisiBroker ORBを初期化し，AccountオブジェクトとAccountManagerオブジェクトにバインドし，これらのオブジェクトのメソッドを呼び出し，残高を表示します。

サーバオブジェクトコードを記述します。

サーバオブジェクトコードのインプリメンテーションを完成させるには，AccountPOAクラスとAccountManagerPOAクラスから派生を行い，interfaceのメソッドのインプリメンテーションを提供し，サーバのmainルーチンをインプリメントする必要があります。

クライアントとサーバコードをコンパイルします。

C++の場合

クライアントプログラムを生成するには，クライアントプログラムコードをクライアントスタブとコンパイルしてリンクしてください。

Accountサーバを生成するには，サーバオブジェクトコードをサーバスケルトンとコンパイルしてリンクしてください。

Javaの場合

クライアントプログラムを生成するには，クライアントプログラムコードをクライアントスタブとコンパイルしてください。

Accountサーバを生成するには，サーバオブジェクトコードをサーバスケルトンとコンパイルしてください。

サーバを起動します。

クライアントプログラムを実行します。

図4‒1　サンプルのバンクアプリケーションの開発

ORBはhvまたはHVで始まる名称の関数，クラス，グローバル変数，環境変数を使用します。この名称で始まる関数，クラス，グローバル変数，環境変数などを使用した開発はしないでください。

4.2　手順1：オブジェクトインタフェースの定義

Borland Enterprise Server VisiBrokerによるアプリケーション生成の最初の手順は，OMGのIDL（インタフェース定義言語）を使用して，使用するすべてのオブジェクトとそのインタフェースを指定することです。IDLはさまざまなプログラミング言語にマッピングできます。C++およびJavaのそれぞれのマッピングについては，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「IDLからC++言語へのマッピング」および「IDLからJavaへのマッピング」の記述を参照してください。

次にidl2cpp（C++）またはidl2java（Java）コンパイラを使用してIDL指定からスタブルーチンとサーバントコードを生成します。クライアントプログラムはスタブルーチンを使用してオブジェクトのオペレーションを呼び出します。自分で記述したコードとともにサーバントコードを使用して，オブジェクトをインプリメントするサーバを作成してください。クライアントとオブジェクト用のコードは一度完成すれば，クライアントJavaアプレットまたはアプリケーションとオブジェクトサーバを作成するためにC++コンパイラまたはJavaコンパイラへの入力として使用されます。

4.2.1　IDLでのAccountインタフェースの記述

IDLはC++と似た構文を持ち，モジュール，インタフェース，データ構造などの定義に使用できます。

IDLサンプル4-1は，サンプルbank_agentのBank.idlファイルの内容です。Accountインタフェースは，現在の残高を取得するためにC++で一つのメソッド，Javaで一つのメソッドを提供します。AccountManagerインタフェースは，ユーザのアカウントが存在しなければそれを生成します。

IDLサンプル4-1　Bank.idlファイルはAccountインタフェース定義を提供する

module Bank{
   interface Account {
      float balance();
   };
   interface AccountManager {
      Account open(in string name);
   };
};

4.3　手順2：クライアントスタブとサーバサーバントの生成

IDLで作成するインタフェース定義は，Borland Enterprise Server VisiBrokerのidl2cppコンパイラがクライアントプログラム用のC++スタブルーチンとオブジェクトインプリメンテーション用のスケルトンコードを生成するために，またはidl2javaコンパイラがクライアントプログラム用のJavaクラスとオブジェクトインプリメンテーション用のスケルトンコードを生成するために使用します。

C++の場合

スタブルーチンは，すべてのメンバ関数呼び出しでクライアントプログラムが使用します。

Javaの場合

Javaクラスは，すべてのメソッド呼び出しでクライアントプログラムが使用します。

自分で記述したコードとともにスケルトンコードを使用して，C++およびJava用のオブジェクトをインプリメントするサーバを生成してください。

C++の場合

クライアントプログラムとサーバオブジェクト用のコードが完成すると，このコードをC++コンパイラとリンカへの入力として使用してクライアントとサーバを作成します。

Javaの場合

クライアントプログラムとサーバオブジェクト用のコードが完成すると，このコードをJavaコンパイラへの入力として使用してクライアントとサーバの実行可能クラスを作成します。

クライアントスタブとサーバサーバントを生成する手順については，「4.1　開発手順」を参照してください。

Bank.idlファイルは特別な処理を必要としないので，次のコマンドでファイルをコンパイルできます。

C++の場合

prompt> idl2cpp Bank.idl

Javaの場合

prompt> idl2java Bank.idl

idl2cppおよびidl2javaコンパイラに関するコマンドラインオプションの詳細については，「11.　IDLの使用」を参照してください。

4.3.1　IDLコンパイラが作成するファイル

(1)　C++の場合

idl2cppコンパイラはBank.idlファイルから次の四つのファイルを生成します。

Bank_c.hh

AccountおよびAccountManagerクラスの定義を含みます。

Bank_c.cpp

クライアントが使用する内部スタブルーチンを含みます。

Bank_s.hh

AccountPOAおよびAccountManagerPOAサーバントクラスの定義を含みます。

Bank_s.cpp

サーバが使用する内部ルーチンを含みます。

ユーザはBank_c.hhファイルとBank_c.cppファイルを使用してクライアントアプリケーションを構築します。Bank_s.hhファイルとBank_s.cppファイルはサーバオブジェクトを構築するために使用します。生成されたファイルとソースファイルとを区別するために，生成されたファイルにはすべて.cppか.hhという拡張子が付けられます。

Windows

idl2cppコンパイラから生成されたファイルのデフォルトの拡張子は.cppですが，Borland Enterprise Server VisiBrokerの例に対応するMakefileは，-src_suffixを使用して，出力を指定の拡張子に変更します。

(2)　Javaの場合

Javaでは，ファイルごとに一つのパブリックインタフェースまたはクラスだけ使用できるので，IDLファイルをコンパイルすると複数の.javaファイルを生成します。このようなファイルは生成されたBankというサブディレクトリに格納されます。BankディレクトリはIDLで指定されたモジュール名であり，生成済みのファイルが属するパッケージです。生成される.javaファイルのリストを次に示します。

_AccountManagerStub.java

クライアント側のAccountManagerオブジェクトのスタブコードです。

_AccountStub.java

クライアント側のAccountオブジェクトのスタブコードです。

Account.java

Accountインタフェース宣言です。

AccountHelper.java

ユーティリティメソッドを定義するAccountHelperクラスを宣言します。

AccountHolder.java

Accountオブジェクトを渡すためのホルダを提供するAccountHolderクラスを宣言します。

AccountManager.java

AccountManagerインタフェース宣言です。

AccountManagerHelper.java

ユーティリティメソッドを定義するAccountManagerHelperクラスを宣言します。

AccountManagerHolder.java

AccountManagerオブジェクトを渡すためのホルダを提供するAccountManagerHolderクラスを宣言します。

AccountManagerOperation.java

このインタフェースは，Bank.idlファイルでAccountManagerインタフェースに定義されたメソッドシグニチャを宣言します。

AccountManagerPOA.java

サーバ側のAccountManagerオブジェクトインプリメンテーション用のPOAサーバンドコード（インプリメンテーションベースコード）です。

AccountManagerPOATie.java

サーバ側のAccountManagerオブジェクトをtie機能を使用してインプリメントするためのクラスです。tie機能の詳細については，「9.　tie機能の使用」を参照してください。

AccountOperations.java

このインタフェースは，Bank.idlファイルでAccountインタフェースに定義されたメソッドシグニチャを宣言します。

AccountPOA.java

サーバ側のAccountオブジェクトインプリメンテーション用のPOAサーバンドコード（インプリメンテーションベースコード）です。

AccountPOATie.java

サーバ側のAccountオブジェクトをtie機能を使用してインプリメントするためのクラスです。tie機能の詳細については，「9.　tie機能の使用」を参照してください。

Helperクラス，Holderクラス，およびOperationsクラスの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「生成されるインタフェースとクラス（Java）」の記述を参照してください。

4.4　手順3：クライアントのインプリメント

bankクライアントをインプリメントするために使用するクラスの多くは，前述の例で説明したように，idl2cpp（C++）が生成したBankコード，またはidl2java（Java）コンパイラが生成したBankパッケージに入っています。

bank_agentディレクトリに格納されているClient.Cファイル（C++）およびClient.javaファイル（Java）はこの例をわかりやすく説明します。通常は，このファイルは自分で作成してください。

4.4.1　Client.C

Clientプログラムは，bankのアカウントの現在の残高を取得するクライアントアプリケーションをインプリメントします。bankクライアントプログラムは次の手順を実行します。

VisiBroker ORBを初期化します。

AccountManagerオブジェクトにバインドします。

bind()メソッドが返すオブジェクトリファレンスを使用して，Accountの残高を取得します。

Accountオブジェクトでbalanceを呼び出して，残高を取得します。

コードサンプル4-1　クライアント側のプログラム（C++）

#include "Bank_c.hh"
int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
      // Get the manager Id
      PortableServer::ObjectId_var managerId =
            PortableServer::string_to_ObjectId("BankManager");
      // Locate an account manager. Give the full POA name and
      // the servant ID.
      Bank::AccountManager_ptr manager =
      Bank::AccountManager::_bind(
            "/bank_agent_poa", managerId);
      // use argv[1] as the account name, or a default.
      const char* name = argc > 1 ? argv[1] : "Jack B. Quick";
      // Request the account manager to open a named account.
      Bank::Account_ptr account = manager->open(name);
      // Get the balance of the account.
      float balance = account->balance();
      // Print out the balance.
      cout << "The balance in "<< name << "'s account is $"
            << balance << endl;
   } catch(const CORBA::Exception& e) {
     cerr << e << endl;
   }
}

4.4.2　Client.java

Clientクラスは，bankのアカウントの現在の残高を取得するクライアントアプリケーションをインプリメントします。bankクライアントプログラムは次の手順を実行します。

VisiBroker ORBを初期化します。

AccountManagerオブジェクトにバインドします。

AccountManagerオブジェクトでopenを呼び出して，Accountオブジェクトを取得します。

Accountオブジェクトでbalanceを呼び出して，残高を取得します。

コードサンプル4-2　クライアント側のプログラム（Java）

public class Client {
   public static void main(String[ ] args){
      // Initialize the ORB.
      org.omg.CORBA.ORB orb =
                         org.omg.CORBA.ORB.init(args, null);
      // Get the manager Id
      byte[ ] managerId = "BankManager".getBytes();
      // Locate an account manager.
      // Give the full POA name and the servant ID.
      Bank.AccountManager manager =
            Bank.AccountManagerHelper.bind(orb,
                                           "/bank_agent_poa",
                                            managerId);
      // use args[0] as the account name, or a default.
      String name = args.length > 0 ? args[0] : "Jack B. Quick";
      // Request the account manager to open a named account.
      Bank.Account account = manager.open(name);
      // Get the balance of the account.
      float balance = account.balance();
      // Print out the balance.
      System.out.println("The balance in " + name +
                         "'s account is $" + balance);
   }
}

4.4.3　AccountManagerオブジェクトへのバインド

クライアントプログラムは，open（String name）メソッドを呼び出す前に，まずbind()メソッドを使用してAccountManagerオブジェクトをインプリメントするサーバとのコネクションを確立する必要があります。

C++の場合

bind()メソッドのインプリメンテーションは，idl2cppコンパイラが自動的にインプリメントします。bind()メソッドは，サーバを探してコネクションを確立するようVisiBroker ORBにリクエストします。

Javaの場合

bind()メソッドのインプリメンテーションは，idl2javaコンパイラが自動的に生成します。bind()メソッドは，サーバを探してコネクションを確立するようVisiBroker ORBにリクエストします。

サーバの探索に成功し，コネクションが確立されると，サーバのAccountManagerPOAオブジェクトに対応するプロキシオブジェクトが作成されます。AccountManagerオブジェクトのオブジェクトリファレンスはクライアントプログラムに返されます。

4.4.4　Accountオブジェクトの取得

次に，クライアントクラスは，指定された顧客名に対するAccountオブジェクトのオブジェクトリファレンスを取得するためにAccountManagerオブジェクトのopen()メソッドを呼び出す必要があります。

4.4.5　残高の取得

クライアントプログラムがAccountオブジェクトとのコネクションを確立すると，balance()メソッドを使用して残高を取得できます。クライアント側のbalance()メソッドは実際にはidl2cppまたはidl2javaコンパイラが生成したスタブであり，リクエストが必要とするデータをすべて集め，それをサーバオブジェクトに送ります。

4.4.6　AccountManagerHelper.java（Java）

このファイルはBankパッケージに入っています。このファイルはAccountManagerHelperオブジェクトを格納し，このオブジェクトをインプリメントするサーバにバインドするための複数のメソッドを定義します。bind()クラスメソッドは，指定されたPOAマネージャとコンタクトしてオブジェクトを解決します。サンプルアプリケーションでは，オブジェクト名を受け付けるbind()メソッドを使用していますが，クライアントはオプションで特定のホストおよび特別なバインドオプションを指定できます。Helperクラスの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「Helperクラス」の記述を参照してください。

コードサンプル4-3　AccountManagerHelper.javaファイルの一部

package Bank;
public final class AccountManagerHelper {
  . . .
  public static Bank.AccountManager bind(
                                org.omg.CORBA.ORB orb){
    return bind(orb, null, null, null);
    . . .
  }
}

4.4.7　そのほかのメソッド

これまで説明してきたメソッド以外にも，クライアントプログラムがAccountManagerオブジェクトリファレンスを処理できるようにするメソッドが提供されています。

サンプルのクライアントアプリケーションではこれらのメソッドはほとんど使用していません。これらのメソッドの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」を参照してください。

4.5　手順4：サーバのインプリメント

クライアントの場合と同様に，bankサーバをインプリメントするために使用するクラスの多くは，idl2cppコンパイラが生成するヘッダファイル（C++）またはidl2javaコンパイラが生成するBankパッケージ（Java）に入っています。Server.CおよびServer.javaファイルは，この例をわかりやすく説明するために用意されたサーバインプリメンテーションです。通常は，プログラマがこのファイルを作成します。

4.5.1　サーバプログラム

このファイルは，サンプルのbankでサーバ側のServerクラスをインプリメントします。コードサンプル4-4はC++のサーバ側プログラムの例です。コードサンプル4-5はJavaのサーバ側プログラムの例です。サーバプログラムは次のように動作します。

ORBを初期化します。

必要なポリシーでポータブルオブジェクトアダプタを作成します。

アカウントマネージャのサーバントオブジェクトを作成します。

サーバントオブジェクトを活性化します。

POAマネージャ（とPOA）を活性化します。

入力リクエストを待ちます。

コードサンプル4-4　Server.Cプログラム（C++）

#include "BankImpl.h"
int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

      // get a reference to the rootPOA
      PortableServer::POA_var rootPOA =
            PortableServer::POA::_narrow(
            orb->resolve_initial_references("RootPOA"));

      CORBA::PolicyList policies;
      policies.length(1);
      policies[(CORBA::ULong)0] =
            rootPOA->create_lifespan_policy(
                  PortableServer::PERSISTENT);

      // get the POA Manager
      PortableServer::POAManager_var poa_manager =
            rootPOA->the_POAManager();

      // Create myPOA with the right policies
      PortableServer::POA_var myPOA = rootPOA->create_POA(
            "bank_agent_poa",
            poa_manager, policies);

      // Create the servant
      AccountManagerImpl managerServant;

      // Decide on the ID for the servant
      PortableServer::ObjectId_var managerId =
            PortableServer::string_to_ObjectId("BankManager");

      // Activate the servant with the ID on myPOA
      myPOA->activate_object_with_id(
            managerId, &managerServant);

      // Activate the POA Manager
      poa_manager->activate();

      cout << myPOA->servant_to_reference(&managerServant) <<
            "is ready" << endl;

      // Wait for incoming requests
      orb->run();
   } catch(const CORBA::Exception& e) {
      cerr << e << endl;
      return 1;
   }
   return 0;
}

コードサンプル4-5　Server.javaプログラム（Java）

public class Server {
   public static void main(String[ ] args) {
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);
         // get a reference to the rootPOA
         POA rootPOA = POAHelper.narrow(
                 orb.resolve_initial_references("RootPOA"));
         // Create policies for our persistent POA
            org.omg.CORBA.Policy[ ] policies = {
            rootPOA.create_lifespan_policy(
                                LifespanPolicyValue.PERSISTENT)
         };
         // Create myPOA with the right policies
         POA myPOA = rootPOA.create_POA("bank_agent_poa",
                                        rootPOA.the_POAManager(),
                                        policies );
         // Create the servant
         AccountManagerImpl managerServant =
                                   new AccountManagerImpl();
         // Decide on the ID for the servant
         byte[ ] managerId = "BankManager".getBytes();
         // Activate the servant with the ID on myPOA
         myPOA.activate_object_with_id(
                                  managerId,managerServant);
         // Activate the POA manager
         rootPOA.the_POAManager().activate();
         System.out.println(
                myPOA.servant_to_reference(managerServant) +
                                               "is ready.");
         // Wait for incoming requests
         orb.run();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

4.5.2　Accountクラス階層について（C++）

ユーザがインプリメントしたAccountクラスは，POA_Bank::Accountクラスから派生します。POA_Bank::Accountクラスはidl2cppコンパイラが生成したものです。Bank_c.hhファイルに定義してあるPOA_Bank::Accountクラスの定義を見ると，Accountクラスから派生していることがわかります。クラス階層を図4-2に示します。

図4‒2　AccountImplインタフェースのクラス階層

4.6　手順5：サンプルプログラムのビルド

C++の場合

ユーザが作成したClient.Cと生成されたBank_c.cppファイルがコンパイルされ，リンクされるとクライアントプログラムが作成されます。ユーザが作成したServer.Cファイルは，生成されたBank_s.cppファイルおよびBank_c.cppファイルと一緒にコンパイルされ，リンクされてBankアカウントサーバが作成されます。クライアントプログラムとサーバは，両方ともVisiBroker ORBライブラリとリンクしなければなりません。

Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamplesディレクトリには，このサンプルとほかのBorland Enterprise Server VisiBrokerのサンプルであるMakefile.cpp（C++）またはvbmake.bat（Java）が入っています。

C++の場合

サンプルのディレクトリにはstdmk（UNIX用）かstdmk_nt（Windows用）という名前のファイルがあり，ファイルの位置とMakefileが使用する変数設定を定義しています。

注（C++の場合）

コンパイラが指定のフラグをサポートしていなければ，stdmkファイルかstdmk_ntファイルをカスタマイズする必要があります。

4.6.1　サンプルのコンパイル

(1)　Windows

Borland Enterprise Server VisiBrokerがC:¥vbrokerにインストールされている場合，サンプルをコンパイルするには次のコマンドを入力します。

C++の場合

prompt> C:
prompt> cd ¥vbroker¥examples¥vbe¥basic¥bank_agent
prompt> nmake -f Makefile.cpp

Visual C++のコマンドnmakeは，idl2cppコンパイラを実行してから各ファイルをコンパイルします。

Javaの場合

prompt> C:
prompt> cd ¥vbroker¥examples¥vbe¥basic¥bank_agent
prompt> vbmake

vbmakeコマンドは，idl2javaコンパイラを実行してから各ファイルをコンパイルするバッチファイルです。

nmake（C++）またはvbmake（Java）の実行中に何らかの問題が生じた場合は，PATH環境変数がBorland Enterprise Server VisiBrokerをインストールしたbinディレクトリをポイントしていることを確認してください。またC++の場合，Borland Enterprise Server VisiBrokerをインストールしたディレクトリにVBROKERDIR環境変数を設定してみてください。

(2)　UNIX

Borland Enterprise Server VisiBrokerが/opt/vbrokerにインストールされている場合，サンプルをコンパイルするには次のコマンドを入力します。

prompt> cd /opt/vbroker/examples/vbe/basic/bank_agent

C++の場合

prompt> make cpp

Javaの場合

prompt> make java

このサンプルのmakeは標準のUNIXの機能です。PATHにmakeがなければ，システム管理者に問い合わせてください。

4.7　手順6：サーバの起動とサンプルの実行

これでクライアントプログラムとサーバインプリメンテーションがコンパイルできたので，Borland Enterprise Server VisiBrokerアプリケーションを実行するための準備ができました。

4.7.1　スマートエージェントの起動

Borland Enterprise Server VisiBrokerクライアントプログラムやサーバインプリメンテーションを実行する前に，まずローカルネットワーク上の一つ以上のホストでスマートエージェントを起動する必要があります。

スマートエージェントを起動するための基本コマンドは次のとおりです。

prompt> osagent

Windowsを実行中で，スマートエージェントをNTサービスとして起動したければ，インストール時にORBサービスをNTサービスとして登録する必要があります。サービスを登録したら，サービスコントロールパネルを介してスマートエージェントをNTサービスとして起動できます。

スマートエージェントについては，「12.　スマートエージェントの使用」を参照してください。

4.7.2　サーバの起動

(1)　Windows

コマンドプロンプトウィンドウを開き，次のDOSコマンドを使用してサーバを起動します。

C++の場合

prompt> Server

Javaの場合

prompt> vbj Server

(2)　UNIX

次のように入力してAccountサーバを起動します。

C++の場合

prompt> Server&

Javaの場合

prompt> vbj Server&

4.7.3　クライアントの実行

(1)　Windows

別のコマンドプロンプトウィンドウを開き，次のDOSコマンドを使用してクライアントを起動します。

C++の場合

prompt> Client

Javaの場合

prompt> vbj Client

次に示すような出力がされたかどうかを確認してください（アカウントの残高はランダムに計算されます）。

The balance in the account in $168.38.

(2)　UNIX

次のように入力してクライアントプログラムを起動します。

C++の場合

prompt> Client

Javaの場合

prompt> vbj Client

次に示すような出力がされたかどうかを確認してください（アカウントの残高はランダムに計算されます）。

The balance in the account in $168.38.

4.8　Borland Enterprise Server VisiBrokerを使用したアプリケーションの配置

Borland Enterprise Server VisiBrokerは配置フェーズでも使用します。このフェーズは，テストしてリリース準備ができているクライアントプログラムまたはサーバアプリケーションを，開発者が作成した場合に発生します。この時点で，システム管理者はクライアントプログラムをエンドユーザのデスクトップに配置したり，サーバアプリケーションをサーバクラスマシンに配置したりする準備ができています。

配置については，VisiBroker ORBはフロントエンドでクライアントプログラムをサポートします。クライアントプログラムを実行する各マシンにVisiBroker ORBをインストールしなければなりません。同じサーバマシン上の（VisiBroker ORBを使用する）複数のクライアントがVisiBroker ORBを共有します。また，VisiBroker ORBは，ミドルティア上のサーバアプリケーションもサポートします。サーバアプリケーションを実行する各マシンにORBをインストールしなければなりません。同じサーバマシン上の（VisiBroker ORBを使用する）サーバアプリケーションまたはオブジェクトでVisiBroker ORBを共有します。クライアントにはGUIフロントエンド，アプレット，およびクライアントプログラムが使用できます。サーバインプリメンテーションにはミドルティア上のビジネスロジックが含まれます。

図4-3に，VisiBroker ORBと一緒に配置されたクライアントプログラムとサーバプログラムを示します。

図4‒3　VisiBroker ORBと一緒に配置されたクライアントプログラムとサーバプログラム

4.8.1　Borland Enterprise Server VisiBrokerアプリケーション

(1)　アプリケーションの配置

Borland Enterprise Server VisiBrokerを使用して開発したアプリケーションを配置するには，まずアプリケーションを実行するホストでランタイム環境を設定して，必要なサポートサービスがローカルネットワークで使用できる状態であることを確認してください。

C++の場合

Borland Enterprise Server VisiBroker（C++）を使用して開発したアプリケーションに必要なランタイム環境には次のようなコンポーネントが含まれます。

Borland Enterprise Server VisiBrokerをインストールしたbinサブディレクトリにあるBorland Enterprise Server VisiBroker C++ライブラリ

アプリケーションに必要なサポートサービスの可用性

VisiBroker ORBライブラリは，配置されたアプリケーションを実行するホストにインストールしなければなりません。このライブラリは，アプリケーション環境用のPATHにインストールしなければなりません。

Javaの場合

Borland Enterprise Server VisiBroker（Java）を使用して開発したアプリケーションに必要なランタイム環境には，次のようなコンポーネントが含まれます。

Javaランタイム環境

Borland Enterprise Server VisiBrokerをインストールしたlibサブディレクトリのvbjorb.jarファイルにあるアーカイブしたBorland Enterprise Server VisiBrokerのJavaパッケージ

アプリケーションに必要なサポートサービスの可用性

Javaランタイム環境は，配置されたアプリケーションを実行するホストにインストールしなければなりません。Borland Enterprise Server VisiBrokerのJavaパッケージは，配置されたアプリケーションを実行するホストにインストールしなければなりません。

(a)　環境変数

配置されたアプリケーションが特定のホストのスマートエージェント（osagent）を使用する場合，アプリケーションを実行する前にOSAGENT_ADDR環境変数を設定しなければなりません。vbj実行形式ファイルを使用する場合は，環境変数が自動的に設定されます。ただし，次のコマンドライン引数を使用する場合，コマンドライン引数の指定が環境変数の指定より優先されます。

C++の場合

-ORBagentAddrコマンドライン引数またはvbroker.agent.addrコマンドライン引数を使用してホスト名またはIPアドレスを指定できます。

Javaの場合

vbroker.agent.addr（Java）コマンドライン引数を使用してホスト名またはIPアドレスを指定できます。

配置されたアプリケーションがスマートエージェント（osagent）との通信時に特定のUDPポートを使用する場合，アプリケーションを実行する前にOSAGENT_PORT環境変数を設定しなければなりません。次のコマンドライン引数を使用する場合，コマンドライン引数の指定が環境変数の指定より優先されます。

C++の場合

-ORBagentPortコマンドライン引数またはvbroker.agent.portコマンドライン引数を使用してIPポート番号を指定できます。

Javaの場合

vbroker.agent.portコマンドライン引数を使用してUDPポート番号を指定できます。

表4-2にC++アプリケーションのコマンドライン引数を示します。また，表4-3にJavaアプリケーションのコマンドライン引数を示します。

環境変数の詳細については，「2.　環境設定」を参照してください。

(b)　サポートされているサービスを使用するには

スマートエージェント（osagent）は，配置されたアプリケーションを実行するネットワークのどこかで実行しなければなりません。このように，実行するアプリケーションの要件によっては，ほかのBorland Enterprise Server VisiBrokerのプログラムを起動する必要があります。これらのサービスには，表4-1のものが含まれます。

表4‒1　実行するアプリケーション要件によって確認する必要があるケース

サービス

必要なケース

オブジェクト活性化デーモン（oad）

アプリケーションが，オンデマンドで起動しなければならないオブジェクトをインプリメントするサーバである場合。

インタフェースリポジトリ（irep）

アプリケーションが，動的スケルトンインタフェースまたは動的インプリメンテーションインタフェースを使用する場合。これらのインタフェースの説明については，「16.　インタフェースリポジトリの使用」を参照してください。

ゲートキーパー

アプリケーションを，ネットワークセキュリティのファイアウォールを使用した環境で実行する必要がある場合。

(2)　vbjの使用（Java）

vbjコマンドを使用してアプリケーションを起動し，アプリケーションの動作を制御するコマンドライン引数を入力できます。

vbj -Dvbroker.agent.port=10000 <class>

(3)　アプリケーションの実行（C++）

ここで，クライアントプログラムとサーバインプリメンテーションをコンパイルしたので，最初のBorland Enterprise Server VisiBrokerアプリケーションを実行する準備ができました。

Borland Enterprise Server VisiBrokerクライアントプログラムやサーバインプリメンテーションを実行する前に，まず，ローカルネットワーク上の最低一つのホストでスマートエージェントを起動する必要があります。スマートエージェントについては，「4.7.1　スマートエージェントの起動」を参照してください。

(4)　クライアントアプリケーションの実行

クライアントアプリケーションはVisiBroker ORBオブジェクトを使用するアプリケーションですが，自身のVisiBroker ORBオブジェクトをほかのクライアントアプリケーションには提供しません。

C++の場合

クライアントアプリケーションに指定できるコマンドライン引数を表4-2に示します。この引数はサーバにも適用できます。

表4‒2　クライアントアプリケーションのコマンドライン引数（C++）

オプション

説明

-ORBagent <0|1>

VisiBrokerの_bind()時に，スマートエージェントがサーバを探索するかどうかを指定します。

0を設定した場合，探索しません。

1を設定した場合，探索します。

デフォルトは1です。

-ORBagentAddr <hostname|ip_address>

このクライアントが使用するスマートエージェントを実行しているホストのホスト名またはIPアドレスを指定します。

hostnameを設定した場合，ホスト名を指定します。

ip_addressを設定した場合，IPアドレスを指定します。

このオプションの指定を省略した場合や，自ホストまたはagentaddrファイルで指定したホストからスマートエージェントを探索できない場合は，ブロードキャストメッセージでスマートエージェントを見つけます。

-ORBagentPort <port_number>

スマートエージェントのポート番号を指定します。複数のVisiBroker ORBドメインが必要な場合に有用です。

指定を省略した場合，14000番で動作します。

-ORBconnectionMax <#>

コネクションの最大数を指定します。

指定を省略した場合，無制限にコネクションを許可します。

-ORBconnectionMaxIdle <#>

コネクションが非アクティブな状態の最大監視時間を秒単位で指定します。最大監視時間を経過してもコネクションが非アクティブなままの場合，VisiBrokerがコネクションを終了します。

このオプションはインターネットアプリケーションで設定します。

0を設定した場合，監視しません。

デフォルトは0です。

-ORBDefaultInitRef

デフォルトの初期リファレンスを指定します。

-ORBInitRef

初期リファレンスを指定します。

-ORBnullstring <0|1>

1を設定した場合，VisiBroker ORBがC++ NULL文字をストリームします。NULL文字列は長さが0の文字列としてマーシャルされます。これは，長さが1の文字列としてマーシャルされる空の文字列（""）とは異なり，単独の文字（"¥0"）です。

0を設定した場合，NULL文字列をマーシャルしたときは，CORBA::BAD_PARAMとなります。NULL文字列をアンマーシャルしたときは，CORBA::MARSHALとなります。

デフォルトは0です。

注

サーバとクライアントが同一プロセス内に存在しnull文字列を送信するようなエラーケースの場合，BAD_PARAM例外は発生しません。サーバとクライアントが別プロセスの場合はCORBA::BAD_PARAM例外が発生します。

-ORBrcvbufsize <buffer_size>

応答を受信するために使用するTCPバッファのサイズをバイト単位で指定します。指定値は，性能やベンチマークの結果に著しく影響します。

指定を省略した場合，デフォルト値が設定されます。

デフォルトはOSよって異なるため，各OSのマニュアルを参照してください。

-ORBsendbufsize <buffer_size>

クライアント要求を送信するために使用するTCPバッファのサイズをバイト単位で指定します。指定値は，性能やベンチマークの結果に著しく影響します。

指定を省略した場合，デフォルト値が設定されます。

デフォルトはOSよって異なるため，各OSのマニュアルを参照してください。

-ORBtcpNoDelay <0|1>

ソケットが要求を送信する契機を指定します。指定値は，性能やベンチマークの結果に著しく影響します。

1を設定した場合，すべてのソケットが即座に要求を送信します。

0を設定した場合，ソケットはバッファが満杯になった時点で要求を一括して送信します。

デフォルトは0です。

Javaの場合

クライアントは，vbjコマンドまたはJava対応のWebブラウザから起動します。

クライアントアプリケーションに指定できるコマンドライン引数を表4-3に示します。

表4‒3　クライアントアプリケーションのコマンドライン引数（Java）

オプション

説明

-DORBagentAddr=<hostname|ip_address>

このクライアントが使用するスマートエージェントを実行しているホストのホスト名またはIPアドレスを指定します。

hostnameを設定した場合，ホスト名を指定します。

ip_addressを設定した場合，IPアドレスを指定します。

このオプションの指定を省略した場合や，自ホストまたはagentaddrファイルで指定したホストからスマートエージェントを探索できない場合は，ブロードキャストメッセージでスマートエージェントを見つけます。

-DORBagentAddrFile=<file_name>

デフォルトファイルのagentaddrの代わりに使用するファイルを指定します。

-DORBagentNoFailOver=<false|true>

VisiBrokerアプリケーションが通信しているosagentが終了した場合，ほかのosagentと通信するかどうかを指定します。

trueを設定した場合，VisiBrokerアプリケーションは，先に通信していたosagentにだけ再度通信を試みます。

falseを設定した場合，VisiBrokerアプリケーションは，先に通信していたosagentだけでなくほかのosagentにも再度通信を試みます。

不正な値を指定した場合，trueを設定したときと同じ動作をします。

デフォルトはfalseです。

-DORBagentPort=<port_number>

スマートエージェントのポート番号を指定します。複数のVisiBroker ORBドメインが必要な場合に有用です。

デフォルトは14000です。指定を省略した場合，デフォルト値が設定されます。

アプリケーション内でORB.init()メソッドの第2引数にORBagentPortまたはORBdisableLocatorのプロパティを設定した場合，その効果はありません。ORBオプションの値を有効にする場合は，コマンドライン上で-Dオプションで指定してください。

-DORBalwaysProxy=<false|true>

クライアントが常にゲートキーパーを使用して接続する必要があるかどうかを指定します。

falseを設定した場合，ゲートキーパーを使用しないで接続できます。

trueを設定した場合，常にゲートキーパーを使用して接続します。また，trueを設定した場合は，必ず-DORBgatekeeperIORオプションも設定してください。

不正な値を指定した場合，trueを設定したときと同じ動作をします。

デフォルトはfalseです。

-DORBalwaysTunnel=<false|true>

クライアントが常にHTTPを使用してゲートキーパーに接続する必要があるかどうかを指定します。

falseを設定した場合，HTTPを使用しないで接続できます。

trueを設定した場合，常にHTTPを使用して接続します。また，trueを設定した場合は，必ず-DORBgatekeeperIORオプションも設定してください。

不正な値を指定した場合，trueを設定したときと同じ動作をします。

デフォルトはfalseです。

-DORBbackCompat=<false|true>

旧バージョンのVisiBrokerクライアントとVisiBrokerサーバとの互換性を確保するかどうかを指定します。指定値はランタイムに通知されます。

falseを設定した場合，互換性を確保しません。

trueを設定した場合，互換性を確保します。

旧バージョンのVisiBrokerに基づいてサーバやクライアントの環境を構成する場合は，trueを指定してください。

デフォルトはfalseです。

-DORBconnectionMax=<#>

コネクションの最大数を指定します。

指定を省略した場合，無制限にコネクションを許可します。

-DORBconnectionMaxIdle=<#>

コネクションが非アクティブな状態の最大監視時間を秒単位で指定します。最大監視時間を経過してもコネクションが非アクティブなままの場合，VisiBrokerがコネクションを終了します。

このオプションはインターネットアプリケーションで設定します。

0を設定した場合，監視しません。

最大アイドル時間の監視は，プロパティvbroker.orb.gcTimeoutの設定値（デフォルト30秒）の範囲の誤差があります。

デフォルトは0です。

-DORBdebug=<false|true>

デバッグ機能を使用するかどうかを指定します。

falseを設定した場合，デバッグ機能を使用しません。

trueを設定した場合，デバッグ機能を使用します。

デフォルトはfalseです。

-DORBdebugDir=<directory>

スレッドのデバッグ情報を書き込むディレクトリを指定します。

デフォルトでは，カレントワーキングディレクトリを使用します。

-DORBdebugThreads=<false|true>

スレッドのデバッグ機能を使用するかどうかを指定します。

falseを設定した場合，デバッグ機能を使用しません。

trueを設定した場合，デバッグ機能を使用します。

デフォルトはfalseです。

-DORBDefaultInitRef

デフォルトの初期リファレンスを指定します。

nameservには，ORBDefaultInitRefを使用しないでください。ORBInitRefを使用してください。

-DORBdisableAgentCache=<false|true>

スマートエージェントのキャッシュを有効にするかどうかを指定します。

falseを設定した場合，有効にします。

trueを設定した場合，無効にします。

不正な値を指定した場合，trueを設定したときと同じ動作をします。

デフォルトはfalseです。

-DORBdisableGatekeeperCallbacks=<false|true>

ゲートキーパーのコールバックを有効にするかどうかを指定します。

falseを設定した場合，有効にします。

trueを設定した場合，無効にします。また，trueを設定した場合は，-DORBgatekeeperIORオプションも設定してください。

デフォルトはfalseです。

-DORBdisableLocator=<false|true>

スマートエージェントとゲートキーパーを有効にするかどうかを指定します。

falseを設定した場合，有効にします。

trueを設定した場合，無効にします。

不正な値を指定した場合，trueを設定したときと同じ動作をします。

アプリケーション内でORB.init()メソッドの第2引数にORBagentPortまたはORBdisableLocatorのプロパティを設定した場合，その効果はありません。ORBオプションの値を有効にする場合は，コマンドライン上で-Dオプションで指定してください。

デフォルトはfalseです。

-DORBgatekeeperIOR=<URL>

IORに対応するURLを指定します。

-DORBgcTimeout=<#>

ORBのガーベッジコレクションを実行する周期を秒単位で指定します。

デフォルトは30です。

-DORBInitRef

初期リファレンスを指定します。

-DORBmbufSize=<buffer_size>

Borland Enterprise Server VisiBrokerがオペレーション要求処理に使用する中間バッファのサイズを指定します。

性能向上のため，ORBは前のバージョンのBorland Enterprise Server VisiBrokerよりも複雑なバッファ管理を行います。送信または受信したデータがデフォルトより大きければ，リクエストごと，または応答ごとに新しいバッファが割り当てられます。

4キロバイトより大きいデータをアプリケーションが頻繁に送信する場合に，バッファ管理の利点を生かしたいとき，このシステムプロパティを使用して，デフォルトのバッファサイズよりも大きいバイト数を指定できます。

送信バッファと受信バッファのデフォルトサイズは，それぞれ4キロバイトです。

-DORBservices=<service>

インストールするORBの特殊サービスを指定します。

インストールできるサービスは，ユーザが作成したサービス，Borland Enterprise Server VisiBrokerが提供するORBManagerサービス，および別製品のBorland Enterprise Server VisiBrokerサービス（ネーミングサービスなど）です。

-DORBtcpNoDelay=<false|true>

ネットワークコネクションがデータを送信する契機を指定します。

falseを設定した場合，ネットワークコネクションは，バッファが満杯になった時点でデータを一括して送信します。

trueを設定した場合，すべてのネットワークコネクションが即座にデータを送信します。

デフォルトはfalseです。

-DORBwarn=<0|1|2>

警告メッセージの出力レベルを指定します。

0を設定した場合，警告メッセージを出力しません。

1を設定した場合，次の警告メッセージを出力します。

ユーザ作成コードからのCORBA以外の例外

ユーザ作成コードからのCORBA以外の例外のスタックトレース

2を設定した場合，次の警告メッセージを出力します。

ユーザ作成コードからのCORBA以外の例外

ユーザ作成コードからのCORBA以外の例外のスタックトレース

CORBAの例外

CORBAの例外のスタックトレース

デフォルトは0です。

5　例外の処理

この章では，システム例外およびユーザ例外について説明します。

5.1　CORBAモデルでの例外

CORBAモデルでの例外にはシステム例外とユーザ例外の両方が含まれます。CORBAの仕様では，クライアントリクエストの処理でエラーが発生した場合に発生する可能性のある一組のシステム例外を定義します。システム例外は通信障害の場合にも発生します。システム例外はいつでも発生する可能性があり，インタフェース内で宣言する必要はありません。ユーザ例外は，生成するオブジェクトについてIDLで定義でき，このような例外が起こる環境を指定できます。これらはメソッドシグニチャに含まれます。クライアントリクエストの処理中にオブジェクトが例外を発生させると，ORBはこの情報をクライアントに反映する責任を負います。

5.2　システム例外

オブジェクトインプリメンテーションは，「20.　VisiBroker 4.xインタセプタの使用」で説明しているインタセプタを介してシステム例外を発生させることができますが，通常はVisiBroker ORBがシステム例外を発生させます。

主要なCORBA例外の一覧とVisiBroker ORBがその例外を発生させた理由を表5-1に示します。また，CORBA例外のマイナーコードを表5-2に示します。

表5‒1　主要なCORBA例外，および考えられる原因

例外

例外の内容

考えられる原因

CORBA::BAD_CONTEXT

サーバに無効コンテキストが渡されました。

クライアントがオペレーションを呼び出したが，渡されたコンテキストにオペレーションで必要なコンテキスト値がない場合に，オペレーションはこの例外を発生します。

CORBA::BAD_INV_ORDER

オペレーション要求の前に，必要な前提条件オペレーションが呼び出されていません。

リクエストを実際に送信する前に，CORBA::Request::get_response()メソッドかCORBA::Request::poll_response()メソッドを呼び出そうとした可能性があります。

C++ ORBでは，リモートメソッド呼び出しのインプリメンテーション外で，exception::get_client_info()メソッドを呼び出そうとした可能性があります。この関数が有効なのは，リモート呼び出しのインプリメンテーション内だけです。

すでにシャットダウンされたVisiBroker ORBでオペレーションが呼び出されました。

CORBA::BAD_OPERATION

無効なオペレーションが実行されました。

サーバは，IDLで定義されていないオペレーションを受信すると，この例外を発生させます。クライアントとサーバが，同じIDLからコンパイルされているかどうかを確認してください。

リクエストが，リターン値を使用するように設定されていないと，CORBA::Request::return_value()メソッドはこの例外を発生させます。DII呼び出しをするときにリターン値が期待される場合には，必ず，CORBA::Request::set_return_type()メソッドを呼び出してリターン値型を設定してください。

CORBA::BAD_PARAM

無効なパラメタが引き渡されました。

sequence型の無効インデックスにアクセスしようとすると発生します。必ず，length()メソッドを使用してシーケンスの長さを設定してから，そのシーケンスの要素を格納または検索してください。

Java ORBでは，列挙体のデータの範囲外の値を送信しようとした可能性があります。

無効なTCKindを指定してTypeCodeを構築しようとした可能性があります。

nilまたはNULLオブジェクトリファレンスをAnyに挿入しようとした可能性があります。

DIIとonewayメソッド呼び出しを使用してout引数が指定された可能性があります。

インタフェースリポジトリに登録するインプリメンテーションオブジェクトの登録情報（例えば登録名）がすでに存在している場合，インタフェースリポジトリはこの例外を発生させます。

C++ ORBでは，無効なCORBA::Object_ptrがin引数として渡されると（例えば，nilリファレンスが渡されると），この例外を発生させます。

C++ ORBでは，NULLポインタの送信が試行されるとこの例外を発生させます。例えば，リターン値としてNULLを返そうとしたり，sequenceを返さなければならないメソッドからoutパラメタを返そうとすると，この例外が発生します。この場合，新しいsequence（長さは0の可能性がある）が代わりに返されなければなりません。NULL値で送信できないタイプには，Any，Context，struct，またはsequenceが含まれます。

Java ORBでは，nullリファレンスが渡されると，この例外を発生させます。

CORBA::BAD_TYPECODE

ORBが不正なTypeCodeを検出しました。

−

CORBA::CODESET_INCOMPATIBLE

クライアントとサーバのコードセットに互換がないため，通信に失敗しました。

クライアントとサーバが使用するコードセットが，一致していません。例えば，クライアントはISO 8859-1を使用し，サーバは日本語コードセットを使用しています。

CORBA::COMM_FAILURE

通信障害が発生しました。

C++ORBでは，一端のコネクション障害によって，既存のコネクションがクローズすることがあります。また，クライアントマシンまたはサーバマシンのリソース制限によって（最大コネクション数に到達し）通信が失敗した場合，この例外が発生します。

Java ORBでは，オペレーションの進行中（クライアントがリクエストを送信後で，サーバからクライアントに応答が返される前）に通信が損失すると，この例外が発生します。

CORBA::DATA_CONVERSION

データ変換エラーが発生しました。

マーシャリングで不正な文字コードを検出した場合，この例外が発生します。

CORBA::IMP_LIMIT

インプリメンテーションの上限に違反しました。

−

CORBA::INITIALIZE

必要な初期化が実行されませんでした。

ORB_init()メソッドまたはORB.init()メソッドが呼び出されなかった可能性があります。VisiBroker ORB対応のオペレーションを実行する前には，クライアントは，C++アプリケーションの場合はORB_init()メソッドを，Javaアプリケーションの場合はORB.init()メソッドを呼び出す必要があります。この呼び出しは通常，mainルーチンの最上部でプログラムが起動されるとすぐに実行されます。

Java ORBでは，起動時に指定するオプションに不正値を設定したおそれがあります。例えば，vbroker.orb.gcTimeoutにマイナスの値を設定した場合が該当します。

CORBA::INTERNAL

内部エラーが発生しました。

VisiBroker ORBの内部データ構造が破壊されるなど，ORB内部で論理矛盾を検出した場合に発生します。

CORBA::INTF_REPOS

インタフェースリポジトリへのアクセスエラーが発生しました。

get_interface()メソッドの呼び出し時に，オブジェクトインプリメンテーションがIRを見つけられないと，クライアントでこの例外が発生します。IRが実行されていることを確認してください。また，リクエストされたオブジェクトのインタフェース定義が，IRにロードされていることを確認してください。

CORBA::INV_IDENT

識別子の構文が無効です。

IRに渡された識別子の書式が正しくありません。

不当なオペレーション名が動的起動インタフェースで使用されています。

CORBA::INV_OBJREF

無効なオブジェクトリファレンスが検出されました。

使用できるプロファイルが指定されていないオブジェクトリファレンスが取得されると，VisiBroker ORBはこの例外を発生させます。

文字列型オブジェクトリファレンスの先頭文字が「IOR:」でないと，CORBA::ORB::string_to_object()メソッドは，この例外を発生させます。

IORファイルを指定する場合，ファイル中の文字列はobject_to_stringの結果と同じである必要があります。ファイル中には，空白，タブ，改行コードを含めて不正な文字が存在してはいけません。これに該当していない場合はINV_OBJREF例外が発生します。

CORBA::INV_POLICY

無効なポリシーの変更が検出されました。

この例外は，どの呼び出しからも発生する可能性があります。特定の呼び出しに適用されるポリシーの変更同士で互換性がないために呼び出しができない場合に発生します。

CORBA::INVALID_TRANSACTION

トランザクションコンテキストが不正です。

この例外の詳細については，トランザクションサービスのドキュメントを参照してください。

CORBA::MARSHAL

マーシャルパラメタまたは結果が不当です。

ネットワークからの要求または応答が構造的に不当です。このエラーは，通常，クライアント側またはサーバ側のランタイムのどちらかのバグを示します。例えば，サーバからの応答で，メッセージが1000バイトであるが，実際のメッセージが1000バイトより短いか長いことを示す場合，VisiBroker ORBはこの例外を発生させます。MARSHAL例外はDIIやDSIを不当に使用しても発生します。例えば，送信された実際のパラメタの型がオペレーションのIDLシグニチャと一致しない場合です。

CORBA::NO_IMPLEMENT

リクエストオブジェクトが見つかりませんでした。

呼び出されたオペレーションがある（IDL定義がある）のに，そのオペレーションのインプリメンテーションがないことを示します。

CORBA::NO_PERMISSION

許可されていないオペレーションを実行しようとしました。

−

CORBA::NO_RESOURCES

必要な資源を取得できませんでした。

新しいスレッドが生成できない場合に，この例外が発生します。

リモートクライアントがコネクションを確立しようとしたときに，サーバがファイルディスクリプタを使い果たすなどしてソケットを生成できないと，サーバはこの例外を発生させます。

ファイルディスクリプタを使い果たしたなどの理由でコネクションの確立が失敗すると，クライアントも同じようにこの例外を発生させます。

C++ORBでは，メモリを使い切った場合にもこの例外が発生します。

CORBA::NO_RESPONSE

クライアントが送信したリクエストの応答がまだありません。

OADに登録したオブジェクトインプリメンテーションの活性化が，OADに指定した時間内に行われなかった場合に，この例外が発生します。

CORBA::OBJ_ADAPTER

オブジェクトアダプタが障害を検出しました。

アプリケーションのサーバントマネージャの問題を検出した場合などに，POAはこの例外を発生させます。

CORBA::OBJECT_NOT_EXIST

リクエストされたオブジェクトが存在していません。

該当するサーバ内に存在しないインプリメンテーションでオペレーションを実行しようとすると，サーバは，この例外を発生させます。

非活性化したインプリメンテーションでオペレーションを起動しようとすると，この例外がクライアントによって表示されます。

例えば，オブジェクトへのバインドが失敗，または自動リバインドが失敗すると，OBJECT_NOT_EXIST例外が発生します。

CORBA::REBIND

クライアントが，QoSポリシーに矛盾するIORを受信しました。

設定されたQoSポリシーに矛盾するIORをクライアントが取得するとこの例外が発生します。RebindPolicyにNO_REBIND，NO_RECONNECT，またはVB_NOTIFY_REBINDの値があると，バインドされたオブジェクトリファレンスの呼び出しの結果，オブジェクト転送メッセージやロケーション転送メッセージが生成されます。

CORBA::TIMEOUT

オペレーションがタイムアウトしました。

コネクションを設定しようとしているとき，またはリクエストの送受信の完了を待っているときに，指定時間前にオペレーションが完了しないと，TIMEOUT例外が発生します。

CORBA::TRANSACTION_REQUIRED

リクエスト時に無効なトランザクションコンテキストがトランザクションサービスに渡されましたが，アクティブなトランザクションが必要です。

この例外の詳細については，トランザクションサービスのドキュメントを参照してください。

CORBA::TRANSACTION_ROLLEDBACK

リクエストに対応するトランザクションがすでにロールバックされているか，またはロールバック用にマーキングされています。

この例外の詳細については，トランザクションサービスのドキュメントを参照してください。

CORBA::TRANSIENT

通信エラーが検出されましたが，再接続できる場合があります。

通信障害が発生したおそれがありますが，VisiBroker ORBは通信が失敗したサーバとリバインドする必要があるとシグナル通知しています。RebindPolicyの設定によっては，この例外は発生しません。

CORBA::UNKNOWN

未知の例外です。

サーバが発生させたのは，Javaランタイム例外などの適切な例外ではありません。

サーバとクライアント間にIDL不一致があり，クライアントプログラムで，この例外は定義されていません。

DIIでは，サーバがコンパイル時にクライアントに未知の例外を発生させ，クライアントがCORBA::Requestの例外リストを指定しなかった場合です。

サーバがJavaアプリケーションの場合は，vbroker.orb.warn=2プロパティを設定して，どのランタイム例外が問題の原因かを調べます。

（凡例）−：該当しない

表5‒2　CORBA例外のマイナーコード

システム例外

マイナーコード

説明

BAD_PARAM

1

値ファクトリの登録，登録解除，または探索に失敗しました。

2

RIDがすでにIRに定義されています。

3

名前がすでにIRのコンテキストで使用されています。

4

ターゲットが有効なコンテナではありません。

5

継承されたコンテキストで名前がクラッシュしました。

6

abstractインタフェースのタイプが正しくありません。

MARSHAL

1

値ファクトリを探索できません。

NO_IMPLEMENT

1

ローカル値インプリメンテーションがありません。

2

値のインプリメンテーションバージョンの互換性がありません。

BAD_INV_ORDER

1

IRに依存性が存在し，オブジェクトがデストラクトできません。

2

IR内のデストラクトできないオブジェクトをデストラクトしようとしました。

3

オペレーションがデッドロックになりました。

4

VisiBroker ORBがシャットダウンしました。

OBJECT_NOT_EXIST

1

活性化されていない（登録解除されている）値をオブジェクトリファレンスとして渡そうとしました。

コードサンプル5-1　SystemExceptionクラス（C++）

class SystemException : public CORBA::Exception {
   public:
      static const char*_id;
      virtual ~SystemException();
      CORBA::ULong minor() const;
      void minor(CORBA::ULong val);
      CORBA::CompletionStatus completed() const;
      void completed(CORBA::CompletionStatus status);
      . . .
      static SystemException *_downcast(Exception *exc);
      . . .
};

コードサンプル5-2　SystemExceptionクラス（Java）

public abstract class org.omg.CORBA.SystemException
                        extends java.lang.RuntimeException {
   protected SystemException(java.lang.String reason,
      int minor,CompletionStatus completed) {...}
   public String toString() {...}
   public CompletionStatus completed;
   public int minor;
}

5.2.1　完了状態の取得

システム例外には，例外発生時に，オペレーションが完了したかどうかを伝える完了状態があります。CompletionStatusの列挙値を次に示します。オペレーションの完了状態が判定できない場合には，COMPLETED_MAYBEが返されます。

IDLサンプル5-1　CompletionStatus値

enum CompletionStatus {
   COMPLETED_YES = 0;
   COMPLETED_NO = 1;
   COMPLETED_MAYBE = 2;
};

C++の場合，SystemExceptionメソッドを使用して完了状態を検索できます。

コードサンプル5-3　完了状態の検索

CompletionStatus completed();

5.2.2　マイナーコードの取得と設定（C++）

SystemExceptionメソッドを使用してマイナーコードを検索，設定できます。マイナーコードからエラーのタイプの詳細情報がわかります。

コードサンプル5-4　マイナーコードの検索と設定

ULong minor() const;
void minor(ULong val);

5.2.3　システム例外のタイプの判定（C++）

Borland Enterprise Server VisiBrokerの例外クラスの設計によって，ユーザのプログラムはどのようなタイプの例外でもキャッチし，_downcast()メソッドによってそのタイプを判定できます。静的メソッドである_downcast()メソッドは，Exceptionオブジェクトへのポインタを受け付けます。CORBA::Objectで定義した_downcast()メソッドによって，ポインタがSystemExceptionタイプの場合，_downcast()メソッドはポインタを返します。ポインタがSystemExceptionタイプでない場合，_downcast()メソッドはNULLポインタを返します。詳細については，「23.　RMI-IIOPの使用」を参照してください。

5.2.4　システム例外のキャッチ

アプリケーションは，VisiBroker ORBとリモートコールをトライキャッチブロックで囲むのがよいでしょう。「4.　Borland Enterprise Server VisiBrokerによるサンプルアプリケーションの開発」で説明したアカウントのクライアントプログラムがC++の例外をどのように出力するのかを，コードサンプル5-5でわかりやすく説明します。コードサンプル5-6は，アカウントクライアントプログラムがJavaの例外をどのように出力するかを示します。

コードサンプル5-5　例外の出力（C++）

#include "Bank_c.hh"
int main(int argc, char* const* argv) {
   try {
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
      PortableServer::ObjectId_var managerId =
            PortableServer::string_to_ObjectId("BankManager");
      Bank::AccountManager_var manager =
            Bank::AccountManager::_bind("/bank_agent_poa",
                  managerId);
      const char* name = argc >1 ? argv [1] : "Jack B. Quick";
      Bank::Account_var account = manager->open(name);
      CORBA::Float balance = account->balance();
      cout << "The balance in " << name << "'s account is $"
            << balance << endl;
   } catch(const CORBA::Exception& e) {
     cerr << e << endl;
     return 1;
   }
   return 0;
}

コードサンプル5-6　例外の出力（Java）

public class Client {
   public static void main(String[ ] args) {
      try {
         org.omg.CORBA.ORB orb =
                         org.omg.CORBA.ORB.init(args, null);
         byte[ ] managerId = "BankManager".getBytes();
         Bank.AccountManager manager =
               Bank.AccountManagerHelper.bind(orb,
                                          "/bank_agent_poa",
                                          managerId);
         String name =
                 args.length > 0 ? args[0] : "Jack B. Quick";
         Bank.Account account = manager.open(name);
         float balance = account.balance();
         System.out.println("The balance in "
                      + name + "'s account is $" + balance);
     } catch (Exception e) {
         System.err.println(e);
     }
   }
}

上記のような変更を加えたクライアントプログラムをサーバが存在しない場合に実行するときは，次のような出力が行われ，オペレーションが未完であることと，例外の理由を示します。

C++の場合

prompt> Client
Exception: CORBA::OBJECT_NOT_EXIST
         Minor: 0
         Completion Status: NO

Javaの場合

prompt>vbj Client
org.omg.CORBA.OBJECT_NOT_EXIST:
      Could not locate the following POA:
      poa name : /bank_agent_poa
      minor code:0 completed: No

5.2.5　システム例外への例外のダウンキャスト

キャッチした例外をSystemExceptionへダウンキャストするために，アカウントのクライアントプログラムを修正できます。コードサンプル5-7および5-8に，クライアントプログラムの修正方法を示します。コードサンプル5-9および5-10に，システム例外が発生した場合に表示される出力を示します。

コードサンプル5-7　システム例外への例外のダウンキャスト（C++）

int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

      // Bind to an account.
      Account_var account = Account::_bind();

      // Get the balance of the account.
      CORBA::Float acct_balance = account->balance();
      // Print out the balance.
      cout << "The balance in the account is $"
            << acct_balance << endl;
      } catch(const CORBA::Exception& e) {
         CORBA::SystemException* sys_excep;
         sys_excep = CORBA::SystemException::_downcast
                                    ((CORBA::Exception)(&e));
         if(sys_excep != NULL) {
            cerr << "System Exception occurred:" << endl;
            cerr << "exception name: " <<
            sys_excep->_name() << endl;
            cerr << "minor code: " << sys_excep->minor()
                  << endl;
            cerr << "completion code: "
                  << sys _excep->completed()
                  << endl;
      } else {
         cerr << "Not a system exception" << endl;
         cerr << e << endl;
      }
   }
}

コードサンプル5-8　システム例外への例外のダウンキャスト（Java）

public class Client {
   public static void main(String[ ] args){
     try {
        // Initialize the ORB
        org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);
        // Bind to an account
        Account account = AccountHelper.bind(orb, "/bank_poa",
                      "BankAccount".getBytes());
        // Get the balance of the account
        float balance = account.balance();
        // Print the account balance
        System.out.println("The account balance is $" + balance);
     }catch(Exception e){
        if (e instanceof org.omg.CORBA.SystemException){
          System.err.println("System Exception occurred:");
        }else {
          System.err.println("Not a system exception");
        }
        System.err.println(e);
     }
   }
}

コードサンプル5-9　システム例外からの出力（C++）

System Exception occurred:
      exception name: CORBA::NO_IMPLEMENT
      minor code: 0
      completion code: 1

コードサンプル5-10　システム例外からの出力（Java）

System Exception occurred:
in thread "main"org.omg.CORBA.OBJECT_NOT_EXIST
                                   minor code: 0 completed: No

(1)　特定の型のシステム例外のキャッチ

すべての型の例外をキャッチするのではなく，主要な各型の例外を明確にキャッチするように選択できます。コードサンプル5-11にC++，およびコードサンプル5-12にJavaのそれぞれの方法を示します。

コードサンプル5-11　特定の型の例外のキャッチ（C++）

. . .
int main(int argc,char* const* argv){
   try {
       // Initialize the ORB.
       CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

       // Bind to an account.
       Account_var account = Account::_bind();

       // Get account balance.
       CORBA::Float acct_balance = account->balance();
       // Print out the balance.
       cout << "The balance in the account is $"
             << acct_balance << endl;
   }
   // Check for system errors
   catch(const CORBA::SystemException& sys_excep) {
      cout << "System Exception occurred:" << endl;
      cout << "exception name: " << sys_excep->_name() << endl;
      cout << "minor code: " << sys_excep->minor() << endl;
      cout << "completion code: " << sys_excep->completed()
            << endl;
   }
}
. . .

コードサンプル5-12　特定の型の例外のキャッチ（Java）

public class Client {
   public static void main(String[ ] args) {
     try {
        org.omg.CORBA.ORB orb =
                         org.omg.CORBA.ORB.init(args, null);
        byte[ ] managerId = "BankManager".getBytes();
        Bank.AccountManager manager =
             Bank.AccountManagerHelper.bind(orb,
                                          "/bank_agent_poa",
                                          managerId);
        String name =
                args.length > 0 ? args [0] : "Jack B. Quick";
        Bank.Account account = manager.open(name);
        float balance = account.balance();
        System.out.println("The balance in " + name +
                           "'s account is $" + balance);
     } catch(org.omg.CORBA.SystemException e) {
        System.err.println("System Exception occurred:");
        System.err.println(e);
     }
   }
}

5.3　ユーザ例外

オブジェクトのインタフェースをIDLで定義する場合には，オブジェクトが発生させる可能性のあるユーザ例外を指定できます。コードサンプル5-13および5-14に，オブジェクトについて指定するユーザ例外を，idl2cppコンパイラ（C++）またはidl2javaコンパイラ（Java）がUserExceptionコードから派生させる場合について示します。

コードサンプル5-13　UserExceptionクラス（C++）

class UserException: public Exception {
   public:
      . . .
      static const char*_id;
      virtual ~UserException();
      static UserException *_downcast(Exception *);
   };

コードサンプル5-14　UserExceptionクラス（Java）

public abstract class UserException extends
                                       java.lang.Exception {
   protected UserException();
   protected UserException(String reason);
}

5.3.1　ユーザ例外の定義

「4.　Borland Enterprise Server VisiBrokerによるサンプルアプリケーションの開発」で説明したアカウントアプリケーションを拡張して，accountオブジェクトが例外を発生させるようにしたい場合，accountオブジェクトの資金が不十分なら，AccountFrozenという名前のユーザ例外を発生させる必要があります。AcoountインタフェースのIDL指定にユーザ例外を追加するために必要な追加コードを，ボールド体で示します。

IDLサンプル5-2　ユーザ例外の定義

// Bank.idl
module Bank {
   interface Account {
      exception AccountFrozen {
      };
      float balance() raises(AccountFrozen);
   };
};

idl2cppコンパイラ（C++）またはidl2java（Java）コンパイラは，AccountFrozen例外クラスに対して次に示すコードを生成します。

コードサンプル5-15　idl2cppコンパイラが生成するAccountFrozenクラス（C++）

class Account : public virtual CORBA::Object {
   . . .
   class AccountFrozen: public CORBA_UserException {
      public:
         static const CORBA_Exception::Description description;

        AccountFrozen() {}
        static CORBA::Exception *_factory() {
           return new AccountFrozen();
        }
        ~AccountFrozen() {}
        virtual const CORBA_Exception::Description& _desc()
              const;
        static AccountFrozen *_downcast(CORBA::Exception *exc);
        CORBA::Exception *_deep_copy() const {
           return new AccountFrozen(*this);
        }
        void _raise() const {
           raise *this;
        }
     }
   . . .
}

コードサンプル5-16　idl2javaコンパイラが生成するAccountFrozenクラス（Java）

package Bank;
public interface Account extends
                           com.inprise.vbroker.CORBA.Object,
     Bank.AccountOperations, org.omg.CORBA.portable.IDLEntity {
}

package Bank;
public interface AccountOperations {
   public float balance () throws
                          Bank.AccountPackage.AccountFrozen;
}

package Bank.AccountPackage;
public final class AccountFrozen extends
                               org.omg.CORBA.UserException {
   public AccountFrozen (){...}
   public AccountFrozen (java.lang.String _reason){...}
   public synchronized java.lang.String toString(){...}
}

(1)　例外を発生させるためのオブジェクトの修正

適切なエラー条件下で例外を発生させることによって例外を使用するように，AccountImplオブジェクトを修正する必要があります。

コードサンプル5-17　例外を発生させるためのオブジェクトインプリメンテーションの修正（C++）

CORBA::Float AccountImpl::balance()
{
      if( _balance < 50 ) {
             throw Account::AccountFrozen();
      } else {
            return _balance;
      }
}

コードサンプル5-18　例外を発生させるためのオブジェクトインプリメンテーションの修正（Java）

public class AccountImpl extends Bank.AccountPOA {
   public AccountImpl(float balance) {
       _balance = balance;
   }
   public float balance()throw new AccountFrozen {
      if (_balance < 50) {
         throw new AccountFrozen();
      }else {
        return _balance;
      }
  }
   private float _balance;
}

(2)　ユーザ例外のキャッチ

オブジェクトインプリメンテーションが例外を発生させる場合，ORBは例外をクライアントプログラムに反映させる責任を負います。UserExceptionについてのチェックはSystemExceptionについてのチェックと同様です。AccountFrozen例外をキャッチするようにアカウントのクライアントプログラムを修正するには，コードサンプル5-19および5-20で示すようにコードの修正をしてください。

コードサンプル5-19　UserExceptionのキャッチ（C++）

. . .
   try {
      // Initialize the ORB.
      CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

      // Bind to an account.
      Account_var account = Account::_bind();

      // Get the balance of the account.
      CORBA::Float acct_balance = account->balance();
   }
   catch(const Account::AccountFrozen& e) {
      cerr << "AccountFrozen returned:" << endl;
      cerr << e << endl;
      return(0);
   }
   // Check for system errors
   catch(const CORBA::SystemException& sys_excep) {
   }
. . .

コードサンプル5-20　UserExceptionのキャッチ（Java）

public class Client {
   public static void main(String[ ] args) {
     try {
        // Initialize the ORB
        org.omg.CORBA.ORB orb =
                         org.omg.CORBA.ORB.init(args, null);
        // Bind to an account
        Account account = AccountHelper.bind(orb, "/bank_poa",
                              "BankAccount".getBytes());

        // Get the balance of the account
        float balance = account.balance();

        // Print the account balance
        System.out.println("The account balance is $" +
                           balance);
     }
     // Check for AccountFrozen exception
     catch(Account.AccountFrozen e) {
        System.err.println("AccountFrozen returned:");
        System.err.println(e);
     }
     // Check for system error
     catch(org.omg.CORBA.SystemException sys_excep) {
     . . .
     }
   }
}

(3)　ユーザ例外へのフィールドの追加

ユーザ例外に特定の値を対応させることができます。理由コードをAccountFrozenユーザ例外に追加するようにIDLインタフェース定義を修正する方法をコードサンプル5-21に示します。例外を発生させるオブジェクトインプリメンテーションは，理由コードの設定に責任を負います。理由コードは，例外が出力ストリームにあると自動的に出力されます。

コードサンプル5-21　AccountFrozen例外への理由コードの追加

// Bank.idl
module Bank {
   interface Account {
      exception AccountFrozen {
         int reason;
      };
      float balance() raises(AccountFrozen);
   };
};

第2編　サーバの概念

6　サーバの基本事項

この章では，クライアントリクエストを受信するサーバの設定に必要な手順の概要について説明します。

6.1　概要

サーバ設定の基本手順は，次のとおりです。

VisiBroker ORBの初期化

POAの作成と設定

POAマネージャの活性化

オブジェクトの活性化

クライアントリクエストを待つ

この章では，ポイントを明確にするために，各手順の概要を説明します。各手順の詳細は，個々の要件によって異なります。

6.2　VisiBroker ORBの初期化

前章までで説明したように，VisiBroker ORBはクライアントリクエストとオブジェクトインプリメンテーション間の通信リンクを提供します。各アプリケーションは，VisiBroker ORBと通信を行う前にVisiBroker ORBを初期化しなければなりません。

コードサンプル6-1　VisiBroker ORBの初期化（C++）

// Initialize the ORB.
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

コードサンプル6-2　VisiBroker ORBの初期化（Java）

// Initialize the ORB.
org.omg.CORBA.ORB orb=org.omg.CORBA.ORB.init(args,null);

6.3　POAの作成

旧バージョンのCORBAオブジェクトアダプタ（基本オブジェクトアダプタ：BOA）ではポータブルなオブジェクトサーバコードを使用できませんでした。新しい仕様はこの問題を解決するためにOMGによって開発されたもので，POA（ポータブルオブジェクトアダプタ）といいます。

注

この節では，POAの基本機能の幾つかを紹介します。詳細については，「7.　POAの使用」およびOMG仕様を参照してください。

基本的には，POA（およびそのコンポーネント）はクライアントリクエスト受信時にどのサーバントを起動するかを決定してから，そのサーバントを起動します。サーバントとはabstractオブジェクトのインプリメンテーションを提供するプログラミングオブジェクトです。サーバントはCORBAオブジェクトではありません。

各VisiBroker ORBは一つのPOA（rootPOAといいます）を提供します。追加のPOAを作成して，それぞれのPOAを異なった動作で構成できます。また，POAが制御するオブジェクトの特徴を定義することもできます。

サーバントを使ったPOAの設定手順は次のとおりです。

rootPOAのリファレンスの取得

POAポリシーの定義

rootPOAの子としてPOAを作成

サーバントの作成と活性化

POAのマネージャを介したPOAの活性化

上記の手順には，アプリケーションによって異なるものがあります。

6.3.1　rootPOAのリファレンスの取得

オブジェクトを管理したり新たにPOAを作成したりするために，すべてのサーバアプリケーションはrootPOAのリファレンスを取得する必要があります。

コードサンプル6-3　rootPOAのリファレンスの取得（C++）

// get a reference to the rootPOA
CORBA::Object_var obj =
      orb->resolve_initial_references("RootPOA");
// narrow the object reference to a POA reference
PortableServer::POA_var rootPOA =
      PortableServer::POA::_narrow(obj);

コードサンプル6-4　rootPOAのリファレンスの取得（Java）

//2.Get a reference to the rootPOA
org.omg.CORBA.Object obj =
                  orb.resolve_initial_references("RootPOA");
// Narrow the object reference to a POA reference
POA rootPoa =  org.omg.PortableServer.POAHelper.narrow(obj);

rootPOAのリファレンスは，resolve_initial_referencesを使用して取得できます。resolve_initial_referencesは，CORBA::Object型の値を返します。返されたオブジェクトリファレンスを希望の型（上記のサンプルではPortableServer::POA）にナロウするのはプログラマの責任です。

これで，必要ならこのリファレンスを使用してほかのPOAを作成できるようになります。

6.3.2　子POAの作成

rootPOAにはあらかじめ定義されたポリシーの集合があり，これらは変更できません。ポリシーとは，POAの動作とPOAが管理するオブジェクトを制御するオブジェクトのことです。別のライフスパンポリシーのような別の動作が必要なら，新しいPOAを作成できます。

POAは，create_POAを使用して既存POAの子として作成します。必要なだけの数のPOAを作成できます。

注

子POAは親POAのポリシーを継承しません。

次に示すサンプルでは，子POAはrootPOAから作成され，パーシステントなライフスパンポリシーを持ちます。この子POAの状態管理にはrootPOAのPOAマネージャを使用します。POAマネージャの詳細については，「6.3.4　POAの活性化」で説明します。

コードサンプル6-5　ポリシーと子POAの作成（C++）

CORBA::PolicyList policies;
policies.length(1);
policies[(CORBA::ULong)0] = rootPOA->create_lifespan_policy(
      PortableServer::PERSISTENT);
// Create myPOA with the right policies
PortableServer::POAManager_var rootManager =
      rootPOA->the_POAManager();
PortableServer::POA_var myPOA = rootPOA->create_POA(
      "bank_agent_poa", rootManager,policies );

コードサンプル6-6　ポリシーと子POAの作成（Java）

// Create policies for our persistent POA
org.omg.CORBA.Policy[ ] policies = {
   rootPOA.create_lifespan_policy(
                             LifespanPolicyValue.PERSISTENT)
};
// Create myPOA with the right policies
POA myPOA =  rootPOA.create_POA( "bank_agent_poa",
                               rootPOA.the_POAManager(),
                               policies );

6.3.3　サーバントメソッドのインプリメント

IDLはC++と似た構文を持ち，モジュール，インタフェース，データ構造などの定義に使用できます。インタフェースを含むIDLをコンパイルするとき，サーバントのベースクラスとして動作するクラスが生成されます。例えば，Bank.idlファイルには，AccountManagerインタフェースが記述されます。

コードサンプル6-7　Bank.idlに記述されるインタフェース

module Bank{
   interface Account {
         float balance();
   };
   interface AccountManager {
         Account open (in string name);
   };
};

コードサンプル6-8にサーバ側のAccountManagerインプリメンテーションを示します。

コードサンプル6-8　AccountManagerImplコード（C++）

class AccountManagerImpl : public POA_Bank::AccountManager {
   private:
      Dictionary _accounts;
   public:
      virtual Bank::Account_ptr open(const char* name) {
         // Lookup the account in the account dictionary.
         Bank::Account_ptr account =
               (Bank::Account_ptr) _accounts.get(name);
         if(account == Bank::Account::_nil()) {
            // Make up the account's balance, between 0 and
            // 1000 dollars.
         float balance = abs(rand()) % 100000 / 100.0;
         // Create the account implementation, given
         // the balance.
         AccountImpl *accountServant =
               new AccountImpl(balance);
         try {
             // Activate it on the default POA which is root
             // POA for this servant
             PortableServer::POA_var rootPOA = _default_POA();
             CORBA::Object_var obj =
                 rootPOA->servant_to_reference(accountServant);
             account = Bank::Account::_narrow(obj);
         } catch(const CORBA::Exception& e) {
             cerr << "_narrow caught exception: " << e << endl;
         }
         // Print out the new account.
         cout << "Created " << name << "'s account: " <<
               account << endl;
         // Save the account in the account dictionary.
         _accounts.put(name, account);
      }

      // Return the account.
      return Bank::Account::_duplicate(account);
   }
};

Javaの場合，コードサンプル6-9に示すように，AccountManagerPOA.javaが作成され，サーバ側のAccountManagerオブジェクトインプリメンテーションのスケルトンコード（インプリメンテーションベースコード）として動作します。

コードサンプル6-9　AccountManagerImplコード（Java）

import org.omg.PortableServer.*;
import java.util.*;
public class AccountManagerImpl extends
                                    Bank.AccountManagerPOA {
   public synchronized Bank.Account open(String name){
     // Lookup the account in the account dictionary.
     Bank.Account account =
                          (Bank.Account) _accounts.get(name);
     // If there was no account in the dictionary, create one.
     if(account == null){
        // Make up the account's balance,
        // between 0 and 1000 dollars.
        float balance =
                Math.abs(_random.nextInt()) % 100000 / 100f;
        // Create the account implementation, given
        // the balance.
        AccountImpl accountServant =
                                   new AccountImpl(balance);
        try {
          // Activate it on the default POA
          // which is rootPOA for this servant
          account =
             Bank.AccountHelper.narrow(_default_POA().
             servant_to_reference(accountServant));
        }catch (Exception e){
          e.printStackTrace();
        }
        // Print out the new account.
        System.out.println(
               "Created " + name + "'s account: " + account);
        // Save the account in the account dictionary.
        _accounts.put(name, account);
     }
     // Return the account.
     return account;
   }
   private Dictionary _accounts =  new Hashtable();
   private Random _random =  new Random();
}

AccountManagerインプリメンテーションは，サーバコードで作成し活性化しなければなりません。このサンプルでは，AccountManagerは，記録先であるアクティブオブジェクトマップにオブジェクトIDを渡すactivate_object_with_idを使用して活性化されます。アクティブオブジェクトマップは，オブジェクトIDをサーバントにマッピングする単なるテーブルです。この手法はオブジェクトの明示的な活性化と呼ばれ，POAがアクティブなときは常にこのオブジェクトが使用できるようにします。

コードサンプル6-10　サーバントの作成と活性化（C++）

// Create the servant
AccountManagerImpl managerServant;
// Decide on the ID for the servant
PortableServer::ObjectId_var managerId =
      PortableServer::string_to_ObjectId("BankManager");
// Activate the servant with the ID on myPOA
myPOA->activate_object_with_id(managerId,&managerServant);

コードサンプル6-11　サーバントの作成と活性化（Java）

// Create the servant
AccountManagerImpl managerServant =
                                   new AccountManagerImpl();
// Decide on the ID for the servant
byte[ ] managerId = "BankManager".getBytes();
// Activate the servant with the ID on myPOA
myPOA.activate_object_with_id(managerId, managerServant);

6.3.4　POAの活性化

最後の手順は，使用するPOAに対応するPOAマネージャの活性化です。デフォルトでは，POAマネージャは待機状態で作成されます。この状態では，すべてのリクエストは保留待ち行列に転送され，処理されません。リクエストをディスパッチできるようにするには，POAに対応するPOAマネージャを待機状態からアクティブな状態に変えなければなりません。POAマネージャとは，POAの状態（リクエストを待ち行列に入れるか，処理するか，または破棄するか）を制御するオブジェクトに過ぎません。POA生成時にPOAマネージャはPOAに対応づけられます。使用するPOAマネージャを指定でき，システムに新しいものを作成させることもできます（POAマネージャ名としてcreate_POA()に，C++ではNULL，Javaではnullを入力してください）。

コードサンプル6-12　POAマネージャの活性化（C++）

// Activate the POA manager
PortableServer::POAManager_var mgr=rootPoa ->the_POAManager();
mgr->activate();

コードサンプル6-13　POAマネージャの活性化（Java）

// Activate the POA manager
rootPOA.the_POAManager().activate();

6.4　オブジェクトの活性化

前節では，オブジェクトの明示的な活性化について簡単に説明しました。オブジェクトを活性化するには幾つかの方法があります。

明示的な活性化

POAの呼び出しによるサーバの起動時にすべてのオブジェクトが活性化されます。

オンデマンドによる活性化

まだオブジェクトIDに対応していないサーバントに対するリクエストをサーバントマネージャが受信すると，サーバントマネージャはオブジェクトを活性化します。

暗黙的な活性化

クライアントリクエストではなく，POAによるオペレーションを契機としてサーバが暗黙的にオブジェクトを活性化します。

デフォルトサーバントによる活性化

POAはデフォルトサーバントを使用してクライアントリクエストを処理します。

オブジェクトの活性化については，「7.　POAの使用」を参照してください。ここでは，オブジェクトを活性化するには幾つかの方法があるということだけを意識してください。

6.5　クライアントリクエストを待つ

POAの設定が完了したら，orb.run()を使用してクライアントリクエストを待つことができます。このプロセスはサーバが終了するまで動作します。

コードサンプル6-14　入力リクエストを待つ（C++）

// Wait for incoming requests.
orb->run();

コードサンプル6-15　入力リクエストを待つ（Java）

// Wait for incoming requests
orb.run();

6.6　コードサンプルのまとめ

ここでは，この章で説明したコード全体を示します。コードサンプル6-16は，この章で説明したC++のコード全体を示します。コードサンプル6-17は，この章で説明したJavaのコード全体を示します。

コードサンプル6-16　サーバ側コード全体（C++）

// Server.C
#include "Bank_s.hh"
#include <math.h>

class Dictionary {
   private:
      struct Data {
         const char* name;
         void* value;
      };

      unsigned _count;
      Data* _data;
   public:
      Dictionary() {
      _count = 0;
   }
   void put(const char* name, void* value) {
      Data* oldData = _data;
      _data = new Data[_count +1];
      for(unsigned i = 0; i < _count; i++) {
         _data[i] = oldData[i];
      }
      _data[_count].name = strdup(name);
      _data[_count].value = value;
      _count++;
   }
   void* get(const char* name) {
      for(unsigned i =0; i < _count; i++) {
         if(!strcmp(name, _data[i].name)) {
            return _data[i].value;
         }
      }
      return 0;
   }
};

class AccountImpl : public POA_Bank::Account {
   private:
      float _balance;
   public:
      AccountImpl(float balance) {
         _balance = balance;
      }
      virtual float balance() {
         return _balance;
   }
};

class AccountManagerImpl : public POA_Bank::AccountManager {
   private:
      Dictionary _accounts;
   public:
      virtual Bank::Account_ptr open(const char* name) {
         // Lookup the account in the account dictionary.
         Bank::Account_ptr account =
               (Bank::Account_ptr) _accounts.get(name);

         if(account == Bank::Account::_nil()) {
            // Make up the account's balance, between
            // 0 and 1000 dollars.
            float balance = abs(rand()) % 100000 / 100.0;
            // Create the account implementation, given
            // the balance.
            AccountImpl *accountServant =
                  new AccountImpl(balance);
            try {
               // Activate it on the default POA which is
               // rootPOA for this servant
               PortableServer::POA_var rootPOA = _default_POA();
               CORBA::Object_var obj =
                  rootPOA->servant_to_reference(accountServant);
               account = Bank::Account::_narrow(obj);
               } catch(const CORBA::Exception& e) {
                  cerr << "_narrow caught exception: " << e
                        << endl;
               }
               //Print out the new account.
               cout << "Created " << name << "'s account: "
                     << account << endl;
               // Save the account in the account dictionary.
               _accounts.put(name, account);
            }
            // Return the account.
            return Bank::Account::_duplicate(account);
      }
};
int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

      // get a reference to the rootPOA
      CORBA::Object_var obj =
            orb->resolve_initial_references("RootPOA");
      // narrow the object reference to a POA reference
      PortableServer::POA_var rootPOA =
            PortableServer::POA::_narrow(obj);

      CORBA::PolicyList policies;
      policies.length(1);

      policies[(CORBA::ULong)0] =
            rootPOA->create_lifespan_policy(
            PortableServer::PERSISTENT
      );
      // Create myPOA with the right policies
      PortableServer::POAManager_var rootManager =
            rootPOA->the_POAManager();
      PortableServer::POA_var myPOA =
            rootPOA->create_POA( "bank_agent_poa",
            rootManager,policies );

      // Create the servant
      AccountManagerImpl managerServant;

      // Decide on the ID for the servant
      PortableServer::ObjectId_var managerId =
            PortableServer::string_to_ObjectId("BankManager");

      // Activate the servant with the ID on myPOA
      myPOA->activate_object_with_id(managerId,&managerServant);

      // Activate the POA Manager
      rootPOA->the_POAManager()->activate();

      cout << myPOA->servant_to_reference(&managerServant)
            << " is ready" << endl;

      // Wait for incoming requests
      orb->run();
   } catch(const CORBA::Exception& e) {
      cerr << e << endl;
   }
}

コードサンプル6-17　サーバ側コード全体（Java）

// Server.java
import org.omg.PortableServer.*;
public class Server {
  public static void main(String[ ] args){
   try {
     // Initialize the ORB.
     org.omg.CORBA.ORB orb =
                         org.omg.CORBA.ORB.init(args, null);
     // get a reference to the rootPOA
     POA rootPOA = POAHelper.narrow(
       orb.resolve_initial_references("RootPOA"));

     // Create policies for our persistent POA
     org.omg.CORBA.Policy[ ] policies = {
        rootPOA.create_lifespan_policy(
                             LifespanPolicyValue.PERSISTENT)
     };
     // Create myPOA with the right policies
     POA myPOA = rootPOA.create_POA( "bank_agent_poa",
                                    rootPOA.the_POAManager(),
                                    policies );

     // Create the servant
     AccountManagerImpl managerServant =
                                   new AccountManagerImpl();
     // Decide on the ID for the servant
     byte[ ] managerId = "BankManager".getBytes();
     // Activate the servant with the ID on myPOA
     myPOA.activate_object_with_id(managerId,
                                   managerServant);
     // Activate the POA manager
     rootPOA.the_POAManager().activate();
     System.out.println(
       myPOA.servant_to_reference(managerServant) +
       "is ready.");
     // Wait for incoming requests
     orb.run();
   }catch (Exception e) {
     e.printStackTrace();
   }
  }
}

7　POAの使用

この章では，POAの使用について説明します。

7.1　ポータブルオブジェクトアダプタとは

POA（ポータブルオブジェクトアダプタ）は，BOA（基本オブジェクトアダプタ）に代わり，サーバ側のポータビリティを提供します。

POAは，オブジェクトのインプリメンテーションとVisiBroker ORB間の中間アダプタです。中間アダプタの役割として，POAはリクエストをサーバントに転送し，その結果サーバントが動作して，必要に応じて子POAが生成されます。

各サーバは，複数のPOAをサポートできます。少なくとも一つのPOA（rootPOA）がなければなりません。rootPOAは自動的に生成されます。POAのセットは階層型になっており，すべてのPOAにはその親としてrootPOAがあります。

サーバントマネージャは，サーバントを探してPOAのオブジェクトに対応させます。abstractオブジェクトがサーバントに割り当てられると，そのオブジェクトはアクティブなオブジェクトと呼ばれ，そのサーバントはアクティブなオブジェクトをインカネートすると言われます。それぞれのPOAにはアクティブオブジェクトマップが一つずつあり，このマップによって，アクティブなオブジェクトのオブジェクトIDとアクティブなサーバントが対応づけられます。POAの概要を図7-1に示します。

注

ここでは，POAの主要なテーマだけに焦点を当てています。詳細な説明については，OMG仕様を参照してください。

図7‒1　POAの概要

7.1.1　POA用語

POAについて説明する前に，幾つかの用語を表7-1に定義しておきます。

表7‒1　ポータブルオブジェクトアダプタ用語

用語

説明

アクティブオブジェクトマップ

アクティブなVisiBroker CORBAオブジェクトを（そのオブジェクトIDによって）サーバントにマッピングするテーブルです。それぞれのPOAにはアクティブオブジェクトマップが一つずつあります。

アダプタアクティベータ

存在しない子POAに対するリクエストを受信したときにオンデマンドでPOAを生成できるオブジェクトです。

エーテライズ

サーバントと抽象化されたCORBAオブジェクト間の対応を削除することです。

インカネート

サーバントを抽象化されたCORBAオブジェクトに対応づけることです。

オブジェクトID

オブジェクトアダプタ内のCORBAオブジェクトを識別する手段です。オブジェクトIDはオブジェクトアダプタまたはアプリケーションによって割り当てることができ，オブジェクトIDの作成元であるオブジェクトアダプタ内だけで一意です。サーバントはオブジェクトIDによってabstractオブジェクトに対応づけられます。

パーシステントオブジェクト

作成元であるサーバプロセスが消滅しても存在するCORBAオブジェクトです。

POAマネージャ

POAが入力リクエストを受信するか破棄するかなどのPOAの状態を管理するオブジェクトです。

ポリシー

対応するPOAの動作およびPOAが管理するオブジェクトを制御するオブジェクトです。

rootPOA

各VisiBroker ORBはrootPOAという一つのPOAで生成されます。必要ならrootPOAから追加のPOAを生成できます。

サーバント

CORBAオブジェクトのメソッドをインプリメントするが，CORBAオブジェクト自身はインプリメントしないコードです。

サーバントマネージャ

オブジェクトとサーバントとの対応の管理と，オブジェクトが存在するかどうかの決定の責任を負うオブジェクトです。一つ以上のサーバントマネージャを存在させることができます。

トランジェントオブジェクト

作成元であるプロセス内でしか存在できないCORBAオブジェクトです。

7.1.2　POAの作成および使用手順

正確にはさまざまな手順がありますが，POAのライフサイクル中に行われる基本手順は次のとおりです。

POAのポリシーを定義します。

POAを作成します。

POAマネージャを介してPOAを活性化します。

サーバントを作成し，活性化します。

サーバントマネージャを作成して使用します。

アダプタアクティベータを使用します。

稼働条件によっては，これらの手順の幾つかが任意になる場合があります。例えば，リクエストを処理するためにPOAが必要な場合，そのPOAだけを活性化すればよいのです。

7.2　POAポリシー

各POAは，その特徴を定義するポリシーの集合から成ります。新しいPOAを作成する場合は，各ポリシーのデフォルトを使用するか，または要件に合わせて異なる値を使用できます。ポリシーはPOAの作成時だけ設定でき，既存POAのポリシーは変更できません。POAは親POAのポリシーは継承しません。

次に，POAポリシーとその値，およびデフォルト値（rootPOAが使用）を説明します。

7.2.1　スレッドポリシー

スレッドポリシーでは，POAが使用するスレッドモデルを指定します。ThreadPolicyに使用できる値は次のとおりです。

ORB_CTRL_MODEL（デフォルト）

POAはリクエストをスレッドに割り当てる責任を負います。マルチスレッド環境では，同時に発生した複数のリクエストは，複数のスレッドで処理されます。Borland Enterprise Server VisiBrokerはマルチスレッドモデルを使用することに注意してください。

SINGLE_THREAD_MODEL

POAプロセスはリクエストを順次処理します。マルチスレッド環境では，POAがサーバントおよびサーバントマネージャに行う呼び出しはすべてスレッドセーフです。

MAIN_THREAD_MODEL

呼び出しは識別されたメインスレッドで処理されます。このポリシーを使用するPOAに対するすべてのリクエストは，順次処理されます。マルチスレッド環境では，このポリシーを使用するPOAによって呼び出されるサーバントのすべての処理は，スレッドセーフでなければなりません。

アプリケーションプログラマは，ORB::run()メソッドまたはORB::perform_work()メソッドを呼び出してメインスレッドを指定します。このメソッドの詳細については，「7.4　オブジェクトの活性化」を参照してください。

7.2.2　ライフスパンポリシー

ライフスパンポリシーでは，POAでインプリメントされたオブジェクトのライフスパンを指定します。LifespanPolicyに使用できる値は次のとおりです。

TRANSIENT（デフォルト）

POAが活性化したトランジェントオブジェクトは，そのオブジェクトが生成されたPOA内でしか存在できません。POAが非活性化されてから，POAが生成したオブジェクトリファレンスを使おうとすると，OBJECT_NOT_EXIST例外が発生します。

PERSISTENT

POAが活性化したパーシステントオブジェクトは，そのオブジェクトが最初に生成されたプロセスが消滅しても存在できます。パーシステントオブジェクトで呼び出されたリクエストは，プロセス，POA，およびオブジェクトをインプリメントしたサーバントを暗黙的に活性化します。

7.2.3　ID Uniquenessポリシー

ID Uniqueness（オブジェクトIDの一意性）ポリシーでは，多くのabstractオブジェクトが一つのサーバントを共有できるようにします。IdUniquenessPolicyに使用できる値は次のとおりです。

UNIQUE_ID（デフォルト）

活性化されたサーバントはオブジェクトIDを一つだけサポートします。

MULTIPLE_ID

活性化されたサーバントは一つ以上のオブジェクトIDを持てます。オブジェクトIDはランタイムに呼び出されているメソッド内で決定しなければなりません。

7.2.4　ID Assignmentポリシー

ID Assignment（ID割り当て）ポリシーでは，サーバアプリケーションとPOAのどちらがオブジェクトIDを生成するかを指定します。IdAssignmentPolicyに使用できる値は次のとおりです。

USER_ID

オブジェクトはアプリケーションによってオブジェクトIDを割り当てられます。

SYSTEM_ID（デフォルト）

オブジェクトはPOAによってオブジェクトIDを割り当てられます。PERSISTENTポリシーも設定している場合，オブジェクトIDは同じPOAのすべての実体化にわたって一意でなければなりません。

通常，USER_IDはパーシステントオブジェクト用であり，SYSTEM_IDはトランジェントオブジェクト用です。

7.2.5　Servant Retentionポリシー

Servant Retention（サーバント保持）ポリシーでは，アクティブオブジェクトマップ内のアクティブなサーバントをPOAが保持するかどうかを指定します。ServantRetentionPolicyに指定できる値は次のとおりです。

RETAIN（デフォルト）

POAはアクティブオブジェクトマップにアクティブなサーバントを保持します。そのため，POAにオブジェクトの探索を要求すると，アクティブオブジェクトマップからの探索が行われます。RETAINは通常，ServantActivatorまたはPOAの明示的な活性化メソッドと一緒に使用します。

NON_RETAIN

POAはアクティブオブジェクトマップにアクティブなサーバントを保持しません。そのため，POAにオブジェクトの探索を要求しても，アクティブオブジェクトマップからの探索は行われません。

NON_RETAINは通常，ServantLocatorと一緒に使用しなければなりません。

ServantActivatorとServantLocatorは，サーバントマネージャのタイプです。サーバントマネージャの詳細については，「7.5　サーバントとサーバントマネージャの使用」を参照してください。

7.2.6　Request Processingポリシー

Request Processing（リクエスト処理）ポリシーでは，POAのリクエストの処理方法を指定します。RequestProcessingPolicyに指定できる値は次のとおりです。

USE_ACTIVE_OBJECT_MAP_ONLY（デフォルト）

アクティブオブジェクトマップにオブジェクトIDが存在しなければ，OBJECT_NOT_EXIST例外が返されます。POAにこの値を指定する場合は，必ずRETAINポリシーも指定してください。

USE_DEFAULT_SERVANT

アクティブオブジェクトマップにオブジェクトIDが存在していないか，またはNON_RETAINポリシーが設定されていれば，リクエストはデフォルトサーバントにディスパッチされます。デフォルトサーバントが登録されていなければ，OBJ_ADAPTER例外が返されます。POAにこの値を指定する場合は，必ずMULTIPLE_IDポリシーも指定してください。

USE_SERVANT_MANAGER

アクティブオブジェクトマップにオブジェクトIDが存在していないか，またはNON_RETAINポリシーが設定されていれば，サーバントマネージャを使用してサーバントを取得します。

7.2.7　Implicit Activationポリシー

Implicit Activation（暗黙的な活性化）ポリシーでは，POAがサーバントの暗黙的な活性化をサポートするかどうかを指定します。ImplicitActivationPolicyに指定できる値は次のとおりです。

IMPLICIT_ ACTIVATION

POAはサーバントの暗黙的な活性化をサポートします。サーバントを活性化するには，次の二つの方法があります。

POA::servant_to_reference()メソッド（C++），またはorg.omg.PortableServer.POA.servant_to_reference()メソッド（Java）を使用してサーバントをオブジェクトリファレンスに変換する。

サーバントで_this()メソッドを呼び出す。

POAにこの値を指定する場合は，必ずSYSTEM_IDポリシーとRETAINポリシーも指定してください。

NO_IMPLICIT_ACTIVATION（デフォルト）

POAはサーバントの暗黙的な活性化をサポートしません。

7.2.8　Bind Supportポリシー

Bind Support（バインドサポート）ポリシー（Borland Enterprise Server VisiBroker固有のポリシー）はPOAとアクティブなオブジェクトのBorland Enterprise Server VisiBroker osagentへの登録を制御します。数千ものオブジェクトがある場合，そのすべてをosagentに登録するのは好ましくありません。その代わりに，POAをosagentに登録できます。クライアントがリクエストすると，osagentがリクエストを正しく転送できるように，POA名とオブジェクトIDがバインドリクエストに含まれます。

BindSupportPolicyに指定できる値は次のとおりです。

BY_INSTANCE

すべてのアクティブなオブジェクトをosagentに登録します。POAにこの値を指定する場合は，必ずPERSISTENTポリシーとRETAINポリシーも指定してください。

BY_POA（デフォルト）

POAだけをosagentに登録します。POAにこの値を指定する場合は，必ずPERSISTENTポリシーも指定してください。

NONE

POAもアクティブなオブジェクトもosagentに登録しません。

7.3　POAの作成

POAを使用してオブジェクトをインプリメントするには，最低一つのPOAオブジェクトがサーバ上に存在しなければなりません。POAが確実に存在するように，VisiBroker ORBの初期化中にrootPOAが提供されます。このPOAは「7.2　POAポリシー」で説明したデフォルトのPOAポリシーになります。

rootPOAを取得すれば，特定のサーバ側ポリシーのセットをインプリメントする子POAを作成できます。

7.3.1　POAネーミング規則

各POAは自身の名前と完全なPOA名称（完全階層パス名）を常に把握しています。階層はスラント（/）で示されます。例えば，/A/B/Cは，POA CはPOA Bの子であり，POA BはPOA Aの子であるという意味です。最初のスラントはrootPOAを示します。Bind Support:BY_POAポリシーをPOA Cに設定すると，/A/B/Cはosagentに登録され，クライアントは/A/B/Cにバインドできるようになります。

使用するPOA名にエスケープ文字またはそれ以外の区切り文字が含まれている場合，名前を内部で記録するときに，Borland Enterprise Server VisiBrokerはこれらの文字の前に二重¥マーク（¥¥）を付加します。例えば，次のような階層に二つのPOAがあるとします。

C++の場合

PortableServer::POA_var myPOA1 =
                          rootPOA->create_POA("A/B",
                          poa_manager,
                          policies);
PortableServer::POA_var myPOA2 =
                          myPOA1->create_POA("¥t",
                          poa_manager,
                          policies);

クライアントがバインドするときには，次のように使用します。

Bank::AccountManager_var manager = Bank::AccountManager::_bind
                          ("/A¥¥/B/¥t", managerId);

Javaの場合

org.omg.PortableServer.POA myPOA1 =
                          rootPOA.create_POA("A/B",
                                             poaManager,
                                             policies);
org.omg.PortableServer.POA myPOA2 =
                          myPOA1.create_POA("¥t",
                                             poaManager,
                                             policies);

クライアントがバインドするときには，次のように使用します。

org.omg.CORBA.Object manager =
        ((com.inprise.vbroker.orb.ORB) orb).bind("/A¥¥/B/¥t",
          managerId,
          null,
          null);

7.3.2　rootPOAの取得

コードサンプル7-1および7-2に，サーバアプリケーションがどのようにrootPOAを取得できるかを示します。

コードサンプル7-1　rootPOAの取得（C++）

// Initialize the ORB.
CORBA::Object_var obj =
      orb->resolve_initial_references("RootPOA");
// get a reference to the rootPOA
PortableServer::POA_var rootPOA =
      PortableServer::POA::_narrow(obj);

コードサンプル7-2　rootPOAの取得（Java）

// Initialize the ORB.
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
// get a reference to the rootPOA
org.omg.PortableServer.POA rootPOA =
      POAHelper.narrow(
                 orb.resolve_initial_references("RootPOA"));

注

resolve_initial_referencesメソッドは，CORBA::Object型の値（C++）またはorg.omg.CORBA.Object型の値（Java）を返します。返されたオブジェクトリファレンスを希望の型（上記のサンプルではPortableServer::POA（C++），またはorg.omg.PortableServer.POA（Java））にナロウするのはプログラマの責任です。

7.3.3　POAプロパティの設定

親POAのポリシーは継承されません。POAに特定の特徴を持たせたければ，デフォルト値と異なるすべてのポリシーを特定する必要があります。POAポリシーの詳細については，「7.2　POAポリシー」を参照してください。

コードサンプル7-3　POAのポリシーの作成例（C++）

CORBA::PolicyList policies;
policies.length(1);
policies[(CORBA::ULong)0] = rootPOA->create_lifespan_policy
      (PortableServer::PERSISTENT);

コードサンプル7-4　POAのポリシーの作成例（Java）

org.omg.CORBA.Policy[ ] policies = {
   rootPOA.create_lifespan_policy(LifespanPolicyValue.
                                  PERSISTENT)
};

7.3.4　POAの作成と活性化

POAは，その親POAのcreate_POAを使用して生成されます。POAには任意の名前を付けられます。ただし，同じ親を持つPOA同士の名前はすべて一意でなければなりません。二つのPOAに同じ名前を付けようとすると，CORBA例外（AdapterAlreadyExists）が発生します。

新しいPOAを生成するには，次のようにcreate_POAを使用してください。

POA create_POA(POA_Name, POAManager, PolicyList);

POAマネージャはPOAの状態（リクエストを処理するかどうかなど）を制御します。POAマネージャ名としてnullがcreate_POAに渡されると，新しいPOAマネージャオブジェクトが生成されてPOAに対応づけられます。通常は，すべてのPOAに対して同じPOAマネージャを持ちたいでしょう。POAマネージャの詳細については，「7.6　POAマネージャによるPOA管理」を参照してください。

POAマネージャ（およびPOA）は，生成後に自動的に活性化されるわけではありません。使用しているPOAに対応するPOAマネージャを活性化するには，activate()メソッドを使用してください。

コードサンプル7-5　POAの作成例（C++）

CORBA::PolicyList policies;
policies.length(1);
policies[(CORBA::ULong)0] = rootPOA->create_lifespan_policy
      (PortableServer::PERSISTENT);
// Create myPOA with the right policies
PortableServer::POAManager_var rootManager =
      rootPOA->the_POAManager();
PortableServer::POA_var myPOA =
      rootPOA->create_POA("bank_agent_poa",
      rootManager, policies);

コードサンプル7-6　POAの作成例（Java）

// Create policies for our persistent POA
org.omg.CORBA.Policy[ ] policies = {
      rootPOA.create_lifespan_policy(
                           LifespanPolicyValue.PERSISTENT)};
// Create myPOA with the right policies
org.omg.PortableServer.POA myPOA =
      rootPOA.create_POA( "bank_agent_poa",
                         rootPOA.the_POAManager(),
                         policies );

7.4　オブジェクトの活性化

CORBAオブジェクトがアクティブなサーバントと対応づけられると，POAのServant Retention（サーバント保持）ポリシーがRETAINである場合，対応するオブジェクトIDがアクティブオブジェクトマップに記録され，そのオブジェクトが活性化されます。活性化するには幾つかの方法があります。

明示的な活性化

サーバアプリケーション自身がactivate_objectまたはactivate_object_with_idを呼び出すことによって明示的にオブジェクトを活性化します。

オンデマンドによる活性化

サーバアプリケーションは，ユーザ提供のサーバントマネージャを介してPOAにオブジェクトを活性化するよう指示します。set_servant_managerを使用して，まずPOAにサーバントマネージャを登録しなければなりません。

暗黙的な活性化

幾つかのオペレーションに対する応答として，サーバが単独でオブジェクト活性化を行います。サーバントがアクティブでなければ，クライアントがサーバントをアクティブにできる方法はありません（例えば，非アクティブなオブジェクトをリクエストしてもオブジェクトをアクティブにはできません）。

デフォルトサーバントによる活性化

POAはサーバントを一つだけ使用して，すべてのオブジェクトをインプリメントします。

7.4.1　オブジェクトの明示的な活性化

IdAssignmentPolicy::SYSTEM_IDをPOAに設定すれば，オブジェクトIDの指定をしないでオブジェクトを明示的に活性化できます。サーバはオブジェクトのオブジェクトIDの活性化，割り当て，リターンを行うPOAのactivate_objectを呼び出します。このタイプの活性化はトランジェントオブジェクトでは最もよく使用されます。オブジェクトもサーバントもあまり長期間は必要ではないので，サーバントマネージャは不要です。

オブジェクトIDを使用してオブジェクトを明示的に活性化することもできます。一般的なシナリオは，サーバが管理するすべてのオブジェクトを活性化するためにユーザがactivate_object_with_idを呼び出すサーバ初期化中です。すべてのオブジェクトは活性化済みなので，サーバントマネージャは不要です。存在しないオブジェクトに対するリクエストを受信すると，OBJECT_NOT_EXIST例外が発生します。サーバが多数のオブジェクトを管理している場合，お勧めできません。

コードサンプル7-7　activate_object_with_idを使用した明示的な活性化の例（C++）

// Create the servant
AccountManagerImpl managerServant;
// Decide on the ID for the servant
PortableServer::ObjectId_var managerId =
      PortableServer::string_to_ObjectId("BankManager");
// Activate the servant with the ID on myPOA
myPOA->activate_object_with_id(managerId,&managerServant);
// Activate the POA Manager
PortableServer::POAManager_var rootManager =
      rootPOA->the_POAManager();
rootManager->activate();

コードサンプル7-8　activate_object_with_idを使用した明示的な活性化の例（Java）

// Create the account manager servant.
Servant managerServant = new AccountManagerImpl(rootPoa);
// Activate the newly created servant.
testPoa.activate_object_with_id(
                  "BankManager".getBytes(), managerServant);
// Activate the POAs
testPoa.the_POAManager().activate();

7.4.2　オブジェクトのオンデマンドによる活性化

対応するサーバントを持たないオブジェクトをクライアントがリクエストすると，オンデマンドによる活性化が発生します。このリクエストの受信後，POAはオブジェクトIDに対応するアクティブなサーバントを求めてアクティブオブジェクトマップを検索します。見つからなければ，POAはオブジェクトID値をサーバントマネージャに渡すサーバントマネージャのincarnateを呼び出します。サーバントマネージャができることは次の三つがあり，どれか一つを行います。

適切なサーバントを見つけます。このサーバントはリクエストに対する適切なオペレーションを実行します。

クライアントに返されるOBJECT_NOT_EXIST例外を発生させます。

リクエストをほかのオブジェクトに転送します。

POAポリシーは，追加する処理を決定します。次にC++およびJavaについて説明します。

C++の場合

RequestProcessingPolicy::USE_SERVANT_MANAGERとServantRetentionPolicy::RETAINが有効なら，アクティブオブジェクトマップはサーバントとオブジェクトIDの対応を更新します。

Javaの場合

RequestProcessingPolicy.USE_SERVANT_MANAGERとServantRetentionPolicy.RETAINが有効なら，アクティブオブジェクトマップはサーバントとオブジェクトIDの対応を更新します。

オンデマンドによる活性化の例については，コードサンプル7-13を参照してください。

7.4.3　オブジェクトの暗黙的な活性化

(1)　C++の場合

ImplicitActivationPolicy::IMPLICIT_ACTIVATION，IdAssignmentPolicy::SYSTEM_ID，およびServantRetentionPolicy::RETAINを設定してPOAを活性化した場合，あるオペレーションでサーバントを暗黙的に活性化できます。暗黙的な活性化は次のメソッドで行えます。

POA::servant_to_referenceメソッド

POA::servant_to_idメソッド

_this()サーバントメソッド

POAにObjectIdUniquenessPolicy::UNIQUE_IDを設定すると，非アクティブなサーバントに対して上記のオペレーションのどれかを行った場合に暗黙的な活性化ができます。

POAにObjectIdUniquenessPolicy::MULTIPLE_IDを設定すると，たとえサーバントがすでにアクティブでも，servant_to_referenceオペレーションとservant_to_idオペレーションは常に暗黙的な活性化を行います。

(2)　Javaの場合

ImplicitActivationPolicy.IMPLICIT_ACTIVATION，IdAssignmentPolicy.SYSTEM_ID，およびServantRetentionPolicy.RETAINを設定してPOAを活性化した場合，あるオペレーションでサーバントを暗黙的に活性化できます。暗黙的な活性化は次のメソッドで行えます。

POA.servant_to_referenceメソッド

POA.servant_to_idメソッド

_this()サーバントメソッド

POAにObjectIdUniquenessPolicy.UNIQUE_IDを設定すると，非アクティブなサーバントに対して上記のオペレーションのどれかを行った場合に暗黙的な活性化ができます。

POAにObjectIdUniquenessPolicy.MULTIPLE_IDを設定すると，たとえサーバントがすでにアクティブでも，servant_to_referenceオペレーションとservant_to_idオペレーションは常に暗黙的な活性化を行います。

7.4.4　デフォルトサーバントによる活性化

オブジェクトIDが何であろうとPOAに同じサーバントを起動させるには，RequestProcessing::USE_DEFAULT_SERVANTポリシー（C++），またはRequestProcessing.USE_DEFAULT_SERVANTポリシー（Java）を使用してください。これは各オブジェクトに少量のデータしか持たせていない場合に便利です。

コードサンプル7-9　同じサーバントによるすべてのオブジェクトの活性化例（C++）

int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
      PortableServer::Current_var cur =
            PortableServer::Current::_instance();
      DataStore::_create();

      // get a reference to the rootPOA
      CORBA::Object_var obj =
            orb->resolve_initial_references("RootPOA");
      PortableServer::POA_var rootPOA =
            PortableServer::POA::_narrow(obj);

      CORBA::PolicyList policies;
      policies.length(3);

      // Create policies for our persistent POA
      policies[(CORBA::ULong)0] =
            rootPOA->create_lifespan_policy
            (PortableServer::PERSISTENT);
      policies[(CORBA::ULong)1] =
            rootPOA->create_request_processing_policy
            (PortableServer::USE_DEFAULT_SERVANT);
      policies[(CORBA::ULong)2] =
            rootPOA->create_id_uniqueness_policy
            (PortableServer::MULTIPLE_ID);

      // Create myPOA with the right policies
      PortableServer::POAManager_var rootManager =
            rootPOA->the_POAManager();
      PortableServer::POA_var myPOA =
            rootPOA->create_POA
            ("bank_default_servant_poa",
            rootManager, policies);
      // Set the default servant
      AccountManagerImpl * managerServant =
            new AccountManagerImpl(cur);
      myPOA->set_servant( managerServant );

      // Activate the POA Manager
      rootManager->activate();

      // Generate two references - one for checking
      // and another for savings.
      // Note that we are not creating any
      // servants here and just manufacturing a reference
      // which is not yet backed by a servant
      PortableServer::ObjectId_var an_oid =
            PortableServer::string_to_ObjectId
            ("CheckingAccountManager");
      CORBA::Object_var cref =
            myPOA->create_reference_with_id(an_oid.in(),
            "IDL:Bank/AccountManager:1.0");

      an_oid = PortableServer::string_to_ObjectId
            ("SavingsAccountManager");
      CORBA::Object_var sref = myPOA->create_reference_with_id
            (an_oid.in(), "IDL:Bank/AccountManager:1.0");

      // Write out Checking reference
      CORBA::String_var string_ref =
            orb->object_to_string(cref.in());
      ofstream crefFile("cref.dat");
      crefFile << string_ref << endl;
      crefFile.close();
      // Now write out the Savings reference
      string_ref = orb->object_to_string(sref.in());
      ofstream srefFile("sref.dat");
      srefFile << string_ref << endl;
      srefFile.close();
      cout << "Bank Manager is ready" << endl;
      // Wait for incoming requests
      orb->run();
      DataStore::_destroy();
   }
   catch(const CORBA::Exception& e) {
      cerr << e << endl;
   }
   return 1;
}

コードサンプル7-10　同じサーバントによるすべてのオブジェクトの活性化例（Java）

import org.omg.PortableServer.*;
public class Server {
   public static void main(String[ ] args) {
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb
                       = org.omg.CORBA.ORB.init(args,null);
         // get a reference to the rootPOA
         POA rootPOA = POAHelper.narrow(
           orb.resolve_initial_references("RootPOA"));
         // Create policies for our persistent POA
         org.omg.CORBA.Policy[ ] policies = {
           rootPOA.create_lifespan_policy(
                 LifespanPolicyValue.PERSISTENT),
           rootPOA.create_request_processing_policy(
                 RequestProcessingPolicyValue.USE_DEFAULT_SERVANT
           )
         };
         // Create myPOA with the right policies
         POA myPOA = rootPOA.create_POA(
               "bank_default_servant_poa",
               rootPOA.the_POAManager(),
               policies );
         // Create the servant
         AccountManagerImpl managerServant =
                                   new AccountManagerImpl();
         // Set the default servant on our POA
         myPOA.set_servant(managerServant);
         org.omg.CORBA.Object ref;
         // Activate the POA manager
         rootPOA.the_POAManager().activate();
         // Generate the reference and write it out. One
         // for each Checking and Savings account types.
         // Note that we are not creating any servants
         // here and just manufacturing a reference
         // which is not yet backed by a servant.
         try {
           ref = myPOA.create_reference_with_id(
                               "CheckingAccountManager".getBytes(),
                               "IDL:Bank/AccountManager:1.0");
           // Write out checking object ID
           java.io.PrintWriter pw = new java.io.PrintWriter(
                 new java.io.FileWriter("cref.dat"));
           pw.println(orb.object_to_string(ref));
           pw.close();
           ref = myPOA.create_reference_with_id(
                            "SavingsAccountManager".getBytes(),
                            "IDL:Bank/AccountManager:1.0");
           // Write out savings object ID
           pw = new java.io.PrintWriter(
                  new java.io.FileWriter("sref.dat"));
           System.gc();
           pw.println(orb.object_to_string(ref));
           pw.close();
        } catch ( java.io.IOException e ){
           System.out.println("Error writing the IOR to file ");
           return;
        }
        System.out.println("Bank Manager is ready.");
        // Wait for incoming requests
        orb.run();
     }catch (Exception e){
        e.printStackTrace();
     }
   }
}

7.4.5　オブジェクトの非活性化

POAはアクティブオブジェクトマップからサーバントを削除できます。例えば，これはガーベッジコレクション手法の一形態として行います。サーバントをマップから削除すると，そのサーバントは非活性化されます。deactivate_object()メソッドを使用してオブジェクトを非活性化できます。オブジェクトを非活性化すると，このオブジェクトが永遠に失われるということではありません。あとで再度活性化できます。

コードサンプル7-11　オブジェクトの非活性化例（C++）

// DeActivatorThread
class DeActivatorThread: public VISThread {
   private :
      PortableServer::ObjectId _oid;
      PortableServer::POA_ptr _poa;

   public :
      virtual ~DeActivatorThread(){}
      // Constructor
      DeActivatorThread(const PortableServer::ObjectId& oid,
            PortableServer::POA_ptr poa ): _oid(oid),
            _poa(poa) {
         // start the thread
         run();
      }

      // implement begin() callback
      void begin() {
         // Sleep for 15 seconds
         VISPortable::vsleep(15);

         CORBA::String_var s =
            PortableServer::ObjectId_to_string (_oid);
         // Deactivate Object
         cout << "¥nDeactivating the object with ID =
            " << s << endl;
         if ( _poa )
            _poa->deactivate_object( _oid );
      }
};

// Servant Activator
class AccountManagerActivator :
      public PortableServer::ServantActivator {
   public:
      virtual PortableServer::Servant incarnate
            (const PortableServer::ObjectId& oid,
            PortableServer::POA_ptr poa) {
         CORBA::String_var s =
            PortableServer::ObjectId_to_string (oid);
         cout << "¥nAccountManagerActivator.incarnate called
            with ID = " << s << endl;
         PortableServer::Servant servant;

         if ( VISPortable::vstricmp( (char *)s,
               "SavingsAccountManager" ) == 0 )
            // Create CheckingAccountManager Servant
            servant = new SavingsAccountManagerImpl;
         else if ( VISPortable::vstricmp( (char *)s,
               "CheckingAccountManager" ) == 0 )
            // Create CheckingAccountManager Servant
            servant = new CheckingAccountManagerImpl;
         else
            throw CORBA::OBJECT_NOT_EXIST();
         // Create a deactivator thread
         new DeActivatorThread( oid, poa );
         // return the servant
         servant->_add_ref();
         return servant;
      }

      virtual void etherealize (
               const PortableServer::ObjectId& oid,
            PortableServer::POA_ptr adapter,
            PortableServer::Servant servant,
            CORBA::Boolean cleanup_in_progress,
            CORBA::Boolean remaining_activations) {
      // If there are no remaining activations i.e ObjectIds
      // associated with the servant delete it.

      CORBA::String_var s =
            PortableServer::ObjectId_to_string (oid);
      cout << "¥nAccountManagerActivator.etherealize called
            with ID = " << s << endl;
      if (!remaining_activations)
         delete servant;
   }
};

コードサンプル7-12　オブジェクトの非活性化例（Java）

import org.omg.PortableServer.*;
public class AccountManagerActivator extends
                                       ServantActivatorPOA {
   public Servant incarnate (
            byte[ ] oid, POA adapter) throws ForwardRequest {
      Servant servant;
      String accountType = new String(oid);
      System.out.println(
        "¥nAccountManagerActivator. incarnate
         called with ID = " + accountType + "¥n");
      // Create Savings or Checking Servant based on
      // AccountType
      if (accountType.equalsIgnoreCase(
                                   "SavingsAccountManager"))
         servant = (Servant )new SavingsAccountManagerImpl();
      else
         servant = (Servant)new CheckingAccountManagerImpl();
         new DeactivateThread(oid, adapter).start();
         return servant;
      }
      public void etherealize (byte[ ] oid,
            POA adapter,
            Servant serv,
            boolean cleanup_in_progress,
            boolean remaining_activations) {
         System.out.println(
           "¥nAccountManagerActivator.etherealize
            called with ID = " + new String(oid) + "¥n");
         System.gc();
      }
}
class DeactivateThread extends Thread {
   byte[ ] _oid;
   POA _adapter;
   public DeactivateThread(byte[ ] oid, POA adapter) {
      _oid = oid;
      _adapter = adapter;
   }
   public void run() {
      try {
         Thread.currentThread().sleep(15000);
         System.out.println(
                    ¥nDeactivating the object with ID = " +
                    new String(_oid) + "¥n");
         _adapter.deactivate_object(_oid);
   } catch (Exception e) {
     e.printStackTrace();
   }
}
}

7.5　サーバントとサーバントマネージャの使用

サーバントマネージャは，サーバントを見つけて返す，サーバントを非活性化する，という2種類のオペレーションを行います。サーバントマネージャは，非アクティブなオブジェクトに対するリクエストが受信されたときにPOAがオブジェクトを活性化できるようにします。サーバントマネージャの使用は任意です。例えば，起動時にサーバがすべてのオブジェクトをロードする場合は，サーバントマネージャは不要です。サーバントマネージャは，ForwardRequest例外を使用してほかのオブジェクトにリクエストを転送するようにクライアントに知らせることもできます。

サーバントは，インプリメンテーションのアクティブなインスタンスです。POAはアクティブなサーバントとサーバントのオブジェクトIDのマップを維持します。クライアントリクエストを受信すると，POAはまずマップをチェックして（クライアントリクエストに埋め込まれている）オブジェクトIDが記録されているかどうかを調べます。このオブジェクトIDが見つかれば，POAはリクエストをサーバントに転送します。オブジェクトIDがマップになければ，サーバントマネージャは適切なサーバントの探索と活性化を要求されます。これは，あくまでもシナリオ例です。正確なシナリオは実際に使用するPOAポリシーによって異なります。サーバントマネージャ機能の例を図7-2に示します。

図7‒2　サーバントマネージャ機能の例

サーバントマネージャにはServantActivatorとServantLocatorという二つのタイプがあります。どのコールバックを使用するかは，設定済みのポリシーのタイプによって決定します。POAポリシーの詳細については，「7.2　POAポリシー」を参照してください。一般には，ServantActivatorがパーシステントオブジェクトを活性化し，ServantLocatorがトランジェントオブジェクトを活性化します。

C++の場合

サーバントマネージャを使用するには，RequestProcessingPolicy::USE_SERVANT_MANAGERと，サーバントマネージャのタイプを定義するポリシー（ServantActivatorの場合はServantRetentionPolicy::RETAIN，ServantLocatorの場合はServantRetentionPolicy::NON_RETAIN）を指定しなければなりません。

Javaの場合

サーバントマネージャを使用するには，RequestProcessingPolicy.USE_SERVANT_MANAGERと，サーバントマネージャのタイプを定義するポリシー（ServantActivatorの場合はServantRetentionPolicy.RETAIN，ServantLocatorの場合はServantRetentionPolicy.NON_RETAIN）を指定しなければなりません。

7.5.1　ServantActivator

C++の場合

ServantActivatorは，ServantRetentionPolicy::RETAINとRequestProcessingPolicy::USE_SERVANT_MANAGERが設定された場合に使用します。

Javaの場合

ServantActivatorは，ServantRetentionPolicy.RETAINとRequestProcessingPolicy.USE_SERVANT_MANAGERが設定された場合に使用します。

このタイプのサーバントマネージャによって活性化されたサーバントは，アクティブオブジェクトマップで管理されます。

サーバントアクティベータを使用したリクエストの処理中には，次のようなイベントが発生します。

クライアントリクエストを受信します（クライアントリクエストにはPOA名，オブジェクトIDなどの情報が含まれます）。

POAはまず，アクティブオブジェクトマップをチェックします。オブジェクトIDがそこで見つかれば，オペレーションはサーバントに渡され，クライアントに応答が返されます。

アクティブオブジェクトマップにオブジェクトIDが見つからなければ，POAはサーバントマネージャのincarnateを呼び出します。incarnateはオブジェクトIDと，オブジェクトを活性化しているPOAを渡します。

サーバントマネージャは適切なサーバントを探します。

サーバントIDがアクティブオブジェクトマップに入力され，クライアントに応答が返されます。

注

etherealizeおよびincarnateメソッドインプリメンテーションはユーザが指定するコードです。

そのあとで，サーバントを非活性化できます。これは，deactivate_objectオペレーション，該当するPOAと対応するPOAマネージャの非活性化など，幾つかのソースから行えます。オブジェクトの非活性化の詳細については，「7.4.5　オブジェクトの非活性化」を参照してください。

コードサンプル7-13　サーバントアクティベータタイプのサーバントマネージャを示すサーバコードサンプル（C++）

int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

      DataStore::_create();

      // get a reference to the rootPOA
      CORBA::Object_var obj =
            orb->resolve_initial_references("RootPOA");
      PortableServer::POA_var rootPOA =
            PortableServer::POA::_narrow(obj);

      CORBA::PolicyList policies;
      policies.length(2);

      policies[(CORBA::ULong)0] =
            rootPOA->create_lifespan_policy
                  (PortableServer::PERSISTENT);
      policies[(CORBA::ULong)1] =
            rootPOA->create_request_processing_policy(
                  PortableServer::USE_SERVANT_MANAGER);

      // Create myPOA with the right policies
      PortableServer::POAManager_var rootManager =
            rootPOA->the_POAManager();
      PortableServer::POA_var myPOA =
            rootPOA->create_POA("bank_servant_activator_poa",
            rootManager, policies);
      // Create a Servant activator
      AccountManagerActivator servant_activator_impl;

      //Set the servant activator
      myPOA->set_servant_manager(&servant_activator_impl);

      // Generate two references - one for checking and another
      //for savings.Note that we are not creating any
      //servants here and just manufacturing a reference which
      //is not yet backed by a servant
      PortableServer::ObjectId_var an_oid =
            PortableServer::string_to_ObjectId
                  ("CheckingAccountManager");
      CORBA::Object_var cref = myPOA->create_reference_with_id
            (an_oid.in(), IDL:Bank/AccountManager:1.0");

      an_oid = PortableServer::string_to_ObjectId
            ("SavingsAccountManager");
      CORBA::Object_var sref = myPOA->create_reference_with_id
            (an_oid.in(), "IDL:Bank/AccountManager:1.0");

      //Activate the POA Manager
      rootManager->activate();

      // Write out Checking reference
      CORBA::String_var string_ref = orb->object_to_string
            (cref.in());
      ofstream crefFile("cref.dat");
      crefFile << string_ref << endl;
      crefFile.close();
      // Now write out the Savings reference
      string_ref = orb->object_to_string(sref.in());
      ofstream srefFile("sref.dat");
      srefFile << string_ref << endl;
      srefFile.close();

      // Waiting for incoming requests
      cout << "BankManager Server is ready" << endl;
      orb->run();

      DataStore::_destroy();
   }
   catch(const CORBA::Exception& e) {
      cerr << e << endl;
   }
   return 1;
}

コードサンプル7-14　サーバントアクティベータタイプのサーバントマネージャを示すサーバコードサンプル（Java）

import org.omg.PortableServer.*;
public class Server {
   public static void main(String[ ] args) {
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                        org.omg.CORBA.FORB.init(args, null);
         // get a reference to the rootPOA
         POA rootPOA = POAHelper.narrow(
           orb.resolve_initial_references("RootPOA"));
         // Create policies for our POA.
         // We need persistence life span and
         // use servant manager request processing policies
         org.omg.CORBA.Policy[ ] policies = {
            rootPOA.create_lifespan_policy(
               LifespanPolicyValue.PERSISTENT),
            rootPOA.create_request_processing_policy(
               RequestProcessingPolicyValue.
               USE_SERVANT_MANAGER)
            };

            // Create myPOA with the right policies
            POA myPOA = rootPOA.create_POA(
                  "bank_servant_activator_poa",
                  rootPOA.the_POAManager(),
                  policies );
            // Create the servant activator servant
            //  and get its reference
            ServantActivator sa =
                   new AccountManagerActivator()._this(orb);
            // Set the servant activator on our POA
            myPOA.set_servant_manager(sa);
            org.omg.CORBA.Object ref;
            // Activate the POA manager
            rootPOA.the_POAManager().activate();
            // Generate the reference and write it out.
            // One for each Checking and Savings
            // account types .Note that we are not creating
            // any servants here and just manufacturing a
            // reference which is not yet backed by a servant.
            try {
              ref = myPOA.create_reference_with_id(
                   "CheckingAccountManager".getBytes(),
                   "IDL:Bank/AccountManager:1.0");
              // Write out checking object ID
              java.io.PrintWriter pw =
              new java.io.PrintWriter(
                        new java.io.FileWriter("cref.dat"));
              pw.println(orb.object_to_string(ref));
              pw.close();
              ref = myPOA.create_reference_with_id(
                    "SavingsAccountManager".getBytes(),
                    "IDL:Bank/AccountManager:1.0");
              // Write out savings object ID
              pw = new java.io.PrintWriter(
                   new java.io.FileWriter("sref.dat"));
              System.gc();
              pw.println(orb.object_to_string(ref));
              pw.close();
          } catch ( java.io.IOException e ) {
              System.out.println(
                          "Error writing the IOR to file ");
              return;
          }
          System.out.println("Bank Manager is ready.");
          // Wait for incoming requests
          orb.run();
     } catch (Exception e) {
        e.printStackTrace();
     }
   }
}

このサンプルのサーバントマネージャを，次に示します。

コードサンプル7-15　サーバントアクティベータのサンプルのサーバントマネージャ（C++）

// Servant Activator
class AccountManagerActivator :
      public PortableServer::ServantActivator {
   public:
      virtual PortableServer::Servant incarnate
            (const PortableServer::ObjectId& oid,
            PortableServer::POA_ptr poa) {
         CORBA::String_var s =
               PortableServer::ObjectId_to_string (oid);
         cout << "¥nAccountManagerActivator.incarnate called
               with ID = " << s << endl;
         PortableServer::Servant servant;

      if ( VISPortable::vstricmp( (char *)s,
            "SavingsAccountManager" ) == 0 )
         //Create CheckingAccountManager Servant
         servant = new SavingsAccountManagerImpl;
      else if ( VISPortable::vstricmp( (char *)s,
            "CheckingAccountManager" ) == 0 )
         //Create CheckingAccountManager Servant
         servant = new CheckingAccountManagerImpl;
      else
         throw CORBA::OBJECT_NOT_EXIST();
      // Create a deactivator thread
      new DeActivatorThread( oid, poa );
      // return the servant
      return servant;
   }

   virtual void etherealize (
         const PortableServer::ObjectId& oid,
         PortableServer::POA_ptr adapter,
         PortableServer::Servant servant,
         CORBA::Boolean cleanup_in_progress,
         CORBA::Boolean remaining_activations) {
      // If there are no remaining activations i.e ObjectIds
      // associated with the servant delete it.
      CORBA::String_var s =
            PortableServer::ObjectId_to_string (oid);
      cout << "¥nAccountManagerActivator.etherealize called
         with ID = " << s << endl;
      if (!remaining_activations)
         delete servant;
   }
};

コードサンプル7-16　サーバントアクティベータのサンプルのサーバントマネージャ（Java）

import org.omg.PortableServer.*;
public class AccountManagerActivator extends
                                       ServantActivatorPOA {
   public Servant incarnate (
       byte[ ] oid, POA adapter) throws ForwardRequest {
         Servant servant;
         String accountType = new String(oid);
         System.out.println(
           "¥nAccountManagerActivator.incarnate
             called with ID = " + accountType + "¥n");
      // Create Savings or Checking Servant based on
      // AccountType
      if ( accountType.equalsIgnoreCase(
                                   "SavingsAccountManager"))
         servant = (Servant )new SavingsAccountManagerImpl();
      else
         servant = (Servant)new CheckingAccountManagerImpl();
      new DeactivateThread(oid, adapter).start();
      return servant;
   }
   public void etherealize (byte[ ] oid,
         POA adapter,
         Servant serv,
         boolean cleanup_in_progress,
         boolean remaining_activations){
     System.out.println(
        "¥nAccountManagerActivator.
         etherealize called with ID = " +
         new String(oid) + "¥n");
     System.gc();
   }
}
class DeactivateThread extends Thread {
   byte[ ] _oid;
   POA _adapter;
   public DeactivateThread(byte[ ] oid, POA adapter) {
     _oid = oid;
     _adapter = adapter;
   }

   public void run(){
     try {
        Thread.currentThread().sleep(15000);
        System.out.println(
          "¥nDeactivating the object with ID = " +
           new String(_oid) + "¥n");
        _adapter.deactivate_object(_oid);
     }catch (Exception e) {
       e.printStackTrace();
     }
   }
}

7.5.2　ServantLocator

POAのアクティブオブジェクトマップがきわめて大きくなりメモリを消費するような状況はよくあります。メモリ消費量を減らすために，サーバントとオブジェクトの対応をアクティブオブジェクトマップに格納しないという意味のRequestProcessingPolicy::USE_SERVANT_MANAGERとServantRetentionPolicy::NON_RETAIN（C++）設定，またはRequestProcessingPolicy.USE_SERVANT_MANAGERとServantRetentionPolicy.NON_RETAIN（Java）設定でPOAを作成できます。対応が格納されないので，ServantLocatorサーバントマネージャをリクエストごとに起動できます。

サーバントロケータを使用したリクエストの処理中には，次のようなイベントが発生します。

クライアントリクエストを受信します（クライアントリクエストにはPOA名およびオブジェクトIDが含まれます）。

ServantRetentionPolicy::NON_RETAIN（C++），またはServantRetentionPolicy.NON_RETAIN（Java）を使用しているので，POAはアクティブオブジェクトマップのオブジェクトIDを探しません。

POAはサーバントマネージャのpreinvokeを呼び出します。preinvokeはオブジェクトID，オブジェクトを活性化しているPOAなどのパラメタを渡します。

サーバントロケータは適切なサーバントを探します。

サーバントに対するオペレーションが実行され，クライアントに応答が返されます。

POAはサーバントマネージャのpostinvokeを呼び出します。

注

preinvokeメソッドとpostinvokeメソッドはユーザが指定するコードです。

コードサンプル7-17　サーバントロケータタイプのサーバントマネージャを示すサーバコードサンプル（C++）

int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

      // And the Data source
      DataStore::_create();

      // get a reference to the rootPOA
      CORBA::Object_var obj =
            orb->resolve_initial_references("RootPOA");
      PortableServer::POA_var rootPOA =
            PortableServer::POA::_narrow(obj);

      CORBA::PolicyList policies;
      policies.length(3);

      // Create a child POA with Persistence life span policy
      // that uses servant manager with non-retain retention
      // policy ( no Active Object Map ) causing the POA to use
      // the servant locator.
      policies[(CORBA::ULong)0] =
            rootPOA->create_lifespan_policy
            (PortableServer::PERSISTENT);
      policies[(CORBA::ULong)1] =
            rootPOA->create_servant_retention_policy
            (PortableServer::NON_RETAIN);
      policies[(CORBA::ULong)2] =
            rootPOA->create_request_processing_policy
            (PortableServer::USE_SERVANT_MANAGER);
      PortableServer::POAManager_var rootManager =
            rootPOA->the_POAManager();
      PortableServer::POA_var myPOA =
            rootPOA->create_POA("bank_servant_locator_poa",
            rootManager, policies);
      // Create the servant locator
      AccountManagerLocator servant_locator_impl;
      myPOA->set_servant_manager(&servant_locator_impl);

      // Generate two references - one for checking and another
      // for savings.Note that we are not creating any
      // servants here and just manufacturing a reference which
      // is not yet backed by a servant
      PortableServer::ObjectId_var an_oid =
            PortableServer::string_to_ObjectId
            ("CheckingAccountManager");
      CORBA::Object_var cref = myPOA->create_reference_with_id
            (an_oid.in(), "IDL:Bank/AccountManager:1.0");

      an_oid = PortableServer::string_to_ObjectId
            ("SavingsAccountManager");
      CORBA::Object_var sref = myPOA->create_reference_with_id
            (an_oid.in(), "IDL:Bank/AccountManager:1.0");

      // Activate the POA Manager
      rootManager->activate();

      // Write out Checking reference
      CORBA::String_var string_ref =
            orb->object_to_string(cref.in());
      ofstream crefFile("cref.dat");
      crefFile << string_ref << endl;
      crefFile.close();
      // Now write out the Savings reference
      string_ref = orb->object_to_string(sref.in());
      ofstream srefFile("sref.dat");
      srefFile << string_ref << endl;
      srefFile.close();

      // Wait for incoming requests
      cout << "Bank Manager is ready" << endl;
      orb->run();
      // Destroy the accounts database
      DataStore::_destroy();
   }
   catch(const CORBA::Exception& e) {
      cerr << e << endl;
   }
   return 1;
}

コードサンプル7-18　サーバントロケータタイプのサーバントマネージャを示すサーバコードサンプル（Java）

import org.omg.PortableServer.*;
   public class Server {
      public static void main(String[ ] args) {
         try {
            // Initialize the ORB.
            org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);
            // get a reference to the rootPOA
            POA rootPOA = POAHelper.narrow(
               orb.resolve_initial_references("RootPOA"));
            // Create policies for our POA.
            // We need persistence life span,
            // use servant manager request processing
            // policies and non retain retention policy.
            // This non retain policy will let us use the

            // servant locator instead of servant activator
            org.omg.CORBA.Policy[ ] policies = {
               rootPOA.create_lifespan_policy(
                    LifespanPolicyValue.PERSISTENT),
               rootPOA.create_servant_retention_policy(
                    ServantRetentionPolicyValue.NON_RETAIN),
               rootPOA.create_request_processing_policy(
                    RequestProcessingPolicyValue.
                    USE_SERVANT_MANAGER)
            };
            // Create myPOA with the right policies
            POA myPOA = rootPOA.create_POA(
                  "bank_servant_locator_poa",
                  rootPOA.the_POAManager(),
                  policies );
            // Create the servant locator servant
            // and get its reference
            ServantLocator sl =
                     new AccountManagerLocator()._this(orb);
            // Set the servant locator on our POA
            myPOA.set_servant_manager(sl);
            org.omg.CORBA.Object ref ;
            // Activate the POA manager
            rootPOA.the_POAManager().activate();
            // Generate the reference and write it out.
            // One for each Checking and Savings
            // account types .Note that we are not creating
            // any servants here and just manufacturing a
            // reference which is not yet backed by a servant.
            try {
              ref = myPOA.create_reference_with_id(
                      "CheckingAccountManager".getBytes(),
                      "IDL:Bank/AccountManager:1.0");
              // Write out checking object ID
              java.io.PrintWriter pw =
              new java.io.PrintWriter(
                        new java.io.FileWriter("cref.dat"));
              pw.println(orb.object_to_string(ref));
              pw.close();
              ref = myPOA.create_reference_with_id(
                      "SavingsAccountManager".getBytes(),
                      "IDL:Bank/AccountManager:1.0");
              // Write out savings object ID
              pw = new java.io.PrintWriter(
                  new java.io.FileWriter("sref.dat"));
              System.gc();
              pw.println(orb.object_to_string(ref));
              pw.close();
           } catch ( java.io.IOException e ){
              System.out.println(
                           "Error writing the IOR to file");
              return;
           }
           System.out.println("BankManager is ready.");
           // Wait for incoming requests
           orb.run();
        } catch (Exception e) {
           e.printStackTrace();
        }
     }
}

このサンプルのサーバントマネージャは，次のとおりです。

コードサンプル7-19　サーバントロケータのサンプルのサーバントマネージャ（C++）

// Servant Locator
class AccountManagerLocator :
      public PortableServer::ServantLocator {
   public:
      AccountManagerLocator (){}

      // preinvoke is very similar to ServantActivator 's
      // incarnate method but gets called every time a
      // request comes in unlike incarnate() which gets called
      // every time the POA does not find a servant in the
      // active object map
      virtual PortableServer::Servant preinvoke
            (const PortableServer::ObjectId& oid,
            PortableServer::POA_ptr adapter,
            const char* operation,
            PortableServer::ServantLocator::
                  Cookie& the_cookie) {
         CORBA::String_var s =
               PortableServer::ObjectId_to_string (oid);
         cout << "¥nAccountManagerLocator.preinvoke called
               with ID = " << s << endl;
         PortableServer::Servant servant;

         if ( VISPortable::vstricmp( (char *)s,
               "SavingsAccountManager" ) == 0 )
            //Create CheckingAccountManager Servant
            servant = new SavingsAccountManagerImpl;
         else if ( VISPortable::vstricmp( (char *)s,
               "CheckingAccountManager" ) == 0 )
         // Create CheckingAccountManager Servant
            servant = new CheckingAccountManagerImpl;
         else
            throw CORBA::OBJECT_NOT_EXIST();

         // Note also that we do not spawn of a thread to
         // explicitly deactivate an object unlike a servant
         // activator , this is because the POA itself calls
         // post invoke after the request is complete.In the
         // case of a servant activator the POA calls
         // etherealize() only if the object is deactivated
         // by calling poa->de_activate object or the POA
         // itself is destroyed.

         //return the servant
         return servant;
      }

   virtual void postinvoke (const PortableServer::ObjectId& oid,
         PortableServer::POA_ptr adapter,
         const char* operation,
         PortableServer::ServantLocator::Cookie the_cookie,
         PortableServer::Servant the_servant) {
      CORBA::String_var s =
            PortableServer::ObjectId_to_string (oid);
      cout << "¥nAccountManagerLocator.postinvoke called
            with ID = " << s << endl;
      delete the_servant;
   }
};

コードサンプル7-20　サーバントロケータのサンプルのサーバントマネージャ（Java）

import org.omg.PortableServer.*;
import org.omg.PortableServer.
                         ServantLocatorPackage.CookieHolder;
public class AccountManagerLocator extends
                                         ServantLocatorPOA {
   public Servant preinvoke (byte[ ] oid,POA adapter,
         java.lang.String operation,
         CookieHolder the_cookie) throws ForwardRequest {
      String accountType = new String(oid);
      System.out.println(
            "¥nAccountManagerLocator.
             preinvoke called with ID = " +
            accountType + "¥n");
      if ( accountType.equalsIgnoreCase
                                  ("SavingsAccountManager"))
         return new SavingsAccountManagerImpl();
      return new CheckingAccountManagerImpl();
   }
   public void postinvoke (byte[ ] oid,
         POA adapter,
         java.lang.String operation,
         java.lang.Object the_cookie,
         Servant the_servant) {
      System.out.println(
           "¥nAccountManagerLocator.postinvoke called
            with ID = " +
           new String(oid) + "¥n");
   }
}

7.6　POAマネージャによるPOA管理

POAマネージャは，POAの状態（リクエストを待ち行列に入れるか破棄するか）を管理し，POAを非活性化できます。各POAはPOAマネージャオブジェクトに対応します。POAマネージャは一つ以上のPOAを制御できます。

POAマネージャはPOAが生成されたときにそのPOAに対応づけられます。使用するPOAマネージャを指定することも，nullを指定して新しいPOAマネージャを生成することもできます。

コードサンプル7-21　POAおよびそのPOAマネージャに名前を付ける（C++）

PortableServer::POAManager_var rootManager =
      rootPOA->the_POAManager();
PortableServer::POA_var myPOA =
      rootPOA->create_POA(
            "bank_servant_locator_poa", rootManager, policies);

PortableServer::POA_var myPOA = rootPOA->create_POA(
      "bank_servant_locator_poa",
      null,
      policies );

コードサンプル7-22　POAおよびそのPOAマネージャに名前を付ける（Java）

POA myPOA = rootPOA.create_POA( "bank_agent_poa",
      rootPOA.the_POAManager(),
      policies );
POA myPOA = rootPOA.create_POA( "bank_agent_poa",
      null,
      policies );

POAマネージャは，対応するPOAがすべてデストラクトされると，自身もデストラクトされます。

POAマネージャには次に示す四つの状態があります。

待機

アクティブ

破棄

非アクティブ

これらの状態は，さらにPOAの状態を決定します。これらの状態について詳しく説明します。

7.6.1　カレントの状態の取得

POAマネージャのカレントの状態を取得するには，次のように使用します。

enum State{HOLDING, ACTIVE, DISCARDING, INACTIVE};
State get_state();

7.6.2　待機状態

デフォルトでは，POAマネージャは待機状態で生成されます。POAマネージャが待機状態のときは，POAはすべての入力リクエストを待ち行列に入れます。

POAマネージャが待機状態のときは，アダプタアクティベータを必要とするリクエストも待ち行列に入れられます。

POAマネージャの状態を待機状態に変えるには，次のように使用します。

void hold_requests(in boolean wait_for_completion)
   raises (AdapterInactive);

wait_for_completionはBooleanです。FALSEなら，このオペレーションは状態を待機状態に変更後すぐにリターンします。TRUEなら，このオペレーションは，状態変更より前に開始されたリクエストがすべて完了した場合か，POAマネージャが待機以外の状態に変更された場合だけリターンします。AdapterInactiveは，このオペレーションを呼び出す前にPOAマネージャが非アクティブな状態だった場合に発生する例外です。

注

現在非アクティブな状態のPOAマネージャは，待機状態に変更できません。

待ち行列に入れられたが開始されていないリクエストは，待機状態中は引き続き待ち行列に入れられます。

7.6.3　アクティブな状態

POAマネージャがアクティブな状態のときは，対応するPOAはリクエストを処理します。

POAマネージャをアクティブな状態に変更するには，次のように使用します。

void activate()
   raises (AdapterInactive);

AdapterInactiveは，このオペレーションを呼び出す前にPOAマネージャが非アクティブな状態だった場合に発生する例外です。

注

現在非アクティブな状態のPOAマネージャは，アクティブな状態に変更できません。

7.6.4　破棄状態

POAマネージャが破棄状態のときは，対応するPOAは，開始していないリクエストをすべて破棄します。さらに，対応するPOAに登録されたアダプタアクティベータは呼び出されません。この状態は，POAが受信するリクエストが多過ぎる場合に便利です。プログラマは，リクエストが破棄されたことと，リクエストを再送するようにクライアントに通知する必要があります。POAが受信するリクエストが多過ぎる理由とその時期を決定する固有の動作はありません。決定は，設定済みのスレッド監視に左右されます。

POAマネージャを破棄状態に変更するには，次のように使用します。

void discard_requests(in boolean wait_for_completion)
   raises (AdapterInactive);

wait_for_completionオプションはBooleanです。FALSEなら，このオペレーションは状態を破棄状態に変更後すぐにリターンします。TRUEなら，このオペレーションは，状態変更より前に開始されたリクエストがすべて完了した場合か，POAマネージャが破棄以外の状態に変更された場合だけリターンします。AdapterInactiveは，このオペレーションを呼び出す前にPOAマネージャが非アクティブな状態だった場合に発生する例外です。

注

現在非アクティブな状態のPOAマネージャは，破棄状態に変更できません。

7.6.5　非アクティブな状態

POAマネージャが非アクティブな状態のときは，対応するPOAは入力リクエストをすべて拒否します。この状態は，対応するPOAを終了しようとするときに使用します。

POAの終了後にリクエストを送信すると，クライアント側でPortableServer::POA::AdapterNonExistent例外またはCORBA::OBJECT_NOT_EXIST例外が発生する場合があります。

注

非アクティブな状態のPOAマネージャは，ほかの状態には変更できません。

POAマネージャを非アクティブな状態に変更するには，次のように使用します。

void deactivate(in boolean etherealize_objects, in boolean
   wait_for_completion) raises (AdapterInactive);

C++の場合

状態変更後，etherealize_objectsがTRUEなら，ServantRetentionPolicy::RETAINとRequestProcessingPolicy::USE_SERVANT_MANAGERを設定した対応するすべてのPOAは，すべてのアクティブなオブジェクトに対してサーバントマネージャのetherealizeを呼び出します。etherealize_objectsがFALSEなら，etherealizeは呼び出されません。wait_for_completionオプションはBooleanです。FALSEなら，このオペレーションは状態を非アクティブな状態に変更後すぐにリターンします。TRUEなら，このオペレーションは，状態変更より前に開始されたリクエストがすべて完了した場合か，etherealizeが対応するすべてのPOA（ServantRetentionPolicy::RETAINとRequest ProcessingPolicy::USE_SERVANT_MANAGERを設定したPOA）で呼び出された場合だけリターンします。AdapterInactiveは，このオペレーションを呼び出す前にPOAマネージャが非アクティブな状態だった場合に発生する例外です。

Javaの場合

状態変更後，etherealize_objectsがTRUEなら，ServantRetentionPolicy.RETAINとRequestProcessingPolicy.USE_SERVANT_MANAGERを設定した対応するすべてのPOAは，すべてのアクティブなオブジェクトに対してサーバントマネージャのetherealizeを呼び出します。etherealize_objectsがFALSEなら，etherealizeは呼び出されません。wait_for_completionオプションはBooleanです。FALSEなら，このオペレーションは状態を非アクティブな状態に変更後すぐにリターンします。TRUEなら，このオペレーションは，状態変更より前に開始されたリクエストがすべて完了した場合か，etherealizeが対応するすべてのPOA（ServantRetentionPolicy.RETAINとRequest ProcessingPolicy.USE_SERVANT_MANAGERを設定したPOA）で呼び出された場合だけリターンします。AdapterInactiveは，このオペレーションを呼び出す前にPOAマネージャが非アクティブな状態だった場合に発生する例外です。

7.7　監視プロパティとディスパッチプロパティの設定

POAは，以前BOAがサポートしていたリスナー機能とディスパッチャ機能をカバーするポリシーを持っていません。これらの機能を提供するために，VisiBroker固有ポリシー（ServerEnginePolicy）を使用できます。

サーバエンジンの内容は，次のとおりです。

ホスト名

プロキシホスト名

サーバコネクションマネージャまたはサーバコネクションマネージャのリスト

これらが互いにどのように適合するかを図7-3に示します。

図7‒3　サーバエンジンの概要

最も単純なケースでは，各POAが独自のサーバエンジンを一つずつ持ちます。この場合，別々のPOAに対するリクエストは別々のポートに到着します。一つのPOAに複数のサーバエンジンを持たせることもできます。このシナリオでは，一つのPOAは複数の入力ポートからのリクエストをサポートします。

POA間でサーバエンジンを共用できることに注意してください。サーバエンジンを共用する場合は，各POAは同じポートを監視します。（複数の）POAに対するリクエストが同じポートに到着しても，リクエストに埋め込まれたPOA名のおかげで，これらのリクエストは正確にディスパッチされます。このシナリオは，デフォルトサーバエンジンを使用して（POA生成時に新しいサーバエンジンを指定しないで）複数のPOAを生成するような場合に起こり得ます。

7.7.1　サーバエンジンプロパティの設定

次に示すプロパティは，デフォルトで使用するサーバエンジンを決定します。

vbroker.se.<server_engine_name>.host
vbroker.se.<server_engine_name>.proxyHost
vbroker.se.<server_engine_name>.scms

サーバエンジンポリシーを指定しないと，POAはサーバエンジン名として，iiop_tpを仮定し，次のデフォルト値を使用します。

vbroker.se.iiop_tp.host=null
vbroker.se.iiop_tp.proxyHost=null
vbroker.se.iiop_tp.scms=iiop

デフォルトのサーバエンジンポリシーを変更するには，vbroker.se.defaultプロパティを使用してその名前を入力し，新しいサーバエンジンのすべてのコンポーネントの値を定義します。次にサンプルを示します。

vbroker.se.default=abc,def
vbroker.se.abc.host=cob
vbroker.se.abc.proxyHost=null
vbroker.se.abc.scms=cobscm1, cobscm2
vbroker.se.def.host=gob
vbroker.se.def.proxyHost=null
vbroker.se.def.scms=gobscm1

7.7.2　サーバコネクションマネージャプロパティの設定

サーバコネクションマネージャは，マネージャ，リスナー，ディスパッチャという三つのプロパティグループで構成されます。

(1)　マネージャプロパティ

次に示すマネージャプロパティを設定できます。

vbroker.se.<server_engine>.scm.<server_connection_mgr>.manager.type

コネクションマネージャタイプを識別します。C++でサポートされているタイプはSocketおよびLocalです。Javaでは，Socketだけサポートされています。

vbroker.se.<server_engine>.scm.<server_connection_mgr>.manager.connectionMax

同時に確立される入力コネクションの最大許容数を定義します。デフォルト値は0で，これはコネクション数を制限しないという意味です。

vbroker.se.<server_engine>.scm.<server_connection_mgr>.manager.connectionMaxIdle

コネクションがシャットダウンされるまでのアイドル状態の最大秒数を定義します。デフォルト値は0で，これはタイムアウトがないという意味です。

最大アイドル時間の監視は，プロパティvbroker.orb.gcTimeoutの設定値（デフォルト30秒）の範囲の誤差があります。

(2)　リスナープロパティ

次に示すリスナープロパティを設定できます。

vbroker.se.<server_engine>.scm.<server_connection_mgr>.listener.type

リスナータイプを識別します。サポートされているのはIIOPだけです。

vbroker.se.<server_engine>.scm.<server_connection_mgr>.listener.port

コネクションマネージャが使用するこのサーバと対応するPOAの監視ポートを定義します。デフォルト値は0で，これはシステム（OS）によって自動的に割り当てられたポート番号を使用するという意味です。

vbroker.se.<server_engine>.scm.<server_connection_mgr>.listener.proxyPort

プロキシホスト名プロパティとともに使用するプロキシポート番号を指定します。デフォルト値は0で，これはシステム（OS）によって自動的に割り当てられたポート番号を使用するという意味です。

(3)　ディスパッチャプロパティ

次に示すディスパッチャプロパティを設定できます。

vbroker.se.<server_engine>.scm.<server_connection_mgr>.dispatcher.type

ディスパッチャタイプを識別します。現在サポートされているタイプはThreadPoolとThreadSessionだけです。

vbroker.se.<server_engine>.scm.<server_connection_mgr>.dispatcher.threadMax

タイプがThreadPoolに設定されている場合だけ使用します。

vbroker.se.<server_engine>.scm.<server_connection_mgr>.dispatcher.threadMaxIdle

タイプがThreadPoolに設定されている場合だけ使用します。

vbroker.se.<server_engine>.scm.<server_connection_mgr>.dispatcher.threadMin

タイプがThreadPoolに設定されている場合だけ使用します。

7.7.3　これらのプロパティはいつ使用するか

幾つかのサーバエンジンプロパティの変更が必要な場合はよくあります。これらのプロパティを変更する方法は必要事項によって異なります。例えば，ポート番号を変更したい場合は，次のようにします。

デフォルトのlistener.portプロパティを変更

新しいサーバエンジンを生成

デフォルトのlistener.portプロパティを変更することは最も単純な方法ですが，デフォルトのサーバエンジンを使用するすべてのPOAに影響を与えます。

特定のPOAのポート番号を変更したい場合は，新しいサーバエンジンを生成し，この新サーバエンジンのプロパティを定義し，さらにPOAの生成時に新サーバエンジンを参照する必要があります。「7.7.1　サーバエンジンプロパティの設定」ではサーバエンジンプロパティの更新方法を説明しました。次に示すコードの一部では，サーバエンジンのプロパティの定義方法とユーザ定義のサーバエンジンポリシーによるPOAの生成方法を示しています。

コードサンプル7-23　特定サーバエンジンによるPOAの生成（C++）

// static initialization
AccountRegistry AccountManagerImpl::_accounts;
int main(int argc, char* const* argv)
{
   try {
   // Initialize the orb
   CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
   // Get the property manager; notice the value returned
   // is not placed into a 'var' type.
   VISPropertyManager_ptr pm = orb->getPropertyManager();
   pm->addProperty("vbroker.se.mySe.host", "");
   pm->addProperty("vbroker.se.mySe.proxyHost", "");
   pm->addProperty("vbroker.se.mySe.scms", "scmlist");
   pm->addProperty("vbroker.se.mySe.scm.scmlist.manager
       .type", "Socket");
   pm->addProperty("vbroker.se.mySe.scm.scmlist.manager
       .connectionMax", 100UL);
   pm->addProperty("vbroker.se.mySe.scm.scmlist.manager
       .connectionMaxIdle", 300UL);
   pm->addProperty("vbroker.se.mySe.scm.scmlist.listener
       .type", "IIOP");
   pm->addProperty("vbroker.se.mySe.scm.scmlist.listener
       .port", 55000UL);
   pm->addProperty("vbroker.se.mySe.scm.scmlist.listener
       .proxyPort", 0UL);
   pm->addProperty("vbroker.se.mySe.scm.scmlist.dispatcher
       .type", "ThreadPool");
   pm->addProperty("vbroker.se.mySe.scm.scmlist.dispatcher
       .threadMax", 100UL);
   pm->addProperty("vbroker.se.mySe.scm.scmlist.dispatcher
       .threadMin", 5UL);
   pm->addProperty("vbroker.se.mySe.scm.scmlist.dispatcher
       .threadMaxIdle", 300UL);
   // Get a reference to the rootPOA
   CORBA::Object_var obj =
       orb->resolve_initial_references("RootPOA");
   PortableServer::POA_var rootPOA =
       PortableServer::POA::_narrow(obj);
   // Create the policies
   CORBA::Any_var seAny(new CORBA::Any);
   // The SERVER_ENGINE_POLICY_TYPE requires a sequence,
   // even if only one engine is being specified.
   CORBA::StringSequence_var engines =
      new CORBA::StringSequence(1UL);
   engines->length(1UL);
   engines[0UL] = CORBA::string_dup("mySe");
   seAny <<= engines;
   CORBA::PolicyList_var policies = new CORBA::PolicyList(2UL);
   policies->length(2UL);
   policies[0UL] = orb->create_policy(
      PortableServerExt::SERVER_ENGINE_POLICY_TYPE, seAny);
      policies[1Ul] = rootPOA->create_lifespan_policy
         (PortableServer::PERSISTENT);
   // Create our POA with our policies
   PortableServer::POAManager_var manager =
      rootPOA->the_POAManager();
   PortableServer::POA_var myPOA = rootPOA->create_POA(
         "bank_se_policy_poa", manager, policies);

   // Create the servant
   AccountManagerImpl* managerServant =
         new AccountManagerImpl();
   // Activate the servant
   PortableServer::ObjectId_var oid =
         PortableServer::string_to_ObjectId("BankManager");
   myPOA->activate_object_with_id(oid ,managerServant);
   // Obtain the reference
   CORBA::Object_var ref =
            myPOA->servant_to_reference(managerServant);
   CORBA::String_var string_ref =
            orb->object_to_string(ref.in());
   ofstream refFile("ref.dat");
   refFile << string_ref << endl;
   refFile.close();
   // Activate the POA manager
   manager->activate();
   // Wait for Incoming Requests
   cout << "AccountManager Server ready" << endl;
   orb->run();
   }
   catch(const CORBA::Exception& e) {
   cerr << e << endl;
   return (1);
   }
return (0);
}

コードサンプル7-24　特定サーバエンジンによるPOAの生成（Java）

// Server.java
import org.omg.PortableServer.*;
public class Server {
   public static void main(String[ ] args) {
      try {
      // Initialize the ORB.
      org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);
      // Get property manager
      com.inprise.vbroker.properties.PropertyManager pm =
           ((com.inprise.vbroker.orb.ORB)orb).
                                       getPropertyManager();
      pm.addProperty("vbroker.se.mySe.host", "");
      pm.addProperty("vbroker.se.mySe.proxyHost", "");
      pm.addProperty("vbroker.se.mySe.scms", "scmlist");
      pm.addProperty(
         "vbroker.se.mySe.scm.scmlist.manager.type",
         "Socket");
      pm.addProperty(
         "vbroker.se.mySe.scm.scmlist.manager.connectionMax",
          100);
      pm.addProperty(
         "vbroker.se.mySe.scm.scmlist.
          manager.connectionMaxIdle", 300);
      pm.addProperty(
        "vbroker.se.mySe.scm.scmlist.listener.giopVersion", "1.2");
      pm.addProperty(
        "vbroker.se.mySe.scm.scmlist.listener.type", "IIOP");
      pm.addProperty(
        "vbroker.se.mySe.scm.scmlist.listener.port", 55000);
      pm.addProperty(
        "vbroker.se.mySe.scm.scmlist.listener.proxyPort", 0);
      pm.addProperty(
         "vbroker.se.mySe.scm.scmlist.dispatcher.type",
         "ThreadPool");
      pm.addProperty(
         "vbroker.se.mySe.scm.scmlist.dispatcher.threadMax",
          100);
      pm.addProperty(
         "vbroker.se.mySe.scm.scmlist.dispatcher.threadMin",
          5);
      pm.addProperty(
         "vbroker.se.mySe.scm.scmlist.
          dispatcher.threadMaxIdle",300);
      // get a reference to the rootPOA
      POA rootPOA = POAHelper.narrow(
         orb.resolve_initial_references("RootPOA"));
      // Create our server engine policy
      org.omg.CORBA.Any seAny = orb.create_any();
      org.omg.CORBA.StringSequenceHelper.insert(
         seAny, new String[ ]{"mySe"});
      org.omg.CORBA.Policy sePolicy =
      orb.create_policy(
            com.inprise.vbroker.PortableServerExt.
            SERVER_ENGINE_POLICY_TYPE.value, seAny);
         // Create policies for our persistent POA
         org.omg.CORBA.Policy[ ] policies = {
         rootPOA.create_lifespan_policy(
             LifespanPolicyValue.PERSISTENT),sePolicy
      };
      // Create myPOA with the right policies
      POA myPOA = rootPOA.create_POA("bank_se_policy_poa",
            rootPOA.the_POAManager(),
            policies );
      // Create the servant
      AccountManagerImpl managerServant =
                                   new AccountManagerImpl();
      // Activate the servant
      myPOA.activate_object_with_id(
         "BankManager".getBytes(), managerServant);
      // Obtaining the reference
      org.omg.CORBA.Object ref = myPOA.servant_to_reference(
         managerServant);
      // Now write out the IOR
      try {
         java.io.PrintWriter pw =
               new java.io.PrintWriter(
                         new java.io.FileWriter("ior.dat"));
         pw.println(orb.object_to_string(ref));
         pw.close();
      } catch (java.io.IOException e ) {
         System.out.println(
                   "Error writing the IOR to file ior.dat");
         return;
      }
      // Activate the POA manager
      rootPOA.the_POAManager().activate();
      System.out.println(ref + "is ready.");
      // Wait for incoming requests
      orb.run();
      } catch (Exception e){
         e.printStackTrace();
      }
   }
}

7.8　アダプタアクティベータ

アダプタアクティベータはPOAと対応し，オンデマンドで子POAを生成する機能を提供します。これが実行できるのは，find_POAオペレーション中か，または特定の子POAの名前を指定したリクエストを受信したときです。

アダプタアクティベータは，子POA（またはその子の一つ）の名前を指定したリクエストを受信したり，活性化パラメタの値をTRUEに設定してfind_POAを呼び出したりしたときに，オンデマンドで子POAを生成する機能をPOAに提供します。実行開始時に必要なすべてのPOAを生成するアプリケーションサーバには，アダプタアクティベータを使用したり提供したりする必要はありません。アダプタアクティベータはリクエスト処理中にPOAを作成する場合だけ必要です。

POAからアダプタアクティベータへのリクエストの処理中は，新POA（または任意の子孫POA）が管理するオブジェクトへのリクエストはすべて待ち行列に入れられます。このシリアリゼーションによって，アダプタアクティベータは新POAにリクエストが配達される前に，そのPOAの初期化を完了できます。

アダプタアクティベータの使用例については，POAのサンプルプログラムadaptor_activatorを参照してください。

7.9　リクエストの処理

リクエストには，ターゲットのオジェクトのオブジェクトIDと，ターゲットのオブジェクトリファレンスを作成したPOAが含まれます。クライアントがリクエストを送信すると，VisiBroker ORBはまず適切なサーバを探すか，必要ならサーバを起動します。それからVisiBroker ORBはそのサーバ内の適切なPOAを探します。

VisiBroker ORBは適切なPOAを見つけると，リクエストをそのPOAに渡します。その時点でリクエストがどのように処理されるかは，POAのポリシーとオブジェクトの活性化状態によって異なります。オブジェクト活性化状態については，「7.4　オブジェクトの活性化」を参照してください。

C++でPOAにServantRetentionPolicy::RETAINが設定してあれば，またはJavaでPOAにServantRetentionPolicy.RETAINが設定してあれば，POAはアクティブオブジェクトマップを見て，リクエストに指定されたオブジェクトIDに対応するサーバントを探します。サーバントが存在するなら，POAはサーバントの適切なメソッドを呼び出します。

C++でPOAにServantRetentionPolicy::NON_RETAINまたはServantRetentionPolicy::RETAINが設定してあるか，JavaでPOAにServantRetentionPolicy.NON_RETAINまたはServantRetentionPolicy.RETAINが設定してある状態で，適切なサーバントが見つからない場合は，次のような結果になります。

POAにRequestProcessingPolicy::USE_DEFAULT_SERVANT（C++），またはRequestProcessingPolicy.USE_DEFAULT_SERVANT（Java）が設定してあれば，POAはデフォルトサーバントの適切なメソッドを呼び出します。

POAにRequestProcessingPolicy::USE_SERVANT_MANAGER（C++），またはRequestProcessingPolicy.USE_SERVANT_MANAGER（Java）が設定してあれば，POAはサーバントマネージャのincarnateまたはpreinvokeを呼び出します。

POAにRequestProcessingPolicy::USE_OBJECT_MAP_ONLY（C++），またはRequestProcessingPolicy.USE_OBJECT_MAP_ONLY（Java）を設定してあれば，例外が発生します。

サーバントマネージャが呼び出されたが，オブジェクトをインカネートできない場合には，サーバントマネージャがForwardRequest例外を発生させることができます。

8　スレッドとコネクションの管理

この章では，クライアントプログラムとオブジェクトインプリメンテーションでのマルチスレッドの使用について説明します。この章を読むと，Borland Enterprise Server VisiBrokerが使用するスレッドおよびコネクションモデルについて理解できます。

8.1　Borland Enterprise Server VisiBrokerでのスレッドの使用

スレッドとは，プロセス中の一つの連続した制御の流れのことです。スレッドは，基本的な部分をほかのスレッドと共用することによってオーバヘッドを減らせることからライトウェイトプロセスともいいます。スレッドは軽いので，一つのプロセス内部に多くのスレッドが存在できます。

マルチスレッドを使用すると，アプリケーション内に並行性がもたらされるので，性能が向上します。独立した幾つもの計算を同時に処理するスレッドを利用して，アプリケーションを効率的に構築できます。例えば，データベースシステムは，同時に複数のファイルオペレーションとネットワークオペレーションを実行しながら，多くのユーザの処理を進めることができます。複数のリクエストを非同期に処理させる一つの制御用のスレッドでソフトウェアを作成できますが，各リクエストを独立したシーケンスとして作成し，システムに異なるオペレーション間の同期処理をさせることによって，コードを単純化できます。

マルチスレッドは次の場合に役立ちます。

ほかの処理（ウィンドウ描画，文書の出力，マウスクリックへの応答，スプレッドシートの列計算，シグナル処理など）にお互いの処理が依存しないオペレーションのグループがある場合

データの排他処理がほとんど発生しそうにない場合（共用データの量は識別可能で少量である場合）

タスクをさまざまな処理に分けることができる場合。例えば，あるスレッドはシグナルを処理し，別のスレッドはユーザインタフェースを処理できる

8.2　Borland Enterprise Server VisiBrokerが提供するスレッドポリシー

Borland Enterprise Server VisiBrokerはスレッドプーリングとスレッドパーセッションという二つのスレッドポリシーを提供します。両モデルは基本的に次の点で異なります。

生成される状況

同じクライアントからの同時に発生したリクエストを処理する方法

スレッドを解放する時期とその方法

デフォルトのスレッドポリシーはスレッドプーリングポリシーです。スレッドパーセッションポリシーの設定およびスレッドプーリングのプロパティの変更については，「8.6　ディスパッチポリシーとプロパティの設定」を参照してください。

8.3　スレッドプーリングポリシー

サーバがスレッドプーリングポリシーを使用する場合，サーバはクライアントリクエストの処理用に割り当て可能なスレッドの最大数を定義します。ワーカスレッドがクライアントリクエストごとに割り当てられますが，それはその特定のリクエストの期間だけです。リクエストが完了すると，そのリクエストに割り当てられたワーカスレッドは，クライアントから続いて要求されるリクエストを処理するために再度割り当てができるように，利用できるスレッドのプールに入れられます。

このモデルを使用すると，スレッドはサーバオブジェクトに対するリクエストトラフィックの量に基づいて割り当てられます。つまり，サーバに対し同時に多くのリクエストをする非常にアクティブなクライアントはマルチスレッドによってサービスされ，各リクエストの迅速な実行が保証されるのに対し，それほどアクティブでないクライアントは一つのスレッドを共用でき，そのリクエストは即時にサービスを受けられます。その上，スレッドはデストラクトされるのではなく再利用され，複数のコネクションに割り当てることができるので，ワーカスレッドの生成およびデストラクトに対応するオーバヘッドは減少します。

Borland Enterprise Server VisiBrokerは，同時のクライアントリクエストの数に基づいてスレッドプール中のスレッド数を動的に割り当てることでシステム資源を節約します。クライアントが非常にアクティブになると，スレッドはそのニーズに合わせて割り当てられます。スレッドがアイドルのままなら，Borland Enterprise Server VisiBrokerは現在のクライアントリクエストを満たすだけのスレッドを残してスレッドを解放します。これによって，サーバのアクティブなスレッド数は常に最適な数に保たれます。

スレッドプールのサイズはサーバアクティビティに基づいて大きくなり，個々の分散システムのニーズに合わせて実行前または実行中に設定できます。スレッドプーリングで設定できる内容は，次のとおりです。

最大スレッド数および最小スレッド数

最大アイドル時間

クライアントリクエストを受信するたびに，そのリクエストを処理するためにスレッドプールからスレッドを割り当てようとします。これが最初のクライアントリクエストで，プールが空なら，スレッドが生成されます。同様に，すべてのスレッドがビジーなら，新しいスレッドが生成されてそのリクエストが処理されます。

サーバはクライアントリクエストを処理するために割り当て可能なスレッドの最大数を定義できます。利用できるスレッドがプール中になく，最大数のスレッドがすでに生成されている場合は，現在使用中のスレッドが解放されてプール中に戻されるまで，そのリクエストは待たされます。

スレッドプーリングはデフォルトのスレッドポリシーです。特に環境を設定する必要はありません。スレッドプーリングのプロパティを設定したい場合は，「8.6　ディスパッチポリシーとプロパティの設定」を参照してください。

図8‒1　スレッドのプールが利用できる

図8-1は，スレッドプーリングポリシーを使用したオブジェクトインプリメンテーションを示しています。その名が示すとおり，このポリシーではワーカスレッドをプールできます。

図8‒2　クライアントアプリケーション#1がリクエストを送信

図8-2では，クライアントアプリケーション#1がオブジェクトインプリメンテーションとのコネクションを確立して，リクエストの処理のためにスレッドが生成されます。スレッドプーリングでは，クライアントごとに一つのコネクションがあり，コネクションごとに一つのスレッドがあります。リクエストが入ってくると，ワーカスレッドはリクエストを受信します。そのワーカスレッドはもうプール中にはありません。

ワーカスレッドはスレッドプールから削除され，リクエストがあるかどうかを常に監視します。リクエストが入ってくると，そのワーカスレッドはリクエストを読み込んで，そのリクエストを適切なオブジェクトインプリメンテーションにディスパッチします。リクエストをディスパッチする前に，ワーカスレッドは次のリクエストの有無を監視するほかのワーカスレッドを一つ割り当てます。

図8‒3　クライアントアプリケーション#2がリクエストを送信

図8-3で示すように，クライアントアプリケーション#2が自身のコネクションを確立してリクエストを送信すると，第2のワーカスレッドが生成されます。現在はワーカスレッド3が入力リクエストの有無を監視しています。

図8‒4　クライアントアプリケーション#1が2番目のリクエストを送信

図8-4は，クライアントアプリケーション#1から2番目のリクエストが入ってくると，ワーカスレッド4を使用することを示しています。新しいリクエストの有無を監視するためにワーカスレッド5が生成されます。クライアントアプリケーション#1からさらにリクエストが入ってきたら，各リクエストを処理するためにワーカスレッドが次々に割り当てられます（各ワーカスレッドは，監視スレッドがリクエストを受信したあとに生成されます）。ワーカスレッドはそのタスクを完了すると，スレッドプールに戻され，クライアントからのリクエストを処理するために利用できる状態になります。

8.4　スレッドパーセッションポリシー

スレッドパーセッションポリシーでは，スレッドはクライアントおよびサーバのプロセス間のコネクションによって割り当てられます。サーバがスレッドパーセッションポリシーを選択すると，新しいクライアントがサーバに接続するたびに新しいスレッドが割り当てられます。個々のクライアントから受信したすべてのリクエストを処理するために，一つのスレッドが割り当てられます。このため，スレッドパーセッションはスレッドパーコネクションとも呼ばれます。クライアントがサーバとのコネクションを切断すると，スレッドはデストラクトされます。クライアントコネクションごとに割り当て可能なスレッドの最大数は，vbroker.se.iiop_ts.scm.iiop_ts.manager.connectionMaxプロパティの設定で制限できます。

図8‒5　スレッドパーセッションポリシーを使用したオブジェクトインプリメンテーション

図8-5は，スレッドパーセッションポリシーの使用を示しています。クライアントアプリケーション#1がオブジェクトインプリメンテーションとのコネクションを確立します。クライアントアプリケーション#2とオブジェクトインプリメンテーションの間には別のコネクションが存在します。クライアントアプリケーション#1からオブジェクトインプリメンテーションにリクエストが入ってくると，ワーカスレッドがそのリクエストを処理します。クライアントアプリケーション#2からリクエストが入ってくると，そのリクエストを処理するために別のワーカスレッドが割り当てられます。

図8‒6　同じクライアントから2番目のリクエストが入ってくる

図8-6は，クライアントアプリケーション#1から2番目のリクエストがオブジェクトインプリメンテーションに入ってきたところを示しています。リクエスト1を処理するのと同じスレッドがリクエスト2を処理します。このスレッドは，リクエスト1の処理を完了するまでリクエスト2を待たせます（スレッドパーセッションでは，同じクライアントからの複数のリクエストは並列処理しません）。リクエスト1が完了すると，スレッドはクライアントアプリケーション#1からのリクエスト2を処理できます。クライアントアプリケーション#1から複数のリクエストが入ってくることがありますが，リクエストは入ってきた順に処理され，追加スレッドがクライアントアプリケーション#1に割り当てられることはありません。

8.5　Borland Enterprise Server VisiBrokerが提供するコネクション管理

基本的に，Borland Enterprise Server VisiBrokerが提供するコネクション管理はサーバとのクライアントコネクションの数を最小にします。つまり，サーバプロセスごとにコネクションは一つだけあり，これが共有されます。すべてのクライアントリクエストは，たとえ別々のスレッドから発行されても，同じコネクションで多重化されます。さらに，解放されたクライアントコネクションは同じサーバとの以降の再コネクションのために再利用されるので，クライアントはサーバとの新しいコネクションのオーバヘッドを発生させないで済みます。

図8-7のシナリオでは，クライアントアプリケーションがサーバプロセスの二つのオブジェクトにバインドされています。それぞれのbind()メソッドは，サーバプロセス中の別々のオブジェクト用bind()メソッドであっても，サーバプロセスとの共通コネクションを共有します。

図8‒7　同じサーバプロセス中の二つのオブジェクトにバインド

サーバ上の一つのオブジェクトにバインドされたマルチスレッドを使用したクライアントのコネクションを図8-8に示します。

図8‒8　サーバプロセス中の一つのオブジェクトにバインド

図8-8で示すように，すべてのスレッドからのすべての呼び出しは，同じコネクションによってサービスを受けます。図8-8で示したシナリオの場合，使用する最も効率的なマルチスレッドモデルはスレッドプーリングモデル（デフォルト）です。このシナリオでスレッドパーセッションモデルを使用すると，クライアントアプリケーション中のすべてのスレッドからのすべてのリクエストを処理するためにサーバ上のスレッドが一つだけ割り当てられ，その結果，性能が低下してしまいます。

サーバへの，またはクライアントからのコネクションの最大数を設定できます。アイドルなコネクションは最大数に達したときに再利用されるので，資源を確実に節約できます。

8.6　ディスパッチポリシーとプロパティの設定

マルチスレッドのオブジェクトサーバ内の各POAは，スレッドパーセッションとスレッドプーリングという二つのディスパッチモデルから選択できます。ディスパッチポリシーを選択するには，ServerEngineのdispatcher.typeプロパティを設定してください。

vbroker.se.<srvr_eng_name>.scm.
    <srvr_connection_mngr_name>.dispatcher.type="ThreadPool"
vbroker.se.<srvr_eng_name>.scm.
 <srvr_connection_mngr_name>.dispatcher.type="ThreadSession"

これらのプロパティの詳細については，「7.7　監視プロパティとディスパッチプロパティの設定」，またはマニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「サーバ側スレッドセッションコネクションのプロパティ」および「サーバ側スレッドプールコネクションのプロパティ」の記述を参照してください。

8.6.1　スレッドプーリング

ThreadPool（スレッドプーリング）は，ServerEnginePolicyを指定しないでPOAを生成する場合のデフォルトのディスパッチポリシーです。

ThreadPoolに指定できるプロパティについては，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「サーバ側スレッドプールコネクションのプロパティ」および「サーバ側ローカルスレッドプールコネクションのプロパティ」を参照してください。

8.6.2　スレッドパーセッション

ディスパッチャタイプとしてThreadSessionを使用する場合は，se.defaultプロパティをiiop_tsに設定してください。

vbroker.se.default=iiop_ts

8.6.3　コーディングの考慮事項

VisiBroker ORBオブジェクトをインプリメントするサーバ内のコードは，すべてがスレッドセーフである必要があります。オブジェクトインプリメンテーション内のシステム全体にわたる資源にアクセスする場合は特に注意が必要です。例えば，スレッドセーフではないデータベースアクセスメソッドが多くあるとします。オブジェクトインプリメンテーションはこのような資源にアクセスを試みる前に，まず排他制御してその資源に対するアクセスをロックする必要があります。

オブジェクトへのシリアライズなアクセスが必要な場合は，ThreadPolicyの値にSINGLE_THREAD_MODELを設定してこのオブジェクトを活性化するPOAを生成する必要があります。

9　tie機能の使用

この章では，tie機能を使用して既存のC++およびJavaコードを分散オブジェクトシステムに組み込む方法について説明します。この章を読むと，デリゲータインプリメンテーションを生成したり，インプリメンテーション継承を提供したりできます。

9.1　tie機能の働き

通常，オブジェクトインプリメンテーションクラスは，idl2cppまたはidl2javaコンパイラによって生成されたサーバントクラスを継承します。また，サーバントクラスは，PortableServer.Servant::Servant（C++），org.omg.PortableServer.Servant（Java）を継承します。既存のクラスを変更してBorland Enterprise Server VisiBrokerサーバントクラスを継承するのが不便または不可能な場合は，tie機能が代替手段となります。

tie機能はオブジェクトサーバに，PortableServer::Servant（C++）またはorg.omg.PortableServer.Servant（Java）を継承するデリゲータインプリメンテーションクラスを提供します。デリゲータインプリメンテーションは独自のセマンティクスを持たないで，ただ受信したすべてのリクエストを，個別にインプリメントできる実インプリメンテーションクラスにデリゲート（委任）するだけです。実インプリメンテーションクラスは，PortableServer::Servant（C++），またはorg.omg.PortableServer.Servant（Java）を継承する必要はありません。

tie機能を使用することで，二つのファイルがIDLコンパイラから生成されます。

<interface_name>POATieは，すべてのIDL定義メソッドのインプリメンテーションをデリゲートまで遅延させます。デリゲートは<interface_name>Operationsインタフェースをインプリメントします。レガシーインプリメンテーションは，オペレーションインタフェースをインプリメントし，またリアルインプリメンテーションをデリゲートするために少しだけ継承できます。

<interface_name>Operationsは，オブジェクトインプリメンテーションがインプリメントしなければならないすべてのメソッドを定義します。このインタフェースは，tie機能を使用する場合に，対応する<interface_name>POATieクラスのデリゲートオブジェクトとして動作します。

9.2　サンプルプログラム

9.2.1　tie機能を使用したサンプルプログラムの格納場所

tie機能を使用したサンプルのBankは，Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/basic/bank_tie下に入っています。

9.2.2　tieテンプレートの考察（C++）

idl2cppコンパイラは，コードサンプル9-1に示すように_tie_Accountテンプレートクラスを自動的に生成します。POA_Bank_Account_tieクラスは，オブジェクトサーバが実体化して，AccountImplのインスタンスで初期化します。POA_Bank_Account_tieクラスは，受信するオペレーション要求すべてを実際のインプリメンテーションであるAccountImplに任せます。このサンプルでは，AccountImplクラスはPOA_Bank::Accountクラスを継承しません。

コードサンプル9-1　POA_Bank_Account_tieテンプレートの考察

. . .
template <class T> class POA_Bank_Account_tie :
      public POA_Bank::Account {
   private:
      CORBA::Boolean _rel;
      PortableServer::POA_ptr _poa;
      T *_ptr;
      POA_Bank_Account_tie(const POA_Bank_Account_tie&) {}
      void operator=(const POA_Bank_Account_tie&) {}

   public:
      POA_Bank_Account_tie (T& t): _ptr(&t), _poa(NULL),
            _rel((CORBA::Boolean)0) {}

      POA_Bank_Account_tie (T& t, PortableServer::POA_ptr poa):
            _ptr(&t),
            _poa(PortableServer::_duplicate(poa)),
            _rel((CORBA::Boolean)0) {}

      POA_Bank_Account_tie (T *p, CORBA::Boolean release = 1) :
            _ptr(p), _poa(NULL),_rel(release) {}

      POA_Bank_Account_tie (T *p, PortableServer::POA_ptr poa,
            CORBA::Boolean release = 1)
            : _ptr(p), _poa(PortableServer::_duplicate(poa)),
            _rel(release) {}

      virtual ~POA_Bank_Account_tie() {
         CORBA::release(_poa);
         if (_rel) {
            delete _ptr;
         }
      }

      T* _tied_object() { return _ptr; }

      void _tied_object(T& t) {
         if (_rel) {
         delete _ptr;
      }
      _ptr = &t;
      _rel = 0;
   }

   void _tied_object(T *p, CORBA::Boolean release=1) {
      if (_rel) {
         delete _ptr;
      }
      _ptr = p;
      _rel = release;
   }

   CORBA::Boolean _is_owner() { return _rel; }

   void _is_owner(CORBA::Boolean b) { _rel = b; }

   CORBA::Float balance() {
      return _ptr->balance();
   }

   PortableServer::POA_ptr _default_POA() {
      if ( !CORBA::is_nil(_poa) ) {
         return _poa;
      } else {
         return PortableServer_ServantBase::_default_POA();
      }
   }
};

9.2.3　_tie_Accountクラスを使用するためのサーバの変更（C++）

コードサンプル9-2に_tie_Accountクラスを使用する際に必要なServer.Cファイルの変更内容を示します。

コードサンプル9-2　_tieクラスを使用したサーバの例

#include "Bank_s.hh"
#include <math.h>
. . .
int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

      // get a reference to the rootPOA
      PortableServer::POA_var rootPOA =
            PortableServer::POA::_narrow(
            orb->resolve_initial_references("RootPOA"));

      CORBA::PolicyList policies;
      policies.length(1);
      policies[(CORBA::ULong)0] =
            rootPOA->create_lifespan_policy(
            PortableServer::PERSISTENT);

      // get the POA Manager
      PortableServer::POAManager_var poa_manager =
            rootPOA->the_POAManager();

      // Create myPOA with the right policies
      PortableServer::POA_var myPOA =
            rootPOA->create_POA("bank_agent_poa",
            poa_manager, policies);
      // Create the servant
      AccountManagerImpl managerServant(rootPOA);

      // Create the delegator
      POA_Bank_AccountManager_tie<AccountManagerImpl>
            tieServer(managerServant);

      // Decide on the ID for the servant
      PortableServer::ObjectId_var managerId =
            PortableServer::string_to_ObjectId("BankManager");

      // Activate the servant with the ID on myPOA
      myPOA->activate_object_with_id(managerId, &tieServer);

      // Activate the POA Manager
      poa_manager->activate();

      cout << myPOA->servant_to_reference(&tieServer) <<
            "is ready" << endl;

      // Wait for incoming requests
      orb->run();
   } catch(const CORBA::Exception& e) {
      cerr << e << endl;
      return 1;
   }
   return 0;
}

9.2.4　Serverクラスの変更（Java）

次のコードサンプルは，Serverクラスに加える変更を示します。AccountManagerPOATieのインスタンスを生成するための追加手順に注意してください。

コードサンプル9-3　bank_tieディレクトリのServer.javaファイル

import org.omg.PortableServer.*;
public class Server {
   public static void main(String[ ] args) {
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);
         // get a reference to the rootPOA
         POA rootPOA = POAHelper.narrow(
            orb.resolve_initial_references("RootPOA"));
         // Create policies for our persistent POA
         org.omg.CORBA.Policy[ ] policies = {
              rootPOA.create_lifespan_policy(
                LifespanPolicyValue.PERSISTENT)
         };
         // Create myPOA with the right policies
         POA myPOA = rootPOA.create_POA("bank_agent_poa",
              rootPOA.the_POAManager(), policies);
         // Create the tie which delegates
         //      to an instance of AccountManagerImpl
         Bank.AccountManagerPOATie tie =
              new Bank.AccountManagerPOATie(
                 new AccountManagerImpl(rootPOA));
         // Decide on the ID for the servant
         byte[ ] managerId = "BankManager".getBytes();
         // Activate the servant with the ID on myPOA
         myPOA.activate_object_with_id(managerId,tie);
         // Activate the POA manager
         rootPOA.the_POAManager().activate();
         System.out.println("Server is ready.");
         // Wait for incoming requests
         orb.run();
      } catch (Exception e){
         e.printStackTrace();
      }
   }
}

9.2.5　AccountManagerの変更（Java）

AccountManagerクラスに加える変更（サンプルbank_agentと比較して）は次のとおりです。

AccountManagerImplは，Bank.AccountManagerPOAをもう継承しません。

新しいAccountを生成する場合には，AccountPOATieも生成し，初期化します。

コードサンプル9-4　AccountManagerImplクラス

import org.omg.PortableServer.*;
import java.util.*;

public class AccountManagerImpl implements
                             Bank.AccountManagerOperations {
   public AccountManagerImpl(POA poa) {
      _accountPOA = poa;
   }
   public synchronized Bank.Account open(String name) {
      // Lookup the account in the account dictionary.
      Bank.Account account =
                          (Bank.Account)_accounts.get(name);
      // If there was no account in the dictionary,
      // create one.
      if (account == null) {
         // Make up the account's balance, between 0 and
         // 1000 dollars.
         float balance =
                Math.abs(_random.nextInt()) % 100000 / 100f;
         // Create an account tie
         // which delegate to an instance of AccountImpl
         Bank.AccountPOATie tie =
           new Bank.AccountPOATie(new AccountImpl(balance));
         try {
            // Activate it on the default POA
            // which is rootPOA for this servant
            account = Bank.AccountHelper.narrow(
                     _accountPOA.servant_to_reference(tie));
         }catch (Exception e){
            e.printStackTrace();
         }
         // Print out the new account.
         System.out.println(
              "Created " + name + "'s account: " + account);
         // Save the account in the account dictionary.
         _accounts.put(name, account);
      }
      // Return the account.
      return account;
   }
   private Dictionary _accounts = new Hashtable();
   private Random _random = new Random();
   private POA _accountPOA = null;
}

9.2.6　Accountクラスの変更（Java）

Accountクラスに加える変更（サンプルbank_agentと比較して）は，もうBank.AccountPOAを継承しなくするということだけです。

コードサンプル9-5　AccountImplクラス

// Server.java
public class AccountImpl implements Bank.AccountOperations {
   public AccountImpl(float balance) {
      _balance = balance;
   }
   public float balance() {
      return _balance;
   }
   private float _balance;
}

9.2.7　tieのサンプルプログラムの構築

「4.　Borland Enterprise Server VisiBrokerによるサンプルアプリケーションの開発」で説明した内容も，tie機能を実装するサンプルに流用できます。

第3編　クライアントの概念

10　クライアントの基本事項

この章では，クライアントプログラムがどのように分散オブジェクトにアクセスして使用するのかについて説明します。

10.1　VisiBroker ORBの初期化

ORB（Object Request Broker）はクライアントとサーバ間の通信リンクを提供します。クライアントがリクエストすると，VisiBroker ORBはオブジェクトインプリメンテーションを探して，リクエストをそのオブジェクトに渡し（必要ならオブジェクトを活性化して），クライアントに応答を返します。クライアントは，オブジェクトが同じマシンにあるのかネットワークのどこかにあるのかを意識しません。

注（Javaの場合）

VisiBroker ORBは，システムリソースを集中的に使用するため，一つのプロセスにつき一つのVisiBroker ORBのインスタンスだけを作成することをお勧めします。

VisiBroker ORBが実行する作業の大部分はプログラマに意識されませんが，クライアントプログラムは明示的にVisiBroker ORBを初期化しなければなりません。

マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「コマンドラインオプション」または「Borland Enterprise Server VisiBrokerプロパティ」の記述で説明しているVisiBroker ORBオプションをコマンドライン引数として指定できます。したがって，これらのオプションが確実に有効になるように，ORB_initにargcとargv（C++），またはORB.initにargs（Java）を渡す必要があります。コードサンプル10-1にVisiBroker ORBの初期化（C++），コードサンプル10-2にVisiBroker ORBの初期化（Java）を示します。

コードサンプル10-1　VisiBroker ORBの初期化（C++）

#include <fstream.h>
#include "Bank_c.hh"

int main(int argc, char* const* argv) {
   CORBA::ORB_var orb;
   CORBA::Float balance;
   try {
      // Initialize the ORB.
      orb = CORBA::ORB_init(argc, argv);
      . . .
    } catch {
      . . .
    }
}

コードサンプル10-2　VisiBroker ORBの初期化（Java）

public class Client {
   public static void main (String[ ] args) {
      org.omg.CORBA.ORB orb =
                         org.omg.CORBA.ORB.init(args, null);
      . . .
    }
}

10.2　オブジェクトへのバインド

クライアントプログラムは，オブジェクトのリファレンスを取得することによってリモートオブジェクトを使用します。オブジェクトリファレンスは，通常は静的<interface_name>::_bind()メソッド（C++），または<interface_name>Helperのbind()メソッド（Java）を使用して取得されます。VisiBroker ORBはオブジェクトをインプリメントするサーバを探してそのサーバとのコネクションを確立する，というようなオブジェクトリファレンス取得についての手順の大部分を隠します。

10.2.1　バインドプロセス中に行われる動作

サーバプログラムがcreate_POA()を実行すると，生成したPOAがスマートエージェントに登録されます。

この状態で，クライアントプログラムが静的bind()メソッドを呼び出した場合，VisiBroker ORBはプログラムのために幾つかの機能を実行し，スマートエージェントからオブジェクトインプリメンテーションの位置情報を得られます。クライアントとスマートエージェントの相互動作を図10-1に示します。

VisiBroker ORBは，リクエストされたインタフェースを提供するオブジェクトインプリメンテーションを探すためにスマートエージェントにコンタクトします。_bind()メソッド（C++）またはbind()メソッド（Java）の呼び出し時にオブジェクト名が指定されていたら，その名前はディレクトリサービス検索で使用します。「15.　オブジェクト活性化デーモンの使用」で説明するOAD（オブジェクト活性化デーモン）にサーバオブジェクトが登録されている場合は，OADを起動しておく必要があります。

オブジェクトインプリメンテーションが見つかると，VisiBroker ORBは見つけたオブジェクトインプリメンテーションとクライアントプログラム間のコネクション確立を試みます。

コネクションの確立が成功すると，VisiBroker ORBはプロキシオブジェクトを生成して，そのオブジェクトのリファレンスを返します。クライアントはサーバオブジェクトと相互動作するプロキシオブジェクトのメソッドを呼び出します。

図10‒1　クライアントとスマートエージェントの相互動作

注

クライアントプログラムがサーバクラスのコンストラクタを呼び出すことはありません。その代わり，静的_bind()メソッド（C++），または静的bind()メソッド（Java）呼び出しによってオブジェクトリファレンスを取得できます。

コードサンプル10-3　バインド呼び出しの例（C++）

. . .
PortableServer::ObjectId_var manager_id =
   PortableServer::string_to_ObjectId("BankManager");
Bank::AccountManager_var =
   Bank::AccountManager::_bind("/bank_agent_poa", manager_id);
. . .

コードサンプル10-4　バインド呼び出しの例（Java）

. . .
Bank.AccountManager manager =
   Bank.AccountManagerHelper.bind(orb,
               "/bank_agent_poa", "BankManager".getBytes());
. . .

10.3　オブジェクトのオペレーションの呼び出し

クライアントプログラムは，オブジェクトリファレンスを使用してオブジェクトのオペレーションを呼び出したりオブジェクトに含まれたデータを参照したりします。オブジェクトリファレンスのさまざまな操作方法は，「10.4　オブジェクトリファレンスの操作」で説明します。

コードサンプル10-5　オブジェクトリファレンスを使用したオペレーションの呼び出し（C++）

. . .
//  Invoke the balance operation.
   balance = account->balance();
   cout <<"Balance is $" << balance << endl;
. . .

コードサンプル10-6　オブジェクトリファレンスを使用したオペレーションの呼び出し（Java）

. . .
// Invoke the balance operation.
  System.out.println(
          "The balance in Account1: $" + account1.balance());
. . .

10.4　オブジェクトリファレンスの操作

静的_bind()メソッド（C++），またはbind()メソッド（Java）は，CORBAオブジェクトのリファレンスをクライアントプログラムに返します。クライアントプログラムは，オブジェクトリファレンスを使用することで，IDLインタフェース定義で定義されたオブジェクトのオペレーションを呼び出せます。さらに，オブジェクトの操作に使用できるCORBA::Objectクラス（C++），またはorg.omg.CORBA.Objectクラス（Java）からすべてのVisiBroker ORBオブジェクトを継承するメソッドもあります。

10.4.1　nilリファレンスのチェック（C++）

CORBAクラスのメソッドである次のis_nil()メソッドを使用して，オブジェクトリファレンスがnilであるかどうかを調べることができます。渡されたオブジェクトリファレンスがnilの場合，このメソッドは1を返します。オブジェクトリファレンスがnilでない場合，0を返します。

コードサンプル10-7　nilオブジェクトリファレンスをチェックするメソッド

class CORBA {
   . . .
   static Boolean is_nil(CORBA::Object_ptr obj);
   . . .
};

10.4.2　nilリファレンスの取得（C++）

CORBA::Objectクラスの_nil()メソッドを使用してnilオブジェクトリファレンスを取得できます。この関数は，Object_ptrにキャストするNULL値を返します。

コードサンプル10-8　nilリファレンスを取得するメソッド

class Object {
   . . .
   static CORBA::Object_ptr _nil();
   . . .
};

10.4.3　オブジェクトリファレンスの複製（C++）

ユーザのクライアントプログラムが_duplicate()メソッドを起動すると，オブジェクトリファレンスのリファレンスカウントが一つずつ増え，同じオブジェクトリファレンスが返されます。クライアントプログラムは_duplicate()メソッドを使用して，オブジェクトリファレンスのリファレンスカウントを増やせるので，リファレンスはデータ構造に格納されるか，またはパラメタとして渡されます。リファレンスカウントが増えると，オブジェクトリファレンスに対応するメモリはリファレンスカウントがゼロになるまで解放されません。

IDLコンパイラは，指定の各オブジェクトインタフェースに対して_duplicate()メソッドを生成します。_duplicate()メソッドは，汎用Object_ptrを受け付けて返します。

コードサンプル10-9　オブジェクトリファレンスを二重化するメソッド

class Object {
   . . .
   static CORBA::Object_ptr _duplicate(CORBA::Object_ptr obj);
   . . .
};

注

POAやORBのオブジェクトは，リファレンスカウントをサポートしていないため，_duplicate()メソッドを使用しても無効です。

10.4.4　オブジェクトリファレンスの解放（C++）

オブジェクトリファレンスが必要でなくなったら，オブジェクトリファレンスを解放する必要があります。オブジェクトリファレンスを解放する方法の一つとして，CORBA::Objectクラスの_release()メソッドを起動する方法があります。

注

必ず_release()メソッドを使用してください。オブジェクトリファレンスに対してoperator deleteを使用しないでください。

コードサンプル10-10　オブジェクトリファレンスの解放

class CORBA {
   class Object {
      . . .
      void _release();
      . . .
   };
};

また，CORBAクラスのrelease()メソッドを使用することもできます。この関数はCORBAとの互換性を提供します。

コードサンプル10-11　オブジェクトリファレンスを解放するCORBAメソッド

class CORBA {
   . . .
   static void release(Object_ptr);
   . . .
};

10.4.5　リファレンスカウントの取得（C++）

各オブジェクトリファレンスにはリファレンスカウントがあり，これを使用してリファレンスが何回複製されたかを調べることができます。_bind()メソッドを起動してオブジェクトリファレンスを最初に取得する場合，リファレンスカウントは1に設定されます。オブジェクトリファレンスを_release()メソッドで解放するたびに，リファレンスカウントを1ずつ減らします。リファレンスカウントが0になったら，Borland Enterprise Server VisiBrokerはオブジェクトリファレンスを自動的に削除します。コードサンプル10-12にリファレンスカウントを返す_ref_count()メソッドを示します。

注

リモートクライアントがオブジェクトリファレンスを二重化したり解放したりする際，サーバのオブジェクトリファレンスカウントは影響を受けません。

コードサンプル10-12　リファレンスカウントを取得するメソッド

class Object {
   . . .
   CORBA::Long _ref_count() const;
   . . .
};

10.4.6　リファレンスの文字列への変換

Borland Enterprise Server VisiBroker では，オブジェクトリファレンスを文字列に変換したり，文字列をオブジェクトリファレンスに戻したりするメソッドをVisiBroker ORBクラスで提供しています。CORBAの仕様では，オブジェクトリファレンスを文字列に変換するプロセスを文字列化，文字列をオブジェクトリファレンスに戻すプロセスを非文字列化と呼びます。

文字列化と非文字列化のメソッドを表10-1に示します。

表10‒1　文字列化と非文字列化のメソッド

メソッド

説明

object_to_string

オブジェクトリファレンスを文字列に変換します。

string_to_object

文字列をオブジェクトリファレンスに戻します。

クライアントプログラムは，object_to_stringメソッドを使用してオブジェクトリファレンスを文字列に変換し，それをほかのクライアントプログラムに渡します。すると2番目のクライアントは，string_to_objectメソッドを使用してオブジェクトリファレンスを非文字列化し，オブジェクトへの明示的なバインドを必要としないでオブジェクトリファレンスを使用できます。

注1（C++の場合）

object_to_stringの呼び出し元は，返された文字列を，CORBA::string_free()メソッドで解放する必要があります。

注2

VisiBroker ORBまたはPOAのようなローカルスコープのオブジェクトリファレンスは文字列化できません。文字列化しようとすると，マイナーコード4のMARSHAL例外が発生します。

10.4.7　オブジェクト名とインタフェース名の取得

オブジェクト名とインタフェース名，およびオブジェクトリファレンスに対応するリポジトリIDの取得に使用できるObjectクラスが提供するメソッドを，表10-2に示します。インタフェースリポジトリについては，「16.　インタフェースリポジトリの使用」を参照してください。

注

静的_bind()メソッドの呼び出し時にオブジェクト名を指定しなかった場合，結果として生じたオブジェクトリファレンスを指定して_object_name()メソッドを呼び出すとNULL（C++）またはnull（Java）が返されます。

表10‒2　インタフェース名とオブジェクト名を取得するメソッド

メソッド

説明

_interface_name（C++の場合）

このオブジェクトのインタフェース名を返します。

_object_name

このオブジェクトの名前を返します。

_repository_id

リポジトリのタイプ識別子を返します。

10.4.8　オブジェクトリファレンスのタイプの判定

C++の場合

ユーザは_hash()メソッドを使用して，オブジェクトリファレンスのハッシュ値を取得できます。この値は一意であるとは限りませんが，オブジェクトリファレンスのライフスパンを通して一定の値を保ちます。そして，この値はハッシュテーブルに格納されます。

オブジェクトリファレンスが特定のタイプかどうかは，_is_a()メソッド（C++およびJava）を使用してチェックできます。最初に，_repository_id()メソッド（C++およびJava）を使用して，チェックしたいタイプのリポジトリIDを取得する必要があります。このメソッドは，オブジェクトが_repository_id()メソッドで表されるタイプのインスタンスか，サブタイプであれば，1（C++）またはtrue（Java）を返します。オブジェクトが指定のタイプでなければ，0（C++）またはfalse（Java）を返します。このとき，タイプを判定するためにリモート呼び出しが必要な場合があるので注意してください。

注（Javaの場合）

instanceofキーワードはランタイムタイプの判定には使用できません。

二つのオブジェクトリファレンスが同じオブジェクトインプリメンテーションを参照するかどうかのチェックには，_is_equivalent()メソッド（C++およびJava）を使用します。このメソッドは，これらのオブジェクトリファレンスが等しければ1（C++）またはtrue（Java）を返します。オブジェクトリファレンスが異なるなら，このメソッドは0（C++）またはfalse（Java）を返しますが，オブジェクトリファレンスが二つの異なったオブジェクトであるということを示すとは限りません。これはライトウェイトメソッドであり，サーバオブジェクトとの実際の通信は必要としません。オブジェクトリファレンスのタイプを判定するメソッドを表10-3に示します。

表10‒3　オブジェクトリファレンスのタイプを判定するメソッド

メソッド

説明

_hash（C++の場合）

オブジェクトリファレンスのハッシュ値を返します。

_is_a

指定されたインタフェースをオブジェクトがインプリメントするかどうかを判定します。

_is_equivalent

二つのオブジェクトが同じインタフェースインプリメンテーションを参照するなら，1（C++）またはtrue（Java）を返します。

10.4.9　バインドされたオブジェクトの位置と状態の判定

オブジェクトリファレンスが有効であれば，クライアントプログラムは，_is_bound()メソッド（C++およびJava）を使用してオブジェクトがバインドされているかどうかを判定できます。このメソッドは，オブジェクトがバインドされていれば1（C++）またはtrue（Java）を，バインドされていなければ0（C++）またはfalse（Java）を返します。

_is_local()メソッドは，クライアントプログラムとオブジェクトインプリメンテーションが同じプロセスまたはアドレス空間に常駐する場合に1（C++）またはtrue（Java）を返します。

_is_remote()メソッドは，クライアントプログラムとオブジェクトインプリメンテーションが同じホストにあるかどうかに関係なく，異なるプロセスに存在する場合に1（C++）またはtrue（Java）を返します。

オブジェクトリファレンスの位置と状態を判定するメソッドを表10-4に示します。

表10‒4　オブジェクトリファレンスの位置と状態を判定するメソッド

メソッド

説明

_is_bound

このオブジェクトに対してコネクションが現在アクティブなら，1（C++）またはtrue（Java）を返します。

_is_local

このオブジェクトがローカルアドレス空間でインプリメントされたなら，1（C++）またはtrue（Java）を返します。

_is_remote

このオブジェクトのインプリメンテーションがローカルアドレス空間になければ，1（C++）またはtrue（Java）を返します。

注

メソッドが呼び出されたプロセスと同じプロセスにオブジェクトがある場合，_is_local()は1（C++）またはtrue（Java）を返します。

10.4.10　non_existentオブジェクトのチェック（C++）

_non_existent()メソッドを使用して，オブジェクトリファレンスに対応するオブジェクトインプリメンテーションがまだ存在するかどうかを判定できます。実際には，このメソッドはオブジェクトをpingして，オブジェクトがまだ存在するかどうかを判定し，存在すればFALSEを返します。

10.4.11　オブジェクトリファレンスのナロウイング

オブジェクトリファレンスのタイプを一般的なスーパータイプから特定のサブタイプに変更するプロセスをナロウイングといいます。

注1（C++の場合）

_narrow()メソッドは，新しいC++オブジェクトを構築し，そのオブジェクトのポインタを返します。オブジェクトがもう必要なければ，_narrow()メソッドで返されたオブジェクトリファレンスを解放する必要があります。

注2（Javaの場合）

ナロウイングにJavaキャスティング機能は使用できません。

Borland Enterprise Server VisiBrokerでは，オブジェクトのnarrow()メソッドを使用してナロウイングができるように，それぞれのオブジェクトインタフェースのタイプグラフを保持しています。

C++の場合

narrowメソッドが要求したタイプにオブジェクトをナロウできないと判定した場合，NULLを返します。

Javaの場合

ナロウイングが失敗すると，IDL例外であるCORBA::BAD_PARAM例外が返されます。それはオブジェクトリファレンスがリクエストされたタイプをサポートしていないためです。

コードサンプル10-13　AccountManager用に生成されたnarrowメソッド（C++）

Bank::AccountManager_ptr
Bank::AccountManager::_narrow(CORBA::Object * _obj) {
                   :
}

コードサンプル10-14　AccountManager用に生成されたnarrowメソッド（Java）

public abstract class AccountManagerHelper {
   . . .
   public static Bank.AccountManager narrow (
                               org.omg.CORBA.Object object){
      . . .
   }
   . . .
}

10.4.12　オブジェクトリファレンスのワイドニング

オブジェクトリファレンスのタイプをスーパータイプに変換することをワイドニングといいます。コードサンプル10-15および10-16では，C++およびJavaのそれぞれのAccountポインタのObjectポインタへのワイドニング例を示します。AccountクラスはObjectクラスを継承するので，ポインタacctをObjectポインタとしてキャストできます。

コードサンプル10-15　オブジェクトリファレンスのワイドニング（C++）

. . .
Account *acct;
CORBA::Object *obj;
acct = Account::_bind();
obj = (CORBA::Object *)acct; . . .

コードサンプル10-16　オブジェクトリファレンスのワイドニング（Java）

. . .
Account account;
org.omg.CORBA.Object obj;
account = AccountHelper.bind();
obj = (org.omg.CORBA.Object)account;
. . .

10.5　Quality of Serviceの使用

QoS（Quality of Service）は，各ポリシーを利用してクライアントアプリケーションとそれに接続されているサーバとのコネクションの定義と管理を行います。

10.5.1　QoSの概要

QoSポリシー管理は，次のオペレーションによって行われます。

VisiBroker ORBレベルポリシーは局所に限定されたPolicyManagerによって処理され，このPolicyManagerを介して，ポリシーを設定したり現在のPolicyを見たりできます。VisiBroker ORBレベルで設定されたポリシーはシステムのデフォルトを変更します。

スレッドレベルポリシーはPolicyCurrentを介して設定され，PolicyCurrentにはスレッドレベルでのPolicyの変更の表示と設定を行うオペレーションが含まれます。スレッドレベルで設定されたポリシーは，システムデフォルトとVisiBroker ORBレベルで設定された値を変更します。

ベースオブジェクトインタフェースのQoSオペレーションにアクセスすることによって，オブジェクトレベルポリシーが適用できます。オブジェクトレベルで適用されたポリシーは，システムデフォルトとVisiBroker ORBレベルまたはスレッドレベルで設定された値を変更します。

(1)　ポリシーの変更および有効ポリシー

有効ポリシーとは，適用できるすべてのポリシーの変更が完了し，最終的にリクエストに適用されるポリシーのことです。有効ポリシーは，有効な変更の内容とIORに指定されたポリシーを比較することで決定します。有効ポリシーは，有効な変更の内容とIORに指定されたPolicyとの共通部分です。共通部分がない場合，org.omg.CORBA.INV_POLICY例外が発生します。

10.5.2　QoSインタフェース

QoSポリシーの取得と設定には，次のインタフェースを使用します。

(1)　CORBA::Objectまたはorg.omg.CORBA.Object

CORBA::Object（C++）およびorg.omg.CORBA.Object（Java）に含まれる次のメソッドは，有効ポリシーの取得やポリシーの変更の取得または設定に使用します。

_get_policyは，オブジェクトリファレンスの有効ポリシーを返します。

_set_policy_overrideは，オブジェクトレベルの，リクエストされたポリシーの変更のリストで新しいオブジェクトリファレンスを返します。

(2)　CORBA::Objectまたはcom.inprise.vbroker.CORBA.Object（Borland）

Javaの場合

このインタフェースを使用するには，org.omg.CORBA.Objectをcom.inprise.vbroker.CORBA.Objectにキャストする必要があります。このインタフェースはorg.omg.CORBA.Objectから派生するので，org.omg.CORBA.Objectで定義されたメソッドに加えて次のメソッドが使用できます。

C++の場合

次のメソッドは，メソッド名の先頭の"_"がない名称で提供されています。

_get_client_policyは，サーバ側ポリシーとの共通部分以外のオブジェクトリファレンスの有効Policyを返します。有効な変更は，指定された変更をオブジェクトレベル，スレッドレベル，VisiBroker ORBレベルの順でチェックすることで取得されます。リクエストされたPolicyTypeの変更を指定していない場合，PolicyTypeのシステムデフォルト値が使用されます。

_get_policy_overridesは，オブジェクトレベルで設定された指定ポリシータイプのPolicyを変更するリストを返します。指定されたシーケンスが空の場合，オブジェクトレベルのすべての変更が返されます。オブジェクトレベルで変更されたPolicyTypeがなければ，空シーケンスが返されます。

_validate_connectionは，オブジェクトに対して現在有効なポリシーが呼び出しを許可するかどうかに基づいて，boolean値を返します。オブジェクトリファレンスがバインドされていなければ，バインディングが発生します。オブジェクトリファレンスがすでにバインドされているが，現在のポリシーの変更作業が変更された場合，またはバインディングがもう有効でない場合は，RebindPolicyの変更の設定には関係なくリバインドが試みられます。現在の有効ポリシーがINV_POLICY例外を発生させる場合は，リターン値はfalseです。現在の有効ポリシーに不具合があれば，不具合なポリシーを記載したPolicyListタイプのシーケンスが返されます。

(3)　CORBA::PolicyManagerまたはorg.omg.CORBA.PolicyManager

PolicyManagerは，VisiBroker ORBレベルのPolicyの変更の取得と設定を行うメソッドを提供するインタフェースです。

get_policy_overridesは，リクエストされたPolicyTypesの変更されたすべてのポリシーのPolicyListシーケンスを返します。指定されたシーケンスが空の場合，カレントコンテキストレベルのすべてについてPolicyの変更が返されます。リクエストされたPolicyTypesが一つもターゲットのPolicyManagerで変更されていなければ，空のシーケンスが返されます。

set_policy_overridesは，リクエストされたPolicyの変更のリストでカレントの変更作業を変更します。第1入力パラメタのpoliciesは，Policyオブジェクトのリファレンスのシーケンスです。SetOverrideType型（C++）またはorg.omg.CORBA.SetOverrideType型（Java）の第2パラメタであるset_addは，ADD_OVERRIDEを使用してこれらのポリシーをPolicyManagerにすでに存在するほかの変更に追加するか，またはSET_OVERRIDESを使用して，変更を含まないPolicyManagerにこれらのポリシーを追加するかを示します。ポリシーの空シーケンスとSET_OVERRIDESモードを指定してset_policy_overridesを呼び出すと，すべての変更をPolicyManagerから削除します。クライアントに適用できないポリシーを変更しようとすると，NO_PERMISSION例外（C++）またはorg.omg.CORBA.NO_PERMISSION例外（Java）が発生します。指定されたPolicyManagerが，リクエストが原因で不一致な状態になった場合には，ポリシーの変更や追加は行われないで，InvalidPolicies例外が発生します。

(4)　CORBA::PolicyCurrentまたはorg.omg.CORBA.PolicyCurrent

PolicyCurrentインタフェースは，新たなメソッドを追加しないでPolicyManagerから派生します。このインタフェースは，スレッドレベルで変更されたポリシーへのアクセスを提供します。resolve_initial_references（C++）またはorg.omg.CORBA.ORB.resolve_initial_references（Java）で"PolicyCurrent"という識別子を指定して実行することでスレッドのPolicyCurrentのリファレンスを取得できます。

(5)　QoSExt::DeferBindPolicyまたはcom.inprise.vbroker.QoSExt.DeferBindPolicy

DeferBindPolicyは，リモートオブジェクトが最初に作成されたときにVisiBroker ORBがそのオブジェクトとのコンタクトを試みるか，最初の呼び出しが行われるまでこのコンタクトを遅延させるかを決定します。DeferBindPolicyの値はtrueとfalseです。DeferBindPolicyをtrueに設定すると，バインディングインスタンスの最初の呼び出しまですべてのバインドが遅延されます。デフォルト値はfalseです。

クライアントオブジェクトを生成し，DeferBindPolicyをtrueに設定すると，最初の呼び出しまでサーバ起動を延期できます。以前このオプションは，生成されたヘルパークラスのバインドメソッドのオプションとして提供されていました。

コードサンプル10-17は，DeferBindPolicy（C++）を作成して，VisiBroker ORB上にそのポリシーを設定する例を示します。コードサンプル10-18は，DeferBindPolicy（Java）を作成して，VisiBroker ORB上にそのポリシー，スレッド，およびオブジェクトレベルを設定するサンプルを示します。

コードサンプル10-17　DeferBindPolicyの作成（C++）

//Initialize the flag and references
 CORBA::Boolean deferMode = (CORBA::Boolean)1;
 CORBA::Any policy_value;
 policy_value << = CORBA::Any::from_boolean(deferMode);

 CORBA::Policy_var policy =
    orb->create_policy(QoSExt::DEFER_BIND_POLICY_TYPE,policy_value);

 CORBA::PolicyList policies;
 policies.length(1);
 policies [0] = CORBA::Policy::_duplicate(policy);

//Get a reference to the thread manager
 CORBA::Object_var obj =
   orb->resolve_initial_references("ORBPolicyManager");
 CORBA::PolicyManager_var orb_mgr =
   CORBA::PolicyManager::_narrow(obj);

//Set the policy on the ORB level
 orb_mgr->set_policy_overrides(policies,CORBA::SET_OVERRIDE);

コードサンプル10-18　DeferBindPolicyの作成（Java）

次のサンプルではDeferBindPolicyを作成して，VisiBroker ORB上にそのポリシー，スレッド，およびオブジェクトレベルを設定します。

//Initialize the flag and the references
 boolean deferMode = true;
 Any policyValue = orb.create_any();
 policyValue.insert_boolean(deferMode);

 Policy policies =
 orb.create_policy(DEFER_BIND_POLICY_TYPE.value,policyValue);

//Get a reference to the thread manager
   PolicyManager orbManager =
     PolicyManagerHelper.narrow(
       orb.resolve_initial_references("ORBPolicyManager"));

//Set the policy on the ORB level
 orbManager.set_policy_overrides(new Policy[ ] {policies},
 SetOverrideType.SET_OVERRIDE);

//Get the binding method
  byte[ ] managerId =="BankManager".getBytes();
  Bank.AccountManager manager =
    Bank.AccountManagerHelper.bind(orb,"/qos_poa",managerId);

(6)　QoSExt::ExclusiveConnectionPolicyまたはcom.inprise.vbroker.QoSExt.ExclusiveConnectionPolicy

ExclusiveConnectionPolicyはBorland Enterprise Server VisiBroker固有のポリシーであり，指定のサーバオブジェクトへの排他（非共用）コネクションを設定できます。このポリシーにboolean値（trueまたはfalse）を割り当てます。ポリシーがfalseの場合，既存のコネクションが存在すれば，既存のコネクションを使用（共用）します。既存のコネクションが存在しない場合は，新しいコネクションを作成します。デフォルト値はfalseです。

このポリシーはVisiBroker 3.xのObject._clone()と同じ機能を提供します。

examples/vbe/QoS_policies/qos/CloneClient.javaサンプルで，排他および非排他コネクションの設定方法の例を示します。

(7)　QoSExt::RelativeConnectionTimeoutPolicyまたはcom.inprise.vbroker.QoSExt.RelativeConnectionTimeoutPolicy

RelativeConnectionTimeoutPolicyは，使用できる終端のどれかを使用してオブジェクトへの接続をリトライする場合のタイムアウトを指定します。タイムアウトの状態は，ファイアウォール（オブジェクトに接続する唯一の方法がHTTPトンネルである）で保護されたオブジェクトで発生しやすくなります。

コードサンプル10-19　RelativeConnectionTimeoutPolicyの作成（Java）

次のコードはRelativeConnectionTimeoutPolicyの作成方法を示します。

   Any connTimeoutPolicyValue =orb.create_any();

   // Input is in 100s of Nanoseconds.
   // To specify a value of 20 seconds,
   // use 20 *10 ^7 nanoseconds as input

   int connTimeout =20;

   connTimeoutPolicyValue.insert_ulonglong(connTimeout *10000000);
   org.omg.CORBA.Policy ctoPolicy =
         orb.create_policy(RELATIVE_CONN_TIMEOUT_POLICY_TYPE.value,
               connTimeoutPolicyValue);
   PolicyManager orbManager =PolicyManagerHelper.narrow (
               orb.resolve_initial_references("ORBPolicyManager"));

   orbManager.set_policy_overrides(new Policy[ ] ¥{ctoPolicy ¥},
          SetOverrideType.SET_OVERRIDE);

(8)　Messaging::RebindPolicyまたはorg.omg.Messaging.RebindPolicy

RebindPolicyは，リバインディング時にクライアントの動作を定義するためにMessaging::RebindMode型の値（C++）またはorg.omg.Messaging.RebindMode型の値（Java）を読み込みます。RebindPolicyはクライアント側だけに設定されます。RebindPolicyには，コネクション切断，オブジェクト転送リクエスト，オブジェクト障害などの場合に動作を決定する六つの値のうち一つを指定できます。現在サポートされている値は，次のとおりです。

Messaging::TRANSPARENT（C++）またはorg.omg.Messaging.TRANSPARENT（Java）は，リモートリクエスト時に，VisiBroker ORBがオブジェクト転送および必要なリコネクションを透過的に処理します。コードサンプル10-20では，TRANSPARENT型のRebindPolicy（Java）を作成して，VisiBroker ORBでそのポリシー，スレッド，およびオブジェクトレベルを設定します。

Messaging::NO_REBIND（C++）またはorg.omg.Messaging.NO_REBIND（Java）は，リモートリクエスト時に，クローズしたコネクションの再オープンをVisiBroker ORBが透過的に処理できるようにしますが，クライアントが想定している有効QoSポリシーの変更の原因となる透過的なオブジェクト転送はしません。RebindModeをNO_REBINDに設定すると，明示的なリバインドだけが許可されます。

Messaging::NO_RECONNECT（C++）またはorg.omg.Messaging.NO_RECONNECT（Java）は，VisiBroker ORBがオブジェクト転送やクローズしたコネクションの再オープンを透過的に処理しないようにします。RebindModeをNO_RECONNECTに設定した場合は，明示的にリバインドとリコネクトをする必要があります。

QoSExt::VB_TRANSPARENT（C++）またはcom.inprise.vbroker.QoSExt.VB_TRANSPARENTはデフォルトポリシーです。これは，明示的なバインディングと暗黙的なバインディングの双方による透過的バインディングを許可することで，TRANSPARENTの機能を継承します。VB_TRANSPARENTは，VisiBroker 3.xのオブジェクトフェールオーバーインプリメンテーションとの互換性を持つように設計されています。

QoSExt::VB_NOTIFY_REBIND（C++）またはcom.inprise.vbroker.QoSExt.VB_NOTIFY_REBIND（Java）は，リバインドが必要な場合に例外を発生させます。クライアントはこの例外をキャッチして，2回目の呼び出しでバインドします。

QoSExt::VB_NO_REBIND（C++）またはcom.inprise.vbroker.QoSExt.VB_NO_REBIND（Java）は，オブジェクト障害後osagentを使用してほかのオブジェクト呼び出しを有効にしません。これは，クライアントVisiBroker ORBが同じサーバへのクローズしたコネクションを再びオープンすることだけができるようになります。オブジェクトフォワーディングはできません。

注1

クライアントの有効ポリシーがVB_TRANSPARENTで，かつクライアントが状態データを保持しているサーバとともに動作中の場合，VB_TRANSPARENTは，クライアントにサーバの変更を気づかせることなくクライアントを新しいサーバに接続できます。元のサーバが保持していた状態データは失われます。

注2（C++の場合）

NO_REBINDまたはNO_RECONNECTの場合，CORBA::Objectクラスの_validate_connectionを呼び出すことによって，クローズしたコネクションの再オープンや転送が明示的に許可されることがあります。

表10-5に，異なるRebindMode型の動作を示します。

表10‒5　RebindModeポリシー

RebindMode型

同じオブジェクトへのクローズしたコネクションの再確立

オブジェクト転送の可否

オブジェクトフェールオーバーの可否※

NO_RECONNECT

行わないで，REBIND例外を発生させます。

不可。REBIND例外を発生させます。

不可。

NO_REBIND

行います。

ポリシーが一致すれば可。

それ以外は，不可。REBIND例外を発生させます。

不可。

TRANSPARENT

行います。

可。

不可。

VB_NO_REBIND

行います。

不可。行わないで，例外を発生させます。

不可。行わないで，例外を発生させます。

VB_NOTIFY_REBIND

行います。

可。

可。障害検出後，VB_NOTIFY_REBINDは例外を発生させてから，以降のリクエストでosagentを使用してほかのオブジェクト呼び出しを試みます。

VB_TRANSPARENT

行います。

可。

透過的に可。

注※　通信障害またはオブジェクト障害でフェールオーバーできない場合は，適切なCORBA例外が発生します。

コードサンプル10-20　TRANSPARENT型のRebindPolicyの作成

次のサンプルでは，TRANSPARENT型のRebindPolicyを作成して，VisiBroker ORBでそのポリシー，スレッド，およびオブジェクトレベルを設定します。

Any policyValue=orb.create_any();
RebindModeHelper.insert(policyValue,
             org.omg.Messaging.TRANSPARENT.value);
Policy myRebindPolicy =orb.create_policy(
                REBIND_POLICY_TYPE.value,policyValue);

//get a reference to the ORB policy manager
org.omg.CORBA.PolicyManager manager;

try {
  manager =
      PolicyManagerHelper.narrow(orb.resolve_initial_references
                      ("ORBPolicyManager"));
}
catch(org.omg.CORBA.ORBPackage.InvalidName e){}

//get a reference to the per-thread manager
org.omg.CORBA.PolicyManager current;
try {
   current=PolicyManagerHelper.narrow(orb.resolve_initial_references
                      ("PolicyCurrent"));
}
catch(org.omg.CORBA.ORBPackage.InvalidName e){}

//set the policy on the orb level
try{
   manager.set_policy_overrides(myRebindPolicy,
                                  SetOverrideType.SET_OVERRIDE);
}
catch (InvalidPolicies e){}

//set the policy on the Thread level
try{
   current.set_policy_overrides(myRebindPolicy,
                                  SetOverrideType.SET_OVERRIDE);
}
catch (InvalidPolicies e){}

//set the policy on the object level:
org.omg.CORBA.Object oldObjectReference=bind(...);
org.omg.CORBA.Object newObjectReference=oldObjectReference._set_policy_override
         (myRebindPolicy,SetOverrideType.SET_OVERRIDE);

QoSポリシーと型の詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「QoSインタフェースとクラス」の記述，およびCORBA 2.5仕様のメッセージングについての記述を参照してください。

(9)　Messaging::RelativeRequestTimeoutPolicyまたはorg.omg.CORBA.Messaging.RelativeRequestTimeoutPolicy

RelativeRequestTimeoutPolicyは，Requestまたはその応答Replyが渡される相対的な時間を示します。この時間が過ぎると，Requestはキャンセルされます。このポリシーは同期および非同期の両方の呼び出しに適用されます。リクエストは指定のタイムアウト時間内に完了するものと仮定するので，Replyがタイムアウトによって破棄されることはありません。タイムアウト値は100ナノ秒単位で指定されます。

コードサンプル10-21　RelativeRequestTimeoutPolicyの作成

次のサンプルでは，RelativeRequestTimeoutPolicyの作成方法を示します。

//Specify the timeout in 100s of Nanoseconds
//To set a timeout of 20 secs,set 20 *10 ^7 nanoseconds

int reqTimeout =20;
RelativeRequestTimeoutPolicyImpl relReq =
       new RelativeRequestTimeoutPolicyImpl(reqTimeout *10000000);
 Any policyValue =orb.create_any();¥par
 RelativeRequestTimeoutPolicyHelper.insert(policyValue,
                  (RelativeRequestTimeoutPolicy)relReq);

//set the RelativeRequestTimeoutPolicy
org.omg.CORBA.Policy reqPolicy =orb.create_policy(
        RELATIVE_REQ_TIMEOUT_POLICY_TYPE.value,policyValue);
 PolicyManager orbManager =PolicyManagerHelper.narrow(
                  orb.resolve_initial_references("ORBPolicyManager"))
orbManager.set_policy_overrides(new Policy[ ]
              SetOverrideType.SET_OVERRIDE);

(10)　Messaging::RelativeRoundTripTimeoutPolicyまたはorg.omg.CORBA.Messaging.RelativeRoundtripTimeoutPolicy

RelativeRoundtripTimeoutPolicyは，Requestまたはその該当するReplyが渡される相対的な時間を指定します。このタイムアウトが過ぎても応答が渡されなかった場合，Requestはキャンセルされます。また，Requestがすでに渡されており，Replyがターゲットから返されると，Replyはこの時間が過ぎたら破棄されます。このポリシーは同期および非同期の両方の呼び出しに適用されます。タイムアウト値は100ナノ秒単位で指定します。

コードサンプル10-22　RelativeRoundTripTimeoutPolicyの作成

次のサンプルでは，RelativeRoundTripTimeoutPolicyの作成方法を示します。

//Specify the timeout in 100s of Nanoseconds
//To set a timeout of 90 secs,set 90 *10 ^7 nanosecs

int rttTimeout =20;
RelativeRoundtripTimeoutPolicyImpl relRtt =new
        RelativeRoundtripTimeoutPolicyImpl(rttTimeout *10000000);
Any policyValue =orb.create_any();
          RelativeRoundtripTimeoutPolicyHelper.insert(policyValue,
                   (RelativeRoundtripTimeoutPolicy)relRtt);

//set the RelativeRoundtripTimeoutPolicy

org.omg.CORBA.Policy rttPolicy =orb.create_policy(
          RELATIVE_RT_TIMEOUT_POLICY_TYPE.value,policyValue);
PolicyManager orbManager =PolicyManagerHelper.narrow(
          orb.resolve_initial_references("ORBPolicyManager"));
orbManager.set_policy_overrides(new Policy[ ]
            SetOverrideType.SET_OVERRIDE);

(11)　Messaging::SyncScopePolicyまたはorg.omg.CORBA.Messaging.SyncScopePolicy

SyncScopePolicyは，ターゲットに関するリクエストの同期レベルを定義します。SyncScope型の値は，一方向オペレーションの動作を制御するために，SyncScopePolicyとともに使用されます。

SyncScopePolicyのデフォルトは，SYNC_WITH_TRANSPORTです。

注

アプリケーションは，VisiBroker ORBインプリメンテーションのポータビリティを確保するために，明示的にVisiBroker ORBレベルのSyncScopePolicyを設定する必要があります。SyncScopePolicyのインスタンスが作成される場合，Messaging::SyncScope型の値はCORBA::ORB::create_policyに渡されます。このポリシーは，クライアント側の変更だけ適用できます。

10.5.3　QoS例外

CORBA::INV_POLICY（C++）またはorg.omg.CORBA.INV_POLICY（Java）は，Policyの変更の間に不具合があると発生します。

CORBA::REBIND（C++）またはorg.omg.CORBA.REBIND（Java）は，RebindPolicyの値がNO_REBIND，NO_RECONNECT，VB_NOTIFY_REBINDのどれかであり，バインドされたオブジェクトリファレンスの呼び出しの結果としてオブジェクトフォワードまたはロケーションフォワードメッセージが出力されると発生します。

CORBA::PolicyError（C++）またはorg.omg.CORBA. PolicyError（Java）は，リクエストされたPolicyがサポートされていない場合に発生します。

CORBA::InvalidPolicies（C++）またはorg.omg.CORBA.InvalidPolicies（Java）は，オペレーションをPolicyListシーケンスに渡すと発生します。例外本体に含まれるのは，ポリシーがカレントのスコープ内ですでに変更されているためか，またはリクエストされたほかのポリシーと一緒であると有効にならないために有効ではないシーケンスのポリシーです。

第4編　ツールとサービス

11　IDLの使用

この章では，CORBAのIDL（インタフェース記述言語）の使用方法について説明します。

11.1　IDLとは

IDLはリモートオブジェクトがインプリメントしているインタフェースを記述する記述言語です（プログラム言語ではありません）。IDL内では，インタフェースの名称やそれぞれの属性名とメソッド名などを定義できます。IDLファイルを生成すれば，IDLコンパイラを使用してスタブファイルやサーバスケルトンファイルをC++またはJavaプログラム言語で生成できます。

OMGはこのような言語マッピングの仕様を規定しています。Borland Enterprise Server VisiBrokerはOMGが規定したマッピング仕様に従っています。言語マッピングについての情報はこのマニュアルには記載していません。言語マッピングの詳細については，OMG Webサイトにアクセスしてください。

11.2　IDLコンパイラのコード生成方法

IDLを使用して，クライアントプログラムが使用するオブジェクトインタフェースを定義してください。idl2cppおよびidl2javaコンパイラは，このインタフェース定義を使用してコードを生成します。

idl2cppおよびidl2javaコンパイラの構文の詳しい使い方については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「idl2cpp」および「idl2java」の記述を参照してください。

11.2.1　IDLの指定例

インタフェース定義は，オブジェクトの名前と，オブジェクトが提供するすべてのメソッドの名前を定義します。各メソッドには，メソッドに渡すパラメタ，パラメタの型，およびパラメタが入力用，出力用，入出力用のどれなのかを指定します。IDLサンプル11-1は，exampleという名前のオブジェクトのIDL仕様を示しています。exampleオブジェクトは，op1という一つのメソッドだけを所有しています。

IDLサンプル11-1　IDL指定の例

// IDL specification for the example object
interface example {
   long op1 (in char x, out short y);
};

%TPDIR%¥idlディレクトリのorb.idlや，CosTransactions.idlなどorb.idlをインクルードするIDLファイルをidl2javaまたはidl2cppでコンパイルした場合に次の警告メッセージが出力されます。この警告メッセージはトランザクション処理などの実行時には影響を与えません。

(warning)::CORBA::Environment declared ("orb.idl", line 28) but never defined
(warning)(references to it will be permitted, but no code will be generated for this definition)

11.3　生成されたコードの考察

IDLコンパイラは前述のIDLサンプルから幾つかのファイルを生成します。

_exampleStub.javaはクライアント側のexampleオブジェクトのスタブコードです。

example.javaはexampleインタフェース宣言です。

exampleHelper.javaは，exampleインタフェースのユーティリティ機能とサポート機能を定義するexampleHelperクラスを宣言します。

exampleHolder.javaは，outパラメタとinoutパラメタを渡すためのホルダを提供するexampleHolderクラスを宣言します。

exampleOperations.javaはexampleインタフェースでメソッドを定義し，クライアント側とサーバ側の両方で使用されます。また，tie機能を提供するためにtieクラスと一緒に動作します。

examplePOA.javaは，サーバ側のexampleオブジェクトのスケルトンコード（インプリメンテーションベースコード）を格納します。

examplePOATie.javaは，tie機能を使用してサーバ側のexampleオブジェクトをインプリメントする場合に使用するクラスを格納します。

11.3.1　_<interface_name>Stub.java

idl2javaコンパイラによって，ユーザ定義型ごとにスタブクラスが生成されます。これは，<interface_name>インタフェースをインプリメントするクライアント側で実体化されるクラスです。

コードサンプル11-1　スタブクラスコードの例（Java）

public class exampleStub extends
               com.inprise.vbroker.CORBA.portable.ObjectImpl
       implements example {
   final public static java.lang.Class _opsClass =
                                    exampleOperations.class;
   public java.lang.String[ ] ids (){
      . . .
   }
   public int op1 (char x, org.omg.CORBA.ShortHolder y){
      . . .
}

11.3.2　<interface_name>.java

<interface_name>.javaファイルは，各IDLインタフェース用に生成されたJavaインタフェースです。これはIDLインタフェース定義を，適切なJavaインタフェースにマッピングするためのものです。このインタフェースは，クライアントとサーバスケルトンの両方によってインプリメントされます。

コードサンプル11-2　インタフェース宣言コードの例（Java）

public interface example extends
                           com.inprise.vbroker.CORBA.Object,
      exampleOperations,
      org.omg.CORBA.portable.IDLEntity {
}

11.3.3　<interface_name>Helper.java

idl2javaによって，ユーザ定義型ごとにヘルパークラスが生成されます。ヘルパークラスは，生成されたJavaインタフェースのさまざまな静的メソッドを持つfinalクラスです。

コードサンプル11-3　ヘルパークラスコードの例（Java）

public final class exampleHelper {
   public static example narrow (
                            final org.omg.CORBA.Object obj){
      . . .
   }
   public static example unchecked_narrow (
                                  org.omg.CORBA.Object obj){
      . . .
   }
   public static example bind (org.omg.CORBA.ORB orb){
   . . .
   }
   public static example bind (
               org.omg.CORBA.ORB orb, java.lang.String name){
   . . .
   }
   public static example bind (
         org.omg.CORBA.ORB orb, java.lang.String name,
         java.lang.String host,
         com.inprise.vbroker.CORBA.BindOptions _options){
       . . .
   }
   public static example bind (
         org.omg.CORBA.ORB orb, java.lang.String fullPoaName,
         byte[ ] oid){
       . . .
   }
   public static example bind (org.omg.CORBA.ORB orb,
         java.lang.String fullPoaName, byte[ ] oid,
         java.lang.String host,
         com.inprise.vbroker.CORBA.BindOptions _options){
       . . .
   }
   public java.lang.Object read_Object (
          final org.omg.CORBA.portable.InputStream istream){
       . . .
   }
   public void write_Object (
          final org.omg.CORBA.portable.OutputStream ostream,
          final java.lang.Object obj){
       . . .
   }
   public java.lang.String get_id (){
       . . .
   }
   public org.omg.CORBA.TypeCode get_type (){
       . . .
   }
   public static example read (
           final org.omg.CORBA.portable.InputStream _input){
       . . .
   }
   public static void write (
          final org.omg.CORBA.portable.OutputStream _output,
   final example value){
       . . .
   }
   public static void insert (
           final org.omg.CORBA.Any any, final example value){
       . . .
   }
   public static example extract (final org.omg.CORBA.Any any){
       . . .
   }
   public static org.omg.CORBA.TypeCode type (){
       . . .
   }
   public static java.lang.String id (){
       . . .
   }
}

11.3.4　<interface_name>Holder.java

idl2javaコンパイラによって，ユーザ定義型ごとにホルダークラスが生成されます。これは，outパラメタとinoutパラメタとして渡される場合，<interface_name>インタフェースをサポートするオブジェクトをラッピングするオブジェクトのクラスを提供します。

コードサンプル11-4　ホルダークラスの例（Java）

public final class exampleHolder implements
                         org.omg.CORBA.portable.Streamable {
   public foo.example value;
   public exampleHolder (){
   }
   public exampleHolder (final foo.example _vis_value){
      . . .
   }
   public void _read (
            final org.omg.CORBA.portable.InputStream input){
      . . .
   }
   public void _write (
          final org.omg.CORBA.portable.OutputStream output){
      . . .
   }
   public org.omg.CORBA.TypeCode _type (){
      . . .
   }
}

11.3.5　<interface_name>Operations.java

IDL宣言で定義されたすべてのメソッドを含むidl2javaコンパイラによって，ユーザ定義型ごとにオペレーションクラスが生成されます。

コードサンプル11-5　オペレーションコードの例（Java）

public interface exampleOperations {
   public int op1 (char x, org.omg.CORBA.ShortHolder y);
}

11.3.6　<interface_name>POA.java

<interface_name>POA.javaファイルはインタフェースのサーバ側のスケルトンです。このファイルはinパラメタをアンマーシャルしてからオブジェクトインプリメンテーションに渡し，リターン値と（あれば）outパラメタをマーシャルし直します。

コードサンプル11-6　ExamplePOA.javaファイル（Java）

public abstract class examplePOA extends
                   org.omg.PortableServer.Servant implements
    org.omg.CORBA.portable.InvokeHandler, exampleOperations {
   public example _this (){
   . . .
   }
   public example _this (org.omg.CORBA.ORB orb){
   . . .
   }
   public java.lang.String[ ] _all_interfaces (
                       final org.omg.PortableServer.POA poa,
      . . .
   }
   public org.omg.CORBA.portable.OutputStream _invoke (
        java.lang.String opName,
        org.omg.CORBA.portable.InputStream _input,
        org.omg.CORBA.portable.ResponseHandler handler){
      . . .
   }
   public static org.omg.CORBA.portable.OutputStream _invoke (
      exampleOperations _self,
      int _method_id, org.omg.CORBA.portable.InputStream _input,
      org.omg.CORBA.portable.ResponseHandler _handler){
      . . .
   }
}

11.3.7　<interface_name>POATie.java

<interface_name>POATie.javaファイルは，<interface_name>インタフェースのデリゲータインプリメンテーションです。すべてのオペレーションのデリゲート先である<interface_name>Operationsクラスをインプリメントするインプリメンテーションクラスのインスタンスで，tieクラスの各インスタンスを初期化する必要があります。

コードサンプル11-7　Example POATieファイル（Java）

public class examplePOATie extends examplePOA {
   public examplePOATie (final exampleOperations _delegate){
      . . .
   }
   public examplePOATie (final exampleOperations _delegate,
   final org.omg.PortableServer.POA _poa){
      . . .
   }
   public exampleOperations _delegate (){
      . . .
   }
   public void _delegate (final exampleOperations delegate){
      . . .
   }
   public org.omg.PortableServer.POA _default_POA (){
      . . .
   }
   public int op1 (char x, org.omg.CORBA.ShortHolder y){
      . . .
   }
}

11.3.8　クライアント用に生成されたコードの考察（C++）

コードサンプル11-8に，IDLコンパイラ（IDLサンプル11-1）が二つのクライアントファイルexample_c.hhとexample_c.ccをどのように生成するかを示します。この二つのファイルはクライアントが使用するexampleクラスを提供します。規則でIDLコンパイラが生成するファイルには必ず.ccまたは.hhという拡張子が付けられ，ユーザが自分で作成したファイルと区別できるようになっています。ファイルに別の拡張子を付けたければファイル生成の規則を変えることもできます。規則を変える方法については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「idl2cpp」の記述を参照してください。

注

IDLコンパイラが生成したファイルの内容は変更しないでください。

コードサンプル11-8　example_c.hh生成ファイルの生成クラス例（C++）

class example : public virtual CORBA_Object {
   protected:
      example() {}
      example(const example&) {}
public:
   virtual ~example() {}
   static  const CORBA::TypeInfo *_desc();
   virtual const CORBA::TypeInfo *_type_info() const;
   virtual void *_safe_narrow(const CORBA::TypeInfo& ) const;
   static CORBA::Object*_factory();
   example_ptr _this();
   static example_ptr _duplicate(example_ptr _obj)
               { /* . . . */ }
   static example_ptr _nil() { /* . . . */ }
   static example_ptr _narrow(CORBA::Object* _obj);
   static example_ptr _clone(example_ptr _obj)
               { /* . . . */ }
   static example_ptr _bind(
      const char *_object_name = NULL,
      const char *_host_name = NULL,
      const CORBA::BindOptions* _opt = NULL,
      CORBA::ORB_ptr _orb = NULL);
   static example_ptr _bind(
      const char *_poa_name,
      const CORBA::OctetSequence& _id,
      const char *_host_name = NULL,
      const CORBA::BindOptions* _opt = NULL,
      CORBA::ORB_ptr _orb = NULL);
   virtual CORBA::Long op1(CORBA::Char _x, CORBA::Short_out _y);
};

11.3.9　IDLコンパイラが生成するメソッド（スタブ）

コードサンプル11-8ではIDLコンパイラが生成するop1メソッドを，ほかの幾つかのメソッドと一緒に示しました。op1メソッドはスタブとも呼ばれます。それはクライアントプログラムがこのメソッドを起動すると，インタフェースリクエストと引数を実際にメッセージにパッケージ化し，そのメッセージをオブジェクトインプリメンテーションに送信し，応答を待ち，その応答をデコードし，結果をユーザのプログラムに返すためです。

exampleクラスは，CORBA::Objectクラスから派生するので使用できる継承されたメソッドが幾つかあります。

11.3.10　ポインタタイプ<interface_name>_ptr定義

IDLコンパイラは，常にポインタタイプ定義を提供します。コードサンプル11-9にexampleクラスのタイプ定義を示します。

コードサンプル11-9　example_c.hh生成ファイルの_ptrタイプ（C++）

typedef example *example_ptr;

11.3.11　自動メモリ管理<interface_name>_varクラス

IDLコンパイラは，example_varという名前のクラスも生成します。このクラスはexample_ptrの代わりに使用できます。example_varクラスは動的に割り当てられたオブジェクトリファレンスに対応するメモリを自動的に管理します。example_varオブジェクトが削除されると，example_ptrに対応するオブジェクトが解放されます。example_varオブジェクトが新しい値を割り当てられると，example_ptrによってポイントされた古いオブジェクトリファレンスは，割り当て後に解放されます。キャスティング演算子も提供されており，これによってexample_varをタイプexample_ptrに割り当てることができます。

コードサンプル11-10　example_c.hh生成ファイルのexample_varクラス（C++）

class example_var : public CORBA::_var {
   . . .
   public:
      static example_ptr _duplicate(example_ptr);
      static void _release(example_ptr);
      example_var();
      example_var(example_ptr);
      example_var(const example_var &);
      ~example_var();
      example_var& operator=(example_ptr);
      example_var& operator=(const example_var& _var)
                              { /* . . . */ }
      operator example* () const { return _ptr; }
      . . .
};

表11-1に，_varクラスのメソッドを説明します。

表11‒1　_varクラスのメソッド

メソッド

説明

example_var()

_ptrをNULLに初期化するコンストラクタ。

example_var (example_ptr ptr)

渡された引数に_ptrを初期化したオブジェクトを作成するコンストラクタ。varはデストラクト時に_ptrでrelease()メソッドを起動します。_ptrのリファレンスカウントが0になると，そのオブジェクトは削除されます。

example_var(const example_var& var)

パラメタvarとして渡されたオブジェクトのコピーを作成し，_ptrを新しくコピーされたオブジェクトにポイントするコンストラクタ。

~example()

_ptrがポイントするオブジェクトで_release()メソッドを一度起動するデストラクタ。

operator=(example_ptr p)

_ptrがポイントするオブジェクトで_release()メソッドを起動し，pを_ptrに格納する代入演算子。

operator=(const example_ptr p)

_ptrがポイントするオブジェクトで_release()メソッドを起動し，pの_duplicate()メソッドを_ptrに格納する代入演算子。

example_ptr operator->()

該当するオブジェクトに格納された_ptrを返します。この演算子は，該当するオブジェクトが正しく初期化されるまで呼び出してはいけません。

11.4　サーバ用に生成されたコードの考察（C++）

コードサンプル11-11に，IDLコンパイラがexample_s.hhとexample_s.ccという二つのサーバファイルを生成する方法を示します。この二つのファイルはPOA_exampleクラスを提供します。POA_exampleクラスは，インプリメンテーションクラスを派生するためにサーバが使用します。POA_exampleクラスは，PortableServer_ServantBaseクラスから派生します。

注

IDLコンパイラが生成したファイルの内容は変更しないでください。

コードサンプル11-11　example_s.hh生成ファイルのクラス例

class POA_example : public virtual PortableServer_ServantBase {
   protected:
      POA_example(){}
      virtual ~POA_example(){}
public:
   static const CORBA::TypeInfo _skel_info;
   virtual const CORBA::TypeInfo *_type_info() const;
   example_ptr _this();
   virtual void *_safe_narrow(const CORBA::TypeInfo& ) const;
   static POA_example * _narrow(
         PortableServer_ServantBase *_obj);
   // The following operations need to be implemented
   virtual CORBA::Long op1(
         CORBA::Char _x, CORBA::Short_out _y) = 0;
   // Skeleton Operations implemented automatically
   static void _op1(void *_obj, CORBA::MarshalInBuffer &_istrm,
   const char *_oper, VISReplyHandler& handler);
};

11.4.1　IDLコンパイラが生成するメソッド（スケルトン）

IDLサンプル11-1に示すIDL仕様で宣言されたop1メソッドは，_op1メソッドで生成されることに注意してください。POA_exampleクラスは，op1という名前の純仮想メソッドを宣言します。POA_exampleから派生したインプリメンテーションクラスは，このメソッドのインプリメンテーションを提供する必要があります。

POA_exampleクラスはスケルトンと呼ばれ，そのメソッド（_op1）はクライアントリクエストの受信時にPOAが起動します。スケルトンの内部メソッドはリクエストのすべてのパラメタをマーシャルし，ユーザのop1メソッドを起動してから，返されるパラメタまたは例外を応答メッセージにマーシャルします。ORBは，その応答をクライアントプログラムに送信します。

コンストラクタとデストラクタは，両方とも保護されており，継承されたメンバだけが起動できます。コンストラクタはオブジェクト名を受け付けるので，サーバは複数の異なるオブジェクトを実体化できます。

11.4.2　IDLコンパイラが生成するクラステンプレート

POA_exampleクラスに加えて，IDLコンパイラは_tie_exampleという名前のクラステンプレートを生成します。このテンプレートは，クラスをPOA_exampleから派生させたくない場合に使用します。テンプレートは，新しいクラスを継承するために変更できない既存のアプリケーションのオブジェクトラッパークラスを提供する場合に役立ちます。コードサンプル11-12に，exampleクラス用にIDLコンパイラが生成したテンプレートクラスを示します。

コードサンプル11-12　exampleクラス用に生成したテンプレートクラス（C++）

template <class T>
class POA_example_tie : public POA_example {
   public:
      POA_example_tie (T& t): _ptr(&t), _poa(NULL),
                           _rel((CORBA::Boolean)0) {}
      POA_example_tie (T& t, PortableServer::POA_ptr poa):
                           _ptr(&t),
         _poa(PortableServer::_duplicate(poa)),
                           _rel((CORBA::Boolean)0) {}
      POA_example_tie (T *p, CORBA::Boolean release= 1)
         : _ptr(p), _poa(NULL), _rel(release) {}
      POA_example_tie (T *p, PortableServer::POA_ptr poa,
                           CORBA::Boolean release =1)
         : _ptr(p), _poa(PortableServer::_duplicate(poa)),
                           _rel(release) {}
      virtual ~POA_example_tie() { /* . . . */ }
      T* _tied_object() { /* . . . */ }
      void _tied_object(T& t) { /* . . . */ }
      void _tied_object(T *p, CORBA::Boolean release=1)
                           { /* . . . */ }
      CORBA::Boolean _is_owner() { /* . . . */ }
      void _is_owner(CORBA::Boolean b) { /* . . . */ }
      CORBA::Long op1(CORBA::Char _x, CORBA::Short_out _y)
                           { /* . . . */ }
      PortableServer::POA_ptr _default_POA() { /* . . . */ }
};

_tieテンプレートクラスの使用については，「9.　tie機能の使用」を参照してください。

オブジェクトデータベースとユーザのサーバを統合するために，_ptieテンプレートを生成することもできます。

11.5　IDLのインタフェース属性の定義

インタフェース定義では，オペレーションに加えて，インタフェースの一部分として属性を定義できます。デフォルトでは，すべての属性はread-writeであり，IDLコンパイラは属性の値を設定するメソッドと属性の値を取得するメソッドの二つのメソッドを生成します。また，read-only属性も指定できますが，この場合は読み込みメソッドだけが生成されます。

IDLサンプル11-2は，read-write属性とread-only属性という二つの属性を定義するIDL指定を示しています。コードサンプル11-13は，IDLで宣言されたインタフェース用に生成されたオペレーションクラスを示しています。

IDLサンプル11-2　read-writeとread-onlyという二つの属性を持つIDL指定

interface Test {
   attribute long count;
   readonly attribute string name;
};

コードサンプル11-13　Testインタフェース用に生成されたコード（C++）

class Test : public virtual CORBA::Object {
      . . .
      // Methods for read-write attribute
      virtual CORBA::Long count();
      virtual void count(CORBA::Long __count);

      // Method for read-only attribute.
      virtual char * name();
      . . .
};

コードサンプル11-14　TestOperationsインタフェース用に生成されたコード（Java）

public interface TestOperations {
   // Methods for read-write attribute
   public int count ();
   public void count (int count);

   // Method for read-only attribute.
   public java.lang.String name ();
}

11.6　リターン値を持たないonewayメソッドの指定

IDLでは，リターン値を持たないoneway（一方向）メソッドと呼ばれるオペレーションを指定できます。このオペレーションには入力パラメタしかありません。onewayメソッドが呼び出されると，リクエストはサーバに送信されますが，このリクエストが実際に受信されたことを示すオブジェクトインプリメンテーションからの応答はありません。Borland Enterprise Server VisiBrokerはTCP/IPを使用してクライアントをサーバに接続します。これによってすべてのパケットの配信が保証され，サーバが使用可能であるかぎり，クライアントはリクエストがサーバに届いたことを確信できます。それでもクライアントには，リクエストが実際にオブジェクトインプリメンテーション自体によって処理されたことを知る方法はありません。

注

一方向オペレーションは，例外またはリターン値を発生させることはできません。

IDLサンプル11-3　一方向オペレーションの定義

interface oneway_example {
   oneway void set_value(in long val);
};

11.7　別のインタフェースを継承するインタフェースのIDLでの指定

IDLでは，別のインタフェースを継承するインタフェースを指定できます。IDLコンパイラによって生成されるクラスは，この継承関係を反映します。親インタフェースが宣言したすべてのメソッド，データ型定義，定数，および列挙体は，派生インタフェースからも参照できます。

IDLサンプル11-4　インタフェース定義での継承の例

interface parent {
   void operation1();
};
interface child : parent {
   . . .
   long operation2(in short s);
};

コードサンプル11-15，11-16はIDLサンプル11-4に示すインタフェース定義から生成されたC++コードおよびJavaコードを示しています。

コードサンプル11-15　IDLサンプル11-4から生成されたコード（C++）

. . .
class parent : public virtual CORBA::Object {
   . . .
   void operation1();
   . . .
};

class child : public virtual parent {
   . . .
   CORBA::Long operation2(CORBA::Short s);
   . . .
};

コードサンプル11-16　IDLサンプル11-4から生成されたコード（Java）

public interface parentOperations {
   public void operation1 ();
}
public interface childOperations extends parentOperations {
   public int operation2 (short s);
}
public interface parent extends
          com.inprise.vbroker.CORBA.Object, parentOperations,
          org.omg.CORBA.portable.IDLEntity {
}
public interface child extends childOperations, Baz.parent,
          org.omg.CORBA.portable.IDLEntity {
}

12　スマートエージェントの使用

この章では，オブジェクトインプリメンテーションを見つけるためにクライアントプログラムが登録する，スマートエージェント（osagent）について説明します。また，自分のVisiBroker ORBドメインの設定方法，異なるローカルネットワークのスマートエージェントの接続方法，およびホスト間のオブジェクトのマイグレート方法を説明します。

12.1　スマートエージェントとは

Borland Enterprise Server VisiBrokerのスマートエージェント（osagent）は，クライアントプログラムとオブジェクトインプリメンテーションの両方が使用する機能を提供する，動的な分散ディレクトリサービスです。スマートエージェントは，ご使用のローカルネットワークの少なくとも一つのホストで起動する必要があります。クライアントプログラムが，あるオブジェクトのbind()メソッドを呼び出すと，自動的にスマートエージェントに問い合わせが行われます。スマートエージェントは，クライアントとインプリメンテーションの間にコネクションを確立できるように，指定されたインプリメンテーションを探します。スマートエージェントを使用した通信は，クライアントプログラムから見て透過的です。

POAにPERSISTENTポリシーを設定し，activate_object_with_idを使用すると，スマートエージェントはオブジェクトまたはインプリメンテーションを登録して，クライアントプログラムから使用できるようにします。オブジェクトまたはインプリメンテーションが非活性化されると，スマートエージェントはそれを使用可能オブジェクトのリストから削除します。クライアントプログラムの場合と同様に，スマートエージェントを使用した通信は，オブジェクトインプリメンテーションから見て透過的です。

12.1.1　スマートエージェントの探索

Borland Enterprise Server VisiBrokerはブロードキャストメッセージを使用して，クライアントプログラムまたはオブジェクトインプリメンテーションで使用するスマートエージェントを探します。最初に応答したスマートエージェントが使用されます。スマートエージェントが見つかったあと，スマートエージェントへの登録リクエストや検索リクエストの送信には，ポイントツーポイントUDPコネクションが使用されます。UDPプロトコルを使用するのは，TCPコネクションよりもネットワーク資源の消費が少ないためです。すべての登録リクエストおよび探索リクエストは動的なので，必要な構成ファイルまたはマッピングは存在しません。

注

ブロードキャストメッセージは，スマートエージェントを探すためだけに使用されます。スマートエージェントとのほかのすべての通信には，ポイントツーポイント通信が使用されます。ブロードキャストメッセージの使用を抑止する方法の詳細については，「12.5　ポイントツーポイント通信の使用」を参照してください。

12.1.2　エージェント間の協力によるオブジェクトの探索

スマートエージェントがローカルネットワークの複数のホストで起動されると，各スマートエージェントは使用可能なオブジェクトのサブセットを認識し，見つからないオブジェクトはほかのスマートエージェントと通信して探します。スマートエージェントプロセスの一つが不測の事態で終了した場合，そのスマートエージェントに登録されたすべてのインプリメンテーションがこのイベントを発見し，これらのインプリメンテーションは自動的に別の使用可能なスマートエージェントに再登録します。

12.1.3　OADとの協力によるオブジェクトへの接続

オブジェクトインプリメンテーションは，オンデマンドで開始できるようにOAD（オブジェクト活性化デーモン）に登録できます。このようなオブジェクトは，実際にアクティブな状態でOAD内に存在するかのようにスマートエージェントに登録されます。クライアントがこれらのオブジェクトの一つにリクエストすると，そのリクエストはOADで受け付けられます。そのあと，OADはそのリクエストを実サーバに転送します。このとき，実サーバが起動されていない場合はOADが起動してリクエストを転送します。スマートエージェントは，実オブジェクトインプリメンテーションがOADによって実際に起動されているかどうかは知りません。

12.1.4　スマートエージェント（osagent）の起動

スマートエージェントの少なくとも一つのインスタンスが，ローカルネットワークのホストで実行中でなければなりません。ローカルネットワークとは，内部でブロードキャストメッセージを送信できるサブネットワークを指します。

Windows

Windowsのシステムでスマートエージェントを起動するには，コマンドプロンプトで次のコマンドを入力してください。

prompt> osagent [options]

UNIX

UNIXのシステムでスマートエージェントを起動するには，次のコマンドを入力してください。

prompt> osagent [options] &

osagentコマンドには，表12-1のコマンドライン引数を指定できます。

表12‒1　osagentコマンドのオプション

オプション

説明

-p UDP_port

環境変数の値（UNIXの場合），または環境変数およびレジストリの値（Windowsの場合）より優先して使用されるosagentのUDPポートを指定します。

注

ポート番号の有効範囲は，5001〜65535の範囲の整数値です。それ以外の値を指定した場合，動作の保証はできません。

-v

実行時に情報および診断メッセージを提供するバーボースモードをオンにします。

-help，-?

ヘルプメッセージを出力します。

-n，-N

Windowsでシステムトレーアイコンを使用禁止にします。

-a ip_address

osagentがデフォルトで使用するIPアドレスを指定します。

注

マルチホームホスト上で，osagentに-aオプションを指定して起動する場合は，localaddrファイルに-aオプションで指定したネットワークだけを記述してください。記述が正しくない場合，次のような動作になります。

-aオプションで指定していないネットワークへ電文を送信してしまう場合があります。

-vオプションを指定している場合，バーボースログに出力されるosagentが使用するインタフェースのリストに，-aオプションで指定していないインタフェースが表示されます。

-g

UNIXでバーボースモード時に出力される情報および診断メッセージをログファイルに出力します。

次に示すosagentコマンド例は，特定のUDPポートを指定しています。

例

osagent -p 17000

(1)　バーボース出力

osagentに-vオプションを指定した場合にバーボース出力が行われます。

UNIX

バーボース出力はstdoutに出力されます。

Windows

バーボース出力は「2.5　ロギング出力」を参照してください。

prompt> osagent

(2)　エージェントを使用禁止にする

ランタイムにORBのプロパティを渡すことによって，スマートエージェントとの通信を禁止できます。

C++の場合

prompt> Server -Dvbroker.agent.enableLocator=false

Javaの場合

prompt> vbj -Dvbroker.agent.enableLocator=false Server

文字列から変換したオブジェクトリファレンス，ネーミングサービス，またはURLリファレンスを利用する場合は，スマートエージェントは不要のため使用禁止にできます。オブジェクト名にbindメソッドを利用する場合は，必ずスマートエージェントを使用してください。

(3)　スマートエージェント起動時の注意事項

osagent起動時に，socket関数で次のエラーが発生した場合，最大で5回リトライ処理をします。5回リトライ処理をしても，次のエラーが発生し続けると，osagentからアプリケーションへの送信メッセージが遅延，またはosagentがすぐに終了します。

Unixの場合：EAGAINまたはEWOULDBLOCK

Windowsの場合：WSAEWOULDBLOCK

12.1.5　エージェントの可用性の確保

ローカルネットワークの複数のホストでスマートエージェントを起動すると，クライアントは，スマートエージェントの一つが不測の事態で終了した場合でも，オブジェクトへのバインドを続行できます。スマートエージェントが使用不能になると，そのスマートエージェントに登録されたすべてのオブジェクトインプリメンテーションは，別のスマートエージェントに自動的に再登録されます。ローカルネットワークで動作中のスマートエージェントがなければ，オブジェクトインプリメンテーションは新しいスマートエージェントにコンタクトできるまでリトライを続けます。

その際，C++アプリケーションはstdoutに「VisiBroker: Unable to locate agent. Will try every 15 seconds to locate agent.」というメッセージを出力します。ローカルネットワーク上でスマートエージェントを起動するか，agentaddrファイルにスマートエージェントが起動しているホストを指定してください。詳細については「12.5　ポイントツーポイント通信の使用」を参照してください。

スマートエージェントが終了しても，スマートエージェントが終了する前にクライアントとオブジェクトインプリメンテーションの間に確立されたコネクションは中断しないで継続します。ただし，クライアントが新たに_bind()リクエストを発行すると，新しいスマートエージェントにコンタクトされます。

これらのフォルトトレラントな機能を利用するために，特別なコーディングは必要ありません。ローカルネットワークの一つ以上のホストでスマートエージェントが起動されていることを確認すればよいだけです。

(1)　クライアントの存在の確認

スマートエージェントは，クライアントがまだ接続されているかどうかを確認するために，各クライアントとの通信状態を一定時間ごとにチェックします。

チェック時に一定時間の間スマートエージェントとの通信が行われていないクライアントに対して，「Are You Alive」メッセージ（ハートビートメッセージ）を送信します。クライアントが応答しなければ，スマートエージェントはクライアントがコネクションを終了したものとみなします。

クライアントへのポーリング間隔は変更できません。

注

「クライアント」という用語の使用がオブジェクトまたはプロセスの機能を説明するとは限りません。オブジェクトリファレンスのためにスマートエージェントに接続するプログラムはどれもクライアントです。

12.2　VisiBroker ORBドメイン内の作業

図12-1のように，同時に複数のVisiBroker ORBドメインを実行することが望ましい場合がよくあります。一つのドメインを製品用のクライアントプログラムとオブジェクトインプリメンテーションで構成し，もう一つのドメインを同一クライアントとオブジェクトの，まだ一般向けにリリースされていないテストバージョンで構成できます。複数の開発者が同じローカルネットワークで作業している場合，それぞれの開発者は，テスト作業が相互に干渉し合うことがないように，自身のVisiBroker ORBドメインを確立することを望む可能性があります。

図12‒1　別々のORBドメインの同時実行

Borland Enterprise Server VisiBrokerでは，各ドメインのスマートエージェントに対する一意のUDPポート番号を使用することによって，同じネットワーク上の複数のVisiBroker ORBドメインを相互に区別できます。このポート番号は，OSAGENT_PORT環境変数で指定できます。OSAGENT_PORT環境変数のデフォルト値は，14000です。異なるポート番号を使用したい場合は，システム管理者に問い合わせて，使用できるポート番号を確認してください。デフォルト設定を変更するには，スマートエージェント，OAD，オブジェクトインプリメンテーション，またはそのORBドメインに割り当てられたクライアントプログラムを実行する前に，OSAGENT_PORT環境変数を設定する必要があります。

Windowsでは，OSAGENT_PORT環境変数を設定する代わりに，Windowsのレジストリ設定，またはvregedit.exeユーティリティプログラム（Borland Enterprise Server VisiBrokerをインストールしたディレクトリのbinディレクトリ内にある）を使用して設定することもできます。

コードサンプル12-1　cshを実行するUNIXのシステムでのOSAGENT_PORT環境変数の設定

prompt> setenv OSAGENT_PORT 5678
prompt> osagent &
prompt> oad &

また，スマートエージェントは，自身のORBドメインに属するアプリケーション（osfind，nameservおよびoadも含む）と通信するために，OSAGENT_PORT環境変数で設定するポート番号とは別に，OSAGENT_CLIENT_HANDLER_PORT環境変数で設定するポート番号も使用します。OSAGENT_CLIENT_HANDLER_PORT環境変数で設定するポート番号は，TCPとUDPの両方のプロトコルで使用され，両方とも同じ番号です。

OSAGENT_CLIENT_HANDLER_PORT環境変数のデフォルト値はありません。OSAGENT_CLIENT_HANDLER_PORT環境変数が設定されていない場合は，OSによって自動的に割り当てられたポート番号を使用して通信を行います。

注

OSAGENT_CLIENT_HANDLER_PORT環境変数に0以外を指定する場合，OSAGENT_PORT環境変数と同様にポート番号の有効範囲は，5001〜65535の範囲の整数値です。それ以外の値を指定した場合，動作の保証はできません。

12.3　異なるローカルネットワーク上のスマートエージェントの接続

ローカルネットワーク上で複数のスマートエージェントを起動する場合，スマートエージェントはUDPブロードキャストメッセージを使用して互いに探し合います。ネットワーク管理者は，IPサブネットマスクを使用してブロードキャストメッセージのスコープを指定することによって，ローカルネットワークを構成します。図12-2に，ネットワークリンクによって接続された二つのローカルネットワークを示します。

図12‒2　別々のローカルネットワークに存在する二つのスマートエージェント

ある一つのネットワーク上のスマートエージェントが別のローカルネットワーク上のスマートエージェントとコンタクトできるようにするには，リモートスマートエージェントのIPアドレスを，agentaddrという名前のファイルで使用可能にする必要があります。これは，二つのネットワーク上のスマートエージェントがUDPブロードキャストを介して互いを検知できない場合だけ必要です。ローカルネットワーク#1のスマートエージェントからほかのネットワークのスマートエージェントへ接続できるようにするためのファイルの指定内容を，コードサンプル12-2に示します。このファイルへのパスは，スマートエージェントプロセス用に設定されたVBROKER_ADM環境変数で指定されます。OSAGENT_ADDR_FILE環境変数を設定することによって，このファイル名を変更できます。このファイルには，1行につき一つのIPアドレスを記述できます。また「#」で始まる行は，コメントとみなされて無視されます。

コードサンプル12-2　ネットワーク#1のスマートエージェント用のagentaddrファイルの内容

# list all OSAgent addresses.
101.10.2.6
101.10.2.7

適切なagentaddrファイルによって，ローカルネットワーク#1のクライアントプログラムは，ローカルネットワーク#2のオブジェクトインプリメンテーションを探して使用できます。環境変数の詳細については，「2.　環境設定」を参照してください。

注

リモートネットワークで複数のスマートエージェントを実行している場合，リモートネットワーク上のすべてのスマートエージェントのIPアドレスを記述する必要があります。

12.3.1　スマートエージェントの互いの検知方法

エージェント1とエージェント2という二つのエージェントが，同じサブネット上の異なる二つのマシンから同じUDPポートを監視し，エージェント1がエージェント2より前に起動する場合，次のようなことが起こります。

エージェント2を起動すると，自分の存在をUDPブロードキャストして，ほかのスマートエージェントを探すためにリクエストメッセージを送信します。

エージェント1はエージェント2がネットワーク上で使用可能であることに気づき，リクエストメッセージに応答します。

エージェント2は，ほかのエージェント（エージェント1）がネットワーク上で使用可能であることに気づきます。

エージェント2が正常に終了すると（例えば，＜Ctrl＞＋＜C＞を使用して終了させる），エージェント1はエージェント2がもう使用できないことを通知されます。

エージェント2が異常終了すると（例えば，タスクマネージャを使用してエージェント2を終了させる），エージェント1はエージェント2が使用できないことを通知されません。このため，エージェント1のディクショナリに存在しないオブジェクトリファレンスをクライアントが要求すると，エージェント1はエージェント2にリクエストを転送します。その結果，エージェント1はエージェント2からの応答を得られないため，エージェント2が使用できないことを検出し，エージェント1はクリーンアップ（以後，エージェント2を使用できないとみなします）を行います。または，エージェント1が行うハートビートメッセージにエージェント2が返信しない場合，エージェント1はエージェント2が使用できないとみなし，クリーンアップを行います。

エージェント1がクリーンアップを行うまで，osfindを実行しても二つのエージェントを表示し，エージェント2についてはObjLocation::Fail例外を表示します。

12.4　マルチホームホストを使用した作業

複数の実IPアドレスを持つホスト（マルチホームホストと呼ばれます）上でスマートエージェントを起動すると，スマートエージェントは別々のローカルネットワークに存在するオブジェクトをブリッジするための強力なメカニズムを提供できます。そのホストが接続されているすべてのローカルネットワークは，ただ一つのスマートエージェントとだけ通信でき，ローカルネットワークのブリッジを効果的に行います。マルチホームホスト環境のスマートエージェントを図12-3に示します。

図12‒3　マルチホームホストのスマートエージェント

UNIX

マルチホームUNIXホストのスマートエージェントは，ポイントツーポイントコネクションまたはブロードキャストコネクションをサポートするすべてのホストインタフェースの監視とブロードキャストを行うように自身を動的に構成します。「12.4.1　スマートエージェント用インタフェースの指定」で説明するように，localaddrファイルを使用してインタフェース設定値を明示的に指定できます。

Windows

マルチホームWindowsホストのスマートエージェントは，正しいサブネットマスク値とブロードキャストアドレス値を動的に決定できません。この制限を克服するには，スマートエージェントに使用させたいインタフェース設定値を，localaddrファイルで明示的に指定する必要があります。

-v（バーボース）オプションを使用してスマートエージェントを起動すると，作成されたメッセージの先頭に，スマートエージェントが使用する各インタフェースがリスト表示されます。コードサンプル12-3は，マルチホームホストでバーボースオプションを使用して起動されたスマートエージェントからの出力例を示しています。

コードサンプル12-3　マルチホームホストで起動されたスマートエージェントからのバーボース出力

Bound to the following interfaces:
Address: 199.10.9.5 Subnet: 255.255.255.0 Broadcast:199.10.9.255
Address: 101.10.2.6 Subnet: 255.255.255.0 Broadcast:101.10.2.255
. . .

コードサンプル12-3に示すように，出力には，マシンの各インタフェースのアドレス，サブネットマスク，およびブロードキャストアドレスが表示されます。UNIXの場合，この出力は，UNIXコマンドifconfig -aの結果と一致するはずです。

これらの設定値を変更したい場合は，このインタフェース情報をlocaladdrファイルに指定できます。詳細については，「12.4.1　スマートエージェント用インタフェースの指定」を参照してください。

12.4.1　スマートエージェント用インタフェースの指定

注

シングルホームホストでインタフェース情報を指定する必要はありません。

マルチホームホストでスマートエージェントに使用させたい各インタフェースのインタフェース情報を，localaddrファイルに指定できます。localaddrファイルの別々の行に，各インタフェースの情報（ホストのIPアドレス，サブネットマスク，およびブロードキャストアドレス）を指定します。デフォルトでは，Borland Enterprise Server VisiBrokerはVBROKER_ADMディレクトリのlocaladdrファイルを探索します。このファイルをポイントするようにOSAGENT_LOCAL_FILE環境変数を設定することによって，この位置を変更できます。このファイルの「#」で始まる行は，コメントとみなされて無視されます。コードサンプル12-4に，前述のマルチホームホストのlocaladdrファイルの内容を示します。

コードサンプル12-4　サンプルのlocaladdrファイルの内容

#entries of format <address> <subnet_mask> <broadcast address>
199.10.9.5 255.255.255.0 199.10.9.255
101.10.2.6 255.255.255.0 101.10.2.255

(1)　UNIX

スマートエージェントは，UNIXを実行するマルチホームホストで自動的に自身を構成できますが，localaddrファイルを使用して，ホストに含まれているインタフェースを明示的に指定できます。次のコマンドを使用して，UNIXホストの使用できるすべてのインタフェース値を表示できます。コマンドの詳細は各OSのマニュアルを参照してください。

SolarisまたはAIX

prompt> ifconfig -a

このコマンドによる出力は，次のようになります。

lo0: flags=849<UP,LOOPBACK,RUNNING,MULTICAST> mtu 8232
      inet 127.0.0.1 netmask ff000000
le0: flags=863
         <UP,BROADCAST,NOTRAILERS,RUNNING,MULTICAST> mtu 1500
     inet 199.10.9.5 netmask ffffff00 broadcast 199.10.9.255
le1: flags=863
         <UP,BROADCAST,NOTRAILERS,RUNNING,MULTICAST> mtu 1500
     inet 101.10.2.6 netmask ffffff00 broadcast 101.10.2.255

HP-UX

lanscanコマンドで出力されるネットワークインタフェース名を指定して，ifconfigコマンドを実行します。

(2)　Windows

Windowsを実行するホストの場合，スマートエージェントが自動的に自身を構成できないため，マルチホームホストではlocaladdrファイルを使用する必要があります。ネットワーク制御パネルでTCP/IPプロトコルプロパティにアクセスすることによって，このファイルの適切な値を取得できます。ホストがWindowsを実行している場合，ipconfigコマンドが必要な値を提供します。このコマンドは次のように実行してください。

prompt> ipconfig

このコマンドによる出力は，次のようになります。

Ethernet adapter El59x1:
      IP Address..........:199.10.9.5
      Subnet Mask ........:255.255.255.0
      Default Gateway ....:199.10.9.1

Ethernet adapter Elnk32:
      IP Address.........:101.10.2.6
      Subnet Mask .......:255.255.255.0
      Default Gateway ...:101.10.2.1

12.5　ポイントツーポイント通信の使用

Borland Enterprise Server VisiBrokerは，UDPブロードキャストメッセージを使用しないでスマートエージェントプロセスを探す三つの異なる機能を提供します。

これらの三つの機能を使用すると，Borland Enterprise Server VisiBrokerは，次の順序でスマートエージェントの探索を行います。

C++の場合

実行時パラメタとして指定されたホスト

詳細については，「12.5.1　実行時パラメタとしてのホストの指定」，および「12.5.2　環境変数によるIPアドレスの指定」を参照してください。

自ホスト

agentaddrファイルによって指定されたホスト

詳細については，「12.5.3　agentaddrファイルによるホストの指定」を参照してください。

1.と同じホスト

Javaの場合

実行時パラメタとして指定されたホスト

詳細については，「12.5.1　実行時パラメタとしてのホストの指定」，および「12.5.2　環境変数によるIPアドレスの指定」を参照してください。

agentaddrファイルによって指定されたホスト

詳細については，「12.5.3　agentaddrファイルによるホストの指定」を参照してください。

agentaddrファイルが指定されない場合で，かつ$VBROKER_ADM/agentaddrファイルが存在する場合に，Javaでは，次のとおり実行時パラメタとして指定されたものとみなします。

vbroker.agent.addrFile=$VBROKER_ADM/agentaddr

自ホスト

これらの代替アプローチのどれかを使用してスマートエージェントが見つかると，それ以降のすべての受け渡しにはスマートエージェントが使用されます。

注

これらの代替アプローチを使用してもスマートエージェントを探し出せなかった場合は，UDPブロードキャストメッセージを使用した探索を行います。

12.5.1　実行時パラメタとしてのホストの指定

コードサンプル12-5に，クライアントプログラムまたはオブジェクトインプリメンテーションのランタイムパラメタとして，スマートエージェントが実行されているIPアドレスを指定する方法を示します。IPアドレスを指定するとポイントツーポイントコネクションが確立されるので，ローカルネットワークの外部にあるホストのIPアドレスさえ指定できます。この機能は，ほかのすべてのホスト指定に優先します。

コードサンプル12-5　ランタイムパラメタとしてのスマートエージェントのIPアドレスの指定

C++の場合

prompt> Server -Dvbroker.agent.addr=<ip_address>

Javaの場合

prompt> vbj -Dvbroker.agent.addr=<ip_address> Server

また，プロパティファイルを介してIPアドレスを指定することもできます。vbroker.agent.addrの説明も参照してください。

コードサンプル12-6　プロパティファイルへのスマートエージェントのIPアドレスの指定

vbroker.agent.addr=<ip_address>

デフォルトでは，プロパティファイルのvbroker.agent.addrはNULLに設定されています。

エージェントが存在している可能性があるホスト名をリスト出力してから，プロパティファイルのvbroker.agent.addrFileオプションを使用してそのファイルを指定できます。

12.5.2　環境変数によるIPアドレスの指定

クライアントプログラムまたはオブジェクトインプリメンテーションを開始する前にOSAGENT_ADDR環境変数を設定することによって，スマートエージェントのIPアドレスを指定できます。この環境変数は，osagentの動作しているホストがランタイムパラメタとして指定されていない場合に優先されます。

(1)　UNIX

prompt> setenv OSAGENT_ADDR 199.10.9.5
prompt> client

(2)　Windows

WindowsでOSAGENT_ADDR環境変数を設定するには，システムコントロールパネルを使用して環境変数を編集できます。Windowsの場合の編集方法を次に示します。

「システムプロパティ」の「環境」を選択し，現在の変数を選択します。

変数ボックスにOSAGENT_ADDRとタイプ入力します。

値ボックスに，199.10.9.5のようにIPアドレスをタイプ入力します。

12.5.3　agentaddrファイルによるホストの指定

「12.3　異なるローカルネットワーク上のスマートエージェントの接続」で述べたように，クライアントプログラムまたはオブジェクトインプリメンテーションは，UDPブロードキャストメッセージを使用しないでスマートエージェントを探すために，agentaddrファイルを使用できます。スマートエージェントを実行している各ホストのIPアドレスか完全に修飾されたホスト名を収納したファイルを作成したあと，このファイルのパスをポイントするようにOSAGENT_ADDR_FILE環境変数を設定してください。クライアントプログラムまたはオブジェクトインプリメンテーションにこの環境変数が設定されていれば，VisiBroker ORBはスマートエージェントが見つかるまで，このファイル内の各アドレスをトライします。これは，ホストを指定する機能の中で最も優先度が低い機能です。このファイルが指定されないと，$VBROKER_ADM/agentaddrファイルが使用されます。

注

agentaddrファイルに日本語や2バイトコード文字を含むホスト名を指定しないでください。指定した場合，日本語や2バイトコード文字を含むホスト名のosagentには接続されません。

12.6　オブジェクト可用性の確保

複数のホストでオブジェクトのインスタンスを開始することによって，これらのオブジェクトのフォルトトレランスを提供できます。インプリメンテーションが使用不能になると，VisiBroker ORBはクライアントプログラムとオブジェクトインプリメンテーションの間のコネクションの切断を検出し，クライアントが設定した有効なリバインドポリシーによってオブジェクトインプリメンテーションの別のインスタンスとコネクションを確立するために，自動的にスマートエージェントにコンタクトします。クライアントポリシーの設定の詳細については，「10.5　Quality of Serviceの使用」を参照してください。

注

VisiBroker ORBがクライアントを別のオブジェクトインプリメンテーションに再接続させようとする場合，リバインドオプションを使用可能にする必要があります。これはデフォルトの動作です。

12.6.1　状態を維持しないオブジェクトのメソッドの呼び出し

クライアントプログラムは，オブジェクトの新しいインスタンスが使用中であるかどうかを関知することなく，状態を維持しないオブジェクトインプリメンテーションのメソッドを呼び出せます。

12.6.2　状態を維持するオブジェクトのフォルトトレランスの実現

状態を維持するオブジェクトインプリメンテーションに対してもフォルトトレランスを実現できますが，これはクライアントプログラムから見て透過的ではありません。この場合，クライアントプログラムはQoS（Quality of Service）ポリシーVB_NOTIFY_REBINDを使用するか，または，VisiBroker ORBオブジェクトのインタセプタを登録して状態の変更時にORBによって呼び出されるよう実装しておきます。QoSの使用に関する詳細については，「10.5　Quality of Serviceの使用」を参照してください。

オブジェクトインプリメンテーションとのコネクションが失敗し，VisiBroker ORBがクライアントを別のオブジェクトインプリメンテーションに再接続すると，bindインタセプタのbindメソッドがVisiBroker ORBによって呼び出されます。クライアントは，このバインドメソッドを実装することによって，別のオブジェクトインプリメンテーションに再接続されたことを知ることができます。インタセプタの詳細については，「20.　VisiBroker 4.xインタセプタの使用」を参照してください。

12.6.3　OADに登録されたオブジェクトの複製

オブジェクトがダウンしてもOADによって再起動されるので，OADはより高いオブジェクト可用性を保証します。ホストが使用不能になった時のためにフォルトトレランスを望む場合は，OADを複数のホストで起動し，オブジェクトを各OADインスタンスに登録する必要があります。

注

Borland Enterprise Server VisiBrokerが提供するタイプのオブジェクト複製では，マルチキャストやミラーリング機能を提供しません。任意の時点で，クライアントプログラムと個々のオブジェクトインプリメンテーションの間には常に一対一の対応関係があります。

12.7　ホスト間のオブジェクトのマイグレート

オブジェクトマイグレーションとは，一つのホストでオブジェクトインプリメンテーションを終了し，別のホストでそれを開始する方法です。オブジェクトマイグレーションを使用して，過負荷のホストから，より多くの資源または処理能力を持つホストにオブジェクトを移動することによって負荷分散ができます（異なるosagentに登録されたサーバ間の負荷分散はありません）。ハードウェアまたはソフトウェアの保守のためにホストをシャットダウンしなければならない場合，オブジェクトを使用できる状態に保つためにもオブジェクトマイグレーションを使用できます。

注

状態を維持しないオブジェクトのマイグレーションは，クライアントプログラムから見て透過的です。マイグレートされたオブジェクトインプリメンテーションにクライアントが接続されると，スマートエージェントはコネクションの切断を検出し，クライアントを新しいホストの新しいオブジェクトに透過的に再接続します。

12.7.1　状態を維持するオブジェクトのマイグレート

状態を維持するオブジェクトのマイグレーションもできますが，マイグレーションプロセスが始まる前に接続したクライアントプログラムから見て，このマイグレーションは透過的ではありません。この場合，クライアントプログラムはオブジェクトのインタセプタを登録する必要があります。

(1)　C++

元のオブジェクトとのコネクションが失われ，VisiBroker ORBがクライアントをオブジェクトに再接続すると，インタセプタのbind_succeeded()メソッドがVisiBroker ORBによって呼び出されます。クライアントは，オブジェクトの状態を最新のものにするためにこのメソッドをインプリメントできます。

(2)　Java

元のオブジェクトとのコネクションが失われ，VisiBroker ORBがクライアントをオブジェクトに再接続すると，インタセプタのbind_succeeded()メソッドがVisiBroker ORBによって呼び出されます。クライアントは，オブジェクトの状態を最新のものにするためにこのメソッドをインプリメントできます。

インタセプタについては，「20.　VisiBroker 4.xインタセプタの使用」を参照してください。

12.7.2　実体化されたオブジェクトのマイグレート

マイグレートしたいVisiBroker ORBオブジェクトが，インプリメンテーションのクラスを実体化するサーバプロセスによって生成されていた場合，ユーザは新しいホストでオブジェクトを開始し，サーバプロセスを終了するだけです。元のインスタンスが終了すると，それはスマートエージェントから登録解除されます。新しいホストで新しいインスタンスを開始すると，それはスマートエージェントに登録されます。この時点から，クライアントの呼び出しは，新しいホストのオブジェクトインプリメンテーションに転送されます。

12.7.3　OADに登録されたオブジェクトのマイグレート

マイグレートしたいVisiBroker ORBオブジェクトがOADに登録されている場合，旧ホストのOADからVisiBroker ORBオブジェクトを登録解除する必要があります。そのあと，VisiBroker ORBオブジェクトを新しいホストのOADに登録してください。この手順を次に示します。

旧ホストのOADからオブジェクトインプリメンテーションを登録解除します。

新ホストのOADにオブジェクトインプリメンテーションを登録します。

旧ホストのオブジェクトインプリメンテーションを終了します。

オブジェクトインプリメンテーションの登録および登録解除の詳細については，「15.　オブジェクト活性化デーモンの使用」を参照してください。

12.8　すべてのオブジェクトとサービスの報告

スマートファインダ（osfind）コマンドは，スマートエージェント（osagent）と連携して，現在ネットワーク上で使用可能な次の情報を報告します。

スマートエージェントが動作するホストおよび数

Borland Enterprise Server VisiBrokerオブジェクト

オブジェクト活性化デーモン（OAD）が動作するホストおよび数

オブジェクト活性化デーモンに登録されたオブジェクト

接続したスマートエージェントが保持する情報が使用できないスマートエージェントの場合には，ObjLocation::Fail例外を表示します。

osfindコマンドの構文は次のとおりです。

構文

osfind [options]

osfindコマンドでは表12-2に示すオプションが有効です。オプションを指定しないと，osfindはドメイン内のすべてのエージェント，OAD，およびインプリメンテーションをリスト表示します。

表12‒2　osfindコマンドのオプション

オプション

説明

-a

ドメイン内のすべてのスマートエージェントをリスト表示します。

-b

VisiBroker 2.0と下位互換性のあるosfind機能を使用します。

-d

ドットを含む数値アドレスでホスト名を出力します。

-f <agent address filename>

ファイルに指定されたホストで実行されているスマートエージェントを問い合わせます。このファイルには，1行につき一つのIPアドレス，または完全に修飾されたホスト名があります。すべてのスマートエージェントを報告する場合にこのファイルは使用されないことに注意してください。このファイルはオブジェクトインプリメンテーションとサービスの報告時だけに使用されます。

-g

オブジェクトがあるかどうかを確認します。このオプションを指定してコマンドを実行するとシステムのロードが大きく遅れる原因となる場合があります。BY_INSTANCEを登録したオブジェクトだけについて，その有無が確認されます。

OADに登録されたオブジェクト，またはBY_POAポリシーを登録したオブジェクトについては，その有無の確認は行われません。

-h,-help,-usage,-?

このオプションのヘルプ情報を出力します。

-o

ドメイン内のすべてのOADをリスト表示します。

-C

終了する前にポーズします。コマンドの実行完了と同時に終了してしまうようなWindowsのコンソールで使用すると，コンソールがポーズするため終了しなくなります。

コードサンプル12-7は，osfindコマンドの出力例を示しています。

コードサンプル12-7　osfindコマンドの出力例

prompt>osfind
osfind: Found one agent at port 14000
        HOST: HostA
osfind: Found 1 OADs in your domain
        HOST: HostA
osfind: Following are the list of Implementations registered with OADs.
        HOST: HostA
                REPOSITORY ID: IDL:Bank/Account:1.0
                        OBJECT NAME: Jack B. Quick
osfind: Following are the list of Implementations started manually.
        HOST: HostA
                REPOSITORY ID: IDL:visigenic.com/Activation/OAD:1.0
                        OBJECT NAME: 172.17.113.31

12.9　オブジェクトへのバインド

クライアントアプリケーションがインタフェース上のメソッドを呼び出すには，まずbindメソッドでオブジェクトリファレンスを取得しなければなりません。

クライアントアプリケーションがbindメソッドを呼び出すと，VisiBroker ORBはアプリケーションの代わりに幾つかの機能を実行します。

VisiBroker ORBはosagentにコンタクトして，要求されたインタフェースを提供しているオブジェクトサーバを探索します。オブジェクト名とホスト名（またはIPアドレス）が指定されていれば，これらはディレクトリサービス検索をさらに限定するために使用されます。

オブジェクトインプリメンテーションが探索されると，VisiBroker ORBは探索されたオブジェクトインプリメンテーションとクライアントアプリケーション間のコネクションを設定しようとします。

コネクションの設定に成功すると，VisiBroker ORBは必要に応じてプロキシオブジェクトを生成し，そのオブジェクトにリファレンスを返します。

注

VisiBroker ORBは個別のプロセスではありません。VisiBroker ORBはクラスとほかのリソースの集まりであり，これによってクライアントとサーバ間で通信できるようになります。

13　ロケーションサービスの使用

この章では，Borland Enterprise Server VisiBrokerロケーションサービスの使用方法について説明します。Borland Enterprise Server VisiBrokerロケーションサービスは，特定の属性に基づいてオブジェクトインスタンスを見つけられる高度なオブジェクトディスカバリを提供します。ロケーションサービスはBorland Enterprise Server VisiBrokerスマートエージェントを使って，ネットワーク上でどのオブジェクトが現在アクセスできるか，それらがどこに存在するかを通知します。ロケーションサービスはCORBAの仕様に対するBorland Enterprise Server VisiBrokerの拡張機能で，Borland Enterprise Server VisiBrokerでインプリメントされたオブジェクトを見つけるためだけに有用です。

13.1　ロケーションサービスとは

ロケーションサービスはCORBAの仕様に対する拡張機能で，オブジェクトインスタンスを見つける汎用機能を提供します。ロケーションサービスは，自身が知っているインスタンスのリストを格納しているカタログを保守するスマートエージェントと直接通信します。ロケーションサービスから問い合わせがあると，スマートエージェントはその問い合わせをほかのスマートエージェントに転送し，その応答を集めてロケーションサービスに返します。

ロケーションサービスは，BY_INSTANCEポリシーを指定したPOAに登録されたすべてのオブジェクトインスタンスについて知っています。これらのオブジェクトを含むサーバは，手動起動またはOADによる自動起動ができます。

図13-1はこの概念を表したものです。

図13‒1　スマートエージェントを使用した，オブジェクトのインスタンスの検索

注

サーバは，インスタンスを生成するときにインスタンスのスコープを指定します。グローバルにスコープされたインスタンスだけがスマートエージェントに登録されます。

ロケーションサービスは，スマートエージェントが各オブジェクトインスタンスについて保持している情報を使用できます。各オブジェクトインスタンスに対して，ロケーションサービスはIDLサンプル13-1のようなObjLocation::Desc構造体の中にカプセル化された情報を保持しています。

IDLサンプル13-1　Desc構造体のIDL

struct Desc {
     Object ref;
     ::IIOP::ProfileBodyValue iiop_locator;
     string repository_id;
     string instance_name;
     boolean activable;
     string agent_hostname;
};
typedef sequence<Desc> DescSeq;

Desc構造体のIDLには次のような情報が入っています。

オブジェクトリファレンスであるrefは，オブジェクトを呼び出すハンドルです。

iiop_locatorインタフェースは，インスタンスのサーバのホスト名およびポートへのアクセスをできるようにします。この情報は，唯一サポートされているプロトコルであるIIOPにオブジェクトが接続されている場合だけ意味があります。ホスト名はインスタンス記述内の文字列として返されます。

repository_idは，IR（インタフェースリポジトリ）とインプリメンテーションリポジトリの中で検索できるオブジェクトインスタンスのインタフェース指定です。一つのインスタンスが複数のインタフェースに応じる場合は，インタフェースごとに一つのインスタンスがあるかのように，カタログにはインタフェースごとにエントリが含まれます。

instance_nameは，そのサーバがオブジェクトに与えた名前です。

activableフラグは，OADが活性化できるインスタンスと，手動操作で起動されるインスタンスを識別します。

agent_hostnameは，インスタンスが登録されているスマートエージェント名です。

ロケーションサービスは負荷分散や監視などの目的に役立ちます。あるオブジェクトの複製が幾つかのホスト上にある場合，複製を提供するホスト名と各ホストの最近の負荷平均のキャッシュを維持するバインドインタセプタを配置できます。インタセプタは，オブジェクトのインスタンスを現在提供しているホストについてロケーションサービスに尋ねることでキャッシュを更新してから，ホストに問い合わせて負荷平均を取得します。そのあと，インタセプタは最も負荷が軽いホスト上の複製に対するオブジェクトリファレンスを返します。インタセプタの記述の詳細については，「19.　ポータブルインタセプタの使用」を参照してください。

13.2　ロケーションサービスコンポーネント

ロケーションサービスはAgentインタフェースを介してアクセスできます。Agentインタフェースのメソッドは，二つのグループに分類できます。インスタンスを記述するデータをスマートエージェントに問い合わせるグループと，トリガーの登録や登録解除を行うグループです。トリガーは，ロケーションサービスのクライアントにインスタンスの可用性の変更を通知する通知機能を提供します。

13.2.1　ロケーションサービスエージェントとは

ロケーションサービスエージェントは，スマートエージェントのネットワークに接続されたオブジェクトを探索するメソッドの集まりです。IRのIDに基づいて，またはIRのIDとインスタンス名の組み合わせに基づいて問い合わせができます。問い合わせ結果はオブジェクトリファレンスとして，またはより詳細なインスタンスの情報として返されます。オブジェクトリファレンスは，スマートエージェントが見つけたオブジェクトの特定インスタンスのハンドルに過ぎません。インスタンス記述に含まれるのはオブジェクトリファレンス，インスタンスのインタフェース名，インスタンス名，ホスト名とポート番号，および状態に関する情報（実行中か活性化可能かなど）です。

注

該当するサービスはコアVisiBroker ORBに統合されたため，旧バージョンのようにlocserv実行形式ファイルはもう存在しません。

次のIDLサンプルが与えるIRのIDとインスタンス名の使用方法を図13-2に示します。

module Automobile {
         interface Car{...};
         interface Sedan:Car {...};
}

図13‒2　IRのIDとインスタンス名の使用

図13-3は，図13-2の例を使って，ネットワーク上のスマートエージェントとCarのインスタンスのリファレンスをわかりやすく示したものです。この例では，Kerri's CarのインスタンスとTom's Carの二つの複製という三つのインスタンスがあります。

図13‒3　一つのインタフェースのインスタンスを持つネットワーク上のスマートエージェント

以降，Agentクラスが提供したメソッドを使用してBorland Enterprise Server VisiBrokerスマートエージェントの情報を問い合わせる方法を説明します。それぞれの照会メソッドは，失敗の理由を示すFail例外を発生させることができます。

(1)　スマートエージェントを実行するすべてのホスト名の取得

all_agent_locations()メソッドのHostnameSeq（C++）またはString[ ]（Java）を使用して，Borland Enterprise Server VisiBrokerスマートエージェントのホストとして動作しているサーバを見つけられます。図13-3の例では，このメソッドはAthenaとZeusという二つのサーバの名前を返します。

(2)　アクセス可能なすべてのインタフェースの検索

アクセス可能なインタフェースをすべて見つけるために，ネットワーク上のBorland Enterprise Server VisiBrokerスマートエージェントに問い合わせることができます。そのためにはall_repository_ids()メソッドのRepositoryIDSeq（C++），またはString[ ]（Java）を使用できます。図13-3の例では，このメソッドはCarとSedanという二つのインタフェースのリポジトリIDを返します。

注

旧バージョンのVisiBroker ORBでは，IDLインタフェース名を使用してインタフェースを識別していましたが，ロケーションサービスは，その代わりにリポジトリIDを使用します。この違いを説明すると，インタフェース名が::module1::module2::interfaceの場合，これに等しいリポジトリIDはIDL:module1/module2/interface:1.0です。図13-2の例では，CarのリポジトリIDはIDL:Automobile/Car:1.0，SedanのリポジトリIDはIDL:Automobile/Sedan:1.0になります。

(3)　あるインタフェースのインスタンスのリファレンスの取得

個々のインタフェースのすべての使用可能インスタンスを見つけるために，ネットワーク上のBorland Enterprise Server VisiBrokerスマートエージェントに問い合わせることができます。問い合わせる場合，表13-1または表13-2のメソッドのどれかを使用できます。

表13‒1　任意のインタフェースをインプリメントするオブジェクトのリファレンスの取得（C++）

メソッド

説明

CORBA::ObjectSeq* all_instances (const char*_repository_id)

このメソッドを使用すると，インタフェースのインスタンスのオブジェクトリファレンスが返されます。

DescSeq* all_instance_descs (const char*_repository_id)

このメソッドを使用すると，インタフェースのインスタンスのインスタンス記述が返されます。

表13‒2　任意のインタフェースをインプリメントするオブジェクトのリファレンスの取得（Java）

メソッド

説明

org.omg.CORBA.Object[ ] all_instances (String repository_id)

このメソッドを使用すると，インタフェースのインスタンスのオブジェクトリファレンスが返されます。

Desc[ ] all_instance_descs (String repository_id)

このメソッドを使用すると，インタフェースのインスタンスのインスタンス記述が返されます。

図13-3の例では，IDL:Automobile/Car:1.0というリクエストでどれかのメソッドを呼び出すと，Tom's Car on Athena，Tom's Car on ZeusおよびKerri's CarというCarインタフェースの三つのインスタンスが返されます。Tom's Carインスタンスは，二つの異なるスマートエージェントによって検索されるため，2度返されます。

(4)　あるインタフェースの同名インスタンスに対するリファレンスの取得

表13-3または表13-4のメソッドの一つを使用して，特定のインスタンス名があればそれをすべて返すようにネットワーク上のBorland Enterprise Server VisiBrokerスマートエージェントに問い合わせることができます。

表13‒3　あるインタフェースの同名インスタンスに対するリファレンス（C++）

メソッド

説明

CORBA::ObjectSeq* all_replica (const char*_repository_id, const char*_instance_name)

このメソッドを使用すると，インタフェースの同名インスタンスのオブジェクトリファレンスが返されます。

DescSeq all_replica_descs (const char*_repository_id, const char*_instance_name)

このメソッドを使用すると，インタフェースの同名インスタンスのインスタンス記述が返されます。

表13‒4　あるインタフェースの同名インスタンスに対するリファレンス（Java）

メソッド

説明

org.omg.CORBA Object[ ] all_replica (String repository_id, String instance_name)

このメソッドを使用すると，インタフェースの同名インスタンスのオブジェクトリファレンスが返されます。

Desc[ ] all_replica_descs (String repository_id, String instance_name)

このメソッドを使用すると，インタフェースの同名インスタンスのインスタンス記述が返されます。

図13-3の例では，リポジトリIDにIDL:Automobile/Sedan:1.0を，インスタンス名にTom's Carを指定してどれかのメソッドを呼び出すと，二つのインスタンスが返されます。これは，二つの異なるスマートエージェントによってインスタンスが発生するためです。

13.2.2　トリガーとは何か

トリガーとは本来，指定されたインスタンスの使用の可否をユーザに判定させるコールバック機能です。トリガーはAgentのポーリングの非同期な代替手段で，通常はオブジェクトとのコネクションが絶たれたあとの回復に使用されます。問い合わせはさまざまな方法で行われますが，トリガーは特殊な用途です。

(1)　トリガーメソッドの考察

Agentクラスのトリガーメソッドについて表13-5および表13-6に示します。

表13‒5　トリガーメソッド（C++）

メソッド

説明

void reg_trigger (const TriggerDesc& _desc,

TriggerHandler_ptr _handler);

このメソッドはトリガーハンドラを登録するために使用します。

void unreg_trigger (const TriggerDesc& _desc,

TriggerHandler_ptr _handler)

このメソッドはトリガーハンドラの登録を解除するために使用します。

表13‒6　トリガーメソッド（Java）

メソッド

説明

void reg_trigger (

com.inprise.vbroker.ObjLocation.TriggerDesc desc,com.inprise.vbroker.ObjLocation.TriggerHandler handler)

このメソッドはトリガーハンドラを登録するために使用します。

void unreg_trigger (

com.inprise.vbroker.ObjLocation.TriggerDesc desc,com.inprise.vbroker.ObjLocation.TriggerHandler handler)

このメソッドはトリガーハンドラの登録を解除するために使用します。

どちらのAgentトリガーメソッドも，失敗の理由を示すFail例外を発生させることができます。

TriggerHandlerインタフェースは，表13-7および表13-8で説明するメソッドで構成されます。

表13‒7　TriggerHandlerインタフェースメソッド（C++）

メソッド

説明

void impl_is_ready(const Desc& _desc);

このメソッドは，descに一致するインスタンスがアクセス可能になると，ロケーションサービスによって呼び出されます。

void impl_is_down(const Desc& _desc )

このメソッドは，インスタンスが使用不能になると，ロケーションサービスによって呼び出されます。

表13‒8　TriggerHandlerインタフェースメソッド（Java）

メソッド

説明

void impl_is_ready (

com.inprise.vbroker.ObjLocation.TriggerDesc desc)

このメソッドは，descに一致するインスタンスがアクセス可能になると，ロケーションサービスによって呼び出されます。

void impl_is_down (

com.inprise.vbroker.ObjLocation.TriggerDesc desc)

このメソッドは，インスタンスが使用不能になると，ロケーションサービスによって呼び出されます。

(2)　トリガーの生成

TriggerHandlerはコールバックオブジェクトです。TriggerHandlerをインプリメントするには，TriggerHandlerPOAクラスから派生させ，そのimpl_is_ready()メソッドとimpl_is_down()メソッドをインプリメントします。ロケーションサービスにトリガーを登録するには，Agentインタフェースのreg_trigger()メソッドを使用します。このメソッドには，監視したいインスタンスを記述し，インスタンスの可用性が変化した場合に呼び出したいTriggerHandlerオブジェクトを指定する必要があります。インスタンス記述（TriggerDesc）には，リポジトリID，インスタンス名，ホスト名などのインスタンス情報の組み合わせを入れることができます。提供するインスタンス情報が詳細であればあるほど，インスタンスの仕様も特定化できます。

IDLサンプル13-2　TriggerDescのIDL

struct TriggerDesc {
    string repository_id;
    string instance_name;
    string host_name;
};

注

TriggerDescのフィールドに空の文字列（""）を設定すると，このフィールドは無視されます。各フィールドのデフォルト値は空の文字列です。

例えば，リポジトリIDしか持たないTriggerDescは，そのインタフェースのどのインスタンスにも一致します。図13-3の例に戻ると，IDL:Automobile/Car:1.0のどのインスタンスのトリガーも，Tom's Car on Athena，Tom's Car on Zeus，Kerri's Carというインスタンスのうちの一つが使用可能または使用不能になるとして発生します。ただし，TriggerDescに「Tom's Car」というインスタンス名を追加すると，二つの「Tom's Car」というインスタンスのどちらかの可用性が変化する場合だけトリガーが発生するように指定を厳しくします。最後にAthenaというホスト名を追加すると，AthenaサーバのTom's Carインスタンスが使用可能または使用不能になる場合に限りトリガーが発生するように，トリガーをさらに改善できます。

(3)　トリガーが検出した最初のインスタンスだけを確認

トリガーは何度も呼び出されるものです。TriggerHandlerは，トリガー記述に合致するオブジェクトがアクセス可能になるたびに呼び出されます。最初のインスタンスがアクセス可能になる場合だけを知りたいときがあるでしょう。この場合には，このようなインスタンスの存在が最初に見つかったあと，Agentのunreg_trigger()メソッドを呼び出してトリガーを登録解除します。

13.3　Agentの問い合わせ

この節では，ロケーションサービスを使用してインタフェースのインスタンスを見つける二つのサンプルを示します。最初のサンプルでは，次のIDLの抜粋部分のようなAccountインタフェースを使用します。

IDLサンプル13-3　Accountインタフェース定義の例

//Bank.idl
module Bank {
   interface Account {
      float balance();
   };
   interface AccountManager {
      Account open (in string name);
   };
};

13.3.1　あるインタフェースのすべてのインスタンスの検索

コードサンプル13-1および13-2は，all_instances()メソッドを使用してAccountインタフェースのすべてのインスタンスを探します。スマートエージェントへの問い合わせは，ORB::resolve_initial_references()メソッド（C++）またはORB.resolve_initial_references()メソッド（Java）に「LocationService」を渡し，そのメソッドが返したオブジェクトをObjLocation::Agent（C++）またはObjLocation.Agent（Java）にナロウすることによって行われることに注意してください。またAccountリポジトリIDのフォーマットはIDL:Bank/Account:1.0であることにも注意してください。

コードサンプル13-1　AccountManagerインタフェースの要求を満たすすべてのインスタンスの検索（C++）

#include "corba.h"
#include "locate_c.hh"

// USE_STD_NS is a define setup by VisiBroker to use the std
// namespace USE_STD_NS

int main(int argc, char** argv)
{
   try {
      // ORB initialization
      CORBA::ORB_var the_orb = CORBA::ORB_init(argc, argv);
      // Obtain a reference to the Location Service
      CORBA::Object_var obj = the_orb->
         resolve_initial_references("LocationService");
      if ( CORBA::is_nil(obj) ) {
         cout << "Unable to locate initial LocationService"
               << endl;
         return 0;
      }
      ObjLocation::Agent_var the_agent =
            ObjLocation::Agent::_narrow(obj);
      // Query the Location Service for all implementations of
      // the Account interface
      ObjLocation::ObjSeq_var accountRefs =
         the_agent->all_instances(
         "IDL:Bank/AccountManager:1.0");
      cout << "Obtained " << accountRefs->length()
            << "Account objects" << endl;
      for (CORBA::ULong i=0; i < accountRefs->length(); i++) {
         cout << "Stringified IOR for account #"<< i << ":"
               << endl;
         CORBA::String_var stringified_ior(
               the_orb->object_to_string(accountRefs[i]));
         cout << stringified_ior << endl;
         cout << endl;
      }
   } catch (const CORBA::Exception& e) {
      cout << "Caught exception: " << e << endl;
      return 0;
   }
   return 1;
}

コードサンプル13-2　AccountManagerインタフェースの要求を満たすすべてのインスタンスの検索（Java）

// AccountFinder.java
public class AccountFinder {
   public static void main(String[ ] args){
   try {
      // Initialize the ORB.
      org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);
      com.inprise.vbroker.ObjLocation.Agent the_agent = null;
      try {
         the_agent =
             com.inprise.vbroker.ObjLocation.AgentHelper.narrow(
             orb.resolve_initial_references("LocationService"));
      } catch (org.omg.CORBA.ORBPackage.InvalidName e){
         System.out.println(
            "Not able to resolve references " +
            "for LocationService");
         System.exit(1);
      } catch (Exception e){
         System.out.println(
            "Unable to locate LocationService!");
         System.out.println("Caught exception: " + e);
         System.exit(1);
      }
      org.omg.CORBA.Object[ ] accountRefs =
         the_agent.all_instances(
                      "IDL:Bank/AccountManager:1.0");
      System.out.println("Agent returned " +
         accountRefs.length  +
         "object references");
      for (int i=0; i <accountRefs.length; i++){
         System.out.println(
             "Stringified IOR for account #" + (i+1) + ":");
         System.out.println(orb.object_to_string(
                                           accountRefs[i]));
         System.out.println();
      }
   }catch (Exception e){
      System.out.println("Caught exception: " + e);
      System.exit(1);
   }
}
}

13.3.2　スマートエージェントが認識するものをすべて検索

コードサンプル13-3および13-4は，スマートエージェントが認識するものをすべて検索する方法を示します。これにはまず，all_repository_ids()メソッドを呼び出して，既知のインタフェースをすべて取得します。次に，all_instances_descs()メソッドをインタフェースごとに呼び出して，インスタンス記述を取得します。

コードサンプル13-3　スマートエージェントが認識するものをすべて検索（C++）

#include "corba.h"

#include "locate_c.hh"

// USE_STD_NS is a define setup by VisiBroker to use
// the std namespace if it exists
USE_STD_NS

int DisplaybyRepID(CORBA::ORB_ptr the_orb,
         ObjLocation::Agent_var the_agent,
         char * myRepId){
   ObjLocation::ObjSeq_var accountRefs;
   accountRefs = the_agent->all_instances(myRepId);
   cout << "Obtained " << accountRefs->length() <<
         "Account objects" << endl;
   for (CORBA::ULong i=0; i < accountRefs->length(); i++) {
      cout << "Stringified IOR for account #" << i << ":"
            << endl;
      CORBA::String_var stringified_ior(
            the_orb->object_to_string(accountRefs[i]));
      cout << stringified_ior << endl;
      cout << endl;
   }
   return(1);
}
void PrintUsage(char * name) {
   cout << "¥nUsage: ¥n" << endl;
   cout << "¥t" << name << " [Rep ID]" << endl;
   cout << "¥n¥tWith no argument,
         finds and prints all objects" << endl;
   cout << "¥tOptional rep ID searches for
         specific rep ID¥n" << endl;
}
int main(int argc, char** argv) {
   char myRepId[255] = "";
   if (argc == 2) {
      if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "/?") ||
            !strcmp(argv[1], "-?") ){
         PrintUsage(argv[0]);
         exit(0);
      } else {
         strcpy(myRepId, argv[1]);
      }
   }
   else if (argc > 2) {
      PrintUsage(argv[0]);
      exit(0);
   }
   try {
      CORBA::ORB_ptr the_orb = CORBA::ORB_init(argc, argv);
      CORBA::Object_ptr obj = the_orb->
      resolve_initial_references("LocationService");
      if ( CORBA::is_nil(obj) ) {
         cout << "Unable to locate initial LocationService"
               << endl;
         return 0;
      }
      ObjLocation::Agent_var the_agent =
            ObjLocation::Agent::_narrow(obj);
      ObjLocation::DescSeq_var descriptors;

      //Display stringified IOR for RepID requested and exit
      if (argc == 2) {
         DisplaybyRepID(the_orb, the_agent, myRepId);
         exit(0);
      }
      //Report all hosts running osagents
      ObjLocation::HostnameSeq_var HostsRunningAgents =
            the_agent->all_agent_locations();
      cout << "Located " << HostsRunningAgents->length() <<
            "Hosts running Agents" << endl;
      for (CORBA::ULong k=
            0; k<HostsRunningAgents->length(); k++){
         cout << "¥tHost #" << (k+1) << ": " <<
               (const char*) HostsRunningAgents[k] << endl;
      }
      cout << endl;

      // Find and display all Repository Ids
      ObjLocation::RepositoryIdSeq_var repIds =
            the_agent->all_repository_ids();
      cout << "Located " << repIds->length() <<
            " Repository Ids" << endl;
      for (CORBA::ULong j=0; j<repIds->length(); j++) {
         cout << "¥tRepository ID #" << (j+1) << ": " <<
               repIds[j] << endl;
      }
      // Find all Object Descriptors for each Repository Id
      for (CORBA::ULong i=0; i < repIds->length(); i++) {
         descriptors =
               the_agent->all_instances_descs(repIds[i]);
         cout << endl;
         cout << "Located " << descriptors->length()
               << " objects for " << (const char*) (repIds[i])
               << " (Repository Id #" << (i+1) << "):" <<endl;
         for (CORBA::ULong j=0; j < descriptors->length(); j++){
            cout << endl;
            cout << (const char*) repIds[i] << " #"
                  << (j+1) << ":" << endl;
            cout << "¥tInstance Name ¥t=
                  " << descriptors[j].instance_name << endl;
            cout << "¥tHost ¥t=
                  " << descriptors[j].iiop_locator.host << endl;
            cout << "¥tPort ¥t=
                  " << descriptors[j].iiop_locator.port << endl;
            cout << "¥tAgent Host ¥t=
                  " << descriptors[j].agent_hostname << endl;
            cout << "¥tActivable ¥t="
               << (descriptors[j].activable?"YES":"NO") << endl;
         }
      }
   } catch (const CORBA::Exception& e) {
      cout << "CORBA Exception during execution of find_all: "
            << e << endl;
      return 0;
   }
   return 1;
}

コードサンプル13-4　スマートエージェントが認識するものをすべて検索（Java）

// Find.java
public class Find {
public static void main(String[ ] args){
   try {
      // Initialize the ORB.
      org.omg.CORBA.ORB orb =
                       org.omg.CORBA.ORB.init(args,null);
      com.inprise.vbroker.ObjLocation.Agent agent = null;
      try {
         agent =
         com.inprise.vbroker.ObjLocation.AgentHelper.narrow(
         orb.resolve_initial_references("LocationService"));
      } catch (org.omg.CORBA.ORBPackage.InvalidName e){
         System.out.println(
            "Not able to resolve references " +
            "for LocationService");
      System.exit(1);
      } catch (Exception e){
         System.out.println(
            "Not able to resolve references " +
            "for LocationService");
         System.out.println("Caught exception: " + e);
         System.exit(1);
      }
      boolean done=false;
      java.io.BufferedReader in =
         new java.io.BufferedReader(
            new java.io.InputStreamReader(System.in));
      while (!done){
         System.out.print("-> ");
         System.out.flush();
         String line = in.readLine();
         if(line.startsWith("agents")){
            java.lang.String[ ] agentList =
                                agent.all_agent_locations();
            System.out.println(
                 "Located " + agentList.length  + "agents");
            for (int i=0; i < agentList.length; i++){
               System.out.println("¥t" + "Agent #" +
                  (i+1) + ": " + agentList[i]);
            }
         }else if(line.startsWith("rep")){
           java.lang.String[ ] repIds =
                                 agent.all_repository_ids();
           System.out.println("Located " + repIds.length  +
                              "repository Ids");
           for (int i=0; i <repIds.length; i++){
              System.out.println("¥t" + "Repository Id #"
                                 + (i+1) + ": " + repIds[i]);
           }
         } else if(line.startsWith("objects ")){
            String names = line.substring(
                         "objects ".length(), line.length());
            PrintObjects(names,agent,orb);
         } else if(line.startsWith("quit")){
            done = true;
         } else {
            System.out.println("Commands: agents¥n" +
               "          repository_ids¥n" +
               "          objects <rep Id>¥n" +
               "          objects <rep Id><obj name>¥n" +
               "          quit¥n");
         }
      }
   } catch (com.inprise.vbroker.ObjLocation.Fail err){
      System.out.println(
          "Location call failed with reason " + err.reason);
   } catch (java.lang.Exception err){
      System.out.println("Caught error " + err);
      err.printStackTrace();
   }
}
public static void PrintObjects(String names,
               com.inprise.vbroker.ObjLocation.Agent agent,
               org.omg.CORBA.ORB orb)
      throws com.inprise.vbroker.ObjLocation.Fail {
   int space_pos = names.indexOf(' ');
   String repository_id;
   String object_name;
   if (space_pos == -1){
      repository_id = names;
      object_name = null;
   }else {
      repository_id = names.substring(0,names.indexOf(' '));
      object_name = names.substring(names.indexOf(' ') + 1);
   }
   org.omg.CORBA.Object[ ] objects;
   com.inprise.vbroker.ObjLocation.Desc[ ] descriptors;
   if (object_name == null){
      objects = agent.all_instances(repository_id);
      descriptors =
         agent.all_instances_descs(repository_id);
   }else {
      objects =
               agent.all_replica(repository_id,object_name);
               descriptors = agent.all_replica_descs(
                                 repository_id,object_name);
   }
   System.out.println(
                 "Returned " + objects.length  + " objects");
   for (int i=0; i<objects.length; i++){
      System.out.println("¥n¥nObject #" + (i+1) + ":");
      System.out.println("==================");
      System.out.println("¥tRep ID: " +
                         ((com.inprise.vbroker.CORBA.Object)
                              objects[i])._repository_id());
      System.out.println("¥tInstance:" +
                         ((com.inprise.vbroker.CORBA.Object)
                                objects[i])._object_name());
      System.out.println(
               "¥tIOR: " + orb.object_to_string(objects[i]));
      System.out.println();
      System.out.println("Descriptor #" + (i+1));
      System.out.println(
                   "=====================================");
      System.out.println(
                "Host:" + descriptors[i].iiop_locator.host);
      System.out.println(
                "Port:" + descriptors[i].iiop_locator.port);
      System.out.println(
             "Agent Host:" + descriptors[i].agent_hostname);
      System.out.println(
           "Repository Id:" + descriptors[i].repository_id);
      System.out.println(
                "Instance:" + descriptors[i].instance_name);
      System.out.println(
                   "Activable:" + descriptors[i].activable);
   }
}
}

13.4　トリガーハンドラの記述と登録

ここでは，トリガーのインプリメントおよび登録の方法を示します。

13.4.1　トリガーハンドラのインプリメントと登録

コードサンプル13-5および13-6では，TriggerHandlerのインプリメントと登録をします。TriggerHandlerImplのimpl_is_ready()メソッドとimpl_is_down()メソッドは，トリガーを起動する原因となったインスタンスの記述を表示し，オプションとしてそれ自体の登録を解除します。

C++の場合

登録が解除されると，メソッドはプログラムを終了するためにCORBA::ORB::shutdown()メソッドを呼び出します。このメソッドは，メインプログラムのimpl_is_ready()メソッドを終了するためにBOAに転送されます。

Javaの場合

登録が解除されると，メソッドはプログラムを終了するためにSystem.exit()メソッドを呼び出します。

TriggerHandlerImplクラスは，このクラスの生成に使われたdescパラメタとAgentパラメタのコピーを保持していることに注意してください。unreg_trigger()メソッドにはdescパラメタが必要です。Agentパラメタは，メインプログラムからのリファレンスが解放された場合に備えて複製されています。

コードサンプル13-5　トリガーハンドラのインプリメント（C++）

// AccountTrigger.c
#include "locate_s.hh"

// USE_STD_NS is a define set up by VisiBroker to use the
// std namespace USE_STD_NS Instances of this class
// will be called back by the Agent when the
// event for which it is registered happens.

class TriggerHandlerImpl :
      public _sk_ObjLocation::_sk_TriggerHandler
{
   public:
      TriggerHandlerImpl(
           ObjLocation::Agent_var agent,
           const ObjLocation::TriggerDesc& initial_desc)
           : _agent(ObjLocation::Agent::_duplicate(agent)),
           _initial_desc(initial_desc) {}

      void impl_is_ready(const ObjLocation::Desc& desc) {
         notification(desc, 1);
      }
      void impl_is_down(const ObjLocation::Desc& desc){
         notification(desc, 0);
      }

   private:
      void notification(const ObjLocation::Desc& desc,
                CORBA::Boolean isReady){
         if (isReady) {
            cout << "Implementation is ready:" << endl;
         } else {
            cout << "Implementation is down:" << endl;
         }
         cout << "¥tRepository Id =
               " << desc.repository_id << endl;
         cout << "¥tInstance Name =
               " << desc.instance_name << endl;
         cout << "¥tHost Name =
               " << desc.iiop_locator.host << endl;
         cout << "¥tPort =
               " << desc.iiop_locator.port << endl;
         cout << "¥tAgent Host =
               " << desc.agent_hostname << endl;
         cout << "¥tActivable =
               " << (desc.activable? "YES" : "NO") << endl;
         cout << endl;
         cout << "Unregister this handler and exit (yes/no)? "
               << endl;
         char prompt [256];
         cin >> prompt;
         if ((prompt[0] == 'y') || (prompt[0] == 'Y')) {
            try {
               _agent->unreg_trigger(_initial_desc, this);
            }
            catch (const ObjLocation::Fail& e) {
               cout << "Failed to unregister trigger with
                  reason=[" << (int) e.reason << "]" << endl;
            }
            cout << "exiting..." << endl;
            CORBA::ORB::shutdown();
         }
      }

   private:
      ObjLocation::Agent_var _agent;
      ObjLocation::TriggerDesc _initial_desc;
};

int main(int argc,char* const *argv)
{
   try {
      CORBA::ORB_var the_orb = CORBA::ORB_init(argc, argv);
      CORBA::BOA_var boa = the_orb->BOA_init(argc, argv);
      CORBA::Object_var obj = the_orb->
      resolve_initial_references("LocationService");
      if ( CORBA::is_nil(obj) ) {
         cout << "Unable to locate initial LocationService"
               << endl;
         return 0;
      }
      ObjLocation::Agent_var the_agent =
            ObjLocation::Agent::_narrow(obj);

      // Create the trigger descriptor to notify us about
      // osagent changes with respect to Account objects
      ObjLocation::TriggerDesc desc;
      desc.repository_id = (const char*)
            "IDL:Bank/AccountManager:1.0";
      desc.instance_name = (const char*) "";
      desc.host_name = (const char*) "";

      ObjLocation::TriggerHandler_var trig =
            new TriggerHandlerImpl(the_agent, desc);
      boa->obj_is_ready(trig);
      the_agent->reg_trigger(desc,trig);
      boa->impl_is_ready();
   }
   catch (const CORBA::Exception& e) {
      cout << "account_trigger caught Exception: "
            << e << endl;
      return 0;
   }
   return 1;
}

コードサンプル13-6　トリガーハンドラのインプリメント（Java）

// AccountTrigger.java

import java.io.*;
import org.omg.PortableServer.*;

class TriggerHandlerImpl extends
      com.inprise.vbroker.ObjLocation.TriggerHandlerPOA {
   public TriggerHandlerImpl(
      com.inprise.vbroker.ObjLocation.Agent agent,
      com.inprise.vbroker.ObjLocation.TriggerDesc initial_desc){
         agent = agent;
         initial_desc = initial_desc;
   }
   public void impl_is_ready(
                 com.inprise.vbroker.ObjLocation.Desc desc){
                                    notification(desc, true);
   }
   public void impl_is_down(
                  com.inprise.vbroker.ObjLocation.Desc desc){
                                     notification(desc,false);
   }

   private void notification(
     com.inprise.vbroker.ObjLocation.Desc desc,
     boolean isReady){
      if (isReady){
         System.out.println("Implementation is ready:");
      } else {
         System.out.println("Implementation is down:");
      }
      System.out.println(
       "¥tRepository Id = " + desc.repository_id + "¥n" +
       "¥tInstance Name = " + desc.instance_name + "¥n" +
       "¥tHost Name     = " + desc.iiop_locator.host + "¥n" +
       "¥tActivable     = " + desc.activable + "¥n" + "¥n");
      System.out.println(
              "Unregister this handler and exit (yes/no)?");
      try {
         BufferedReader in = new BufferedReader(
                          new InputStreamReader(System.in));
         String line = in.readLine();
         if(line.startsWith("y") || line.startsWith("Y")) {
           try {
              agent.unreg_trigger(_initial_desc, _this());
           } catch (com.inprise.vbroker.ObjLocation.Fail e){
              System.out.println(
                "Failed to unregister trigger with reason=[" +
                e.reason + "]");
           }
            System.out.println("exiting...");
            System.exit(0);
           }
      } catch (java.io.IOException e){
         System.out.println(
               "Unexpected exception caught: " + e);
         System.exit(1);
      }
   }

   private com.inprise.vbroker.ObjLocation.Agent _agent;
   private com.inprise.vbroker.ObjLocation.TriggerDesc
                                           _initial_desc;
}

public class AccountTrigger {

   public static void main(String args[ ]){
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);
         POA rootPoa = POAHelper.narrow(
                 orb.resolve_initial_references("RootPOA"));
         rootPoa.the_POAManager().activate();
         com.inprise.vbroker.ObjLocation.Agent the_agent =
         com.inprise.vbroker.ObjLocation.AgentHelper.narrow(
         orb.resolve_initial_references("LocationService"));
         // Create a trigger description and an appropriate
         // TriggerHandler. The TriggerHandler will be
         // invoked when the osagent become aware of any
         // new implementations of the interface
         // "Bank::AccountManager"
         com.inprise.vbroker.ObjLocation.TriggerDesc desc =
           new com.inprise.vbroker.ObjLocation.TriggerDesc(
                       "IDL:Bank/AccountManager:1.0", "", "");
         TriggerHandlerImpl trig =
                     new TriggerHandlerImpl(the_agent, desc);
         rootPoa.activate_object(trig);
         the_agent.reg_trigger(desc, trig._this());
         orb.run();
      }catch (Exception e){
         e.printStackTrace();
         System.exit(1);
      }
   }
}

14　ネーミングサービスの使用

この章ではOMGの「インターオペラブルネーミング仕様」ドキュメント（formal/02-09-02）の完全なインプリメンテーションであるBorland Enterprise Server VisiBrokerネーミングサービスの使用方法について説明します。

14.1　概要

ネーミングサービスによって，一つ以上の論理名称を一つのオブジェクトリファレンスに対応させ，これらの名前をネームスペースに格納できるようになります。また，クライアントアプリケーションはネーミングサービスを使用して，オブジェクトに割り当てられた論理名称を使用してオブジェクトリファレンスを取得できます。

図14-1に，次の内容のネーミングサービス簡略図を示します。

オブジェクトインプリメンテーションが，どのようにして名前をネームスペース内のオブジェクトの一つにバインドできるか。

クライアントアプリケーションが，ネーミングコンテキストまたはオブジェクトにオブジェクトリファレンスを返す名前を解決するために，どのように同じネームスペースを使用できるか。

図14‒1　ネームスペース内のネーミングコンテキストからのオブジェクト名のバインド，解決，使用

Borland Enterprise Server VisiBrokerネーミングサービスを使用してオブジェクトインプリメンテーションを探す場合は，スマートエージェントを使用した場合と比べて考慮しなくてはならない相違点が幾つかあります。

スマートエージェントはフラットなネームスペースを使用しますが，ネーミングサービスは階層形式のものを使用します。

C++の場合に，スマートエージェントを使用するとき，オブジェクトのインタフェース名は，クライアントアプリケーションとサーバアプリケーションのコンパイル時に定義されます。インタフェース名を変更するにはアプリケーションを再度コンパイルしなければなりません。これとは対照的に，ネーミングサービスでは，オブジェクトインプリメンテーションはランタイム時に論理名称とオブジェクトをバインドできます。

C++の場合に，スマートエージェントを使用するとき，オブジェクトは一つのインタフェース名しか実装できませんが，ネーミングサービスによって，一つ以上の論理名称を一つのオブジェクトにバインドできます。

Javaの場合，オブジェクトのインタフェース名は，クライアントアプリケーションとサーバアプリケーションのコンパイル時に定義されます。インタフェース名を変更するにはアプリケーションを再度コンパイルしなければなりません。これとは対照的に，ネーミングサービスでは，オブジェクトインプリメンテーションはランタイム時に論理名称とオブジェクトにバインドできます。

Javaの場合，オブジェクトは一つのインタフェース名しかインプリメントできませんが，ネーミングサービスによって，一つ以上の論理名称を一つのオブジェクトにバインドできます。

次のOSでは，ネーミングサービスを使用する場合，実行方法はvbjを使用せず，nameservプログラムを使用して起動させてください。

Windows Vista

Windows 7

Windows Server 2008

Windows Server 2008 R2

14.2　ネームスペースの解説

オーダーエントリシステムを構成する各オブジェクトに名前を付けるためにネーミングサービスをどのように使用できるかを，図14-2に示します。この階層オーダーエントリシステムのネームスペースは地域別，部署別などで構成されます。ネーミングサービスを使用すれば，特定名称を探す場合の検索対象にできるNamingContextオブジェクトの階層構造で，ネームスペースを構成できます。例えば，論理名称NorthAmerica/ShippingDepartment/Ordersを使用してOrderオブジェクトを探せます。

図14‒2　オーダーエントリシステムのネーミング手法

14.2.1　ネーミングコンテキスト

Borland Enterprise Server VisiBrokerネーミングサービスを使用して，図14-2に示したネームスペースをインプリメントするには，それぞれをNamingContextオブジェクトでインプリメントする必要があります。NamingContextオブジェクトには，オブジェクトインプリメンテーションに，またはほかのNamingContextオブジェクトにバインドされたName構造体のリストが入っています。論理名称はNamingContextにバインドできますが，デフォルトではNamingContextは対応する論理名称を持たず，またそのような名前も不要であるということを認識しておくことが大切です。

オブジェクトインプリメンテーションはNamingContextオブジェクトを使用して，提供するオブジェクトに名前をバインドします。クライアントアプリケーションはNamingContextを使用して，バインドされた名前をオブジェクトリファレンスへと解決します。

文字列化された名前を使用する場合に必要なメソッドを提供するNamingContextExtインタフェースも使用できます。

14.2.2　ネーミングコンテキストファクトリ

ネーミングコンテキストファクトリは，ネーミングサービスに接続するインタフェースを提供します。このファクトリはネーミングサービスを終了させたり，コンテキストがない場合に新しいコンテキストを生成するオペレーションを持ちます。各ファクトリは，ルートコンテキストを返すAPIも持っています。ルートコンテキストは情報を照会するために重要な役目を果たします。これは，参照可能なすべてのデータを格納するためのルートです。

Borland Enterprise Server VisiBrokerネーミングサービスには，デフォルトネーミングコンテキストファクトリと拡張ネーミングコンテキストファクトリという二つのクラスが提供され，これによってネームスペースが生成できるようになります。デフォルトネーミングコンテキストファクトリは，ルートNamingContextを持たない空のネームスペースを生成します。拡張ネーミングコンテキストファクトリはルートNamingContext付きのネームスペースを生成するので，こちらのネーミングコンテキストファクトリを使用することをお勧めします。

オブジェクトインプリメンテーションが名前をオブジェクトにバインドしたり，クライアントアプリケーションが名前をオブジェクトリファレンスへと解決したりするには，これらのNamingContextオブジェクトを最低一つは取得しなければなりません。

図14-2に示したNamingContextオブジェクトは，五つすべてを一つのネームサービスプロセス内でインプリメントすることもできるし，最大で五つのネームサービスプロセス内で別々にインプリメントすることもできます。

14.2.3　NameとNameComponent

CosNaming::Nameは，オブジェクトインプリメンテーションまたはCosNaming::NamingContextにバインドできる識別子を表します。Nameはただの英数文字列ではなく，一つ以上のNameComponent構造体のシーケンスです。

各NameComponentには，idとkindという二つの属性文字列が含まれます。それぞれのidとkindが任意のNamingContext内で一意であることを確認する場合以外は，ネーミングサービスはこれらの文字列の解釈や管理はしません。

id属性とkind属性は，名前がバインドされているオブジェクトを一意に識別するための文字列です。kindメンバは名前に詳細情報を付加します。例えば，「Inventory.RDBMS」という名前は「Inventory」というidメンバと「RDBMS」というkindメンバを持ちます。

IDLサンプル14-1　NameComponent構造体のIDL指定

module CosNaming {
   typedef string Istring;
   struct NameComponent {
      Istring id ;
      Istring kind ;
   };
   typedef sequence<NameComponent> Name ;
};

NameComponentのid属性とkind属性は，NULL文字（0x00）とそのほかの印刷不能文字を除いたISO 8859-1（Latin-1）文字セットの文字でなければなりません。NameComponentに指定する文字列は，どちらも255文字を超えてはいけません。さらに，ネーミングサービスはワイド文字を使用するNameComponentはサポートしません。

注

空文字列はNameのid属性には指定できませんが，kind属性には指定できます。

14.2.4　ネーム解決

クライアントアプリケーションは，NamingContextメソッドresolveを使用して，論理的なNameが与えられたオブジェクトリファレンスを取得します。Nameは一つ以上のNameComponentオブジェクトで構成されているので，解決プロセスは，Nameを構成するすべてのNameComponent構造体を調べなければなりません。

(1)　文字列化された名前

CosNaming::Name識別子は可読性やデータ交換に向かない形式です。この問題を解決するために，文字列化された名前が定義されています。文字列化された名前とは，文字列とCosNaming::Nameとの一対一のマッピングです。二つのCosNaming::Nameオブジェクトが等しければ，その文字列化された表記も等しく，これは逆の場合にも当てはまります。文字列化された名前では，スラント（/）はネームコンポーネントのセパレータとして，ピリオド（.）はid属性とkind属性のセパレータとして，¥記号はエスケープ文字としてそれぞれ使用されます。規定によって，空のkind属性を持ったNameComponentはピリオドを使用しません（Orderなど）。

コードサンプル14-1　文字列化された名前の例

"Borland.Company/Engineering.Department/Printer.Resource"

注

以降のサンプルでは，NameComponent構造体は文字列化された表記で示されます。

(2)　単純名と複合名

Billingのような単純名はNameComponentを一つしか持たないで，常にターゲットのネーミングコンテキスト上で解決されます。単純名はオブジェクトインプリメンテーションまたはNamingContextにバインドできます。

NorthAmerica/ShippingDepartment/Inventoryのような複合名は三つのNameComponent構造体のシーケンスで構成されます。n個のNameComponentオブジェクトで構成される複合名をオブジェクトインプリメンテーションにバインドすると，シーケンス内の最初の（n-1）個のNameComponentオブジェクトはそれぞれNamingContextへと解決され，最後のNameComponentオブジェクトはオブジェクトインプリメンテーションへと解決されなければなりません。

NameをNamingContextにバインドすると，シーケンス内の各NameComponent構造体はNamingContextを参照しなければなりません。

コードサンプル14-2は，三つのコンポーネントで構成され，CORBAオブジェクトにバインドされた複合名を示します。この名前に相当する文字列化された名前はNorthAmerica/SalesDepartment/Orderです。いちばん上のネーミングコンテキスト内で解決されると，この複合名の最初の二つのコンポーネントはNamingContextオブジェクトへと解決され，最後のコンポーネントは論理名称「Order」を持ったオブジェクトインプリメンテーションへと解決されます。

コードサンプル14-2　VisiBroker ORBオブジェクトにバインドされた複合名の例（C++）

. . .
// Name stringifies to "NorthAmerica/SalesDepartment/Order"
CosNaming::Name_var continentName =
      rootNamingContext->to_name("NorthAmerica");
CosNaming::NamingContext_var continentContext =
      rootNamingContext->bind_new_context(continentName);
CosNaming::Name_var departmentName =
      continentContext->to_name("SalesDepartment");
CosNaming::NamingContext_var departmentContext =
      continentContext->bind_new_context(departmentName);
CosNaming::Name_var objectName =
      departmentContext->to_name("Order");
departmentContext->rebind(objectName, myPOA->
      servant_to_reference(managerServant));
. . .

コードサンプル14-3　VisiBroker ORBオブジェクトにバインドされた複合名の例（Java）

. . .
// Name stringifies to "NorthAmerica/SalesDepartment/Order "
NameComponent[ ] continentName =
                     { new NameComponent("NorthAmerica", "")};
NamingContext continentContext =
          rootNamingContext.bind_new_context(continentName);
NameComponent[ ] departmentName =
                  { new NameComponent("SalesDepartment", "")};
NamingContext departmentContext =
          continentContext.bind_new_context(departmentName);
NameComponent[ ] objectName = { new NameComponent("Order", "")};
departmentContext.rebind(
     objectName, myPOA.servant_to_reference(managerServant));
. . .

14.3　ネーミングサービスの実行

ネーミングサービスは次に示すコマンドで起動できます。

14.3.1　ネーミングサービスのインストール

Borland Enterprise Server VisiBrokerをインストールすると，ネーミングサービスが自動的にインストールされます。ネーミングサービスは，Windowsではバイナリの実行形式ファイル，UNIXではスクリプトであるnameservファイルと，vbjorb.jarファイルに格納されているJavaクラスファイルで構成されています。

14.3.2　ネーミングサービスの設定

旧バージョンのVisiBroker Naming Serviceでは，ネーミングサービスは変更のあったすべてのオペレーションをフラットファイルへロギングすることによってパーシステンスを維持しました。バージョン4.0以降は，ネーミングサービスはバッキングストアアダプタと連携動作します。すべてのバッキングストアアダプタがパーシステンスをサポートしているわけではないことに注意してください。デフォルトのInMemoryアダプタは非パーシステントですが，ほかのアダプタはパーシステントです。アダプタの詳細については，「14.10　プラガブルバッキングストア」を参照してください。

注

ネーミングサーバは，起動時に自分自身をスマートエージェントに登録しなければなりません。したがって，ネーミングサービスを開始するためにスマートエージェントを先に実行しておく必要があります。これによって，クライアントはresolve_initial_referencesメソッドを呼び出すことでイニシャルルートコンテキストを検索できます。解決機能は，必要なリファレンスの検索のためにスマートエージェントを通して動作します。同様に，仕組みに加わっている各ネーミングサーバも，同じ機能を使用して仕組みをセットアップします。

14.3.3　ネーミングサービスの起動

binディレクトリにあるnameservプログラムを使用してネーミングサービスを起動できます。nameservは，デフォルトではcom.inprise.vbroker.naming.ExtFactoryファクトリクラスを使用します。ネーミングサービスのオプションを表14-1に示します。

UNIX

nameserv [driver_options] [nameserv_options] <ns_name> &

Windows

start nameserv [driver_options] [nameserv_options] <ns_name>

表14‒1　ネーミングサービスのオプション

オプション

説明

driver_options

（ファクトリ名の前に表示されなければなりません）

-J<Java option>

指定されたオプションをJavaVMに直接渡します。

-VBJversion

Borland Enterprise Server VisiBrokerのバージョン番号を出力します。

-VBJdebug

Borland Enterprise Server VisiBrokerのデバッグ情報を出力します。

nameserv_options

-?，-h，-help，-usage

使用情報を出力します。

-config <properties_file>

ネーミングサービス起動時に<properties_file>を構成ファイルとして使用します。このオプションで指定したファイル内では，「#」で始まる行はコメント行となり，無視されます。

<ns_name>

このネーミングサービスで使用する名前です。これは省略できます。デフォルト名はNameServiceです。

(1)　vbjによるネーミングサービスの起動（Java）

ネーミングサービスはvbjを使用しても起動できます。

prompt>vbj com.inprise.vbroker.naming.ExtFactory <ns_name>

14.4　コマンドラインからのネーミングサービスの呼び出し

ネーミングサービスユーティリティ（nsutil）は，コマンドラインにバインディングを格納したり，コマンドラインからバインディングを検索したりする機能を提供します。

14.4.1　nsutilの構成

nsutilを使用するには，まず次のどちらかを使用してネーミングサービスインスタンスを構成します。nsutilのオプションを表14-2に示します。

prompt>nameserve <factory_name>

または

prompt>nsutil -VBJprop <ns_config> <cmd>[args]

表14‒2　nsutilのオプション

オプション

説明

ns_config

SVCnameroot=<factory_name>

ORBInitRef=NameService=<url>

ファクトリ名を定義します。

注

SVCnamerootを使用するには，まずosagentを実行しなければなりません。

corbaloc:，corbaname:，file:，ftp:，http:，またはior:のような型を示すプリフィクスを付けたファイル名またはURL。例えば，ローカルディレクトリにファイルを割り当てるには，ns_config文字列は次のようになります。

-VBJprop ORBInitRef=NameService=<file:ns.ior>

cmd

pingとshutdownを加えたCosNaming オペレーションです。

14.4.2　nsutilの実行

ネーミングサービスユーティリティはすべてのCosNamingオペレーションと二つの追加コマンドをサポートします。サポートしているCosNamingオペレーションを表14-3に示します。

表14‒3　nsutilでサポートしているCosNamingオペレーション

cmd

パラメタ

bind

name objRef

bind_context

name objRef

bind_new_context

name ctxRef

destroy

name

list

name*

new_context

なし

rebind

name objRef

rebind_context

name ctxRef

resolve

name

unbind

name

追加のnsutilコマンドを表14-4に示します。表14-4のコマンドを実行するにはスマートエージェントを起動する必要があります。スマートエージェントの起動については，「4.7.1　スマートエージェントの起動」を参照してください。

表14‒4　nsutilの追加コマンド

cmd

パラメタ

説明

ping

name

文字列化されたnameを解決し，オブジェクトが活性であるかどうかを調べるためにオブジェクトとコンタクトします。

shutdown

factory_name

コマンドラインから正しい手順でネーミングサービスをシャットダウンします。factory_nameはネーミングサービスの起動時に指定した名前です。

注

このコマンドの起動では初期コンテキストを設定しておく必要はありません。

nsutilコマンドからオペレーションを実行するには，オペレーション名とそのパラメタを<cmd>パラメタとして設定してください。例を次に示します。

prompt>nsutil -VBJprop ORBInitRef=NameService=file://ns.¥
       ior resolve myName <factory_name>

14.4.3　nsutilのクローズ

nsutilをクローズするにはshutdownコマンドを使用してください。

prompt>nsutil -VBJprop ORBInitRef=NameService=file://ns.¥
       ior shutdown

14.5　ネーミングサービスへの接続

指定されたネーミングサービスからイニシャルオブジェクトリファレンスを取得できるようにクライアントアプリケーションを起動するには，3とおりの方法があります。ネーミングサービスを起動するときに，次の三つのコマンドラインオプションを使用できます。

ORBInitRef

ORBDefaultInitRef

DSVCnameroot

14.5.1　resolve_initial_referencesの呼び出し

新規のネーミングサービスが提供する単純な機能を使用すれば，共通ネーミングコンテキストを返すようにresolve_initial_referencesメソッドを設定できます。クライアントプログラムが接続しようとするネーミングサーバのルートコンテキストを返すresolve_initial_referencesメソッドを使用してください。これらの三つのオプションの使い方を，三つの簡単な例で説明します。TestHostというホストで実行中の三つのBorland Enterprise Server VisiBrokerネーミングサービス（ns1，ns2，ns3）があり，三つのサーバアプリケーション（sr1，sr2，sr3）がそれぞれホストTestHostの別々のポート（20001，20002，20003）で実行中の場合，サーバsr1はns1に，sr2はns2に，sr3はns3にバインドします。

コードサンプル14-4　ルートネーミングコンテキストの取得方法を示すコードの抜粋部分（C++）

. . .
   CORBA::ORB_ptr orb = CORBA::ORB_init(argv, argc, NULL);
   CORBA::Object_var rootObj =
         orb->resolve_initial_references("NameService");
. . .

コードサンプル14-5　ルートネーミングコンテキストの取得方法を示すコードの抜粋部分（Java）

. . .
   org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
   org.omg.CORBA.Object rootObj =
               orb.resolve_initial_references("NameService");
. . .

14.5.2　-DSVCnamerootの使用

-DSVCnamerootオプションを使用して，どのBorland Enterprise Server VisiBrokerネーミングサービスインスタンスへ接続したいかを指定できます（互いに無関係のネーミングサービスを複数実行している場合は特に重要です）。例えば，ns1へ接続したい場合は，次のようにクライアントアプリケーションを起動してください。

C++の場合

<client_application> -DSVCnameroot=ns1

Javaの場合

vbj -DSVCnameroot=ns1 <client_application>

これで，コードサンプル14-4および14-5で示したように，クライアントアプリケーション内部でORBリファレンスのresolve_initial_referencesメソッドを呼び出すことによって，ns1のルートコンテキストを取得できます。

注

このオプションを使用するには，osagentが実行中でなければなりません。

-DSVCnamerootオプションはosagentの機能に基づいており，ほかのCORBAインプリメンテーションとのインターオペラビリティがないことに注意してください。

14.5.3　-ORBInitRef（C++）および-DORBInitRef（Java）の使用

corbaloc URLまたはcorbaname URLネーミング機能を使用して，どのBorland Enterprise Server VisiBrokerネーミングサービスへ接続したいかを指定できます。

(1)　corbaloc URLの使用

ネーミングサービスns2を使用して接続したい場合は，次のようにクライアントアプリケーションを起動してください。

C++の場合

<client_application> -ORBInitRef NameService=
      corbaloc::TestHost:20002/NameService

Javaの場合

vbj -DORBInitRef=NameService=
   corbaloc::TestHost:20002/NameService <client_application>

これで，コードサンプル14-4および14-5で示したように，クライアントアプリケーション内部でVisiBroker ORBリファレンスのresolve_initial_referencesメソッドを呼び出すことによって，ns2のルートコンテキストを取得できます。

注

このサンプルは，アクセスしたいネーミングサービスにバインドされたポート20002で実行中のサーバがある場合だけ有効です。

ORBInitRefを使用し，corbalocを指定した場合，URL最後のNameService指定がないと，ArrayIndexOutOfBoundsException例外が発生します。

(2)　corbaname URLの使用

corbanameを使用してns3へ接続したい場合は，次のようにクライアントプログラムを起動してください。

C++の場合

<client_application> -ORBInitRef NameService=
      corbaname::TestHost:20003/

Javaの場合

vbj -DORBInitRef=NameService=corbaname::TestHost:20003/ <client_application>

これで，コードサンプル14-4および14-5で示したように，クライアントアプリケーション内部でVisiBroker ORBリファレンスのresolve_initial_referencesメソッドを呼び出すことによって，ns3のルートコンテキストを取得できます。

14.5.4　-ORBDefaultInitRef（C++）および-DORBDefaultInitRef（Java）

corbaloc URLまたはcorbaname URLを使用して，どのBorland Enterprise Server VisiBrokerネーミングサービスへ接続したいかを指定できます。

(1)　-ORBDefaultInitRef（C++）または-DORBDefaultInitRef（Java）とcorbaloc URLの使用

ns2へ接続したい場合は，次のようにクライアントプログラムを起動してください。

C++の場合

<client_application> -ORBDefaultInitRef corbaloc::TestHost:20002

Javaの場合

vbj -DORBDefaultInitRef=corbaloc::TestHost:20002 <client_application>

これで，コードサンプル14-4および14-5で示したように，クライアントアプリケーション内部でVisiBroker ORBリファレンスのresolve_initial_referencesメソッドを呼び出すことによって，ns2のルートコンテキストを取得できます。

(2)　-ORBDefaultInitRef（C++）または-DORBDefaultInitRef（Java）とcorbanameの使用

-ORBDefaultInitRef（C++）または-DORBDefaultInitRef（Java）とcorbanameを組み合わせると，予期したものとは異なる動作をします。-ORBDefaultInitRef（C++）または-DORBDefaultInitRef（Java）を指定すると，スラントと文字列化された，オブジェクトkeyが常にcorbanameに追加されます。

C++の場合

例えば，URL（corbaname::TestHost:20002）と指定してから-ORBDefaultInitRefと指定すると，resolve_initial_references（C++）の結果は新しいURL（corbaname::TestHost:20003/NameService）になります。

Javaの場合

例えば，URL（corbaname::TestHost:20002）と指定してから-DORBDefaultInitRefと指定すると，resolve_initial_references（Java）の結果は新しいURL（corbaname::TestHost:20003/NameService）になります。

14.6　NamingContext

このオブジェクトは，VisiBroker ORBオブジェクトまたはほかのNamingContextオブジェクトにバインドされている名前のリストを保持し操作するために使用します。クライアントアプリケーションは，このインタフェースを使用して，そのコンテキスト内のすべての名前を解決またはリスト出力します。オブジェクトインプリメンテーションは，このオブジェクトを使用して複数の名前をオブジェクトインプリメンテーションにバインドしたり一つの名前をNamingContextオブジェクトにバインドしたりします。IDLサンプル14-2に，NamingContextのIDL指定を示します。

IDLサンプル14-2　NamingContextインタフェースの指定

module CosNaming {
   interface NamingContext {
      void bind(in Name n,in Object obj)
         raises(NotFound, CannotProceed,
                InvalidName, AlreadyBound);
      void rebind(in Name n, in Object obj)
         raises(NotFound, CannotProceed, InvalidName);
      void bind_context(in Name n, in NamingContext nc)
         raises(NotFound, CannotProceed,
                InvalidName, AlreadyBound);
      void rebind_context(in Name n,in NamingContext nc)
         raises(NotFound, CannotProceed, InvalidName);
      Object resolve(in Name n)
         raises(NotFound, CannotProceed, InvalidName);
      void unbind(in Name n)
         raises(NotFound, CannotProceed, InvalidName);
      NamingContext new_context();
      NamingContext bind_new_context(in Name n)
         raises(NotFound, CannotProceed, InvalidName,
                AlreadyBound);
      void destroy()
         raises(NotEmpty);
      void list(in unsigned long how_many,
            out BindingList bl,
            out BindingIterator bi);
   };
};

14.7　NamingContextExt

NamingContextExtインタフェースはNamingContextの拡張であり，文字列化された名前とURLを使用する場合に必要なオペレーションを提供します。

IDLサンプル14-3　NamingContextExtインタフェースの指定

module CosNaming {
   interface NamingContextExt : NamingContext {
      typedef string StringName;
      typedef string Address;
      typedef string URLString;

      StringName to_string(in Name n)
         raises(InvalidName);
      Name to_name(in StringName sn)
         raises(InvalidName);

      exception InvalidAddress {};
      URLString to_url(in Address addr, in StringName sn)
         raises(InvalidAddress, InvalidName);
      Object resolve_str(in StringName n)
         raises(NotFound, CannotProceed, InvalidName);
   };
};

14.8　デフォルトネーミングコンテキスト

クライアントアプリケーションはデフォルトネーミングコンテキストを指定できますが，これはアプリケーションが自分のルートコンテキストとみなすネーミングコンテキストです。デフォルトネーミングコンテキストは，このクライアントアプリケーションに対してだけルートであり，実際にはほかのコンテキストに入っていてもかまいません。

14.8.1　デフォルトコンテキストの取得（C++）

VisiBroker ORBのresolve_initial_referencesメソッドを使用することによって，クライアントアプリケーションはデフォルトのネーミングコンテキストを取得できます。デフォルトのネーミングコンテキストは，クライアントアプリケーションの開始時にORBInitRefコマンドライン引数を渡すことで指定しておく必要があります。コードサンプル14-6に，C++クライアントアプリケーションがどのようにこのメソッドを起動するかを示します。

コードサンプル14-6　resolve_initial_referencesメソッドの起動

#include "CosNaming_c.hh"
. . .
int main(int argc, char* const* argv) {
   try {
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
      . . .
      CORBA::Object_var ref =
            orb->resolve_initial_references("NameService");
      CosNaming::NamingContext_var rootContext =
         CosNaming::NamingContext::_narrow(ref);
      . . .
   } catch(const CORBA::Exception& e) {
      cout << "Failure: " << e << endl;
      exit(1);
   }
   exit(0);
}

14.8.2　デフォルトネーミングコンテキストの取得（Java）

ORBインタフェースのresolve_initial_referencesメソッドを使用することによって，Javaクライアントアプリケーションをネーミングサービスに接続できます。この機能を使用するには，クライアントの起動時にSVCnamerootパラメタを指定しなければなりません。

例えば，ネーミングコンテキストInventoryを自分のデフォルトネーミングコンテキストとして使用することになっているClientApplicationというJavaアプリケーションを起動するには，次のコマンドを入力できます。

prompt> vbj -DSVCnameroot=¥
        NorthAmerica/ShippingDepartment/Inventory    ¥
        ClientApplication

このサンプルで，NorthAmericaはサーバ名，ShippingDepartment/Inventoryはルートコンテキストから文字列化された名前です。

注

vbjコマンドを使用するときは，すべての-DプロパティをJavaクラス名の前に指定しなければなりません。

14.9　ネーミングサービスプロパティ

ネーミングサービスプロパティを表14-5に示します。

表14‒5　ネーミングサービスプロパティ

プロパティ

デフォルト

説明

vbroker.naming.adminPwd

inprise

VisiBroker管理ネーミングサービスオペレーションで必要なパスワードです。

vbroker.naming.enableClusterFailover

true

trueに設定すると，ネーミングサービスから取得されたオブジェクトのフェールオーバーを処理するインタセプタをインストールすることを指定します。オブジェクト障害の場合，元のクラスタと同じクラスタから別のオブジェクトに透過的に再接続するよう試みます。

vbroker.naming.enableSlave

0

trueの場合，マスタ／スレーブネーミングサービス構成を有効にします。マスタ／スレーブネーミングサービスの構成については，「14.12　フェールオーバー」を参照してください。

vbroker.naming.iorFile

ns.ior

ネーミングサービスIORを格納する完全パス名を指定します。このプロパティを設定しないと，ネーミングサービスはカレントディレクトリのns.iorという名前のファイルにIORを出力しようとします。IORを出力しようとすると，ネーミングサービスはファイルアクセス権限例外を透過的に無視します。

vbroker.naming.LogLevel

emerg

ネーミングサービスから出力されるログメッセージのレベルを指定します。

vbroker.naming.propBindOn

0

trueの場合は，暗黙的なクラスタリング機能がオンになります。

vbroker.naming.smrr.pruneStaleRef

1

このプロパティは，ネームサービスクラスタがスマートラウンドロビン方法を使用する場合に関連してきます。このプロパティに1を設定した場合，以前スマートラウンドロビン方法でクラスタにバインドされた古いオブジェクトリファレンスをネームサービスが探索すると，それがバインディングから削除されます。このプロパティに0を設定した場合，クラスタ下の古いオブジェクトリファレンスバインディングは削除されません。ただし，スマートラウンドロビン方法を用いたクラスタは，常に，vbroker.naming.smrr.pruneStaleRefプロパティの値に関係なく，このようなオブジェクトバインディングがある場合に，resolve()メソッドまたはselect()メソッド呼び出し時にアクティブなオブジェクトリファレンスを戻します。デフォルトでは，ネームサービス4.5の暗黙的なクラスタリングはプロパティ値を1に設定してスマートラウンドロビン方法を使用します。

14.10　プラガブルバッキングストア

旧バージョンのネーミングサービスでは，ネームスペース（つまりネーミングコンテキストとオブジェクト−名前のバインディングの集合）をメモリに保存し，変更できるすべてのオペレーションをネームスペースからロギングファイルへロギングしました。そして，前回のネームスペースを再生成するためにネーミングサービスを起動するときに，このフラットファイルを使用できました。

現在のネーミングサービスは，プラガブルバッキングストアを使用してネームスペースを維持します。ネームスペースがパーシステントかどうかは，どのようにバッキングストアを設定するか，つまりJDBCアダプタ，Java Naming and Directory Interface（LDAP用に認証されたJNDI），デフォルトのインメモリアダプタのどれを使用するかに左右されます。

14.10.1　バッキングストアのタイプ

サポートしているバッキングストアアダプタは4タイプあります。

インメモリアダプタ

リレーショナルデータベースのJDBCアダプタ

DataExpressアダプタ

JNDI（LDAPだけ）アダプタ

注

プラガブルバッキングストアアダプタの使用例については，Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/ins/pluggable_adaptors内のコードを参照してください。

(1)　インメモリアダプタ

インメモリアダプタは，ネームスペース情報をメモリに保管し，パーシステントではありません。これはネーミングサービスがデフォルトで使用するアダプタです。

(2)　JDBCアダプタ

リレーショナルデータベースはJDBCを介してサポートされます。次に示すデータベースがネーミングサービスJDBCアダプタの処理用に認証されています。

JDataStore

Oracle

Sybase

Microsoft SQL Server

DB2

Interbase

(3)　DataExpressアダプタ

二つのJDBCアダプタに加えて，JDataStoreデータベースにネイティブにアクセスできるようにするDataExpressアダプタがあります。JDBCを介してJDataStoreにアクセスするよりも速いのですが，DataExpressアダプタには幾つかの制限事項があります。このアダプタはネーミングサーバと同じマシンで実行中のローカルデータベースだけをサポートします。リモートJDataStoreデータベースにアクセスするには，JDBCアダプタを使用する必要があります。

(4)　JNDIアダプタ

JNDIアダプタもサポートされています。SunのJNDIは，企業全体の複数のネーミングおよびディレクトリサービスとの標準インタフェースを提供します。JNDIは，別々のネーミングベンダとサービスベンダが準拠しなければならないSPI（サービスプロバイダインタフェース）を持ちます。Netscape LDAPサーバ，Novell NDS，WebLogic Tengahなどで別々のSPIモジュールを使用できます。JNDIをサポートすることによって，Borland Enterprise Server VisiBrokerネーミングサービスはこれらのネーミングおよびディレクトリサービス，ならびにそのほかの将来のSPIプロバイダへのポータブルアクセスをできるようにします。ただし，JNDIアダプタはNetscape LDAPサーバ4.0専用に認証されています。

14.10.2　構成と使用

バッキングストアアダプタを接続できます。つまり，使用するアダプタの型を，ネーミングサービスの起動時に使用する構成（プロパティ）ファイルにユーザ定義情報として格納して指定できます。インメモリアダプタを除くすべてのアダプタはパーシステントです。ネームスペース全体をメモリに保管するライトウェイトのネーミングサービスを使用したい場合には，インメモリアダプタを使用してください。

注

最新バージョンのネーミングサービスでは，ネーミングサービスの実行中は設定を変更できません。設定を変更するには，必ずサービスを停止し，構成ファイルを変更してからネーミングサービスを再起動してください。

(1)　プロパティファイル

そのほかの多くのネーミングサービスと同様，どのアダプタを使用するかや，その個々の構成などはネーミングサービスのプロパティファイルで処理されます。デフォルトのプロパティを表14-6に示します。

表14‒6　すべてのアダプタに共通のデフォルトプロパティ

プロパティ

デフォルト

説明

vbroker.naming.backingStoreType

InMemory

使用するネーミングサービスアダプタのタイプを指定します。

このプロパティは，ネーミングサービスを使用したいプラガブルバッキングストア（外部記憶装置）のタイプを指定します。有効なオプションは，InMemory，JDBC，Dx，およびJNDIです。デフォルトはInMemoryです。

vbroker.naming.cacheOn

0

ネーミングサービスキャッシュを使用するかどうかを指定します。

vbroker.naming.cacheSize

5

ネーミングサービスキャッシュがオンの場合にそのサイズを指定します。

(2)　JDBCアダプタプロパティ

vbroker.naming.backingStoreType

このプロパティはJDBCに設定しなければなりません。JDBCアダプタでは，poolSize，jdbcDriver，url，loginName，およびloginPwdプロパティも設定する必要があります。

vbroker.naming.jdbcDriver

このプロパティは，バッキングストアとして使用するデータベースへのアクセスに必要なJDBCドライバです。ネーミングサービスはこの設定に従って表14-7の中から適切なJDBCドライバをロードします。デフォルトはJava DataStore JDBCドライバです。

表14‒7　vbroker.naming.jdbcDriverプロパティを使用してデータベースへアクセスするためのJDBCドライバ

JDBCドライバ値

説明

com.borland.datastore.jdbc.DataStoreDriver

JDataStoreドライバ

com.sybase.jdbc.SybDriver

Sybaseドライバ

oracle.jdbc.driver.OracleDriver

Oracleドライバ

interbase.interclient.Driver

Interbaseドライバ

weblogic.jdbc.mssqlserver4.Driver

WebLogic MS SQLServerドライバ

COM.ibm.db2.jdbc.app.DB2Driver

IBM DB2ドライバ

vbroker.naming.loginName

このプロパティはデータベースに対応するログイン名です。デフォルトはVisiNamingです。

vbroker.naming.loginPwd

このプロパティはデータベースに対応するログインパスワードです。デフォルトはVisiNamingです。

vbroker.naming.poolSize

このプロパティは，バッキングストアとしてJDBCアダプタを使用する場合にコネクションプールで使用するデータベースコネクションの数を指定します。デフォルト値は5ですが，データベースが扱える任意の値に増やせます。ネーミングサービスへのリクエスト数が多くなりそうな場合は，この値を大きくしてください。

vbroker.naming.url

このプロパティは，アクセスしたいデータベースの位置を指定します。この設定は使用するデータベースに依存します。デフォルトはJDataStoreで，データベース位置はrootDB.jdsというカレントディレクトリです。rootDB.jdsに限らないで，任意の名前を付けてかまいません。これに従って構成ファイルを更新しなければなりません。データベースのURL値を表14-8に示します。

表14‒8　vbroker.naming.urlプロパティを使用してアクセスするデータベースのURL

URL値

説明

jdbc:borland:dslocal:<db_name>

JDataStore URL

jdbc:sybase:Tds:<host>:<port>/<db_name>

Sybase URL

jdbc:oracle:thin:@<host>:<port>:<sid>

Oracle URL

jdbc:interbase://<server>/<full_db_path>

Interbase ※1 URL

jdbc:weblogic:mssqlserver4:<db_name>@<host>:<port>

WebLogic MS SQLServer URL

jdbc:db2:<db_name>

IBM DB2※2 URL

<full_path_JDataStore_db>

ネイティブドライバのDataExpress※3 URL

注※1

JDBCを介してInterBaseにアクセスする前に，InterServerサーバを起動してください。InterBaseサーバがローカルホストに存在するなら，localhostを<server>に指定します。これ以外の場合はホスト名を<server>に指定します。InterBaseデータベースがWindowsに存在するなら，<full_db_path>にdriver:¥¥dir1¥¥dir2¥¥db.gdb（最初の¥記号は2番目の¥記号をエスケープします）を指定します。InterBaseデータベースがUNIXに存在するなら，<full_db_path>に/dir1/dir2/db.gdbを指定します。

注※2

JDBCを介してDB2にアクセスする前に，Client Configuration Assistantを使用してデータベースをエイリアス <db_name>で登録しなければなりません。データベースの登録後は，vbroker.naming.urlプロパティに<host>や<port>を指定する必要はありません。

注※3

JDataStoreデータベースがWindowsに存在するなら，<full path of the JDataStore database>にDriver:¥¥dir1¥¥dir2¥¥db.jds（最初の¥記号は2番目の¥記号をエスケープします）を指定します。JDataStoreデータベースがUNIXに存在するなら，<full path of the JDataStore database>に/dir1/dir2/db.jdsを指定します。

(3)　DataExpressアダプタプロパティ

DataExpressアダプタプロパティについて説明します。

vbroker.naming.backingStoreType

このプロパティはDxに設定する必要があります。

vbroker.naming.loginName

このプロパティはデータベースに対応するログイン名です。デフォルトはVisiNamingです。

vbroker.naming.loginPwd

このプロパティはデータベースに対応するログインパスワードです。デフォルト値はVisiNamingです。

vbroker.naming.url

このプロパティは，データベースの位置を指定します。

(4)　JNDIアダプタプロパティ

表14-9に，JNDIアダプタの構成ファイルに表示される設定例を示します。

表14‒9　JNDIアダプタ構成ファイルの例

設定

説明

vbroker.naming.backingStoreType=JNDI

プラガブルバッキングストア（外部記憶装置）のタイプをJNDIアダプタ用のJNDIに指定します。

vbroker.naming.loginName=<user name>

JNDIバッキングサーバ上のユーザログイン名です。

vbroker.naming.loginPwd=<password>

JNDIバッキングサーバのユーザパスワードです。

vbroker.naming.jndiInitialFactory=com.sun.jndi.ldap.LdapCtxFactory

JNDI初期ファクトリを指定します。

vbroker.naming.jndiProviderURL=ldap://<hostname>:<ldap portNo>/<initial root context>

JNDIプロバイダURLを指定します。

vbroker.naming.jndiAuthentication=simple

JNDIバッキングサーバがサポートするJNDI認証タイプを指定します。

注

ユーザは，ディレクトリサーバにスキーマや属性を追加するために必要な権限を持つ必要があります。

(5)　キャッシング機能

キャッシング機能をオンにすることで，バッキングストアの性能を向上できます。例えば，JDBCアダプタの場合，解決またはバインドオペレーションがあるたびにデータベースに直接アクセスすると，かなりの時間が掛かりますが，結果をキャッシングすることでデータベースアクセスの回数を減らせます。キャッシング機能をオンにする前に知っておくべき留意点が幾つかあります。まず，基本となるデータにアクセスするネーミングサービスは，キャッシュを使用したネーミングサービスだけであることを確認してください。そうでなければ，古くなったデータがキャッシュに入っていることがあるため，ネーミングサービスを使用するクライアントが間違ったデータを取得することがあります。バッキングストアの性能向上が見られるのは，同じ一つのデータが複数回アクセスされた場合だけです。

注

使用環境での性能がキャッシング機能によって必ず向上するという確信がないかぎり，キャッシング機能はオンにしないでください。

このキャッシング機能は，コンテキストごとにキャッシュする実装になっています。この場合，各コンテキストにキャッシュがインストールされることになり，コンテキストとオブジェクトの両方をキャッシュするために使用されます。このキャッシュのサイズは調整できます。デフォルトでは，このキャッシュのサイズは5です。

キャッシング機能を使用するには，次のプロパティを構成ファイルに追加してください。

vbroker.naming.cacheOn=1
vbroker.naming.CacheSize=5

14.11　クラスタ

Borland Enterprise Server VisiBrokerは，多数のオブジェクトバインディングを一つの名前に対応させることを可能とするクラスタ化機能をサポートします。さらに，ネーミングサービスはクラスタ内の別々のバインディング間で負荷分散を行えます。クラスタの生成時には負荷分散の方法を決定できます。それ以降にクラスタに対して名前とオブジェクトのバインディングを解決するクライアントの負荷が，異なるクラスタサーバメンバ間で分散されることになります。

クラスタは，Nameをオブジェクトリファレンスのグループに対応づけるマルチバインド機能です。クラスタの生成はClusterManagerオブジェクトによって行われます。生成時に，ClusterManagerのcreate_clusterメソッドは，使用する方法を指定するStringパラメタを取り込みます。このメソッドはクラスタへのリファレンスを返し，これを使用してメンバの追加，削除，および検索ができます。クラスタの構成を決定したら，そのクラスタのリファレンスを特定の名前でネーミングサービス内の任意のコンテキストにバインドできます。こうすることで，Nameに対する以降のresolveオペレーションはクラスタ内にバインドされたオブジェクトリファレンスを返します。

create_clusterメソッドの引数に""を指定した場合は，"RoundRobin"指定時と同じ動作をします。

create_clusterメソッドの引数に，"RoundRobin"，"SmartRoundRobin"，""以外の文字列を指定した場合，nameservでNullPointerExceptionが発生し，クライアントに不正なオブジェクトリファレンスが返ります。そのため，そのオブジェクトリファレンスを用いたリクエストで，UNKNOWN例外が発生します。

14.11.1　クラスタ化方法

ネーミングサービスは，デフォルトではクラスタによるRoundRobinの方法を使用します。クラスタの生成後は，クラスタの方法を変更できません。ユーザが定義した方法はサポートしていませんが，今後RoundRobin以外の方法もできるように予定しています。デフォルトのRoundRobinの方法のほかに現在使用できる方法は，SmartRoundRobinの方法だけです。SmartRoundRobinとRoundRobinの違いは，SmartRoundRobinは，CORBAオブジェクトリファレンスがアクティブであること，つまりレディ状態であるCORBAサーバをオブジェクトリファレンスが参照中であることを確認するために幾つかの検証をします。

注

アクティブであることが検証されたオブジェクトは，カレントインプリメンテーションが活性化するので，SmartRoundRobinの使用はお勧めできません。また，クラスタフェールオーバー機能はRoundRobinの方法だけ使用できます。

14.11.2　クラスタインタフェースとClusterManagerインタフェース

クラスタとネーミングコンテキストが酷似していても，コンテキストにはクラスタと無関係のメソッドがあります。例えば，ネーミングコンテキストをクラスタにバインドしても無意味です。クラスタにはネーミングコンテキストではなくオブジェクトリファレンスの集合が入るためです。ただし，クラスタインタフェースは，bind，rebind，resolve，unbind，listなどNamingContextと同じメソッドを多く持っています。これらのオペレーションは，主にグループに対するオペレーションに関係します。クラスタ固有オペレーションはpickだけです。両者の重要な違いのもう一つは，クラスタは複合名をサポートしないということです。クラスタは階層ディレクトリ構造を持たないで，フラット構造でオブジェクトリファレンスを格納するので，コンポーネントを一つだけ持つ名前だけを使用できます。

(1)　クラスタインタフェースのIDL指定

module CosNamingExt {
   typedef sequence<Cluster> ClusterList;
   enum ClusterNotFoundReason {
      missing_node,
      not_context,
      not_cluster_context
   };
   exception ClusterNotFound {
      ClusterNotFoundReason why;
      CosNaming::Name rest_of_name;
   };
   exception Empty {};
   interface Cluster {
      Object select() raises(Empty);
      void bind(in CosNaming::NameComponent n, in Object obj)
           raises(CosNaming::NamingContext::CannotProceed,
                  CosNaming::NamingContext::InvalidName,
                  CosNaming::NamingContext::AlreadyBound);
      void rebind(in CosNaming::NameComponent n, in Object obj)
           raises(CosNaming::NamingContext::CannotProceed,
                  CosNaming::NamingContext::InvalidName);
      Object resolve(in CosNaming::NameComponent n)
           raises(CosNaming::NamingContext::NotFound,
                  CosNaming::NamingContext::CannotProceed,
                  CosNaming::NamingContext::InvalidName);
      void unbind(in CosNaming::NameComponent n)
           raises(CosNaming::NamingContext::NotFound,
                  CosNaming::NamingContext::CannotProceed,
                  CosNaming::NamingContext::InvalidName);
      void destroy()
           raises(CosNaming::NamingContext::NotEmpty);
      void list(in unsigned long how_many,
            out CosNaming::BindingList bl,
            out CosNaming::BindingIterator bi);
   } ;
};

(2)　ClusterManagerインタフェースのIDL指定

CosNamingExt module {
   interface ClusterManager {
      Cluster create_cluster(in string algo);
      Cluster find_cluster(
       in CosNaming::NamingContext ctx, in CosNaming::Name n)
         raises(ClusterNotFound,
             CosNaming::NamingContext::CannotProceed,
             CosNaming::NamingContext::InvalidName);
      Cluster find_cluster_str(
                 in CosNaming::NamingContext ctx, in string n)
         raises(ClusterNotFound,
             CosNaming::NamingContext::CannotProceed,
             CosNaming::NamingContext::InvalidName);
      ClusterList clusters();
   };
};

14.11.3　クラスタの生成

クラスタを生成するには，Cluster Managerインタフェースを使用します。ネーミングサーバの起動時に，Cluster Managerオブジェクトが一つだけ自動的に生成されます。Cluster Managerはネーミングサーバごとに一つだけあります。Cluster Managerの役割は，ネーミングサーバ内のクラスタの生成，検索，および状態の把握です。

クラスタオブジェクトの生成に使用したいネーミングサーバにバインドします。

ファクトリリファレンスのget_cluster_managerメソッド呼び出しによって，Cluster Managerへのリファレンスを取得します。

指定されたクラスタの方法でクラスタを生成します。

クラスタを使用して，オブジェクトをNameにバインドします。

Clusterオブジェクト自身をNameにバインドします。

指定されたクラスタの方法のClusterリファレンスによって解決します。

コードサンプル14-7　Clusterオブジェクトの生成と使用（C++）

. . .
ExtendedNamingContextFactory_var myFactory =
      ExtendedNamingContextFactory::_bind(orb, "NamingService");
ClusterManager_var clusterMgr =
      myFactory->get_cluster_manager();
Cluster_var clusterObj =
      clusterMgr->create_cluster("RoundRobin");
clusterObj->bind(new NameComponent(
      "member1", "aCluster"), obj1);
clusterObj->bind(new NameComponent(
      "member2", "aCluster"), obj2);
clusterObj->bind(new NameComponent(
      "member3", "aCluster"), obj3);
NameComponent_var myClusterName =
      new NameComponent("ClusterName", "");
root->bind(myClusterName, clusterObj);
root->resolve(myClusterName);
      // a member of the Cluster is returned
root->resolve(myClusterName);
      // the next member of the Cluster is returned
root->resolve(myClusterName);
      // the last member of the Cluster is returned
. . .

コードサンプル14-8　Clusterオブジェクトの生成と使用（Java）

. . .
ExtendedNamingContextFactory myFactory =
    ExtendedNamingContextFactoryHelper.bind(orb,
                                           "NamingService");
ClusterManager clusterMgr = myFactory.get_cluster_manager();
Cluster clusterObj = clusterMgr.create_cluster("RoundRobin");
clusterObj.bind(new NameComponent("member1", "aCluster"),
                obj1);
clusterObj.bind(new NameComponent("member2", "aCluster"),
                obj2);
clusterObj.bind(new NameComponent("member3", "aCluster"),
                obj3);
NameComponent myClusterName =
                        new NameComponent("ClusterName", "");
root.bind(myClusterName, clusterObj);
root.resolve(myClusterName) //
                        a member of the Cluster is returned.
root.resolve(myClusterName) //
                 the next member of the Cluster is returned.
root.resolve(myClusterName) //
                 the last member of the Cluster is returned.
. . .

(1)　明示的なクラスタと暗黙的なクラスタ

クラスタ化機能はネーミングサービスに対して自動的にオンになります。注意点は，この機能がオンになると，オブジェクトをバインドするためにクラスタが透過的に生成されるということです。使用の方法はラウンドロビンに固定されます。この影響は，ネーミングサーバ内の同じ名前に幾つかのオブジェクトをバインドできるということです。反対に，この名前を解決すると，これらのオブジェクトの一つが返され，unbindオペレーションはその名前に対応するクラスタをデストラクトします。これは，ネーミングサービスがCORBAの仕様に準拠しなくなったという意味です。インターオペラブルネーミングサービスの仕様では，複数のオブジェクトを同じ名前でバインドする機能を明示的に禁止します。準拠しているネーミングサービスでは，クライアントが同じ名前を使用して異なるオブジェクトにバインドしようとすると，AlreadyBound例外が発生します。ユーザは最初から，個々のサーバにこの機能を使用するかどうかを決定する必要があり，その決定を守るべきです。

注

暗黙的なクラスタモードから明示的なクラスタモードへの切り替えはできません。バッキングストアを破壊するおそれがあるためです。

ネーミングサーバを暗黙的なクラスタ化機能と一緒に使用した場合，クラスタ化機能をオンにした状態でネーミングサーバを引き続き活性化してください。機能をオンにするには，構成ファイルに次のプロパティ値を定義してください。

vbroker.naming.propBindOn=1

注

明示的なクラスタ化および暗黙的なクラスタ化の両方のサンプルについては，次のインストールディレクトリ下の次のディレクトリのコードを参照してください。

examples/vbe/ins/implicit_clustering
examples/vbe/ins/explicit_clustering

14.11.4　負荷分散

Cluster Managerとスマートエージェントはどちらもラウンドロビン負荷分散機能を提供しますが，これらは異なる性質を持ちます。スマートエージェントの負荷分散は暗黙のうちに行われます。サーバの起動時，サーバは自動的に自分自身をスマートエージェントに登録し，これによって今度はBorland Enterprise Server VisiBrokerが，容易だが独占的な方法でクライアントがサーバへのリファレンスを取得できるようにします。ただし，これらの自動化には相応の代償があります。グループを構成するものおよびグループのメンバの決定に際しては，プログラマが選択することはできません。スマートエージェントがすべてを決定します。ここで，代替手段を提供するクラスタが便利です。これはクラスタのプロパティをプログラムによって定義，生成する方法を提供します。プログラマはクラスタに適用する方法を定義でき，クラスタのメンバも自由に選択できます。方法は生成時に固定されますが，クライアントはクラスタの存続期間中にクラスタのメンバを追加したり削除したりできます。

14.12　フェールオーバー

ネーミングサービスはマスタ／スレーブモデルを使用したフェールオーバー機能をインプリメントします。アクティブモードのマスタとスタンドバイモードのスレーブという二つのネーミングサーバが同時実行中でなければなりません。マスタとスレーブの両ネーミングサーバは，同じ基本データをパーシステントなバッキングストアにサポートする必要があります。各サーバに強制的にバッキングストアと直接やり取りさせるために両方のサーバのキャッシング機能は必ずオフにして，データが確実に不変であるようにしてください。

両方のネーミングサーバがアクティブなら，ネーミングサービスを使用しているクライアントは常にマスタを優先します。マスタが不測の事態で終了した場合，スレーブネーミングサーバが引き継ぎます。このマスタからスレーブへの切り替えはシームレスであり，クライアントから見て透過的です。ただし，スレーブネーミングサーバはマスタサーバにはなりません。その代わり，マスタサーバが使用不能になった場合には一時的にバックアップします。この間に，ユーザはクラッシュしたマスタサーバの回復のための対策を行います。マスタが再び起動されたあとは，新しいクライアントからのリクエストだけがマスタサーバに送信されます。すでにスレーブネーミングサーバにバインドされているクライアントは，自動的にマスタにスイッチバックしません。

フェールオーバーが発生すると，クライアントから見て透過的ですが，わずかに遅延があります。これは，スレーブネーミングサーバのサーバオブジェクトを，入ってきたリクエストによってオンデマンドによる活性化をしなければならない場合があるためです。また，イテレータのような一時的なオブジェクトリファレンスは無効です。トランジェントなイテレータによるリファレンスを使用したクライアントは，これらのリファレンスの無効化に備えなければならないので，これは正常なことです。一般に，ネーミングサーバはあまり多くのイタレータオブジェクトを集中保管しないで，いつでもクライアントのイタレータによるリファレンスを無効にできます。これらはトランジェントリファレンスではなく，パーシステントリファレンスを使用したクライアントリクエストであればスレーブネーミングサーバに再転送されます。

注

すでにスレーブネーミングサーバにバインドされているクライアントは，自動的にマスタにスイッチバックしないで，一つのレベルのフェールオーバーしかサポートしません。したがって，スレーブネーミングサーバが使用不能になると，ネーミングサービスも使用不能になります。

14.12.1　フォルトトレランス用のネーミングサービスの設定

二つのネーミングサーバが実行中でなければなりません。その一つにはマスタ，もう一つにはスレーブと名づけてください。両方のサーバで同じプロパティファイルを使用できます。プロパティファイルでの適切な値については，コードサンプル14-9を参照してください。

コードサンプル14-9　フォルトトレランスを使用するための設定

vbroker.naming.enableSlave=1
vbroker.naming.masterServer=<Master Naming Server Name>
vbroker.naming.masterHost=<host ip address for Master>
vbroker.naming.masterPort=<port number that Master is listening on>
vbroker.naming.slaveServer=<Slave Naming Server Name>
vbroker.naming.slaveHost=<host ip address for Slave>
vbroker.naming.slavePort=<port number that Slave is listening on>

特定ポートで強制的にネーミングサーバを起動するには，次に示すコマンドラインオプションでネーミングサーバを起動してください。

prompt> nameserv -J¥
        -Dvbroker.se.iiop_tp.scm.iiop_tp.listener.port=¥
        <port number> com.inprise.vbroker.naming.ExtFactory ¥
        <Naming_Server_Name>

注

マスタサーバとスレーブサーバの起動順序に制限はありません。

14.13　プログラムのコンパイルとリンク（C++）

ネーミングサービスを使用するC++アプリケーションには，次に示す生成ファイルが必要です。

#include "CosNaming_c.hh"
#include "CosNamingExt_c.hh"

14.13.1　UNIX

UNIXアプリケーションは，次のライブラリのどれかとリンクする必要があります。

AIX

libcosnm_r.a（マルチスレッド）

HP-UX

libcosnm_r.sl（マルチスレッド）

Solaris

libcosnm_r.so（マルチスレッド）

14.13.2　Windows

Windowsアプリケーションは，次のライブラリとリンクする必要があります。

cosnm_r.lib（マルチスレッド）

14.14　Javaのインポート文

Javaの場合，次に示すインポート文は，ネーミングサービスのBorland Enterprise Server VisiBroker拡張機能を使用したいJavaクラスに使用してください。

import com.inprise.vbroker.CosNamingExt.*;
. . .

OMGに準拠したネーミングサービスの機能へアクセスしたい場合は，次に示すパッケージが必要です。

import org.omg.CosNaming.*
import org.omg.CosNaming.NamingContextPackage.*
import org.omg.CosNaming.NamingContextExtPackage.*

14.15　サンプルプログラム

Borland Enterprise Server VisiBrokerには，ネーミングサービスの使用方法を説明する幾つかのサンプルプログラムが提供されています。これらのサンプルはexamples/vbe/insディレクトリに入っており，現在ネーミングサービスで使用できる新機能をすべて説明しています。さらに，examples/vbe/basic/bank_namingディレクトリに入っているBankネーミングのサンプルは，ネーミングサービスの基本的な使い方を説明しています。

サンプルプログラムを実行する前に，まず「14.3　ネーミングサービスの実行」で説明したようにネーミングサービスを起動しなければなりません。さらに，最低一つのネーミングコンテキストが次に示すどれかの手段で生成されていることを必ず確認してください。

「14.3　ネーミングサービスの実行」で説明したようにネーミングサービスを起動します。これでイニシャルコンテキストが自動生成されます。

VisiBrokerコンソールを使用します。

クライアントをNamingContextFactoryにバインドさせ，create_contextメソッドを使用します。

クライアントにExtendedNamingContextFactoryを使用させます。

注

ネーミングコンテキストを生成していない場合，クライアントがbindを発行しようとしたときにCORBA.NO_IMPLEMENT例外が発生します。

14.15.1　名前のバインド

BankネーミングのサンプルではAccountManagerインタフェースを使用してAccountをオープンしたりアカウントの残高を問い合わせたりします。次に示すServerクラスは，名前をオブジェクトリファレンスにバインドするためのネーミングサービスの使い方を説明します。サーバは，ネーミングサーバのルートコンテキストにIORをバインド登録し，これは次にクライアントが検索します。

このサンプルでは，次の方法を理解できるようになります。

ネーミングサービスのルートコンテキストへのリファレンスを取得するための，VisiBroker ORBインスタンスのresolve_initial_referencesメソッドの使用方法（サンプルでは，NameServiceのデフォルト名でネーミングサービスを起動しなければなりません）

NamingContextExtHelperクラスのnarrowメソッド使用による，ルートコンテキストのリファレンスへのキャスト方法

AccountManagerImplオブジェクトのPOAおよびサーバントの生成方法

最後にNamingContextインタフェースのbindメソッドを使用して，「BankManager」という名前をAccountManagerImplオブジェクトのオブジェクトリファレンスにバインドする方法

コードサンプル14-10　Server.c（C++）

#include "CosNaming_c.hh"
#include "BankImpl.h"

// USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

      // get a reference to the root POA
      PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(
                   orb->resolve_initial_references("RootPOA"));

      // get a reference to the Naming Service root_context
      CosNaming::NamingContext_var rootContext =
                  CosNaming::NamingContext::_narrow(
                  orb->resolve_initial_references("NameService"));

    CORBA::PolicyList policies;
    policies.length(1);

    policies[(CORBA::ULong)0] =
         rootPOA->create_lifespan_policy(PortableServer::PERSISTENT);

      // get the POA Manager
      PortableServer::POAManager_var poa_manager =
                   rootPOA->the_POAManager();

      // Create myPOA with the right policies
      PortableServer::POA_var myPOA =
         rootPOA->create_POA("bank_agent_poa", poa_manager, policies);

      // Create the servant
      AccountManagerImpl managerServant;

      // Decide on the ID for the servant
      PortableServer::ObjectId_var managerId =
      PortableServer::string_to_ObjectId("BankManager");

      // Activate the servant with the ID on myPOA
      myPOA->activate_object_with_id(managerId, &managerServant);

      // Activate the POA Manager
      poa_manager->activate();

      CORBA::Object_var reference =
      myPOA->servant_to_reference(&managerServant);

      // Associate the bank manager with the name at the root context
      CosNaming::Name name;
      name.length(1);
      name[0].id = (const char *) "BankManager";
      name[0].kind = (const char *) "";
      rootContext->rebind(name, reference);

      cout << reference << " is ready" << endl;

      // Wait for incoming requests
      orb->run();
  }
      catch(const CORBA::Exception& e) {
      cerr << e << endl;
      return 1;
  }

  return 0;
}

コードサンプル14-11　Server.java（Java）

import org.omg.PortableServer.*;
import org.omg.CosNaming.*;

public class Server {
   public static void main(String[ ] args){
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);
         // get a reference to the rootPOA
         POA rootPOA = POAHelper.narrow(
                 orb.resolve_initial_references("RootPOA"));
         // get a reference to the Naming Service root
         // context
         org.omg.CORBA.Object rootObj =
                 orb.resolve_initial_references("NameService");
         NamingContextExt root =
                     NamingContextExtHelper.narrow(rootObj);

         // Create policies for our persistent POA
         org.omg.CORBA.Policy[ ] policies = {
             rootPOA.create_lifespan_policy(
                             LifespanPolicyValue.PERSISTENT)
         };
         // Create myPOA with the right policies
         POA myPOA = rootPOA.create_POA(
                  "bank_agent_poa", rootPOA.the_POAManager(),
                  policies );
         // Create the servant
         AccountManagerImpl managerServant =
                                 new AccountManagerImpl();
         // Decide on the ID for the servant
         byte[ ] managerId = "BankManager".getBytes();
         // Activate the servant with the ID on myPOA
         myPOA.activate_object_with_id(managerId,
                                        managerServant);

         // Activate the POA manager
         rootPOA.the_POAManager().activate();

         // Associate the bank manager with the name at
         // the root context Note that casting is needed
         // as a workaround for a JDK 1.1.x bug.
         ((NamingContext)root).bind(
               root.to_name("BankManager"),
               myPOA.servant_to_reference(managerServant));

         System.out.println(
                  myPOA.servant_to_reference(managerServant)
                  + " is ready.");
         // Wait for incoming requests
         orb.run();
      }catch (Exception e){
         e.printStackTrace();
      }
   }
}

15　オブジェクト活性化デーモンの使用

この章では，OAD（オブジェクト活性化デーモン）の使用方法について説明します。

15.1　オブジェクトとサーバの自動活性化

OAD（オブジェクト活性化デーモン）は，インプリメンテーションリポジトリを実装したBorland Enterprise Server VisiBrokerのデーモンです。インプリメンテーションリポジトリは，サーバがサポートしているクラス，実体化されているオブジェクトとそれらに関する情報をランタイム時にリポジトリとして提供します。また，OADはクライアントがオブジェクトを参照するときにインプリメンテーションを自動的に活性化する目的にも使用されます。OADにオブジェクトインプリメンテーションを登録することで，利用したいオブジェクトは自動的に活性化されます。

オブジェクトインプリメンテーションは，コマンドラインインタフェース（oadutil）を使用して登録できます。「15.5　OADとのIDLインタフェース」で説明する，OADとのVisiBroker ORBインタフェースもあります。どちらの場合も，リポジトリID，オブジェクト名，活性化ポリシー，およびインプリメンテーションを表す実行可能プログラムを指定しなければなりません。

注

任意のバージョンのBorland Enterprise Server VisiBroker（Java）およびVisiBroker for C++3.0で生成されたサーバを実体化するには，Borland Enterprise Server VisiBroker OADを使用できます。

OADは，オブジェクトサーバがオンデマンドで活性化されるホスト上で起動しておけばよい，独立したプロセスです。

15.1.1　インプリメンテーションリポジトリデータの探索

OADに登録されたすべてのオブジェクトインプリメンテーションについての活性化情報は，インプリメンテーションリポジトリに格納されます。デフォルトでは，インプリメンテーションリポジトリデータはimpl_repという名前のファイルに格納されます。このファイルのパス名はVBROKER_ADM環境変数の値によって決まります。Borland Enterprise Server VisiBrokerが/usr/local/vbrokerディレクトリにインストールされている場合，このファイルへのパスは/usr/local/vbroker/adm/impl_dir/impl_repになります。これらのデフォルト値は「2.　環境設定」で説明したOAD環境変数を使用して変更できます。

15.1.2　サーバの起動

OADはクライアントリクエストに応じてサーバを起動します。次に示すタイプのクライアントが，OADによってサーバを起動できます。

VisiBroker for C++ 3.xクライアント

VisiBroker 4.xクライアント（C++）

VisiBroker for Java 3.xクライアント

VisiBroker 4.xクライアント（Java）

Borland Enterprise Server VisiBrokerのクライアント

Borland Enterprise Server VisiBroker以外のIIOPプロトコルを使用するクライアント

IIOPに準拠するクライアントから，サーバのリファレンス使用時にBorland Enterprise Server VisiBrokerサーバを起動する際は十分な接続検証が必要です。サーバのエクスポートされたオブジェクトリファレンスはOADをポイントし，生成されたサーバにはIIOP規則に従ってクライアントを転送できます。（ネームサービスなどを使用して）サーバのオブジェクトリファレンスの厳密な永続化を保証するために，OADは常に同じポートで起動しなければなりません。次の例では，OADはポート16050で起動されます。

prompt> oad -VBJprop vbroker.se.iiop_tp.scm.iiop_tp.¥
        listener.port=16050

注

ポート16000はデフォルトポートですが，これはlistener.portプロパティを設定することによって変更できます。

15.2　OADの起動

OADは，クライアントのアクセス時に自動的に起動されるオブジェクトを登録できるようにするオプション機能です。まずスマートエージェントを起動したあとに，OADを起動してください。

Windowsの場合

コマンドプロンプトで次のコマンドを入力してOADを起動してください。

prompt> oad

UNIXの場合

次のコマンドを入力してOADを起動してください。

prompt> oad &

oadコマンドには，表15-1のコマンドライン引数を指定できます。

表15‒1　oadコマンドのオプション

オプション

説明

-verbose

バーボースモードをオンにして，メッセージがstdoutに出力されるようにします。

-version

このツールのバージョンを出力します。

-path <path>

インプリメンテーションリポジトリ格納用のプラットフォーム固有ディレクトリを指定します。これは，環境変数の使用による設定をすべて変更します。

-filename <repository filename>

インプリメンテーションリポジトリの名前を指定します。このオプションを指定しないと，デフォルトはimpl_repです。これはユーザの環境変数設定をすべて変更します。

-timeout <# of seconds>

生成されたサーバプロセスが，リクエストされたVisiBroker ORBオブジェクトを活性化するのを，OADが待つ時間を指定します。デフォルトのタイムアウトは20秒です。待ち時間を不定にしたい場合は，この値を0に設定してください。

生成されたサーバプロセスが，リクエストされたORBオブジェクトをタイムアウト時間内に活性化しなければ，OADは生成されたプロセスに対してKillを実行し，クライアントにはCORBA::NO_RESPONSE例外が返されることになります。より詳細な情報を返したい場合は，バーボースオプションをオンにしてください。

-IOR <IOR filename>

OADの文字列化されたIORを格納するファイル名を指定します。

-kill

オブジェクトがOADから登録解除された場合に，その子プロセスに対してKillを実行するよう規定します。

-no_verify

登録の有効性チェックをオフにします。

-?

コマンドの使い方を表示します。

-readonly

OADを-readonlyオプションで起動した場合，登録されたオブジェクトは何も変更されません。オブジェクトの登録や登録解除をしようとするとエラーを返します。-readonlyオプションは，一般にインプリメンテーションリポジトリを変更し，追加変更を行わないようにreadonlyモードでOADをリスタートしたあとに使用します。

15.3　オブジェクト活性化デーモンユーティリティの使用

oadutilコマンドは，Borland Enterprise Server VisiBrokerのシステムで使用できるオブジェクトインプリメンテーションの登録，登録解除，およびリスト出力を手動で行う手段を提供します。oadutilコマンドはJavaでインプリメントされ，コマンドラインインタフェースを使用します。各コマンドは，oadutilコマンドを起動し，実行するオペレーションのタイプを第1引数として渡すことによってアクセスされます。

注

oadutilコマンドを使用するには，ネットワークの少なくとも一つのホストでOAD（オブジェクト活性化デーモンプロセス）を起動しなければなりません。

oadutilコマンドの構文は次のとおりです。

構文

oadutil {list|reg|unreg} [options]

このツールのオプションは，list，reg，unregのどれを指定したかによって異なります。

インタフェース名からリポジトリIDへの変換

インタフェース名とリポジトリIDは，活性化されたオブジェクトがインプリメントするべきインタフェースの型を表す方法です。IDLで定義されたすべてのインタフェースには一意のリポジトリIDが割り当てられます。この文字列は，インタフェースリポジトリ（IR）やOAD，およびVisiBroker ORB自身への呼び出しで通信するときに型を識別するために使用します。

オブジェクトをOADに登録または登録解除する場合，oadutilコマンドを使用すれば，オブジェクトのIDLインタフェース名か，そのリポジトリIDを指定できます。

インタフェース名は，次のようにしてリポジトリIDに変換できます。

インタフェース名の前に「IDL:」を付けます。

スコープ解決演算子の，先頭以外のすべてのインスタンス「::」をスラント「/」文字に置換します。

インタフェース名の後ろに「:1.0」を付けます。

例えば，「::Module1::Module2::IntfName」というIDLインタフェース名を変換すると，次のようなリポジトリIDになります。

IDL:Module1/Module2/IntfName:1.0

#pragma idと#pragmaプリフィクス機能を使用して，インタフェース名からのデフォルト生成のリポジトリIDを変更できます。ユーザ定義のIDLファイルで標準外のリポジトリIDを指定するために#pragma id機能を使用した場合，上記で説明した変換プロセスは効きません。この場合，-rリポジトリID引数を使用してオブジェクトのリポジトリIDを指定してください。

C++の場合

オブジェクトインプリメンテーションのインタフェースのリポジトリIDを取得するには，すべてのCORBAオブジェクトに対して定義された<interface_name>._repository_id()メソッドを使用してください。

Javaの場合

オブジェクトインプリメンテーションのインタフェースのリポジトリIDを取得するには，すべてのCORBAオブジェクトに対して定義されたjava: <interface_name>Helper.id()メソッドを使用してください。

15.3.1　oadutil listによるオブジェクトのリスト出力

oadutil listコマンドは，OADに登録されたすべてのVisiBroker ORBオブジェクトインプリメンテーションを返します。各OADは，自分のインプリメンテーションリポジトリデータベースに登録情報を格納しています。

注

oadutil listコマンドを使用するには，ネットワークの少なくとも一つのホストでOAD（オブジェクト活性化デーモンプロセス）を起動しなければなりません。

oadutil listコマンドの構文は次のとおりです。

構文

oadutil list [options]

oadutil listコマンドには表15-2のコマンドライン引数を指定できます。

表15‒2　oadutil listコマンドのオプション

オプション

説明

-i <interface_name>

特定のIDLインタフェース名のオブジェクトについてのインプリメンテーション情報をリスト出力します。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

注

VisiBroker ORBとのすべての通信は，インタフェース名ではなくオブジェクトのリポジトリIDを参照します。インタフェース名の指定時に行われる変換の詳細については，「15.3　オブジェクト活性化デーモンユーティリティの使用」の「インタフェース名からリポジトリIDへの変換」を参照してください。

-r <repository_id>

特定のリポジトリIDのインプリメンテーション情報をリスト出力します。リポジトリID指定の詳細については，「15.3　オブジェクト活性化デーモンユーティリティの使用」の「インタフェース名からリポジトリIDへの変換」を参照してください。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

-s <service name>

特定のサービス名のインプリメンテーション情報をリスト出力します。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

-poa <poa_name>

特定のPOA名に関するインプリメンテーション情報をリスト出力します。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

-o <object_name>

特定のオブジェクト名に関するインプリメンテーション情報をリスト出力します。これは，インタフェースまたはリポジトリIDがコマンド文で指定された場合だけ使用できます。このオプションは，-s引数または-poa引数を使用した場合は適用できません。

-host <OAD host name>

特定のリモートホストで実行中のOADに登録されたオブジェクトのインプリメンテーション情報をリスト出力します。

-verbose

バーボースモードをオンにして，メッセージがstdoutに出力されるようにします。

-version

このツールのバージョンを出力します。

-full

OADに登録されたすべてのインプリメンテーションの状態をリスト出力します。

コードサンプル15-1は，oadutil listコマンドの出力例を示しています。

コードサンプル15-1　oadutil listコマンドの出力例

prompt>oadutil list
oadutil list:  located 1 record(s)
Implementation #1:
-------------------
repository_id     =   IDL:Bank/Account:1.0
object_name       =   Jack B. Quick
reference data    =
path_name         =   vbj
activation_policy =   SHARED_SERVER
args              =   (length=1)[Server; ]
env               =   NONE

(1)　説明

oadutil listユーティリティは，OADに登録されたすべてのVisiBroker ORBオブジェクトインプリメンテーションをリスト出力できるようにします。各オブジェクトの情報の内容は，次のとおりです。

VisiBroker ORBオブジェクトのインタフェース名

そのインプリメンテーションが提供したオブジェクトのインスタンス名

サーバインプリメンテーションの実行可能ファイルの完全パス名

VisiBroker ORBオブジェクトの活性化ポリシー（シェアードまたはアンシェアード）

インプリメンテーションがOADに登録されたときに指定されたリファレンスデータ

活性化時にサーバに渡す引数のリスト

活性化時にサーバに渡す環境変数のリスト

インタフェース名とオブジェクト名を指定したローカルリストリクエストの例を次に示します。

例

oadutil list -i Bank::AccountManager -o InpriseBank

ホストIPアドレスを指定したリモートリストリクエストの例を次に示します。

例

oadutil list -host 206.64.15.198

15.3.2　oadutilの使用によるオブジェクトの登録

oadutilコマンドを使用すると，コマンドラインから，またはスクリプト内からオブジェクトインプリメンテーションを登録できます。パラメタは，インタフェース名とオブジェクト名，サービス名，またはPOA名，これらに加えてインプリメンテーションを起動する実行可能ファイルへのパス名です。活性化ポリシーを指定しないと，デフォルトとしてシェアードサーバポリシーが使用されます。インプリメンテーションを記述しておき，開発フェーズとテストフェーズでそのインプリメンテーションを手動で起動できます。インプリメンテーションを配置する準備が整ったら，oadutilを使用するだけで，OADにそのインプリメンテーションを登録できます。

注

オブジェクトインプリメンテーションを登録する場合は，そのインプリメンテーションオブジェクトを構築したときに使用したのと同じオブジェクト名を使用してください。グローバルスコープを持った，名前付きオブジェクトだけをOADに登録できます。

oadutil regコマンドの構文は次のとおりです。

構文

oadutil reg [options]

注

oadutil regコマンドを使用するには，ネットワークの少なくとも一つのホストでoadプロセスを起動しなければなりません。

oadutil regコマンドのオプションには表15-3のコマンドライン引数を指定できます。

表15‒3　oadutil regコマンドのオプション

オプション

説明

必須

-i <interface_name>

特定のIDLインタフェース名を指定します。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

リポジトリID指定の詳細については，「15.3　オブジェクト活性化デーモンユーティリティの使用」の「インタフェース名からリポジトリIDへの変換」を参照してください。

-r < repository_id>

特定のリポジトリIDを指定します。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

-s <service name>

特定のサービス名を指定します。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

-poa <poa_name>

このオプションは，オブジェクトインプリメンテーションの代わりにPOAを登録する場合に使用してください。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

-o <object_name>

特定のオブジェクトを指定します。これは，インタフェース名またはリポジトリIDがコマンド文で指定された場合だけ使用できます。このオプションは，-s引数または-poa引数を使用している場合には適用できません。

-cpp <file name to execute>

-o/-r/-s/-poa引数に一致するオブジェクトを生成し登録しなければならない実行可能ファイルの完全パス名を指定します。-cpp引数で登録されたアプリケーションは，スタンドアロン実行可能ファイルでなければなりません。

-java <full class name>

メインルーチンを含むJavaクラスの完全名を指定します。このアプリケーションは，-o/-r/-s/-poa引数に一致するオブジェクトを生成し登録しなければなりません。-java引数で登録されたクラスは，コマンドvbj <full_classname>で実行されます。

任意指定

-host <OAD host name>

OADを実行中である特定のリモートホストを指定します。

-verbose

バーボースモードをオンにして，メッセージがstdoutに出力されるようにします。

-version

このツールのバージョンを出力します。

-d <referenceData>

活性化時にサーバに渡すリファレンスデータを指定します。

-a arg1

-a arg2

生成された実行可能ファイルにコマンドライン引数として渡す引数を指定します。複数の-a (arg)パラメタを使用して引数を渡せます。これらの引数は，生成された実行可能ファイルを生成するためにプロパゲートされます。

-e env1

-e env2

生成された実行可能ファイルに渡す環境変数を指定します。複数の-e (env)パラメタを使用して引数を渡せます。これらの引数は，生成された実行可能ファイルを生成するためにプロパゲートされます。

-p {shared|unshared}

生成されたオブジェクトの活性化ポリシーを指定します。デフォルトポリシーはSHARED_SERVERです。

shared指定時は，任意のオブジェクトの複数のクライアントが同じインプリメンテーションを共用します。OADが一度に活性化するサーバは一つだけです。

unshared指定時は，任意のインプリメンテーションの一つのクライアントだけが，活性化されたサーバにバインドされます。複数のクライアントが同じオブジェクトインプリメンテーションにバインドしたがると，クライアントアプリケーションごとに別々のサーバが活性化されます。クライアントアプリケーションが切断または終了すると，対応するサーバが終了します。

(1)　例1：リポジトリIDの指定

次に示すコマンドは，OADにBorland Enterprise Server VisiBrokerプログラムfactoryを登録します。これは，リポジトリIDがIDL:ehTest/Factory:1.0（インタフェース名ehTest::Factoryに対応）のオブジェクトがリクエストされると活性化されます。活性化対象のオブジェクトのインスタンス名はReentrantServerであり，その名前も，生成された実行可能ファイルにコマンドライン引数として渡されます。このサーバにはアンシェアードポリシーが指定されているので，リクエスト元のクライアントが生成されたサーバとのコネクションを切断すると，サーバが終了します。

C++の場合

prompt> oadutil reg -r IDL:ehTest/Factory:1.0   ¥
        -o ReentrantServer -cpp /home/developer¥
        /Project1/factory_r -a ReentrantServer  ¥
        -p unshared

Javaの場合

prompt> oadutil reg -r IDL:ehTest/Factory:1.0  ¥
        -o ReentrantServer -java factory_r     ¥
        -a ReentrantServer -p unshared

注

上記の例では，指定されたJavaクラスがCLASSPATHになければなりません。

(2)　例2：IDLインタフェース名の指定

次に示すコマンドは，OADにBorland Enterprise Server VisiBrokerクラスServerを登録します。この例では，指定されたクラスは，リポジトリIDがIDL:Bank/AccountManager:1.0（インタフェース名IDL名Bank::AccountManagerに対応）で，インスタンス名がCreditUnionのオブジェクトを活性化しなければなりません。サーバはアンシェアードポリシーで起動されるので，リクエスト元のクライアントがコネクションを切断すると，サーバは確実に終了します。

サンプル（Java）

prompt> oadutil reg -i Bank::AccountManager -o CreditUnion ¥
        -java Server -a CreditUnion -p unshared -e DEBUG=1

注

上記の例では，指定されたJavaクラスがCLASSPATHになければなりません。

上記の登録は，リクエストされたサーバの生成時に次のコマンドを実行するようOADに指示します。

vbj -DDEBUG=1 Server CreditUnion

(3)　OADへのリモート登録

リモートホストのOADにインプリメンテーションを登録するには，oadutil regに-host引数を指定してください。

UNIXシェルからWindowsのOADへのリモート登録の実行例を次に示します。¥記号をoadutilに渡す前にシェルに解釈させないようにするには，二重¥記号（¥¥）が必要です。

例

prompt> oadutil reg -r IDL:Library:1.0 Harvard             ¥
        -cpp c:¥¥vbroker¥¥examples¥¥library¥¥libsrv.exe    ¥
        -p shared -host 100.64.15.198

15.3.3　オブジェクトの複数のインスタンスの区別

インプリメンテーションはReferenceDataを使用することで，同じオブジェクトの複数のインスタンスを区別できます。リファレンスデータの値はオブジェクト生成時にインプリメンテーションによって選択され，オブジェクトの存続期間中は一定に保たれます。ReferenceData typedefは複数のプラットフォームとVisiBroker ORBの間で移植できます。

注

Borland Enterprise Server VisiBrokerは，生成しているオブジェクトのインタフェースを識別するために，CORBAが定義するinf_ptrを使用しません。Borland Enterprise Server VisiBrokerで生成するアプリケーションは，常にこのパラメタでNULL値を指定しなければなりません。

15.3.4　CreationImplDefクラスの使用による活性化プロパティの設定

CreationImplDefクラスには，OADがVisiBroker ORBオブジェクトを活性化するために必要なpath_name，activation_policy，args，およびenvというプロパティがあります。IDLサンプル15-1に，CreationImplDef structを示します。

path_nameプロパティには，オブジェクトをインプリメントする実行可能プログラムの正確なパス名を指定します。activation_policyプロパティは，IDLサンプル15-4に示すサーバの活性化ポリシーを表します。argsプロパティとenvプロパティはサーバのコマンドライン引数と環境設定を表します。

IDLサンプル15-1　CreationImplDef IDL

module extension {
. . .

   enum Policy {
      SHARED_SERVER,
      UNSHARED_SERVER
   };

   struct CreationImplDef {
      CORBA::RepositoryId      repository_id;
      string                   object_name;
      CORBA::ReferenceData     id;
      string                   path_name;
      Policy                   activation_policy;
      CORBA::StringSequence    args;
      CORBA::StringSequence    env;
   };
. . .
};

15.3.5　VisiBroker ORBインプリメンテーションの動的変更

IDLサンプル15-2に，オブジェクトの登録を動的に変更するために使用できるchange_implementation()メソッドを示します。このメソッドを使用して，オブジェクトの活性化ポリシー，パス名，引数，および環境変数を変更できます。

IDLサンプル15-2　change_implementation

module Activation
{
. . .
   void change_implementation(
         in extension::CreationImplDef old_info,
         in extension::CreationImplDef new_info)
      raises ( NotRegistered, InvalidPath, IsActive );
. . .
};

注

オブジェクトのインプリメンテーション名とオブジェクト名はchange_implementation()メソッドを使用して変更できますが，注意が必要です。変更すると，クライアントプログラムはそのオブジェクトを昔の名前で探せなくなります。

15.3.6　OAD::reg_implementationを使用したOADの登録

oadutil regコマンドを手動でまたはスクリプトで使用しなくても，Borland Enterprise Server VisiBrokerでは，クライアントアプリケーションがOAD::reg_implementationオペレーションを使って一つ以上のオブジェクトを活性化デーモンに登録できます。このオペレーションを使用すると，オブジェクトインプリメンテーションがOADとosagentに登録されます。OADは情報をインプリメンテーションリポジトリに格納し，クライアントがオブジェクトにバインドしようとしたときにオブジェクトインプリメンテーションを探し，活性化できるようにします。

IDLサンプル15-3　OAD::reg_implementationオペレーション

module Activation {
. . .
   typedef sequence<ObjectStatus> ObjectStatus List;
. . .
   typedef sequence<InplementationStatus> ImplStatusList;
. . .
   interface OAD {
      // Register an implementation.
      Object reg_implementation(
            in extension::CreationImplDef impl)
         raises (DuplicateEntry, InvalidPath);
   }
}

CreationImplDef structにはOADが必要とするプロパティがあります。プロパティには，repository_id，object_name，id，path_name，activation_policy，args，およびenvがあります。これらの値を設定したり照会したりするオペレーションも用意されています。OADはこれらの追加プロパティを使用してVisiBroker ORBオブジェクトを活性化します。

IDLサンプル15-4　CreationImplDefインタフェース

struct CreationImplDef {
   CORBA::RepositoryId repository_id;
   string object_name;
   CORBA::ReferenceData id;
   string path_name;
   Policy activation_policy;
   CORBA::StringSequence args;
   CORBA::StringSequence env;
};

path_nameプロパティには，オブジェクトをインプリメントする実行可能プログラムの正確なパス名を指定します。activation_policyプロパティはサーバの活性化ポリシーを表します。argsプロパティとenvプロパティはサーバに渡されるオプションの引数と環境設定を表します。

15.3.7　オブジェクトの生成と登録の例

コードサンプル15-2とコードサンプル15-3に，CreationImplDefクラスとOAD.reg_implementation()メソッドを使用してサーバをOADに登録する方法を示します。この機能は独立した管理プロセスで使用されますが，オブジェクトインプリメンテーションそのもので使用する必要はありません。オブジェクトインプリメンテーションで使用する場合，これらのタスクをオブジェクトインプリメンテーションの活性化より前に実行しなければなりません。

コードサンプル15-2　 VisiBroker ORBオブジェクトの生成とOADへの登録（C++）

#include "oad_c.hh"
// USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

int main(int argc, char* const* argv)
{
   try {
      // Initialize the ORB.
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

      Activation::OAD_var anOAD = Activation::OAD::bind();

      // Create an ImplDef
      extension::CreationImplDef_var _implDef =
            anOAD->create_CreationImplDef();

      _implDef->repository_id = "IDL:Bank/AccountManager:1.0";
      _implDef->object_name = "BankManager";
      _implDef->path_name = "/user/TPBrokerV5/Server";
      _implDef->activation_policy = extension::SHARED_SERVER;
      try {
             anOAD->reg_implementation(
                    *((extension::CreationImplDef*)_implDef));

      } catch(const CORBA::Exception& e) {
            cerr << "reg_implementation Failed:" <<endl;
                  cerr << e << endl;
            return 1;
      }
   }
   catch(const CORBA::Exception& e) {
      cerr << e << endl;
      return 1;
   }

   return 0;
}

コードサンプル15-3　VisiBroker ORBオブジェクトの生成とOADへの登録（Java）

// Register.java
import com.inprise.vbroker.Activation.*;
import com.inprise.vbroker.extension.*;

public class Register{

   public static void main(String[ ] args) {
      // Initialize the ORB.
      org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);
      // Locate an OAD

      try {
         OAD anOAD =
            OADHelper.bind(orb);

         // Create an ImplDef
         CreationImplDef _implDef = new com.inprise.vbroker.
            extension.CreationImplDef();
         _implDef.repository_id =
                              "IDL:Bank/AccountManager:1.0";
         _implDef.object_name = "BankManager";
         _implDef.path_name = "vbj";
         _implDef.id = new byte[0];
         _implDef.activation_policy = com.inprise.vbroker.
            extension.Policy.SHARED_SERVER;
         _implDef.env = new String[0];

         String[ ] str = new String[1];
         str[0] = "Server";
         _implDef.args = str;
         try {
            anOAD.reg_implementation(_implDef);
         } catch (Exception e) {
            System.out.println("Caught " + e);
         }

      }
      catch (org.omg.CORBA.NO_IMPLEMENT e) {
      }
   }
}

15.3.8　OADが渡す引数

OADはオブジェクトインプリメンテーションを開始するときに，そのインプリメンテーションがOADに登録された時点で指定された引数をすべて渡します。

15.4　オブジェクトの登録解除

オブジェクトによって提供されたサービスがもう使用できなくなったか，一時的に停止されたら，そのオブジェクトをOADから登録解除しなければなりません。VisiBroker ORBオブジェクトを登録解除すると，インプリメンテーションリポジトリからそのオブジェクトが削除されます。オブジェクトはスマートエージェントのディクショナリからも削除されます。オブジェクトが登録解除されると，クライアントプログラムはそのオブジェクトを探したり，使用したりできなくなります。また，OAD.change_implementation()メソッドを使用して，そのオブジェクトのインプリメンテーションを変更することもできなくなります。登録プロセスと同様，登録解除はコマンドラインまたはプログラムを使用して実行できます。ここで説明するOADとのVisiBroker ORBオブジェクトインタフェースもあります。

15.4.1　oadutilツールの使用によるオブジェクトの登録解除

oadutil unregコマンドを使用すると，OADに登録された一つ以上のオブジェクトインプリメンテーションを登録解除できます。いったん登録解除されたオブジェクトは，クライアントがオブジェクトをリクエストしても，もうOADによって自動的に活性化できません。oadutil unregコマンドで登録解除できるのは，前回oadutil regコマンドによって登録されたオブジェクトだけです。

インタフェース名だけを指定すると，そのインタフェースに対応するすべてのVisiBroker ORBオブジェクトが登録解除されます。または，インタフェース名とオブジェクト名によってVisiBroker ORBオブジェクトを特定できます。オブジェクトを登録解除すると，そのオブジェクトに対応するすべてのプロセスが終了します。

注

oadutil unregコマンドを使用する前に，ネットワークの少なくとも一つのホストでoadプロセスを起動しなければなりません。

oadutil unregコマンドの構文は次のとおりです。

構文

oadutil unreg [options]

oadutil unregコマンドには表15-4のコマンドライン引数を指定できます。

表15‒4　oadutil unregコマンドのコマンドライン引数

オプション

説明

必須

-i <interface_name>

特定のIDLインタフェース名を指定します。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

リポジトリID指定の詳細については，「15.3　オブジェクト活性化デーモンユーティリティの使用」の「インタフェース名からリポジトリIDへの変換」を参照してください。

-r <repository_id>

特定のリポジトリIDを指定します。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

-s <service name>

特定のサービス名を指定します。一度に指定できるオプションは，-i，-r，-s，-poaのうち一つだけです。

-o <object_name>

特定のオブジェクト名を指定します。これは，インタフェース名またはリポジトリIDがコマンド文で指定された場合だけ使用できます。このオプションは，-s引数または-poa引数を使用している場合には適用できません。

-poa <POA_name>

oadutil reg -poa <POA_name>を使用して登録されたPOAを，登録解除します。

任意指定

-host <host name>

OADを実行中であるホスト名を指定します。

-verbose

バーボースモードを有効にして，メッセージがstdoutに出力されるようにします。

-version

このツールのバージョンを出力します。

登録解除例

oadutil unreg ユーティリティは，次に示す三つの場所から一つ以上のVisiBroker ORBオブジェクトを登録解除します。

OAD

インプリメンテーションリポジトリ

スマートエージェント

oadutil unregコマンドの使用例を次に示します。このコマンドは，InpriseBankという名前を指定したBank::AccountManagerのインプリメンテーションをローカルOADから登録解除します。

oadutil unreg -i Bank::AccountManager -o InpriseBank

15.4.2　OADオペレーションを使用した登録解除

オブジェクトのインプリメンテーションは，OADインタフェースのどのオペレーションまたは属性を使用してもVisiBroker ORBオブジェクトの登録を解除できます。

unreg_implementation(in CORBA::RepositoryId repId, in string object_name)

unreg_interface(in CORBA:: RepositoryId repId)

unregister_all()

attribute boolean destroy_on_unregister

unreg_implementation()

このオペレーションは，特定のリポジトリIDとオブジェクト名を使用してインプリメンテーションを登録解除したい場合に使用します。このオペレーションは，指定されたリポジトリIDとオブジェクト名を現在インプリメントしているすべてのプロセスを終了します。

unreg_interface()

このオペレーションは，特定のリポジトリIDだけを使用してインプリメンテーションを登録解除したい場合に使用します。このオペレーションは，指定されたリポジトリIDを現在インプリメントしているすべてのプロセスを終了します。

unregister_all()

このオペレーションは，すべてのインプリメンテーションを登録解除するために使用します。destroyActiveがtrueに設定されていないかぎり，アクティブなインプリメンテーションはどれも実行を続けます。下位互換性を保つため，unregister_all()メソッドも使用できます。これはunregister_all_destroy(false)メソッドを呼び出すのと同じです。

destroy_on_unregister

この属性は，関連したインプリメンテーションの登録解除時に，発生したすべてのプロセスを解放する場合に使用します。デフォルト値はfalseです。

IDLサンプル15-5　OAD登録解除オペレーション

module Activation {
. . .
   interface OAD {
         . . .
      void unreg_implementation(
            in CORBA::RepositoryId repId,
            in string object_name)
         raises(NotRegistered);
         . . .
      }
}

15.4.3　インプリメンテーションリポジトリの内容表示

oadutilコマンドを使用すると，個々のインプリメンテーションリポジトリの内容をリスト出力できます。oadutilコマンドは，リポジトリ内のインプリメンテーションごとに，すべてのオブジェクトインスタンス名，実行可能プログラムのパス名，活性化モード，およびリファレンスデータをリスト表示します。実行可能プログラムに渡される引数または環境変数もすべてリスト表示されます。

15.5　OADとのIDLインタフェース

OADはVisiBroker ORBオブジェクトとしてインプリメントされており，クライアントプログラムがOADにバインドして，登録されたオブジェクトの状態を照会するためにインタフェースを使用できるようにしています。IDLサンプル15-6に，OADのIDLインタフェース定義を示します。

IDLサンプル15-6　OADインタフェース定義

module Activation
{
   enum State {
      ACTIVE,
      INACTIVE,
      WAITING_FOR_ACTIVATION
   };
   struct ObjectStatus {
      long unique_id;
      State activation_state;
      Object objRef;
   };
   typedef sequence<ObjectStatus> ObjectStatusList;
   struct ImplementationStatus {
      extension::CreationImplDef impl;
      ObjectStatusList status;
   };
   typedef sequence<ImplementationStatus> ImplStatusList;

   exception DuplicateEntry {};
   exception InvalidPath {};
   exception NotRegistered {};
   exception FailedToExecute {};
   exception NotResponding {};
   exception IsActive {};
   exception Busy {};

   interface OAD {
      Object reg_implementation(
            in extension::CreationImplDef impl)
              raises (DuplicateEntry, InvalidPath);
      extension::CreationImplDef get_implementation(
            in CORBA::RepositoryId repId,
            in string object_name)
              raises ( NotRegistered);
      void change_implementation(
            in extension::CreationImplDef old_info,
            in extension::CreationImplDef new_info)
              raises (NotRegistered,InvalidPath,IsActive);
      attribute boolean destroy_on_unregister;
      void unreg_implementation(in CORBA::RepositoryId repId,
            in string object_name)
              raises ( NotRegistered );
      void unreg_interface(in CORBA::RepositoryId repId)
              raises ( NotRegistered );
      void unregister_all();
      ImplementationStatus get_status(
            in CORBA::RepositoryId repId,
            in string object_name)
              raises ( NotRegistered );
      ImplStatusList get_status_interface(
            in CORBA::RepositoryId repId)
              raises (NotRegistered);
      ImplStatusList get_status_all();
   };
};

16　インタフェースリポジトリの使用

この章では，IR（インタフェースリポジトリ）を生成し，Borland Enterprise Server VisiBrokerユーティリティまたは独自のコードを使用してそれにアクセスする方法について説明します。

IRにはCORBAオブジェクトインタフェースの記述が入っています。IR内のデータはIDLファイル内のデータと同じもので，モジュール，インタフェース，オペレーション，およびパラメタの記述ですが，クライアントによるランタイムアクセス用に構成されています。クライアントは，IR（開発者用のオンライン参照ツールとしての機能を果たすこともある）を検索するか，参照対象の任意のオブジェクトのインタフェースを（動的起動インタフェースによってオブジェクトを起動するための準備として）検索できます。

16.1　インタフェースリポジトリとは

IR（インタフェースリポジトリ）は，CORBAオブジェクトのインタフェース情報のデータベースのようなもので，クライアントはこれを使用してランタイム時にインタフェースを調べたり更新したりできます。「13.　ロケーションサービスの使用」で説明したオブジェクトのインスタンスを記述するデータを保持するBorland Enterprise Server VisiBrokerロケーションサービスとは対照的に，IRのデータはインタフェース（型）を記述します。IR内に格納されたインタフェースの要求を満たす使用可能なインスタンスが必ず存在するとは限りません。IR内の情報は（一つまたは複数の）IDLファイル（または複数ファイル）内の情報と同じものですが，クライアントがランタイムに使用しやすい方法で実装されています。

IRを使用するクライアントは，「17.　動的起動インタフェースの使用」で説明するDII（動的起動インタフェース）も使用できます。このようなクライアントは，IRを使用して未知のオブジェクトのインタフェースについて照会し，DIIを使用してオブジェクトのメソッドを呼び出します。ただし，IRとDIIの間にコネクションを確立する必要はありません。例えば，IRを使用して開発者向けの「IDLブラウザ」ツールを作成できますが，このツールでは，メソッドの記述をブラウザからエディタにドラッグすると，テンプレートのメソッド呼び出しが開発者のソースコードに挿入されます。この場合，DIIを使用しないでIRだけを使用します。

IRは，IRサーバ（インプリメンテーション）であるBorland Enterprise Server VisiBrokerのirepプログラムを使用して生成します。Borland Enterprise Server VisiBrokerのidl2irプログラムを使用してIRの更新やデータ入力ができるほか，IRの照会や更新，またはその両方を行う独自のIRクライアントを作成することもできます。

16.1.1　IRの内容

IR内のオブジェクトは階層構造になっており，そのオブジェクトのメソッドがインタフェースに関する情報を明らかにします。通常，インタフェースはオブジェクトを記述するものと考えられていますが，CORBA環境では，オブジェクトの集まりを使用してインタフェースを記述することに意味があります。理由は，この方法によってデータベースなどの新しいメカニズムが不要になるためです。

IRに入れることができるオブジェクトの種類の例として，IDLファイルにIDLモジュール定義を，モジュールにインタフェース定義を，インタフェースにオペレーション（メソッド）定義をそれぞれ入れることができるということを考えてください。これに対応して，IRにModuleDefオブジェクトを，ModuleDefオブジェクトにInterfaceDefオブジェクトを，InterfaceDefオブジェクトにOperationDefオブジェクトをそれぞれ入れることができます。このため，IR ModuleDefから，その中にどのようなInterfaceDefが入っているがわかります。逆に，あるInterfaceDefがどのModuleDefに入っているかがわかります。そのほかのすべてのIDL構成体，例えば例外，属性，valuetypeもIRの中で表現できます。

IRにはタイプコードも入っています。タイプコードはIDLファイル内で明示的に示されるのではなく，IDLファイル内で定義または記述された型（long，string，structなど）から自動的に派生されます。タイプコードは，CORBAのany型（任意の型を示し，動的起動インタフェースで使用される汎用型）のインスタンスのエンコードとデコードに使用されます。

16.1.2　使用できるIRの数

IRは，ほかのオブジェクトと同様に，幾つでも生成できます。IRの生成または使用について，Borland Enterprise Server VisiBrokerが規定するポリシーはありません。IRをサイトにどのように配置し命名するかは，プログラマで決めてください。例えば，中央のIRにすべての「生成」オブジェクトのインタフェースを入れ，個々の開発者は各自のテスト用のIRを生成するという規則を採用してもかまいません。

注

IRは書き込み可能であり，アクセス制御によってプロテクトされていません。クライアントが誤って，または意図的にIRを破壊したり，IRから機密情報を取得したりするおそれがあります。

すべてのオブジェクト用に定義された_get_interfaceメソッド（C++）または_get_interface_defメソッド（Java）を使用したい場合は，VisiBroker ORBがIR内のインタフェースを検索できるよう，最低一つのIRサーバを実行していなければなりません。使用可能なIRがないか，VisiBroker ORBのバインド先であるIRがそのオブジェクト用のインタフェース定義と一緒にロードされていない場合，_get_interfaceメソッド（C++）または_get_interface_defメソッド（Java）は，NO_IMPLEMENT例外を発生させます。

16.2　irepを使用したIRの生成と表示

Borland Enterprise Server VisiBrokerのIRサーバはirepと呼ばれ，binディレクトリにあります。irepプログラムはデーモンとして実行します。irepは，あらゆるオブジェクトインプリメンテーションと同様に，OAD（オブジェクト活性化デーモン）に登録できます。oadutilツールは，（CORBA::Repositoryなどのインタフェース名ではなく）IDL:org.omg/CORBA/ Repository:1.0のようなオブジェクトIDを必要とします。

16.2.1　irepを使用したIRの生成

IRを生成し，その内容を表示するには，irepプログラムを使用します。irepプログラムを使用するための構文は次のとおりです。

構文

irep <driverOptions> <otherOptions> IRepName [file.idl]

表16-1に，irepでIRを生成するための構文を示します。

表16‒1　irepでIRを生成するための構文

構文

説明

IRepName

IRのインスタンス名を指定します。クライアントは，この名前を指定することによって，このIRのインスタンスにバインドできます。

file.idl

irepが，自分の生成したIRにロードするIDLファイルを指定します。irepは終了時にIRの内容をこのファイルに格納します。ファイルを指定しなければ，irepは空のIRを生成します。

表16-2に，irepのオプションの定義を示します。

表16‒2　irepのオプション

オプション

説明

ドライバオプション

-J<java option>

JavaVMにオプションを直接渡します。

-VBJversion

VisiBrokerのバージョンを出力します。

-VBJdebug

VisiBrokerのデバッグ情報を出力します。

-VBJclasspath

クラスパスを指定します。これはCLASSPATH環境変数の指定より優先されます。

-VBJprop <name>[=<value>]

名前・値のペアをJavaVMに渡します。

-VBJjavavm <jvmpath>

JavaVMパスを指定します。

-VBJaddJar <jarfile>

JavaVMを実行する前に，CLASSPATHにjarfileを追加します。

そのほかのオプション

-D, -define foo[=bar]

プリプロセサマクロ（任意で値も指定できる）を定義します。

-I, -include <dir>

#includeサーチ用に追加ディレクトリを指定します。

-P, -no_line_directives

プリプロセサから#lineディレクティブを発しません。デフォルトはオフです。

-H, -list_includes

見つかった#includedファイル名をそのまま表示します。デフォルトはオフです。

-C, -retain_comments

前処理された出力にコメントを保持します。デフォルトはオフです。

-U, -undefine foo

プリプロセサマクロの定義を削除します。

-[no_]idl_strict

IDLソースを厳密にOMG標準解釈させます。デフォルトはオフです。

-[no_]warn_unrecognized_pragmas

#pragmaが認識されない場合に警告します。デフォルトはオンです。

-[no_]back_compat_mapping

VisiBroker 3.x対応のマッピングを使用します。

-h, -help, -usage, -?

ヘルプを出力します。

-version

ソフトウェアバージョン番号を表示します。

-install <service name>

NTサービスとしてインストールします。

-remove <service name>

このNTサービスを取り外します。

次の例は，TestIRというIRをBank.idlというファイルから生成する方法を示しています。

例

irep TestIR Bank.idl

16.2.2　IRの内容表示

Borland Enterprise Server VisiBrokerのir2idlユーティリティまたはBorland Enterprise Server VisiBrokerコンソールアプリケーションを使用してIRの内容を表示できます。ir2idlユーティリティの構文は次のとおりです。

構文

ir2idl -irep IRname

表16-3に，irepでIRの内容を表示するための構文を示します。

表16‒3　irepでIRの内容を表示するための構文

構文

説明

-irep IRname

IRnameに指定したIRインスタンスにバインドするようプログラムに指示します。

ir2idlユーティリティ引数の詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「ir2idl」の記述を参照してください。

16.3　idl2irを使用したIRの更新

IRクライアントであるBorland Enterprise Server VisiBroker idl2irユーティリティを使用して，IRを更新できます。idl2irユーティリティの構文は次のとおりです。

構文

idl2ir [arguments] idl_file_list

idl2irユーティリティ引数の詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「idl2ir」の記述を参照してください。

次の例は，TestIRというIRをBank.idlファイルからの定義によって更新する方法を示しています。

例

idl2ir -irep TestIR -replace Bank.idl

IR内の項目は，idl2irユーティリティやirepユーティリティを使用しても削除できません。項目の削除は次の手順で行います。

irepプログラムを終了するか中止します。

irepコマンドラインで指定したIDLファイルを編集します。

更新したファイルを使用してirepを再び起動します。

IRはシンプルなトランザクションサービスを持っています。指定されたIDLファイルがロードに失敗すると，IRはその内容を前の状態までロールバックします。IDLのロード後は，IRは以降のトランザクションで使用する状態にコミットします。どのリポジトリに対しても，ロールバック用にトランザクションの状態を格納したIRname.rollbackファイルがホームディレクトリにあります。

注

IRのすべての項目を削除したい場合，その内容を新しい空のIDLファイルと置き換えることができます。例えば，Empty.idlという名前のIDLファイルを使用すると，次のコマンドを実行できます。

idl2ir -irep TestIR -replace Empty.idl

16.4　IRの構造の理解

IR内のオブジェクトは階層構造になっており，その階層は，IDL指定でインタフェースが定義されている方法に対応しています。IDLモジュール定義が幾つかのインタフェース定義を含むことがあるのと同様に，IR内の一部のオブジェクトがほかのオブジェクトを含むことがあります。IDLサンプル16-1に示すIDLファイルが，IR内でどのようにしてオブジェクトの階層に変換されるのかを図16-1に示します。

IDLサンプル16-1　Bank.idlファイル

// Bank.idl
module Bank {
   interface Account {
      float balance();
   };
   interface AccountManager {
      Account open(in string name);
   };
};

図16‒1　Bank.idlのIRオブジェクト階層

OperationDefオブジェクトには，パラメタとリターンタイプを保持する追加データ構造体（インタフェースではない）のリファレンスが入っています。

16.4.1　IR内のオブジェクトの識別

表16-4に，IRオブジェクトの識別と分類のために提供されるオブジェクトを示します。

表16‒4　IRオブジェクトの識別と分類に使用するオブジェクト

項目

説明

name

IDL指定の中でモジュール，インタフェース，オペレーションなどに割り当てられた識別子に対応する文字列。識別子は一意でなくてもかまいません。

id

IRObjectを一意に識別する文字列。RepositoryIDには三つのコンポーネントがコロン（:）デリミタで区切られて入っています。最初のコンポーネントは「IDL:」で，最後は「:1.0」などのバージョン番号です。2番目のコンポーネントはスラント（/）文字で区切られた一連の識別子です。通常，最初の識別子は一意のプリフィクスです。

def_kind

IRオブジェクトとして可能なすべての型を表す値を定義した列挙体です。

16.4.2　IRに格納できるオブジェクトの型

IRに入れることができるオブジェクトを表16-5に示します。これらのオブジェクトのほとんどはIDL構文要素に対応しています。例えば，StructDefにはIDLのstruct宣言と同じ情報が入っており，InterfaceDefにはIDLのインタフェース宣言と同じ情報が入っています。IDLの基本型（boolean，longなど）宣言と同じ情報が入っているPrimitiveDefに至るまで，すべてこのように対応しています。

表16‒5　IRに格納できるオブジェクト

オブジェクトタイプ

説明

Repository

ほかのすべてのオブジェクトが入っている最上位モジュールを示します。

ModuleDef

IDLモジュール宣言を示します。この中には，ModuleDef，InterfaceDef，ConstantDef，AliasDef，ExceptionDef，およびIDLモジュールで定義できるそのほかのIDL構成体に相当するIRオブジェクトを入れることができます。

InterfaceDef

IDLインタフェース宣言を示し，OperationDef，ExceptionDef，AliasDef，ConstantDef，およびAttributeDefが入っています。

AttributeDef

IDL属性宣言を示します。

OperationDef

IDLオペレーション（メソッド）宣言を示します。インタフェースのオペレーションを定義します。これには，そのオペレーションに必要なパラメタのリスト，リターン値，そのオペレーションによって発生する可能性がある例外のリスト，およびコンテキストのリストが含まれます。

ConstantDef

IDL定数宣言を示します。

ExceptionDef

IDL例外宣言を示します。

ValueDef

定数，型，値メンバ，例外，オペレーション，および属性のリストが入っているvaluetype定義を示します。

ValueBoxDef

ほかのIDL型の，ボックスに入った単純なvaluetypeを示します。

ValueMemberDef

valuetypeのメンバを示します。

NativeDef

ネイティブ定義を示します。ユーザは独自のネイティブ定義ができます。

StructDef

IDL構造体宣言を示します。

UnionDef

IDL union宣言を示します。

EnumDef

IDL列挙体宣言を示します。

AliasDef

IDL typedef宣言を示します。IR TypedefDefインタフェースは，StructDef，UnionDef，およびそのほかの共通オペレーションを定義する基本インタフェースであることに注意してください。

StringDef

IDLバウンデッドstring宣言を示します。

SequenceDef

IDL sequence宣言を示します。

ArrayDef

IDL配列宣言を示します。

PrimitiveDef

IDL基本宣言（null，void，long，ushort，ulong，float，double，boolean，char，octet，any，TypeCode，Principal，string，objref，longlong，ulonglong，longdouble，wchar，およびwstring）を示します。

16.4.3　継承されるインタフェース

共通メソッドを定義する三つの実体化できない（つまり抽象的な）IDLインタフェースが，IR内の多数のオブジェクト（表16-5参照）に継承されます。表16-6に，これらの広く継承されるインタフェースを示します。これらのインタフェースのほかのメソッドの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「インタフェースリポジトリインタフェースとクラス」の記述を参照してください。

表16‒6　多数のIRオブジェクトが継承するインタフェース

インタフェース

インタフェースを継承する

オブジェクト

主要な照会メソッド

IRObject

Repositoryを含むすべてのIRオブジェクト

def_kind()

モジュールまたはインタフェースなどのIRオブジェクトの定義の種類を返します。

destroy()

IRオブジェクトをデストラクトします。

Container

モジュールまたはインタフェースのような，そのほかのIRオブジェクトを入れることができるIRオブジェクト

lookup()

入っているオブジェクトを名前で検索します。

contents()

Container内のオブジェクトをリスト表示します。

describe_contents()

Container内のオブジェクトを記述します。

Contained

ほかのオブジェクト，つまりContainerの中に入れることができるIRオブジェクト

name()

このオブジェクトの名前です。

defined_in()

オブジェクトを含むContainerです。

describe()

オブジェクトを記述します。

move()

オブジェクトをほかのコンテナに移します。

16.5　IRへのアクセス

クライアントプログラムは，IRのIDLインタフェースを使用して，IR内のオブジェクトについて情報を取得できます。クライアントプログラムはRepositoryにバインドして，コードサンプル16-1に示すメソッドを呼び出せます。このインタフェースの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「インタフェースリポジトリインタフェースとクラス」の記述を参照してください。

コードサンプル16-1　リポジトリクラス（C++）

class CORBA {
   class Repository : public Container {
      . . .
      CORBA::Contained_ptr lookup_id(
            const char * search_id);
      CORBA::PrimitiveDef_ptr get_primitive(
            CORBA::PrimitiveKind kind);
      CORBA::StringDef_ptr create_string(
            CORBA::ULong bound);
      CORBA::SequenceDef_ptr create_sequence(
            CORBA::ULong bound,
            CORBA::IDLType_ptr element_type);
      CORBA::ArrayDef_ptr create_array(
            CORBA::ULong length,
            CORBA::IDLType_ptr element_type);
      . . .
   };
   . . .
};

注

IRを使用するプログラムは，-D_VIS_INCLUDE_IRフラグでコンパイルする必要があります。

コードサンプル16-2　リポジトリインタフェース（Java）

package org.omg.CORBA;
public interface Repository extends Container {
   . . .
   org.omg.CORBA.Contained lookup_id(string id);
   org.omg.CORBA.PrimitiveDef get_primitive(
                     org.omg.CORBA.PrimitiveKind kind);
   org.omg.CORBA.StringDef create_string(long bound);
   org.omg.CORBA.SequenceDef create_sequence(long bound,
                     org.omg.CORBA.IDLType element_type);
   org.omg.CORBA.ArrayDef create_array(long length,
                     org.omg.CORBA.IDLType element_type);
   . . .
}

16.6　サンプルプログラム

ここでは，アカウントを生成して（再び）オープンするための単純なAccountManagerインタフェースを含む，IRの簡単なサンプルを示します。コードはexamples¥vbe¥irディレクトリ内にあります。初期化時にAccountManagerインプリメンテーションは，管理されたアカウントインタフェースのIR定義と接続します。

これは，特定のAccountインプリメンテーションがすでにインプリメントした追加オペレーションをクライアントに提供します。ここでクライアントはわかっている（IDLに記述されている）すべてのオペレーションにアクセスでき，さらに，ほかのオペレーションをサポートするIRを検証し，それを呼び出せます。サンプルでは，IR定義オブジェクトの管理方法と，C++およびJavaのIRを使用したリモートオブジェクトの検査の方法を示します。

このプログラムをテストするには，次の条件が成立している必要があります。

osagentが起動され，実行中である

IRがirepを使用して起動されている

IR起動時のコマンドラインによって，またはidl2irを使用して，IRにIDLファイルがロードされている

クライアントプログラムが起動する

コードサンプル16-3　IR内のインタフェースのオペレーションと属性の検索（C++）

/* PrintIR.C */
#ifndef _VIS_INCLUDE_IR
#define _VIS_INCLUDE_IR
#endif

#include "corba.h"
#include "strvar.h"

int main(int argc, char *argv[ ]) {
   try {
      if (argc != 2) {
      cout << "Usage: PrintIR idlName" << endl;
      exit(1);
      }
      CORBA::String_var idlName = (const char *)argv[1];

      CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
      CORBA::Repository_var rep = CORBA::Repository::_bind();

      CORBA::Contained_var contained = rep->lookup(idlName);
      CORBA::InterfaceDef_var intDef =
         CORBA::InterfaceDef::_narrow(contained);
      if (intDef != CORBA::InterfaceDef::_nil()) {
      CORBA::InterfaceDef::FullInterfaceDescription_var fullDesc =
            intDef->describe_interface();
      cout << "Operations:" << endl;
      for(CORBA::ULong i = 0;
            i < fullDesc->operations.length(); i++)
         cout << " " << fullDesc->operations[i].name << endl;
         cout << "Attributes:" << endl;
         for(i = 0; i < fullDesc->attributes.length(); i++)
            cout << " " << fullDesc->attributes[i].name
                  << endl;
      }else
         cout << "idlName is not an interface: "
               << idlName << endl;

   } catch (const CORBA::Exception& excep) {
      cerr << "Exception occurred ..." << endl;
      cerr << excep << endl;
      exit(1);
   }
   return 0;
}

コードサンプル16-4　IR内のインタフェースのオペレーションと属性の検索（Java）

// Client.java
import org.omg.CORBA.InterfaceDef;
import org.omg.CORBA.InterfaceDefHelper;
import org.omg.CORBA.Request;
import java.util.Random;

public class Client {
   public static void main(String[ ] args) {
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);
         // Get the manager Id
         byte[ ] managerId = "BankManager".getBytes();
         // Locate an account manager. Give the full POA name
         // and the servant ID.
         Bank.AccountManager manager =
            Bank.AccountManagerHelper.bind(orb,
                                  "/bank_ir_poa", managerId);
         // use args[0] as the account name, or a default.
         String name = args.length > 0 ?
                                    args[0] : "Jack B. Quick";
         // Request the account manager to open a named
         // account.
         Bank.Account account = manager.open(name);
         // Get the balance of the account.
         float balance = account.balance();
         // Print out the balance.
         System.out.println("The balance in " + name +
                                "'s account is $" + balance);
         // Calculate and set a new balance
         balance = args.length > 1 ?
            Float.parseFloat(args[1]):
            Math.abs(new Random().nextInt()) % 100000 / 100f;
         account.balance(balance);
         // Get the balance description if it is possible
         // and print it
         String desc = getDescription(account);
         System.out.println("Balance description:¥n" + desc);
      }catch (org.omg.CORBA.SystemException e) {
         System.err.println("System exception caught:" + e);
      }catch (Exception e) {
         System.err.println("Unexpected exception caught:");
         e.printStackTrace();
      }
   }

   static String getDescription(Bank.Account account) {
      // Get the interface repository definition for
      // this interface
      InterfaceDef accountDef = InterfaceDefHelper.
         narrow(account._get_interface_def());
      // Check if this *particular* implementation supports
      // "describe" operation
      if (accountDef.lookup("describe") != null) {
         // We cannot use the static skeleton's method here
         // because at the time of its creation this method
         // was not present in the IDL's version of the
         // Account interface. Use DII instead.
         Request request = account._request("describe");
         request.result().value().insert_string("");
         request.invoke();
         return request.result().value().extract_string();
      }else {
         return "<no description>";
      }
   }
}

第5編　高度概念

17　動的起動インタフェースの使用

この章では，DII（動的起動インタフェース）の使用方法について説明します。ほとんどのクライアントプログラムの開発者は，自分のCORBAオブジェクトの型を知っていて，それらの型のIDLコンパイラが生成したスタブをコードの中に組み込みます。これに対し，汎用的なクライアントを作成しようとする開発者は，どの種類のオブジェクトを起動したいのかが事前にわかりません。このような場合，開発者はDIIを使用して，ランタイム時に入手した情報から任意のCORBAオブジェクトの任意のメソッドを起動できるクライアントを作成します。

17.1　動的起動インタフェースとは

DII（動的起動インタフェース）を使用すると，クライアントプログラムから，そのクライアントの作成時点では型がわからないCORBAオブジェクトに対してメソッドを起動できます。DIIはデフォルトの静的起動とは対照的です。静的起動ではクライアントソースコードに，そのクライアントから起動するCORBAオブジェクトの型ごとに一つずつコンパイラが生成したスタブを組み込む必要があります。つまり，静的起動を使用するクライアントは，起動するオブジェクトの型を事前に宣言します。DIIを使用するクライアントは，どのような種類のオブジェクトが起動されるかがプログラマにもわからないので，そのような宣言をしません。DIIの利点は柔軟性です。DIIを使用すると，クライアントをコンパイルした時点ではインタフェースが存在しなかったオブジェクトも含め，任意のオブジェクトを起動できる汎用的なクライアントを作成できます。DIIの短所は次の2点です。

プログラミングが難しい（実質的に，作成するコードはスタブの機能を果たさなければなりません）

ランタイムに多くの作業が行われるので起動に時間が掛かる

DIIは純粋にクライアントインタフェースであり，静的起動と動的起動はオブジェクトインプリメンテーションの観点から見れば同じものです。

DIIを使用すると，次のようなクライアントを作成できます。

スクリプト環境とCORBAオブジェクトの間のブリッジまたはアダプタ。例えば，スクリプトはブリッジを呼び出し，オブジェクトの識別子，メソッドの識別子，およびパラメタ値を引き渡します。ブリッジは動的リクエストを構築して発行し，結果を受け取り，それをスクリプト環境に返します。そのようなブリッジでは，スクリプト環境がどのような種類のオブジェクトを起動したいかが事前に開発者にわからないので，静的起動を使用できません。

汎用的なオブジェクトテスタ。例えば，あるクライアントが任意のオブジェクトの識別子を使用し，そのインタフェースをIR（インタフェースリポジトリ）から検索し（「16.　インタフェースリポジトリの使用」参照），個々のメソッドを人為的な引数値を使用して起動するとします。このような汎用的なテスタも，静的起動では作成できません。

注

クライアントは，DIIリクエストの中で有効な引数を引き渡さなければなりません。それに失敗すると，サーバのクラッシュも含め，予期できない結果が生じるおそれがあります。IRを使用してパラメタ値の型を動的にチェックすることもできますが，パフォーマンスが低下します。最も効果的な方法は，DIIを使用するクライアントを起動するコード（例えば，スクリプト）の信頼性を高め，確実に有効な引数が引き渡されるようにすることです。

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メソッドを使用します。

17.1.2　オブジェクトのオペレーションを動的に起動する手順

DIIを使用する場合にクライアントが実行する手順を次に示します。

C++の場合，タイプコードがIDLインタフェースとタイプ用に生成されるように，必ずidlコンパイラに-type_code_infoオプションが渡されるようにしてください。idl2cppツールの完全な説明については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「idl2cpp」の記述を参照してください。

使用したいターゲットオブジェクトの汎用的なリファレンスを取得します。

ターゲットオブジェクト用のRequestオブジェクトを生成します。

requestパラメタと返したい結果を初期化します。

リクエストを起動し，結果を待ちます。

結果を抽出します。

17.1.3　DIIを使用したサンプルプログラムの格納場所

DIIの使用方法を示したサンプルプログラムがBorland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/basic/bank_dynamicに入っています。この章では，これらのサンプルプログラムを使って，DIIの概念を説明します。C++の場合，これらのサンプルプログラムをVIS_INCLUDE_IRフラグでコンパイルし，タイプコード生成オプションを追加してください。

17.1.4　idl2javaコンパイラの使用（Java）

idl2javaコンパイラにはフラグ（-dynamic_marshal）があり，このフラグがオンになるとDIIを使用してスタブコードを生成します。DIIの任意の型でこれを行うには，IDLファイルを作成し，-dynamic_marshalでスタブコードを生成し，調べます。

17.2　汎用的なオブジェクトリファレンスを取得

DIIを使用する場合，クライアントプログラムで従来のバインド方法を使用してターゲットオブジェクトのリファレンスを取得する必要はありません。コンパイル時に，ターゲットオブジェクトのクラス定義をクライアントがわからない場合があるためです。

コードサンプル17-1に，VisiBroker ORBオブジェクトが提供するbindメソッドをクライアントプログラムが使用して，オブジェクト名を指定することによってオブジェクトにバインドする方法を示します。このメソッドは汎用CORBA::Object（C++）を返します。

コードサンプル17-1　汎用的なオブジェクトリファレンスを取得する（C++）

. . .
CORBA::Object_var account;
try {
   // initialize the ORB.
   CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
} catch (const CORBA::Exception& e)
   cout << "Failure during ORB_init " << endl;
   cout << e << endl;
}
. . .
try {
   // Request ORB to bind to object supporting the
   // account interface.
   account = orb->bind("IDL:Account:1.0");
} catch (const CORBA::Exception& excep)
   cout << "Error binding to account" << endl;
   cout << excep << endl;
}
cout << "Bound to account object " << endl;
. . .

コードサンプル17-2に，VisiBroker ORBオブジェクトが提供するbindメソッドをクライアントプログラムが使用して，オブジェクト名を指定することによってオブジェクトにバインドする方法を示します。このメソッドは汎用org.omg.CORBA.Object（Java）を返します。

コードサンプル17-2　汎用的なオブジェクトリファレンスを取得する（Java）

. . .
org.omg.CORBA.Object account;
try {
   // initialize the ORB.
   com.inprise.vbroker.CORBA.ORB orb =
                                    (com.inprise.vbroker.CORBA.ORB)
                                    org.omg.CORBA.ORB.init(args, null);
}catch(Exception e) {
   System.err.println ("Failure during ORB_init");
   e.printStackTrace();
}
. . .

try {
   // Request ORB to bind to the object supporting
   // the account interface.
   account = orb.bind("IDL:Account:1.0",
                      "BankManager", null, null);
}catch(Exception excep) {
   System.err.println ("Error binding to account" );
   excep.printStackTrace();
}
System.out.println ("Bound to account object");
. . .

17.3　Requestを生成し初期化

クライアントプログラムがオブジェクトのメソッドを起動した場合，メソッドの起動を表すRequestオブジェクトが生成されます。このRequestオブジェクトはバッファに書き込まれ（つまりマーシャルされ），オブジェクトインプリメンテーションへ送信されます。クライアントプログラムがクライアントスタブを使用する場合に，この処理は透過的に行われます。DIIを使用するクライアントプログラムは，自分自身でRequestオブジェクトを生成し，送信する必要があります。

注

このクラスにはコンストラクタがありません。Requestオブジェクトの生成には，Objectの_requestメソッドまたはObjectの_create_requestメソッドを使用します。

17.3.1　Requestクラス（C++）

コードサンプル17-3に，Requestクラスを示します。リクエストのtargetは，Requestの生成に使用したオブジェクトリファレンスから暗黙的に設定されます。operation名はRequestの生成時に指定しなければなりません。

コードサンプル17-3　Requestクラス（C++）

class Request {
   public:
      CORBA::Object_ptr target() const;
      const char* operation() const;
      CORBA::NVList_ptr arguments();
      CORBA::NamedValue_ptr result();
      CORBA::Environment_ptr env();
      void ctx(CORBA::Context_ptr ctx);
      CORBA::Context_ptr ctx() const;
      CORBA::Status invoke();
      CORBA::Status send_oneway();
      CORBA::Status send_deferred();
      CORBA::Status get_response();
      CORBA::Status poll_response();
      . . .
   };
};

17.3.2　Requestインタフェース（Java）

コードサンプル17-4に，Requestインタフェースを示します。リクエストのtargetは，Requestの生成に使用したオブジェクトリファレンスから暗黙的に設定されます。operation名はRequestの生成時に指定しなければなりません。

コードサンプル17-4　Requestインタフェース（Java）

package org.omg.CORBA;
public abstract class Request {
   public abstract org.omg.CORBA.Object target();
   public abstract java.lang.String operation();
   public abstract org.omg.CORBA.NVList arguments();
   public abstract org.omg.CORBA.NamedValue result();
   public abstract org.omg.CORBA.Environment env();
   public abstract org.omg.CORBA.ExceptionList exceptions();
   public abstract org.omg.CORBA.ContextList contexts();
   public abstract void ctx(org.omg.CORBA.Context ctx);
   public abstract org.omg.CORBA.Context ctx();
   public abstract org.omg.CORBA.Any add_in_arg();
   public abstract org.omg.CORBA.Any add_named_in_arg();
   public abstract org.omg.CORBA.Any add_inout_arg();
   public abstract org.omg.CORBA.Any add_named_inout_arg();
   public abstract org.omg.CORBA.Any add_out_arg();
   public abstract org.omg.CORBA.Any add_named_out_arg();
   public abstract void set_return_type();
   public abstract org.omg.CORBA.Any return_value();
   public abstract void invoke();
   public abstract void send_oneway();
   public abstract void send_deferred();
   public abstract void get_response();
   public abstract boolean poll_response();
}

17.3.3　DIIリクエストを生成し初期化する方法

オブジェクトへのバインドを発行し，オブジェクトリファレンスを取得したあと，Requestオブジェクトを生成するために二つの方法のどちらかを使用できます。コードサンプル17-5にCORBA::Objectクラスが提供するメソッドを示します。コードサンプル17-6にorg.omg.CORBA.Objectインタフェースが提供するメソッドを示します。

コードサンプル17-5　Requestオブジェクトを生成する三つのメソッド（C++）

class Object {
   . . .
   CORBA::Request_ptr _request(Identifier operation);
   CORBA::Status _create_request(
      CORBA::Context_ptr ctx,
      const char *operation,
      CORBA::NVList_ptr arg_list,
      CORBA::NamedValue_ptr result,
      CORBA::Request_ptr request,
      CORBA::Flags req_flags);
   CORBA::Status _create_request(
      CORBA::Context_ptr ctx,
      const char *operation,
      CORBA::NVList_ptr arg_list,
      CORBA::NamedValue_ptr result,
      CORBA::ExceptionList_ptr eList,
      CORBA::ContextList_ptr ctxList,
      CORBA::Request_out request,
      CORBA::Flags req_flags);
    . . .
};

コードサンプル17-6　Requestオブジェクトを生成する三つのメソッド（Java）

package org.omg.CORBA;
public interface Object {
. . .
   public org.omg.CORBA.Request _request(
                          java.lang.String operation);

   public org.omg.CORBA.Request _create_request(
      org.omg.CORBA.Context ctx,
      java.lang.String operation,
      org.omg.CORBA.NVList arg_list,
      org.omg.CORBA.NamedValue result
   );

   public org.omg.CORBA.Request _create_request(
      org.omg.CORBA.Context ctx,
      java.lang.String operation,
      org.omg.CORBA.NVList arg_list,
      org.omg.CORBA.NamedValue result,
      org.omg.CORBA.ExceptionList exceptions,
      org.omg.CORBA.ContextList contexts
   );
. . .
}

17.3.4　_create_requestメソッドを使用

_create_requestメソッドを使用してRequestオブジェクトを生成し，Context，オペレーション名，引き渡したい引数リスト，および結果を初期化できます。

オプションとして，リクエストのContextListを設定することもできます。ContextListは，リクエストのIDLで定義された属性に対応するものです。requestパラメタは，このオペレーション用に生成されたRequestオブジェクトをポイントします。

17.3.5　_requestメソッドを使用

コードサンプル17-7に，_requestメソッドを使用して，オペレーション名だけを指定してRequestオブジェクトを生成する方法を示します。floatリクエストの生成後，floatリクエストのadd_in_argメソッドを起動すると，入力パラメタアカウント名を追加して，その結果型がset_return_typeメソッドの呼び出しによるオブジェクトリファレンス型となるよう初期化されます。呼び出し後に，メソッドresultに対する結果の呼び出しによってリターン値が抽出されます。アカウントマネージャインスタンスで別のメソッドを起動するには，同じ手順が繰り返されます。その場合，inパラメタとリターン型だけが異なります。

reqのAnyオブジェクトは，希望のアカウントnameによって初期化され，入力引数としてrequestの引数リストに加えられます。リクエストの初期化の最後の手順は，floatを受信するためにresult値を設定することです。

17.3.6　Requestオブジェクトの生成例

Requestオブジェクトはオペレーション，引数，および結果に対応するすべてのメモリの所有権を保持し，プログラマがそれらの項目を解放しないようにします。コードサンプル17-7にRequestオブジェクトの生成例（C++），コードサンプル17-8にRequestオブジェクトの生成例（Java）を示します。

コードサンプル17-7　Requestオブジェクトを生成する（C++）

. . .
CORBA::NamedValue_ptr result;
CORBA::Any_ptr resultAny;
CORBA::Request_var req;
CORBA::Any customer;

. . .
try {
   req = account->_request("balance");

   // Create argument to request
   customer <<= (const char *) name;
   CORBA::NVList_ptr arguments = req->arguments();
   arguments->add_value("customer", customer, CORBA::ARG_IN);

   // Set result
   result = req->result();
   resultAny = result->value();
   resultAny->replace(CORBA::_tc_float, &result);

} catch(CORBA::Exception& excep) {
. . .

コードサンプル17-8　Requestオブジェクトを生成する（Java）

// Client.java
public class Client {
   public static void main(String[ ] args) {
      if (args.length ! = 2) {
         System.out.println(
          "Usage: vbj Client <manager-name> <account-name>¥n");
         return;
      }
      String managerName = args[0];
      String accountName = args[1];
      org.omg.CORBA.Object accountManager, account;
      org.omg.CORBA.ORB orb =
         org.omg.CORBA.ORB.init(args, null);
      accountManager =
         orb.bind("IDL:Bank/AccountManager:1.0",
                  managerName, null, null);
      org.omg.CORBA.Request request =
         accountManager._request("open");
      request.add_in_arg().insert_string(accountName);
      request.set_return_type(orb.get_primitive_tc(
         org.omg.CORBA.TCKind.tk_objref)
      );
      request.invoke();
      account = request.result().value().extract_Object();
      org.omg.CORBA.Request request =
                                 account._request("balance");
      request.set_return_type(orb.get_primitive_tc(
         org.omg.CORBA.TCKind.tk_float)
      );
      request.invoke();
      float balance =
          request.result().value().extract_float();
      System.out.println("The balance in " + accountName +
         "'s account is $" + balance);
   }
}

17.3.7　リクエストのコンテキストを設定（C++）

サンプルプログラムでは使用されていませんが，Requestの一部としてオブジェクトインプリメンテーションに渡され，NamedValueオブジェクトとして格納されるプロパティのリストを含めるためにContextオブジェクトを使用できます。これらのプロパティは，オブジェクトインプリメンテーションと通信する暗黙的な情報を表します。

コードサンプル17-9　Contextクラス

class Context {
   public:
      const char *context_name() const;
      CORBA::Context_ptr parent();
      CORBA::Status create_child(
            const char *name, CORBA::Context_ptr&);
      CORBA::Status set_one_value(
            const char *name, const CORBA::Any&);
      CORBA::Status set_values(CORBA::NVList_ptr);
      CORBA::Status delete_values(const char *name);
      CORBA::Status get_values(
            const char *start_scope,
            CORBA::Flags,
            const char *name,
            CORBA::NVList_ptr&) const;
};

17.3.8　リクエストの引数を設定

Requestの引数はNVListオブジェクトで表現されます。このオブジェクトは名前・値のペアをNamedValueオブジェクトとして格納します。このリストのポインタを取得するには，argumentsメソッドを使用します。そのあと，このポインタを使用して個々の引数の名前と値を設定できます。

注

Requestを送信する前に，必ず引数を初期化してください。そうしないと，マーシャルエラーが発生し，サーバの処理が中断されることがあります。

(1)　NVListを使用して引数のリストをインプリメントする

このクラスは，メソッド起動用の引数を表すNamedValueオブジェクトのリストをインプリメントします。リスト内のオブジェクトの追加，削除，および照会を行うメソッドが提供されます。

コードサンプル17-10　NVListクラス（C++）

class NVList {
   public:
      . . .
      CORBA::Long count() const;
      CORBA::NamedValue_ptr add(CORBA::Flags flags);
      CORBA::NamedValue_ptr add_item(
         const char *name, CORBA::Flags flags);
      CORBA::NamedValue_ptr add_value(
         const char *name,
         const CORBA::Any *any,
         CORBA::Flags flags);

   CORBA::NamedValue_ptr add_item_consume(
         char *name, CORBA::Flags flags);
   CORBA::NamedValue_ptr add_value_consume(
         char *name,
         CORBA::Any *any,
         CORBA::Flags flags);
   CORBA::NamedValue_ptr item(CORBA::Long index);
   CORBA::Status remove(CORBA::Long index);
   . . .
};

コードサンプル17-11　NVListクラス（Java）

package org.omg.CORBA;

public abstract class NVList {
   public int count();
   public org.omg.CORBA.NamedValue add(int flags);
   public org.omg.CORBA.NamedValue add_item(
                             java.lang.String name, int flags);
   public org.omg.CORBA.NamedValue add_value(
      java.lang.String name,
      org.omg.CORBA.Any value,
      int flags
   );
   public org.omg.CORBA.NamedValue item(int index);
   public void remove(int index);
}

(2)　NamedValueクラスを使用して入出力引数を設定する

このクラスは，メソッド起動リクエストの入出力両用の引数を表す名前・値のペアをインプリメントします。NamedValueクラスは，クライアントプログラムへ返すリクエストの結果を表すために使用することもできます。nameプロパティは単なる文字列であり，valueプロパティはAnyクラスによって表されます。コードサンプル17-12にNamedValueクラスの例（C++），およびコードサンプル17-13にNamedValueクラスの例（Java）を示します。

注

Javaの場合，このクラスにコンストラクタはありません。NamedValueオブジェクトのリファレンスを取得するには，ORB.create_named_valueメソッドを使用します。

コードサンプル17-12　NamedValueクラス（C++）

class NamedValue{
   public:
      const char *name() const;
      CORBA::Any *value() const;
      CORBA::Flags flags() const;
};

コードサンプル17-13　NamedValueインタフェース（Java）

package org.omg.CORBA;
public abstract class NamedValue {
   public java.lang.String name();
   public org.omg.CORBA.Any value();
   public int flags();
}

表17-1は，NamedValueクラスのメソッドの説明です。

表17‒1　NamedValueのメソッド

メソッド

説明

name

項目名のポインタを返します。このポインタを使用して名前を初期化できます。

value

項目の値を表すAnyオブジェクトのポインタを返します。このポインタを使用して値を初期化できます。詳細については，「17.3.9　Anyクラスを使用して型を保護した状態で引き渡す」を参照してください。

flags

この項目が入力引数，出力引数，入出力両用の引数のどれであるかを示します。項目が入出力両用の引数である場合は，VisiBroker ORBが引数のコピーを作成して呼び出し側のメモリをそのまま残すように指示するフラグを指定できます。次のフラグがあります。

ARG_IN

ARG_OUT

ARG_INOUT

17.3.9　Anyクラスを使用して型を保護した状態で引き渡す

このクラスは，IDL指定型を保持し，タイプセーフ方式で引き渡せるようにするために使用します。

(1)　C++の場合

このクラスのオブジェクトは，含まれているオブジェクトの型を定義するTypeCodeのポインタと，その含まれたオブジェクトのポインタを持ちます。オブジェクトの値と型を初期化し照会するメソッドだけでなく，オブジェクトの構築，コピー，および解放を行うメソッドも提供されます。さらに，オブジェクトをストリームに書き込んだり，ストリームから読み取ったりするストリームメソッドも提供されます。コードサンプル17-14に定義例を示します。

コードサンプル17-14　Anyクラス（C++）

class Any {
   public:
      . . .
      CORBA_TypeCode_ptr type();
      void type(CORBA_TypeCode_ptr tc);
      const void *value() const;
      static CORBA::Any_ptr _nil();
      static CORBA::Any_ptr _duplicate(CORBA::Any *ptr);
      static void _release(CORBA::Any *ptr);
      . . .
}

(2)　Javaの場合

このクラスのオブジェクトは，含まれているオブジェクトの型を定義するTypeCodeのリファレンスと，その含まれたオブジェクトのリファレンスを持ちます。オブジェクトの値と型を初期化し照会するメソッドだけでなく，オブジェクトの構築，コピー，および解放を行うメソッドも提供されます。さらに，オブジェクトをストリームに書き込んだり，ストリームから読み取ったりするストリームメソッドも提供されます。コードサンプル17-15に定義例を示します。

コードサンプル17-15　Anyクラス（Java）

package org.omg.CORBA;
public abstract class Any {
   public abstract TypeCode type();
   public abstract void type(TypeCode type);
   public abstract void read_value(InputStream input,
                                   TypeCode type);
   public abstract void write_value(OutputStream output);
   public abstract boolean equal(Any rhs);
   . . .
}

17.3.10　TypeCodeクラスを使用して引数または属性の型を表す

このクラスは，IRとIDLコンパイラが引数または属性の型を表すために使用します。Requestオブジェクトの中では，引数の型を指定する場合に，AnyクラスとともにTypeCodeオブジェクトも使用します。

C++の場合，TypeCodeオブジェクトは，kindとパラメタリストプロパティを持っています。コードサンプル17-16にTypeCodeクラスの例（C++）を示します。

Javaの場合，TypeCodeオブジェクトは，kindとパラメタリストプロパティを持っており，TCKindクラスで定義した値のどれかで表されます。コードサンプル17-17にTypeCodeクラスの例（Java）を示します。

注

Javaの場合，このクラスにはコンストラクタはありません。ORB.get_primitive_tcメソッドか，またはORB.create_*_tcメソッドの一つを使用して，TypeCodeオブジェクトを作成してください。詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「ORB」の記述を参照してください。

表17-2に，TypeCodeオブジェクトの種類とパラメタを示します。

表17‒2　TypeCodeの種類とパラメタ

種類

パラメタリスト

tk_abstract_interface

repository_id，interface_name

tk_alias

repository_id，alias_name，TypeCode

tk_any

なし

tk_array

length，TypeCode

tk_boolean

なし

tk_char

なし

tk_double

なし

tk_enum

repository_id，enum-name，enum-id¹，enum-id²，…enum-idn

tk_except

repository_id，exception_name，StructMembers

tk_fixed

digits，scale

tk_float

なし

tk_long

なし

tk_longdouble

なし

tk_longlong

なし

tk_native

id，name

tk_null

なし

tk_objref

repository_id，interface_id

tk_octet

なし

tk_Principal

なし

tk_sequence

TypeCode，maxlen

tk_short

なし

tk_string

maxlen-integer

tk_struct

repository_id，struct-name，{member¹，TypeCode¹}，{membern，TypeCoden}

tk_TypeCode

なし

tk_ulong

なし

tk_ulonglong

なし

tk_union

repository_id，union-name，switch TypeCode，{label-value¹，member-name¹，TypeCode¹}，{label-valuen，member-namen，TypeCoden}

tk_ushort

なし

tk_value

repository_id，value_name，boxType

tk_value_box

repository_id，value_name，typeModifier，concreteBase，members

tk_void

なし

tk_wchar

なし

tk_wstring

なし

コードサンプル17-16　TypeCodeクラス（C++）

class _VISEXPORT CORBA_TypeCode {
   public:
      . . .
      // For all CORBA_TypeCode kinds
      CORBA::Boolean equal(CORBA_TypeCode_ptr tc) const;
      CORBA::Boolean equivalent(CORBA_TypeCode_ptr tc) const;
      CORBA_TypeCode_ptr get_compact_typecode() const;
      CORBA::TCKind kind() const // . . .
      // For tk_objref, tk_struct, tk_union,
            tk_enum, tk_alias and tk_except
      virtual const char* id() const; // raises(BadKind);
      virtual const char *name() const; // raises(BadKind);
      // For tk_struct, tk_union, tk_enum and tk_except
      virtual CORBA::ULong member_count() const;
            // raises((BadKind));
      virtual const char *member_name(
            CORBA::ULong index) const;
            // raises((BadKind, Bounds));
      // For tk_struct, tk_union and tk_except
      virtual CORBA_TypeCode_ptr member_type(
            CORBA::ULong index) const;
            // raises((BadKind, Bounds));
      // For tk_union
      virtual CORBA::Any_ptr member_label(
            CORBA::ULong index) const;
            // raises((BadKind, Bounds));
      virtual CORBA_TypeCode_ptr discriminator_type() const;
            // raises((BadKind));
      virtual CORBA::Long default_index() const;
            // raises((BadKind));
      // For tk_string, tk_sequence and tk_array
      virtual CORBA::ULong length() const; // raises(
            (BadKind));
      // For tk_sequence, tk_array and tk_alias
      virtual CORBA_TypeCode_ptr content_type() const;
            // raises((BadKind));
      // For tk_fixed
      virtual CORBA::UShort fixed_digits() const;
            // raises (BadKind)
      virtual CORBA::Short fixed_scale() const;
            // raises (BadKind)

       // for tk_value
      virtual CORBA::Visibility member_visibility(
            CORBA::ULong index)const;
            //raises(BadKind, Bounds);
      virtual CORBA::ValueModifier type_modifier() const;
            // raises(BadKind);
      virtual CORBA::TypeCode_ptr concrete_base_type() const;
            // raises(BadKind);
};

コードサンプル17-17　TypeCodeインタフェース（Java）

public abstract class TypeCode extends java.lang.Object
      implements org.omg.CORBA.portable.IDLEntity {
   public abstract boolean equal(org.omg.CORBA.TypeCode tc);
   public boolean equivalent(org.omg.CORBA.TypeCode tc);
   public abstract org.omg.CORBA.TCKind kind();
   public TypeCode get_compact_typecode();
   public abstract java.lang.String id()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
   public abstract java.lang.String name()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
   public abstract int member_count()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
   public abstract java.lang.String member_name(int index)
      throws org.omg.CORBA.TypeCodePackage.BadKind,
         org.omg.CORBA.TypeCodePackage.Bounds;
   public abstract org.omg.CORBA.TypeCode member_type(
                                                  int index)
      throws org.omg.CORBA.TypeCodePackage.BadKind,
         org.omg.CORBA.TypeCodePackage.Bounds;

   public abstract org.omg.CORBA.Any member_label(int index)
      throws org.omg.CORBA.TypeCodePackage.BadKind,
         org.omg.CORBA.TypeCodePackage.Bounds;
   public abstract org.omg.CORBA.TypeCode
                                     discriminator_type()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
   public abstract int default_index()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
   public abstract int length()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
   public abstract org.omg.CORBA.TypeCode content_type()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
   public short fixed_digits()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
   public short fixed_scale()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
   public short member_visibility(int index)
      throws org.omg.CORBA.TypeCodePackage.BadKind,
         org.omg.CORBA.Bounds;
   public short type_modifier()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
   public TypeCode concrete_base_type()
      throws org.omg.CORBA.TypeCodePackage.BadKind;
}

17.4　DIIリクエストを送信し，結果を受信

コードサンプル17-3および17-4に示したRequestクラスは，正しく初期化されたあと，リクエストを送信する複数のメソッドを提供します。

17.4.1　リクエストを起動

リクエストを送信する最も単純な方法は，そのリクエストのinvokeメソッドを呼び出すことです。このメソッドはリクエストを送信し，応答を待ってからクライアントプログラムに戻ります。return_valueメソッドは，リターン値を表すAnyオブジェクトのポインタ（C++）またはリファレンス（Java）を返します。

コードサンプル17-18　invokeを使用してリクエストを送信する（C++）

try {
   . . .
   // Create request that will be sent to the account object
   request = account->_request("balance");
   // Set the result type
   request->set_return_type(CORBA::_tc_float);
   // Execute the request to the account object
   request->invoke();
   // Get the return balance
   CORBA::Float balance;
   CORBA::Any& balance_result = request->return_value();
   balance_result >>= balance;
   // Print out the balance
   cout << "The balance in " << name << "'s account is $"
         << balance << endl;
} catch(const CORBA::Exception& e) {
   cerr << e << endl;
   return 1;
}
return 0;
. . .

コードサンプル17-19　invokeを使用してリクエストを送信する（Java）

try {
   . . .
   // Create request that will be sent to the account object
   request = account._request("balance");
   // Set the result type
   request.set_return_type(orb.get_primitive_tc
                  (org.omg.CORBA.TCKind.tk_float));
   // Execute the request to the account object
   request.invoke();
   // Get the return balance
   float balance;
   org.omg.CORBA.Any balance_result = request.return_value();
   balance = balance_result.extract_float();
   // Print out the balance
   System.out.println("The balance in " + name +
                      "'s account is $" + balance);
} catch(Exception e) {
   e.printStackTrace();
}

17.4.2　send_deferredメソッドを使用して遅延DIIリクエストを送信

オペレーション要求の送信には，応答を待ち続けないメソッドであるsend_deferredも使用できます。このメソッドを使用したクライアントは，リクエストを送信したあと，poll_responseメソッドを使用して応答が返ってきているかどうかを調べることができます。get_responseメソッドは，応答を受信するまで待ちます。コードサンプル17-20にsend_deferredメソッドとpoll_responseメソッドを使用して遅延DIIリクエストを送信する方法（C++），コードサンプル17-21に遅延DIIリクエストを送信する方法（Java）を示します。

コードサンプル17-20　send_deferredメソッドとpoll_responseメソッドを使用して遅延DIIリクエストを送信する（C++）

. . .
try {
   // Create request that will be sent to the manager object
   CORBA::Request_var request = manager->_request("open");
   // Create argument to request
   CORBA::Any customer;
   customer <<= (const char *) name;
   CORBA::NVList_ptr arguments = request->arguments();
   arguments->add_value( "name" , customer, CORBA::ARG_IN );
   // Set result type
   request->set_return_type(CORBA::_tc_Object);
   // Creation of a new account can take some time
   // Execute the deferred request to the manager object
   request->send_deferred();
   VISPortable::vsleep(1);
   while (!request->poll_response()) {
      cout << " Waiting for response..." << endl;
      VISPortable::vsleep(1); // Wait one second between polls
   }
   request->get_response();
   // Get the return value
   CORBA::Object_var account;
   CORBA::Any& open_result = request->return_value();
   open_result >>= CORBA::Any::to_object(account.out());
. . .
}

コードサンプル17-21　send_deferredメソッドとpoll_responseメソッドを使用して遅延DIIリクエストを送信する（Java）

try {
. . .
   // Create request that will be sent to the manager object
   org.omg.CORBA.Request request = manager._request("open");
   // Create argument to request
   org.omg.CORBA.Any customer = orb.create_any();
   customer.insert_string(name);
   org.omg.CORBA.NVList arguments = request.arguments();
   arguments.add_value("name",
                       customer, org.omg.CORBA.ARG_IN.value);
   // Set result type
   request.set_return_type(orb.get_primitive_tc
      (org.omg.CORBA.TCKind.tk_objref));
   // Creation of a new account can take some time
   // Execute the deferred request to the manager
   // object-plist
   request.send_deferred();
   Thread.currentThread().sleep(1000);
   while (!request.poll_response()) {
      System.out.println(" Waiting for response...");
      Thread.currentThread().sleep(1000);
                             // Wait one second between polls
   }
   request.get_response();
   // Get the return value
   org.omg.CORBA.Object account;
   org.omg.CORBA.Any open_result = request.return_value();
   account = open_result.extract_Object();
   . . .
}catch(Exception e) {
   e.printStackTrace();
}

17.4.3　send_onewayメソッドを使用して非同期DIIリクエストを送信

send_onewayメソッドを使用すると，非同期リクエストを送信できます。一方向リクエストは，オブジェクトインプリメンテーションからクライアントへ返される応答はありません。

17.4.4　複数のリクエストを送信

Requestオブジェクトの配列を使用すると，DII Requestオブジェクトのシーケンスを生成できます。リクエストのシーケンスを送信するには，VisiBroker ORBメソッドのsend_multiple_requests_onewayかsend_multiple_requests_deferredを使用します。リクエストのシーケンスを一方向リクエストとして送信した場合，どのリクエストにもサーバからの応答は期待できません。

C++の場合，コードサンプル17-22に，二つのリクエストがどのように生成され，リクエストのシーケンスを生成するためにどのように使用されるかを示します。シーケンスは，send_multiple_requests_deferredメソッドによって送信されます。

コードサンプル17-22　send_multiple_requests_deferredメソッドによる複数の遅延リクエストの送信（C++）

. . .
// Create request to balance
try {
   req1 = account->_request("balance");
   // Create argument to request
   customer1 <<= (const char *) "Happy";
   CORBA::NVList_ptr arguments = req1->arguments();
   arguments->add_value("customer", customer1, CORBA::ARG_IN);
   // Set result
   . . .
} catch(const CORBA::Exception& excep) {
   cout << "Error while creating request" << endl;
   cout << excep << endl;
}
// Create request2 to slowBalance
try {
   req2 = account->_request("slowBalance");
   // Create argument to request
   customer2 <<= (const char *) "Sleepy";
   CORBA::NVList_ptr arguments = req2->arguments();
   arguments->add_value("customer", customer2, CORBA::ARG_IN);
   // Set result
   . . .
}catch(const CORBA::Exception& excep) {
   cout << "Error while creating request" << endl;
   cout << excep << endl;
}
// Create request sequence
CORBA::Request_ptr reqs[2];
reqs[0] = (CORBA::Request*) req1;
reqs[1] = (CORBA::Request*) req2;
CORBA::RequestSeq reqseq((CORBA::ULong)2, 2,
      (CORBA::Request_ptr *)reqs);
// Send the request
try {
   orb->send_multiple_requests_deferred(reqseq);
   cout << "Send multiple deferred calls are made..." << endl;
} catch(const CORBA::Exception& excep) {
. . .

17.4.5　複数のリクエストを受信

send_multiple_requests_deferredを使用してリクエストのシーケンスを送信した場合は，poll_next_responseメソッドとget_next_responseメソッドを使用して，サーバから各リクエストについて送信される応答を受信します。

VisiBroker ORBメソッドpoll_next_responseを使用すると，サーバから応答を受信したかどうかを調べることができます。このメソッドは，一つでも応答があればtrue（真）を返し，何も応答がなければfalse（偽）を返します。

VisiBroker ORBメソッドget_next_responseを使用すると，応答を受信できます。何も応答がなければ，このメソッドは応答を受信するまで待ち続けます。クライアントプログラムを待たせ続けたくない場合は，まずpoll_next_responseメソッドを使用して応答が入手できるかどうかを調べ，次にget_next_responseメソッドを使用して結果を受信します。コードサンプル17-23に複数のリクエストを送受信するVisiBroker ORBのメソッド（C++），コードサンプル17-24に複数のリクエストを送受信するVisiBroker ORBのメソッド（Java）を示します。

コードサンプル17-23　複数のリクエストを送信し結果を受信するVisiBroker ORBメソッド（C++）

class CORBA {
   class ORB {
      . . .
      typedef sequence <Request_ptr> RequestSeq;
      void send_multiple_requests_oneway(const RequestSeq &);
      void send_multiple_requests_deferred(const RequestSeq &);
      Boolean poll_next_response();
      Status get_next_response();
      . . .
   };
};

コードサンプル17-24　複数のリクエストを送信し結果を受信するVisiBroker ORBメソッド（Java）

package org.omg.CORBA;
public abstract class ORB {
   public abstract org.omg.CORBA.Environment
                                        create_environment();
   public abstract void send_multiple_requests_oneway(
                               org.omg.CORBA.Request[ ] reqs);
   public abstract void send_multiple_requests_deferred(
                               org.omg.CORBA.Request[ ] reqs);
   public abstract boolean poll_next_response();
   public abstract org.omg.CORBA.Request get_next_response();
   . . .
}

17.5　DIIと一緒にIRを使用

DII Requestオブジェクトに取り込む必要がある情報ソースの一つは，IRです（「16.　インタフェースリポジトリの使用」参照）。次に示すのは，IRを使用してオペレーションのパラメタを取得する場合の例です。この例は，実際のDIIアプリケーションでは一般的ではありませんが，リモートオブジェクトの型（Account）とそのメソッドの一つの名前（balance）を組み込み情報として持っています。実際のDIIアプリケーションでは，その情報をソースの外部，例えばユーザから取得します。

例

任意のAccountオブジェクトにバインドします。

IRの中からAccountのbalanceメソッドを検索し，IRのOperationDefからオペレーションリストを作成します。

引数と結果のコンポーネントを生成し，それらを_create_requestメソッドに引き渡します。balanceメソッドが例外を返さないことに注意してください。

Requestを起動し，結果を抽出して出力します。

コードサンプル17-25　IRとDIIの使用（C++）

// acctdii_ir.C
// This example illustrates IR and DII

#include <iostream.h>
#include "corba.h"

int main(int argc, char* const* argv) {
   CORBA::ORB_ptr orb;
   CORBA::Object_var account;

   CORBA::NamedValue_var result;
   CORBA::Any_ptr resultAny;
   CORBA::Request_var req;
   CORBA::NVList_var operation_list;

   CORBA::Any customer;
   CORBA::Float acct_balance;

try {
   // use argv[1] as the account name, or a default.
   CORBA::String_var name;
   if (argc == 2)
      name = (const char *) argv[1];
   else
      name = (const char *) "Default Name";
   try {
      // Initialize the ORB.
      orb = CORBA::ORB_init(argc, argv);
   } catch(const CORBA::Exception& excep) {
      cout << "Failure during ORB_init" << endl;
      cout << excep << endl;
      exit(1);
   }

   cout << "ORB_init succeeded" << endl;

   // Unlike traditional binds, this bind is called off of "orb"
   // and returns a generic object pointer based
   // on the interface name
   try {
      account = orb->bind("IDL:Account:1.0");
   } catch(const CORBA::Exception& excep) {
      cout << "Error binding to account" << endl;
      cout << excep << endl;
      exit(2);
   }

   cout << "Bound to account object" << endl;

   // Obtain Operation Description for the "balance" method of
   // the Account
   try {
      CORBA::InterfaceDef_var intf = account->_get_interface();
      if (intf == CORBA::InterfaceDef::_nil()) {
         cout << "Account returned a nil interface definition."
              << endl;
         cout << "Be sure an Interface Repository is
               running and"
              << endl;
         cout << "properly loaded" << endl;
         exit(3);
      }
      CORBA::Contained_var oper_container =
            intf->lookup("balance");
      CORBA::OperationDef_var oper_def =
      CORBA::OperationDef::_narrow(oper_container);
      orb->create_operation_list(
            oper_def, operation_list.out());

   } catch(const CORBA::Exception& excep) {
      cout << "Error while obtaining operation list" << endl;
      cout << excep << endl;
      exit(4);
   }

   // Create request that will be sent to the account object
   try {
      // Create placeholder for result
      orb->create_named_value(result.out());
      resultAny = result->value();
      resultAny->replace( CORBA::_tc_float, &result);

      // Set the argument value within the operation_list
      CORBA::NamedValue_ptr arg = operation_list->item(0);
      CORBA::Any_ptr anyArg = arg->value();
      *anyArg <<= (const char *) name;

      // Create the request
      account->_create_request(CORBA::Context::_nil(),
            "balance",
            operation_list,
            result,
            req.out(),
            0);

   } catch(const CORBA::Exception& excep) {
      cout << "Error while creating request" << endl;
      cout << excep << endl;
      exit(5);
   }

   // Execute the request
   try {
      req->invoke();
      CORBA::Environment_ptr env = req->env();
      if ( env->exception() ) {
         cout << "Exception occurred" << endl;
         cout << *(env->exception()) << endl;
         acct_balance = 0;
      } else {
         // Get the return value;
         acct_balance = *(CORBA::Float *)resultAny->value();
      }
   } catch(const CORBA::Exception& excep) {
      cout << "Error while invoking request" << endl;
      cout << excep << endl;
      exit(6);
   }

   // Print out the results
   cout << "The balance in " << name << "'s account is $";
   cout << acct_balance << "." << endl;
} catch ( const CORBA::Exception& excep ) {
   cout << "Error occurred" << endl;
   cout << excep << endl;
}

18　動的スケルトンインタフェースの使用

この章では，オブジェクトサーバがランタイム時にどのようにしてオブジェクトインプリメンテーションを動的に生成し，クライアントリクエストにサービスするかについて説明します。

18.1　動的スケルトンインタフェースとは

DSI（動的スケルトンインタフェース）は，生成されたスケルトンインタフェースから何も継承しないオブジェクトインプリメンテーションを生成する方式を提供します。通常，オブジェクトインプリメンテーションはidl2cppコンパイラ（C++）またはidl2javaコンパイラ（Java）によって生成されたスケルトンクラスから派生します。DSIを使用すると，オブジェクトはidl2cppコンパイラ（C++）またはidl2javaコンパイラ（Java）が生成したスケルトンクラスを継承しないで自分自身をVisiBroker ORBに登録し，クライアントからオペレーション要求を受信し，リクエストを処理し，結果をクライアントに返せます。

注

クライアントプログラムから見た場合，DSIを使用してインプリメントされたオブジェクトは，ほかのVisiBroker ORBオブジェクトとまったく同じように動作します。クライアントは，DSIを使用するオブジェクトインプリメンテーションと通信するために特別な処理を提供する必要はありません。

VisiBroker ORBは，オブジェクトのinvokeメソッドを呼び出してそれをServerRequestオブジェクトに引き渡すことによって，DSIオブジェクトインプリメンテーションにクライアントオペレーション要求を提示します。オブジェクトインプリメンテーションは，リクエストされたオペレーションを判断し，リクエストに対応する引数を解釈し，適切な内部メソッドまたはリクエストを満たすメソッドを呼び出し，適切な値を返します。

DSIを使用してオブジェクトをインプリメントするには，オブジェクトスケルトンが提供する通常の言語マッピングを使用した場合よりは手間の掛かるプログラミング作業が必要です。それでも，DSIを使用してインプリメントしたオブジェクトは，プロトコル間ブリッジを提供する場合に便利です。

18.1.1　idl2javaコンパイラの使用（Java）

idl2javaコンパイラにはフラグ（-dynamic_marshal）があり，このフラグをオンにするとDSIを使用してスケルトンコードを生成します。任意の型のDSIの使用方法を理解するには，IDLファイルを生成し，-dynamic_marshalを使用してスケルトンコードを生成して調べます。

18.2　オブジェクトインプリメンテーションの動的生成手順

DSIを使用してオブジェクトインプリメンテーションを動的に生成するには，次の手順を実行します。

C++でIDLをコンパイルする場合，-type_code_infoフラグを使用します。JavaでIDLをコンパイルする場合，-dynamic_marshalフラグを使用します。

スケルトンクラスからオブジェクトインプリメンテーションを派生させる代わりに，PortableServer::DynamicImplementation abstractクラス（C++），またはorg.omg.PortableServer.DynamicImplementationインタフェース（Java）からオブジェクトインプリメンテーションを派生させるようにオブジェクトインプリメンテーションを設計します。

invokeメソッドを宣言し，インプリメントします。このメソッドは，VisiBroker ORBがクライアントリクエストをユーザのオブジェクトへ渡すために使用します。

デフォルトのサーバントとして，オブジェクトインプリメンテーション（POAサーバント）をPOAマネージャに登録します。

18.2.1　DSIを使用したサンプルプログラムの格納場所

DSIの使用方法を示したサンプルプログラムは，Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/basic/bank_dynamicに入っています。この章では，このサンプルプログラムを使って，DSIの概念を説明します。IDLサンプル18-1に示すBank.idlファイルは，このサンプルでインプリメントされるインタフェースを示します。

IDLサンプル18-1　DSIのサンプルプログラムで使用するBank.idlファイル

// Bank.idl
module Bank {
   interface Account {
      float balance();
   };
   interface AccountManager {
      Account open(in string name);
   };
};

18.3　DynamicImplementationクラスの継承

DSIを使用するには，コードサンプル18-1に示したDynamicImplementationベースクラスからオブジェクトインプリメンテーションを派生させる必要があります。このクラスは，複数のコンストラクタとinvokeメソッドを提供しますが，これらは自分でインプリメントしてください。

コードサンプル18-1　DynamicImplementationベースクラス（C++）

class PortableServer::DynamicImplementation :
      public virtual PortableServer::ServantBase {
   public:
      virtual void invoke(
            PortableServer::ServerRequest_ptr request) = 0;
. . .
};

コードサンプル18-2　DynamicImplementation abstractクラス（Java）

package org.omg.CORBA;
public abstract class DynamicImplementation extends Servant {
   public abstract void invoke(ServerRequest request);
. . .
}

18.3.1　動的リクエスト用オブジェクトの設計例

コードサンプル18-3および18-4に，DSIを使用してインプリメントするC++およびJavaのAccountImplクラスの宣言を示します。これは，invokeメソッドを宣言するDynamicImplementationクラスから派生します。VisiBroker ORBは，そのinvokeメソッドを呼び出して，クライアントオペレーション要求をServerRequestオブジェクトの形でインプリメンテーションに引き渡します。

コードサンプル18-3にAccountクラスコンストラクタと_primary_interface関数を示します。

コードサンプル18-3　dynamicから派生するAccountImplクラスの例（C++）

class AccountImpl :
      public PortableServer::DynamicImplementation ,
              public virtual PortableServer::RefCountServantBase{
   public:
      AccountImpl(PortableServer::Current_ptr current,
            PortableServer::POA_ptr poa)
            : _poa_current(PortableServer::Current::_
                  duplicate(current)), _poa(poa)
      {}

      CORBA::Object_ptr get(const char *name) {
         CORBA::Float balance;
         // Check if account exists
         if (!_registry.get(name, balance)) {
            // simulate delay while creating new account
            VISPortable::vsleep(3);
            // Make up the account's balance,
                  between 0 and 1000 dollars
            balance = abs(rand()) % 100000 / 100.0;
            // Print out the new account
            cout << "Created " << name << "'s account: "
                  << balance << endl;
            _registry.put(name, balance);
         }
         // Return object reference
         PortableServer::ObjectId_var accountId =
         PortableServer::string_to_ObjectId(name);
         return _poa->create_reference_with_id(
               accountId, "IDL:Bank/Account:1.0");
      }
   private:
      AccountRegistry _registry;
      PortableServer::POA_ptr _poa;
      PortableServer::Current_var _poa_current;

      CORBA::RepositoryId _primary_interface(
            const PortableServer::ObjectId& oid,
                  PortableServer::POA_ptr poa) {
            return CORBA::string_dup(
                  (const char *)"IDL:Bank/Account:1.0");
      };

      void invoke(CORBA::ServerRequest_ptr request) {
      // Get the account name from the object id
      PortableServer::ObjectId_var oid =
            _poa_current->get_object_id();
      CORBA::String_var name;
      try {
         name = PortableServer::ObjectId_to_string(oid);
      } catch (const CORBA::Exception& e) {
         throw CORBA::OBJECT_NOT_EXIST();
      }
         // Ensure that the operation name is correct
         if (strcmp(request->operation(), "balance") != 0) {
            throw CORBA::BAD_OPERATION();
         }
         // Find out balance and fill out the result
         CORBA::NVList_ptr params = new CORBA::NVList(0);
         request->arguments(params);
         CORBA::Float balance;
         if (!_registry.get(name, balance))
            throw CORBA::OBJECT_NOT_EXIST();
         CORBA::Any result;
         result <<= balance;
         request->set_result(result);
         cout << "Checked " << name << "'s balance: "
               << balance << endl;
      }
};

コードサンプル18-4にAccountクラスコンストラクタの例を示します。

コードサンプル18-4　Dynamicから派生するAccountImplクラスの例（Java）

import java.util.*;
import org.omg.PortableServer.*;
public class AccountImpl extends DynamicImplementation {
   public AccountImpl(org.omg.CORBA.ORB orb, POA poa) {
      _orb = orb;
      _poa = poa;
   }

   public synchronized org.omg.CORBA.Object get(String name) {
      org.omg.CORBA.Object obj;
      // Check if account exists
      Float balance = (Float)_registry.get(name);
      if (balance == null) {
         // simulate delay while creating new account
         try {
            Thread.currentThread().sleep(3000);
         } catch (Exception e) {
            e.printStackTrace();
         }
         // Make up the account's balance, between 0 and 1000 dollars
         balance = new Float(Math.abs(_random.nextInt())
                                                   % 100000 / 100f);
         // Print out the new account
         System.out.println("Created " + name + "'s account: " +
                balance.floatValue());
         _registry.put(name, balance);
      }
      // Return object reference
      byte[ ] accountId = name.getBytes();
      try {
         obj = _poa.create_reference_with_id(accountId,
                                             "IDL:Bank/Account:1.0");
      } catch (org.omg.PortableServer.POAPackage.WrongPolicy e) {
         throw new org.omg.CORBA.INTERNAL(e.toString());
      }
      return obj;
   }

   public String[ ] _all_interfaces(POA poa, byte[ ] objectId) {
                                                      return null; }

   public void invoke(org.omg.CORBA.ServerRequest request) {
      Float balance;
      // Get the account name from the object id
      String name = new String(_object_id());
      // Ensure that the operation name is correct
      if (!request.operation().equals("balance")) {
         throw new org.omg.CORBA.BAD_OPERATION();
      }
      // Find out balance and fill out the result
      org.omg.CORBA.NVList params = _orb.create_list(0);
      request.arguments(params);
      balance = (Float)_registry.get(name);
      if (balance == null) {
         throw new org.omg.CORBA.OBJECT_NOT_EXIST();
      }
      org.omg.CORBA.Any result = _orb.create_any();
      result.insert_float(balance.floatValue());
      request.set_result(result);
      System.out.println("Checked " + name + "'s balance: " +
             balance.floatValue());
   }
   private Random _random = new Random();
   static private Hashtable _registry = new Hashtable();
   private POA _poa;
   private org.omg.CORBA.ORB _orb;
}

コードサンプル18-5および18-6に，DSIを使用してインプリメントする必要のあるAccountManagerImplクラスのインプリメンテーションを示します。これは，invokeメソッドを宣言するDynamicImplementationクラスからも派生します。VisiBroker ORBは，そのinvokeメソッドを呼び出して，クライアントオペレーション要求をServerRequestオブジェクトの形でインプリメンテーションに引き渡します。

コードサンプル18-5　Dynamicから派生するAccountManagerImplクラスの例（C++）

class AccountManagerImpl
      : public PortableServer::DynamicImplementation,
        public virtual PortableServer::RefCountServantBase {
   public:
      AccountManagerImpl(AccountImpl* accounts)
            { _accounts = accounts; }

      CORBA::Object_ptr open(const char* name) {
         return _accounts->get(name);
      }

   private:
      AccountImpl* _accounts;
      CORBA::RepositoryId _primary_interface
            (const PortableServer::ObjectId& oid,
            PortableServer::POA_ptr poa) {
         return CORBA::string_dup((const char *)
               "IDL:Bank/AccountManager:1.0");
      };
      void invoke(CORBA::ServerRequest_ptr request) {
         // Ensure that the operation name is correct
         if (strcmp(request->operation(), "open") !=0)
            throw CORBA::BAD_OPERATION();
         // Fetch the input parameter
         char *name = NULL;
         try {
            CORBA::NVList_ptr params = new CORBA::NVList(1);
            CORBA::Any any;
            any <<= (const char*) "";
            params->add_value("name", any, CORBA::ARG_IN);
            request->arguments(params);
            *(params->item(0)->value()) >>= name;
         } catch (const CORBA::Exception& e) {
            throw CORBA::BAD_PARAM();
         }
         // Invoke the actual implementation and
         // fill out the result
         CORBA::Object_var account = open(name);
         CORBA::Any result;
         result <<= account;
         request->set_result(result);
      }
};

コードサンプル18-6　Dynamicから派生するAccountManagerImplクラスの例（Java）

import org.omg.PortableServer.*;
public class AccountManagerImpl extends DynamicImplementation {
   public AccountManagerImpl(org.omg.CORBA.ORB orb, AccountImpl
      accounts) { _orb =orb; _accounts =accounts;
   }

   public synchronized org.omg.CORBA.Object open(String name) {
      return _accounts.get(name);
   }
   public String[ ] _all_interfaces(POA poa, byte[ ] objectId)
      { return null; }

   public void invoke(org.omg.CORBA.ServerRequest request) {
      // Ensure that the operation name is correct
      if (!request.operation().equals("open")) {
         throw new org.omg.CORBA.BAD_OPERATION();
      }

      // Fetch the input parameter
      String name = null;
      try {
         org.omg.CORBA.NVList params = _orb.create_list(1);
         org.omg.CORBA.Any any = _orb.create_any();
         any.insert_string(new String(""));
         params.add_value("name", any, org.omg.CORBA.ARG_IN.value);
         request.arguments(params);
         name = params.item(0).value().extract_string();
      } catch (Exception e) {
         throw new org.omg.CORBA.BAD_PARAM();
      }
      // Invoke the actual implementation and fill out the result
      org.omg.CORBA.Object account = open(name);
      org.omg.CORBA.Any result = _orb.create_any();
      result.insert_Object(account);
      request.set_result(result);
   }

   private AccountImpl _accounts;
   private org.omg.CORBA.ORB _orb;
}

18.3.2　リポジトリIDの指定

サポートされているリポジトリIDを返すには，_primary_interfaceメソッドをインプリメントしなければなりません。正しいリポジトリIDを指定するには，オブジェクトのIDLインタフェース名を使用して，次の手順に従います。

区切り文字であるスコープ解決演算子「::」をすべて「/」に置換します。

文字列の先頭に「IDL:」を付けます。

文字列の最後に「:1.0」を付けます。

IDLインタフェース名の一例をコードサンプル18-7に，生成されるリポジトリID文字列の一例をコードサンプル18-8に示します。

コードサンプル18-7　IDLインタフェース名

Bank::AccountManager

コードサンプル18-8　生成されるリポジトリID

IDL:Bank/AccountManager:1.0

18.4　ServerRequestクラスの考察

ServerRequestオブジェクトは，オブジェクトインプリメンテーションのinvokeメソッドへパラメタとして引き渡されます。ServerRequestオブジェクトはオペレーション要求を示し，リクエストされたオペレーションの名前，パラメタリスト，およびコンテキストを取得するメソッドを提供します。また，呼び出し側へ返す結果を設定するメソッドと例外を反映させるメソッドも提供します。

コードサンプル18-9　ServerRequestベースクラス（C++）

class CORBA::ServerRequest {
   public:
   . . .
   CORBA::Context_ptr ctx();
   // POA spec methods
   const char *operation() const ;
   void arguments(CORBA::NVList_ptr param);
   void set_result(const CORBA::Any& a) ;
   void set_exception(const CORBA::Any& a);
};

コードサンプル18-10　ServerRequest abstractクラス（Java）

package org.omg.CORBA;
public abstract class ServerRequest {
   public java.lang.String operation();
   public void arguments(org.omg.CORBA.NVList args);
   public void set_result(org.omg.CORBA.Any result);
   public void set_exception(org.omg.CORBA.Any except);
   public abstract org.omg.CORBA.Context ctx();
   // the following methods are deprecated
   public java.lang.String op_name(); // use operation()
   public void params(org.omg.CORBA.NVList params);
                                                  // use arguments()
   public void result(org.omg.CORBA.Any result); // use set_result()
   public abstract void except(org.omg.CORBA.Any except);
                                              // use set_exception()
}

C++の場合，arguments，set_result，またはset_exceptionの各メソッドへ引き渡したすべての引数は，VisiBroker ORBの所有になります。これらの引数用のメモリはVisiBroker ORBによって解放されるので，ユーザで解放しないでください。

18.5　Accountオブジェクトのインプリメント

Accountインタフェースはメソッドを一つしか宣言しないので，AccountImplクラスのinvokeメソッドが実行する処理は非常に単純です。

invokeメソッドは最初に，リクエストされたオペレーションの名前が「balance」であるかどうかを調べます。この名前が一致しない場合は，BAD_OPERATION例外が発生します。Accountオブジェクトが複数のメソッドを提供する場合には，invokeメソッドは可能なすべてのオペレーション名について検査し，適切な内部メソッドを使用してオペレーション要求を処理する必要があります。

balanceメソッドにはパラメタを指定できないので，オペレーション要求に対応するパラメタリストはありません。balanceメソッドは単純に起動され，結果はAnyオブジェクトの中にパッケージされ，そのAnyオブジェクトがServerRequestオブジェクトのset_resultメソッドを使用して呼び出し側へ返されます。

18.6　AccountManagerオブジェクトのインプリメント

Accountオブジェクトと同様に，AccountManagerインタフェースもメソッドを一つしか宣言しません。しかし，AccountManagerImplオブジェクトのopenメソッドにはアカウント名パラメタを指定できるので，invokeメソッドが実行する処理は少しだけ複雑になります。コードサンプル18-3（C++）および18-4（Java）に，AccountManagerImplオブジェクトのinvokeメソッドのインプリメンテーションを示しています。

このメソッドは最初に，リクエストされたオペレーションの名前が「open」であるかどうかを調べます。この名前が一致しない場合は，BAD_OPERATION例外が発生します。AccountManagerオブジェクトが複数のメソッドを提供する場合には，invokeメソッドは可能なすべてのオペレーション名について検査し，適切な内部メソッドを使用してオペレーション要求を処理する必要があります。

18.6.1　入力パラメタを処理する

AccountManagerImplオブジェクトのinvokeメソッドがオペレーション要求の入力パラメタを処理するために使用する手順は，次のとおりです。

オペレーション用のパラメタリストを保持するNVListを生成します。

予期されるパラメタごとにAnyオブジェクトを生成し，TypeCodeとパラメタ型（ARG_IN，ARG_OUT，ARG_INOUTのどれか）を設定してNVListに追加します。

ServerRequestオブジェクトのargumentsメソッドを起動してNVListを引き渡し，リスト内のすべてのパラメタの値を更新します。

openメソッドはアカウント名パラメタを予期しているので，ServerRequest内のパラメタを入れるNVListオブジェクトが生成されます。NVListクラスは，一つ以上のNamedValueオブジェクトが入っているパラメタリストをインプリメントします。NVListクラスとNamedValueクラスについては，「17.　動的起動インタフェースの使用」を参照してください。

アカウント名を入れるAnyオブジェクトが生成されます。このAnyは，引数名を「name」，パラメタ型をARG_INに設定してNVListに追加されます。

NVListが初期化されたあと，リスト内のすべてのパラメタ値を取得するために，ServerRequestオブジェクトのargumentsメソッドが呼び出されます。

注

argumentsメソッドを呼び出したあと，NVListはVisiBroker ORBに所有されます。したがって，オブジェクトインプリメンテーションがNVList内のARG_INOUTパラメタを変更すると，その変更はVisiBroker ORBにも自動的に認識されます。このNVListを呼び出し側で解放してはなりません。

入力引数用にNVListを構築する代わりに，VisiBroker ORBオブジェクトのcreate_operation_listメソッドを使用することもできます。このメソッドはOperationDefオブジェクトを受け取り，必要なすべてのAnyオブジェクトを使用して完全に初期化されたNVListオブジェクトを返します。適切なOperationDefオブジェクトは，「16.　インタフェースリポジトリの使用」で説明したIRから取得できます。

18.6.2　リターン値を設定する

ServerRequestオブジェクトのargumentsメソッドを起動したあと，nameパラメタの値を抽出して新しいAccountオブジェクトの生成に使用できます。新規に生成されたAccountオブジェクトを入れるためのAnyオブジェクトが生成され，ServerRequestオブジェクトのset_resultメソッドを起動することによってそのAnyオブジェクトが呼び出し側へ返されます。

18.7　サーバのインプリメンテーション

mainルーチンのインプリメンテーションは，コードサンプル18-11および18-12に示すように，「4.　Borland Enterprise Server VisiBrokerによるサンプルアプリケーションの開発」で示したサンプルとほぼ同じものです。

コードサンプル18-11　サーバのインプリメンテーション（C++）

int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

      // Get a reference to the rootPOA
      CORBA::Object_var obj =
            orb->resolve_initial_references("RootPOA");
      PortableServer::POA_var rootPOA =
            PortableServer::POA::_narrow(obj);
      // Get the POA Manager
      PortableServer::POAManager_var poaManager =
            rootPOA->the_POAManager();
      // Create the account POA with the right policies
      CORBA::PolicyList accountPolicies;
      accountPolicies.length(3);
      accountPolicies [(CORBA::ULong)0] =
            rootPOA->create_servant_retention_policy(
            PortableServer::NON_RETAIN);
      accountPolicies[(CORBA::ULong)1] =
            rootPOA->create_request_processing_policy(
            PortableServer::USE_DEFAULT_SERVANT);
      accountPolicies[(CORBA::ULong)2] =
            rootPOA->create_id_uniqueness_policy(
            PortableServer::MULTIPLE_ID);
      PortableServer::POA_var accountPOA = rootPOA->create_POA(
            "bank_account_poa",
            poaManager,
            accountPolicies);
     // Create the account default servant
      PortableServer::Current_var current =
            PortableServer::Current::_instance();
      AccountImpl accountServant(current, accountPOA);
      accountPOA->set_servant(&accountServant);
      // Create the manager POA with the right policies
      CORBA::PolicyList managerPolicies;
      managerPolicies.length(3);
      managerPolicies[(CORBA::ULong)0] =
            rootPOA->create_lifespan_policy(
            PortableServer::PERSISTENT);
      managerPolicies[(CORBA::ULong)1] =
            rootPOA->create_request_processing_policy(
            PortableServer::USE_DEFAULT_SERVANT);
      managerPolicies[(CORBA::ULong)2] =
            rootPOA->create_id_uniqueness_policy(
            PortableServer::MULTIPLE_ID);
      PortableServer::POA_var managerPOA =
            rootPOA->create_POA(
            "bank_agent_poa",
            poaManager,
            managerPolicies);
      // Create the manager default servant
      AccountManagerImpl managerServant(&accountServant);
      managerPOA->set_servant(&managerServant);
      // Activate the POA Manager
      poaManager->activate();
      cout << "AccountManager is ready" << endl;
      // Wait for incoming requests
      orb->run();
   } catch(const CORBA::Exception& e) {
      cerr << e << endl;
      return 1;
   }
   return 0;
}

コードサンプル18-12　サーバのインプリメンテーション（Java）

import org.omg.PortableServer.*;
public class Server {
   public static void main(String[ ] args) {
      try {
         // Initialize the ORB
         org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
         // Get a reference to the rootPOA
         POA rootPOA = POAHelper.narrow(orb.
                                  resolve_initial_references("RootPOA"));
         // Get the POA Manager
         POAManager poaManager = rootPOA.the_POAManager();
         // Create the account POA with the right policies
         org.omg.CORBA.Policy[ ] accountPolicies = {
            rootPOA.create_servant_retention_policy(
               ServantRetentionPolicyValue.NON_RETAIN),
            rootPOA.create_request_processing_policy(
               RequestProcessingPolicyValue.USE_DEFAULT_SERVANT)
         };
         POA accountPOA = rootPOA.create_POA("bank_account_poa",
               poaManager, accountPolicies);
         // Create the account default servant
         AccountImpl accountServant = new AccountImpl(orb,
                                                         accountPOA);
         accountPOA.set_servant(accountServant);
         // Create the manager POA with the right policies
         org.omg.CORBA.Policy[ ] managerPolicies = {
          rootPOA.create_lifespan_policy(
                  LifespanPolicyValue.PERSISTENT),
          rootPOA.create_request_processing_policy(
                  RequestProcessingPolicyValue.USE_DEFAULT_SERVANT)
         };
         POA managerPOA = rootPOA.create_POA("bank_agent_poa",
               poaManager,managerPolicies);
         // Create the manager default servant
         AccountManagerImpl managerServant =
                           new AccountManagerImpl(orb, accountServant);
         managerPOA.set_servant(managerServant);
         // Activate the POA Manager
         poaManager.activate();
         System.out.println("AccountManager is ready");
         // Wait for incoming requests
         orb.run();
      } catch(Exception e) {
         e.printStackTrace();
      }
   }
}

DSIインプリメンテーションは，デフォルトサーバントとして実体化されます。また，POAは該当するポリシーのサポートによって生成されなければなりません。詳細については，「7.　POAの使用」を参照してください。

19　ポータブルインタセプタの使用

この章では，OMG規格で定義されている新しいポータブルインタセプタの概要について説明し，ポータブルインタセプタの例を示しながら，ポータブルインタセプタファクトリなどの高度な機能について説明します。ポータブルインタセプタの詳細については，OMG採用確定規格のポータブルインタセプタについての記述を参照してください。

19.1　概要

Borland Enterprise Server VisiBroker ORBは，セキュリティ，トランザクション，ログなどの機能をORBへ追加するための一連のインタフェースをインタセプタとして提供しています。これらのインタセプタインタフェースは，コールバック方式に基づいています。例えば，インタセプタを使用するとクライアント／サーバ間の通信を知ることができ，それらの通信を希望に応じて修正し，Borland Enterprise Server VisiBroker ORBの動作を効果的に変更できます。

最も単純な使用方法として，インタセプタはコードのトレースに便利です。クライアント／サーバ間で送信されるメッセージを見られるので，ORBがリクエストをどう処理しているのかを正確に確認できます。インタセプタの機能を図19-1に示します。

図19‒1　インタセプタの機能

モニタリングツールやセキュリティレイヤなどの，より高度なアプリケーションを開発する場合は，それらを開発するのに必要な低レベルアプリケーションの情報や制御をインタセプタから得られます。例えば，各種のサーバの動作を監視し，負荷分散を実行するアプリケーションを開発できます。

Borland Enterprise Server VisiBroker ORBがサポートするインタセプタには，ポータブルインタセプタ（単にインタセプタと呼ぶこともあります）およびVisiBroker Interceptorの2種類があります。ポータブルインタセプタはOMG標準化機能であり，インタセプタのポータブルコードの書き込みと各種ベンダORBでの使用が可能となります。VisiBroker 4.xインタセプタは，VisiBroker 4.xで定義され，インプリメントされるインタセプタです（VisiBrokerインタセプタの詳細については，「20.　VisiBroker 4.xインタセプタの使用」を参照してください）。

OMG規格が定義するポータブルインタセプタには次の2種類があります。

リクエストインタセプタを使用すると，クライアントとサーバ間でBorland Enterprise Server VisiBroker ORBサービスがコンテキスト情報を転送できるようになります。リクエストインタセプタは，さらにクライアントリクエストインタセプタとサーバリクエストインタセプタに分けられます。

IORインタセプタを使用すると，Borland Enterprise Server VisiBroker ORBサービスがサーバまたはオブジェクトのORBサービス関連機能を説明する情報をIORに追加できるようになります。例えば，SSLのようなセキュリティサービスがそのタグの付いたコンポーネントをIORに追加するので，そのコンポーネントを認識したクライアントは，そのコンポーネントの情報に基づいてサーバとのコネクションを設定できます。

ポータブルインタセプタの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「ポータブルインタセプタインタフェースとクラス」の記述を参照してください。

ポータブルインタセプタとVisiBrokerインタセプタの使用については，「20.　VisiBroker 4.xインタセプタの使用」を参照してください。

19.2　ポータブルインタセプタおよび情報インタフェース

すべてのポータブルインタセプタは次に示すベースインタセプタAPIクラスのどれかをインプリメントします。ベースインタセプタAPIクラスはBorland Enterprise Server VisiBroker ORBによって定義され，インプリメントされます。

リクエストインタセプタ

ClientRequestInterceptor

ServerRequestInterceptor

IORインタセプタ

19.2.1　インタセプタ

リクエストインタセプタおよびIORインタセプタは，共通クラスであるInterceptorクラスから派生します。このInterceptorクラスは共通メソッドを定義しており，この共通メソッドはInterceptorクラスの継承クラスにも使用できます。

コードサンプル19-1　Interceptorクラス（C++）

class PortableInterceptor::Interceptor
{
     virtual char* name()=0;
     virtual void destroy()=0;
}

コードサンプル19-2　Interceptorインタフェース（Java）

public interface Interceptor
extends org.omg.CORBA.portable.IDLEntity,org.omg.CORBA.LocalInterface
{
     public java.lang.String name();
     public void destroy();
}

19.2.2　リクエストインタセプタ

リクエストインタセプタは，特定のインタセプトポイントでリクエスト／応答シーケンスのフローを受け取るために使用します。これによってサービスはクライアントとサーバ間でコンテキスト情報を転送できます。各インタセプトポイントではBorland Enterprise Server VisiBroker ORBはオブジェクトを与えて，このオブジェクトによってインタセプタはリクエスト情報にアクセスできます。リクエストインタセプタには2種類あり，そのそれぞれにリクエスト情報インタフェースがあります。

ClientRequestInterceptorおよびClientRequestInfo

ServerRequestInterceptorおよびServerRequestInfo

リクエストのインタセプタポイントを図19-2に示します。

図19‒2　リクエストのインタセプタポイント

リクエストインタセプタの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「ポータブルインタセプタインタフェースとクラス」の記述を参照してください。

(1)　ClientRequestInterceptor

ClientRequestInterceptorには，クライアント側でインプリメントされたインタセプトポイントがあります。

表19-1に示すように，OMGがClientRequestInterceptorで定義しているインタセプトポイントは五つあります。

表19‒1　ClientRequestInterceptorインタセプトポイント

インタセプトポイント

説明

send_request

クライアント側インタセプタが，リクエストがサーバに送信される前にリクエストを照会して，サービスコンテキストを修正します。

send_poll

クライアント側インタセプタが，TII（時間非依存呼び出し）ポーリング取得応答シーケンス※中にリクエストを照会します。

receive_reply

クライアント側インタセプタが，サーバから応答情報が戻されたあと，クライアントに制御が移る前にその応答情報を照会します。

receive_exception

クライアント側インタセプタが，例外発生時に，その例外がクライアントに送信される前に例外情報を照会します。

receive_other

クライアント側インタセプタが，正常応答または例外以外のリクエスト結果を受け取った場合に利用できる情報を照会します。

注※

TIIはVisiBroker Edition ORBではインプリメントされていません。結果として，send_poll()インタセプトポイントが呼び出されることはありません。

各インタセプトポイントの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「ポータブルインタセプタインタフェースとクラス」の記述を参照してください。

コードサンプル19-3　ClientRequestInterceptorクラス（C++）

class _VISEXPORT ClientRequestInterceptor:public virtualInterceptor {
    public:
    virtual void send_request(ClientRequestInfo_ptr _ri)=0;
    virtual void send_poll(ClientRequestInfo_ptr _ri)=0;
    virtual void receive_reply(ClientRequestInfo_ptr _ri)=0;
    virtual void receive_exception(ClientRequestInfo_ptr _ri)=0;
    virtual void receive_other(ClientRequestInfo_ptr _ri)=0;
}

コードサンプル19-4　ClientRequestInterceptorインタフェース（Java）

package org.omg.PortableInterceptor;
public interface ClientRequestInterceptor
      extends Interceptor,org.omg.CORBA.portable.IDLEntity,
               org.omg.CORBA.LocalInterface
{
      public void send_request(ClientRequestInfo ri)
             throws ForwardRequest;
      public void send_poll(ClientRequestInfo ri)
             throws ForwardRequest;
      public void receive_reply(ClientRequestInfo ri);
      public void receive_exception(ClientRequestInfo ri)
             throws ForwardRequest;
      public void receive_other(ClientRequestInfo ri)
             throws ForwardRequest;
}

クライアント側の規則を次に，具体例を表19-2に示します。

開始インタセプトポイントはsend_requestおよびsend_pollです。どのリクエスト／応答シーケンスでも，このインタセプトポイントのどちらか一方だけが呼び出されます。

終了インタセプトポイントはreceive_reply，receive_exception，およびreceive_otherです。どのリクエスト／応答シーケンスでも，このインタセプトポイントのどれか一つだけが呼び出されます。

中間インタセプトポイントはありません。

終了インタセプトポイントは，send_requestまたはsend_pollのどちらかの実行が成功した場合だけ呼び出されます。

receive_exceptionは，ORBのシャットダウンによってリクエストがキャンセルされて，マイナーコード4（ORBのシャットダウン）のシステム例外BAD_INV_ORDERが発生すると呼び出されます。

receive_exceptionは，リクエストがそのほかの理由によってキャンセルされて，マイナーコード3のシステム例外TRANSIENTが発生すると呼び出されます。

表19‒2　クライアント側の規則の具体例

クライアント側の規則

説明

呼び出し成功

send_requestのあとにreceive_reply。開始点のあとに終了点がきます。

リトライ

send_requestのあとにreceive_other。開始点のあとに終了点がきます。

(2)　ServerRequestInterceptor

ServerRequestInterceptorには，サーバ側でインプリメントされたインタセプトポイントがあります。表19-3に示すように，OMGがServerRequestInterceptorで定義しているインタセプトポイントは五つあります。

表19‒3　ServerRequestInterceptorインタセプトポイント

インタセプトポイント

説明

receive_request_service_contexts

サーバ側インタセプタが，入力リクエストからそのサービスコンテキスト情報を取得して，それをPortableInterceptor::Currentのスロットに転送します。

receive_request

サーバ側インタセプタが，オペレーションパラメタのようなすべての情報が利用可能になってから，リクエスト情報を照会します。

send_reply

サーバ側インタセプタが，ターゲットのオペレーションが呼び出されたあと，クライアントに応答が戻される前に応答情報を照会して，応答サービスコンテキストを修正します。

send_exception

サーバ側インタセプタが，例外発生時に，その例外がクライアントに送信される前に例外情報を照会して応答サービスコンテキストを修正します。

send_other

サーバ側インタセプタが，正常応答または例外以外のリクエスト結果を受け取った場合に利用できる情報を照会します。

各インタセプトポイントの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「ポータブルインタセプタインタフェースとクラス」の記述を参照してください。

コードサンプル19-5　ServerRequestInterceptorクラス（C++）

class _VISEXPORT ServerRequestInterceptor:public virtual Interceptor {
      public:
      virtual void receive_request_service_contexts
         (ServerRequestInfo_ptr _ri)=0;
      virtual void receive_request(ServerRequestInfo_ptr _ri)=0;
      virtual void send_reply(ServerRequestInfo_ptr _ri)=0;
      virtual void send_exception(ServerRequestInfo_ptr _ri)=0;
      virtual void send_other(ServerRequestInfo_ptr _ri)=0;
};

コードサンプル19-6　ServerRequestInterceptorインタフェース（Java）

package org.omg.PortableInterceptor;

public interface ServerRequestInterceptor
   extends Interceptor,org.omg.CORBA.portable.IDLEntity,
        org.omg.CORBA.LocalInterface
{
     public void receive_request_service_contexts
         (ServerRequestInfo ri)throws ForwardRequest;
     public void receive_request(ServerRequestInfo ri)
          throws ForwardRequest;
     public void send_reply(ServerRequestInfo ri);
     public void send_exception(ServerRequestInfo ri)
          throws ForwardRequest;
     public void send_other(ServerRequestInfo ri)throws ForwardRequest;
}

サーバ側の規則を次に，具体例を表19-4に示します。

開始インタセプトポイントはreceive_request_service_contextsです。どのリクエスト／応答シーケンスでも，このインタセプトポイントが呼び出されます。

終了インタセプトポイントはsend_reply，send_exception，およびsend_otherです。どのリクエスト／応答シーケンスでも，このインタセプトポイントのどれか一つだけが呼び出されます。

中間インタセプトポイントはreceive_requestです。これは，receive_request_service_contextsのあと，終了インタセプトポイントの前に呼び出されます。

例外では，receive_requestは呼び出されないことがあります。

終了インタセプトポイントは，send_requestまたはsend_pollのどちらかの実行が成功した場合だけ呼び出されます。

send_exceptionは，ORBのシャットダウンによってリクエストがキャンセルされて，マイナーコード4（ORBのシャットダウン）のシステム例外BAD_INV_ORDERが発生すると呼び出されます。

send_exceptionは，リクエストがそのほかの理由によってキャンセルされて，マイナーコード3のシステム例外TRANSIENTが発生すると呼び出されます。

表19‒4　サーバ側の規則の具体例

サーバ側の規則

説明

呼び出し成功

インタセプトポイントの順序receive_request_service_contexts，receive_request，send_reply。開始点，中間点，終了点の順。

19.2.3　IORインタセプタ

(1)　IORInterceptor

IORInterceptorは，クライアント側のBorland Enterprise Server VisiBroker ORBサービスインプリメンテーションが正しく機能できるように，サーバまたはオブジェクトのORBサービス関連機能を説明する情報をオブジェクトリファレンスに追加する機能をアプリケーションに提供します。これは，インタセプトポイントestablish_componentsを呼び出すことによって提供されます。IORInfoのインスタンスは，インタセプトポイントに渡されます。IORInfoの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「IORInfo」の記述を参照してください。

コードサンプル19-7　IORInterceptorクラス（C++）

class _VISEXPORT IORInterceptor:public virtual Interceptor
{
   public:
      virtual void establish_components(IORInfo_ptr _info)=0;
      virtual void components_established(IORInfo_ptr _info)=0;
      virtual void adapter_manager_state_changed(
         CORBA::Long _id,CORBA::Short _state)=0;
      virtual void adapter_state_changed(
         const ObjectReferenceTemplateSeq&_templates,
         CORBA::Short _state)=0;
};

コードサンプル19-8　IORInterceptorインタフェース（Java）

package org.omg.PortableInterceptor;

public interface IORInterceptor
   extends Interceptor,org.omg.CORBA.portable.IDLEntity,
        org.omg.CORBA.LocalInterface
{
     public void establish_components(IORInfo info);
     public void components_established(IORInfo info);
     public void adapter_manager_state_changed(int id,short state);
     public void adapter_state_changed(
          ObjectReferenceTemplate[ ] templates, short state);
}

19.2.4　Portable Interceptor Current

PortableInterceptor::Currentオブジェクト（以降，PICurrentと呼びます）は，スレッドコンテキスト情報をリクエストコンテキストに転送するためにポータブルインタセプタが使用するスロットのテーブルです。PICurrentの使用は必須ではありませんが，インタセプトポイントでクライアントのスレッドコンテキスト情報が必要である場合は，この情報を転送するためにPICurrentを使用できます。PICurrentは次に示す呼び出しによって取得されます。

Javaの場合

ORB.resolve_initial_references ("PICurrent");

C++の場合

ORB->resolve_initial_references ("PICurrent");

コードサンプル19-9　PortableInterceptor::Currentクラス（C++）

class _VISEXPORT Current:public virtual CORBA::Current,
      public virtual CORBA_Object
{
   public:
      virtual CORBA::Any*get_slot(CORBA::ULong _id);
      virtual void set_slot(CORBA::ULong _id,
              const CORBA::Any&_data);
};

コードサンプル19-10　PortableInterceptor.Currentインタフェース（Java）

package org.omg.PortableInterceptor;

public interface Current
   extends org.omg.CORBA.CurrentOperations,
      org.omg.CORBA.portable.IDLEntity
{
   public org.omg.CORBA.Any get_slot(int id)throws InvalidSlot;
   public void set_slot(int id,org.omg.CORBA.Any data)throws
          InvalidSlot;
}

19.2.5　Codec

Codecは，コンポーネントのIDLデータ型とCDRカプセル化表現の間でコンポーネントを転送する機能をインタセプタに提供します。Codecは，CodecFactoryから取得されます。

コードサンプル19-11　Codecクラス（C++）

class _VISEXPORT Codec
{
   public:
      virtual CORBA::OctetSequence* encode(const CORBA::Any& _data)=0;
      virtual CORBA::Any* decode(const CORBA::OctetSequence& _data)=0;
      virtual CORBA::OctetSequence* encode_value
                                         (const CORBA::Any& _data)=0;
      virtual CORBA::Any* decode_value(const
             CORBA::OctetSequence& _data, CORBA::TypeCode_ptr _tc)=0;
};

コードサンプル19-12　Codecインタフェース（Java）

package org.omg.IOP;

public interface Codec
   extends org.omg.CORBA.portable.IDLEntity,org.omg.CORBA.LocalInterface
{
   public byte[ ] encode(org.omg.CORBA.Any data)
       throws InvalidTypeForEncoding;
   public org.omg.CORBA.Any decode(byte[ ] data)throws
                                                  FormatMismatch;
   public byte[ ] encode_value(org.omg.CORBA.Any data)
      throws InvalidTypeForEncoding;
   public org.omg.CORBA.Any decode_value(byte[ ] data,
      org.omg.CORBA.TypeCode tc)
      throws FormatMismatch,TypeMismatch;
}

19.2.6　CodecFactory

このクラスは，エンコーディングフォーマット，メジャーバージョン，およびマイナーバージョンを指定してCodecオブジェクトを生成するために使用します。CodecFactoryは次の呼び出しによって取得されます。

Javaの場合

ORB.resolve_initial_references ("CodecFactory")

C++の場合

ORB->resolve_initial_references("CodecFactory")

コードサンプル19-13 CodecFactoryクラス（C++）

class _VISEXPORT CodecFactory
{
   public:
      virtual Codec_ptr create_codec(const Encoding&_enc)=0;
};

コードサンプル19-14　CodecFactoryインタフェース（Java）

public interface CodecFactory
     extends org.omg.CORBA.portable.IDLEntity,
                                         org.omg.CORBA.LocalInterface
   {
    public Codec create_codec(Encoding enc) throws
                                         UnknownEncoding;
   }

19.2.7　ポータブルインタセプタの作成

ポータブルインタセプタの一般的な作成手順を次に示します。

インタセプタは次のインタセプタインタフェースの一つから継承されなければなりません。

ClientRequestInterceptor

ServerRequestInterceptor

IORInterceptor

インタセプタは，インタセプタで使用できる一つ以上のインタセプトポイントをインプリメントします。

インタセプタは名前付き，または名前なしでもかまいません。すべての名前は同じタイプのインタセプタすべての中では一意である必要がありますが，名前なしのインタセプタは幾つでもBorland Enterprise Server VisiBroker ORBに登録できます。

コードサンプル19-15　ポータブルインタセプタの作成例（C++）

#include "PortableInterceptor_c.hh"

class SampleClientRequestInterceptor:public
   PortableInterceptor::ClientRequestInterceptor
{
   char *name(){
      return "SampleClientRequestInterceptor";
   }

   void send_request(ClientRequestInfo_ptr _ri){
     .......//actual interceptor code here
   }

   void send_poll(ClientRequestInfo_ptr _ri){
     .......//actual interceptor code here
   }

   void receive_reply(ClientRequestInfo_ptr _ri){
     .......//actual interceptor code here
   }

   void receive_exception(ClientRequestInfo_ptr _ri){
     .......//actual interceptor code here
   }

   void receive_other(ClientRequestInfo_ptr _ri){
     .......//actual interceptor code here
   }
};

コードサンプル19-16　ポータブルインタセプタの作成例（Java）

import org.omg.PortableInterceptor.*;

public class SampleClientRequestInterceptor extends
   org.omg.CORBA.LocalObject
   implements ClientRequestInterceptor
{
   public java.lang.String name(){
      return "SampleClientRequestInterceptor";
   }

   public void send_request(ClientRequestInfo ri)
      throws ForwardRequest {
      .......//actual interceptor code here
   }

   public void send_poll(ClientRequestInfo ri)
      throws ForwardRequest {
      .......//actual interceptor code here
   }

   public void receive_reply(ClientRequestInfo ri){
      .......//actual interceptor code here
   }

   public void receive_exception(ClientRequestInfo ri)
      throws ForwardRequest {
      .......//actual interceptor code here
   }

   public void receive_other(ClientRequestInfo ri)
      throws ForwardRequest {
      .......//actual interceptor code here
   }
}

19.2.8　ポータブルインタセプタの登録

ポータブルインタセプタは使用前にBorland Enterprise Server VisiBroker ORBに登録する必要があります。ポータブルインタセプタを登録するには，ORBInitializerオブジェクトをインプリメントして，登録する必要があります。ポータブルインタセプタは，pre_init ()メソッドもしくはpost_init()メソッド，またはその両方をインプリメントする対応ORBInitializerオブジェクトを登録することによって，ORB初期化時に実体化されて登録されます。Borland Enterprise Server VisiBroker ORBは，初期化プロセス時にORBInitInfoオブジェクトに登録された各ORBInitializerを呼び出します。

コードサンプル19-17　ORBInitializerクラス（C++）

class _VISEXPORT ORBInitializer
{
   public:
      virtual void pre_init(ORBInitInfo_ptr _info)=0;
      virtual void post_init(ORBInitInfo_ptr _info)=0;
};

コードサンプル19-18　ORBInitInfoクラス（C++）

class _VISEXPORT ORBInitInfo
{
   public:
      virtual CORBA::StringSequence*arguments()=0;
      virtual char*orb_id()=0;
      virtual IOP::CodecFactory_ptr codec_factory()=0;
      virtual void register_initial_reference(const char*_id,
         CORBA::Object_ptr _obj)=0;
      virtual CORBA::Object_ptr resolve_initial_references
         (const char*_id)=0;
      virtual void add_client_request_interceptor(
         ClientRequestInterceptor_ptr _interceptor)=0;
      virtual void add_server_request_interceptor(
         ServerRequestInterceptor_ptr _interceptor)=0;
      virtual void add_ior_interceptor(IORInterceptor_ptr
                                              _interceptor)=0;
      virtual CORBA::ULong allocate_slot_id()=0;
      virtual void register_policy_factory(CORBA::ULong _type,
         PolicyFactory_ptr _policy_factory)=0;
};

コードサンプル19-19　ORBInitializerインタフェース（Java）

package org.omg.PortableInterceptor;

public interface ORBInitializer
   extends org.omg.CORBA.portable.IDLEntity,
      org.omg.CORBA.LocalInterface
{
   public void pre_init(ORBInitInfo info);
   public void post_init(ORBInitInfo info);
}

コードサンプル19-20　ORBInitInfoインタフェース（Java）

package org.omg.PortableInterceptor;

public interface ORBInitInfo
   extends org.omg.CORBA.portable.IDLEntity,org.omg.CORBA.LocalInterface
{
   public java.lang.String[ ] arguments(();
   public java.lang.String orb_id();
   public CodecFactory codec_factory();
   public void register_initial_reference
      (java.lang.String id,org.omg.CORBA.Object obj)
      throws InvalidName;
   public void resolve_initial_references(java.lang.String id)
      throws InvalidName;
   public void add_client_request_interceptor
      (ClientRequestInterceptor interceptor)
      throws DuplicateName;
   public void add_server_request_interceptor
      (ServerRequestInterceptor interceptor)
      throws DuplicateName;
   public void add_ior_interceptor(IORInterceptor interceptor)
      throws DuplicateName;
   public int allocate_slot_id();
   public void register_policy_factory
      (int type,PolicyFactory policy_factory);
}

19.2.9　ORBInitializerの登録

ORBInitializerを登録するために，グローバルメソッドであるregister_orb_initializerが提供されています。インタセプタをインプリメントする各サービスは，ORBInitializerのインスタンスを提供します。サービスを使用するために，アプリケーションは次の手順を行います。

サービスのORBInitializerでregister_orb_initializer()メソッドを呼び出します。

新しいORB識別子でORB_Init()メソッド呼び出しを実体化して新しいORBを生成します。

Javaの場合

register_orb_initializer()メソッドは，グローバルメソッドであるため，ORBに関するアプレットセキュリティに違反します。結果として，ORBInitializerは，register_orb_initializer()メソッドを呼び出すのではなく，Java ORBプロパティを使用してVisiBroker Edition ORBに登録されます。

(1)　新しいプロパティセット（Java）

新しいプロパティ名の形式を次に示します。

org.omg.PortableInterceptor.ORBInitializerClass.<Service>

ここで<Service>は，org.omg.PortableInterceptor.ORBInitializerをインプリメントするクラスの文字列名です。

ORB.init()メソッドの実行中に行われることを次に示します。

org.omg.PortableInterceptor.ORBInitializerClassで始まるORBプロパティが収集されます。

各プロパティの<Service>部分が収集されます。

オブジェクトは，そのクラス名として<Service>文字列を使用して実体化されます。

pre_init()メソッドおよびpost_init()メソッドがそのオブジェクトで呼び出されます。

例外が発生すると，ORBはそれを無視して続行します。

注

名前の衝突を避けるために，DNS名の入れ替え規則を適用することを推奨します。例えば，ABC社に二つのイニシャライザがある場合，次のプロパティを定義できます。

org.omg.PortableInterceptor.ORBInitializerClass.com.abc.ORBInit1
org.omg.PortableInterceptor.ORBInitializerClass.com.abc.ORBInit2

C++の場合

register_orb_initializerメソッドはPortableInterceptorモジュールに次のように定義されます。

class _VISEXPORT PortableInterceptor {
    static void register_orb_initializer(ORBInitializer *init);
}

(2)　サンプル

ABC社が書き込んだクライアント側の監視ツールに，次に示すORBInitializerインプリメンテーションがあるとします。

コードサンプル19-21　ORBInitializerの登録例（C++）

#include "PortableInterceptor_c.hh"

class MonitoringService:public PortableInterceptor::ORBInitializer
{
   void pre_init(ORBInitInfo_ptr _info)
   {
      //instantiate the service ’s Interceptor.
      Interceptor*interceptor =new MonitoringInterceptor();

      //register the Monitoring ’s Intereptor.
      _info->add_client_request_interceptor(interceptor);
   }

   void post_init(ORBInitInfo_ptr _info)
   {
      //This init point is not needed.
   }
};
MonitoringService *monitoring_service =new MonitoringService();
PortableInterceptor::register_orb_initializer(monitoring_service);

コードサンプル19-22　ORBInitializerの登録例（Java）

package com.abc.Monitoring;

import org.omg.PortableInterceptor.Interceptor;
import org.omg.PortableInterceptor.ORBInitializer;
import org.omg.PortableInterceptor.ORBInitInfo;

public class MonitoringService extends org.omg.CORBA.LocalObject
   implements org.omg.PortableInterceptor.ORBInitializer
{
   void pre_init(ORBInitInfo info)
   {
      //instantiate the service ’s Interceptor.
      Interceptor interceptor =new MonitoringInterceptor();

      //register the Monitoring ’s Interceptor.
      info.add_client_request_interceptor(interceptor);
   }

   void post_init(ORBInitInfo info)
   {
      //This init point is not needed.
   }
}

この監視サービスを使用してMyAppと呼ばれるプログラムを実行するために次のコマンドが使用されます。

java -Dorg.omg.PortableInterceptor.ORBInitializerClass.
     com.abc.Monitoring.MonitoringService MyApp

19.2.10　ポータブルインタセプタのBorland Enterprise Server VisiBroker拡張機能

(1)　POAスコープサーバリクエストインタセプタ

OMGが指定したポータブルインタセプタは，グローバルにスコープされます。Borland Enterprise Server VisiBrokerは，PortableInterceptorExtという新しいモジュールを追加することによってポータブルインタセプタのパブリック拡張機能である「POAスコープサーバリクエストインタセプタ」を定義しています。この新しいモジュールには，PortableInterceptor::IORInfoから継承され，POAスコープサーバリクエストインタセプタをインストールするための拡張メソッドを持つIORInfoExtというローカルインタフェースがあります。

コードサンプル19-23　IORInfoExtクラス（C++）

#include "PortableInterceptorExt_c.hh"

class IORInfoExt:public PortableInterceptor::IORInfo
{
   public:
      virtual void add_server_request_interceptor(
         ServerRequestInterceptor_ptr _interceptor)=0;
      virtual char*full_poa_name();
};

コードサンプル19-24　IORInfoExtインタフェース（Java）

package com.inprise.vbroker.PortableInterceptor;

public interface IORInfoExt extends
   org.omg.CORBA.LocalInterface,
   org.omg.PortableInterceptor.IORInfo,
   com.inprise.vbroker.PortableInterceptor.IORInfoExtOperations,
   org.omg.CORBA.portable.IDLEntity
{
   public void add_server_request_interceptor
      (ServerRequestInterceptor interceptor)
      throws DuplicateName;
   public java.lang.String[ ] full_poa_name();
}

19.3　サンプル

この節では，ポータブルインタセプタを使用するための実際のアプリケーションの書き方と，各リクエストインタセプタのインプリメント方法について説明します。それぞれのサンプルはクライアントアプリケーションとサーバアプリケーションのセット，およびC++とJavaで記述されたそれぞれのインタセプタで構成されています。各インタフェースの定義については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「ポータブルインタセプタインタフェースとクラス」の記述を参照してください。

また，ポータブルインタセプタを使用する開発者には，CORBAの仕様のポータブルインタセプタについての記述を読むことをお勧めします。

19.3.1　サンプルコード

$VBROKERDIR/examples/vbe/piディレクトリ（UNIX）または%VBROKERDIR%¥examples¥vbe¥piディレクトリ（Windows）内にあるサンプルのリストを次に示します。それぞれのサンプルは，そのサンプルの目的をわかりやすくするためにディレクトリ名に対応しています。

client_server

chaining

次にコンパイル手順およびその実行（または配置）について，client_serverをサンプルにして詳細に説明します。

19.3.2　サンプル：client_server

(1)　サンプルの目的

このサンプルでは，コードを変更しないで，既存のCORBAアプリケーションにポータブルインタセプタを追加する簡単な方法を実際に説明します。ポータブルインタセプタはクライアント側およびサーバ側の両方のどのアプリケーションにも追加できます。これは，ランタイム時に設定する指定のオプションやプロパティで，関連するアプリケーションを再実行することによって行えます。

使用するクライアントおよびサーバアプリケーションは，$VBROKERDIR/examples/vbe/basic/bank_agent（UNIX）または%VBROKERDIR%¥examples¥vbe¥basic¥bank_agent（Windows）にあるアプリケーションと類似しています。サンプル全体は抜粋であり，ポータブルインタセプタはランタイム構成時に追加されています。その理由は，VisiBrokerのインタセプタを熟知している開発者にVisiBrokerのインタセプタとOMG固有ポータブルインタセプタ間のコーディングを早く行える方法を提供するためです。

(2)　コードの説明

(a)　必須パッケージのインポート

ポータブルインタセプタインタフェースを使用するには，関連パッケージまたはヘッダファイルが組み込まれている必要があります。Java ORBで，DuplicateNameやInvalidNameのようなポータブルインタセプタの例外を使用している場合，org.omg.PortableInterceptor.ORBInitInfoPackageはオプションであることに注意してください。

コードサンプル19-25　ポータブルインタセプタを使用する際の必須ヘッダファイル（C++）

#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"

コードサンプル19-26　ポータブルインタセプタを使用する際の必須パッケージ（Java）

import org.omg.PortableInterceptor.*;
import org.omg.PortableInterceptor.ORBInitInfoPackage.*;

まずクライアント側で，リクエストインタセプタの各部分の書き方について詳細に説明します。クライアント側のリクエストインタセプタをロードするには，インタフェースをインプリメントするクラスであるORBInitializerをインプリメントする必要があります。また，これは初期化を考慮するとサーバ側のリクエストインタセプタにも該当します。

次にこれをインプリメントするコードを示します。

コードサンプル19-27　クライアントリクエストインタセプタをロードするためのORBInitializerの正しい継承

C++の場合

class SampleClientLoader :
   public PortableInterceptor::ORBInitializer

Javaの場合

public class SampleClientLoader extends
   org.omg.CORBA.LocalObject implements ORBInitializer

コードサンプル19-28　サーバリクエストインタセプタをロードするためのORBInitializerの正しい継承

C++の場合

class SampleServerLoader :
   public PortableInterceptor::ORBInitializer

Javaの場合

public class SampleServerLoader extends
   org.omg.CORBA.LocalObject implements ORBInitializer

インタフェースをインプリメントするオブジェクトであるORBInitializerそれぞれもLocalObjectオブジェクトから継承される必要があることに注意してください。これが必要である理由は，ORBInitializerのIDL定義がキーワードであるlocalを使用するためです。IDLキーワードlocalの詳細については，「25.　valuetypeの使用」を参照してください。

ORBの初期化時に，各リクエストインタセプタはpre_init()インタフェースのインプリメンテーションによって追加されています。このインタフェース内では，クライアントリクエストインタセプタは，add_client_request_interceptor()メソッドによって追加されています。関連するクライアントリクエストインタセプタ自身をORBに追加する前に，そのインタセプタが実体化される必要があります。

コードサンプル19-29　クライアント側リクエストインタセプタの初期化およびORBへの登録

C++の場合

public:
   void pre_init(PortableInterceptor::ORBInitInfo_ptr
    _info){
      SampleClientInterceptor *interceptor =
                                  new SampleClientInterceptor;
         try {
            _info->add_client_request_interceptor(interceptor);
            . . .

Javaの場合

public void pre_init(ORBInitInfo info){
   try {
      info.add_client_request_interceptor(new
                                    SampleClientInterceptor());
      . . .

OMG規格に従って，必須アプリケーションはregister_orb_initializerメソッドによってそれぞれのインタセプタを登録します。詳細については「19.3.2(2)(f)　クライアントおよびサーバアプリケーションの開発」を参照してください。VisiBrokerには，このようなインタセプタの別のオプションの登録方法，（DLLによる登録など）があります。この登録方法を使用すると，アプリケーションはコードをまったく変更する必要がなく，その実行方法だけを変更すれば済むという利点があります。実行時の拡張オプションによって，インタセプタが登録され実行されます。オプションはVisiBroker 4.xインタセプタであるvbroker.orb.dynamicLibs=<DLL filename>と同様です。ここで，<DLL filename>はダイナミックリンクライブラリのファイル名であり，拡張子は，UNIXの場合は.so，.sl，.aなどで，Windowsの場合は.dllです。一つ以上のDLLファイルをロードするには，次のように各ファイル名をコンマ（,）で区切ります。

vbroker.orb.dynamicLibs=a.so,b.so,c.so（UNIX）

vbroker.orb.dynamicLibs=a.dll,b.dll,c.dll（Windows）

動的にインタセプタをロードするには，VISInitインタフェースが使用されます。これはVisiBroker 4.xインタセプタで使用されるものと同様です。詳細については「20.　VisiBroker 4.xインタセプタの使用」を参照してください。ORB_initのインプリメンテーションでは，各インタセプタローダの登録は同様に行われます。

コードサンプル19-30　DLLのロードによるクライアント側のORBInitializerの登録（C++）

void ORB_init(int& argc,char* const* argv,CORBA::ORB_ptr orb)
{
   if(_bind_interceptors_installed)return;

   SampleClientLoader *client =new SampleClientLoader();
   PortableInterceptor::register_orb_initializer(client);

   . . .

クライアント側インタセプタローダの完全なインプリメンテーションを次に示します。

コードサンプル19-31　クライアント側インタセプタローダの完全なインプリメンテーション（C++）

//SampleClientLoader.C

#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"

#include "SampleClientInterceptor.h"

#if !defined(DLL_COMPILE )
#include "vinit.h"
#include "corba.h"
#endif

//USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

class SampleClientLoader :
   public PortableInterceptor::ORBInitializer
{
private:
   short int _interceptors_installed;

   #if defined(DLL_COMPILE )
   static SampleClientLoader _instance;
   #endif

public:
   SampleClientLoader(){
      _interceptors_installed =0;
   }

   void pre_init(PortableInterceptor::ORBInitInfo_ptr _info){
      if(_interceptors_installed)return;

      cout <<"=====>SampleClientLoader:Installing ..."<<endl;

      SampleClientInterceptor *interceptor =
                                 new SampleClientInterceptor;

      try {
            _info->add_client_request_interceptor(interceptor);

            _interceptors_installed =1;
            cout <<"=====>SampleClientLoader:Interceptors loaded."
                 <<endl;
      }
      catch(PortableInterceptor::ORBInitInfo::DuplicateName &e){
         cout <<"=====>SampleClientLoader:"
              <<e.name <<"already installed!"<<endl;
      }
      catch(...){
         cout <<"=====>SampleClientLoader:other exception occurred!"
              <<endl;
         }
      }

      void post_init(PortableInterceptor::ORBInitInfo_ptr _info){
   }
};

#if defined(DLL_COMPILE )

class VisiClientLoader :VISInit

{
private:
      static VisiClientLoader _instance;
      short int _bind_interceptors_installed;

public:
   VisiClientLoader():VISInit(1){
   _bind_interceptors_installed =0;
   }

   void ORB_init(int&argc,char*const*argv,CORBA::ORB_ptr orb){
      if(_bind_interceptors_installed)return;

      try {
            SampleClientLoader *client =new SampleClientLoader();
            PortableInterceptor::register_orb_initializer(client);

            _bind_interceptors_installed =1;
      }

      catch(const CORBA::Exception&e)
      {
         cerr <<e <<endl;
      }
   }
};

//static instance
VisiClientLoader VisiClientLoader::_instance;

#endif

コードサンプル19-32　クライアント側インタセプタローダの完全なインプリメンテーション（Java）：SampleClientLoader.java

//SampleClientLoader.java

import org.omg.PortableInterceptor.*;
import org.omg.PortableInterceptor.ORBInitInfoPackage.*;

public class SampleClientLoader extends org.omg.CORBA.LocalObject
implements ORBInitializer
{
   public void pre_init(ORBInitInfo info){
      try {
         System.out.println("=====>SampleClientLoader:
                                                   Installing ...");
         info.add_client_request_interceptor
                                       (new SampleClientInterceptor());
         System.out.println("=====>SampleClientLoader:Interceptors
                                                             loaded.");
      }
      catch(DuplicateName dn){
         System.out.println("=====>SampleClientLoader:"+dn.name
                                                +"already installed.");
      }
      catch(Exception e){
         e.printStackTrace();
         throw new org.omg.CORBA.INITIALIZE(e.toString());
     }
   }

      public void post_init(ORBInitInfo info){
         //We do not do anything here.
      }
}

(b)　サーバ側インタセプタでのORBInitializerのインプリメント

この段階では，クライアントリクエストインタセプタはすでに正しく実体化され，追加されているはずです。これ以降のコードサンプルは例外処理と結果表示だけを提供します。同様に，サーバ側のサーバリクエストインタセプタにも同じことが行われます。ただし，add_server_request_interceptor()メソッドを使用して関連サーバリクエストインタセプタをORBに追加することが異なります。

コードサンプル19-33　サーバ側リクエストインタセプタの初期化およびORBへの登録

C++の場合

public:
   void pre_init(PortableInterceptor::ORBInitInfo_ptr
    _info){
      SampleServerInterceptor *interceptor =
                                  new SampleServerInterceptor;
      try {
         _info->add_server_request_interceptor(interceptor);
         . . .

Javaの場合

public void pre_init(ORBInitInfo info){
   try {
      info.add_server_request_interceptor(
                                new SampleServerInterceptor());
      . . .

これは，サーバ側ORBInitializerクラスのDLLインプリメンテーションによるロードにも同様に適用されます。

コードサンプル19-34　DLLによってロードされるサーバ側リクエストORBInitializer（C++）

void ORB_init(int& argc,char* const* argv,CORBA::ORB_ptr orb)
{
   if(_poa_interceptors_installed)return;
   SampleServerLoader *server =new SampleServerLoader();
   PortableInterceptor::register_orb_initializer(server);
   . . .

サーバ側インタセプタローダの完全なインプリメンテーションを次に示します。

コードサンプル19-35　サーバ側インタセプタローダの完全なインプリメンテーション（C++）

//SampleServerLoader.C

#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"

#if defined(DLL_COMPILE )
#include "vinit.h"
#include "corba.h"
#endif

#include "SampleServerInterceptor.h"

//USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

class SampleServerLoader :
   public PortableInterceptor::ORBInitializer
{
private:
   short int _interceptors_installed;

public:
   SampleServerLoader(){
      _interceptors_installed =0;
   }

   void pre_init(PortableInterceptor::ORBInitInfo_ptr _info){
       if(_interceptors_installed)return;

       cout <<"=====>SampleServerLoader:Installing ..."<<endl;

       SampleServerInterceptor *interceptor =
                             new SampleServerInterceptor();

       try {
         _info->add_server_request_interceptor(interceptor);

         _interceptors_installed =1;
         cout <<"=====>SampleServerLoader:Interceptors loaded."
              <<endl;
       }
       catch(PortableInterceptor::ORBInitInfo::DuplicateName &e){
         cout <<"=====>SampleServerLoader:"
           <<e.name <<"already installed!"<<endl;
       }
       catch(...){
         cout <<"=====>SampleServerLoader:other exception occurred!"
           <<endl;
     }
   }
void post_init(PortableInterceptor::ORBInitInfo_ptr _info){}
};

#if defined(DLL_COMPILE )
class VisiServerLoader :VISInit
{
private:
   static VisiServerLoader _instance;
   short int _poa_interceptors_installed;

public:
   VisiServerLoader():VISInit(1){
   _poa_interceptors_installed =0;
}
void ORB_init(int& argc,char* const* argv,CORBA::ORB_ptr orb){
      if(_poa_interceptors_installed)return;
      try {
            SampleServerLoader *server =new SampleServerLoader();
            PortableInterceptor::register_orb_initializer(server);
            _poa_interceptors_installed =1;
      }
   catch(const CORBA::Exception&e)
      {
      cerr <<e <<endl;
      }
   }
};
//static instance
VisiServerLoader VisiServerLoader::_instance;

#endif

コードサンプル19-36　サーバ側インタセプタローダの完全なインプリメンテーション（Java）：SampleServerLoader.java

//SampleServerLoader.java

import org.omg.PortableInterceptor.*;
import org.omg.PortableInterceptor.ORBInitInfoPackage.*;

public class SampleServerLoader extends org.omg.CORBA.LocalObject
implements ORBInitializer

{
   public void pre_init(ORBInitInfo info){
      try {
         info.add_server_request_interceptor(new
                  SampleServerInterceptor());
         System.out.println("=====>SampleServerLoader:
                  Interceptors loaded");
      }
      catch(DuplicateName dn){
         System.out.println("Interceptor:
                              "+dn.name +"already installed.");
      }
      catch(Exception e){
         e.printStackTrace();
         throw new org.omg.CORBA.INITIALIZE(e.toString());
      }
   }
   public void post_init(ORBInitInfo info){
      //We do not do anything here.
   }
}

(c)　クライアント側およびサーバ側リクエストインタセプタでのRequestInterceptorのインプリメント

クライアント側またはサーバ側のリクエストインタセプタのインプリメンテーション時に，その両方に共通の別の二つのインタフェースをインプリメントする必要があります。それは，name()とdestroy()です。リクエストや応答でロードおよび呼び出しを行うインタセプタを正しく識別するためにORBに名前を提供するので，name()は重要です。CORBAの仕様に従うと，インタセプタはアノニマスでもかまいません。つまり，名前属性として空の文字列でもかまいません。このサンプルでは，SampleClientInterceptorという名前がクライアント側インタセプタに，SampleServerInterceptorという名前がサーバ側インタセプタに割り当てられています。

コードサンプル19-37　インタフェース属性，read-only属性名のインプリメンテーション

C++の場合

public:
   char *name(void){
      return _name;
}

Javaの場合

public String name(){
   return _name;
}

(d)　クライアントでのClientRequestInterceptorのインプリメント

クライアントリクエストインタセプタでは，リクエストインタセプタが正しく動作するためにClientRequestInterceptorインタフェースをインプリメントする必要があります。クラスがインタフェースをインプリメントする場合，インプリメンテーションに関係なく五つのリクエストインタセプタメソッドがインプリメントされます。これにはsend_request()メソッド，send_poll()メソッド，receive_reply()メソッド，receive_exception()メソッド，およびreceive_other()メソッドがあります。さらに，事前にリクエストインタセプタのインタフェースをインプリメントしておくことが必要です。クライアント側のインタセプタでは，そのイベントに関して次のリクエストインタセプトポイントが起動されます。

send_request

インタセプトポイントを提供し，インタセプタがリクエスト情報を照会して，リクエストがサーバに送信される前にサービスコンテキストを修正できるようにします。

コードサンプル19-38　public void send_request(ClientRequestInfo ri)インタフェースのインプリメンテーション

C++の場合

void send_request(PortableInterceptor::ClientRequestInfo_ptr ri){
   . . .

Javaの場合

public void send_request(ClientRequestInfo ri)
                                          throws ForwardRequest {
   . . .

コードサンプル19-39　void send_poll(ClientRequestInfo ri)インタフェースのインプリメンテーション

send_poll

インタセプトポイントを提供し，TII（時間非依存呼び出し）ポーリング取得応答シーケンス時に情報をインタセプタが照会できるようにします。

C++の場合

void send_poll(PortableInterceptor::ClientRequestInfo_ptr ri){
   . . .

Javaの場合

public void send_poll(ClientRequestInfo ri){
   . . .

コードサンプル19-40　void receive_reply(ClientRequestInfo ri)インタフェースのインプリメンテーション

receive_reply

インタセプトポイントを提供し，応答がサーバから戻されてから，制御がクライアントに戻る前にインタセプタがその応答に関する情報を照会できるようにします。

C++の場合

void receive_reply(PortableInterceptor::ClientRequestInfo_ptr
                                                           ri){
   . . .

Javaの場合

public void receive_reply(ClientRequestInfo ri){
   . . .

コードサンプル19-41　void receive_exception(ClientRequestInfo ri)インタフェースのインプリメンテーション

receive_exception

インタセプトポイントを提供し，例外がクライアントに発生する前にインタセプタがその例外の情報を照会できるようにします。

C++の場合

void receive_exception
               (PortableInterceptor::ClientRequestInfo_ptr ri){
   . . .

Javaの場合

public void receive_exception(ClientRequestInfo ri)
                                        throws ForwardRequest {
   . . .

receive_other

インタセプトポイントを提供し，リクエスト結果が正常応答または例外以外の結果になった場合に，インタセプタが利用可能な情報を照会できるようにします。例えば，リクエストの結果がリトライ（例：　LOCATION_FORWARDステータスのGIOP応答を受信）になる場合です。非同期呼び出しの場合は，リクエストのあとにすぐに応答は行われませんが，制御はクライアントに戻り，終了インタセプトポイントが呼び出されます。

コードサンプル19-42　void receive_other(ClientRequestInfo ri)インタフェースのインプリメンテーション

C++の場合

void receive_other(PortableInterceptor::ClientRequestInfo_ptr
                                                          ri){
   . . .

Javaの場合

public void receive_other(ClientRequestInfo ri)
                                          throws ForwardRequest {
   . . .

クライアント側リクエストインタセプタの完全なインプリメンテーションを次に示します。

コードサンプル19-43　クライアント側リクエストインタセプタの完全なインプリメンテーション（C++）

//SampleClientInterceptor.h

#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"

//USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

class SampleClientInterceptor :
   public PortableInterceptor::ClientRequestInterceptor
{
private:
   char *_name;

   void init(char *name){
      _name =new char [strlen(name)+1 ];
      strcpy(_name,name);
   }

public:
   SampleClientInterceptor(char *name){
      init(name);
   }

   SampleClientInterceptor(){
      init("SampleClientInterceptor");
   }

char *name(void){
   return _name;
}

void destroy(void){
   //do nothing here

   cout <<"=====>SampleServerLoader:Interceptors unloaded"<<endl;
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void preinvoke_premarshal(CORBA::Object_ptr target,
*                           const char*operation,
*                           IOP::ServiceContextList&servicecontexts,
*                           VISClosure&closure)=0;
*/
void send_request(PortableInterceptor::ClientRequestInfo_ptr ri){
   cout <<"=====>SampleClientInterceptor id "<<ri->request_id()
      <<"send_request =>"<<ri->operation()
      <<":Target ="<<ri->target()
      <<endl;
}

/**
* There is no equivalent interface for VisiBroker 4.x
* ClientRequestInterceptor.
*/

void send_poll(PortableInterceptor::ClientRequestInfo_ptr ri){
   cout <<"=====>SampleClientInterceptor id "<<ri->request_id()
      <<"send_poll =>"<<ri->operation()
      <<":Target ="<<ri->target()
      <<endl;
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void postinvoke(CORBA::Object_ptr target,
*                 const IOP::ServiceContextList&service_contexts,
*                 CORBA_MarshalInBuffer&payload,
*                 CORBA::Environment_ptr env,
*                 VISClosure&closure)=0;
*
* with env not holding any exception value.
*/
void receive_reply(PortableInterceptor::ClientRequestInfo_ptr ri){
   cout <<"=====>SampleClientInterceptor id "<<ri->request_id()
      <<"receive_reply =>"<<ri->operation()
      <<endl;
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void postinvoke(CORBA::Object_ptr target,
*                 const IOP::ServiceContextList&service_contexts,
*                 CORBA_MarshalInBuffer&payload,
*                 CORBA::Environment_ptr env,
*                 VISClosure&closure)=0;
*
* with env holding the exception value.
*/
void receive_exception(PortableInterceptor::ClientRequestInfo_ptr
                                                              ri){
   cout <<"=====>SampleClientInterceptor id "<<ri->request_id()
      <<"receive_exception =>"<<ri->operation()
      <<":Exception ="<<ri->received_exception()
      <<endl;
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void postinvoke(CORBA::Object_ptr target,
*                 const IOP::ServiceContextList&service_contexts,
*                 CORBA_MarshalInBuffer&payload,
*                 CORBA::Environment_ptr env,
*                 VISClosure&closure)=0;
*
* with env holding the exception value.
*/
void receive_other(PortableInterceptor::ClientRequestInfo_ptr ri){
   cout <<"=====>SampleClientInterceptor id "<<ri->request_id()
      <<"receive_other =>"<<ri->operation()
      <<":Exception ="<<ri->received_exception()
      <<",Reply Status ="<<
     getReplyStatus(ri->reply_status())
     <<endl;
   }

protected:
   char *getReplyStatus(CORBA::Short status){
      if(status ==PortableInterceptor::SUCCESSFUL)
            return "SUCCESSFUL";
      else if(status ==PortableInterceptor::SYSTEM_EXCEPTION)
            return "SYSTEM_EXCEPTION";
      else if(status ==PortableInterceptor::USER_EXCEPTION)
            return "USER_EXCEPTION";
      else if(status ==PortableInterceptor::LOCATION_FORWARD)
            return "LOCATION_FORWARD";
      else if(status ==PortableInterceptor::TRANSPORT_RETRY)
            return "TRANSPORT_RETRY";
      else
            return "invalid reply status id";
      }
};

コードサンプル19-44　クライアント側リクエストインタセプタの完全なインプリメンテーション（Java）：SampleClientInterceptor.java

//SampleClientInterceptor.java

import org.omg.PortableInterceptor.*;
import org.omg.Dynamic.*;

public class SampleClientInterceptor extends org.omg.CORBA.LocalObject
implements ClientRequestInterceptor {

   public SampleClientInterceptor(){
      this("SampleClientInterceptor");
}

public SampleClientInterceptor(String name){
_name =name;
}
private String _name =null;
/**
* InterceptorOperations implementation
*/
public String name(){
   return _name;
}

public void destroy(){
   System.out.println("=====>SampleServerLoader:Interceptors unloaded");
}

/**
* ClientRequestInterceptor implementation
*/

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void preinvoke_premarshal(org.omg.CORBA.Object target,
      String operation,
*   ServiceContextListHolder service_contexts_holder,Closure
    closure);
*/

public void send_request(ClientRequestInfo ri)throws ForwardRequest {
   System.out.println("=====>SampleClientInterceptor id "+
      ri.request_id()+
           "send_request =>"+ri.operation()+
           ":target ="+ri.target());
}

/**
* There is no equivalent interface for VisiBroker 4.x
* ClientRequestInterceptor.
*/

public void send_poll(ClientRequestInfo ri){
   System.out.println("=====>SampleClientInterceptor id "+
      ri.request_id()+
           "send_poll => " + ri.operation() +
           " : target = " + ri.target());
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void postinvoke(org.omg.CORBA.Object target,
*   ServiceContext[ ] service__contexts,InputStream payload,
*   org.omg.CORBA.Environment env,Closure closure);
*
* with env not holding any exception value.
*/
public void receive_reply(ClientRequestInfo ri){
   System.out.println("=====>SampleClientInterceptor id " +
     ri.request_id() +
           " receive_reply => " + ri.operation());
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void postinvoke(org.omg.CORBA.Object target,
*   ServiceContext[ ] service__contexts,InputStream payload,
*   org.omg.CORBA.Environment env,Closure closure);
*
* with env holding the exception value.
*/
public void receive_exception(ClientRequestInfo ri)throws ForwardRequest {
   System.out.println("=====>SampleClientInterceptor id "+
      ri.request_id() +
            " receive_exception => " + ri.operation() +
            ": exception = " + ri.received_exception());
}
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void postinvoke(org.omg.CORBA.Object target,
*   ServiceContext[ ] service__contexts,InputStream payload,
*   org.omg.CORBA.Environment env,Closure closure);
*
* with env holding the exception value.
*/
public void receive_other(ClientRequestInfo ri) throws ForwardRequest {
   System.out.println("=====> SampleClientInterceptor id "+
      ri.request_id() +
           " receive_reply => " + ri.operation() +
           ": exception = " + ri.received_exception() +
           ", reply status = " + getReplyStatus(ri));
}
protected String getReplyStatus(RequestInfo ri){
   switch(ri.reply_status()){
      case SUCCESSFUL.value:
         return "SUCCESSFUL";
      case SYSTEM_EXCEPTION.value:
         return "SYSTEM_EXCEPTION";
      case USER_EXCEPTION.value:
         return "USER_EXCEPTION";
      case LOCATION_FORWARD.value:
         return "LOCATION_FORWARD";
      case TRANSPORT_RETRY.value:
         return "TRANSPORT_RETRY";
      default:
         return "invalid reply status id";
      }
   }
}

(e)　サーバでのServerRequestInterceptorのインプリメント

サーバリクエストインタセプタでは，リクエストインタセプタが正しく動作するためにServerRequestInterceptorインタフェースをインプリメントする必要があります。サーバ側インタセプタでは，各イベントに関して次のリクエストインタセプトポイントが起動されます。

receive_request_service_contexts

インタセプトポイントを提供し，インタセプタが入力リクエストからサービスコンテキスト情報を取得し，それをPortableInterceptor::Currentのスロットに転送できるようにします。このインタセプトポイントはサーバントマネージャの前に呼び出されます。

コードサンプル19-45　void receive_request_service_contexts (ServerRequestInfo ri)インタフェースのインプリメンテーション

C++の場合

void receive_request_service_contexts
                (PortableInterceptor::ServerRequestInfo_ptr
                                                        ri){
   . . .

Javaの場合

public void receive_request_service_contexts
       (ServerRequestInfo ri) throws ForwardRequest{
   . . .

receive_request

インタセプトポイントを提供し，使用できるすべての情報（オペレーションパラメタなど）をインタセプタが照会できるようにします。

コードサンプル19-46　void receive_request (ServerRequestInfo ri)インタフェースのインプリメンテーション

C++の場合

void receive_request(PortableInterceptor::ServerRequestInfo_ptr
                                                           ri){
   . . .

Javaの場合

public void receive_request(ServerRequestInfo ri)
                                         throws ForwardRequest {
   . . .

send_reply

インタセプトポイントを提供し，ターゲットオペレーションが呼び出されたあと，応答がクライアントに戻される前にインタセプタが応答情報を照会し，応答サービスコンテキストを修正できるようにします。

コードサンプル19-47　void send_reply (ServerRequestInfo ri)インタフェースのインプリメンテーション

C++の場合

void send_reply(PortableInterceptor::ServerRequestInfo_ptr
                                                      ri){
   . . .

Javaの場合

public void send_reply(ServerRequestInfo ri){
   . . .

send_exception

インタセプトポイントを提供し，例外がクライアントで発生する前にインタセプタが例外情報を照会し，応答サービスコンテキストを修正できるようにします。

コードサンプル19-48　void send_exception (ServerRequestInfo ri)インタフェースのインプリメンテーション

C++の場合

void send_exception(PortableInterceptor::ServerRequestInfo_ptr
                                                          ri) {
   . . .

Javaの場合

public void send_exception(ServerRequestInfo ri)throws
                                                ForwardRequest {
   . . .

send_other

インタセプトポイントを提供し，リクエスト結果が正常応答または例外以外の結果になった場合に，インタセプタが利用可能な情報を照会できるようにします。例えば，リクエストの結果がリトライ（例:　LOCATION_FORWARDステータスのGIOP応答を受信）する場合です。非同期呼び出しの場合は，リクエストのあとにすぐに応答は行われませんが，制御はクライアントに戻り，終了インタセプトポイントが呼び出されます。

コードサンプル19-49　void send_other (ServerRequestInfo ri)インタフェースのインプリメンテーション

C++の場合

void send_other(PortableInterceptor::ServerRequestInfo_ptr
                                                        ri){
   . . .

Javaの場合

public void send_other(ServerRequestInfo ri)throws
                                     ForwardRequest {
   . . .

すべてのインタセプトポイントによって，クライアントおよびサーバは異なる種類の情報を呼び出しの異なるポイントで取得できます。サンプルでは，このような情報はデバッグの形式で画面に表示されています。

サーバ側リクエストインタセプタの完全なインプリメンテーションを次に示します。

コードサンプル19-50　サーバ側リクエストインタセプタの完全なインプリメンテーション（C++）：SampleServerInterceptor.cpp

// SampleServerInterceptor.h

#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"

//USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

class SampleServerInterceptor :
   public PortableInterceptor::ServerRequestInterceptor
{
private:
   char *_name;

   void init(char *name){
      _name =new char [strlen(name)+1 ];
      strcpy(_name,name);
}

public:
   SampleServerInterceptor(char *name){
      init(name);
   }

   SampleServerInterceptor(){
      init("SampleServerInterceptor");
   }

   char *name(void){
      return _name;
}

   void destroy(void){
      //do nothing here
      cout <<"=====>SampleServerLoader:Interceptors unloaded"<<endl;
   }

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void preinvoke_premarshal(CORBA::Object_ptr target,
*                           const char*operation,
*                           IOP::ServiceContextList&servicecontexts,
*                           VISClosure&closure)=0;
*/
void
receive_request_service_contexts(PortableInterceptor::
   ServerRequestInfo_ptr ri){
         cout <<"=====>SampleServerInterceptor id "<<ri->request_id()
         <<"receive_request_service_contexts =>"<<ri->operation()
         <<endl;
}

/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
void receive_request(PortableInterceptor::ServerRequestInfo_ptr
                                                              ri)
{
   cout <<"=====>SampleServerInterceptor id "<<ri->request_id()
      <<"receive_request =>"<<ri->operation()
      <<":Object ID ="<<ri->object_id()
      <<",Adapter ID ="<<ri->adapter_id()
      <<endl;
}

/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
void send_reply(PortableInterceptor::ServerRequestInfo_ptr ri){
   cout <<"=====>SampleServerInterceptor id "<<ri->request_id()
      <<"send_reply =>"<<ri->operation()
      <<endl;
}

/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* virtual void postinvoke_premarshal(CORBA::Object_ptr _target,
*                      IOP::ServiceContextList&_service_contexts,
*                                    CORBA::Environment_ptr _env,
*                                    VISClosure&_closure)=0;
*
*with env holding the exception value.
*/
void send_exception(PortableInterceptor::ServerRequestInfo_ptr
                                                              ri){
   cout << "=====> SampleServerInterceptor id " << ri->request_id()
        << " send_exception => " << ri ->operation()
        << " :Exception = " << ri ->sending_exception()
        << " ,Reply status = " << getReplyStatus(ri->reply_status())
        <<endl;
}

/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* virtual void postinvoke_premarshal(CORBA::Object_ptr _target,
*                                    IOP::ServiceContextList&_service_contexts,
*                                    CORBA::Environment_ptr _env,
*                                    VISClosure&_closure)=0;
*
* with env holding the exception value.
*/
void send_other(PortableInterceptor::ServerRequestInfo_ptr ri){
   cout <<"=====>SampleServerInterceptor id "<<ri->request_id()
      <<"send_other =>"<<ri->operation()
      <<":Exception ="<<ri->sending_exception()
      <<",Reply Status ="<<getReplyStatus(ri->reply_status())
      <<endl;
}

protected:
   char *getReplyStatus(CORBA::Short status){
      if(status ==PortableInterceptor::SUCCESSFUL)
         return "SUCCESSFUL";
            else if(status ==PortableInterceptor::SYSTEM_EXCEPTION)
         return "SYSTEM_EXCEPTION";
            else if(status ==PortableInterceptor::USER_EXCEPTION)
         return "USER_EXCEPTION";
            else if(status ==PortableInterceptor::LOCATION_FORWARD)
         return "LOCATION_FORWARD";
            else if(status ==PortableInterceptor::TRANSPORT_RETRY)
         return "TRANSPORT_RETRY";
            else
         return "invalid reply status id";
      }
};

コードサンプル19-51　サーバ側リクエストインタセプタの完全なインプリメンテーション（Java）：SampleServerInterceptor.java

// SampleServerInterceptor.java

import org.omg.PortableInterceptor.*;
import org.omg.Dynamic.*;
import java.io.PrintStream;

public class SampleServerInterceptor extends org.omg.CORBA.LocalObject
implements ServerRequestInterceptor {

   private String _name =null;

   public SampleServerInterceptor(){
      this("SampleServerInterceptor");
   }

   public SampleServerInterceptor(String name){
      _name =name;
   }
/**
* InterceptorOperations implementation
*/
public String name() {
      return _name;
}

public void destroy(){
   System.out.println("=====>SampleServerLoader:Interceptors unloaded");
}

/**
* ServerRequestInterceptor implementation
*/

/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* public void preinvoke(org.omg.CORBA.Object target,
*   String operation,
*   ServiceContext[ ] service__contexts,InputStream payload,
*   Closure closure);
*/

public void receive_request_service_contexts(ServerRequestInfo ri)
      throws ForwardRequest {
   System.out.println("=====>SampleServerInterceptor id " +
           ri.request_id() +
           " receive_request_service_contexts => " + ri.operation());
}

/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
public void receive_request(ServerRequestInfo ri)
      throws ForwardRequest {
   System.out.println("=====>SampleServerInterceptor id "
            + ri.request_id() +
            " receive_request => " + ri.operation() +
            ": object id = " + ri.object_id() +
            ", adapter_id = " + ri.adapter_id());
}

/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
public void send_reply(ServerRequestInfo ri){
   System.out.println("=====> SampleServerInterceptor id " +
            ri.request_id() +
            " send_reply => " + ri.operation());
}

/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* public void postinvoke_premarshal(org.omg.CORBA.Object target,
* ServiceContextListHolder service_contexts_holder,
* org.omg.CORBA.Environment env,Closure closure);
*
*with env holding the exception value.
*/
public void send_exception(ServerRequestInfo ri)
      throws ForwardRequest {
   System.out.println("=====>SampleServerInterceptor id " +
            ri.request_id() +
            " send_exception => " + ri.operation() +
            ": exception = " + ri.sending_exception() +
            ", reply status = " + getReplyStatus(ri));
}

/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* public void postinvoke_premarshal(org.omg.CORBA.Object target,
*   ServiceContextListHolder service_contexts_holder,
*   org.omg.CORBA.Environment env,Closure closure);
*
* with env holding the exception value.
*/
public void send_other(ServerRequestInfo ri)throws ForwardRequest {
      System.out.print("=====>SampleServerInterceptor id "+
            ri.request_id() +
            " send_other =>" + ri.operation() +
            ": exception = " + ri.sending_exception() +
            ", reply status = " + getReplyStatus(ri));
}
      protected String getReplyStatus(RequestInfo ri){
         switch(ri.reply_status()){
            case SUCCESSFUL.value:
               return "SUCCESSFUL";
            case SYSTEM_EXCEPTION.value:
               return "SYSTEM_EXCEPTION";
            case USER_EXCEPTION.value:
               return "USER_EXCEPTION";
            case LOCATION_FORWARD.value:
               return "LOCATION_FORWARD";
            case TRANSPORT_RETRY.value:
               return "TRANSPORT_RETRY";
            default:
               return "invalid reply status id";
         }
      }
}

(f)　クライアントおよびサーバアプリケーションの開発

インタセプタクラスを書き込んだあと，このクラスをそれぞれクライアントおよびサーバアプリケーションに登録する必要があります。

C++の場合

C++では，クライアントとサーバはPortableInterceptor::register_orb_initializer(<class name>)メソッドによって，それぞれのORBInitializerクラスを登録します。

ここで，<class name>は登録するクラスの名前です。サンプルでは，DLL（動的リンクライブラリ）としてインタセプタクラスを登録する別の方法も説明します。この方法の利点は，アプリケーションがコードを変更する必要がなく，実行方法だけを変更すればいいということです。「19.3.2(4)　クライアントおよびサーバアプリケーションの実行または配置」を参照してください。これはVisiBrokerの適切な登録方法であることに注意してください。OMGに完全に準拠するには，次に示す方法は使用しないでください。

DLLとしてインタセプタクラスをロードすること（すなわち，VisiBrokerの適切なメソッドを使用すること）を選択したら，クライアントおよびサーバアプリケーションに拡張コードを追加する必要はありません。サンプルでは，DLLコンパイルとリンク付けが指定されていないと，コードの部分がマクロによる適切な状態ではないことがわかります。

クライアントアプリケーションの完全なインプリメンテーションを次に示します。

コードサンプル19-52　クライアントアプリケーションの完全なインプリメンテーション（C++）

//Client.C

#include "Bank_c.hh"

//USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

#if !defined(DLL_COMPILE )
#include "SampleClientLoader.C"
#endif

int main(int argc, char* const* argv)
{
   try {
      // Instantiate the Loader *before* the orb initialization
      // if chose not to use DLL method of loading
      #if !defined(DLL_COMPILE )
      SampleClientLoader* loader = new SampleClientLoader;
      PortableInterceptor::register_orb_initializer(loader);
      #endif

      // Initialize the ORB.
      CORBA::ORB_var orb =CORBA::ORB_init(argc,argv);

      // Get the manager Id
      PortableServer::ObjectId_var managerId =
               PortableServer::string_to_ObjectId("BankManager");

      // Locate an account manager.Give the full POA name and the
      // servant ID.
      Bank::AccountManager_var manager =
              Bank::AccountManager::_bind("/bank_agent_poa"
                                                    ,managerId);

      // use argv [1 ] as the account name,,or a default.
      const char*name =argc >1 ?argv [1 ] ::"Jack B.Quick";

      // Request the account manager to open a named account.
      Bank::Account_var account =manager->open(name);

      // Get the balance of the account.
      CORBA::Float balance =account->balance();

      // Print out the balance.
      cout <<"The balance in "<<name <<"'s account is $"<<balance
            <<endl;
   }
   catch(const CORBA::Exception&e){
   cerr <<e <<endl;
   return 1;
   }
   return 0;
}

サーバアプリケーションの完全なインプリメンテーションを次に示します。

コードサンプル19-53　サーバアプリケーションの完全なインプリメンテーション（C++）

// Server.C

#include "BankImpl.h"

// USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

#if !defined(DLL_COMPILE )
#include "SampleServerLoader.C"
#endif

int main(int argc,char*const*argv)
{
   try {
       // Instantiate an interceptor loader before initializing
       // the orb:
       #if !defined(DLL_COMPILE )
       SampleServerLoader*loader = new SampleServerLoader();
       PortableInterceptor::register_orb_initializer(loader);
       #endif

       // Initialize the ORB.
       CORBA::ORB_var orb = CORBA::ORB_init(argc,argv);

       // get a reference to the rootPOA
       CORBA::Object_var obj = orb->
                                 resolve_initial_references("RootPOA");
       PortableServer::POA_var rootPOA =
                                 PortableServer::POA::_narrow(obj);

       CORBA::PolicyList policies;
       policies.length(1);
       policies [(CORBA::ULong)0 ] = rootPOA->
                  create_lifespan_policy( PortableServer::PERSISTENT );

       // get the POA Manager
       PortableServer::POAManager_var poa_manager =
                                              rootPOA->the_POAManager();

       // Create myPOA with the right policies
       PortableServer::POA_var myPOA =
                                rootPOA->create_POA("bank_agent_poa",
                                                         poa_manager,
                                                         policies);

       // Create the servant
       AccountManagerImpl managerServant;

       // Decide on the ID for the servant
       PortableServer::ObjectId_var managerId =
                   PortableServer::string_to_ObjectId("BankManager");

       // Activate the servant with the ID on myPOA
       myPOA->activate_object_with_id(managerId,&managerServant);

       // Activate the POA Manager
       poa_manager->activate();

       CORBA::Object_var reference =
       myPOA->servant_to_reference(&managerServant);
       cout <<reference <<"is ready"<<endl;

       // Wait for incoming requests
       orb->run();
   }
   catch(const CORBA::Exception&e){
      cerr <<e <<endl;
      return 1;
   }
   return 0;
}

Javaの場合

Javaでは，OMG規格のregister_orb_initializerのマッピングに従います。すなわち，このクラスをJava ORBプロパティによって登録します。サンプルでは，クライアントおよびサーバアプリケーションは実際には，プロパティファイルから，org.omg.PortableInterceptor.ORBInitializerClass.<Service>（<Service>はorg.omg.PortableInterceptor.ORBInitializerをインプリメントするクラスの文字列名です）プロパティがあるclient.propertiesおよびserver.propertiesを読み取ります。この場合は，SampleClientLoaderおよびSampleServerLoaderという二つのクラスです。

また，ファイルからプロパティを読み取らないで，アプリケーションを書き込むことを選択する場合，コマンドラインオプションを使用することもできます。これには，アプリケーションを次のように実行する必要があります。

vbj -Dorg.omg.PortableInterceptor.ORBInitializerClass.
    SampleClientLoader = SampleClientLoaderClient
vbj -Dorg.omg.PortableInterceptor.ORBInitializerClass.
    SampleServerLoader = SampleServerLoaderServer

クライアントアプリケーションの完全なインプリメンテーションを次に示します。

コードサンプル19-54　クライアントアプリケーションの完全なインプリメンテーション（Java）:Client.java

// Client.java

import org.omg.PortableServer.*;

import java.util.Properties;
import java.io.FileInputStream;

public class Client {

   private static Properties property =null;

   public static void main(String [ ] args){
      try {
         property = new Properties();
         property.load(new FileInputStream("client.properties"));

      // Initialize the ORB.
      org.omg.CORBA.ORB orb=org.omg.CORBA.ORB.init(args,property);
      // Get the manager Id
      byte[ ] AccountManagerId="BankManager".getBytes();
      // Locate an account manager.Give the full POA name and
      // the servant ID.
      Bank.AccountManager manager =
         Bank.AccountManagerHelper.bind(orb,
            "/bank_client_server_poa", AccountManagerId);
      // use args [0 ]as the account name,or a default.
      String name =null;
      name =args.length >0 ?args [0 ] :"Jack B.Quick";
      // Request the account manager to open a named account.
      Bank.Account account =manager.open(name);
      // Get the balance of the account.
      float balance =account.balance();
      // Print out the balance.
      System.out.println("The balance in "+name +"'s account is $"+
         balance);
      }
      catch(Exception e){
      e.printStackTrace();
      }
  }
}

サーバアプリケーションの完全なインプリメンテーションを次に示します。

コードサンプル19-55　サーバアプリケーションの完全なインプリメンテーション（Java）:Server.java

// Server.java

import org.omg.PortableServer.*;
import java.util.Properties;
import java.io.FileInputStream;

public class Server {

   private static Properties property = null;

   public static void main(String[ ] args)){
      try {
         property =new Properties();
         property.load(new FileInputStream("server.properties"));

         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                            org.omg.CORBA.ORB.init(args,property);
         // get a reference to the rootPOA
         POA rootPOA =POAHelper.narrow(orb.resolve_initial_references
                                                          ("RootPOA"));

         // Create policies for our persistent POA
         org.omg.CORBA.Policy[ ] policies =={
             rootPOA.create_lifespan_policy(
                         LifespanPolicyValue.PERSISTENT)
         };

         // Create myPOA with the right policies
         POA myPOA =rootPOA.create_POA("bank_client_server_poa",
                          rootPOA.the_POAManager(),policies );

         // Create Account servants
         AccountManagerImpl managerServant =
                                         new AccountManagerImpl();
         byte[ ] managerId == "BankManager".getBytes();
         myPOA.activate_object_with_id(managerId,managerServant);
         rootPOA.the_POAManager().activate();

         // Announce Servants are ready
         System.out.println(myPOA.servant_to_reference
                                    (managerServant) + "is ready.");
         //Wait for incoming requests
         orb.run();
      }
      catch (Exception e){
      e.printStackTrace();
     }
   }
}

(3)　コンパイルの手順

C++の場合

VisiBrokerのC++サンプルをコンパイルするには，次のコマンドを実行します。

UNIX

$VBROKERDIR/examples/vbe/pi/client_server>make -f Makefile.cpp

Windows

%VBROKERDIR%¥examples¥vbe¥pi¥client_server>nmake -f Makefile.cpp

VisiBrokerのC++サンプルをコンパイルするには，次のコマンドを実行します。

UNIX

$VBROKERDIR/examples/vbe/pi/client_server>make -f Makefile.cpp dll

Windows

%VBROKERDIR%¥examples¥vbe¥pi¥client_server>nmake -f Makefile.cpp dll

Javaの場合

Javaのサンプルをコンパイルするには，次のコマンドを実行します。

UNIX

$VBROKERDIR/examples/vbe/pi/client_server>make -f Makefile.java

Windows

%VBROKERDIR%¥examples¥vbe¥pi¥client_server>vbmake

または，環境変数%VBROKERDIR%¥binが環境変数PATHにすでに追加されている場合は，バッチファイルアイコンをダブルクリックします。

(4)　クライアントおよびサーバアプリケーションの実行または配置

C++の場合

VisiBrokerのC++サンプルを実行するには，サーバとクライアントを次のように起動します。

UNIX（二つのコンソールウィンドウをオープンします）

$VBROKERDIR/examples/vbe/pi/client_server>Server（最初のウィンドウ）

$VBROKERDIR/examples/vbe/pi/client_server>Client John（2番目のウィンドウ：任意の名前を使用）

または，

$VBROKERDIR/examples/vbe/pi/client_server> Client（2番目のウィンドウ：デフォルトの名前を使用）

Windows

%VBROKERDIR%¥examples¥vbe¥pi¥client_server> start Server（新しいコマンドプロンプトウィンドウ下で実行）

%VBROKERDIR%¥examples¥vbe¥pi¥client_server> Client John（任意の名前を使用）

または，

%VBROKERDIR%¥examples¥vbe¥pi¥client_server> Client（デフォルトの名前を使用）

VisiBrokerのC++サンプルを実行するには，サーバとクライアントを次のように起動します。

UNIX（二つのコンソールウィンドウをオープンします）

$VBROKERDIR/examples/vbe/pi/client_server>Server

-Dvbroker.orb.dynamicLibs=./SampleServerLoader.so（最初のウィンドウ）

$VBROKERDIR/examples/vbe/pi/client_server>Client

-Dvbroker.orb.dynamicLibs=./SampleClientLoader.so John（2番目のウィンドウ：任意の名前を使用）

Windows

%VBROKERDIR%¥examples¥vbe¥pi¥client_server>start Server -Dvbroker.orb.dynamicLibs=SampleServerLoader.dll（新しいコマンドプロンプトウィンドウ下で実行）

%VBROKERDIR%¥examples¥vbe¥pi¥client_server>Client John -Dvbroker.orb.dynamicLibs=SampleClientLoader.dll（任意の名前を使用）

または，

%VBROKERDIR%¥examples¥vbe¥pi¥client_server>Client -Dvbroker.orb.dynamicLibs=SampleClientLoader.dll（デフォルトの名前を使用）

Javaの場合

インストール済みのポータブルインタセプタでJavaサンプルを実行するには，サーバとクライアントを次のように起動します。

UNIX（二つのコンソールウィンドウをオープンします）

$VBROKERDIR/examples/vbe/pi/client_server>vbj Server（最初のウィンドウ）

$VBROKERDIR/examples/vbe/pi/client_server>vbj Client John（2番目のウィンドウ：任意の名前を使用）

または，

$VBROKERDIR/examples/vbe/pi/client_server>vbj Client（2番目のウィンドウ：デフォルトの名前を使用）

Windows

%VBROKERDIR%¥examples¥vbe¥pi¥client_server>start vbj Server（新しいコマンドプロンプトウィンドウ下で実行）

%VBROKERDIR%¥examples¥vbe¥pi¥client_server>vbj Client John（任意の名前を使用）

20　VisiBroker 4.xインタセプタの使用

この章では，VisiBroker 4.xインタセプタの構成の概要について説明し，VisiBroker 4.xインタセプタの例を示しながら，インタセプタファクトリやインタセプタのチェーン化などの高度な機能について説明します。最後に，この章ではポータブルインタセプタとVisiBroker 4.xインタセプタが同じサービスを使用している場合に予測される動作について説明します。

20.1　概要

VisiBroker 4.xインタセプタは，VisiBroker 4.xで定義され，インプリメントされるインタセプタです。ポータブルインタセプタと同様，VisiBroker 4.xインタセプタはORBの正常な実行フローを受け取る機能であるBorland Enterprise Server VisiBroker ORBサービスを提供します。VisiBroker 4.xインタセプタには次の2種類があります。

クライアントインタセプタは，メソッドがクライアントオブジェクトで起動される場合に呼び出されるシステムレベルのインタセプタです。

サーバインタセプタは，メソッドがサーバオブジェクトで起動される場合に呼び出されるシステムレベルのインタセプタです。

インタセプタを使用するには，インタセプタインタフェースの一つをインプリメントするクラスを宣言します。インタセプタオブジェクトを実体化したら，そのインタセプタオブジェクトを対応するインタセプタマネージャに登録します。インタセプタオブジェクトに対応するマネージャは，起動されたメソッドやマーシャルされたりデマーシャルされたりしたパラメタの一つがオブジェクトにある場合に，そのインタセプタオブジェクトを認識できるようになります。

注

オペレーション要求がクライアント側でマーシャルされる前，またはサーバ側で処理される前にそのオペレーション要求を受け取りたい場合は，オブジェクトラッパーを使用してください（「21.　オブジェクトラッパーの使用」を参照）。

20.2　VisiBroker 4.xインタセプタインタフェースおよびマネージャ

VisiBroker 4.xインタセプタの開発者は，VisiBroker 4.xによって定義され，インプリメントされた次に示す複数のベースインタセプタAPIクラスからクラスを派生させます。

クライアントインタセプタ

BindInterceptor

ClientRequestInterceptor

サーバインタセプタ

POALifeCycleInterceptor

ActiveObjectLifeCycleInterceptor

ServerRequestInterceptor

IORCreationInterceptor

ServiceResolverインタセプタ

Service Resolver Interceptor

20.2.1　クライアントインタセプタ

次の2種類のクライアントインタセプタとそれに対応するマネージャがあります。

BindInterceptorおよびBindInterceptorManager

ClientRequestInterceptorおよびClientRequestInterceptorManager

クライアントインタセプタの詳細については，「19.　ポータブルインタセプタの使用」を参照してください。

(1)　BindInterceptor

BindInterceptorオブジェクトは，バインド前後にクライアント側で呼び出されるグローバルインタセプタです。

コードサンプル20-1　BindInterceptorインタフェース（Java）

package com.inprise.vbroker.InterceptorExt;
public interface BindInterceptor {
   public IORValue bind(IORValue ior,
         org.omg.CORBA.Object target,
         boolean rebind,
         Closure closure);
   public IORValue bind_failed(IORValue ior,
         org.omg.CORBA.Object target,
         Closure closure);
   public void bind_succeeded(IORValue ior,
         org.omg.CORBA.Object target,
         int Index,
         InterceptorManagerControl control,
         Closure closure);
   public void exception_occurred(IORValue ior,
         org.omg.CORBA.Object target,
         org.omg.CORBA.Environment env,
         Closure closure);
}

(2)　ClientRequestInterceptor

ClientRequestInterceptorオブジェクトは，BindInterceptorオブジェクトのbind_succeeded呼び出し中に登録できます。またこれは，コネクション期間中アクティブのままです。このメソッドのうちの二つは，クライアントオブジェクトの起動前に呼び出されます。一つ（preinvoke_premarshal）は，パラメタがマーシャルされる前に，もう一つ（preinvoke_postmarshal）は，パラメタがマーシャルされたあとに呼び出されます。三つ目のメソッド（postinvoke）は，リクエストの完了後に呼び出されます。

コードサンプル20-2　ClientRequestInterceptorインタフェース（Java）

package com.inprise.vbroker.InterceptorExt;
public interface ClientRequestInterceptor {
   public void preinvoke_premarshal(org.omg.CORBA.Object target,
         String operation,
         ServiceContextListHolder service_contexts_holder,
         Closure closure);
   public void preinvoke_postmarshal(org.omg.CORBA.Object target,
         OutputStream payload,
         Closure closure);
   public void postinvoke(org.omg.CORBA.Object target,
         ServiceContext [ ] service_contexts,
         InputStream payload,
         org.omg.CORBA.Environment env,
         Closure closure);
   public void exception_occurred(org.omg.CORBA.Object target,
         org.omg.CORBA.Environment env,
         Closure closure);
}

20.2.2　サーバインタセプタ

4種類のサーバインタセプタがあります。

POALifeCycleInterceptorおよびPOALifeCycleInterceptorManager

ActiveObjectLifeCycleInterceptorおよびActiveObjectLifeCycleInterceptorManager

ServerRequestInterceptorおよびServerRequestInterceptorManager

IORCreationInterceptorおよびIORCreationInterceptorManager

サーバインタセプタの詳細については，「19.　ポータブルインタセプタの使用」を参照してください。

(1)　POALifeCycleInterceptor

POALifeCycleInterceptorオブジェクトはPOAが（create()メソッドによって）生成されるたび，または（destroy()メソッドによって）デストラクトされるたびに呼び出されるグローバルインタセプタです。

コードサンプル20-3　POALifeCycleInterceptorインタフェース（Java）

package com.inprise.vbroker.InterceptorExt;
public interface POALifeCycleInterceptor {
   public void create(org.omg.PortableServer.POA poa,
      org.omg.CORBA.PolicyListHolder policies_holder,
      IORValueHolder iorTemplate,
      InterceptorManagerControl control);
   public void destroy(org.omg.PortableServer.POA poa);
}

(2)　ActiveObjectLifeCycleInterceptor

ActiveObjectLifeCycleInterceptorオブジェクトは，オブジェクトが（createメソッドによって）アクティブオブジェクトマップに追加された場合，またはオブジェクトが（destroyメソッドによって）停止し，エーテライズされたあとに呼び出されます。インタセプタは，POALifeCycleInterceptorによって，POA生成時にPOAごとに登録できます。このインタセプタは，POAにRETAINポリシーがある場合だけ登録できます。

コードサンプル20-4　ActiveObjectLifeCycleInterceptorインタフェース（Java）

package com.inprise.vbroker.InterceptorExt;
public interface ActiveObjectLifeCycleInterceptor {
   public void create(byte[ ] oid,,
         org.omg.PortableServer.Servant servant,
         org.omg.PortableServer.POA adapter);
   public void destroy (byte[ ] oid,,
         org.omg.PortableServer.Servant servant,
         org.omg.PortableServer.POA adapter);
}

(3)　ServerRequestInterceptor

ServerRequestInterceptorオブジェクトは，リモートオブジェクトのサーバインプリメンテーションの起動中のさまざまな段階，例えば（preinvokeメソッドによる）起動前，（postinvoke_premarshalおよびpostinvoke_premarshalメソッドによる）応答のマーシャル前後の起動後に呼び出されます。このインタセプタは，POAごとに，POAの生成時にPOALifeCycleInterceptorオブジェクトによって登録できます。

コードサンプル20-5　ServerRequestInterceptorインタフェース（Java）

package com.inprise.vbroker.InterceptorExt;
public interface ServerRequestInterceptor {
   public void preinvoke(org.omg.CORBA.Object target,
      String operation,
      ServiceContext [ ] service_contexts,
      InputStream payload,
      Closure closure);
   public void postinvoke_premarshal(org.omg.CORBA.Object target,
      ServiceContextListHolder service_contexts_holder,
      org.omg.CORBA.Environment env,
      Closure closure);
   public void postinvoke_postmarshal(org.omg.CORBA.Object target,
      OutputStream payload,
      Closure closure);
   public void exception_occurred(org.omg.CORBA.Object target,
      org.omg.CORBA.Environment env,
      Closure closure);
}

(4)　IORCreationInterceptor

IORCreationInterceptorオブジェクトは，POAが（createメソッドによって）オブジェクトリファレンスを生成する場合に呼び出されます。このインタセプタは，POAごとに，POAの生成時にPOALifeCycleInterceptorオブジェクトによって登録できます。

IDLサンプル20-1　IORCreationInterceptorインタフェース（Java）

package com.inprise.vbroker.InterceptorExt;
public interface IORCreationInterceptor {
   public void create(org.omg.PortableServer.POA poa,
         IORValueHolder ior);
}

20.2.3　ServiceResolverインタセプタ

このインタセプタはユーザサービスをインストールするために使用し，これによってユーザサービスを動的にロードできるようになります。

コードサンプル20-6　ServiceResolverInterceptorインタフェース（Java）

public interface ServiceResolverInterceptor {
   public org.omg.CORBA.Object resolve (java.lang.String name):
}
public interface ServiceResolverInterceptorManager extends
   com.inprise.vbroker.interceptor.InterceptorManager {
      public void add (java.lang.String name,
      com.inprise.vbroker.interceptor.ServiceResolverInterceptor
                                                  ¥interceptor);
   public void remove (java.lang.String name):
}

resolve_initial_references()メソッドを実行すると，すべてのユーザのインストールされたサービスのresolveが呼び出されます。resolveは該当するオブジェクトを返せます。

サービスイニシャライザを書き込むには，サービスを追加できるようになるInterceptorManagerControlを取得後に，ServiceResolverを取得する必要があります。

20.2.4　デフォルトのインタセプタクラス（Java）

Borland Enterprise Server VisiBrokerは，デフォルトのインタセプタJavaクラスを提供します。このクラスによって継承とインプリメントができます。このデフォルトのインタセプタクラスはインタセプタインタフェースと同じメソッドを提供しますが，デフォルトのインタセプタクラスを継承すると，インプリメントまたは変更するメソッドを選択できます。このクラスを使用する場合，このクラスが提供するデフォルトの動作を受け付けるか，またはそれを変更できます。

DefaultBindInterceptorクラス

DefaultClientInterceptorクラス

DefaultServerInterceptorクラス

20.2.5　Borland Enterprise Server VisiBroker ORBへのインタセプタの登録

それぞれのインタセプタインタフェースには，Borland Enterprise Server VisiBroker ORBにインタセプタオブジェクトを登録する際に使用する，対応するインタセプタマネージャインタフェースがあります。インタセプタを登録するための手順を次に示します。

ORBオブジェクトで，パラメタをVisiBrokerInterceptorControlとしてresolve_initial_referencesメソッドを呼び出して，InterceptorManagerControlオブジェクトのリファレンスを取得します。

表20-1のString値のどれかを指定したInterceptorManagerControlオブジェクトでget_managerメソッドを呼び出します。表20-1はInterceptorManagerControlオブジェクトのget_managerメソッドへ渡すString値を示します（オブジェクトリファレンスを対応するインタセプタマネージャインタフェースに必ずキャストしてください）。

表20‒1　InterceptorManagerControlオブジェクトのString値

値

対応するインタセプタインタフェース

ClientRequest

ClientRequestInterceptor

Bind

BindInterceptor

POALifeCycle

POALifeCycleInterceptor

ActiveObjectLifeCycle

ActiveObjectLifeCycleInterceptor

ServerRequest

ServerRequestInterceptor

IORCreation

IORCreationInterceptor

ServiceResolver

ServiceResolverInterceptor

インタセプタのインスタンスを生成します。

addメソッドを呼び出して，インタセプタオブジェクトをマネージャオブジェクトに登録します。

クライアントプログラムおよびサーバプログラムの実行時にインタセプタオブジェクトをロードします。

20.2.6　インタセプタオブジェクトの生成

ここで，インタセプタのインスタンスを生成し，それをBorland Enterprise Server VisiBroker ORBに登録するファクトリクラスをインプリメントする必要があります。ファクトリクラスはServiceLoaderインタフェース（Java）をインプリメントしなければなりません。

コードサンプル20-7　ServiceLoaderインタフェース（Java）

package com.inprise.vbroker.interceptor;
public interface ServiceLoader {
   //This method is called by the ORB when ORB.init()is called.
   public abstract void init(org.omg.CORBA.ORB orb);

   //Called after ORB.init()is done but control hasn't been returned to
   //the user.Can be used to disable certain resources that were only
   //made available to other service inits.
   public abstract void init_complete(org.omg.CORBA.ORB orb);

   //Called when the orb is being shutdown.
   public abstract void shutdown(org.omg.CORBA.ORB orb);
}

注

次の例のように，インタセプタの新しいインスタンスを生成し，それを別のインタセプタからBorland Enterprise Server VisiBroker ORBに登録することもできます。

20.2.7　インタセプタのロード

Javaの場合，インタセプタをロードするには，vbroker.orb.dynamicLibsプロパティを設定する必要があります。このプロパティはプロパティファイルで設定するか，または-Dオプションを使用してBorland Enterprise Server VisiBroker ORBに渡せます。

20.3　インタセプタのサンプル

次のインタセプタのサンプルでは，（「19.　ポータブルインタセプタの使用」にリストした）すべてのインタセプタAPIメソッドを使用しています。そのため，これらのメソッドがどのように使用されているか，またいつ呼び出されるかがわかるようになっています。

20.3.1　コードサンプル

「20.3.2　コード一覧」では，それぞれのインタセプタAPIメソッドは単純にインプリメントされており，これは標準出力に情報メッセージを出力します。

Borland Enterprise Server VisiBrokerインストレーションのexamples/vbe/interceptorsディレクトリには次の四つのアプリケーションの例があります。

active_object_lifecycle

client_server

ior_creation

encryption（Java）

(1)　クライアント−サーバインタセプタのサンプル

サンプルを実行するには，通常どおりにファイルをコンパイルします。そして，サーバとクライアントを次に示すように起動します。

Javaの場合

prompt>vbj -Dvbroker.orb.dynamicLibs=SampleServerLoader Server
prompt>vbj -Dvbroker.orb.dynamicLibs=SampleClientLoader Client Kate

Borland Enterprise Server VisiBroker ORBサービスに，ServiceLoaderインタフェースをインプリメントする二つのクラスを指定します。

注

VisiBroker 3.xで使用したServiceInitクラスは，ServiceLoaderおよびServiceResolverInterceptorという二つのインタフェースをインプリメントすることによって置き換えられています。この方法のサンプルについては，「20.3.1(2)　ServiceResolverInterceptorのサンプル（Java）」を参照してください。

表20-2にインタセプタの例の実行結果を示します。クライアントとサーバによる実行が順を追って示してあります。

表20‒2　インタセプタの例の実行結果

クライアント

サーバ

========> SampleServerLoader:Interceptors

loaded

========> In POA / . Nothing to do.

========> In POA bank_agent_poa,1

ServerRequest interceptor installed

Stub [repository_id=IDL:Bank/

AccountManager:1.0,key=ServiceId [service=/

bank_agent

_poa,id={11 bytes:

[B ][a ][n ][k ][M ][a ][n ][a ][g ][e ][r ]}]] is ready.

Bind Interceptors loaded

========> SampleBindInterceptor bind

========> SampleBindInterceptor

bind_succeeded

========> SampleClientInterceptor id

MyClientInterceptor preinvoke_premarshal

=> open

========> SampleClientInterceptor id

MyClientInterceptor preinvoke_postmarshal

========> SampleServerInterceptor id

MyServerInterceptor preinvoke => open

Created john's account:

Stub [repository_id=IDL:Bank/

Account:1.0,key=TransientId [

poaName=/,id={4 bytes:

(0)(0)(0)(0)},sec=0,usec=0 ]]

========> SampleClientInterceptor id

MyClientInterceptor postinvoke

========> SampleBindInterceptor bind

========> SampleBindInterceptor

bind_succeeded

========> SampleClientInterceptor id

MyClientInterceptor preinvoke_premarshal =>

balance

========> SampleClientInterceptor id

MyClientInterceptor preinvoke_postmarshal

========>SampleServerInterceptor id

MyServerInterceptor postinvoke_premarshal

========>SampleServerInterceptor id

MyServerInterceptor postinvoke_postmarshal

========>SampleClientInterceptor id

MyClientInterceptor postinvoke

The balance in john's account is $245.64

OADは実行されていないので，bind()メソッドの呼び出しは失敗し，サーバが処理を続行します。クライアントはアカウントオブジェクトにバインドしてから，balance()メソッドを起動します。このリクエストはサーバが受信して処理し，結果がクライアントに戻されます。クライアントは結果を出力します。

コードと結果のサンプルに示したように，クライアントとサーバの両方のインタセプタは，それぞれのプロセスの開始時点でインストールされます。インタセプタの登録についての情報については，「20.2.5　Borland Enterprise Server VisiBroker ORBへのインタセプタの登録」を参照してください。

(2)　ServiceResolverInterceptorのサンプル（Java）

次のコードでServiceLoaderインタフェースのインプリメント方法の例を示します。

import com.inprise.vbroker.properties.*;
import com.inprise.vbroker.interceptor.*;
import com.inprise.vbroker.InterceptorExt.*;

public final class UtilityServiceLoader implements ServiceLoader,
   ServiceResolverInterceptor {
   private com.inprise.vbroker.orb.ORB _orb = null;
   private String[ ] __serviceNames = { "TimeService",
                                               "WeatherService"};

   public void init(org.omg.CORBA.ORB orb) {
      //Just in case they are needed by resolve()
      _orb =(com.inprise.vbroker.orb.ORB)orb;

      PropertyManager pm =_orb.getPropertyManager();
      //use the PropertyManager to query property settings
      //if needed (not used in this example)

      /****Installing the Initial Reference *****/
      InterceptorManagerControl control =_orb.interceptorManager();
      ServiceResolverInterceptorManager manager =
         (ServiceResolverInterceptorManager)control.get_manager
                  ("ServiceResolver");
      for (int i =0;i <_serviceNames.length;i++){
         manager.add(_serviceNames [i ],this);
      }
      /****end of installation ***/

      if (_orb.debug)
         _orb.println("UtilityServices package has been
          initialized");
   }

   public void init_complete(org.omg.CORBA.ORB orb){
      //can be used for post-initialization processing if desired
   }

   public void shutdown(org.omg.CORBA.ORB orb){
      _orb =null;
      _serviceNames =null;
   }

   public org.omg.CORBA.Object resolve(java.lang.String service){
      org.omg.CORBA.Object srv =null;
      byte[ ] serviceId =service.getBytes();
      try {
         if (service =="TimeService"){
            srv =UtilityServices.TimeServiceHelper.bind(_orb,
               "/time_service_poa",serviceId);
         }
         else if (service =="WeatherService"){
            srv =UtilityServices.WeatherServiceHelper.bind(_orb,
               "/weather_service_poa",serviceId);
         }
      }catch (org.omg.CORBA.SystemException e){
         if (_orb.debug)
            _orb.println("UtilityServices package resolve error:"+e);
         srv =null;
      }

       return srv;
   }
}

20.3.2　コード一覧

Javaの場合，SampleServerInterceptorLoaderオブジェクトは，POALifeCycleInterceptorクラスのロードとオブジェクトの実体化に責任があります。このクラスは，vbroker.orb.dynamicLibsによって動的にBorland Enterprise Server VisiBroker ORBにリンクされます。SampleServerLoader クラスにはinit()メソッドがあり，このメソッドは初期化時にBorland Enterprise Server VisiBroker ORBによって起動されます。その唯一の目的は，POALifeCycleInterceptorオブジェクトを生成して，InterceptorManagerに登録することによって，POALifeCycleInterceptorオブジェクトをインストールすることです。

コードサンプル20-8　SampleServerLoader.java（Java）

import java.util.*;
import com.inprise.vbroker.orb.*;
import com.inprise.vbroker.interceptor.*;
import com.inprise.vbroker.PortableServerExt.*;

public class SampleServerLoader implements ServiceLoader {
   public void init(org.omg.CORBA.ORB orb){
      try {
         InterceptorManagerControl control =
           InterceptorManagerControlHelper.narrow(
             orb.resolve_initial_references
                ("VisiBrokerInterceptorControl"));
         //Install a POA interceptor
         POALifeCycleInterceptorManager poa_manager =
               (POALifeCycleInterceptorManager)control.get_manager
                   ("POALifeCycle");
         poa_manager.add(new SamplePOALifeCycleInterceptor());
      }catch(Exception e){
         e.printStackTrace();
         throw new org.omg.CORBA.INITIALIZE(e.toString());
      }
      System.out.println("============>SampleServerLoader:
            Interceptors loaded");
   }
   public void init_complete(org.omg.CORBA.ORB orb){
   }
   public void shutdown(org.omg.CORBA.ORB orb){
   }
}

SamplePOALifeCycleInterceptorオブジェクトは，POAが生成されるたびに，またはPOAがデストラクトされるたびに起動されます。client_serverの例では二つのPOAがあるので，このインタセプタは2回起動されます。1回目は，rootPOA生成時，2回目はmyPOA生成時です。myPOAの生成時だけ，SampleServerInterceptorをインストールします。

コードサンプル20-9　SamplePOALifeCycleInterceptor.java（Java）

import com.inprise.vbroker.interceptor.*;
import com.inprise.vbroker.PortableServerExt.*;
import com.inprise.vbroker.IOP.*;

public class SamplePOALifeCycleInterceptor implements
                                            POALifeCycleInterceptor {
   public void create(org.omg.PortableServer.POA poa,
      org.omg.CORBA.PolicyListHolder policies_holder,
      IORValueHolder iorTemplate,
      InterceptorManagerControl control){
   if(poa.the_name().equals("bank_agent_poa")){
      //Add the Request-level interceptor
      SampleServerInterceptor interceptor =
            new SampleServerInterceptor("MyServerInterceptor");
      //Get the IORCreation interceptor manager
      ServerRequestInterceptorManager manager =
            (ServerRequestInterceptorManager)control.get_manager
                ("ServerRequest");
      //Add the interceptor
      manager.add(interceptor);
      System.out.println("========>In POA " + poa.the_name() +
            ",1 ServerRequest interceptor installed");
   }else
      System.out.println("========>In POA " + poa.the_name() +
                                              ". Nothing to do.");
   }
   public void destroy(org.omg.PortableServer.POA poa){
      //To be a trace!
      System.out.println("========>SamplePOALifeCycleInterceptor
                                                         destroy");
   }
}

SampleServerInterceptorオブジェクトは，リクエストを受信するたびに，またはサーバが応答するたびに起動されます。

コードサンプル20-10　SampleServerInterceptor.java（Java）

import com.inprise.vbroker.interceptor.*;
import com.inprise.vbroker.IOP.*;
import com.inprise.vbroker.CORBA.portable.*;

public class SampleServerInterceptor implements ServerRequestInterceptor {
   private String _id;
   public SampleServerInterceptor(String id){
      _id =id;
   }
   public void preinvoke(org.omg.CORBA.Object target,
         String operation,
         ServiceContext [ ] service_contexts,
         InputStream payload,
         Closure closure){
      //Put the _id of this ServerRequestInterceptor into the
      // closure object
      closure.object =new String(_id);
      System.out.println("========>SampleServerInterceptor id "+
         closure.object + " preinvoke => " + operation);
   }
   public void postinvoke_premarshal(org.omg.CORBA.Object target,
         ServiceContextListHolder service_contexts_holder,
         org.omg.CORBA.Environment env,
         Closure closure){
         System.out.println("========>SampleServerInterceptor id "+
            closure.object + " postinvoke_premarshal");
   }
   public void postinvoke_postmarshal(org.omg.CORBA.Object target,
         OutputStream payload,
         Closure closure){
         System.out.println("========>SampleServerInterceptor id "+
            closure.object + " postinvoke_postmarshal");
   }
   public void exception_occurred(org.omg.CORBA.Object target,
         org.omg.CORBA.Environment env,
         Closure closure){
      System.out.println("============>SampleServerInterceptor id "+
            closure.object +" exception_occurred");
   }
}

SampleClientInterceptorは，リクエストを生成するたびに，またはクライアントが応答を受信するたびに起動されます。

ローダはBindInterceptorオブジェクトのロードに責任があります。SampleClientInterceptorLoaderクラスには，bind()メソッドとbind_succeeded()メソッドがあります。これらのメソッドは，オブジェクトのバインド時にBorland Enterprise Server VisiBroker ORBによって起動されます。バインドが成功すると，bind_succeeded()メソッドがORBによって起動され，BindInterceptorオブジェクトを生成し，それをInterceptorManagerに登録することによって，BindInterceptorオブジェクトがインストールされます。

コードサンプル20-11　SampleClientInterceptor.java（Java）

import com.inprise.vbroker.interceptor.*;
import com.inprise.vbroker.IOP.*;
import com.inprise.vbroker.CORBA.portable.*;

public class SampleClientInterceptor implements ClientRequestInterceptor {
   private String _id;
   public SampleClientInterceptor(String id){
      _id =id;
   }
   public void preinvoke_premarshal(org.omg.CORBA.Object target,
         String operation,
         ServiceContextListHolder service_contexts_holder,
         Closure closure){
      // Put the _id of this ClientRequestInterceptor into the
      // closure object
      closure.object =new String(_id);
      System.out.println("============>SampleClientInterceptor id "+
            closure.object +
            "preinvoke_premarshal =>"+operation);
   }
   public void preinvoke_postmarshal(org.omg.CORBA.Object target,
         OutputStream payload,
         Closure closure){
      System.out.println("============>SampleClientInterceptor id "+
         closure.object +"preinvoke_postmarshal");
   }
   public void postinvoke(org.omg.CORBA.Object target,
         ServiceContext [ ] service_contexts,
         InputStream payload,
         org.omg.CORBA.Environment env,
         Closure closure){
      System.out.println("============>SampleClientInterceptor id "+
            closure.object +"postinvoke");
   }
   public void exception_occurred(org.omg.CORBA.Object target,
         org.omg.CORBA.Environment env,
         Closure closure){
      System.out.println("============>SampleClientInterceptor id "+
            closure.object +"exception_occurred");
   }
}

Javaの場合，ローダはBindInterceptorオブジェクトのロードに責任があります。このクラスは，vbroker.orb.dynamicLibsによって動的にBorland Enterprise Server VisiBroker ORBにリンクされます。SampleClientInterceptorLoaderクラスには，bind()メソッドとbind_succeeded()メソッドがあります。これらのメソッドは，オブジェクトのバインド時にORBによって起動されます。バインドが成功すると，bind_succeeded()メソッドがORBによって起動され，BindInterceptorオブジェクトを生成し，それをInterceptorManagerに登録することによって，BindInterceptorオブジェクトがインストールされます。

コードサンプル20-12　SampleClientLoader.java（Java）

import java.util.*;
import com.inprise.vbroker.orb.*;
import com.inprise.vbroker.interceptor.*;
import com.inprise.vbroker.PortableServerExt.*;

public class SampleClientLoader implements ServiceLoader {
   public void init(org.omg.CORBA.ORB orb){
      try {
         InterceptorManagerControl control =
            InterceptorManagerControlHelper.narrow(
               orb.resolve_initial_references("VisiBrokerInterceptorControl"));
         BindInterceptorManager bind_manager =
               (BindInterceptorManager)control.get_manager("Bind");
         bind_manager.add(new SampleBindInterceptor());
      }catch(Exception e){
         e.printStackTrace();
         throw new org.omg.CORBA.INITIALIZE(e.toString());
      }
      System.out.println("Bind Interceptors loaded");
   }
   public void init_complete(org.omg.CORBA.ORB orb){
   }
   public void shutdown(org.omg.CORBA.ORB orb){
   }
}

SampleBindInterceptorは，オブジェクトにバインドしようとするクライアントによって起動されます。ORB初期化後のクライアント側の最初の手順は，AccountManagerオブジェクトにバインドすることです。このバインドによってSampleBindInterceptorを起動し，バインドが成功すると，SampleClientInterceptorがインストールされます。

コードサンプル20-13　SampleBindInterceptor.java（Java）

import com.inprise.vbroker.interceptor.*;
import com.inprise.vbroker.IOP.*;

public class SampleBindInterceptor implements BindInterceptor {
   public IORValue bind(IORValue ior,org.omg.CORBA.Object target,
         boolean rebind,Closure closure){
      //To be a trace!
      System.out.println("============>SampleBindInterceptor bind");
      return null;
   }
   public IORValue bind_failed(IORValue ior,org.omg.CORBA.Object target,
         Closure closure){
      //To be a trace!
      System.out.println("============>SampleBindInterceptor
        bind_failed");
      return null;
   }
   public void bind_succeeded(IORValue ior,org.omg.CORBA.Object target,
         int Index,InterceptorManagerControl control,
         Closure closure){
      //To be a trace!
      System.out.println("============>SampleBindInterceptor
        bind_succeeded");
      //Create the Client Request interceptor:
      SampleClientInterceptor interceptor =
      new SampleClientInterceptor("MyClientInterceptor");
      //Get the manager
      ClientRequestInterceptorManager manager =
            (ClientRequestInterceptorManager)control.
                                     get_manager("ClientRequest");
      //Add CRQ to the list:
      manager.add(interceptor);
   }
   public void exception_occurred(IORValue ior,org.omg.CORBA.Object
      target,
         org.omg.CORBA.Environment env,
         Closure closure){
      //To be a trace!
      System.out.println("============>SampleBindInterceptor
       exception_occurred");
   }
}

20.4　VisiBroker 4.xインタセプタ間での情報の渡し方

Closure（Java）オブジェクトは，インタセプタ呼び出しのシーケンスの始めにORBによって生成されます。同じClosure（Java）オブジェクトがその特定のシーケンスのすべての呼び出しで使用されます。Closure（Java）オブジェクトには，一つのパブリックデータフィールドであるjava.lang.Objectタイプ（Java）のオブジェクトがあり，これは状態情報を保存するためにインタセプタが設定します。

Closureオブジェクトが生成されるシーケンスは，インタセプタ型によって異なります。

ClientRequestInterceptorでは，preinvoke_premarshalの呼び出し前に新しいClosure（Java）が生成され，リクエストの完了が成功してもしなくても，そのリクエストが完了するまで，そのリクエストで同じClosure（Java）が使用されます。ServerInterceptorでも同様に，新しいClosure（Java）はpreinvokeの呼び出し前に生成され，そのClosure（Java）が特定のリクエストの処理に関連するすべてのインタセプタ呼び出しで使用されます。

Closure（Java）の使用方法のサンプルについては，Borland Enterprise Server VisiBrokerインストレーションのexamples/vbe/interceptors/client_serverディレクトリを参照してください。

response_expectedとrequest_idを取得するために，Closure（Java）オブジェクトは次のようにExtendedClosure（Java）にキャストできます。

int my response_expected
   =((ExtendedClosure)closure).reqInfo.response_expected;
int my request_id
   =((ExtendedClosure)closure).reqInfo.request_id;

20.5　ポータブルインタセプタおよびVisiBroker 4.xインタセプタを同時に使用

ポータブルインタセプタおよびVisiBroker 4.xインタセプタはBorland Enterprise Server VisiBroker ORBで同時にインストールできますが，この二つのインタセプタには異なるインプリメンテーションがあるので，両方のインタセプタを使用する際に開発者が理解しておかなければならないフローの規則と制約があります。

20.5.1　インタセプトポイントの呼び出し順

インタセプトポイントの呼び出し順は，開発者が実際に一つ以上のインタセプタのバージョンをインストールするかどうかに関係なく，それぞれのバージョンのインタセプタのインタセプトポイント順序の規則に従います。

20.5.2　クライアント側インタセプタ

クライアント側にポータブルインタセプタおよびVisiBrokerインタセプタの両方がインストールされる場合，例外を発生させるインタセプタがないと想定されるイベント順は次のようになります。

send_request（ポータブルインタセプタ）の次にpreinvoke_premarshal（VisiBroker 4.xインタセプタ）

構成体リクエストメッセージ

preinvoke_postmarshal（VisiBroker 4.xインタセプタ）

送信リクエストメッセージおよび応答待ち

応答のタイプに応じて，postinvoke（VisiBroker 4.xインタセプタ）の次にreceived_reply，receive_exception，またはreceive_other（ポータブルインタセプタ）

20.5.3　サーバ側インタセプタ

サーバ側にポータブルインタセプタおよびVisiBrokerインタセプタの両方がインストールされる場合，例外を発生させるインタセプタがないと想定されるイベント受信順（VisiBrokerの動作と同様，リクエストの探索はインタセプタを起動しない）は次のようになります。

received_request_service_contexts（ポータブルインタセプタ）の次にpreinvoke（VisiBroker 4.xインタセプタ）

servantLocator.preinvoke（サーバントロケータを使用している場合）

receive_request（ポータブルインタセプタ）

サーバントでの起動オペレーション

postinvoke_premarshal（VisiBroker 4.xインタセプタ）

servantLocator.postinvoke（サーバントロケータを使用している場合）

リクエストの結果に応じて，send_reply，send_exception，またはsend_other

postinvoke_postmarshal（VisiBroker 4.xインタセプタ）

20.5.4　POA生成中のORBイベント順

POA生成中のORBイベント順を次に示します。

IORテンプレートはPOAを処理するサーバエンジンのプロファイルに基づいて生成されます。

VisiBroker 4.xインタセプタのPOAライフサイクルインタセプタのcreate()メソッドが呼び出されます。このメソッドは新しいポリシーを追加したり，前述の手順で生成されたIORテンプレートを修正する可能性があります。

ポータブルインタセプタのIORInfoオブジェクトが生成され，IORInterceptorのestablish_components()メソッドが呼び出されます。このインタセプトポイントによって，インタセプタはcreate_POA()に渡されたポリシー，および前述の手順で追加されたポリシーを照会し，このポリシーに基づいてIORテンプレートにコンポーネントを追加できます。

POAのオブジェクトリファレンスファクトリとオブジェクトリファレンステンプレートが生成され，ポータブルインタセプタIORInterceptorのcomponents_established()メソッドが呼び出されます。このインタセプトポイントによって，インタセプタはオブジェクトリファレンスの作成に使用するPOAのオブジェクトリファレンスファクトリを変更できます。

20.5.5　オブジェクトリファレンス生成中のORBイベント順

create_reference()メソッドやcreate_reference_with_id()メソッドのようなオブジェクトリファレンスを生成するPOAの呼び出し中に発生するイベントを次に示します。

オブジェクトリファレンス（これはVisiBroker IOR生成インタセプタを呼び出しません。ファクトリはユーザ提供の場合もあります）を生成するためにオブジェクトリファレンスファクトリのmake_object()メソッドを呼び出します。VisiBroker IOR生成インタセプタがインストールされていなければ，これはアプリケーションに返されるオブジェクトリファレンスであるはずです。インストールされている場合は手順2.に進みます。

返されたオブジェクトリファレンスのデリゲートからIORを抽出し，VisiBroker IOR生成インタセプタのcreate()メソッドを呼び出します。

オブジェクトリファレンスとしてcreate_reference()メソッドおよびcreate_reference_with_id()メソッドの呼び出し元に手順2.のIORが返されます。

21　オブジェクトラッパーの使用

この章では，Borland Enterprise Server VisiBrokerのオブジェクトラッパー機能について説明します。この機能を使うと，ユーザのアプリケーションに通知したり，アプリケーションがオブジェクトのオペレーション要求をトラップしたりできます。

21.1　概要

Borland Enterprise Server VisiBrokerのオブジェクトラッパー機能を使うと，クライアントアプリケーションがバインドされたオブジェクトのメソッドを呼び出すときに呼び出されるメソッドや，サーバアプリケーションがオペレーション要求を受け取ったときに呼び出されるメソッドを，ユーザが定義できるようになります。前に説明したインタセプタ機能（VisiBroker ORBレベルで起動される）とは異なり，オブジェクトラッパーはオペレーション要求がマーシャルされる前に起動されます。実はオペレーション要求がマーシャルされなくても，ネットワークに送られなくても，または本当にオブジェクトインプリメンテーションに提供されなくても，オブジェクトラッパーが結果を返すように設計できます。

オブジェクトラッパーはクライアント側だけ，サーバ側だけ，または一つのアプリケーションにクライアントとサーバの両方が実装されているものにインストールできます。

ユーザのアプリケーション中でのオブジェクトラッパーの使い方の例を次に示します。

クライアントが発行した，またはサーバが受け取ったオペレーション要求に関する情報のログを取得する

オペレーション要求が完了するまでの時間を計る

実際には毎回オブジェクトインプリメンテーションにコンタクトすることなく，頻繁に発行されるオペレーション要求の結果がすばやく返されるように，結果をキャッシュする

注

VisiBroker ORBオブジェクトのobject_to_stringメソッドを使って，オブジェクトラッパーがインストールされているオブジェクトのリファレンスを文字列化しても，文字列化したリファレンスの受信者が異なるプロセスなら，オブジェクトラッパーが伝わることはありません。

21.1.1　タイプドおよびアンタイプドオブジェクトラッパー

Borland Enterprise Server VisiBrokerは，タイプドとアンタイプドの2種類のオブジェクトラッパーを提供します。一つのアプリケーション内で，両方の型のオブジェクトラッパーを混在して使えます。タイプドオブジェクトラッパーの詳細については，「21.4　タイプドオブジェクトラッパー」を参照してください。表21-1に，2種類のオブジェクトラッパーの相違点を示します。

表21‒1　タイプドおよびアンタイプドオブジェクトラッパーの機能の比較

機能

タイプド

アンタイプド

スタブに渡すすべての引数を受信する

○

×

次のオブジェクトラッパー，スタブ，またはオブジェクトインプリメンテーションを実際に起動しないで，発信元に制御を返すことができる

○

×

すべてのオブジェクトのすべてのオペレーション要求で起動する

×

○

（凡例）○：できる　×：できない

21.1.2　idl2cppの前提条件（C++）

タイプドオブジェクトラッパーまたはアンタイプドオブジェクトラッパーを使う場合はいつでも，アプリケーションのコード生成の際に，idl2cppコンパイラに-obj_wrapperオプションを指定しなければなりません。そうすることで次のものが生成されます。

ユーザのインタフェースごとのオブジェクトラッパーベースクラス

21.1.3　idl2javaの前提条件（Java）

タイプドオブジェクトラッパーまたはアンタイプドオブジェクトラッパーを使う場合はいつでも，アプリケーションのコード生成の際に，idl2javaコンパイラに-obj_wrapperオプションを指定しなければなりません。そうすることで次のものが生成されます。

ユーザのインタフェースごとのオブジェクトラッパーベースクラス

Helperクラスにオブジェクトラッパーの追加，削除のためのメソッドを追加

21.1.4　サンプルアプリケーション

VisiBrokerをインストールしたディレクトリのexamples/vbe/interceptors/objectWrappersには，クライアントとサーバのサンプルアプリケーションが三つ入っています。この章では，このサンプルを使って，タイプドオブジェクトラッパーおよびアンタイプドオブジェクトラッパーの概念を説明します。

21.2　アンタイプドオブジェクトラッパー

アンタイプドオブジェクトラッパーを使うと，ユーザは，オペレーション要求が処理される前，あと，または前後両方で呼び出されるメソッドを定義できます。アンタイプドオブジェクトラッパーは，クライアントアプリケーション用またはサーバアプリケーション用にインストールでき，また複数のオブジェクトラッパーをインストールできます。

同じクライアントまたはサーバアプリケーション内で，タイプドとアンタイプドの両方のオブジェクトラッパーを混在して使えます。

デフォルトでは，アンタイプドオブジェクトラッパーはグローバルスコープを持ち，どのようなオペレーション要求に対しても起動されます。関係ないオブジェクトタイプのオペレーション要求については影響を与えないように，アンタイプドオブジェクトラッパーを設計できます。

注

タイプドオブジェクトラッパーとは異なり，アンタイプドオブジェクトラッパーメソッドは，スタブまたはオブジェクトインプリメンテーションが受け取る引数を受け取りません。また，スタブやオブジェクトインプリメンテーションの起動を防ぐこともできません。

図21-1に，クライアントスタブメソッドの前にアンタイプドオブジェクトラッパーのpre_methodがどのように起動されるのか，そのあとpost_methodがどのように起動されるのかを示します。また，オブジェクトインプリメンテーションに関するサーバ側での起動シーケンスも示します。

図21‒1　単一のアンタイプドオブジェクトラッパー

21.2.1　複数のアンタイプドオブジェクトラッパーの使用

複数のアンタイプドオブジェクトラッパーを使用した場合の流れを図21-2に示します。

図21‒2　複数のアンタイプドオブジェクトラッパー

21.2.2　pre_method起動の順序

クライアントがバインドされたオブジェクトに対するメソッドを呼び出す場合，各アンタイプドオブジェクトラッパーpre_methodは，クライアントのスタブルーチンが呼び出される前に制御を受け取ります。サーバがオペレーション要求を受信する場合，各アンタイプドオブジェクトラッパーpre_methodは，オブジェクトインプリメンテーションが制御を受け取る前に起動されます。どちらの場合も，最初に制御を受け取るpre_methodは，「最初に登録された」オブジェクトラッパーに属するpre_methodです。

21.2.3　post_method起動の順序

サーバのオブジェクトインプリメンテーションが処理を終了すると，応答がクライアントに送信される前に各post_methodが起動されます。クライアントがオペレーション要求に対する応答を受信すると，制御がクライアントに返される前に各post_methodが起動されます。どちらの場合も，最初に制御を受け取るpost_methodは，「最後に登録された」オブジェクトラッパーに属するpost_methodです。

注

タイプドオブジェクトラッパーおよびアンタイプドオブジェクトラッパーの両方を使うことを選択した場合，起動順序については「21.6　タイプドおよびアンタイプドオブジェクトラッパーの混在使用」を参照してください。

21.3　アンタイプドオブジェクトラッパーの使用

アンタイプドオブジェクトラッパーを使う際は次の手順に従ってください。各手順については以降で順に説明します。

アンタイプドオブジェクトラッパーを生成したい，一つまたは複数のインタフェースを指定してください。

次のコンパイラに-obj_wrapperオプションを指定して，IDL指定からコードを生成してください。

C++の場合

idl2cpp

Javaの場合

idl2java

次のクラスから派生する，アンタイプドオブジェクトラッパーファクトリのインプリメンテーションを生成してください。

C++の場合

VISObjectWrapper::UntypedObjectWrapperFactory

Javaの場合

UntypedObjectWrapperFactory

クラスから派生する，アンタイプドオブジェクトラッパーのインプリメンテーションを生成してください。

C++の場合

VISObjectWrapper::UntypedObjectWrapper

Javaの場合

UntypedObjectWrapper

Javaの場合，クライアントまたはサーバアプリケーションを変更して，適切な型のChainUntypedObjectWrapperFactoryにアクセスしてください。

アプリケーションを変更して，アンタイプドオブジェクトラッパーファクトリを生成してください。

Javaの場合，ChainUntypedObjectWrapperFactoryのaddメソッドを使って，ファクトリをチェーンに加えてください。

21.3.1　アンタイプドオブジェクトラッパーファクトリのインプリメント

C++の場合

objectWrappersサンプルアプリケーションの一部であるTimeWrap.hファイルは，VISObjectWrapper::UntypedObjectWrapperFactoryから派生したアンタイプドオブジェクトラッパーファクトリの定義方法を示します。

コードサンプル21-1に，TimingObjectWrapperFactoryを示します。これはメソッド呼び出しのタイミング情報を表示するアンタイプドオブジェクトラッパーを生成するために使用します。keyパラメタをTimingObjectWrapperFactoryコンストラクタに追加することに注意してください。また，このパラメタはオブジェクトラッパーを識別するためにサービスイニシャライザが使用します。

コードサンプル21-1　TimeWrap.hファイルから派生するTimingObjectWrapperFactoryインプリメンテーション（C++）

class TimingObjectWrapperFactory
   : public VISObjectWrapper::UntypedObjectWrapperFactory
{
   public:
      TimingObjectWrapperFactory(VISObjectWrapper::
            Location loc, const char* key)
         : VISObjectWrapper::
            UntypedObjectWrapperFactory(loc), _key(key) {}

      // ObjectWrapperFactory operations
      VISObjectWrapper::UntypedObjectWrapper_ptr create (
               CORBA::Object_ptr target,
               VISObjectWrapper::Location loc) {
         if (_owrap == NULL) {
               _owrap = new TimingObjectWrapper(_key);
         }
         return VISObjectWrapper::UntypedObjectWrapper::
               _duplicate(_owrap);
   }

   private:
      CORBA::String_var _key;
      VISObjectWrapper::UntypedObjectWrapper_var _owrap;
};

Javaの場合

objectWrappersサンプルアプリケーションの一部であるTimingUntypedObjectWrapperFactoryのインプリメンテーションは，UntypedObjectWrapperFactoryから派生したアンタイプドオブジェクトラッパーファクトリの定義方法を示します。

クライアントがオブジェクトにバインドする際，またはサーバがオブジェクトインプリメンテーションでメソッドを起動する際はいつも，ユーザのファクトリのcreateメソッドが呼び出され，アンタイプドオブジェクトラッパーを生成します。createメソッドは目的のオブジェクトを受け取ります。つまりユーザは，無視したいオブジェクトタイプについて，ファクトリがアンタイプドオブジェクトラッパーを作らないようにファクトリを設計できます。また，生成されたオブジェクトラッパーがサーバ側オブジェクトインプリメンテーションなのか，クライアント側オブジェクトなのかを指定するenumも受け取ります。

コードサンプル21-2に，TimingObjectWrapperFactoryを示します。これはメソッド呼び出しのタイミング情報を表示するアンタイプドオブジェクトラッパーを生成するために使用されます。

コードサンプル21-2　TimingUntypedObjectWrapperFactoryインプリメンテーション

package UtilityObjectWrappers;
import com.inprise.vbroker.interceptor.*;

public class TimingUntypedObjectWrapperFactory implements
      UntypedObjectWrapperFactory {
   public UntypedObjectWrapper create(
         org.omg.CORBA.Object target,
         com.inprise.vbroker.interceptor.Location loc) {
      return new TimingUntypedObjectWrapper();
   }
}

21.3.2　アンタイプドオブジェクトラッパーのインプリメント

(1)　C++の場合

コードサンプル21-3に，TimeWrap.hファイルに定義されたTimingUntypedObjectWrapperのインプリメンテーションを示します。アンタイプドオブジェクトラッパーはVISObjectWrapper::UntypedObjectWrapperクラスから派生していなければなりません。ユーザはアンタイプドオブジェクトラッパー中のpre_methodとpost_methodの両メソッドのインプリメンテーションを提供できます。

ファクトリがインストールされたら，ファクトリのコンストラクタによって自動的にまたはVISObjectWrapper::ChainUntypedObjectWrapperFactory::createメソッドの起動によって手動で，クライアントがオブジェクトにバインドする際，またはサーバがオブジェクトインプリメンテーションでメソッドを起動する際に，アンタイプドオブジェクトラッパーオブジェクトが自動的に生成されます。

コードサンプル21-3に示すpre_methodは，TimeWrap.Cで定義されたTimerBeginメソッドを起動します。このメソッドは，現在の時間を取得するためにClosureオブジェクトを使用します。同様に，post_methodはTimerDeltaメソッドを起動し，pre_methodが呼び出されてからどれくらい時間がたったかを調べ，経過時間を出力します。

コードサンプル21-3　TimingUntypedObjectWrapperインプリメンテーション（C++）

class TimingObjectWrapper : public VISObjectWrapper::
      UntypedObjectWrapper {
   public:
      TimingObjectWrapper(
            const char* key=NULL) : _key(key) {}

      void pre_method(const char* operation,
            CORBA::Object_ptr target,
            VISClosure& closure) {
         cout << "*Timing: [" << flush;
         if ((char *)_key)
            cout << _key << flush;
         else
            cout << "<no key>" << flush;
         cout << "] pre_method¥t" << operation << "¥t->"
            << endl;
         TimerBegin(closure, operation);
      }

      void post_method(const char* operation,
            CORBA::Object_ptr target,
            CORBA::Environment& env,
            VISClosure& closure) {
         cout << "*Timing: [" << flush;
         if ((char *)_key)
            cout << _key << flush;
         else
            cout << "<no key>" << flush;
         cout << "] post_method¥t" ;
         TimerDelta(closure, operation);
      }
   private:
      CORBA::String_var _key;
};

(2)　Javaの場合

コードサンプル21-4に，TimingUntypedObjectWrapperのインプリメンテーションを示します。アンタイプドオブジェクトラッパーはUntypedObjectWrapperクラスから派生していなければなりません。ユーザはアンタイプドオブジェクトラッパー中のpre_methodとpost_methodの両メソッドのインプリメンテーションを提供できます。

ファクトリがインストールされたら，ファクトリのコンストラクタによって自動的にまたはChainUntypedObjectWrapperFactory::addメソッドの起動によって手動で，クライアントがオブジェクトにバインドする際，またはサーバがオブジェクトインプリメンテーションでメソッドを起動する際に，アンタイプドオブジェクトラッパーオブジェクトが自動的に生成されます。

コードサンプル21-4に示すpre_methodは，現在の時間を取得し，それをプライベート変数に保存し，メッセージを出力します。同様に，post_methodも現在の時間を取得し，pre_methodが呼び出されてからどれくらい時間がたったかを調べ，経過時間を出力します。

コードサンプル21-4　TimingUntypedObjectWrapperインプリメンテーション（Java）

package UtilityObjectWrappers;
import com.inprise.vbroker.interceptor.*;

public class TimingUntypedObjectWrapper implements
                                     UntypedObjectWrapper {
   private long time;
   public void pre_method(String operation,
         org.omg.CORBA.Object target,
         Closure closure) {
      System.out.println("Timing: " +
               ((com.inprise.vbroker.CORBA.Object) target).
               _object_name() + "->" + operation + "()");
      time = System.currentTimeMillis();
   }
   public void post_method(String operation,
         org.omg.CORBA.Object target,
         org.omg.CORBA.Environment env,
         Closure closure) {
      long diff = System.currentTimeMillis() - time;
      System.out.println("Timing: Time for call ¥t" +
         ((com.inprise.vbroker.CORBA.Object)target).
          _object_name() + "->" + operation + "() = " +
          diff + " ms.");
   }
}

(3)　pre_methodおよびpost_methodパラメタ

pre_methodとpost_methodは表21-2のパラメタを受け取ります。

表21‒2　pre_methodおよびpost_methodメソッドの共通引数

パラメタ

説明

operation

目的のオブジェクトでリクエストしたオペレーションの名前

target

目的のオブジェクト

closure

このオブジェクトラッパーのメソッド呼び出し用にデータを保存する領域

post_methodはEnvironmentパラメタも受け取ります。Environmentパラメタは，メソッド呼び出しの前の手順で起こる可能性のある例外をユーザに通知する際に使えます。

21.3.3　アンタイプドオブジェクトラッパーファクトリの生成と登録

C++の場合

アンタイプドオブジェクトラッパーファクトリは，ロケーションを受け付けるbaseクラスコンストラクタで生成される場合，アンタイプドオブジェクトラッパーのチェーンに自動的に追加されます。

クライアント側では，オブジェクトがバインドされる前にアンタイプドオブジェクトラッパーファクトリが生成，登録される場合だけ，オブジェクトがラッピングされます。サーバ側では，オブジェクトインプリメンテーションが呼び出される前にアンタイプドオブジェクトラッパーファクトリが生成，登録されます。

コードサンプル21-5に，クライアント用の二つのアンタイプドオブジェクトラッパーファクトリの生成と自動登録を示したUntypedClient.Cサンプルファイルの一部を示します。ファクトリはVisiBroker ORBが初期化されたあと，かつクライアントがオブジェクトにバインドする前に生成されます。

コードサンプル21-5　二つのクライアント側アンタイプドオブジェクトラッパーファクトリの生成と登録（C++）

int main(int argc, char* const* argv) {
   try {
         // Initialize the ORB.
         CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
         // Install untyped object wrappers
         TimingObjectWrapperFactory timingfact(
               VISObjectWrapper::Client, "timeclient");
         TraceObjectWrapperFactory tracingfact(
               VISObjectWrapper::Client, "traceclient");
         // Now locate an account manager.
. . .

Javaの場合

コードサンプル21-6に，クライアント用の二つのアンタイプドオブジェクトラッパーファクトリの生成とインストールを示したUntypedClient.javaサンプルファイルの一部を示します。ファクトリはVisiBroker ORBが初期化されたあと，ただしクライアントがオブジェクトにバインドする前に生成されます。

コードサンプル21-6　二つのクライアント側アンタイプドオブジェクトラッパーファクトリのインストール（Java）

// UntypedClient.java
import com.inprise.vbroker.interceptor.*;

public class UntypedClient {
   public static void main(String[ ] args) throws Exception {
      // Initialize the ORB.
      org.omg.CORBA.ORB orb =
                           org.omg.CORBA.ORB.init(args,null);
      doMain (orb, args);
   }
   public static void doMain(org.omg.CORBA.ORB orb,
                            String[ ] args) throws Exception {
      ChainUntypedObjectWrapperFactory Cfactory =
            ChainUntypedObjectWrapperFactoryHelper.narrow(
               orb.resolve_initial_references(
               "ChainUntypedObjectWrapperFactory")
            );
      Cfactory.add(new UtilityObjectWrappers.
            TimingUntypedObjectWrapperFactory(),
            Location.CLIENT);
      Cfactory.add(new UtilityObjectWrappers.
            TracingUntypedObjectWrapperFactory(),
            Location.CLIENT);
      // Locate an account manager. . . .
   }
}

C++の場合

コードサンプル21-7にUntypedServer.Cサンプルファイルを示します。このファイルはサーバ用のアンタイプドオブジェクトラッパーファクトリの生成と登録を示しています。ファクトリはVisiBroker ORBが初期化されたあと，ただしオブジェクトインプリメンテーションが生成される前に生成されます。

コードサンプル21-7　サーバ側アンタイプドオブジェクトラッパーファクトリの登録（C++）

// UntypedServer.C
#include "Bank_s.hh"
#include "BankImpl.h"
#include "TimeWrap.h"
#include "TraceWrap.h"
USE_STD_NS
int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
      // Initialize the POA.
      CORBA::Object_var obj =
            orb->resolve_initial_references("RootPOA");
      PortableServer::POA_var rootPoa =
            PortableServer::POA::_narrow(obj);
      CORBA::PolicyList policies;
      policies.length(1);
      policies[(CORBA::ULong)0] =
            rootPoa->create_lifespan_policy(
            PortableServer::PERSISTENT);
      // Get the POA Manager.
      PortableServer::POAManager_var poa_manager =
            rootPoa->the_POAManager();
      // Create myPOA With the Right Policies.
      PortableServer::POA_var myPOA =
            rootPoa->create_POA("bank_ow_poa",
            poa_manager,
            policies);
      // Install Untyped Object Wrappers for Account Manager.
      TimingObjectWrapperFactory timingfact(
           VISObjectWrapper::Server, "timingserver");
      TraceObjectWrapperFactory tracingfact(
           VISObjectWrapper::Server, "traceserver");
      // Create the Account Manager Servant.
      AccountManagerImpl managerServant;
      // Decide on ID for Servant.
      PortableServer::ObjectId_var managerId =
      PortableServer::string_to_ObjectId("BankManager");
      // Activate the Servant with the ID on myPOA.
      myPOA->activate_object_with_id(
            managerId, &managerServant);
      // Activate the POA Manager.
      rootPoa->the_POAManager()->activate();
      cout << "Manager is ready." << endl;
      // Wait for Incoming Requests.
      orb->run();
   } catch(const CORBA::Exception& e) {
      cerr << e << endl;
      return 1;
   }
   return 0;
}

Javaの場合

コードサンプル21-8にUntypedServer.javaサンプルファイルを示します。このファイルはサーバ用のアンタイプドオブジェクトラッパーファクトリの生成と登録を示しています。ファクトリはVisiBroker ORBが初期化されたあと，ただしオブジェクトインプリメンテーションが生成される前に生成されます。

コードサンプル21-8　サーバ側アンタイプドオブジェクトラッパーファクトリのインストール（Java）

// UntypedServer.java
import com.inprise.vbroker.interceptor.*;
import org.omg.PortableServer.*;
import com.inprise.vbroker.PortableServerExt.
                                BindSupportPolicyValue;
import com.inprise.vbroker.PortableServerExt.
                                BindSupportPolicyValueHelper;
import com.inprise.vbroker.PortableServerExt.
                                BIND_SUPPORT_POLICY_TYPE;

public class UntypedServer {
   public static void main(String[ ] args) throws Exception {
      // Initialize the ORB.
      org.omg.CORBA.ORB orb =
                           org.omg.CORBA.ORB.init(args,null);
      ChainUntypedObjectWrapperFactory Sfactory =
            ChainUntypedObjectWrapperFactoryHelper.narrow
            (orb.resolve_initial_references(
            "ChainUntypedObjectWrapperFactory"));
      Sfactory.add(new UtilityObjectWrappers.
            TracingUntypedObjectWrapperFactory(),
            Location.SERVER);
      // get a reference to the rootPOA
      POA rootPOA = POAHelper.
           narrow(orb.resolve_initial_references("RootPOA"));
      // Create a BindSupport Policy that makes POA register
      // each servant with osagent
      org.omg.CORBA.Any any = orb.create_any();
      BindSupportPolicyValueHelper.insert(any,
         BindSupportPolicyValue.BY_INSTANCE);
      org.omg.CORBA.Policy bsPolicy =
         orb.create_policy(BIND_SUPPORT_POLICY_TYPE.value,
                           any);
      // Create policies for our testPOA
      org.omg.CORBA.Policy[ ] policies = {
         rootPOA.create_lifespan_policy
            (LifespanPolicyValue.PERSISTENT), bsPolicy
      };
      // Create myPOA with the right policies
      POA myPOA = rootPOA.create_POA( "bank_agent_poa",
         rootPOA.the_POAManager(),
         policies );

      // Create the account manager object.
      AccountManagerImpl managerServant =
                                    new AccountManagerImpl();
      // Decide on the ID for the servant
      byte[ ] managerId = "BankManager".getBytes();
      // Activate the servant with the ID on myPOA
      myPOA.activate_object_with_id(managerId,
                                    managerServant);
      // Activate the POA manager
      rootPOA.the_POAManager().activate();
      System.out.println(
                     "AccountManager: BankManager is ready.");
      for( int i = 0; i < args.length; i++ ) {
         if( args[i].equalsIgnoreCase("-runCoLocated") ) {
            if( args[i+1].equalsIgnoreCase("Client") ) {
               Client.doMain(orb, new String[0]);
            }else if( args[i+1].
                           equalsIgnoreCase("TypedClient") ) {
               TypedClient.doMain(orb, new String[0]);
            }
            if( args[i+1].equalsIgnoreCase("UntypedClient") ) {
               UntypedClient.doMain(orb, new String[0]);
            }
            System.exit(1);
         }
      }
      // Wait for incoming requests
      orb.run();
   }
}

21.3.4　アンタイプドオブジェクトラッパーの削除

VISObjectWrapper::ChainUntypedObjectWrapperFactoryクラスのremoveメソッド（C++）またはChainUntypedObjectWrapperFactoryクラスのremoveメソッド（Java）を使って，クライアントまたはサーバアプリケーションからアンタイプドオブジェクトラッパーファクトリを削除できます。ファクトリを削除する場合は，ロケーションを指定しなければなりません。これは，VISObjectWrapper::Both（C++）またはBoth（Java）のロケーションでファクトリを追加した場合に，Clientロケーション，Serverロケーション，または両方のロケーションからファクトリを削除することを選べるということです。

注

クライアントから一つまたは複数のオブジェクトラッパーファクトリを削除しても，クライアントがすでにバインドしたクラスのオブジェクトは影響を受けません。あとでバインドされるオブジェクトだけが影響を受けます。サーバからオブジェクトラッパーファクトリを削除しても，すでに生成されたオブジェクトインプリメンテーションは影響を受けません。あとで生成されるオブジェクトインプリメンテーションだけが影響を受けます。

21.4　タイプドオブジェクトラッパー

ある特定のクラスのタイプドオブジェクトラッパーをインプリメントする際，バインドされたオブジェクトでメソッドが呼び出されるときに起こる処理を定義してください。図21-3にクライアントスタブクラスメソッドの前にクライアントのオブジェクトラッパーメソッドがどのように呼び出されるのか，またサーバのインプリメンテーションメソッドの前にサーバ側のオブジェクトラッパーがどのように起動されるのかを示します。

注

タイプドオブジェクトラッパーインプリメンテーションは，ラップするオブジェクトが提供するメソッドすべてをインプリメントする必要はありません。

同じクライアントまたはサーバアプリケーション内で，タイプドオブジェクトラッパーおよびアンタイプドオブジェクトラッパーの両方を混在させて使用できます。詳細については，「21.6　タイプドおよびアンタイプドオブジェクトラッパーの混在使用」を参照してください。

図21‒3　登録された単一のタイプドオブジェクトラッパー

21.4.1　複数のタイプドオブジェクトラッパーの使用

図21-4に示すように，ある特定のクラスのオブジェクトについて複数のタイプドオブジェクトラッパーをインプリメントし登録する場合があるでしょう。クライアント側では，最初に登録されたオブジェクトラッパーはclient_wrapper_1だったので，そのメソッドが最初に制御を受け取ります。処理を終えたあと，client_wrapper_1メソッドはチェーンの中にある次のオブジェクトのメソッドに制御を渡すか，クライアントに制御を返します。サーバ側では，最初に登録されたオブジェクトラッパーはserver_wrapper_1だったので，そのメソッドが最初に制御を受け取ります。処理を終えたあと，server_wrapper_1メソッドはチェーンの中にある次のオブジェクトのメソッドに制御を渡すか，サーバントに制御を返します。

図21‒4　登録された複数のタイプドオブジェクトラッパー

21.4.2　起動の順序

ある特定のクラス用に登録されたタイプドオブジェクトラッパーのメソッドは，通常，クライアント側のスタブメソッドに渡されるか，サーバ側のサーバントに渡される引数すべてを受け取ります。各オブジェクトラッパーメソッドは，親クラスのメソッド<interface_name>ObjectWrapper::<method_name>（C++）またはsuper.<method_name>（Java）を起動して，チェーンの中にある次のオブジェクトラッパーメソッドに制御を渡します。オブジェクトラッパーがチェーンの中にある次のオブジェクトラッパーメソッドを呼び出さないで制御を返したい場合は，適切なリターン値とともに返されます。

タイプドオブジェクトラッパーメソッドがチェーンの中にある前のメソッドに制御を返せることで，ユーザはクライアントスタブやオブジェクトインプリメンテーションを起動しないオブジェクトラッパーメソッドを作れます。例えば，頻繁に要求されるオペレーションの結果をキャッシュするオブジェクトラッパーメソッドを作れます。この場合，バインドされたオブジェクトに対するメソッドの最初の呼び出しによって，オペレーション要求がオブジェクトインプリメンテーションに送信されます。制御がオブジェクトラッパーメソッドによって戻る場合，結果は保存されます。同じメソッドの後続の呼び出しでは，オブジェクトラッパーメソッドは，オブジェクトインプリメンテーションにオペレーション要求を実際には発行しないで，キャッシュされた結果を返せます。

タイプドオブジェクトラッパーとアンタイプドオブジェクトラッパーの両方を使う選択をした場合，起動順序については「21.6　タイプドおよびアンタイプドオブジェクトラッパーの混在使用」を参照してください。

21.4.3　タイプドオブジェクトラッパーおよび同一プロセスにあるクライアントとサーバ

クライアントとサーバが同じプロセス中にパッケージされている場合，最初に制御を受け取るオブジェクトラッパーメソッドは，最初にインストールされたクライアント側オブジェクトラッパーに属します。図21-5に起動順序を示します。

図21‒5　タイプドオブジェクトラッパーの起動順序

21.5　タイプドオブジェクトラッパーの使用

タイプドオブジェクトラッパーを使う場合は次の手順に従ってください。各手順については以降で順に説明します。

タイプドオブジェクトラッパーを生成したい，一つまたは複数のインタフェースを指定してください。

次のコンパイラに-obj_wrapperオプションを指定して，IDLからコードを生成してください。

C++の場合

idl2cpp

Javaの場合

idl2java

タイプドオブジェクトラッパークラスを，idl2cppコンパイラ（C++）またはidl2javaコンパイラ（Java）で生成した<interface_name>ObjectWrapperクラスから派生させ，ラッピングしたいメソッドのインプリメンテーションを作成してください。

アプリケーションを変更して，タイプドオブジェクトラッパーを登録してください。

21.5.1　タイプドオブジェクトラッパーのインプリメント

タイプドオブジェクトラッパーを，idl2cppコンパイラ（C++）またはidl2javaコンパイラ（Java）で生成した<interface_name>ObjectWrapperクラスから派生させてください。コードサンプル21-10にAccountインタフェース用タイプドオブジェクトラッパーのインプリメンテーション（Java）を示します。このクラスはAccountObjectWrapperインタフェースから派生していて，balanceメソッドの単純なキャッシングインプリメンテーションを提供していることに注意してください。balanceメソッドは次のような手順で処理を実行します。

次のフラグをチェックし，このメソッドが以前に呼び出されたことがあるかどうかを調べます。

C++の場合

_inited

Javaの場合

_initialized

今回が最初の呼び出しの場合，チェーンの中にある次のオブジェクトでbalanceメソッドを呼び出し，結果を_balanceに保存し，_inited（C++）または_initialized（Java）をtrueに設定し，値を返します。

このメソッドがすでに呼び出されたことがある場合，キャッシュされた値を返します。

コードサンプル21-9　CachingAccountObjectWrapperインプリメンテーションの一部（C++）

class CachingAccountObjectWrapper : public Bank::
      AccountObjectWrapper {
   public:
      CachingAccountObjectWrapper() :
            _inited((CORBA::Boolean)0) {}
      CORBA::Float balance() {
         cout << "+CachingAccountObjectWrapper:
               Before Calling Balance" << endl;
      if (! _inited) {
         _balance = Bank::AccountObjectWrapper::balance();
         _inited = 1;
      } else {
         cout << "+ CachingAccountObjectWrapper:
               Returning Cached Value" << endl;
      }
      cout << "+ CachingAccountObjectWrapper:
            After Calling Balance" << endl;
      return _balance;
   }
   . . .
};

コードサンプル21-10　CachingAccountObjectWrapperインプリメンテーションの一部（Java）

package BankWrappers;
public class CachingAccountObjectWrapper extends
                                  Bank.AccountObjectWrapper {
   private boolean _initialized = false;
   private float _balance;
   public float balance() {
      System.out.println(
      "+ CachingAccountObjectWrapper: Before calling balance: ");
      try {
         if( !_initialized ) {
            _balance = super.balance();
            _initialized = true;
         } else {
          System.out.println(
          "+ CachingAccountObjectWrapper: Returning Cached value");
         }
         return _balance;
      }finally {
       System.out.println(
       "+ CachingAccountObjectWrapper: After calling balance: ");
      }
   }
}

21.5.2　クライアント用タイプドオブジェクトラッパーの登録

C++の場合

タイプドオブジェクトラッパーは，idl2cppコンパイラがクラス中に生成した<interface_name>::addメソッドを起動して，クライアント側に登録されます。クライアント側オブジェクトラッパーはORB_initメソッドが呼び出されたあと，ただしオブジェクトがバインドされる前に登録しなければなりません。コードサンプル21-11に，タイプドオブジェクトラッパーを生成，登録するTypedClient.Cファイルの一部を示します。

コードサンプル21-11　クライアント側タイプドオブジェクトラッパーの生成と登録（C++）

. . .
int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

      //Install Typed Object Wrappers for Account.
      Bank::AccountObjectWrapper::add(orb,
            CachingAccountObjectWrapper::factory,
            VISObjectWrapper::Client);

      // Get the Manager ID.
      PortableServer::ObjectId_var managerId =
            PortableServer::string_to_ObjectId("BankManager");

      // Locate an Account Manager.
      Bank::AccountManager_var manager =
            Bank::AccountManager::_bind(
                  "/bank_ow_poa", managerId);
. . .

Javaの場合

タイプドオブジェクトラッパーは，idl2javaコンパイラがHelperクラス中に生成したaddClientObjectWrapperClassメソッドを起動して，クライアント側に登録されます。クライアント側オブジェクトラッパーはORB.initメソッドが呼び出されたあと，ただしオブジェクトがバインドされる前に登録しなければなりません。コードサンプル21-12に，タイプドオブジェクトラッパーを生成，登録するTypedClient.javaファイルの一部を示します。

コードサンプル21-12　クライアント側タイプドオブジェクトラッパーのインストール（Java）

// TypedClient.java
import com.inprise.vbroker.interceptor.*;
public class TypedClient {
   public static void main(String[ ] args) throws Exception {
      // Initialize the ORB.
      org.omg.CORBA.ORB orb =
                           org.omg.CORBA.ORB.init(args,null);
      doMain (orb, args);
   }
   public static void doMain(org.omg.CORBA.ORB orb,
                                             String[ ] args) {
      // Add a typed object wrapper for Account objects
      Bank.AccountHelper.addClientObjectWrapperClass(orb,
         BankWrappers.CachingAccountObjectWrapper.class);
      // Locate an account manager.
      Bank.AccountManager manager =
          Bank.AccountManagerHelper.bind(orb, "BankManager");
      . . .
   }
}

VisiBroker ORBは，クライアント側でこのクラスのために登録されたすべてのオブジェクトラッパーの動作の記録を採っています。クライアントが_bindメソッドを起動して，その型のオブジェクトにバインドしようとすると，必要なオブジェクトラッパーが生成されます。クライアントが特定のクラスのオブジェクトの複数のインスタンスにバインドする場合，各インスタンスは，それぞれ専用のオブジェクトラッパーのセットを持ちます。

21.5.3　サーバ用タイプドオブジェクトラッパーの登録

C++の場合

クライアントアプリケーションと同様，タイプドオブジェクトラッパーをサーバ側に登録するには，<interface_name>::addメソッドを呼び出します。サーバ側タイプドオブジェクトラッパーはORB_initメソッドが呼び出されたあと，ただしオブジェクトインプリメンテーションがリクエストを処理する前に登録されなければなりません。コードサンプル21-13にタイプドオブジェクトラッパーを登録するTypedServer.Cファイルの部分を示します。

コードサンプル21-13　サーバ側タイプドオブジェクトラッパーの登録（C++）

// TypedServer.C
#include "Bank_s.hh"
#include "BankImpl.h"
#include "BankWrap.h"
USE_STD_NS
int main(int argc, char* const* argv) {
   try {
      // Initialize the ORB.
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
      // Initialize the POA.
      CORBA::Object_var obj =
            orb->resolve_initial_references("RootPOA");
      PortableServer::POA_var rootPoa =
            PortableServer::POA::_narrow(obj);
      CORBA::PolicyList policies;
      policies.length(1);
      policies[(CORBA::ULong)0] =
           rootPoa->create_lifespan_policy(
           PortableServer::PERSISTENT);
      // Get the POA Manager.
      PortableServer::POAManager_var poa_manager =
           rootPoa->the_POAManager();
      // Create myPOA With the Right Policies.
      PortableServer::POA_var myPOA = rootPoa->create_POA(
                 "bank_ow_poa",
            poa_manager,
            policies);
      // Install Typed Object Wrappers for Account Manager.
      Bank::AccountManagerObjectWrapper::add(orb,
            SecureAccountManagerObjectWrapper::factory,
            VISObjectWrapper::Server);
      Bank::AccountManagerObjectWrapper::add(orb,
            CachingAccountManagerObjectWrapper::factory,
                  VISObjectWrapper::Server);
      // Create the Account Manager Servant.
      AccountManagerImpl managerServant;
      // Decide on ID for Servant.
      PortableServer::ObjectId_var managerId =
            PortableServer::string_to_ObjectId("BankManager");
      // Activate the Servant with the ID on myPOA.
      myPOA->activate_object_with_id(
            managerId, &managerServant);
      // Activate the POA Manager.
      rootPoa->the_POAManager()->activate();
      cout << "Manager is ready." << endl;
      // Wait for Incoming Requests.
      orb->run();
   } catch(const CORBA::Exception& e) {
      cerr << e << endl;
      return 1;
   }
   return 0;
}

Javaの場合

クライアントアプリケーションと同様，タイプドオブジェクトラッパーをサーバ側に登録するには，Helperクラスが提供するaddServerObjectWrapperClassメソッドを呼び出します。サーバ側タイプドオブジェクトラッパーはORB.initメソッドが呼び出されたあと，ただしオブジェクトインプリメンテーションがリクエストを処理する前に登録されなければなりません。コードサンプル21-14にタイプドオブジェクトラッパーを登録するTypedServer.javaファイルの部分を示します。

コードサンプル21-14　サーバ側タイプドオブジェクトラッパーのインストール（Java）

// TypedServer.java
import org.omg.PortableServer.*;
import com.inprise.vbroker.PortableServerExt.
                                BindSupportPolicyValue;
import com.inprise.vbroker.PortableServerExt.
                                BindSupportPolicyValueHelper;
import com.inprise.vbroker.PortableServerExt.
                                BIND_SUPPORT_POLICY_TYPE;

public class TypedServer {
   public static void main(String[ ] args) throws Exception {
      // Initialize the ORB.
      org.omg.CORBA.ORB orb =
                           org.omg.CORBA.ORB.init(args,null);
      // Add two typed object wrappers for AccountManager
      // objects
      Bank.AccountManagerHelper.addServerObjectWrapperClass
       (orb, BankWrappers.SecureAccountManagerObjectWrapper.
        class);
      Bank.AccountManagerHelper.addServerObjectWrapperClass
       (orb, BankWrappers.CachingAccountManagerObjectWrapper.
        class);
      // get a reference to the rootPOA
      POA rootPOA = POAHelper.narrow
                 (orb.resolve_initial_references("RootPOA"));
      // Create a BindSupport Policy that makes POA register
      // each servant with osagent
      org.omg.CORBA.Any any = orb.create_any();
      BindSupportPolicyValueHelper.insert(any,
                         BindSupportPolicyValue.BY_INSTANCE);
      org.omg.CORBA.Policy bsPolicy =
         orb.create_policy(BIND_SUPPORT_POLICY_TYPE.value,
                           any);
      // Create policies for our testPOA
      org.omg.CORBA.Policy[ ] policies = {
         rootPOA.create_lifespan_policy(LifespanPolicyValue.
         PERSISTENT), bsPolicy
      };
      // Create myPOA with the right policies
      POA myPOA = rootPOA.create_POA("lilo",
                         rootPOA.the_POAManager(), policies);
      // Create the account manager object.
      AccountManagerImpl managerServant =
                                    new AccountManagerImpl();
      // Decide on the ID for the servant
      byte[ ] managerId = "BankManager".getBytes();
      // Activate the servant with the ID on myPOA
      myPOA.activate_object_with_id(managerId, managerServant);
      // Activate the POA manager
      rootPOA.the_POAManager().activate();
      System.out.println(
                    "AccountManager: BankManager is ready.");
      for( int i = 0; i < args.length; i++ ) {
         if ( args[i].equalsIgnoreCase("-runCoLocated") ) {
            if( args[i+1].equalsIgnoreCase("Client") ) {
               Client.doMain(orb, new String[0]);
            } else if( args[i+1].
                           equalsIgnoreCase("TypedClient") ) {
               TypedClient.doMain(orb, new String[0]);
            }
            if( args[i+1].equalsIgnoreCase("UntypedClient") ) {
               UntypedClient.doMain(orb, new String[0]);
            }
            System.exit(1);
         }
      }
      // Wait for incoming requests
      orb.run();
   }
}

サーバが，ある特定のクラスのオブジェクトのインスタンスを複数生成する場合，各インスタンス用にオブジェクトラッパーのセットが生成されます。

21.5.4　タイプドオブジェクトラッパーの削除

C++の場合

idl2cppコンパイラがクラス用に生成する<interface_name>ObjectWrapper::removeメソッドは，クライアントまたはサーバアプリケーションからタイプドオブジェクトラッパーを削除できるようにします。ファクトリを削除する場合はロケーションを指定しなければなりません。これは，ロケーションがVISObjectWrapper::Bothのファクトリを追加したら，クライアントロケーション，サーバロケーション，またはその両方からそのファクトリを削除することを選択できるということです。

Javaの場合

Helperクラスは，クライアントまたはサーバアプリケーションからタイプドオブジェクトラッパーを削除するメソッドも提供します。詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「オブジェクトラッパー用に生成されるメソッド」の記述を参照してください。

注

クライアントから一つまたは複数のオブジェクトラッパーを削除しても，クライアントがすでにバインドしたクラスのオブジェクトは影響を受けません。あとでバインドされるオブジェクトだけが影響を受けます。サーバからオブジェクトラッパーを削除しても，すでにリクエストを処理したオブジェクトインプリメンテーションは影響を受けません。あとで生成されるオブジェクトインプリメンテーションだけが影響を受けます。

21.6　タイプドおよびアンタイプドオブジェクトラッパーの混在使用

アプリケーション中でタイプドオブジェクトラッパーとアンタイプドオブジェクトラッパーの両方を使うことを選択した場合，アンタイプドオブジェクトラッパー用に定義されたpre_methodメソッドはすべて，オブジェクトのために定義されたあらゆるタイプドオブジェクトラッパーメソッドの前に呼び出されます。オブジェクトのために定義されたタイプドオブジェクトラッパーメソッドはすべて，アンタイプドオブジェクトラッパー用に定義されたあらゆるpost_methodメソッドの前に呼び出されます。

サンプルアプリケーションのClient.CとServer.C（C++）またはClient.javaとServer.java（Java）は，タイプドオブジェクトラッパーとアンタイプドオブジェクトラッパーのどちらを使用するかを指定するコマンドラインプロパティを使えるようになっています。

21.6.1　タイプドオブジェクトラッパーのコマンドライン引数

C++の場合

表21-3に，Client.CおよびServer.CでインプリメントされたBankアプリケーションのサンプルでタイプドオブジェクトラッパーを使用できるようにするためのコマンドライン引数を示します。

表21‒3　タイプドオブジェクトラッパー制御用のコマンドライン引数

BankWrappersプロパティ

説明

-BANKaccountCacheClnt <0|1>

クライアントアプリケーション用のbalanceメソッドの結果をキャッシュするタイプドオブジェクトラッパーを使用できるようにするかどうかを指定します。

-BANKaccountCacheSrvr <0|1>

サーバアプリケーション用のbalanceメソッドの結果をキャッシュするタイプドオブジェクトラッパーを使用できるようにするかどうかを指定します。

-BANKmanagerCacheClnt <0|1>

クライアントアプリケーション用のopenメソッドの結果をキャッシュするタイプドオブジェクトラッパーを使用できるようにするかどうかを指定します。

-BANKmanagerCacheSrvr <0|1>

サーバアプリケーション用のopenメソッドの結果をキャッシュするタイプドオブジェクトラッパーを使用できるようにするかどうかを指定します。

-BANKmanagerSecurityClnt <0|1>

クライアントアプリケーション用のopenメソッドで渡される無許可のユーザを検出するタイプドオブジェクトラッパーを使用できるようにするかどうかを指定します。

-BANKmanagerSecuritySrvr <0|1>

サーバアプリケーション用のopenメソッドで渡される無許可のユーザを検出するタイプドオブジェクトラッパーを使用できるようにするかどうかを指定します。

Javaの場合

タイプドオブジェクトラッパーは，コマンドラインに次のように指定することによって使用できます。

-Dvbroker.orb.dynamicLibs=BankWrappers.Init

表21-4にあるプロパティを一つまたは複数指定する

表21‒4　BankWrappersを使用可能または使用不可能にするコマンドラインプロパティ

BankWrappersプロパティ

説明

-DCachingAccount [=<client|server>]

クライアントまたはサーバ用のbalanceメソッドの結果をキャッシュするタイプドオブジェクトラッパーをインストールします。サブプロパティに値を指定しないと，クライアントオブジェクトラッパーとサーバオブジェクトラッパーの両方がインストールされます。

-DCachingAccountManager [=<client|server>]

クライアントまたはサーバ用のopenメソッドの結果をキャッシュするタイプドオブジェクトラッパーをインストールします。サブプロパティに値を指定しないと，クライアントオブジェクトラッパーとサーバオブジェクトラッパーの両方がインストールされます。

-DSecureAccountManager [=<client|server>]

クライアントまたはサーバ用のopenメソッドで渡された無許可のユーザを検出するタイプドオブジェクトラッパーをインストールします。サブプロパティに値を指定しないと，クライアントオブジェクトラッパーとサーバオブジェクトラッパーの両方がインストールされます。

21.6.2　タイプドオブジェクトラッパーのイニシャライザ

C++の場合

タイプドオブジェクトラッパーはobjectWrappers/BankWrap.Cに定義され，BankInit::updateイニシャライザで生成されます。このイニシャライザは，ORB_initが呼び出されるときに起動され，ユーザが指定するコマンドラインプロパティに基づいて，さまざまなタイプドオブジェクトラッパーをインストールできます。

コードサンプル21-15に，イニシャライザがPropStructオブジェクトのセットをどのように使用し，指定されたコマンドラインオプションを把握し，該当するロケーションにAccountObjectWrapperオブジェクトを追加または削除するかを示します。

コードサンプル21-15　タイプドオブジェクトラッパーのイニシャライザ（C++）

. . .
static const CORBA::ULong kNumTypedAccountProps = 2;
static PropStruct TypedAccountProps[kNumTypedAccountProps] =
{ { "BANKaccountCacheClnt",
      CachingAccountObjectWrapper::factory,
      VISObjectWrapper::Client },
   { "BANKaccountCacheSrvr",
         CachingAccountObjectWrapper::factory,
         VISObjectWrapper::Server }
};
static const CORBA::ULong kNumTypedAccountManagerProps = 4;
static PropStruct TypedAccountManagerProps[
      kNumTypedAccountManagerProps] =
{ { "BANKmanagerCacheClnt",
      CachingAccountManagerObjectWrapper::factory,
      VISObjectWrapper::Client },
{ "BANKmanagerSecurityClnt",
      SecureAccountManagerObjectWrapper::factory,
      VISObjectWrapper::Client },
{ "BANKmanagerCacheSrvr",
      CachingAccountManagerObjectWrapper::factory,
      VISObjectWrapper::Server },
{ "BANKmanagerSecuritySrvr",
      SecureAccountManagerObjectWrapper::factory,
      VISObjectWrapper::Server },
};

void BankInit::update(int& argc, char* const* argv) {
   if (argc > 0) {
      init(argc, argv, "-BANK");
      CORBA::ULong i;
      for (i=0; i < kNumTypedAccountProps; i++) {
         CORBA::String_var arg(
            getArgValue(TypedAccountProps[i].propname));
         if (arg && strlen(arg) > 0) {
            if (atoi((char*) arg)) {
               Bank::AccountObjectWrapper::add(_orb,
                     TypedAccountProps[i].fact,
                     TypedAccountProps[i].loc);
            } else {
               Bank::AccountObjectWrapper::remove(_orb,
                     TypedAccountProps[i].fact,
                     TypedAccountProps[i].loc);
            }
         }
      }
      for (i=0; i < kNumTypedAccountManagerProps; i++) {
            CORBA::String_var arg(
               getArgValue(
                     TypedAccountManagerProps[i].propname));
            if (arg && strlen(arg) > 0 ) {
                  if (atoi((char*) arg)) {
                        Bank::AccountManagerObjectWrapper
                          ::add(_orb,
                           TypedAccountManagerProps[i].fact,
                           TypedAccountManagerProps[i].loc);
                  } else {
                       Bank::AccountManagerObjectWrapper
                          ::remove(_orb,
                          TypedAccountManagerProps[i].fact,
                          TypedAccountManagerProps[i].loc);
                  }
            }
      }
   }
}

Javaの場合

タイプドオブジェクトラッパーはBankWrappersパッケージに定義され，コードサンプル21-16にあるサービスイニシャライザのBankWrappers/Init.javaを含みます。このイニシャライザは，クライアントまたはサーバをvbjで起動するときにコマンドラインで-Dvbroker.orb.dynamicLibs=BankWrappers.Initを指定すると起動されます。ユーザが指定するコマンドラインプロパティに基づいて，さまざまなタイプドオブジェクトラッパーをインストールできます。コマンドラインプロパティについては表21-4を参照してください。

コードサンプル21-16　BankWrappersのサービスイニシャライザ（Java）

package BankWrappers;
import java.util.*;
import com.inprise.vbroker.orb.ORB;
import com.inprise.vbroker.properties.PropertyManager;
import com.inprise.vbroker.interceptor.*;
public class Init implements ServiceLoader {
   com.inprise.vbroker.orb.ORB _orb;
   public void init(final org.omg.CORBA.ORB orb) {
      _orb = (ORB) orb;
      PropertyManager pm = _orb.getPropertyManager();
      // install my CachingAccountObjectWrapper
      String val = pm.getString("CachingAccount",
         this.toString());
      Class c = CachingAccountObjectWrapper.class;
      if( !val.equals(this.toString())) {
         if( val.equalsIgnoreCase("client") ) {
            Bank.AccountHelper.
                         addClientObjectWrapperClass(orb, c);
         } else if( val.equalsIgnoreCase("server") ) {
            Bank.AccountHelper.
                         addServerObjectWrapperClass(orb, c);
         } else {
            Bank.AccountHelper.
                         addClientObjectWrapperClass(orb, c);
            Bank.AccountHelper.
                         addServerObjectWrapperClass(orb, c);
         }
      }
      // install my CachingAccountManagerObjectWrapper
      val = pm.getString("CachingAccountManager",
                                            this.toString());
      c = CachingAccountManagerObjectWrapper.class;
      if( !val.equals(this.toString())) {
         if( val.equalsIgnoreCase("client") ) {
            Bank.AccountManagerHelper.
                         addClientObjectWrapperClass(orb, c);
         } else if( val.equalsIgnoreCase("server") ) {
            Bank.AccountManagerHelper.
                         addServerObjectWrapperClass(orb, c);
         } else {
            Bank.AccountManagerHelper.
                         addClientObjectWrapperClass(orb, c);
            Bank.AccountManagerHelper.
                         addServerObjectWrapperClass(orb, c);
         }
      }
      // install my CachingAccountManagerObjectWrapper
      val = pm.getString("SecureAccountManager",
            this.toString());
      c = SecureAccountManagerObjectWrapper.class;
      if( !val.equals(this.toString())) {
         if( val.equalsIgnoreCase("client") ) {
            Bank.AccountManagerHelper.
                         addClientObjectWrapperClass(orb, c);
         } else if( val.equalsIgnoreCase("server") ) {
            Bank.AccountManagerHelper.
                         addServerObjectWrapperClass(orb, c);
         } else {
            Bank.AccountManagerHelper.
                         addClientObjectWrapperClass(orb, c);
            Bank.AccountManagerHelper.
                         addServerObjectWrapperClass(orb, c);
         }
      }
   }
   public void init_complete(org.omg.CORBA.ORB orb) {}
   public void shutdown(org.omg.CORBA.ORB orb) {}
}

21.6.3　アンタイプドオブジェクトラッパー用コマンドライン引数

C++の場合

表21-5にClient.CおよびServer.CでインプリメントされたBankアプリケーションのサンプルでアンタイプドオブジェクトラッパーを使用できるようにするためのコマンドライン引数を示します。

表21‒5　アンタイプドオブジェクトラッパー制御用のコマンドライン引数

BankWrappersプロパティ

説明

-TRACEWRAPclient <numwraps>

クライアントアプリケーション用のオブジェクトラッパーをトレースするための指定の数のアンタイプドオブジェクトラッパーファクトリを実体化します。

-TRACEWRAPserver <numwraps>

サーバアプリケーションでトレースするための指定の数のアンタイプドオブジェクトラッパーファクトリを実体化します。

-TRACEWRAPboth <numwraps>

クライアントおよびサーバアプリケーションでトレースするための指定の数のアンタイプドオブジェクトラッパーファクトリを実体化します。

-TIMINGWRAPclient <numwraps>

クライアントアプリケーションでタイミングを計るための指定の数のアンタイプドオブジェクトラッパーファクトリを実体化します。

-TIMINGWRAPserver <numwraps>

サーバアプリケーションでタイミングを計るための指定の数のアンタイプドオブジェクトラッパーファクトリを実体化します。

-TIMINGWRAPboth<numwraps>

クライアントおよびサーバアプリケーションでタイミングを計るための指定の数のアンタイプドオブジェクトラッパーファクトリを実体化します。

Javaの場合

アンタイプドオブジェクトラッパーは，コマンドラインに次のように指定することによって使用できます。

-Dvbroker.orb.dynamicLibs=UtilityObjectWrappers.Init

表21-6にあるプロパティを一つまたは複数指定する

表21‒6　UtilityObjectWrappersを使用可能または使用不可能にするコマンドラインプロパティ

UtilityObjectWrappersプロパティ

説明

-DTiming[=<client|server>]

クライアントまたはサーバの情報のタイミングを取るためのアンタイプドオブジェクトラッパーをインストールします。サブプロパティの値が指定されない場合，クライアントオブジェクトラッパーとサーバオブジェクトラッパーの両方がインストールされます。

-DTracing[=<client|server>]

クライアントまたはサーバの情報をトレーシングするためのアンタイプドオブジェクトラッパーをインストールします。サブプロパティの値が指定されない場合，クライアントオブジェクトラッパーとサーバオブジェクトラッパーの両方がインストールされます。

21.6.4　アンタイプドオブジェクトラッパーのイニシャライザ

C++の場合

アンタイプドオブジェクトラッパーはBankWrappers/TraceWrap.CとTimeWrap.Cに定義され，TraceWrapInit::updateとTimingWrapInit::updateメソッド内に作成され，登録されます。これらのイニシャライザは，ORB_initメソッドが起動するときに起動され，さまざまなアンタイプドオブジェクトラッパーをインストールできます。コードサンプル21-17に，指定したコマンドラインプロパティに基づいて，該当するアンタイプドオブジェクトラッパーをインストールするTraceWrap.Cファイルの一部を示します。

コードサンプル21-17　アンタイプドオブジェクトラッパーのイニシャライザ（C++）

TraceWrapInit::update(int& argc, char* const* argv) {
   if (argc > 0) {
      init(argc, argv, "-TRACEWRAP");

      VISObjectWrapper::Location loc;
      const char* propname;
      LIST(VISObjectWrapper::
            UntypedObjectWrapperFactory_ptr) *list;

      for (CORBA::ULong i=0; i < 3; i++) {
         switch (i) {
            case 0:
               loc = VISObjectWrapper::Client;
               propname = "TRACEWRAPclient";
               list = &_clientfacts;
               break;
            case 1:
               loc = VISObjectWrapper::Server;
               propname = "TRACEWRAPserver";
               list = &_serverfacts;
               break;
            case 2:
               loc = VISObjectWrapper::Both;
               propname = "TRACEWRAPboth";
               list = &_bothfacts;
               break;
         }
         CORBA::String_var getArgValue(
                           property_value(propname));
         if (arg && strlen(arg) > 0) {
            int numNew = atoi((char*) arg);
            char key_buf[256];
            for (CORBA::ULong j=0; j < numNew; j++) {
               sprintf(key_buf, "%s-%d", propname,
                     list->size());
              list->add(new TraceObjectWrapperFactory(loc,
                    (const char*) key_buf));
            }
         }
      }
   }
}

Javaの場合

アンタイプドオブジェクトラッパーはUtilityObjectWrappersパッケージに定義され，コードサンプル21-18にあるサービスイニシャライザのUtilityObjectWrappers/Init.javaを含みます。このイニシャライザは，クライアントまたはサーバをvbjで起動するときにコマンドラインで-Dvbroker.orb.dynamicLibs=UtilityObjectWrappers.Initを指定すると起動されます。ユーザが指定するコマンドラインプロパティに基づいて，さまざまなアンタイプドオブジェクトラッパーをインストールできます。コマンドラインプロパティについては表21-6を参照してください。

コードサンプル21-18　UtilityObjectWrappersのサービスイニシャライザ（Java）

package UtilityObjectWrappers;
import java.util.*;
import com.inprise.vbroker.orb.ORB;
import com.inprise.vbroker.properties.PropertyManager;
import com.inprise.vbroker.interceptor.*;

public class Init implements ServiceLoader {
   com.inprise.vbroker.orb.ORB _orb;
   public void init(final org.omg.CORBA.ORB orb) {
      _orb = (ORB) orb;
      PropertyManager pm= _orb.getPropertyManager();
      try {
         ChainUntypedObjectWrapperFactory factory =
           ChainUntypedObjectWrapperFactoryHelper.narrow(
             orb.resolve_initial_references(
             "ChainUntypedObjectWrapperFactory"));
         // install my Timing ObjectWrapper
         String val = pm.getString("Timing", this.toString());
         if( !val.equals(this.toString())) {
            UntypedObjectWrapperFactory f=
               new TimingUntypedObjectWrapperFactory();
            if( val.equalsIgnoreCase("client") ) {
               factory.add(f, Location.CLIENT);
            } else if( val.equalsIgnoreCase("server") ) {
               factory.add(f, Location.SERVER);
            } else {
               factory.add(f, Location.BOTH);
            }
         }
         // install my Tracing ObjectWrapper
         val = pm.getString("Tracing", this.toString());
         if( !val.equals(this.toString())) {
            UntypedObjectWrapperFactory f=
                    new TracingUntypedObjectWrapperFactory();
            if( val.equalsIgnoreCase("client") ) {
               factory.add(f, Location.CLIENT);
            } else if( val.equalsIgnoreCase("server") ) {
               factory.add(f, Location.SERVER);
            } else {
               factory.add(f, Location.BOTH);
            }
         }
      } catch( org.omg.CORBA.ORBPackage.InvalidName e ) {
         return;
      }
   }

   public void init_complete(org.omg.CORBA.ORB orb) {}
   public void shutdown(org.omg.CORBA.ORB orb) {}
}

21.6.5　サンプルアプリケーションの実行

サンプルアプリケーションを実行する前に，ネットワーク上でosagentが実行中であることを確認してください。そのあと，トレーシングオブジェクトラッパーやタイミングオブジェクトラッパーを使わないで，次のコマンドを使って，サーバアプリケーションを実行できます。

C++の場合

prompt> Server

Javaの場合

prompt> vbj Server

注

サーバは同一プロセスにあるアプリケーションとして設計されています。これはサーバとクライアントの両方をインプリメントします。

別のウィンドウからは，トレーシングオブジェクトラッパーやタイミングオブジェクトラッパーを使わないで，次のコマンドを使ってクライアントアプリケーションを実行し，ユーザアカウントの残高を問い合わせることができます。

C++の場合

prompt> Client John

Javaの場合

prompt> vbj Client John

また，デフォルト名を使いたい場合も，このコマンドを実行できます。

C++の場合

prompt> Client

Javaの場合

prompt> vbj Client

(1)　タイミングおよびトレーシングオブジェクトラッパーを使用可能にする

アンタイプドタイミングオブジェクトラッパーおよびトレーシングオブジェクトラッパーを使用可能にした状態でクライアントを実行するには，次のコマンドを使用してください。

C++の場合

prompt> Client -TRACEWRAPclient 1 -TIMINGWRAPclient 1

Javaの場合

prompt> vbj -Dvbroker.orb.dynamicLibs=¥
        UtilityObjectWrappers.Init                         ¥
        -DTiming=client                                    ¥
        -DTracing=client Client John

タイミングおよびトレーシング用アンタイプドオブジェクトラッパーを使用可能にした状態でサーバを実行するには，次のコマンドを使用してください。

C++の場合

prompt> Server -TRACEWRAPserver 1 -TIMINGWRAPserver 1

Javaの場合

prompt> vbj -Dvbroker.orb.dynamicLibs=¥
        UtilityObjectWrappers.Init                         ¥
        -DTiming=server                                    ¥
        -DTracing=server Server

(2)　キャッシングおよびセキュリティオブジェクトラッパーを使用可能にする

キャッシングおよびセキュリティのためのタイプドオブジェクトラッパーを使用可能にした状態でクライアントを実行するには，次のコマンドを使用してください。

C++の場合

prompt> Client -BANKaccountCacheClnt 1   ¥
        -BANKmanagerCacheClnt 1          ¥
        -BANKmanagerSecurityClnt 1

Javaの場合

prompt> vbj -Dvbroker.orb.dynamicLibs=BankWrappers.Init   ¥
        -DCachingAccount=client                           ¥
        -DCachingAccountManager=client                    ¥
        -DSecureAccountManager=client                     ¥
        Client John

キャッシングおよびセキュリティのためのタイプドオブジェクトラッパーを使用可能にした状態でサーバを実行するには，次のコマンドを使用してください。

C++の場合

prompt> Server -BANKaccountCacheSrvr 1  ¥
        -BANKmanagerCacheSrvr 1         ¥
        -BANKmanagerSecuritySrvr 1

Javaの場合

prompt> vbj -Dvbroker.orb.dynamicLibs=BankWrappers.Init    ¥
        -DCachingAccount=server                            ¥
        -DCachingAccountManager=server                     ¥
        -DSecureAccountManager=server                      ¥
        Server

(3)　タイプドおよびアンタイプドオブジェクトラッパーを使用可能にする

すべてのタイプドオブジェクトラッパーおよびアンタイプドオブジェクトラッパーを使用可能にした状態でクライアントを実行するには，次のコマンドを使用してください。

C++の場合

prompt> Client -BANKaccountCacheClnt 1          ¥
        -BANKmanagerCacheClnt 1                 ¥
        -BANKmanagerSecurityClnt 1              ¥
        -TRACEWRAPclient 1 -TIMINGWRAPclient 1

Javaの場合

prompt> vbj -Dvbroker.orb.dynamicLibs=BankWrappers.Init,¥
        UtilityObjectWrappers.Init                        ¥
        -DCachingAccount=client                           ¥
        -DCachingAccountManager=client                    ¥
        -DSecureAccountManager=client                     ¥
        -DTiming=client                                   ¥
        -DTracing=client                                  ¥
        Client John

すべてのタイプドオブジェクトラッパーおよびアンタイプドオブジェクトラッパーを使用可能にした状態でサーバを実行するには，次のコマンドを使用してください。

C++の場合

prompt> Server BANKaccountCacheSrvr 1           ¥
        -BANKmanagerCacheSrvr 1                  ¥
        -BANKmanagerSecuritySrvr 1              ¥
        -TRACEWRAPserver 1 -TIMINGWRAPserver 1

Javaの場合

prompt> vbj -Dvbroker.orb.dynamicLibs=BankWrappers.Init,¥
        UtilityObjectWrappers.Init                         ¥
        -DCachingAccount=server                            ¥
        -DCachingAccountManager=server                     ¥
        -DSecureAccountManager=server                      ¥
        -DTiming=server                                    ¥
        -DTracing=server                                   ¥
        Server

(4)　同一プロセスにあるクライアントとサーバを実行する

C++の場合

すべてのタイプドオブジェクトラッパーを使用可能にした状態，クライアントだけのアンタイプドオブジェクトラッパーを使用可能にした状態，およびサーバだけのアンタイプドトレーシングオブジェクトラッパーを使用可能にした状態で，同一プロセスにあるサーバとクライアントを実行するには，次のコマンドを使用してください。

例

prompt> Server -BANKaccountCacheClnt 1                   ¥
        -BANKaccountCacheSrvr 1                          ¥
        -BANKmanagerCacheClnt 1 -BANKmanagerCacheSrvr 1  ¥
        -BANKmanagerSecurityClnt 1                       ¥
        -BANKmanagerSecuritySrvr 1                       ¥
        -TRACEWRAPboth 1                                 ¥
        -TIMINGWRAPboth 1

Javaの場合

表21-7の-runCoLocatedコマンドラインオプションを指定すると，同じプロセス内でクライアントとサーバを実行できます。

表21‒7　-runCoLocatedコマンドラインオプション

プロパティ

説明

-runCoLocated Client

同じプロセス内でServer.javaとClient.javaを実行します。

-runCoLocated TypedClient

同じプロセス内でServer.javaとTypedClient.javaを実行します。

-runCoLocated UntypedClient

同じプロセス内でServer.javaとUntypedClient.javaを実行します。

すべてのタイプドオブジェクトラッパーを使用可能にした状態，クライアントだけのアンタイプドタイミングオブジェクトラッパーを使用可能にした状態，およびサーバだけのアンタイプドトレーシングオブジェクトラッパーを使用可能にした状態で，同一プロセスにあるサーバとクライアントを実行するには，次のコマンドを使用してください。

例

prompt> vbj -Dvbroker.orb.dynamicLibs=BankWrappers.Init,¥
        UtilityObjectWrappers.Init                         ¥
        -DCachingAccount                                   ¥
        -DSecureAccountManager                             ¥
        -DTiming=client                                    ¥
        -DTracing=server                                   ¥
        Server -runCoLocated Client

22　イベントキュー

この章では，イベントキュー機能について説明します。ただし，この機能はサーバ側だけに提供されています。サーバは，サーバが対象とするイベントタイプに基づいてリスナーをイベントキューに登録できるので，サーバが必要なときにこのイベントを処理できます。

22.1　イベントタイプ

コネクションイベントタイプは，生成されているイベントタイプだけです。

22.1.1　コネクションイベント

VisiBroker ORBが生成して，登録されたコネクションイベントにプッシュするコネクションイベントには次の2種類があります。

設定されたコネクション

これは，新しいクライアントがサーバへの接続に成功したことを示します。

クローズしたコネクション

これは，既存のクライアントがサーバから切断されたことを示します。

22.2　イベントリスナー

サーバは，サーバが処理する必要のあるイベントタイプに基づいてVisiBroker ORBによってリスナーをインプリメントして登録します。サポートされているイベントリスナーは，コネクションイベントリスナーだけです。

ほかのタイプのイベントリスナーは，必要に応じて将来のバージョンで追加される予定です。

22.2.1　IDL定義

インタフェース定義を次に示します。

module EventQueue {
   // Connection event types
   enum EventType {UNDEFINED, CONN_EVENT_TYPE};

   // Peer (Client)connection info
   struct ConnInfo {
      string ipaddress; // in %d.%d.%d.%d format
      long     port;
      long     connID;
   };

   // Marker interface for all types of event listeners
   local interface EventListener {};

   typedef sequence<EventListener> EventListeners;

   // connection event listener interface
   local interface ConnEventListener : EventListener{
         void conn_established(in ConnInfo info);
         void conn_closed(in ConnInfo info);
   };

   // The EventQueue manager
   local interface EventQueueManager :
                             interceptor::InterceptorManager {
        void register_listener(in EventListener listener,
                                           in EventType type);
        void unregister_listener(in EventListener listener,
                                           in EventType type);
        EventListeners get_listeners(in EventType type);
   };

};

インタフェース定義の詳細を以降で説明します。

(1)　ConnInfo構造体

ConnInfo構造体には次のようなクライアントコネクション情報があります。

ipaddress : 通信相手のIPアドレスを格納します。

port : 通信相手のポート番号を格納します。

connID : このクライアントコネクションのサーバごとの一意の識別子を格納します。

(2)　EventListenerインタフェース

EventListenerインタフェースの部分は，すべてのタイプのイベントリスナーのマーカーインタフェースです。

(3)　ConnEventListenersインタフェース

ConnEventListenersインタフェースは次のように二つのオペレーションを定義します。

void conn_established (in ConnInfo info)

このオペレーションはVisiBroker ORBによってコールバックされ，コネクション設定イベントをプッシュします。VisiBroker ORBはin ConnInfo infoパラメタにクライアントコネクション情報を与えて，この値をコールバックオペレーションに渡します。

void conn_closed (in ConnInfo info)

このオペレーションはVisiBroker ORBによってコールバックされ，コネクションクローズイベントをプッシュします。VisiBroker ORBはin ConnInfo infoパラメタにクライアントコネクション情報を与えて，この値をコールバックオペレーションに渡します。

サーバ側アプリケーションは，リスナーにプッシュされているイベントの処理と同様，ConnEventListenerインタフェースのインプリメンテーションにも責任があります。

(4)　EventQueueManagerインタフェース

EventQueueManagerインタフェースは，イベントリスナーの登録に関するサーバ側インプリメンテーションによってハンドルとして使用されます。このインタフェースは次のように三つのオペレーションを定義します。

void register_listener (in EventListener listener, in EventType type)

このオペレーションは，指定のイベントタイプのイベントリスナーの登録用に用意されています。

EventListeners get_listeners (in EventType type)

このオペレーションは指定のタイプの登録済みイベントリスナーのリストを返します。

void unregister_listener (in EventListener listener, in EventType type)

このオペレーションは事前に登録された指定のタイプのリスナーを削除します。

22.2.2　EventQueueManagerの返し方

EventQueueManagerオブジェクトはORB初期化時に生成されます。サーバ側のインプリメンテーションは，次に示すコードによってEventQueueManagerオブジェクトリファレンスを返します。

コードサンプル22-1　EventQueueManager（C++）

CORBA::Object *object =
       orb->resolve_initial_references("VisiBrokerInterceptorControl");

interceptor::InterceptorManagerControl_var control =
          interceptor::InterceptorManagerControl::_narrow(object);

interceptor::InterceptorManager_var manager =
       control->get_manager("EventQueueManager");
EventQueue::EventQueueManager_var eq_mgr =

EventQueue::EventQueueManager::_narrow(manager);

コードサンプル22-2　EventQueueManager（Java）

com.inprise.vbroker.interceptor.InterceptorManagerControl control =
com.inprise.vbroker.interceptor.
            InterceptorManagerControlHelper.narrow(
    orb.resolve_initial_references(
            "VisiBrokerInterceptorControl"));
EventQueueManager manager =
            (EventQueueManager)control.get_manager("EventQueue");
EventListener theListener =...
manager.register_listeners(theListener);

22.2.3　コードサンプル

EventListenersの登録およびコネクションEventListenerのインプリメントについて，C++とJavaのコードサンプルを示します。

(1)　EventListenersの登録

SampleServerLoaderクラスには，初期化時にORBが呼び出すORB_init()メソッド（C++）またはinit()メソッド（Java）があります。ServerLoaderの目的は，EventListenerを作成して，それをEventQueueManagerに登録することです。

コードサンプル22-3　SampleServerLoader.h（C++）

#ifdef _VIS_STD
#include <iostream>
#else
#include <iostream.h>
#endif

#include "vinit.h"
#include "ConnEventListenerImpl.h"

USE_STD_NS

class SampleServerLoader :public VISInit
{
    private:
       short int _conn_event_interceptors_installed;

    public:
    SampleServerLoader(){
      _conn_event_interceptors_installed =0;
    }

    void ORB_init(int& argc, char* const* argv, CORBA::ORB_ptr orb)
    {
      if( _conn_event_interceptors_installed) return;
         cout << "Installing Connection event interceptors" << endl;

       ConnEventListenerImpl *interceptor =
        new ConnEventListenerImpl("ConnEventListener");

       // Get the interceptor manager control
       CORBA::Object *object =
            orb->resolve_initial_references
                                ("VisiBrokerInterceptorControl");

       interceptor::InterceptorManagerControl_var control =
            interceptor::InterceptorManagerControl::_narrow(object);

       // Get the POA manager
       interceptor::InterceptorManager_var manager =
          control->get_manager("EventQueueManager");
       EventQueue::EventQueueManager_var eq_mgr =
          EventQueue::EventQueueManager::_narrow(manager);

       // Add POA interceptor to the list
       eq_mgr->register_listener( (EventQueue::ConnEventListener
              *)interceptor,
          EventQueue::CONN_EVENT_TYPE);

       cout << "Event queue interceptors installed" << endl;
            _conn_event_interceptors_installed = 1;
    }
};

コードサンプル22-4　SampleServerLoader.java（Java）

import com.inprise.vbroker.EventQueue.*;
import com.inprise.vbroker.interceptor.*;
import com.inprise.vbroker.PortableServerExt.*;

public class SampleServerLoader implements ServiceLoader
{
   public void init(org.omg.CORBA.ORB orb)
   {
      try {
        InterceptorManagerControl control =
               InterceptorManagerControlHelper.narrow(
                  orb.resolve_initial_references
                     ("VisiBrokerInterceptorControl"));

        EventQueueManager queue_manager =
           (EventQueueManager)control.get_manager("EventQueue");

        queue_manager.register_listener((EventListener)new
                  ConnEventListenerImpl(),EventType.CONN_EVENT_TYPE);
      }
      catch(Exception e){
         e.printStackTrace();
         throw new org.omg.CORBA.INITIALIZE(e.toString());
      }
      System.out.println("=========>SampleServerLoader:
                                    ConnEventListener registered");
   }

   public void init_complete(org.omg.CORBA.ORB orb){

   }

   public void shutdown(org.omg.CORBA.ORB orb){

   }
}

(2)　EventListenersのインプリメント

ConnEventListenerImplには，コネクションイベントリスナーのインプリメンテーションサンプルがあります。ConnEventListenerインタフェースは，サーバ側アプリケーションでconn_establishedおよびconn_closedオペレーションをインプリメントします。インプリメンテーションによってコネクションは，サーバ側でリクエストを待っている間，30,000ミリ秒間アイドル状態にできます。このようなオペレーションは，クライアントがコネクションを設定した場合と，コネクションが切断された場合にそれぞれ呼び出されます。

コードサンプル22-5　ConnEventListenerImpl.h（C++）

#ifdef _VIS_STD
#include <iostream>
#else
#include <iostream.h>
#endif

#include "vextclosure.h"
#include "interceptor_c.hh"
#include "IOP_c.hh"
#include "EventQueue_c.hh"
#include "vutil.h"

//USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

//-----------------------------------------------------------------
//defines the server interceptor functionality
//-----------------------------------------------------------------
class ConnEventListenerImpl :public EventQueue::ConnEventListener
{

   private:
      char * _id;
   public:
   ConnEventListenerImpl( const char* id){
      _id =new char [ strlen((id) + 1 ];
      strcpy( _id,id);
   }

   virtual~ConnEventListenerImpl(){
      delete[ ] _id;
      _id =NULL;
   }

   //-------------------------------------------------------------
   // This method gets called when a request arrives at the
   // server end.
   //-------------------------------------------------------------
   void conn_established(const EventQueue::ConnInfo& connInfo){
      cout <<"Processing connection established from" <<endl;
      cout << connInfo;
      cout <<endl;
      VISUtil : sleep(30000);
   }
   void conn_closed(const EventQueue::ConnInfo &connInfo){
      cout <<"Processing connection closed from " <<endl ;
      cout <<connInfo ;
      cout <<endl;
      VISUtil::sleep(30000);
   }
};

コードサンプル22-6　ConnEventListenerImpl.java（Java）

import com.inprise.vbroker.EventQueue.*;
import org.omg.CORBA.LocalObject;

public class ConnEventListenerImpl extends LocalObject implements
                                               ConnEventListener {
   public void conn_established(ConnInfo info){
      System.out.println("Received conn_established:address ="+
                          info.ipaddress + "port ="+info.port +
                          " connID = " + info.connID);
      System.out.println("Processing the event ...");
      try {
        Thread.sleep(30000);
      }catch (Exception e){e.printStackTrace();}
   }

   public void conn_closed(ConnInfo info) {
      System.out.println("Received conn_closed:address = " +
                          info.ipaddress+"port ="+info.port +
                          " connID = " + info.connID);
   }
}

23　RMI-IIOPの使用

この章では，RMI-IIOPを使用するためのBorland Enterprise Server VisiBrokerツールについて説明します。また，RMI-IIOPを使用するJavaアプレットを実行する場合のセットアップ許可要件についても簡単に説明します。

23.1　概要

RMI（Remote Method Invocation）は，オブジェクトを生成し，分散環境で使用できるようにするJavaの方式です。この意味では，RMIは言語固有（Java）であり，CORBAに準拠しないVisiBroker ORBです。OMGは，IDLマッピングに対するJava言語の仕様を規定しており，これによって，IIOPを使用するCORBAオブジェクトとRMIを使用しているJavaのクラスが相互に通信できるようになります。

23.1.1　RMI-IIOPによるJavaアプレットの設定

RMI-IIOPを使用するアプレットを実行できますが，ReflectおよびRuntimeで許可を設定する必要があります。このような許可はJREのインストールディレクトリにあるjava.policyファイルで設定します。ここに，java.policyファイルでの許可の設定方法の例を示します。

grant codeBase "http://xxx.xxx.xxx.xxx:8088/-" {
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
permission java.lang.RuntimePermission "accessDeclaredMembers";
};

23.1.2　java2iiopおよびjava2idlツール

Borland Enterprise Server VisiBrokerには二つのコンパイラがあります。このコンパイラによって，ユーザはVisiBroker ORBを使用して既存のJavaクラスをほかのオブジェクトで作業させることができるようになります。

java2iiopコンパイラは，RMI準拠のクラスを受け取り，適切なスケルトン，スタブ，およびヘルパークラスを生成してIIOPを使用できるようにします。

java2idlコンパイラは，JavaクラスからIDLを生成して，Java以外の言語でインプリメントできるようにします。

23.2　java2iiopの使用

java2iiopコンパイラは，CORBAで使用できるインタフェースおよびデータ型を定義できますが，このコンパイラのメリットはそれらをIDLではなくJavaで定義できる点にあります。このコンパイラはJavaソースコード（Javaファイル）やIDLを読み込みませんが，Javaバイトコード（classファイル）は読み込みます。そして，java2iiopコンパイラはCORBAで必要なすべてのマーシャルおよび通信のために，IIOP通信を実行するためのスタブおよびスケルトンを生成します。

23.2.1　サポートしているインタフェース

java2iiopコンパイラを実行すると，インタフェースをIDLで記述した場合と同じようにファイルが生成されます。数値型（short，int，long，float，およびdouble）などの基本データ型，文字列，CORBAオブジェクトまたはインタフェースオブジェクト，Anyオブジェクト，typecodeオブジェクトはすべてjava2iiopコンパイラによって認識され，IDLの対応する型にマッピングされます。

Javaクラスまたはインタフェースでjava2iiopを使用できます。例えば，Javaインタフェースが次の規則のどれかを継承する場合，java2iiopはインタフェースをIDLのCORBAインタフェースに変換します。

java.rmi.Remoteを継承して，そのメソッドのすべてでjava.rmi.RemoteExceptionが発生する

org.omg.CORBA.Objectを継承する

コードサンプル23-1にJava RMIインタフェースを示します。コードサンプルは，Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/rmi-iiopに入っています。

コードサンプル23-1　java.rmi.Remoteの継承

public interface Account extends java.rmi.Remote {
   String name() throws java.rmi.RemoteException;
   float getBalance() throws java.rmi.RemoteException;
   void setBalance(float bal) throws java.rmi.RemoteException;
}

23.2.2　java2iiopの実行

java2iiopコンパイラを使用する前に，Javaクラスをコンパイルする必要があります。バイトコードを生成したら，java2iiopを実行してクライアントスタブ，サーバスケルトン，およびその関連補助ファイルを生成できます。例えば，java2iiopをexamples/vbe/rmi-iiop/BankディレクトリのAccount.classファイルで実行すると，次のファイルができることになります。

_Account_Stub

AccountHelper

AccountHolder

AccountPOA

_Account_Tie

AccountOperations

これらのファイルの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「生成されるインタフェースとクラス」の記述を参照してください。

(1)　JavaクラスのIDLへの逆マッピング

idl2javaコンパイラを使用してIDLインタフェースをJavaクラスにマッピングする場合，インタフェース名は，生成されたクラスの拡張子（例: Helper，Holder，POAなど）を使用し，場合によってidl2javaツールはインタフェース名の識別子にプリフィクスとして下線（_）を付けてクラスを生成します。例えば，IDLへFooとFooHolderインタフェースの両方を定義する場合，idl2javaはFoo.java，FooHolder.java，_FooHolder.java，および_FooHolderHolder.javaファイルを生成します。反対に，java2iiopコンパイラを使用してRMI Javaクラスからヘルパークラスやホルダークラスなどを生成する場合，java2iiopツールはプリフィクスとして下線を付けたクラスを生成できません。そのため，予約した拡張子を使用するインタフェースを宣言する場合，同じ名前のインタフェースとして同じパッケージに入れることはできません（例えば，java2iiopコンパイラを使用する場合，FooとFooHolderクラスを同じパッケージに入れることはできません）。

23.2.3　開発プロセスの完了

インタフェースから対応するファイルを生成したあと，インタフェース用にインプリメンテーションを提供する必要があります。そのためには，次の手順に従ってください。

インタフェースクラス用のインプリメンテーションを作成します。

サーバクラスをコンパイルします。

クライアントコードを書き込み，コンパイルします。

サーバプログラムを起動します。

クライアントプログラムを実行します。

注

非準拠クラスをマーシャルしようとすると，org.omg.CORBA.MARSHAL: Cannot marshal non-conforming value of class <class name>が発生します。例えば，次の二つのクラスを生成します。

// This is a conforming class
public class Value implements java.io.Serializable {
   java.lang.Object any;
   . . .
}

// This is a non-conforming class
public class Something {
. . .
}

そして，次を試行します。

Value val = new Value();
val.any = new Something();

valをマーシャルしようとするとorg.omg.CORBA.MARSHAL例外が発生します。

23.3　RMI-IIOPバンクのサンプル

Accountインタフェースは，java.rmi.Remoteインタフェースを継承し，AccountImplクラスによってインプリメントされます（コードサンプル23-2参照）。

Clientクラス（コードサンプル23-3参照）は，まず，アカウントを生成するために各アカウント用にAccountDataオブジェクトを生成して，それらをAccountManagerに渡すことによって，指定のすべてのAccountオブジェクトを適切な残高で生成します。そして，生成されたアカウントで残高が正しいかどうかを確認します。クライアントはAccountManagerに，アカウントすべてのリストを照会し，各アカウントの貸方に$10.00を記入します。クライアントはアカウントの新しい残高が正確であるかどうかを検証します。

注

コードサンプルは，Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/rmi-iiopに入っています。

コードサンプル23-2　Accountインタフェースのインプリメント

public class AccountImpl extends Bank.AccountPOA {
   public AccountImpl(Bank.AccountData data) {
      _name = data.getName();
      _balance = data.getBalance();
   }
   public String name() throws java.rmi.RemoteException {
      return _name;
   }
   public float getBalance() throws java.rmi.RemoteException {
      return _balance;
   }
   public void setBalance(float balance) throws
                                         java.rmi.RemoteException {
      _balance = balance;
   }
   private float _balance;
   private String _name;
}

コードサンプル23-3　Clientクラス

public class Client {
   public static void main(String[ ] args) {
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                           org.omg.CORBA.ORB.init(args,null);
         // Get the manager Id
         byte[ ] managerId = "RMIBankManager".getBytes();
         // Locate an account manager. Give the full POA
         // name and the servant ID.
         Bank.AccountManager manager =
                         Bank.AccountManagerHelper.bind(orb,
                                 "/rmi_bank_poa", managerId);
         // Use any number of argument pairs to indicate
         // name, balance of accounts to create
         if (args.length == 0 || args.length % 2 != 0) {
            args = new String[2];
            args[0] = "Jack B. Quick";
            args[1] = "123.23";
         }
         int i = 0;
         while (i < args.length) {
            String name = args[i++];
            float balance;
            try {
               balance = new Float(args[i++]).floatValue();
            } catch (NumberFormatException n) {
               balance = 0;
            }
            Bank.AccountData data =
                         new Bank.AccountData(name, balance);
            Bank.Account account = manager.create(data);
            System.out.println("Created account for " +
               name + " with opening balance of $" + balance);
         }
         java.util.Hashtable accounts =
                                       manager.getAccounts();
         for (java.util.Enumeration e = accounts.elements();
                                      e.hasMoreElements();) {
            Bank.Account account =
                  Bank.AccountHelper.narrow(
                      (org.omg.CORBA.Object)e.nextElement());
            String name = account.name();
            float balance = account.getBalance();
            System.out.println("Current balance in " + name +
                                "'s account is $" + balance);
            System.out.println("Crediting $10 to " + name +
                                              "'s account.");
            account.setBalance(balance + (float)10.0);
            balance = account.getBalance();
            System.out.println("New balance in " + name +
                                "'s account is $" + balance);
         }
      } catch (java.rmi.RemoteException e){
         System.err.println(e);
      }
   }
}

23.4　サポートされるデータ型

Java基本データ型に加えて，RMI-IIOPはJavaクラスのサブセットをサポートします。

23.4.1　基本データ型のマッピング

java2iiopによって生成されたクライアントスタブは，オペレーション要求を表すJava基本データ型のマーシャルを処理して，そのデータ型をオブジェクトサーバへ送信できるようにしています。Java基本データ型のマーシャル時には，そのデータ型をIIOP互換形式に変換する必要があります。表23-1に，Java基本データ型とIDL/IIOP型間のマッピングの概略を示します。

表23‒1　Javaの型からIDL/IIOPへのマッピング

Javaの型

IDL/IIOPの型

void

void

boolean

boolean

byte

octet

char

wchar

short

short

int

long

long

long long

float

float

double

double

java.lang.String

CORBA::WStringValue

java.lang.Object

any

java.io.Serializable

any

java.io.Externalizable

any

23.4.2　複合データ型のマッピング

ここでは，インタフェース，配列，およびJavaクラスについて説明し，java2iiopコンパイラを使用して複合データ型を処理する方法を示します。

(1)　インタフェース

Javaインタフェースは，IDLではCORBAインタフェースとして表され，org.omg.CORBA.Objectインタフェースから継承する必要があります。このようなインタフェースをインプリメントするオブジェクトを渡す場合はリファレンス渡しになります。

(2)　配列

クラス内に定義される別の複合データ型には配列があります。配列を使用する定義またはインタフェースがある場合，その配列はボックス型のCORBAボックス型シーケンスにマッピングします。

24　動的管理型の使用

この章では，Borland Enterprise Server VisiBrokerのDynAny機能について説明します。この機能を使うことで，ユーザはランタイム時にデータ型を作成し，解釈できます。

24.1　概要

DynAnyインタフェースは，ランタイム時に動的に基本データ型と構造化データ型を生成できるようにします。またコンパイル時にサーバがオブジェクトに含まれる型を知らなくても，Anyオブジェクトの情報を解釈し，抽出できるようにします。DynAnyインタフェースを使用すると，ユーザはランタイム時にデータ型を作成，解釈するためのクライアントおよびサーバアプリケーションを作成できます。

DynAnyインタフェースの使い方を示したクライアントおよびサーバアプリケーションのサンプルが，Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/dynanyに入っています。この章では，これらのサンプルプログラムを使ってDynAnyの概念を説明します。

24.2　DynAnyの型

DynAnyオブジェクトには対応する値があり，その値は基本データ型（例：boolean，int，float）または構造化データ型です。DynAnyインタフェースは，含まれるデータの型を調べるメソッドや，基本データ型の値を設定したり抽出したりするメソッドを提供します。DynAnyインタフェースの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「DynAny」の記述を参照してください。

構造化データ型はすべて，DynAnyから派生する表24-1に示すインタフェースで表現されます。各インタフェースは，おのおのが含む値を設定または抽出するのに適した独自のメソッドのセットを持ちます。

表24‒1　構造化データ型を表現するDynAny派生インタフェース

インタフェース

TypeCode

説明

DynArray

_tk_array

固定数の要素を持つ，同じデータ型の値の配列

DynEnum

_tk_enum

単数の列挙体値

DynFixed

_tk_fixed

未サポート

DynSequence

_tk_sequence

同じデータ型の値のシーケンス。要素数は増加または減少します。

DynStruct

_tk_struct

構造体

DynUnion

_tk_union

Union

DynValue

_tk_value

未サポート

24.2.1　使用上の制限事項

DynAnyオブジェクトを生成したプロセスだけが，ローカルでDynAnyオブジェクトを使用できます。バインドされたオブジェクト用のオペレーション要求でDynAnyオブジェクトをパラメタとして使おうとしたり，ORB::object_to_stringメソッド（C++）またはORB.object_to_stringメソッド（Java）を使ってDynAnyオブジェクトを文字列化しようとしたりすると，BAD_OPERATION例外が発生します。

また，DynAnyオブジェクトをDIIリクエスト中でパラメタとして使おうとすると， BAD_OPERATION例外が発生します。

このバージョンでは，CORBA 2.5で指定したようにlong doubleおよびfixed型はサポートしていません。

24.2.2　DynAnyの生成

DynAnyオブジェクトは，DynAnyFactoryオブジェクトでオペレーションを呼び出して生成します。まず，DynAnyFactoryオブジェクトのリファレンスを取得してから，そのオブジェクトを使用して新しいDynAnyオブジェクトを生成します。

コードサンプル24-1　DynAnyの生成（C++）

CORBA::Object_var obj =
      orb->resolve_initial_references("DynAnyFactory");
DynamicAny::DynAnyFactory_var factory =
      DynamicAny::DynAnyFactory::_narrow(obj);

// Create Dynamic struct
DynamicAny::DynAny_var dynany =
      factory->create_dyn_any_from_type_code(
            Printer::_tc_StructType);

DynamicAny::DynStruct_var info =
      DynamicAny::DynStruct::_narrow(dynany);

info->set_members(seq);

CORBA::Any_var any = info->to_any();

コードサンプル24-2　DynAnyの生成（Java）

// Resolve Dynamic Any Factory
   DynAnyFactory factory =
      DynAnyFactoryHelper.narrow(
            orb.resolve_initial_references("DynAnyFactory"));
      byte[ ] oid = "PrinterManager".getBytes();

// Create the printer manager object.
   PrinterManagerImpl manager =
     new PrinterManagerImpl((com.inprise.vbroker.CORBA.ORB)
                            orb, factory, serverPoa, oid);

// Export the newly create object.
   serverPoa.activate_object_with_id(oid, manager);
   System.out.println(manager + " is ready.");

24.2.3　DynAny中の値の初期化とアクセス

DynAny::insert_<type>メソッド（C++）またはDynAny.insert_<type>メソッド（Java）を使って，ユーザはさまざまな基本データ型のDynAnyオブジェクトを初期化できます。<type>にboolean，octet，charなどを指定できます。DynAnyに定義されたTypeCodeと異なる型を挿入すると，TypeMismatch例外が発生します。

DynAny::get_<type>メソッド（C++）またはDynAny.get_<type>メソッド（Java）を使って，ユーザはDynAnyオブジェクトに含まれる値にアクセスできます。<type>にはboolean，octet，charなどを指定できます。DynAnyに定義されたTypeCodeと異なるDynAnyコンポーネントから値にアクセスしようとすると，TypeMismatch例外が発生します。

DynAnyインタフェースはまた，Anyオブジェクトのコピー，割り当て，および変換（Anyオブジェクトへの変換とAnyオブジェクトからの変換）のメソッドも提供します。この章に記述されているサンプルプログラムは，幾つかのメソッドの使い方を示します。マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「DynAny」の記述で全メソッドについての説明をしています。

24.3　構造化データ型

ここで説明する型は，DynAnyインタフェースから派生したもので，構造化データ型を表現するのに使われます。これらのインタフェースおよびインタフェースが提供するメソッドについては，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「動的インタフェースとクラス」の記述を参照してください。

構造化データ型でコンポーネントを移動する

DynAnyから派生したインタフェースの中には，複数のコンポーネントを持つものがあります。DynAnyインタフェースは，これらのコンポーネントの中で繰り返しを行うメソッドを提供します。複数のコンポーネントを持つDynAny派生オブジェクトは，カレントコンポーネントのポインタを保持します。DynAnyメソッドを表24-2に示します。

表24‒2　DynAnyメソッド

DynAnyメソッド

説明

rewind

カレントコンポーネントポインタを最初のコンポーネントに移動します。オブジェクトにコンポーネントが一つしかない場合，効果はありません。

next

ポインタを次のコンポーネントに移動させます。コンポーネントがすでにない場合や，オブジェクトにコンポーネントが一つしかない場合，falseが返されます。

current_component

DynAnyオブジェクトを返します。DynAnyオブジェクトは，コンポーネントのTypeCodeに基づいて適切な型にナロウされている場合があります。

seek

カレントコンポーネントポインタを，指定された0から始まるインデックスのコンポーネントに設定します。指定されたインデックスにコンポーネントがない場合，falseが返されます。負のインデックスで指定されている場合，カレントコンポーネントポインタを-1（コンポーネントなし）に設定します。

24.3.1　DynEnum

このインタフェースは，一つの列挙体定数を表現します。値を文字列または整数値として設定し，取得するメソッドが提供されます。

24.3.2　DynStruct

このインタフェースは，動的に構築されたstruct型を表現します。構造体のメンバを検索または設定するには，NameValuePairオブジェクトのシーケンスを使用してください。各NameValuePairオブジェクトには，メンバの名前と，メンバの型および値を含んだAnyが含まれます。

ユーザは，rewind，next，current_component，およびseekメソッドを使って，構造体中のメンバ間を移動できます。構造体のメンバを設定および取得するメソッドが提供されます。

24.3.3　DynUnion

このインタフェースはunionを表現し，二つのコンポーネントを含みます。最初のコンポーネントは識別子で，二つ目のコンポーネントはメンバの値を表します。

ユーザは，rewind，next，current_component，およびseekメソッドを使って，コンポーネント間を移動できます。unionの識別子とメンバ値を設定および取得するメソッドが提供されます。

24.3.4　DynSequenceとDynArray

DynSequenceまたはDynArrayは，基本データ型または構造化データ型のシーケンスを表現します。DynSequenceやDynArrayを使えば，シーケンスまたは配列の中のコンポーネントごとに個々にDynAnyオブジェクトを生成しなくて済みます。DynSequence中のコンポーネントの数は変化しますが，DynArray中のコンポーネントの数は固定です。

ユーザは，rewind，next，current_component，およびseekメソッドを使って，DynArrayまたはDynSequenceのメンバ間を移動できます。

24.4　IDLサンプル

コードサンプル24-3に，クライアント／サーバアプリケーションのサンプルで使われているIDLを示します。StructType構造体には，二つの基本データ型と一つの列挙体の値が含まれています。Anyの内容を表示するためにPrinterManagerインタフェースが使われます。この場合，Anyが含むデータ型に関する静的情報は表示されません。

コードサンプル24-3　DynAnyクライアントのサンプルのIDL

// Printer.idl
module Printer {
   enum EnumType {first, second, third, fourth};
   struct StructType {
      string str;
      EnumType e;
      float fl;
   };
   interface PrinterManager {
      void printAny(in any info);
      oneway void shutdown();
   };
};

24.5　クライアントアプリケーションのサンプル

コードサンプル24-4および24-5に，Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/dynanyに入っているクライアントアプリケーションを示します。クライアントアプリケーションはDynStructインタフェースを使って，動的にStructType構造体を生成します。

DynStructインタフェースは，NameValuePairオブジェクトのシーケンスを使って，構造体メンバとメンバに対応する値を表現します。名前・値の各ペアは，構造体のメンバ名を含む文字列と，構造体メンバの値を含むAnyオブジェクトで構成されています。

通常の方法でVisiBroker ORBを初期化し，PrintManagerオブジェクトにバインドしたあと，クライアントは次の動作をします。

空のDynStructを適切な型で生成します。

構造体メンバを含むための，NameValuePairオブジェクトのシーケンスを生成します。

構造体メンバの各値用にAnyオブジェクトを生成し，初期化します。

各NameValuePairを，適切なメンバ名と値で初期化します。

DynStructオブジェクトをNameValuePairシーケンスで初期化します。

PrinterManager::printAnyメソッド（C++）またはPrinterManager.printAnyメソッド（Java）を呼び出し，通常のAnyに変換したDynStructを渡します。

注

DynAnyオブジェクトまたはその派生型の一つをオペレーション要求のパラメタとして渡す前に，DynAny::to_anyメソッド（C++）またはDynAny.to_anyメソッド（Java）を使って，これをAnyに変換しておいてください。

コードサンプル24-4　DynStructを使用したクライアントアプリケーションのサンプル（C++）

// Client.C

#include "Printer_c.hh"
#include "dynany.h"

int main(int argc, char* const* argv) {
   try {
   // Initialize the ORB.
   CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
   DynamicAny::DynAnyFactory_var factory =
      DynamicAny::DynAnyFactory::_narrow(
            orb->resolve_initial_references(
                  "DynAnyFactory"));
   // Get the manager Id
   PortableServer::ObjectId_var managerId =
         PortableServer::string_to_ObjectId("PrinterManager");
   // Locate an account manager. Give the full POA name
   // and the servant ID.
   Printer::PrinterManager_ptr manager =
         Printer::PrinterManager::_bind(
               "/serverPoa", managerId);

   DynamicAny::NameValuePairSeq seq(3);
   seq.length(3);

   CORBA::Any strAny,enumAny,floatAny;
   strAny <<= "String";
   enumAny <<= Printer::second;
   floatAny <<= (CORBA::Float)864.50;

   CORBA::NameValuePair nvpairs[3];

   nvpairs[0].id = CORBA::string_dup("str");
   nvpairs[0].value = strAny;

   nvpairs[1].id = CORBA::string_dup("e");
   nvpairs[1].value = enumAny;

   nvpairs[2].id = CORBA::string_dup("fl");
   nvpairs[2].value = floatAny;

   seq[0] = nvpairs[0];
   seq[1] = nvpairs[1];
   seq[2] = nvpairs[2];

   // Create Dynamic struct
   DynamicAny::DynStruct_var info =
      DynamicAny::DynStruct::_narrow(
      factory->create_dyn_any_from_type_code(
            Printer::_tc_StructType));

   info->set_members(seq);
      manager->printAny(*(info->to_any()));
      manager->shutdown();
   }
   catch(const CORBA::Exception& e) {
      cerr << "Caught " << e << "Exception" << endl;
   }
}

コードサンプル24-5　DynStructを使用したクライアントアプリケーションのサンプル（Java）

// Client.java

import org.omg.DynamicAny.*;

public class Client {

   public static void main(String[ ] args) {
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args, null);

         DynAnyFactory factory = DynAnyFactoryHelper.narrow(
            orb.resolve_initial_references("DynAnyFactory"));

         // Locate a printer manager.
         Printer.PrinterManager manager =
            Printer.PrinterManagerHelper.bind(orb,
                                           "PrinterManager");

         // Create Dynamic struct
         DynStruct info =
            DynStructHelper.narrow(factory.
               create_dyn_any_from_type_code(
                  Printer.StructTypeHelper.type()));

         // Create our NameValuePair sequence (array)
         NameValuePair[ ] NVPair = new NameValuePair[3];

         // Create and initialize Dynamic Struct data as any's
         org.omg.CORBA.Any str_any = orb.create_any();
         str_any.insert_string("String");
         org.omg.CORBA.Any e_any = orb.create_any();
         Printer.EnumTypeHelper.insert(
                             e_any, Printer.EnumType.second);
         org.omg.CORBA.Any fl_any = orb.create_any();
         fl_any.insert_float((float)864.50);

         NVPair[0] = new NameValuePair("str", str_any);
         NVPair[1] = new NameValuePair("e", e_any);
         NVPair[2] = new NameValuePair("fl", fl_any);

         // Initialize the Dynamic Struct
         info.set_members(NVPair);

         manager.printAny(info.to_any());

         manager.shutdown();
      }
      catch (Exception e){
         e.printStackTrace();
      }
   }
}

24.6　サーバアプリケーションのサンプル

コードサンプル24-6に，Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/dynanyに入っているサーバアプリケーションを示します。サーバアプリケーションは次の動作を行います。

VisiBroker ORBを初期化します。

POAのポリシーを生成します。

PrintManagerオブジェクトを生成します。

PrintManagerオブジェクトをエクスポートします。

メッセージを出力し，オペレーション要求が入力されるのを待ちます。

コードサンプル24-6　サーバアプリケーションのサンプル（C++）

. . .
int main(int argc, char* const* argv) {

   try {
      // Initialize the ORB.
      CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
      int Verbose = 0;
      // get a reference to the rootPOA
      PortableServer::POA_var rootPOA =
      PortableServer::POA::_narrow(
            orb->resolve_initial_references("RootPOA"));
      CORBA::PolicyList policies;
      policies.length(1);
      policies[(CORBA::ULong)0] =
            rootPOA->create_lifespan_policy(
            PortableServer::PERSISTENT);
      // Create serverPOA with the right policies
      PortableServer::POA_var serverPOA =
            rootPOA->create_POA("serverPoa",
            rootPOA->the_POAManager(),
            policies );
      // Resolve Dynamic Any Factory
      DynamicAny::DynAnyFactory_var factory =
            orb->resolve_initial_references("DynAnyFactory");
      PortableServer::ObjectId_var managerId =
            PortableServer::string_to_ObjectId(
            "PrinterManager");
      // Create the printer manager object.
      PrinterManagerImpl manager(
            orb, factory, serverPOA, managerId);
      // Export the newly create object.
      serverPOA->activate_object_with_id(managerId,&manager);
      // Activate the POA Manager
      rootPOA->the_POAManager()->activate();
      cout << serverPOA->servant_to_reference(&manager)
            << "is ready" << endl;
      // Wait for incoming requests
      orb->run();
   }
   catch(const CORBA::Exception& e) {
      cerr << e << endl;
   }
}

コードサンプル24-7　サーバアプリケーションのサンプル（Java）

// Server.java

import java.util.*;
import org.omg.DynamicAny.*;
import org.omg.PortableServer.*;
import com.inprise.vbroker.PortableServerExt.*;

public class Server {

   public static void main(String[ ] args) {
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                          org.omg.CORBA.ORB.init(args,null);

         // Resolve RootPOA
         POA rootPoa = POAHelper.narrow(
                  orb.resolve_initial_references("RootPOA"));
         rootPoa.the_POAManager().activate();

         // Create a BindSupport Policy that makes POA
         // register each servant with osagent
         org.omg.CORBA.Any any = orb.create_any();
         BindSupportPolicyValueHelper.insert(any,
                        BindSupportPolicyValue.BY_INSTANCE);

         org.omg.CORBA.Policy bsPolicy = orb.create_policy(
                        BIND_SUPPORT_POLICY_TYPE.value, any);

         // Create policies for our testPOA
         org.omg.CORBA.Policy[ ] policies = {
            rootPoa.create_lifespan_policy(
               LifespanPolicyValue.PERSISTENT),
            bsPolicy
         };

         // Create managerPOA with the right policies
         POA serverPoa = rootPoa.create_POA(
           "serverPoa", rootPoa.the_POAManager(), policies);

         // Resolve Dynamic Any Factory
         DynAnyFactory factory =
            DynAnyFactoryHelper.narrow(
            orb.resolve_initial_references("DynAnyFactory"));

         byte[ ] oid = "PrinterManager".getBytes();

         // Create the printer manager object.
         PrinterManagerImpl manager = new PrinterManagerImpl(
            (com.inprise.vbroker.CORBA.ORB)orb,
            factory, serverPoa, oid);

         // Export the newly create object.

         serverPoa.activate_object_with_id(oid, manager);

         System.out.println(manager + "is ready.");
   // Wait for incoming requests
         orb.run();
      }
      catch (Exception e) {
         e.printStackTrace();
      }
   }
}

コードサンプル24-8は，PrinterManagerインプリメンテーションが，次の手順で，コンパイル時にAnyが含む型を知らないで，DynAnyを使ってAnyオブジェクトを処理する様子を示します。

DynAnyオブジェクトを生成し，受け取ったAnyで初期化します。

DynAnyオブジェクトタイプに対してswitchを実行します。

DynAnyが基本データ型を含む場合，値を出力します。

DynAnyがAny 型を含む場合，Any用にDynAnyを生成し，内容を確定し，値を出力します。

DynAnyがenumを含む場合，enum用にDynEnumを生成し，文字列値を出力します。

DynAnyがunionを含む場合，union用にDynUnionを生成し，unionの識別子とメンバを出力します。

DynAnyがstruct，array，またはsequenceを含む場合，含まれるコンポーネント間を移動し，各値を出力します。

コードサンプル24-8　PrinterManagerのインプリメンテーション（C++）

// PrinterManager Implementation
class PrinterManagerImpl : public POA_Printer::PrinterManager
{
   CORBA::ORB_var           _orb;
   DynamicAny::DynAnyFactory_var   _factory;
   PortableServer::POA_var         _poa;
   PortableServer::ObjectId_var    _oid;

public:
   PrinterManagerImpl(CORBA::ORB_ptr orb,
      DynamicAny::DynAnyFactory_ptr DynAnyFactory,
      PortableServer::POA_ptr poa,
      PortableServer::ObjectId_ptr oid
      ) : _orb(orb), _factory(DynAnyFactory),
          _poa(poa), _oid(oid) {}

   void printAny(const CORBA::Any& info) {
   try {
      // Create a DynAny object
      DynamicAny::DynAny_var dynAny =
          _factory->create_dyn_any(info); display(dynAny);
   }
   catch (CORBA::Exception& e) {
      cout << "Unable to create Dynamic Any from factory"
            << endl;
   }
}
   void shutdown() {
   try {
      _poa->deactivate_object(_oid);
       cout << "Server shutting down..." << endl;
      _orb->shutdown(0UL);
   }
catch (const CORBA::Exception& e){
   cout << e << endl;
   }
}

void display(DynamicAny::DynAny_var value) {
   switch(value->type()->kind()) {
   case CORBA::tk_null:
    case CORBA::tk_void: {
     break;
    }
    case CORBA::tk_short: {
      cout << value->get_short() << endl;
      break;
   }
   case CORBA::tk_ushort: {
     cout << value->get_ushort() << endl;
     break;
    }
   case CORBA::tk_long: {
   cout << value->get_long() << endl;
   break;
   }
   case CORBA::tk_ulong: {
    cout << value->get_ulong() << endl;
    break;
   }
   case CORBA::tk_float: {
     cout << value->get_float() << endl;
     break;
   }
   case CORBA::tk_double: {
     cout << value->get_double() << endl;
     break;
   }
   case CORBA::tk_boolean: {
     cout << value->get_boolean() << endl;
     break;
   }
   case CORBA::tk_char: {
     cout << value->get_char() << endl;
     break;
   }
   case CORBA::tk_octet: {
     cout << value->get_octet() << endl;
     break;
   }
   case CORBA::tk_string: {
     cout << value->get_string() << endl;
     break;
   }
   case CORBA::tk_any: {
     DynamicAny::DynAny_var dynAny =
          _factory->create_dyn_any(*(value->get_any()));
     display(dynAny);
     break;
   }
   case CORBA::tk_TypeCode: {
     cout << value->get_typecode() << endl;
     break;
   }
   case CORBA::tk_objref: {
     cout << value->get_reference() << endl;
     break;
   }
   case CORBA::tk_enum: {
     DynamicAny::DynEnum_var dynEnum =
           DynamicAny::DynEnum::_narrow(value);
     cout << dynEnum->get_as_string() << endl;
     break;
   }
   case CORBA::tk_union: {
     DynamicAny::DynUnion_var dynUnion =
           DynamicAny::DynUnion::_narrow(value);
      display(dynUnion->get_discriminator());
      display(dynUnion->member());
      break;
      }
      case CORBA::tk_struct:
      case CORBA::tk_array:
      case CORBA::tk_sequence: {
        value->rewind();
      CORBA::Boolean next = 1UL;
        while(next) {
        DynamicAny::DynAny_var d =
              value->current_component();
          display(d);
          next =value->next();
        }
        break;
      }
      case CORBA::tk_longlong: {
        cout << value->get_longlong() << endl;
        break;
      }
      case CORBA::tk_ulonglong: {
        cout << value->get_ulonglong() << endl;
        break;
      }
      case CORBA::tk_wstring: {
        cout << value->get_wstring() << endl;
        break;
      }
      case CORBA::tk_wchar: {
        cout << value->get_wchar() << endl;
        break;
      }
      default:
        cout << "Invalid Type" << endl;
      }
   }
};

コードサンプル24-9　PrinterManagerのインプリメンテーション（Java）

// PrinterManagerImpl.java

import java.util.*;
import org.omg.DynamicAny.*;
import org.omg.PortableServer.*;

public class PrinterManagerImpl extends
                              Printer.PrinterManagerPOA {
   private com.inprise.vbroker.CORBA.ORB _orb;
   private DynAnyFactory _factory;
   private POA _poa;
   private byte[ ] _oid;

   public PrinterManagerImpl(
         com.inprise.vbroker.CORBA.ORB orb,
         DynAnyFactory factory, POA poa, byte[ ] oid) {
      _orb = orb;
      _factory = factory;
      _poa = poa;
      _oid = oid;
   }

   public synchronized void printAny(org.omg.CORBA.Any info) {
      // Display info with the assumption that we don't have
      // any info statically about the type inside the any

   try {
      // Create a DynAny object
      DynAny dynAny = _factory.create_dyn_any(info);
      display(dynAny);
   }
   catch (Exception e) {
      e.printStackTrace();
   }

}

public void shutdown() {
   try {
      _poa.deactivate_object(_oid);
      System.out.println("Server shutting down");
      _orb.shutdown(false);
   }
   catch (Exception e) {
      System.out.println(e);
   }
}

private void display(DynAny value) throws Exception {
   switch(value.type().kind().value()) {
      case org.omg.CORBA.TCKind._tk_null:
      case org.omg.CORBA.TCKind._tk_void: {
         break;
      }
      case org.omg.CORBA.TCKind._tk_short: {
         System.out.println(value.get_short());
         break;
      }
      case org.omg.CORBA.TCKind._tk_ushort: {
         System.out.println(value.get_ushort());
         break;
      }
      case org.omg.CORBA.TCKind._tk_long: {
         System.out.println(value.get_long());
         break;
      }
      case org.omg.CORBA.TCKind._tk_ulong: {
         System.out.println(value.get_ulong());
         break;
      }
      case org.omg.CORBA.TCKind._tk_float: {
         System.out.println(value.get_float());
         break;
      }
      case org.omg.CORBA.TCKind._tk_double: {
         System.out.println(value.get_double());
         break;
      }
      case org.omg.CORBA.TCKind._tk_boolean: {
         System.out.println(value.get_boolean());
         break;
      }
      case org.omg.CORBA.TCKind._tk_char: {
         System.out.println(value.get_char());
         break;
      }
      case org.omg.CORBA.TCKind._tk_octet: {
         System.out.println(value.get_octet());
         break;
      }
      case org.omg.CORBA.TCKind._tk_string: {
         System.out.println(value.get_string());
         break;
      }
      case org.omg.CORBA.TCKind._tk_any: {
         DynAny dynAny =
               _factory.create_dyn_any(value.get_any());
         display(dynAny);
         break;
      }
      case org.omg.CORBA.TCKind._tk_TypeCode: {
         System.out.println(value.get_typecode());
         break;
      }
      case org.omg.CORBA.TCKind._tk_objref: {
         System.out.println(value.get_reference());
         break;
      }
      case org.omg.CORBA.TCKind._tk_enum: {
         DynEnum dynEnum = DynEnumHelper.narrow(value);
         System.out.println(dynEnum.get_as_string());
         break;
      }
      case org.omg.CORBA.TCKind._tk_union: {
         DynUnion dynUnion = DynUnionHelper.narrow(value);
         display(dynUnion.get_discriminator());
         display(dynUnion.member());
         break;
      }
      case org.omg.CORBA.TCKind._tk_struct:
      case org.omg.CORBA.TCKind._tk_array:
      case org.omg.CORBA.TCKind._tk_sequence: {
         value.rewind();
         boolean next = true;
         while(next) {
            DynAny d = value.current_component();
            display(d);
            next = value.next();
         }
         break;
      }
      case org.omg.CORBA.TCKind._tk_longlong: {
         System.out.println(value.get_longlong());
         break;
      }
      case org.omg.CORBA.TCKind._tk_ulonglong: {
         System.out.println(value.get_ulonglong());
         break;
      }
      case org.omg.CORBA.TCKind._tk_wstring: {
         System.out.println(value.get_wstring());
         break;
      }
      case org.omg.CORBA.TCKind._tk_wchar: {
         System.out.println(value.get_wchar());
         break;
      }
      default:
         System.out.println("Invalid type");

      }
   }
}

25　valuetypeの使用

この章では，Borland Enterprise Server VisiBrokerのvaluetype IDL型の使用方法を説明します。

25.1　valuetypeとは

IDLのvaluetypeは，ネットワーク越しに状態データを渡す際に使用されます。valuetypeは，継承とメソッドを持つstructと考えることができます。valuetypeは通常のインタフェースとは異なり，valuetypeの状態を記述するプロパティを含み，インタフェース以外にインプリメンテーションの詳細も含みます。次のIDLコードは単純なvaluetypeを宣言します。

IDLサンプル25-1　単純なvaluetype IDL

module Map {
   valuetype Point {
      public long x;
      public long y;
      private string label;
      factory create ( in long x, in long y, in string z);
      void print();
   };
};

valuetypeは，常にローカルなものです。valuetypeはVisiBroker ORBに登録されることもなく，一意の識別子も必要ありません。それはvaluetypeの値自体が識別子のためです。valuetypeはリモートで呼び出すことはできません。

25.1.1　concrete valuetype

concrete valuetypeには，状態データがあります。次のように通常のIDLの表現形式を拡張したものです。

一つのconcrete valuetypeの派生および複数のabstract valuetypeの派生

複数のインタフェースのサポート（一つのconcreteおよび複数のabstract）

任意の再帰的なvaluetypeの定義

ヌルセマンティクス

共用セマンティクス

(1)　valuetypeの派生

concrete valuetypeを別のconcrete valuetypeから派生させることができますが，valuetypeは，別の複数のabstract valuetypeから派生させることもできます。

(2)　共用セマンティクス

valuetypeインスタンスは，別のインスタンスのvaluetypeと共用できます。struct，union，またはsequenceのようなほかのIDLデータ型は共用できません。共用されるvaluetypeは，送信コンテキストおよび受信コンテキスト間で同じ型です。

さらに，同じvaluetypeが複数の引数のオペレーションに渡されると，受信コンテキストは両方の引数の同じvaluetypeリファレンスを受け取ります。

(3)　ヌルセマンティクス

ヌルvaluetypeは，struct，union，sequenceのようなIDLデータ型と異なり，ネットワーク越しに渡せます。例えば，structをボックス型valuetypeとしてボックス化すると，ヌル値structを渡せます。詳細については，「25.4　ボックス型 valuetype」を参照してください。

(4)　ファクトリ

ファクトリは，移植性のあるvaluetypeを生成するために，valuetypeで宣言できるメソッドです。ファクトリの詳細については，「25.3　ファクトリのインプリメント」を参照してください。

25.1.2　abstract valuetype

abstract valuetypeにはメソッドだけがあり，状態はありません。abstract valuetypeは実体化できません。abstract valuetypeは，単にローカルインプリメンテーションのあるオペレーションのシグニチャの固まりです。

例えば，次のIDLは状態を含みませんが，一つのメソッドget_nameを含むabstract valuetype Accountを定義します。

abstract valuetype Account{
   string get_name();
}

ここで，二つのvaluetypeが定義されます。これはabstract valuetypeからget_nameメソッドを継承します。

valuetype savingsAccount:Account{
   private long balance;
}
valuetype checkingAccount:Account{
   private long balance;
}

これら二つのvaluetypeには変数balanceがあり，abstract valuetype Accountからget_nameメソッドを継承します。

25.2　valuetypeのインプリメント

アプリケーションでvaluetypeをインプリメントするには，次の手順を行います。

IDLファイルでvaluetypeを定義します。

次のコンパイラを使用してIDLファイルをコンパイルします。

C++の場合

idl2cpp

Javaの場合

idl2java

valuetypeベースクラスを継承してvaluetypeをインプリメントします。

IDLで定義したファクトリメソッドをインプリメントするためにFactoryクラスをインプリメントします。

create_for_unmarshalメソッドをインプリメントします。

C++の場合，FactoryをVisiBroker ORBに登録します。

Javaの場合，必要であれば，FactoryをORBに登録します。

_add_ref，_remove_ref，_ref_countvalueメソッドをインプリメントするか，またはCORBA::DefaultValueRefCountBaseから派生させます。

25.2.1　valuetypeの定義

IDLサンプル25-1では，Pointという名前のvaluetypeを定義します。このvaluetypeはグラフのポイントを定義します。これには，二つのパブリック変数（x座標とy座標），ポイントのラベルであるプライベート変数一つ，valuetypeのファクトリ，およびポイントを出力する出力メソッドがあります。

25.2.2　IDLファイルのコンパイル

これでIDLを定義できたので，C++ソースファイルを作成するためにidl2cppを使用してコンパイルするか，またはC++ソースファイルを作成するためにidl2javaを使用してコンパイルします。これによって，valuetypeをインプリメントするために修正するJavaソースファイルが作成されます。上記のIDLをコンパイルすると，出力は次のファイルで構成されます。

C++の場合

Map_c.cc

Map_c.hh

Map_s.cc

Map_s.hh

Javaの場合

Point.java

PointDefaultFactory.java

PointHelper.java

PointHolder.java

PointValueFactory.java

25.2.3　valuetypeベースクラスの継承

IDLのコンパイル後，valuetypeのインプリメンテーションを作成します。インプリメンテーションクラスは，ベースクラスを継承します。このクラスには，ValueFactoryで呼び出されたコンストラクタがあり，IDLで宣言された変数とメソッドのすべてを含んでいます。

例えばobv¥PntImpl.hでは，コードサンプル25-1で示すようにPointImplクラスはIDLから生成されたPointクラスを継承します。

例えばobv¥PointImpl.javaでは，コードサンプル25-2で示すようにPointImplクラスはIDLから生成されたPointクラスを継承します。

コードサンプル25-1　valuetypeベースクラスの継承（C++）

class PointImpl : public Map::OBV_Point,
      public CORBA::DefaultValueRefCountBase {
   public:
      PointImpl(){}
      virtual ~PointImpl(){}
      CORBA_ValueBase* _copy_value() {
         return new PointImpl(x(), y(),
               new Map::Label(CORBA::string_dup(label())));
      }
      PointImpl( CORBA::Long x, CORBA::Long y,
            Map::Label_ptr label )
            : OBV_Point( x,y,label->_boxed_in())
      {}
      virtual void print() {
         cout << "Point is [" << label() << ": ("
            << x() << ", " << y() << ")]" << endl << endl;
      }
};

コードサンプル25-2　valuetypeベースクラスの継承（Java）

public class PointImpl extends Point {
   public PointImpl() {}
   public PointImpl(int a_x, int a_y, String a_label) {
      x = a_x;
      y = a_y;
      label = a_label;
   }
   public void print() {
      System.out.println("Point is [" + label +
                         ": (" + x + ", " + y + ")]");
   }
}

25.2.4　Factoryクラスのインプリメント

これでインプリメンテーションクラスを生成したので，valuetypeのFactoryをインプリメントします。

次に示すサンプルでは，生成されたPoint_initクラスにはIDLで宣言されたcreateメソッドがあります。このクラスはCORBA::ValueFactoryBase（C++）またはorg.omg.CORBA.portable.ValueFactory（Java）を継承します。コードサンプル25-3および25-4で示すようにPointDefaultFactoryクラスはPointValueFactoryをインプリメントします。

コードサンプル25-3　Factoryクラスのインプリメント（C++）

class PointFactory: public CORBA::ValueFactoryBase {
   public:
      PointFactory(){}
      virtual ~PointFactory(){}
      CORBA::ValueBase* create_for_unmarshal() {
         return new PointImpl();
      }
};

C++の場合，Point_initには，パブリックメソッドであるcreate_for_unmarshalがあり，これはMap_c.hhの純仮想メソッドとして出力されます。ユーザはPoint_initからクラスを派生させ，create_for_unmarshalメソッドをインプリメントしてFactoryクラスを生成する必要があります。IDLファイルをコンパイルする場合，IDLファイル用のスケルトンクラスを生成しません。

コードサンプル25-4　Factoryクラスのインプリメント（Java）

public class PointDefaultFactory implements
                                       PointValueFactory {
   public java.io.Serializable read_value (
                  org.omg.CORBA.portable.InputStream is) {
      java.io.Serializable val =
          new PointImpl(); // Called the implementation class
      // create and initialize value
      val = ((org.omg.CORBA_2_3.portable.InputStream)is).
                                          read_value(val);
      return val;
   }
   // It is up to the user to implement the valuetype
   // however they want:
   public Point create (int x,
         int y,
         java.lang.String z) {
      //IMPLEMENT:
      return null;
   }
}

新しいvaluetypeを作成するためにPointImpl()が呼び出されます。新しいvaluetypeは，read_valueによってInputStreamから読み込まれます。

注（Javaの場合）

ユーザはread_valueを呼び出す必要があります。これを呼び出さないと，ファクトリが動作しないで，ほかのどのメソッドも呼び出せません。

25.2.5　VisiBroker ORBへのFactoryの登録

(1)　C++の場合

ORB::register_value_factoryを呼び出して，VisiBroker ORBにFactoryを登録します。ファクトリの登録の詳細については，「25.3.2　valuetypeの登録」を参照してください。

(2)　Javaの場合

ORB.register_value_factoryを呼び出して，VisiBroker ORBにFactoryを登録します。これは，ファクトリにvaluetypenameDefaultFactoryという名前を付けない場合だけ必要です。ファクトリの登録の詳細については，「25.3.2　valuetypeの登録」を参照してください。

25.3　ファクトリのインプリメント

VisiBroker ORBがvaluetypeを受け取ると，まずデマーシャルする必要があります。それから，その型の適切なファクトリを，その型の新しいインスタンスを生成するために見つけなければなりません。インスタンスが生成されたら，値データはインスタンスにアンマーシャルされます。その型は呼び出しのときに渡されるRepositoryIDによって識別されます。型とファクトリ間のマッピングは，言語固有です。

コードサンプル25-5および25-6に，JDK1.2を使用したPoint valuetypeのファクトリのサンプルインプリメンテーションを示します。

コードサンプル25-5　Point valuetypeのファクトリ（C++）

class PointFactory: public CORBA::ValueFactoryBase
{
public:
   PointFactory(){}
   virtual ~PointFactory(){}
   CORBA::ValueBase* create_for_unmarshal() {
      return new PointImpl();
   }
};

コードサンプル25-6　Point valuetypeのファクトリ（Java）

public class PointDefaultFactory implements
                                          PointValueFactory {
   public java.io.Serializable read_value(
                     org.omg.CORBA.portable.InputStream is) {
   java.io.Serializable val = new PointImpl();
   // create and initialize value
   // It is very important that this call is made.
   val = ((org.omg.CORBA_2_3.portable.InputStream)is).
                                             read_value(val);
   return val;
   }
   public Point create (int x, int y, java.lang.String z) {
      // IMPLEMENT:
   return NO_IMPLEMENT;
   }
}

Borland Enterprise Server VisiBroker 4.5以降のバージョンは，JDK 1.2またはJDK 1.3のデフォルト値ファクトリメソッドの正しいシグニチャを生成します。既存（Borland Enterprise Server VisiBroker 4.0）の生成コードは，次のようにデフォルト値ファクトリメソッドシグニチャを修正しないかぎり，JDK 1.3で実行するように設計されていません。既存のコードをJDK 1.3で使用し，デフォルト値ファクトリを修正しないと，コードはコンパイルされません。またはNO_IMPLEMENT例外が発生します。したがって，正しいシグニチャを生成するにはコードを再生成することをお勧めします。

次のコードサンプルに，JDK 1.3でコンパイルできるようにデフォルト値ファクトリメソッドシグニチャを修正する方法を示します。

コードサンプル25-7　JDK 1.3コード生成でのメソッドシグニチャを示すファクトリコード（C++）

class PointFactory: public CORBA::ValueFactoryBase
{
public:
   PointFactory(){}
   virtual ~PointFactory(){}
   CORBA::ValueBase* create_for_unmarshal() {
      return new PointImpl();
   }
};

コードサンプル25-8　JDK 1.3コード生成でのメソッドシグニチャを示すファクトリコード（Java）

public class PointDefaultFactory implements
                                          PointValueFactory {
   public java.io.Serializable read_value (
               org.omg.CORBA_2_3.portable.InputStream is) {
   java.io.Serializable val = new PointImpl();
   // create and initialize value
   // It is very important that this call is made.
   val = ((org.omg.CORBA_2_3.portable.InputStream)is).
                                             read_value(val);
   return val;
   }
   public Point create (int x, int y, java.lang.String z) {
      // IMPLEMENT:
   return NO_IMPLEMENT;
   }
}

25.3.1　ファクトリとvaluetype

VisiBroker ORBがvaluetypeを受け取ると，その型のファクトリを探します。ファクトリ名がvaluetypeDefaultFactoryのファクトリを探します。例えば，Point valuetypeのファクトリはPointDefaultFactoryになります。正しいファクトリがこのネーミングスキーマ（valuetypeDefaultFactory）に準拠しない場合，正しいファクトリを登録し，VisiBroker ORBがvaluetypeのインスタンスを生成できるようにする必要があります。

VisiBroker ORBが指定のvaluetypeの正しいファクトリを見つけられない場合，MARSHAL例外が発生し，マイナーコードを示します。

25.3.2　valuetypeの登録

それぞれの言語マッピングによって，登録の方法とタイミングを指定します。valuetypeDefaultFactoryネーミング規則によってファクトリを生成した場合，そのファクトリは暗黙的に登録されるので，VisiBroker ORBにファクトリを明示的に登録する必要はありません。

valuetypeDefaultFactoryネーミング規則に準拠しないファクトリを登録するには，register_value_factoryを呼び出します。ファクトリの登録を解除するには，VisiBroker ORBでunregister_value_factoryを呼び出します。また，VisiBroker ORBでlookup_value_factoryを呼び出して，登録されたvaluetypeファクトリを探すこともできます。

25.4　ボックス型 valuetype

ボックス型valuetypeは，値の定義がないIDLデータ型をvaluetypeとしてラッピングできるものです。例えば，IDLボックス型valuetype宣言（valuetype Label string;）は，次のIDL valuetype宣言と同じです。

valuetype Label{
   public string name;
}

ほかのデータ型をvaluetypeとしてボックス化することによって，ユーザはvaluetypeのヌルセマンティクスと共用セマンティクスを使用できます。

valueboxは，生成されたコードだけでインプリメントされます。ユーザは特殊なコードを追加する必要はありません。

25.5　abstractインタフェース

abstractインタフェースは，オブジェクトを値渡しするのか参照渡しするのかを実行時に選択できるインタフェースです。

abstractインタフェースはIDLインタフェースとは次の点で異なります。

実際のパラメタ型は，オブジェクトがリファレンスによって渡されるか，valuetypeが渡されるかを決めます。このパラメタ型は二つのルールに基づいて決められます。パラメタ型が通常のインタフェース型，またはサブタイプの場合，インタフェース型がabstractインタフェース型のシグニチャのサブタイプの場合，およびオブジェクトがすでにVisiBroker ORBに登録されている場合は，オブジェクトリファレンスとして処理されます。また，パラメタ型がオブジェクトリファレンスとして渡すことはできませんが，値として渡せる場合は，値として処理されます。値として渡すのに失敗すると，BAD_PARAM例外が発生します。

abstractインタフェースはCORBA::Object（C++）またはorg.omg.CORBA.Object（Java）から暗黙的に派生しません。それは，abstractインタフェースがオブジェクトリファレンスかvaluetypeのどちらかを表すためです。valuetypeは，必ずしも共通オブジェクトリファレンスオペレーションをサポートする必要はありません。abstractインタフェースのオブジェクトリファレンス型へのナロウに成功したら，CORBA::Object（C++）またはorg.omg.CORBA.Object（Java）のオペレーションを呼び出せます。

abstractインタフェースはほかのabstractインタフェースだけから継承できます。

valuetypeは，複数のabstractインタフェースをサポートできます。

例えば，次のabstractインタフェースについて次に示します。

IDLサンプル25-2　abstractインタフェースIDL

abstract interface ai{
};
interface itp : ai{
};
valuetype vtp supports ai{
};
interface x {
   void m(ai aitp);
};
valuetype y {
   void op(ai aitp);
};

メソッドmの引数では

itpは常に，オブジェクトリファレンスとして渡されます。

vtpは値として渡されます。

25.6　custom valuetype

IDLでcustom valuetypeを宣言することによって，デフォルトのマーシャルモデルとアンマーシャルモデルをスキップできますが，ユーザはエンコーディングとデコーディングの責任を負います。

IDLサンプル25-3　custom valuetype IDL

custom valuetype customPoint{
   public long x;
   public long y;
   private string label;
   factory create(in long x, in long y, in string z);
};

ユーザは，CustomMarshalインタフェースからマーシャルおよびアンマーシャルメソッドをインプリメントする必要があります。

C++の場合

custom valuetypeを宣言する場合，正規のvaluetypeであるCORBA::StreamableValueとは対照的に，valuetypeはCORBA::CustomValueを継承します。コンパイラは，ユーザのvaluetype用の読み込みメソッド，書き込みメソッドを生成しません。

ユーザは，値の読み込み，書き込みを行うためにCORBA::DataInputStreamとCORBA::DataOutputStreamをそれぞれ使用して自分の読み込みメソッド，書き込みメソッドをインプリメントする必要があります。

Javaの場合

custom valuetypeを宣言する場合，正規のvaluetypeであるorg.omg.CORBA.portable.StreamableValueとは対照的に，valuetypeはorg.omg.CORBA.portable.CustomValueを継承します。コンパイラは，ユーザのvaluetype用の読み込みメソッド，書き込みメソッドを生成しません。

ユーザは，値の読み込み，書き込みを行うためにorg.omg.CORBA.portable.DataInputStreamとorg.omg.CORBA.portable.DataOutputStreamをそれぞれ使用して自分の読み込みメソッド，書き込みメソッドをインプリメントする必要があります。

25.7　truncatable valuetype

truncatable valuetypeによって，ユーザは継承したvaluetypeをその親として処理できます。

次のIDLは，ベースタイプAccountから継承したvaluetype checkingAccountを定義しています。また，valuetype checkingAccountは受信オブジェクトをtruncateできます。

valuetype checkingAccount: truncatable Account{
   private long balance;
}

これは，派生したvaluetypeで受信コンテキストが新しいデータメンバやメソッドを必要としない場合や，受信コンテキストが派生したvaluetypeを認識していない場合に役立ちます。しかし，親データ型に存在しないvaluetypeから派生した状態データは，valuetypeが受信コンテキストに渡されると失われます。

注

custom valuetypeをtruncatableにはできません。

26　URLネーミングの使用

この章では，URLネーミングサービスを使用してURLをオブジェクトのIORに対応させる方法について説明します。いったんURLがオブジェクトにバインドされると，クライアントアプリケーションはオブジェクト名の代わりにそのURLを文字列として指定することによって，そのオブジェクトのリファレンスを取得できます。osagentもCORBAネーミングサービスも使用しないでオブジェクトの場所をクライアントアプリケーションで探したい場合は，代わりにURLを指定する方法があります。

なお，詳細の説明はJavaについてのものだけです。

26.1　URLネーミングサービス

URLネーミングサービスは，サーバオブジェクトにそのIORをファイル内の文字列の形式でURLに対応させる簡単な方式です。クライアントプログラムはWebサーバ上の文字列化されたURLを含むファイルを指しているURLを使用して，そのオブジェクトの場所を探せます。URLネーミングサービスは，オブジェクト登録用のhttp URL体系や，JavaランタイムがサポートするURL体系（http:，ftp:，file:のようなURLによるオブジェクトの探索用）をサポートします。

このURLネームサービスは，スマートエージェントまたはCORBA ネーミングサービスを使用しないでオブジェクトの場所を探す方法を提供します。これによって，クライアントアプリケーションはベンダが提供したオブジェクトの場所を探せます。このサービスのIDL仕様をIDLサンプル26-1に示します。

注

Borland Enterprise Server VisiBrokerのURLネーミングサービスは，Java環境がサポートするすべてのURL処理形式をサポートします。

IDLサンプル26-1　WebNamingモジュール

// WebNaming.idl
#pragma prefix "inprise.com"
module URLNaming {
   exception InvalidURL{string reason;};
   exception CommFailure{string reason;};
   exception ReqFailure{string reason;};
   exception AlreadyExists{string reason;};
   abstract interface Resolver {
   // Read Operations
      Object locate(in string url_s)
         raises (InvalidURL, CommFailure, ReqFailure);
   // Write Operations
      void force_register_url(in string url_s, in Object obj)
         raises (InvalidURL, CommFailure, ReqFailure);
      void register_url(in string url_s, in Object obj)
         raises (InvalidURL, CommFailure, ReqFailure,
                 AlreadyExists);
   };
};

26.2　オブジェクトの登録

オブジェクトサーバは，まずResolverにバインドし，次にregister_urlメソッドまたはforce_register_urlメソッドを使用してURLをオブジェクトのIORに対応させることによってオブジェクトを登録します。まだURLがオブジェクトのIORに対応づけがされていなければ対応させるためにregister_urlを使用します。force_register_urlメソッドを使用すると，URLがオブジェクトにバインドされていてもいなくても，URLをそのオブジェクトのIORに対応させます。これに対して同じ状況でregister_urlメソッドを使用すると，AlreadyExists例外が発生します。利用できるすべてのメソッドについては，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「URLネーミングインタフェースとクラス（Java）」の記述を参照してください。

サーバ側でのこの機能の使用例については，コードサンプル26-1を参照してください。ここに示すサンプルでは，force_register_urlを使用しています。force_register_urlが成功するには，WebサーバによってHTTP PUTコマンドの発行が許可されている必要があります。この章で示すサンプルのコードは，Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/basic下のbank_URLに入っています。

注

Resolverのリファレンスを取得するには，サンプルに示すようにVisiBroker ORBのresolve_initial_referencesメソッドを使用します。

コードサンプル26-1　URLとオブジェクトのIORの対応

. . .
public class Server {
   public static void main(String[ ] args) {
      if (args.length == 0) {
         System.out.println("Usage: vbj Server <URL string>");
         return;
      }
      String url = args[0];
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                        org.omg.CORBA.ORB.init(args,null);
         // get a reference to the rootPOA
         POA rootPOA = POAHelper.narrow(
                  orb.resolve_initial_references("RootPOA"));
         // Create the servant
         AccountManagerImpl managerServant =
                                    new AccountManagerImpl();
         // Decide on the ID for the servant
         byte[ ] managerId = "BankManager".getBytes();
         // Activate the servant with the ID on myPOA
         rootPOA.activate_object_with_id(managerId,
                                         managerServant);

         // Activate the POA manager
         rootPOA.the_POAManager().activate();
         // Create the object reference
         org.omg.CORBA.Object manager =
                rootPOA.servant_to_reference(managerServant);
         // Obtain the URLNaming Resolver
         Resolver resolver = ResolverHelper.narrow(
            orb.resolve_initial_references(
               "URLNamingResolver"));
         // Register the object reference (overwrite
         // if exists)
         resolver.force_register_url(url, manager);
         System.out.println(manager + " is ready.");
         // Wait for incoming requests
         orb.run();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

このコードサンプルでは，args[0]は次の形式になっています。

例

http://<host_name>:<http_server_port>/
                      <ior_file_path>/<ior_file_name>

ior_file_nameは，文字列化されたオブジェクトリファレンスが格納されているユーザ指定のファイル名です。ior_file_nameの接尾語は，ゲートキーパーがHTTPサーバの代わりに使用される場合は.iorである必要があります。ゲートキーパーとそのデフォルトのポート番号を使用した例は次のとおりです。

例

http://mars:15000/URLNaming/Bank_Manager.ior

26.3　URLによるオブジェクトの検索

クライアントアプリケーションはResolverにバインドする必要はなく，コードサンプル26-2に示すようにbind()メソッドの呼び出し時にURLを指定するだけです。バインドはURLをオブジェクト名として受け取ります。URLが無効な場合はInvalidURL例外が発生します。bind()メソッドは透過的にlocate()メソッドを呼び出します。locate()メソッドの使用例については，コードサンプル26-3を参照してください。

コードサンプル26-2　URLの指定によるオブジェクトリファレンスの取得

// ResolverClient.java
import com.inprise.vbroker.URLNaming.*;
public class ResolverClient {
   public static void main(String[ ] args) {
      if (args.length == 0) {
         System.out.println(
            "Usage: vbj Client <URL string> [Account name]");
         return;
      }
      String url = args[0];
      try {
         // Initialize the ORB.
         org.omg.CORBA.ORB orb =
                           org.omg.CORBA.ORB.init(args,null);
         // Obtain the URLNaming Resolver
         Resolver resolver = ResolverHelper.narrow(
            orb.resolve_initial_references(
               "URLNamingResolver"));
         // Locate the object
         Bank.AccountManager manager =
         Bank.AccountManagerHelper.
                                narrow(resolver.locate(url));
         // use args[0] as the account name, or a default.
         String name = args.length > 1 ?
                                    args[1] : "Jack B. Quick";
         // Request the account manager to open a named
         // account.
         Bank.Account account = manager.open(name);
         // Get the balance of the account.
         float balance = account.balance();
         // Print out the balance.
         System.out.println("The balance in " + name +
                            "'s account is $" + balance);
      } catch(Exception e) {
         e.printStackTrace();
      }
   }
}

コードサンプル26-3　Resolver.locateメソッドの使用によるオブジェクトリファレンスの取得

// Client.java
public class Client {
   public static void main(String[ ] args) {
      if (args.length == 0) {
         System.out.println(
            "Usage: vbj Client <URL string> [Account name ]");
         return;
      }
      String url = args[0];
      // Initialize the ORB.
      org.omg.CORBA.ORB orb =
                           org.omg.CORBA.ORB.init(args,null);
      // Locate the object
      Bank.AccountManager manager =
                    Bank.AccountManagerHelper.bind(orb, url);
      // use args[0] as the account name, or a default.
      String name = args.length > 1 ?
                                    args[1] : "Jack B. Quick";
      // Request the account manager to open a named account.
      Bank.Account account = manager.open(name);
      // Get the balance of the account.
      float balance = account.balance();
      // Print out the balance.
      System.out.println("The balance in " + name +
                         "'s account is $" + balance);
   }
}

27　双方向通信

この章では，ゲートキーパーを使用しないでBorland Enterprise Server VisiBrokerで双方向コネクションを設定する方法を説明します。ゲートキーパーを使用する双方向通信については，マニュアル「Borland Enterprise Server VisiBroker　ゲートキーパーガイド」を参照してください。

ただし，双方向IIOPを有効にする前に，「27.6　セキュリティの考慮事項」を参照してください。

27.1　双方向IIOPの使用

インターネットによって情報交換を行うほとんどのクライアントとサーバは，一般に共同のファイアウォールによって保護されています。リクエストがクライアントだけによって開始されるシステムでは，通常クライアントにとってファイアウォールの存在は透過的です。しかし，クライアントが非同期で情報を必要とする場合があります。すなわち，リクエストに対する応答としてではなく情報が到着する必要がある場合です。クライアント側のファイアウォールは，サーバがクライアントにコネクションを戻さないようにします。そのため，クライアントが非同期情報を受け取るためには，通常，拡張構成が必要です。

GIOPおよびBorland Enterprise Server VisiBrokerの従来のバージョンでは，サーバがクライアントに非同期情報を送信できる唯一の方法はクライアント側のゲートキーパーを使用してサーバからのコールバックを処理する方法でした。

非同期情報をクライアントに返送する必要がある場合にクライアントに対して個別のオープンなコネクションをサーバが持つのではなく（どちらにしても，これはクライアント側のファイアウォールに拒否される），双方向IIOPを使用すれば，サーバはクライアント起動コネクションを使用してクライアントに情報を送信します。また，CORBAの仕様はこの機能をポータブルに制御するための新しいポリシーも追加します。

双方向IIOPによってゲートキーパーなしでコールバックが設定できるので，クライアントの配置が非常に楽になります。

27.2　双方向VisiBroker ORBのプロパティ

次に示すの三つのプロパティが双方向をサポートします。

vbroker.orb.enableBiDir=client|server|both|none

vbroker.se.<se-name>.scm.<scm-name>.manager.exportBiDir=true|false

vbroker.se.<se-name>.scm.<scm-name>.manager.importBiDir=true|false

27.2.1　vbroker.orb.enableBiDirプロパティ

vbroker.orb.enableBiDirプロパティは，サーバおよびクライアントの両方で使用され，双方向通信が可能になります。このプロパティによって，ユーザはコードをまったく変更しないで，既存の一方向アプリケーションを双方向アプリケーションに変更できます。vbroker.orb.enableBiDirプロパティは表27-1に示す値に設定できます。

表27‒1　vbroker.orb.enableBiDirプロパティの設定値

値

説明

client

すべてのPOAおよびすべての出力コネクションで双方向IIOPを有効にします。この設定は，bothに対してBiDirectionalポリシーを設定してすべてのPOAを作成すること，およびVisiBroker ORBレベルでbothに対してBiDirectionalポリシーの変更を設定することと同じです。さらに，どのSCMでもexportBiDirプロパティがtureに設定されているかのように，生成されたSCMのすべては双方向コネクションを許可します。

server

サーバが双方向のコネクションを受け付けて，それを使用できるようになります。これは，すべてのSCMでimportBiDirプロパティをtrueに設定するのと同じです。

both

ClientとServerの両方にプロパティを設定します。

none

双方向GIOPを全体的に無効にします。これはデフォルト値です。

27.2.2　vbroker.se.<se-name>.scm.<scm-name>.manager.exportBiDirプロパティ

vbroker.se.<se-name>.scm.<scm-name>.manager.exportBiDirプロパティは，クライアント側のプロパティです。デフォルトでは，VisiBroker ORBによって何も設定されていません。これをtrueに設定すると，指定のサーバエンジンで双方向コールバックPOAの作成ができるようになります。

falseに設定すると，指定のサーバエンジンで双方向POAの作成ができなくなります。

27.2.3　vbroker.se.<se-name>.scm.<scm-name>.manager.importBiDirプロパティ

vbroker.se.<se-name>.scm.<scm-name>.manager.importBiDirプロパティは，サーバ側のプロパティです。デフォルトでは，VisiBroker ORBによって何も設定されていません。これをtrueに設定すると，サーバ側はクライアントにリクエストを送信するためにクライアントがすでに設定したコネクションを再利用できます。falseに設定すると，このようなコネクションの再利用はできません。

27.2.4　注意

これらのプロパティはSCMの作成時に一度だけ評価されます。すべての場合，SCMのexportBiDirプロパティおよびimportBiDirプロパティは，enableBiDirプロパティを管理します。言い換えれば，両方のプロパティに，競合する値が設定されていると，SCM固有のプロパティが有効になります。これによって，ユーザはenableBiDirプロパティをグローバルに設定でき，特に個々のSCMでBiDirをオフにできるようになります。

27.3　サンプルについて

この機能の使用方法のサンプルは，Borland Enterprise Server VisiBrokerインストールディレクトリのexamples/vbe/bidir-iiopサブディレクトリにあります。すべてのサンプルは，次のような単純な株価情報のコールバックアプリケーションに基づいています。

クライアントは，株価情報更新を処理するCORBAオブジェクトを作成します。

クライアントは，このCORBAオブジェクトのオブジェクトリファレンスをサーバに送信します。

サーバは，株価情報を定期的に更新するためにこのコールバックオブジェクトを呼び出します。

「27.4　既存のアプリケーションで双方向IIOPを有効にする」および「27.5　双方向IIOPを明示的に有効にする」では，さまざまな場合の双方向IIOP機能について例を使用して説明します。

27.4　既存のアプリケーションで双方向IIOPを有効にする

ユーザはソースコードをまったく修正しないで，既存のC++およびJavaのBorland Enterprise Server VisiBrokerアプリケーションで双方向通信を有効にできます。双方向IIOPをまったく使用しない単純なコールバックアプリケーションは，examples/vbe/bidir-iiop/basicディレクトリに格納されています。

このアプリケーションで双方向IIOPを有効にするには，vbroker.orb.enableBiDirプロパティを設定します。

スマートエージェントが実行中であることを確認します。

サーバを起動します。

C++の場合（UNIX）

prompt>Server -Dvbroker.orb.enableBiDir=server &

Javaの場合（UNIX）

prompt>vbj -Dvbroker.orb.enableBiDir=server Server &

C++の場合（Windows）

prompt>start Server -Dvbroker.orb.enableBiDir=server

Javaの場合（Windows）

prompt>start vbj -Dvbroker.orb.enableBiDir=server Server

クライアントを起動します。

C++の場合

prompt>Client -Dvbroker.orb.enableBiDir=client

Javaの場合

prompt>vbj -Dvbroker.orb.enableBiDir=client RegularClient

ここで，既存のコールバックアプリケーションは双方向IIOPを使用して，クライアント側のファイアウォールを越えて動作します。

27.5　双方向IIOPを明示的に有効にする

examples/vbe/bidir-iiop/basicディレクトリのClientは，「27.4　既存のアプリケーションで双方向IIOPを有効にする」で記述したClientから派生します。ただし，このクライアントはプログラムによって双方向IIOPを有効にします。

クライアントコードだけを変更する必要があります。一方向クライアントを双方向クライアントに変換するには，次に示す操作を行うだけです。

BiDirectionalポリシーをコールバックPOAのポリシーのリストに入れます。

BiDirectionalポリシーを，双方向IIOPを有効にしたいサーバを表すオブジェクトリファレンスの変更のリストに追加します。

クライアントでexportBiDirプロパティをtrueに設定します。

次に示すコードの抜粋では，双方向IIOPをインプリメントするコードをボールド体で示します。

コードサンプル27-1　双方向IIOPのインプリメント（C++）

try {
   CORBA::ORB_var orb = CORBA::ORB_init(argc,argv);

   // Get the manager Id
   PortableServer::ObjectId_var managerId =
      PortableServer::string_to_ObjectId("BankManager");
   PortableServer::ObjectId_var oid =
      PortableServer::string_to_ObjectId("QuoteServer");
   Quote::QuoteServer_var quoter =
      Quote::QuoteServer::_bind("/QuoteServer_poa",oid);

   //set up the callback object...first get the RootPOA
   CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
   PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);
   PortableServer::POAManager_var the_manager = rootPOA->the_POAManager();
   PortableServer::POA_var consumer_poa;

   //Set up a policy.
   CORBA::Any policy_value;
   policy_value <<= BiDirPolicy::BOTH;
   CORBA::Policy_var policy =
      orb->create_policy(BiDirPolicy::BIDIRECTIONAL_POLICY_TYPE,
         policy_value);

   CORBA::PolicyList policies;
   policies.length(1);
   policies [0] = CORBA::Policy::_duplicate(policy);

   consumer_poa = rootPOA->create_POA("QuoteConsumer_poa"
      ,the_manager,policies );

   QuoteConsumerImpl* consumer = new QuoteConsumerImpl;
   oid = PortableServer::string_to_ObjectId("consumer");
   consumer_poa->activate_object_with_id(oid, consumer);

   the_manager->activate();
   CORBA::Object_var_obj = quoter->set_policy_overrides(
      policies,CORBA::ADD_OVERRIDE);
   quoter = Quote::QuoteServer::_narrow(_obj);

   obj = consumer_poa->id_to_reference(oid);
   Quote::QuoteConsumer_var quote_consumer =
      Quote::QuoteConsumer::_narrow(obj);
   quoter->registerConsumer(quote_consumer.in());

   cout << "implementation is running" << endl;
   orb->run();
}
catch(const CORBA::Exception& e){
   cout <<e <<endl;
}

コードサンプル27-2　双方向IIOPのインプリメント（Java）

public static void main (String[ ] args)){
      try {
      org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);
      org.omg.PortableServer.POA rootPOA =
         org.omg.PortableServer.POAHelper.narrow(
            orb.resolve_initial_references("RootPOA"));
      org.omg.CORBA.Any bidirPolicy = orb.create_any();
      bidirPolicy.insert_short(BOTH.value);
      org.omg.CORBA.Policy[ ] policies = {
         //set bidir policy
         orb.create_policy(BIDIRECTIONAL_POLICY_TYPE.value,
            bidirPolicy)
      };
      org.omg.PortableServer.POA callbackPOA =
         rootPOA.create_POA("bidir", rootPOA.the_POAManager(),
                                                        policies);
      QuoteConsumerImpl c = new QuoteConsumerImpl();
      callbackPOA.activate_object(c);
      callbackPOA.the_POAManager().activate();
      QuoteServer serv = QuoteServerHelper.bind(orb,
                    "/QuoteServer_poa", "QuoteServer".getBytes());
      serv=QuoteServerHelper.narrow(serv._set_policy_override(
            policies,org.omg.CORBA.SetOverrideType.ADD_OVERRIDE));
      serv.registerConsumer(QuoteConsumerHelper.narrow(
            callbackPOA.servant_to_reference(c)));
      System.out.println("Client:consumer registered");
      //sleeping for 60 seconds,receiving message
      try{
         Thread.currentThread().sleep(60*1000);
      }
      catch(java.lang.InterruptedException e){ }
      serv.unregisterConsumer(QuoteConsumerHelper.narrow(
            callbackPOA.servant_to_reference(c)));
      System.out.println("Client: consumer unregistered.Good bye.");
      orb.shutdown(true);
. . .

注

ユーザのアプリケーションを調整するためにポリシーを設定する方法については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」の「QoSインタフェースとクラス」の記述を参照してください。

クライアントコネクションは一方向または双方向のどちらでもかまいません。サーバは双方向コネクションを使用して，新しいコネクションをオープンしないでクライアントをコールバックできます。コネクションがこれ以外の場合，一方向コネクションとみなされます。

コールバックオブジェクトのホストとなるPOAは，BiDirectionalポリシーをBOTHに設定することによって双方向IIOPを有効にする必要があります。このPOAは，SCMマネージャでvbroker.se.<sename>.scm.<scmname>.manager.exportBiDirプロパティを設定して双方向サポートを有効にしてあるSCMで作成する必要があります。POAがこれ以外の場合，POAはクライアント起動コネクションによってサーバからリクエストを受信することはできません。

POAがBiDirectionalポリシーを指定しない場合，POAを出力コネクションで使用しないでください。この要件を満たすために，BiDirectionalポリシーが設定されていないPOAは，exportBiDirプロパティが設定されているSCMが一つでもあるサーバエンジン上では作成できません。一方向SEでPOAを作成しようとすると，ServerEnginePolicyがエラーとなるInvalidPolicy例外が発生します。

注

同じクライアントコネクションを使用している異なるオブジェクトはBiDirectionalポリシーの競合の変更を設定することがあります。しかし，一度コネクションが双方向になったら，あとでポリシーが有効になってもならなくても，常に双方向のままになります。

双方向設定に対してユーザに完全に制御が移ったら，iiop_tp SCMだけで双方向IIOPを有効にします。

C++の場合

prompt>Client -Dvbroker.se.iiop_tp.scm.iiop_tp.manager.exportBiDir¥
       =true

Javaの場合

prompt>vbj -Dvbroker.se.iiop_tp.scm.iiop_tp.manager.¥
       exportBiDir=true Client

27.6　セキュリティの考慮事項

双方向IIOPを使用する場合，重要なセキュリティ問題が発生することがあります。ほかにセキュリティ機能を備えていない場合，悪質なクライアントが選んだホストやポートとコネクションの双方向での使用を要求することがあります。特に，クライアントは，そのホストに常駐していないセキュリティに敏感なオブジェクトのホストやポートを指定することがあります。ほかにセキュリティ機能を備えていない場合，入力コネクションを受け付けたサーバには，アイデンティティを確認したり，コネクションを起動したクライアントの保全性を確認したりする方法がありません。さらに，サーバは双方向コネクションによってアクセスできる別のオブジェクトへのアクセスを確保する可能性があります。これが，個別の双方向SCMをコールバックオブジェクトに使用した方がよい理由です。クライアントの保全性について心配であれば，双方向IIOPを使用しないことをお勧めします。

セキュリティの面から，VisiBrokerを実行しているサーバは双方向IIOPが明示的に設定されていなければ双方向IIOPを使用しません。vbroker.se.<se-name>.scm.<scm-name>.manager.importBiDirプロパティは，双方向性の制御をSCMごとにユーザに与えます。例えば，クライアントを認証するためにSSLを使用するサーバエンジンだけで双方向IIOPを有効にすること，また，双方向の使用のためにそのほかの，通常のIIOPコネクションを有効にしないことを選択できます（この方法については，「27.2　双方向VisiBroker ORBのプロパティ」を参照してください）。さらにクライアント側で，クライアントのファイアウォールの外側でコールバックを行うサーバだけで双方向コネクションを有効にします。クライアントとサーバ間で高度なセキュリティを設定するには，相互認証（クライアントとサーバの両方でvbroker.security.peerAuthenticationModeをREQUIRE_AND_TRUSTに設定）でSSLを使用しなければなりません。

第6編　下位互換性

28　VisiBrokerコードの移行

この章では，VisiBrokerコードをVisiBrokerの以前のバージョンからBorland Enterprise Server VisiBrokerへ移行する方法について説明します。JavaコードをVisiBroker 3.xからVisiBroker 5.xに移行する方法は二つあります。移行プロセスの重要な部分を自動化しようとするコマンドラインユーティリティであるマイグレータと，手動による移行です。できるだけVisiBroker 3.xコードは手動でVisiBroker 5.xに移行することをお勧めします。VisiBroker 3.xをアップグレードするより，VisiBroker 5.xの固有の呼び出しを使用する方が多くの利点があります。

28.1　BOAのPOAへの手動による移行

クラス名はVisiBrokerの以前のバージョンから変更されています。ソースファイルを更新して，最新のクラス名を指定してください。表28-1および表28-2に，クラス名の変更例について示します。

表28‒1　クラス名の変更（C++）

旧クラス名

新クラス名

_sk_Account

POA_Account

_sk_AccountManager

POA_AccountManager

_tie_Account

POA_Account_tie

_tie_AccountManager

POA_AccountManager_tie

表28‒2　クラス名の変更（Java）

旧クラス名

新クラス名

_st_Account

_AccountStub

_st_AccountManager

_AccountManagerStub

_AccountImplBase

AccountPOA

_AccountManagerImplBase

AccountManagerPOA

_tie_Account

AccountPOATie

_tie_AccountManager

AccountManagerPOATie

28.1.1　サンプルについて

Borland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/boa/boa2poaに，BOAをそれに対応するPOAコードに更新する場合のサンプルが入っています。

このサンプルでは，Server.C（C++），Server.java（Java）のBOAコードは次の手順によってPOAに更新されています。

BOAを初期化する代わりにルートPOAのリファレンスを取得する

BOA特性を模造するために適切なPOAポリシーを設定する

サーバントを定義する（POAにはBOAとは異なるサーバントの定義があります）

POAマネージャを起動する（BOAと異なる手順）

boa->impl_is_ready()メソッド（C++）またはboa.impl_is_ready()メソッド（Java）の代わりにorb->run()メソッド（C++）またはorb.run()メソッド（Java）によって入力リクエストを待つ

(1)　ルートPOAのリファレンスの取得

C++の場合

BOAを使用する際に，BOAのリファレンスはorb->BOA_init()メソッドによって取得しました。

しかし，POAではルートPOAのリファレンスを取得します。これは，orb->resolve_initial_references("RootPOA")メソッドを使用して行います。resolve_initial_referencesは，CORBA::object型の値を返します。そしてこの値を目的のタイプにナロウします。

コードサンプル28-1　rootPOAのリファレンスの取得（C++）

CORBA::object_var obj = resolve_initial_references("RootPOA");
PortableServer::POA_var rootPOA =
      PortableServer::POA::_narrow(obj);

Javaの場合

BOAを使用する際に，BOAのリファレンスはorb.BOA_init()メソッドによって取得しました。

しかし，POAではルートPOAのリファレンスを取得します。これは，orb.resolve_initial_references("RootPOA")メソッドを使用して行います。resolve_initial_referencesは，CORBA.object型の値を返します。そしてこの値を目的のタイプにナロウします。

コードサンプル28-2　rootPOAのリファレンスの取得（Java）

POA rootPOA = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));

(2)　POAポリシーの設定

POAの特性は，そのPOAのポリシーセットによって定義されます。各POAには，独自のポリシーのセットがあります。POAは，ほかのPOAからのポリシーを継承できません。

ここに示すサンプルでは，パーシステントオブジェクトが使用されています。BOAでは，パーシステントオブジェクトには特定のインスタンス名があり，スマートエージェントに登録されるものです。

一つのBOAはパーシステントオブジェクトとトランジェントオブジェクトの両方をサポートできます。POAでは，パーシステントオブジェクトはパーシステントオブジェクトを生成するプロセスを残したものです。一つのPOAはパーシステントオブジェクトもトランジェントオブジェクトもサポートしますが，両方をサポートすることはできません。サポートされるオブジェクトタイプは，POAポリシーによって設定されます。ルートPOAはトランジェントオブジェクトを（デフォルトで）サポートするので，パーシステントオブジェクトをサポートするために新しいPOAを作成する必要があります。

注

POAのポリシーをいったん生成したら変更することはできません。

パーシステントオブジェクトをサポートするには，ライフスパンポリシーをPERSISTENTに設定します。これは，C++とJavaの両方に適用されます。

C++またはJavaの場合

ここに示すサンプルでは，バインドサポートポリシー（Borland Enterprise Server VisiBroker固有ポリシー）をBY_INSTANCEに設定します。このポリシーは，すべてのアクティブなオブジェクトをPOA（デフォルト）だけでなくスマートエージェントに登録しています。

適切なポリシーを設定したら，新しいPOAがcreate_POA()メソッドで生成できます。

コードサンプル28-3　POAポリシーの設定（C++）

CORBA::PolicyList policies;
   policies.length(1);

   policies [(CORBA::ULong)0] =
         rootPOA->create_lifespan_policy(
         PortableServer::PERSISTENT);

   // Create myPOA with the right policies
   PortableServer::POAManager_var mgr =
         rootPOA->the_POAManager();
   PortableServer::POA_var myPOA =
         rootPOA->create_POA(
         "bank_agent_poa", mgr, policies );

コードサンプル28-4　POAポリシーの設定（Java）

org.omg.CORBA.Any any = orb.create_any();
   BindSupportPolicyValueHelper.insert(any,
                         BindSupportPolicyValue.BY_INSTANCE);
   org.omg.CORBA.Policy bsPolicy =
     orb.create_policy(com.inprise.vbroker.PortableServerExt.
         BIND_SUPPORT_POLICY_TYPE.value, any);

   org.omg.CORBA.Policy[ ] policies ={
      rootPOA.create_lifespan_policy(LifespanPolicyValue.
         PERSISTENT), bsPolicy};
      // Create myPOA with the right policies
      POA myPOA = rootPOA.create_POA("bank_agent_poa",
                        rootPOA.the_POAManager(), policies);

(3)　サーバントの定義

BOAでは，サーバントがCORBAオブジェクトです。ここに示すサンプルでは，アカウントマネージャオブジェクトが生成されてから，obj_is_ready()メソッドでエクスポートされます。

POAでは，サーバントはプログラミングオブジェクトで，これはabstractオブジェクトのインプリメンテーションを提供します。サーバントはCORBAオブジェクトではありません。POAシナリオ下では，サーバントが生成されてから固有IDで起動されます。このIDを使ってオブジェクトリファレンスを取得できます。

コードサンプル28-5　サーバントの定義および起動（C++）

// Create the servant
   AccountManagerImpl *managerServant =
         new AccountManagerImpl;
// Decide on the ID for the servant
   PortableServer::ObjectId_var managerId =
      PortableServer::string_to_ObjectId("BankManager");
// Activate the servant with the ID on myPOA
   myPOA->activate_object_with_id(managerId,managerServant);

コードサンプル28-6　サーバントの定義および起動（Java）

// Create the servant
   AccountManagerImpl managerServant =
                                    new AccountManagerImpl();
// Decide on the ID for the servant
   byte[ ] managerId = "BankManager".getBytes();
// Activate the servant with the ID on myPOA
   myPOA.activate_object_with_id(managerId, managerServant);

(4)　POAマネージャの起動

POAマネージャはPOAがリクエストをどのように処理するかを制御するオブジェクトです。デフォルトで，POAマネージャは待機状態で生成されます。この状態では，すべてのリクエストは待機キューにルーティングされ，処理はされません。リクエストをディスパッチするには，POAに対応するPOAマネージャを待機状態からアクティブ状態に変更する必要があります。

これは，POAで必要な新しい手順です。BOAと同じ手順ではありません。

コードサンプル28-7　POAマネージャの起動

C++の場合

rootPOA->the_POAManager()->activate();

Javaの場合

rootPOA.the_POAManager().activate();

(5)　入力リクエスト待ち

BOAでは，クライアントからのリクエストを待つためにimpl_is_ready()メソッドが呼び出されます。

POAでは，orb->run()（C++）またはorb.run()（Java）を使用します。

コードサンプル28-8　入力リクエスト待ち

C++の場合

orb->run();

Javaの場合

orb.run();

(6)　ほかのファイルについて（C++およびJava）

AccountImplおよびAccountManagerImplクラスの変更事項は，ほぼ新しいクラスの指定を行うことだけです。

28.1.2　BOA型のPOAポリシーへのマッピング

表28-3は，BOA動作を模造するためにユーザのPOAポリシーを設定する方法を示します。

表28‒3　BOA型のPOAポリシーへのマッピング

ポリシー

トランジェントBOA

パーシステントBOA

TPOOL

TPOOLディスパッチャによるサーバエンジンポリシー

TPOOLディスパッチャによるサーバエンジンポリシー

PERSISTENTに設定されたLifeCycleプロパティ

TRANSIENTに設定されたLifeCycleプロパティ

USER_IDに設定されたIDAssignmentポリシー

BY_INSTANCEに設定されたBindSupportポリシー

TSESSION

TSESSIONディスパッチャによるサーバエンジンポリシー

TSESSIONディスパッチャによるサーバエンジンポリシー

PERSISTENTに設定されたLifeCycleプロパティ

TRANSIENTに設定されたLifeCycleプロパティ

USER_IDに設定されたIDAssignmentポリシー

BY_INSTANCEに設定されたBindSupportポリシー

サービス起動オブジェクト

TRANSIENTに設定されたLifeCycleプロパティ

PERSISTENTに設定されたLifeCycleプロパティ

USE_SERVANT_MANAGERに対するリクエスト処理ポリシー

USE_SERVANT_MANAGERに対するリクエスト処理ポリシー

IMPLICIT_ACTIVATIONに設定された暗黙起動ポリシー

IMPLICIT_ACTIVATIONに設定された暗黙起動ポリシー

28.2　新しいパッケージ名への移行（Java）

表28-4にVisiBroker 3.xパッケージ名プリフィクスの最新バージョンへのマッピング方法を示します。

表28‒4　VisiBroker 3.xパッケージ名プリフィクスのマッピング

VisiBroker 3.xパッケージ名

Borland Enterprise Server VisiBroker 5.xパッケージ名

com.visigenic.vbroker

com.inprise.vbroker

com.visigenic.vbroker.services.CosEvent

com.inprise.vbroker.CosEvent

com.visigenic.vbroker.services.CosNaming

com.inprise.vbroker.naming

28.3　新しいAPI呼び出しへの移行（Java）

表28-5にVisiBroker 3.x API呼び出しの最新バージョンへのマッピング方法を示します。

表28‒5　VisiBroker 3.x API呼び出しのマッピング

VisiBroker 3.x API呼び出し

Borland Enterprise Server VisiBroker API呼び出し

com.visigenic.vbroker.services.CosEvent.EventLibraryのインスタンスでのcreate_channel(boa， name， debug，maxQueueLength)

com.inprise.vbroker.CosEvent.EventLibraryのインスタンスでのcreate_channel(name， debug，maxQueueLength)

com.visigenic.vbroker.services.CosEvent.EventLibraryのインスタンスでのcreate_channel(boa， name， debug)

com.inprise.vbroker.CosEvent.EventLibraryのインスタンスでのcreate_channel(name， debug)

com.visigenic.vbroker.services.CosEvent.EventLibraryのインスタンスでのcreate_channel(boa， name)

com.inprise.vbroker.CosEvent.EventLibraryのインスタンスでのcreate_channel(name)

com.visigenic.vbroker.services.CosEvent.EventLibraryのインスタンスでのcreate_channel(boa)

com.inprise.vbroker.CosEvent.EventLibraryのインスタンスでのcreate_channel()

新しいパッケージ名，クラス，およびAPI呼び出しの詳細については，マニュアル「Borland Enterprise Server VisiBroker　プログラマーズリファレンス」を参照してください。

28.4　インタセプタの移行

インタセプタをBorland Enterprise Server VisiBrokerに移行する際は，ポータブルインタセプタを使用してください。ポータブルインタセプタの動作方法については，「19.　ポータブルインタセプタの使用」を参照してください。

28.5　イベントループの統合の移行（C++）

VisiBroker 3.xの機能によって，ユーザはオブジェクトのイベントポーリングをネットワークやウィンドウコンポーネントのイベントループに組み込めます。VisiBroker 3.xの機能を次に示します。

シングルスレッドライブラリによって，サードパーティライブラリに応答するCORBAアプリケーションを構築できます。このようなアプリケーションは再入可能でないシステムライブラリで構築する必要があります。

Windowsでシングルスレッドサーバを構築するWDispatcherクラス。

このクラスによって，VisiBroker ORBイベントはWindowsメッセージイベントと統合できます。

X Window Systemでシングルスレッドサーバを構築するXDispatcherクラス。

このクラスによって，VisiBroker ORBイベントはX Window SystemのXtMainLoopに直接統合できます。

Dispatcherクラスによって，VisiBroker ORBイベントと別の環境との統合が可能になります。これは，Dispatcherからカスタムサブクラスを派生させ，すべてのメソッドのインプリメンテーションを提供することによって行うことができます。

また，Dispatcherクラスを使用して，VisiBroker ORBイベントを直接監視し，特定のファイルのディスクリプタのイベントを処理し，イベントタイマを設定できます。

ただし，再入可能なVisiBroker ORBライブラリでは，すべてのVisiBroker ORBイベントはVisiBroker ORBスレッドによって処理され，通常の状況下では別のイベント処理システムと統合する必要はありません。VisiBroker 5.xでは，このリリースにはシングルスレッドVisiBroker ORBライブラリは組み込まれていません。このため，上記の機能はVisiBroker 5.x以降のバージョンではサポートされていません。アプリケーションがVisiBroker 3.xの機能を使用するような場合，この機能を除去するためにコーディングを修正する必要があります。以降でこのような変更をするためのガイドラインを説明します。

28.5.1　シングルスレッドVisiBroker ORBの移行

ここでは，シングルスレッドVisiBroker ORBを移行する際のガイドラインを説明します。

使用するすべてのインプリメンテーションメソッドがスレッドセーフであること，動作に応じてアプリケーションでSINGLE_THREAD_MODEL，またはMAIN_THREAD_MODELのPOAThreadPolicyを使用することを確認します。場合によっては，このようなポリシーを使用している場合でも，インプリメンテーションコードの重要な部分を保護する必要があります。このような場合，アプリケーションの重要部分を統合するグローバルミューテックスを使用して，同期を取れます。

アプリケーション（場合によってはメソッド）にmain()メソッドを戻さないようにする機能がほかにない場合は，ORB run()メソッドを使用します。

ただし，run()メソッドを呼び出す必要はありません。すべてのVisiBroker ORBスレッドはORB_init()メソッドおよびPOAマネージャ起動メソッドによって自動的に作成されます。

28.5.2　XDispatcherクラスまたはWDispatcherクラスによる移行

XDispatcherクラスとWDispatcherクラスはVisiBroker ORBランタイムおよびX Window System（またはWindows）イベントループと透過的に動作します。これは，ORB_initに対する最初の呼び出し前に，XDispatcherまたはWDispatcherのインスタンス作成時に動作します。このため，「28.5.1　シングルスレッドVisiBroker ORBの移行」で説明したように，アプリケーションがスレッドセーフとなったら，XDispatcherまたはWDispatcherのリファレンスを単純に削除できます。コードサンプル28-9および28-10にWDispatcher変換の例を示します。

コードサンプル28-9　移行前のWDispatcher

//. . .
hwnd = CreateWindow(szAppName, "AccountServer",
                         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
                         CW_USEDEFAULT,200,200,NULL,
                         NULL,hInstance,NULL);

//Create a WDispatcher instance before calling ORB_init
WDispatcher *winDispatcher = new WDispatcher(hwnd);

//Initialize the ORB
CORBA::ORB_var orb = CORBA::ORB_init(__argc, __argv);

//Initialize the BOA
CORBA::BOA_var orb = orb->BOA_init(__argc, __argv);

//Create the servant
AccountImpl server("BankManager");

//Activate the servant on the BOA
boa->obj_is_ready(&server);

ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);

//Enter message loop
while(GetMessage(&msy, NULL, 0, 0)) {
         TranslateMessage(&msg); DispatchMessage(&msg);
     }
return msg.wParam;

//. . .

コードサンプル28-10　移行後のWDispatcher

//. . .
hwnd = CreateWindow(szAppName, "AccountServer",
                        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
                        CW_USEDEFAULT,200,200,NULL,
                        NULL,hInstance,NULL);
//Initialize the ORB
CORBA::ORB_var orb = CORBA::ORB_init(__argc, __argv);

//Initialize the POA
CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);
CORBA::PolicyList policies;
policies.length(1);
policies [(CORBA::ULong)0 ] = rootPOA->create_lifespan_policy(
                                          PortableServer::PERSISTENT);
PortableServer::POAManager_var poa_mgr =rootPOA->the_POAManager();

PortableServer::POA_var myPOA =rootPOA->create_POA("bank_agent_poa",
                                                    poa_mgr,policies);

//Create the servant
AccountManagerImpl managerServant;

//Activate the servant on the POA
PortableServer::ObjectId_var managerId =
                   PortableServer::string_to_ObjectId("BankManager");

myPOA->activate_object_with_id(managerId, &managerServant);

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

//Enter message loop
while(GetMessage(&msy,NULL,0,0)){
                          TranslateMessage(&msg);
                          DispatchMessage(&msg);
}
return msg.wParam;
// . . .

WDispatcherまたはXDispatcherを削除する場合，POAを使用可能にするためにアプリケーションを変換するための追加手順は必要ありません。

29　オブジェクトアクティベータの使用

この章では，VisiBrokerオブジェクトアクティベータの使用方法について説明します。

提供するBorland Enterprise Server VisiBrokerでは，POAはVisiBroker 3.xでBOAが提供していた機能をサポートします。下位互換性を保証するために，この章で説明するオブジェクトアクティベータをユーザのコードで使用することもできます。BOAアクティベータを提供するBorland Enterprise Server VisiBrokerで使用する方法の詳細については，「28.　VisiBrokerコードの移行」を参照してください。

29.1　オブジェクト活性化の遅延

サーバが多くのオブジェクトに対してインプリメンテーションを提供する必要がある場合に単一のActivatorでサービス活性化を使用して，複数のオブジェクトインプリメンテーションの起動を遅延できます。

29.2　アクティベータインタフェース

ユーザは，独自のインタフェースをActivatorクラス（C++）またはActivatorインタフェース（Java）から派生させることができます。これによってユーザはVisiBroker ORBがAccountImplオブジェクト（C++）またはDBObjectImplオブジェクト（Java）で使用する純仮想（C++）activateおよびdeactivateメソッドをインプリメントできます。次に，ユーザはBOAがオブジェクトに対する要求を受け取るまで，AccountImplオブジェクトの実体化を遅延させることができます。また，BOAがオブジェクトを非活性化する場合に，クリーンアップ処理を提供できるようになります。

コードサンプル29-1にActivatorクラス（C++），コードサンプル29-2にActivatorインタフェース（Java）を示します。これは，VisiBroker ORBオブジェクトを活性化，非活性化するためにBOAが呼び出すメソッドを提供します。

コードサンプル29-1　Activatorクラス（C++）

class Activator {
   public:
      virtual CORBA::Object_ptr activate(
            extension::ImplementationDef impl) = 0;
      virtual void deactivate(
            Object_ptr, extension::ImplementationDef_ptr impl)
            = 0;
};

コードサンプル29-2　Activatorインタフェース（Java）

package com.inprise.vbroker.extension;
public interface Activator {
   public abstract org.omg.CORBA.Object
                            activate(ImplementationDef impl);
   public abstract void deactivate(org.omg.CORBA.Object obj,
                                   ImplementationDef impl);
}

コードサンプル29-3にAccountImplインタフェースに対してActivatorを生成する方法を示します。

コードサンプル29-3　activateおよびdeactivateメソッドをインプリメントしてDBActivatorクラス（C++）を派生

class extension {
   . . .
   class AccountImplActivator : public extension::Activator {
      public:
         virtual CORBA::Object_ptr activate(
               CORBA::ImplementationDef_ptr impl);
         virtual void deactivate(CORBA::Object_ptr,
               CORBA::ImplementationDef_ptr impl);
   };
   CORBA::Object_ptr AccountImplActivator::activate(
         CORBA::ImplementationDef_ptr impl) {
      // When the BOA needs to activate us,
      // instantiate the AccountImpl object.
      extension::ActivationImplDef* actImplDef =
              extension::ActivationImplDef::_downcast(impl);
      CORBA::Object_var obj =
              new AccountImpl(actImplDef->object_name());
      return CORBA::_duplicate(obj);
   }
   void AccountImplActivator::deactivate(CORBA::Object_ptr obj,
         CORBA::ImplementationDef_ptr impl) {
      // When the BOA deactivates us, release the Account object.
      obj->_release;
   }
}

コードサンプル29-4にDBObjectImplインタフェースに対してActivatorを生成する方法を示します。

コードサンプル29-4　activateおよびdeactivateメソッドをインプリメントしてDBActivatorインタフェース（Java）を派生

// Server.java
import com.inprise.vbroker.extension.*;
. . .
class DBActivator implements Activator {
   private static int _count;
   private com.inprise.vbroker.CORBA.BOA _boa;

   public DBActivator(com.inprise.vbroker.CORBA.BOA boa) {
      _boa = boa;
   }
   public org.omg.CORBA.Object activate(
       com.inprise.vbroker.extension.ImplementationDef impl) {
      System.out.println(
          "Activator called " + ++_count + " times");
      byte[ ] ref_data = ((ActivationImplDef) impl) .id();
      DBObjectImpl obj =
                   new DBObjectImpl(new String(ref_data));
      _boa.obj_is_ready(obj);
      return obj;
   }
   public void deactivate(org.omg.CORBA.Object obj,
      com.inprise.vbroker.extension.ImplementationDef impl) {
    // nothing to do here...
   }
}
. . .

29.3　サービス活性化のアプローチ方法

サーバは，多数のオブジェクト（通常，数千個のオブジェクト。数百万個のオブジェクトの場合もある）に対してインプリメンテーションを提供する必要があります。任意の一時点で活性化する必要のあるインプリメンテーションの数が少ない場合，サービス活性化を使用できます。サーバはこれらの補助オブジェクトのどれかが必要になると通知を受ける単一のActivatorを提供できます。サーバはこれらのオブジェクトが使用されていない場合に非活性化することもできます。

例えば，状態がデータベースに格納されるオブジェクトインプリメンテーションをロードするサーバに対してサービス活性化を使用すると仮定します。Activatorには所定の型または論理区分のオブジェクトをすべてロードする責任があります。VisiBroker ORBリクエストがこれらのオブジェクトのリファレンスで発行されると，Activatorは通知を受け，データベースからロードされる状態を持つ，新しいインプリメンテーションを生成します。Activatorはオブジェクトがメモリに存在しなくなったと判断し，オブジェクトが変更されている場合，そのオブジェクトの状態をデータベースに書き込み，インプリメンテーションを解放します。

サービスの活性化の遅延プロセスを図29-1に示します。

図29‒1　サービスの活性化の遅延プロセス

29.3.1　サービスアクティベータを使用したオブジェクト活性化の遅延

サービスを構成するオブジェクトが生成済みであるということを前提にして，サービス活性化を使用するサーバをインプリメントするには，次の手順に従ってください。

Activatorによって活性化され，非活性化されるすべてのオブジェクトを記述するサービス名を定義します。

パーシステントオブジェクトではなく，サービスオブジェクトになっているインタフェースのインプリメンテーションを提供します。これはオブジェクトが自身をサービスの活性化可能部として構成する場合に行われます。

要求に応じて，オブジェクトインプリメンテーションを生成するActivatorをインプリメントします。インプリメンテーション内では，extension::ActivatorからActivatorインタフェースを派生させ，activateメソッドとdeactivateメソッドを変更します。

サービス名とActivatorインタフェースをBOAに登録します。

29.3.2　サービスの遅延オブジェクト活性化のサンプル

ここでは，サービス活性化のodbのサンプルについて説明します。サンプルはBorland Enterprise Server VisiBrokerをインストールしたディレクトリのexamples/vbe/boa/odbに入っています。このディレクトリには，表29-1のファイルも含まれます。

表29‒1　サービス活性化用odbのサンプルファイル

ファイル名

説明

odb.idl

DBインタフェースとDBObjectインタフェースのIDL

Server.C（C++）

Server.java（Java）

サービスアクティベータを使用してオブジェクトを生成し，オブジェクトのIORを返し，オブジェクトを非活性化します。

Creator.C（C++）

Creator.java（Java）

100個のオブジェクトを生成するためにDBインタフェースを呼び出し，結果として生じた文字列化オブジェクトリファレンスをファイル（objref.out）に格納します。

Client.C（C++）

Client.java（Java）

オブジェクトの文字列化オブジェクトリファレンスをファイルから読み出して，それらに対する呼び出しを行い，サーバ内のアクティベータにオブジェクトを生成させます。

Makefile

makeまたはnmake（Windowsの場合）がodbサブディレクトリ内で呼び出されたときに，次に示すクライアントプログラムとサーバプログラムを生成します。

Server.exe（C++）またはServer（Java）

Creator.exe（C++）またはCreator（Java）

Client.exe（C++）またはClient（Java）

odbのサンプルは，一つのサービスから任意の数のオブジェクトがどのように作成できるかを示します。サービス単体は，IORの一部として格納された各オブジェクトのリファレンスデータとともに，各オブジェクトではなくBOAに登録されます。これによって，オブジェクトキーをオブジェクトリファレンスの一部として格納できるので，OODB（オブジェクト指向データベース）統合を簡易化できます。未生成のオブジェクトをクライアントが呼び出す場合，BOAはユーザが定義したActivatorを呼び出します。すると，アプリケーションは適切なオブジェクトをパーシステント記憶領域からロードできます。

このサンプルでは，「DBService」という名前のサービスに対してオブジェクトを活性化し，非活性化する責任のあるActivatorが生成されます。このActivatorが生成するオブジェクトのリファレンスには，VisiBroker ORBがDBServiceサービスのActivatorを再検索し，Activatorが要求に応じてこれらのオブジェクトを再生成するために十分な情報が含まれています。

DBServiceサービスはDBObjectインタフェースをインプリメントするオブジェクトに対して責任があります。インタフェース（odb.idlに含まれる）はこれらのオブジェクトの手動生成をできるようにするために提供されます。

(1)　odb.idlインタフェース

odb.idlインタフェースはDBObject odbインタフェースをインプリメントするオブジェクトの手動生成をできるようにします。

IDLサンプル29-1　odb.idlインタフェース

interface DBObject {
   string get_name();
};

typedef sequence<DBObject> DBObjectSequence;

interface DB {
   DBObject create_object(in string name);
};

DBObjectインタフェースはDBインタフェースが生成したオブジェクトを表し，サービスオブジェクトとして取り扱えます。

DBObjectSequenceはDBObjectのシーケンスです。サーバはこのシーケンスを使って，現在活性化しているオブジェクトを把握します。

DBインタフェースはcreate_objectオペレーションを使って一つ以上のDBObjectを生成します。DBインタフェースが生成したオブジェクト群は，サービスとして一つにまとめることができます。

(2)　サービス活性化オブジェクトのインプリメント（C++）

idl2cppコンパイラは，boa/odb/odb.idlからスケルトンクラス_sk_DBObject用に2種類のコンストラクタを生成します。最初のコンストラクタは手動実体化オブジェクトで使用します。二つ目のコンストラクタはオブジェクトをサービスの一部にします。コードサンプル29-5に示すように，DBObjectのインプリメンテーションは，手動実体化オブジェクトで一般に使用されるobject_nameコンストラクタではなく，サービスコンストラクタを使用してベースの_sk_DBObjectメソッドを構築します。この種のコンストラクタを起動して，DBObjectはそれ自身をDBServiceというサービスの一部として構築します。

コードサンプル29-5　サービス活性化オブジェクトのインプリメント例

class DBObjectImpl: public _sk_DBObject {
   private:
      CORBA::String_var_name;
   public:
      DBObjectImpl(const char *nm,
            const CORBA::ReferenceData& data)
      : _sk_DBObject("DBService", data), _name(nm) {}
   . . .
}

注

ベースのコンストラクタは，不明瞭なCORBA::ReferenceData値と同様にサービス名を必要とします。Activatorは，クライアントリクエストによって起動しなければならない場合に，これらのパラメタを使用して該当するオブジェクトを一意に識別します。このサンプルで複数のインスタンスを区別するための参照データは，0から99までの数字で構成されます。

(3)　サービスアクティベータのインプリメント

通常，オブジェクトをインプリメントしているC++またはJavaクラスをサーバが実体化し，次にBOA::obj_is_ready（C++），BOA::impl_is_ready（C++）またはobj_is_ready（Java），impl_is_ready（Java）の順で呼び出すと，オブジェクトが活性化されます。オブジェクトの活性化を遅延させるには，BOAがオブジェクト活性化中に呼び出すactivateメソッドの制御を得る必要があります。この制御を得るには，extension::Activator（C++）またはcom.inprise.vbroker.extension.Activator（Java）から新たなクラスを派生させ，activateメソッドを変更し，変更したactivateメソッドを使ってオブジェクト固有のC++クラスまたはJavaクラスを実体化します。

odbのサンプルでは，DBActivatorクラスがextension::Activator（C++）またはcom.inprise.vbroker.extension.Activator（Java）から派生し，activateメソッドとdeactivateメソッドを変更します。DBObjectはactivateメソッド内に構築されます。

コードサンプル29-6　activateメソッドとdeactivateメソッドを変更する例（C++）

class DBActivator: public extension::Activator {
      virtual CORBA::Object_ptr activate(
            CORBA::ImplementationDef_ptr impl);
      virtual void deactivate(CORBA::Object_ptr,
            CORBA::ImplementationDef_ptr impl );
   public:
      DBActivator(CORBA::BOA_ptr boa) : _boa(boa) {}
   private:
      CORBA::BOA_ptr _boa;
};

コードサンプル29-7　activateメソッドとdeactivateメソッドを変更する例（Java）

// Server.java
class DBActivator implements Activator {
   private static int _count;
   private com.inprise.vbroker.CORBA.BOA _boa;
   public DBActivator(com.inprise.vbroker.CORBA.BOA boa) {
      _boa = boa;
   }
   public org.omg.CORBA.Object activate(
         com.inprise.vbroker.extension.ImplementationDef impl) {
      System.out.printIn("Activator called " + ++_count + " times");
      byte[ ] ref_data = ((ActivationImplDef) impl).id();
      DBObjectImpl obj = new DBObjectImpl(new String(ref_data));
      _boa.obj_is_ready(obj);
      return obj;
   }
   public void deactivate(org.omg.CORBA.Object obj, ImplementationDef impl) {
      // nothing to do here...
   }
}

コードサンプル29-8に示すように，DBActivatorクラスはそのCORBA::ReferenceDataパラメタに基づいてオブジェクトを生成します（C++）。コードサンプル29-9では，DBActivatorクラスがReferenceDataパラメタに基づいてオブジェクトを生成する方法を示します（Java）。BOAはActivatorの責任の下でオブジェクトを求めるクライアントリクエストを受信すると，そのActivatorに対してactivateメソッドを起動します。このメソッドを呼び出すとき，BOAはActivatorにImplementationDefパラメタを引き渡すことによって，活性化されたオブジェクトインプリメンテーションを一意に識別します。このパラメタから，インプリメンテーションはリクエストされたオブジェクトの一意の識別子であるCORBA::ReferenceData（C++）またはReferenceData（Java）を取得できます。

コードサンプル29-8　サービスアクティベータをインプリメントする例（C++）

CORBA::Object_ptr DBActivator::activate(
      CORBA::ImplementationDef_ptr impl) {
   extension::ActivationImplDef* actImplDef =
         extension::ActivationImplDef::_downcast(impl);
   CORBA::ReferenceData_var id(actImplDef->id());
   cout << "Activate called for object=[" << (char*) id->data()
         << "]" << endl;
   DBObjectImpl *obj = new DBObjectImpl((char *)id->data(), id);
   _impls.length(_impls.length() +1);
   _impls[_impls.length()-1] = DBObject::_duplicate(obj);
   _boa->obj_is_ready(obj);
   return obj;
}

コードサンプル29-9　サービスアクティベータをインプリメントする例（Java）

public org.omg.CORBA.Object activate(ImplementationDef impl) {
   System.out.println("Activator called " + ++_count + " times");
   byte[ ] ref_data = ((ActivationImplDef) impl) .id();
   DBObjectImpl obj = new DBObjectImpl(new String(ref_data));
   _boa.obj_is_ready(obj);
   return obj;
}

(4)　サービスアクティベータの実体化

コードサンプル29-10に示すように，DBActivatorサービスアクティベータは，メインサーバプログラムのBOA::impl_is_ready呼び出しを使って生成され，BOAに登録されます（C++）。コードサンプル29-11は，メインサーバプログラムのimpl_is_ready呼び出しによってDBActivatorサービスアクティベータを作成し，登録するJavaの例を示します。

DBActivatorサービスアクティベータは，DBServiceサービスに属するすべてのオブジェクトに対して責任を持ちます。DBServiceサービスのオブジェクトを求めるリクエストはすべてDBActivatorサービスアクティベータを通じて指示されます。このサービスアクティベータによって活性化されたオブジェクトはすべてそれらがDBServiceサービスに属していることをVisiBroker ORBに通知するリファレンスを持っています。

コードサンプル29-10　サービスアクティベータを実体化する例（C++）

int main(int argc, char **argv) {
   CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
   CORBA::BOA_ptr boa = orb->BOA_init(argc, argv);
   MyDB db("Database Manager");
   boa->obj_is_ready(&db);
   DBObjectImplReaper reaper;
   reaper.start();
   cout << "Server is ready to receive requests" << endl;
   boa->impl_is_ready("DBService", new DBActivator(boa));
   return(0);
}

コードサンプル29-11　サービスアクティベータを実体化する例（Java）

public static void main(String[ ] args) {
   org.omg.CORBA.ORB orb = ORB.init(args, null);
   com.inprise.vbroker.CORBA.BOA boa
              = ((com.inprise.vbroker.orb.ORB )orb).BOA_init();
   DB db = new DBImpl("Database Manager");
   boa.obj_is_ready(db);
   boa.impl_is_ready("DBService", new DBActivator(boa));
}

BOA::impl_is_ready（C++）またはimpl_is_ready（Java）の呼び出しは，通常のBOA::impl_is_ready（C++）またはimpl_is_ready（Java）の呼び出しの変形であり，次のように引数を二つ持つことに注意してください。

サービス名

BOAがサービスに属するオブジェクトを活性化するために使用するActivatorインタフェースのインスタンス

(5)　サービスアクティベータを使用したオブジェクトの活性化（C++）

オブジェクトが構築されるたびに，BOA::obj_is_readyをDBActivator::activate内で明示的に呼び出す必要があります。サーバプログラムにはBOA::obj_is_readyに対して二つの呼び出しがあります。第一の呼び出しはサーバがサービスオブジェクトを生成し，生成元プログラムにIORを返したときに発生します。

コードサンプル29-12　BOA::obj_is_readyへのサーバの第一の呼び出し（C++）

DBObject_ptr create_object(const char *name) {
   char ref_data[100];
   memset(ref_data,'¥0',100);
   sprintf(ref_data, "%s", name);
   CORBA::ReferenceData id(100, 100, (CORBA::Octet *)ref_data);
   DBObjectImpl *obj = new DBObjectImpl(name, id);
   _boa()->obj_is_ready(obj);
   _impls.length(_impls.length() + 1);
   _impls[_impls.length()-1] = DBObject::_duplicate(obj);
   return obj;
}

BOA::obj_is_readyへの第二の呼び出しは，DBActivator::activate内にあり，これは明示的に呼び出す必要があります。コンテキスト内でのこの第二の呼び出しについては，コードサンプル29-8を参照してください。

(6)　サービスアクティベータを使用したオブジェクトの活性化（Java）

オブジェクトが構築されるたびに，obj_is_readyをactivate()メソッド内で明示的に呼び出す必要があります。サーバプログラムにはobj_is_readyに対して二つの呼び出しがあります。第一の呼び出しはサーバがサービスオブジェクトを生成し，生成元プログラムにIORを返したときに発生します。

コードサンプル29-13　obj_is_readyへのサーバの第一の呼び出し（Java）

public DBObject create_object(String name) {
   System.out.println("Creating: " + name);
   DBObject dbObject = new DBObjectImpl(name);
   _boa().obj_is_ready(dbObject, "DBService", name.getBytes());
   return dbObject;
}

obj_is_readyへの第二の呼び出しは，activate内にあり，これは明示的に呼び出す必要があります。コンテキスト内でのこの第二呼び出しについては，コードサンプル29-9を参照してください。

29.3.3　サービス活性化オブジェクトインプリメンテーションの非活性化（C++）

サービス活性化の主な用途は，サーバ内で多数のオブジェクトがアクティブであるような錯覚を与えることです。実際には少数のオブジェクトだけがアクティブです。このモデルをサポートするには，サーバは一時的にオブジェクトを使用できないようにする必要があります。マルチスレッドDBActivatorのサンプルプログラムには，30秒ごとにすべてのDBObjectImplを非活性化するリーパスレッドがあります。DBActivatorは，deactivateメソッドが起動されるとオブジェクトリファレンスを解放します。新しいクライアントリクエストが非活性化オブジェクトに到着すると，VisiBroker ORBはオブジェクトを再起動しなければならないことをActivatorに通知します。

コードサンプル29-14　サービス活性化オブジェクトインプリメンテーションを非活性化する例

//static sequence of currently active Implementations
static VISMutex         _implMtx;
static DBObjectSequence _impls;

//updated DBActivator to store activated implementations
//in the global sequence.
class DBActivator: public extension::Activator {
   virtual CORBA::Object_ptr activate(
         CORBA::ImplementationDef_ptr impl) {
      extension::ActivationImplDef* actImplDef =
            extension::ActivationImplDef::_downcast(impl);
      CORBA::ReferenceData_var id(actImplDef->id());
      DBObjectImpl *obj = new DBObjectImpl(
            (char *)id->data(), id);
      VISMutex_var lock(_implMtx);
      _impls.length(_impls.length() + 1);
      _impls[_impls.length()-1] = DBObject::_duplicate(obj);
      return obj;
   }
   virtual void deactivate(CORBA::Object_ptr,
      CORBA::ImplementationDef_ptr impl) {
      obj->_release();
   }
};
// Multi-threaded Reaper for destroying all activated
// objects every 30 seconds.
class DBObjectImplReaper : public VISThread {
   public:
      // Reaper methods
      virtual void start() {
         run();
      }
      virtual CORBA::Boolean startTimer() {
         vsleep(30);
         return 1;
      }
      virtual void begin() {
         while (startTimer()) {
            doOneReaping();
         }
      }
   protected:
      virtual void doOneReaping() {
         VISMutex_var lock(_implMtx);
         for (CORBA::ULong i=0; i < _impls.length(); i++) {
            // assigning nil into each element will release
            // the reference stored in the _var
            DBObject_var obj = DBObject::_duplicate(_impls[i-1];
            _impls[i] = DBObject::_nil();
            CORBA::BOA_var boa = obj->_boa();
            boa->deactivate_obj(obj);
         }
         _impls.length(0);
      }
};

注

マルチスレッドが_implsデータ構造にアクセスしているコードの部分は，排他を提供するためにVISMutexによって保護されています。

付録

付録A　このマニュアルの参考情報

このマニュアルを読むに当たっての参考情報を示します。

付録A.1　関連マニュアル

関連マニュアルを次に示します。必要に応じてお読みください。

なお，CORBAの仕様の詳細については，「The Common Object Request Broker: Architecture and Specification」を参照してください。

付録A.2　このマニュアルでの表記

このマニュアルでは，製品名を次のように表記しています。

略称

製品名称

AIX

AIX V7.1

AIX V7.2

Borland Enterprise Server VisiBroker

Borland(R) Enterprise Server VisiBroker(R)

HP-UX

HP-UX 11i V2 (IPF)

HP-UX 11i V3 (IPF)

IPF

Itanium(R) Processor Family

Java

JavaTM

JavaServer

JavaServerTM

Linux

Red Hat Enterprise Linux 7.1 (AMD/Intel 64)

Red Hat Enterprise Linux 8.1 (AMD/Intel 64)

Netscape Communicator

Netscape(R) Communicator

Netscapeディレクトリサーバ

Netscape(R) Directory Server

Solaris

Solaris 9

Solaris 10

VisiBroker

Borland(R) Enterprise Server VisiBroker(R)

VisiBroker 3.x

VisiBroker Version 3.0（xは0以上の整数）

VisiBroker 4.x

VisiBroker Version 4.0（xは0以上の整数）

VisiBroker 5.x

VisiBroker Version 5.0（xは0以上の整数）

Windows

Windows Server 2016

Windows Server 2016 Standard

Windows Server(R) 2016 Standard 日本語版

Windows Server 2016 Datacenter

Windows Server(R) 2016 Datacenter 日本語版

Windows Server 2019

Windows Server 2019 Standard

Windows Server(R) 2019 Standard 日本語版

Windows Server 2019 Datacenter

Windows Server(R) 2019 Datacenter 日本語版

Windows 10

Windows 10 x64

Windows(R) 10 Enterprise 日本語版(64ビット版)

AIX，HP-UX，LinuxおよびSolarisを総称してUNIXと表記しています。

付録A.3　英略語

このマニュアルで使用する英略語を次に示します。

英略語

英字での表記

ACL

Access Control List

API

Application Programming Interface

BOA

Basic Object Adapter

CA

Certificate Authority

CDE

Common Desktop Environment

CN

Common-Name

CORBA

Common Object Request Broker Architecture

DII

Dynamic Invocation Interface

DLL

Dynamic Linking Library

DNS

Domain Name System

DSI

Dynamic Skeleton Interface

EJB

Enterprise Java Beans(TM)

GIOP

General Inter - ORB Protocol

GUI

Graphical User Interface

HTML

Hyper Text Markup Language

HTTP

Hyper Text Transport Protocol

HTTPS

HTTP-over-SSL

IDL

Interface Definition Language

IIOP

Internet Inter-ORB Protocol

IOR

Interoperable Object Reference

IR

Interface Repository

J2EE

Java(TM) 2 Platform, Enterprise Edition

JAAS

Java(TM) Authentication and Authorization Service

JavaVM

Java(TM) Virtual Machine

JDBC

Java(TM) Database Connectivity

JDK

Java(TM) Development Kit

JNDI

Java Naming and Directory Interface(TM)

JSSE

Java Secure Sockets Extension

LAN

Local Area Network

LDAP

Lightweight Directory Access Protocol

NDS

Novell Directory Services

OAD

Object Activation Daemon

OMG

Object Management Group

OODB

Object-Oriented Database

ORB

Object Request Broker

PKC

Public-Key Certificate

POA

Portable Object Adapter

QoP

Quality of Protection

QoS

Quality of Service

RMI

Remote Method Invocation

RPC

Remote Procedure Call

SGML

Standard Generalized Markup Language

SPI

Service Provider Interface

SSL

Secure Socket Layer

TCP/IP

Transmission Control Protocol/Internet Protocol

TII

Time-Independent Invocation

UDP

User Datagram Protocol

URL

Uniform Resource Locator

W3C

World Wide Web Consortium

WWW

World Wide Web

XML

Extensible Markup Language

付録A.4　KB（キロバイト）などの単位表記について

1KB（キロバイト），1MB（メガバイト），1GB（ギガバイト），1TB（テラバイト）はそれぞれ1,024バイト，1,024²バイト，1,024³バイト，1,024⁴バイトです。

索引

記号

_AccountManagerStub.java[1]

_AccountStub.java[1]

_create_requestメソッドを使用[1]

_requestメソッドを使用[1]

_tie_Accountクラスを使用するためのサーバの変更[1]

_varクラスのメソッド[1]

.java[1]

-DSVCnamerootの使用[1]

-ORBDefaultInitRef（C++）および-DORBDefaultInitRef（Java）[1]

-ORBDefaultInitRef（C++）または-DORBDefaultInitRef（Java）とcorbaloc URLの使用[1]

-ORBDefaultInitRef（C++）または-DORBDefaultInitRef（Java）とcorbanameの使用[1]

-ORBInitRef（C++）および-DORBInitRef（Java）の使用[1]

A

abstract valuetype[1]

abstractインタフェース[1]

Account.java[1]

AccountHelper.java[1]

AccountHolder.java[1]

AccountManager.java[1]

AccountManagerHelper.java[1]、[2]

AccountManagerHolder.java[1]

AccountManagerOperation.java[1]

AccountManagerPOA.java[1]

AccountManagerPOATie.java[1]

AccountManagerオブジェクトのインプリメント[1]

AccountManagerオブジェクトへのバインド[1]

AccountManagerの変更[1]

AccountOperations.java[1]

AccountPOA.java[1]

AccountPOATie.java[1]

Accountオブジェクトのインプリメント[1]

Accountオブジェクトの取得[1]

Accountクラス階層について[1]

Accountクラスの変更[1]

ActiveObjectLifeCycleInterceptor[1]

agentaddr[1]

agentaddrファイルによるホストの指定[1]

Agentの問い合わせ[1]

Anyクラスを使用して型を保護した状態で引き渡す[1]

B

Bank_c.cpp[1]

Bank_c.hh[1]

Bank_s.cpp[1]

Bank_s.hh[1]

Bank.idlのIRオブジェクト階層[1]

BankWrappersを使用可能または使用不可能にするコマンドラインプロパティ[1]

BindInterceptor[1]

Bind Supportポリシー[1]

BOA型のPOAポリシーへのマッピング[1]、[2]

BOAのPOAへの手動による移行[1]

Borland Enterprise Server VisiBroker ORBへのインタセプタの登録[1]

Borland Enterprise Server VisiBrokerアーキテクチャ[1]

Borland Enterprise Server VisiBrokerアプリケーション[1]

Borland Enterprise Server VisiBrokerが提供するコネクション管理[1]

Borland Enterprise Server VisiBrokerが提供するスレッドポリシー[1]

Borland Enterprise Server VisiBrokerでのスレッドの使用[1]

Borland Enterprise Server VisiBrokerとは[1]

Borland Enterprise Server VisiBrokerによるサンプルアプリケーションの開発[1]

Borland Enterprise Server VisiBrokerの開発環境[1]

Borland Enterprise Server VisiBrokerの機能[1]

Borland Enterprise Server VisiBrokerのスマートエージェントアーキテクチャ[1]

Borland Enterprise Server VisiBrokerのプロパティの設定[1]

Borland Enterprise Server VisiBrokerプロパティ[1]

Borland Enterprise Server VisiBrokerを使用したアプリケーションの配置[1]

BY_INSTANCE[1]

BY_POA[1]

C

C++またはJavaのBorland Enterprise Server VisiBrokerでのインターオペラビリティ[1]

CLASSPATH環境変数の設定（Java）[1]

client_server[1]

Client.C[1]

Client.java[1]

ClientRequestInterceptor[1]、[2]

Codec[1]

CodecFactory[1]

concrete valuetype[1]

ConnEventListenersインタフェース[1]

ConnInfo構造体[1]

CORBA::Objectまたはcom.inprise.vbroker.CORBA.Object[1]

CORBA::Objectまたはorg.omg.CORBA.Object[1]

CORBA::PolicyCurrentまたはorg.omg.CORBA.PolicyCurrent[1]

CORBA::PolicyManagerまたはorg.omg.CORBA.PolicyManager[1]

corbaloc URLの使用[1]

corbaname URLの使用[1]

CORBAサービスツール[1]

CORBAとは[1]

CORBAに対するBorland Enterprise Server VisiBrokerの準拠[1]

CORBAに対するBorland Enterprise Server VisiBrokerの準拠での必要事項[1]

CORBAモデルでの例外[1]

CORBAモデルの解説[1]

CreationImplDefクラスの使用による活性化プロパティの設定[1]

custom valuetype[1]

D

DataExpressアダプタ[1]

DataExpressアダプタプロパティ[1]

destroy_on_unregister[1]

DIIとDSIを使用した動的起動[1]

DIIと一緒にIRを使用[1]

DIIの主要な概念[1]

DIIリクエストを生成し初期化する方法[1]

DIIリクエストを送信し，結果を受信[1]

DIIを使用したサンプルプログラムの格納場所[1]

DSIを使用したサンプルプログラムの格納場所[1]

DynamicImplementationクラスの継承[1]

DynAny中の値の初期化とアクセス[1]

DynAnyの型[1]

DynAnyの生成[1]

DynEnum[1]

DynSequenceとDynArray[1]

DynStruct[1]

DynUnion[1]

E

EventListenersのインプリメント[1]

EventListenersの登録[1]

EventListenerインタフェース[1]

EventQueueManagerインタフェース[1]

EventQueueManagerの返し方[1]

F

Factoryクラスのインプリメント[1]

H

Helper.java[1]

Holder.java[1]

I

ID Assignmentポリシー[1]

idl2cpp[1]、[2]

idl2cppの前提条件[1]

idl2ir[1]、[2]

idl2irユーティリティ[1]

idl2irを使用したIRの更新[1]

idl2java[1]、[2]

idl2javaコンパイラの使用[1]、[2]

idl2javaの前提条件[1]

IDLインタフェース名の指定[1]

IDLからC++へのマッピング（C++）[1]

IDLからJavaへのマッピング（Java）[1]

IDLコンパイラ[1]

IDLコンパイラが作成するファイル[1]

IDLコンパイラが生成するクラステンプレート[1]

IDLコンパイラが生成するメソッド（スケルトン）[1]

IDLコンパイラが生成するメソッド（スタブ）[1]

IDLコンパイラのコード生成方法[1]

IDLサンプル[1]

IDL定義[1]

IDLでのAccountインタフェースの記述[1]

IDLとは[1]

IDLのインタフェース属性の定義[1]

IDLの指定例[1]

IDLの使用[1]

IDLファイルのコンパイル[1]

IDLを使用しないインタフェースの定義（Java）[1]

ID Uniquenessポリシー[1]

IMPLICIT_ ACTIVATION[1]

Implicit Activationポリシー[1]

IORCreationInterceptor[1]

IORInterceptor[1]

IORインタセプタ[1]

ir2idlユーティリティ[1]

irep[1]

irepプログラム[1]

irepを使用したIRの生成[1]

irepを使用したIRの生成と表示[1]

IRオブジェクトの識別と分類に使用するオブジェクト[1]

IR内のオブジェクトの識別[1]

IRに格納できるオブジェクト[1]

IRに格納できるオブジェクトの型[1]

IRのIDとインスタンス名の使用[1]

IRの構造の理解[1]

IRの内容[1]

IRの内容表示[1]

IRへのアクセス[1]

J

java2idl[1]

java2iiop[1]

java2iiopおよびjava2idlツール[1]

java2iiopの実行[1]

java2iiopの使用[1]

Java 2標準版[1]

Java開発環境[1]

JavaクラスのIDLへの逆マッピング[1]

Java対応Webブラウザ[1]

Javaのインポート文[1]

Javaの型からIDL/IIOPへのマッピング[1]

Javaランタイム環境[1]

JDBCアダプタ[1]

JDBCアダプタプロパティ[1]

JNDIアダプタ[1]

JNDIアダプタ構成ファイルの例[1]

JNDIアダプタプロパティ[1]

M

MAIN_THREAD_MODEL[1]

Messaging::RebindPolicyまたはorg.omg.Messaging.RebindPolicy[1]

Messaging::RelativeRequestTimeoutPolicyまたはorg.omg.CORBA.Messaging.RelativeRequestTimeoutPolicy[1]

Messaging::RelativeRoundTripTimeoutPolicyまたはorg.omg.CORBA.Messaging.RelativeRoundtripTimeoutPolicy[1]

Messaging::SyncScopePolicyまたはorg.omg.CORBA.Messaging.SyncScopePolicy[1]

MULTIPLE_ID[1]

N

NamedValueクラスを使用して入出力引数を設定する[1]

NamedValueのメソッド[1]

nameserv[1]

NameとNameComponent[1]

NamingContext[1]

NamingContextExt[1]

nilリファレンスの取得[1]

nilリファレンスのチェック[1]

NO_IMPLICIT_ACTIVATION[1]

non_existentオブジェクトのチェック[1]

NON_RETAIN[1]

NONE[1]

nsutilでサポートしているCosNamingオペレーション[1]

nsutilのオプション[1]

nsutilのクローズ[1]

nsutilの構成[1]

nsutilの実行[1]

NVListを使用して引数のリストをインプリメントする[1]

O

oad[1]

OAD::reg_implementationを使用したOADの登録[1]

oadutil list[1]

oadutil listコマンド[1]

oadutil listによるオブジェクトのリスト出力[1]

oadutil reg[1]

oadutil unreg[1]

oadutil unregコマンド[1]

oadutilコマンド[1]、[2]

oadutilツールの使用によるオブジェクトの登録解除[1]

oadutilの使用によるオブジェクトの登録[1]

OADオペレーションを使用した登録解除[1]

OADが渡す引数[1]

OADとのIDLインタフェース[1]

OADとの協力によるオブジェクトへの接続[1]

OADに登録されたオブジェクトの複製[1]

OADに登録されたオブジェクトのマイグレート[1]

OADの起動[1]

OADへのリモート登録[1]

odb.idlインタフェース[1]

Operations.java[1]

ORB_CTRL_MODEL[1]

ORBInitializerの登録[1]

osagent[1]、[2]

OSAGENT_PORT環境変数の設定[1]

osagentコマンド[1]

osagentコマンドのオプション[1]

osfind[1]

osfindコマンド[1]

osfindコマンドのオプション[1]

P

PATH環境変数の設定[1]

PERSISTENT[1]

POA.java[1]

POALifeCycleInterceptor[1]

POATie.java[1]

POAスコープサーバリクエストインタセプタ[1]

POA生成中のORBイベント順[1]

POAネーミング規則[1]

POAの概要[1]

POAの活性化[1]

POAの作成[1]、[2]

POAの作成および使用手順[1]

POAの作成と活性化[1]

POAの使用[1]

POAプロパティの設定[1]

POAポリシー[1]

POAポリシーの設定[1]

POAマネージャ[1]

POAマネージャによるPOA管理[1]

POAマネージャの起動[1]

POA用語[1]

Portable Interceptor Current[1]

post_method起動の順序[1]

pre_methodおよびpost_methodパラメタ[1]

pre_methodおよびpost_methodメソッドの共通引数[1]

pre_method起動の順序[1]

Q

QoSExt::DeferBindPolicyまたはcom.inprise.vbroker.QoSExt.DeferBindPolicy[1]

QoSExt::ExclusiveConnectionPolicyまたはcom.inprise.vbroker.QoSExt.ExclusiveConnectionPolicy[1]

QoSExt::RelativeConnectionTimeoutPolicyまたはcom.inprise.vbroker.QoSExt.RelativeConnectionTimeoutPolicy[1]

QoSインタフェース[1]

QoSの概要[1]

QoS例外[1]

Quality of Serviceの使用[1]

R

RebindModeポリシー[1]

Request Processingポリシー[1]

Requestインタフェース[1]

Requestオブジェクトの生成例[1]

Requestオブジェクトを使用する[1]

Requestクラス[1]

Requestを生成し初期化[1]

resolve_initial_referencesの呼び出し[1]

RETAIN[1]

RMI-IIOPによるJavaアプレットの設定[1]

RMI-IIOPの使用[1]

RMI-IIOPバンクのサンプル[1]

rootPOA[1]

rootPOAの取得[1]

rootPOAのリファレンスの取得[1]

S

send_deferredメソッドを使用して遅延DIIリクエストを送信[1]

send_onewayメソッドを使用して非同期DIIリクエストを送信[1]

ServantActivator[1]

ServantLocator[1]

Servant Retentionポリシー[1]

ServerRequestInterceptor[1]、[2]

ServerRequestクラスの考察[1]

Serverクラスの変更[1]

ServiceResolverInterceptorのサンプル[1]

ServiceResolverインタセプタ[1]

SINGLE_THREAD_MODEL[1]

Stub.java[1]

SYSTEM_ID[1]

T

tie機能の使用[1]

tie機能の働き[1]

tie機能を使用したサンプルプログラムの格納場所[1]

tieテンプレートの考察[1]

tieのサンプルプログラムの構築[1]

TRANSIENT[1]

TriggerHandlerインタフェースメソッド（C++）[1]

TriggerHandlerインタフェースメソッド（Java）[1]

truncatable valuetype[1]

TypeCodeクラスを使用して引数または属性の型を表す[1]

TypeCodeの種類とパラメタ[1]

U

UNIQUE_ID[1]

UNIXでのOSAGENT_PORT環境変数の設定[1]

UNIXでのPATH環境変数の設定[1]

UNIXでのVBROKER_ADM環境変数の設定[1]

unreg_implementation()[1]

unreg_interface()[1]

unregister_all()[1]

URLによるオブジェクトの検索[1]

URLネーミングサービス[1]

URLネーミングの使用[1]

USE_ACTIVE_OBJECT_MAP_ONLY[1]

USE_DEFAULT_SERVANT[1]

USE_SERVANT_MANAGER[1]

USER_ID[1]

UtilityObjectWrappersを使用可能または使用不可能にするコマンドラインプロパティ[1]

V

valuetypeとは[1]

valuetypeのインプリメント[1]

valuetypeの使用[1]

valuetypeの定義[1]

valuetypeの登録[1]

valuetypeの派生[1]

valuetypeベースクラスの継承[1]

vbjによるネーミングサービスの起動[1]

vbjの使用[1]

VBROKER_ADM環境変数の設定[1]

vbroker.naming.backingStoreType[1]、[2]

vbroker.naming.jdbcDriver[1]

vbroker.naming.loginName[1]、[2]

vbroker.naming.loginPwd[1]、[2]

vbroker.naming.poolSize[1]

vbroker.naming.url[1]、[2]

vbroker.orb.enableBiDirプロパティ[1]

vbroker.se.<se-name>.scm.<scm-name>.manager.exportBiDirプロパティ[1]

vbroker.se.<se-name>.scm.<scm-name>.manager.importBiDirプロパティ[1]

VisiBroker 4.xインタセプタインタフェースおよびマネージャ[1]

VisiBroker 4.xインタセプタ間での情報の渡し方[1]

VisiBroker 4.xインタセプタの使用[1]

VisiBroker ORBインプリメンテーションの動的変更[1]

VisiBroker ORBと一緒に配置されたクライアントプログラムとサーバプログラム[1]

VisiBroker ORBドメイン内の作業[1]

VisiBroker ORBの初期化[1]、[2]

VisiBroker ORBへのFactoryの登録[1]

VisiBrokerコードの移行[1]

W

Webネーミング（Java）[1]

WindowsおよびUNIXプラットフォームでのプロパティの優先順位[1]

Windowsで生成されるログファイル名のまとめ[1]

WindowsでのOSAGENT_PORT環境変数の設定[1]

WindowsでのVBROKER_ADM環境変数の設定[1]

WindowsのDOSコマンドによるPATH環境変数の設定[1]

WindowsのシステムコントロールパネルによるPATH環境変数の設定[1]

Windowsレジストリ[1]

X

XDispatcherクラスまたはWDispatcherクラスによる移行[1]

あ

アクセス可能なすべてのインタフェースの検索[1]

アクティブオブジェクトマップ[1]

アクティブな状態[1]

アクティベータインタフェース[1]

アダプタアクティベータ[1]、[2]

新しいAPI呼び出しへの移行[1]

新しいパッケージ名への移行[1]

新しいプロパティセット[1]

アドミニストレーションツール[1]

アプリケーションの実行[1]

アプリケーションの配置[1]

アプレットのパラメタ（ORB.initの第1パラメタ）（Javaの場合）[1]

アプレットのプロパティの優先順位[1]

あるインタフェースのインスタンスのリファレンスの取得[1]

あるインタフェースのすべてのインスタンスの検索[1]

あるインタフェースの同名インスタンスに対するリファレンス（C++）[1]

あるインタフェースの同名インスタンスに対するリファレンス（Java）[1]

あるインタフェースの同名インスタンスに対するリファレンスの取得[1]

アンタイプドオブジェクトラッパー[1]

アンタイプドオブジェクトラッパー制御用のコマンドライン引数[1]

アンタイプドオブジェクトラッパーのイニシャライザ[1]

アンタイプドオブジェクトラッパーのインプリメント[1]

アンタイプドオブジェクトラッパーの削除[1]

アンタイプドオブジェクトラッパーの使用[1]

アンタイプドオブジェクトラッパーファクトリのインプリメント[1]

アンタイプドオブジェクトラッパーファクトリの生成と登録[1]

アンタイプドオブジェクトラッパー用コマンドライン引数[1]

暗黙的な活性化[1]、[2]

い

イベントキュー[1]、[2]

イベントタイプ[1]

イベントリスナー[1]

イベントループの統合の移行[1]

インカネート[1]

インタセプタ[1]

インタセプタオブジェクトの生成[1]

インタセプタとオブジェクトラッパーを使用したVisiBroker ORBのカスタマイズ[1]

インタセプタの移行[1]

インタセプタの機能[1]

インタセプタのサンプル[1]

インタセプタの例の実行結果[1]

インタセプタのロード[1]

インタセプトポイントの呼び出し順[1]

インタフェース[1]

インタフェース名からリポジトリIDへの変換[1]

インタフェース名とオブジェクト名を取得するメソッド[1]

インタフェースリポジトリとインプリメンテーションリポジトリ[1]

インタフェースリポジトリとは[1]

インタフェースリポジトリの使用[1]

インプリメンテーションとオブジェクト活性化のサポート[1]

インプリメンテーションリポジトリデータの探索[1]

インプリメンテーションリポジトリの内容表示[1]

インメモリアダプタ[1]

え

エージェント間の協力によるオブジェクトの探索[1]

エージェントの可用性の確保[1]

エージェントを使用禁止にする[1]

エーテライズ[1]

お

応答を受信するオプション[1]

オーダーエントリシステムのネーミング手法[1]

同じクライアントから2番目のリクエストが入ってくる[1]

同じサーバプロセス中の二つのオブジェクトにバインド[1]

オブジェクトID[1]

オブジェクトアクティベータの使用[1]

オブジェクトインタフェースの定義[1]

オブジェクトインプリメンテーションの動的生成手順[1]

オブジェクト活性化デーモンの使用[1]

オブジェクト活性化デーモンユーティリティの使用[1]

オブジェクト活性化の遅延[1]

オブジェクト可用性の確保[1]

オブジェクトとサーバの自動活性化[1]

オブジェクトの暗黙的な活性化[1]

オブジェクトのオペレーションの呼び出し[1]

オブジェクトのオペレーションを動的に起動する手順[1]

オブジェクトのオンデマンドによる活性化[1]

オブジェクトの活性化[1]、[2]

オブジェクトの生成と登録の例[1]

オブジェクトの登録[1]

オブジェクトの登録解除[1]

オブジェクトの非活性化[1]

オブジェクトの複数のインスタンスの区別[1]

オブジェクトの明示的な活性化[1]

オブジェクトへのバインド[1]、[2]

オブジェクト名とインタフェース名の取得[1]

オブジェクトラッパーの使用[1]

オブジェクトリファレンス生成中のORBイベント順[1]

オブジェクトリファレンスの位置と状態を判定するメソッド[1]

オブジェクトリファレンスの解放[1]

オブジェクトリファレンスの操作[1]

オブジェクトリファレンスのタイプの判定[1]

オブジェクトリファレンスのタイプを判定するメソッド[1]

オブジェクトリファレンスのナロウイング[1]

オブジェクトリファレンスの複製[1]

オブジェクトリファレンスのワイドニング[1]

オブジェクトを処理するクライアントプログラム[1]

オンデマンドによる活性化[1]、[2]

か

開発手順[1]

開発手順の概要[1]

開発プロセスの完了[1]

カレントの状態の取得[1]

環境設定[1]

環境変数[1]

環境変数によるIPアドレスの指定[1]

監視プロパティとディスパッチプロパティの設定[1]

完了状態の取得[1]

き

既存のアプリケーションで双方向IIOPを有効にする[1]

起動の順序[1]

基本データ型のマッピング[1]

キャッシングおよびセキュリティオブジェクトラッパーを使用可能にする[1]

キャッシング機能[1]

共用セマンティクス[1]

く

クライアントアプリケーション#1が2番目のリクエストを送信[1]

クライアントアプリケーション#1がリクエストを送信[1]

クライアントアプリケーション#2がリクエストを送信[1]

クライアントアプリケーションのコマンドライン引数（C++）[1]

クライアントアプリケーションのコマンドライン引数（Java）[1]

クライアントアプリケーションのサンプル[1]

クライアントアプリケーションの実行[1]

クライアントインタセプタ[1]

クライアントおよびサーバアプリケーションの開発[1]

クライアント側インタセプタ[1]

クライアント側およびサーバ側リクエストインタセプタでのRequestInterceptorのインプリメント[1]

クライアント側の規則の具体例[1]

クライアントスタブとサーバサーバントの生成[1]

クライアントでのClientRequestInterceptorのインプリメント[1]

クライアントとスマートエージェントの相互動作[1]

クライアントのインプリメント[1]

クライアントの基本事項[1]

クライアントの実行[1]

クライアントの存在の確認[1]

クライアント用タイプドオブジェクトラッパーの登録[1]

クライアント用に生成されたコードの考察[1]

クライアントリクエストを待つ[1]

クライアント−サーバインタセプタのサンプル[1]

クラスタ[1]

クラスタインタフェースとClusterManagerインタフェース[1]

クラスタ化方法[1]

クラスタの生成[1]

クラス名の変更（C++）[1]

クラス名の変更（Java）[1]

け

継承されるインタフェース[1]

ゲートキーパー[1]

こ

子POAの作成[1]

構成と使用[1]

構造化データ型[1]

構造化データ型でコンポーネントを移動する[1]

構造化データ型を表現するDynAny派生インタフェース[1]

コーディングの考慮事項[1]

コードサンプルのまとめ[1]

異なるローカルネットワーク上のスマートエージェントの接続[1]

コネクションイベント[1]

コマンドラインからのネーミングサービスの呼び出し[1]

コマンドライン引数[1]

これらのプロパティはいつ使用するか[1]

コンパイルの手順[1]

さ

サーバアプリケーションのサンプル[1]

サーバインタセプタ[1]

サーバエンジンの概要[1]

サーバエンジンプロパティの設定[1]

サーバ側インタセプタ[1]

サーバ側インタセプタでのORBInitializerのインプリメント[1]

サーバ側の規則の具体例[1]

サーバ側のポータビリティ[1]

サーバコネクションマネージャプロパティの設定[1]

サーバでのServerRequestInterceptorのインプリメント[1]

サーバのインプリメンテーション[1]

サーバのインプリメント[1]

サーバの起動[1]、[2]

サーバの起動とサンプルの実行[1]

サーバの基本事項[1]

サーバプログラム[1]

サーバプロセス中の一つのオブジェクトにバインド[1]

サーバ用タイプドオブジェクトラッパーの登録[1]

サーバ用に生成されたコードの考察[1]

サーバント[1]

サーバントとサーバントマネージャの使用[1]

サーバントの定義[1]

サーバントマネージャ[1]

サーバントマネージャ機能の例[1]

サーバントメソッドのインプリメント[1]

サービスアクティベータのインプリメント[1]

サービスアクティベータの実体化[1]

サービスアクティベータを使用したオブジェクト活性化の遅延[1]

サービスアクティベータを使用したオブジェクトの活性化[1]、[2]

サービス活性化オブジェクトインプリメンテーションの非活性化[1]

サービス活性化オブジェクトのインプリメント[1]

サービス活性化のアプローチ方法[1]

サービス活性化用odbのサンプルファイル[1]

サービスの遅延オブジェクト活性化のサンプル[1]

サポートされているサービスを使用するには[1]

サポートされるデータ型[1]

サポートしているインタフェース[1]

残高の取得[1]

サンプルアプリケーションの実行[1]

サンプルアプリケーションのパッケージの位置[1]

サンプルのコンパイル[1]

サンプルのバンクアプリケーションの開発[1]

サンプルの目的[1]

サンプルプログラム[1]、[2]、[3]

サンプルプログラムのビルド[1]

し

シェル／コンソール環境から設定できるプロパティ[1]

シェル／コンソールの環境変数[1]

システムプロパティ（Javaの場合）[1]

システム例外[1]

システム例外のキャッチ[1]

システム例外のタイプの判定[1]

システム例外への例外のダウンキャスト[1]

実行時パラメタとしてのホストの指定[1]

実体化されたオブジェクトのマイグレート[1]

自動メモリ管理<interface_name>_varクラス[1]

主要なCORBA例外，および考えられる原因[1]

使用上の制限事項[1]

状態を維持しないオブジェクトのメソッドの呼び出し[1]

状態を維持するオブジェクトのフォルトトレランスの実現[1]

状態を維持するオブジェクトのマイグレート[1]

使用できるIRの数[1]

シングルスレッドVisiBroker ORBの移行[1]

す

すべてのオブジェクトとサービスの報告[1]

スマートエージェント（osagent）の起動[1]

スマートエージェントが認識するものをすべて検索[1]

スマートエージェント起動時の注意事項[1]

スマートエージェントとは[1]

スマートエージェントの起動[1]

スマートエージェントの使用[1]

スマートエージェントの互いの検知方法[1]

スマートエージェントの探索[1]

スマートエージェント用インタフェースの指定[1]

スマートエージェントを実行するすべてのホスト名の取得[1]

スマートエージェントを使用した，オブジェクトのインスタンスの検索[1]

スレッドとコネクションの管理[1]

スレッドとコネクションの強力な管理[1]

スレッドのプールが利用できる[1]

スレッドパーセッション[1]

スレッドパーセッションポリシー[1]

スレッドパーセッションポリシーを使用したオブジェクトインプリメンテーション[1]

スレッドプーリング[1]

スレッドプーリングポリシー[1]

スレッドポリシー[1]

せ

生成されたコードの考察[1]

セキュリティの考慮事項[1]

そ

双方向IIOPの使用[1]

双方向IIOPを明示的に有効にする[1]

双方向VisiBroker ORBのプロパティ[1]

双方向通信[1]

そのほかのメソッド[1]

た

待機状態[1]

タイプドオブジェクトラッパー[1]

タイプドオブジェクトラッパーおよび同一プロセスにあるクライアントとサーバ[1]

タイプドオブジェクトラッパー制御用のコマンドライン引数[1]

タイプドオブジェクトラッパーのイニシャライザ[1]

タイプドオブジェクトラッパーのインプリメント[1]

タイプドオブジェクトラッパーの起動順序[1]

タイプドオブジェクトラッパーのコマンドライン引数[1]

タイプドオブジェクトラッパーの削除[1]

タイプドオブジェクトラッパーの使用[1]

タイプドおよびアンタイプドオブジェクトラッパー[1]

タイプドおよびアンタイプドオブジェクトラッパーの機能の比較[1]

タイプドおよびアンタイプドオブジェクトラッパーの混在使用[1]

タイプドおよびアンタイプドオブジェクトラッパーを使用可能にする[1]

タイミングおよびトレーシングオブジェクトラッパーを使用可能にする[1]

多数のIRオブジェクトが継承するインタフェース[1]

単一のアンタイプドオブジェクトラッパー[1]

単純名と複合名[1]

て

ディスパッチポリシーとプロパティの設定[1]

ディスパッチャプロパティ[1]

デフォルトコンテキストの取得（C++）[1]

デフォルトサーバントによる活性化[1]、[2]、[3]

デフォルトネーミングコンテキスト[1]

デフォルトネーミングコンテキストの取得（Java）[1]

デフォルトのインタセプタクラス[1]

と

同一プロセスにあるクライアントとサーバを実行する[1]

動的管理型の使用[1]

動的起動インタフェースとは[1]

動的起動インタフェースの使用[1]

動的スケルトンインタフェースとは[1]

動的スケルトンインタフェースの使用[1]

動的リクエスト用オブジェクトの設計例[1]

登録された単一のタイプドオブジェクトラッパー[1]

登録された複数のタイプドオブジェクトラッパー[1]

特定の型のシステム例外のキャッチ[1]

トランジェントオブジェクト[1]

トリガーが検出した最初のインスタンスだけを確認[1]

トリガーとは何か[1]

トリガーの生成[1]

トリガーハンドラのインプリメントと登録[1]

トリガーハンドラの記述と登録[1]

トリガーメソッド（C++）[1]

トリガーメソッド（Java）[1]

トリガーメソッドの考察[1]

な

名前のバインド[1]

に

入力パラメタを処理する[1]

入力リクエスト待ち[1]

任意のインタフェースをインプリメントするオブジェクトのリファレンスの取得（C++）[1]

任意のインタフェースをインプリメントするオブジェクトのリファレンスの取得（Java）[1]

ぬ

ヌルセマンティクス[1]

ね

ネーミングコンテキスト[1]

ネーミングコンテキストファクトリ[1]

ネーミングサービスのインストール[1]

ネーミングサービスのオプション[1]

ネーミングサービスの起動[1]

ネーミングサービスの実行[1]

ネーミングサービスの使用[1]

ネーミングサービスの設定[1]

ネーミングサービスのバッキングストア（外部記憶装置）[1]

ネーミングサービスプロパティ[1]、[2]

ネーミングサービスへの接続[1]

ネーム解決[1]

ネームスペース内のネーミングコンテキストからのオブジェクト名のバインド，解決，使用[1]

ネームスペースの解説[1]

は

パーシステントオブジェクト[1]

バーボース出力[1]

配列[1]

バインドされたオブジェクトの位置と状態の判定[1]

バインドプロセス中に行われる動作[1]

破棄状態[1]

バッキングストアのタイプ[1]

汎用的なオブジェクトリファレンスを取得[1]

ひ

非アクティブな状態[1]

引数をAny型でカプセル化する[1]

必須パッケージのインポート[1]

一つのインタフェースのインスタンスを持つネットワーク上のスマートエージェント[1]

ふ

ファクトリ[1]

ファクトリとvaluetype[1]

ファクトリのインプリメント[1]

フェールオーバー[1]

フォルトトレランス用のネーミングサービスの設定[1]

負荷分散[1]

複合データ型のマッピング[1]

複数のアンタイプドオブジェクトラッパー[1]

複数のアンタイプドオブジェクトラッパーの使用[1]

複数のタイプドオブジェクトラッパーの使用[1]

複数のリクエストを受信[1]

複数のリクエストを送信[1]

プラガブルバッキングストア[1]

プログラミングツール[1]

プログラムのコンパイルとリンク[1]

プロパティ（Javaの場合）[1]

プロパティの設定[1]

プロパティファイル[1]

プロパティファイル（ORBpropStorageオプションを使用）[1]

へ

別のインタフェースを継承するインタフェースのIDLでの指定[1]

別々のORBドメインの同時実行[1]

別々のローカルネットワークに存在する二つのスマートエージェント[1]

ほ

ポインタタイプ<interface_name>_ptr定義[1]

ポイントツーポイント通信の使用[1]

ポータブルインタセプタおよびVisiBroker 4.xインタセプタを同時に使用[1]

ポータブルインタセプタおよび情報インタフェース[1]

ポータブルインタセプタのBorland Enterprise Server VisiBroker拡張機能[1]

ポータブルインタセプタの作成[1]

ポータブルインタセプタの使用[1]

ポータブルインタセプタの登録[1]

ポータブルオブジェクトアダプタとは[1]

ポータブルオブジェクトアダプタ用語[1]

ほかのORB製品とのインターオペラビリティ[1]

ホスト間のオブジェクトのマイグレート[1]

ボックス型 valuetype[1]

ポリシー[1]

ポリシーの変更および有効ポリシー[1]

ま

マイナーコードの取得と設定[1]

マネージャプロパティ[1]

マルチホームホストのスマートエージェント[1]

マルチホームホストを使用した作業[1]

め

明示的な活性化[1]、[2]

明示的なクラスタと暗黙的なクラスタ[1]

も

文字列化された名前[1]

文字列化と非文字列化のメソッド[1]

ゆ

ユーザ例外[1]

ユーザ例外のキャッチ[1]

ユーザ例外の定義[1]

ユーザ例外へのフィールドの追加[1]

ら

ライフスパンポリシー[1]

り

リクエストインタセプタ[1]

リクエストのインタセプタポイント[1]

リクエストのコンテキストを設定[1]

リクエストの処理[1]

リクエストの引数を設定[1]

リクエストを起動[1]

リクエストを送信するオプション[1]

リスナープロパティ[1]

リターン値を設定する[1]

リターン値を持たないonewayメソッドの指定[1]

リファレンスカウントの取得[1]

リファレンスの文字列への変換[1]

リポジトリIDの指定[1]、[2]

る

ルートPOAのリファレンスの取得[1]

れ

例外の処理[1]

例外を発生させるためのオブジェクトの修正[1]

ろ

ロギング出力[1]

ロケーションサービスエージェントとは[1]

ロケーションサービスコンポーネント[1]

ロケーションサービスとは[1]

ロケーションサービスの使用[1]

ロケーションサービスを使用した高度なオブジェクト探索[1]