1.2. プログラミング・開発ガイド

1.2.1. WebOTX AS CORBAアプリケーション

1.2.1.1. はじめに

本プログラミング編では、WebOTXを使ったクライアントおよびサーバアプリケーションの作成について説明したマニュアルです。
R5.3からの変更点は以下の通りです。
R4.2からの変更点は以下の通りです。
R3.2からの変更点は以下の通りです。
本文中では以下の略語を利用します。
WebOTXの特徴
アプリケーションの構成

単純なCORBAアプリケーションは図1のような構成になっています。

単純なCORBA構成
図1.2.1.1-1

図1 単純なCORBA準拠アプリケーション
CORBAに準拠したアプリケーションをWebOTX上で動作させると図2のようになります。

WebOTXを使ったCORBA構成
図1.2.1.1-2

図2 WebOTX上で動作させたCORBAアプリケーション
WebOTX上で動作させるには、WebOTXに登録するだけでよく、通常のオペレーションコールなどのプログラムロジックを変更する必要はありません。
アプリケーションの開発者は、1台の開発機でクライアント、サーバ双方のアプリケーションを開発し、動作を確認してからWebOTXに組み込むことができます。
ステート(ステートフル、ステートレス)
サーバアプリケーションのオブジェクトをWebOTX上で実行する場合、利用者はそれらを ステートレス (状態なし)、 ステートフル (状態あり)のどちらで実行するかを指定します。本節では、WebOTXがステートレスサーバオブジェクト、ステートフルサーバオブジェクトをどのように実行するかを説明します。
ステートレスサーバオブジェクトの動作
クライアントアプリケーションがステートレスサーバオブジェクトに対してオペレーションを呼び出すと、その呼び出しは実行中でない任意のオブジェクト(後述のスレッドモデルの指定によっては使用中のオブジェクトもあり得る)に伝えられます。つまり、クライアントアプリケーションが1つのオブジェクトに対して複数回オペレーションを呼び出すと、それらの呼び出しは別々のサーバオブジェクトで実行される可能性があります。このため、オペレーションの実行結果をサーバオブジェクト内部に保存することは出来ません。
ステートフルサーバオブジェクトの動作
ステートフルでは、クライアントアプリケーションがサーバオブジェクトを生成して解放するまでの間、WebOTXは常に同じサーバオブジェクトに束縛します。このため、オペレーションの実行結果をサーバオブジェクト内部に保存することが可能です。
スレッドモデル(アパートメント、フリースレッド)
WebOTXはプロセス制御とスレッド制御の両方の機能を有しています。このため、マルチスレッド対応していない外部のDLLを含む場合はマルチプロセスで実行させることが可能となっています。また、マルチプロセス+ステートレス形態で動作させることにより、他のプロセスで障害が発生したとしても別のプロセスでの実行が可能ですから、障害の局所化という意味でも有効と言えます。
ここでスレッドモデルについて説明しておきます。スレッドモデルには以下のような種類が存在します。
WebOTXはすべてのモデルのサーバアプリケーションを実行できます。ただし、サーバアプリケーションが使用している外部部品がスレッドセーフでない場合はマルチスレッド指定では正しく動作しません。この場合、マルチプロセスにて1スレッドで実行させて下さい。
サーバオブジェクトとファクトリオブジェクト
WebOTXではIDLで定義したインタフェースに対応するサーバオブジェクトと、そのサーバオブジェクトの生成と消滅を行うファクトリオブジェクトという二つのオブジェクトを使用します。 ファクトリオブジェクトに関する定義や実装は、WebOTX専用のIDLコンパイラ (C++はwoigenxx, Javaはwoi2j)を用いることにより自動生成します。
また、ファクトリオブジェクトを利用しない「ファクトリオブジェクトレス」という機能もあります。ファクトリオブジェクトレスのメリットは、名前サーバにあるサーバオブジェクトをすぐに使えることです。 逆にデメリットはステートフルオブジェクトを使用できない (ステート(ステートフル、ステートレス)を参照)、 オブジェクトの事前生成が必須、 クライアント管理ライブラリが使用できないことです。
以下にファクトリオブジェクトがある場合とない場合の違いをまとめます。
表1.2.1.1-1
ファクトリあり
ファクトリなし
サーバオブジェクトの遅延生成
可能
不可能
ステートフルオブジェクト
利用可能
利用不可能
クライアント管理ライブラリ
利用可能
利用不可能
既存クライアントAPの利用
ファクトリのコーディングが必要
変更不要
通信量
サーバオブジェクトの生成/消滅のオペレーションコールが余計にある
通常のCORBAアプリケーションと同じ
構築するシステムに応じて使い分けてください。
R5形式とR4形式
任意のクラスや同一インタフェース複数インプリメンテーションを利用するには新しいアプリケーション作成方法で作成する必要があります。本手引書ではR4.2までのアプリケーション作成方法を「R4形式※」、R5.1以降のアプリケーション作成方法を「R5形式」と呼びます。
※V8以降はR4形式のアプリケーション作成は推奨しません。
R5形式とR4形式の特徴は以下の通りです。
 R5形式
  R4形式
R5形式は基本的にステートレスになります。ステートフルオブジェクトを扱うには以下のルールに従う必要があります。
interface foo     // ステートフルオブジェクト
{
    void op(in string a, out in string a);
};

interface barFactory
{
    foo creObj();
    ^^^ ^^^^^^^^
    |          +------------------------ オペレーション名は任意です
    +----------------------------------- ステートフルオブジェクトのインタフェース

    void relObj(in foo obj);
    ^^^^ ^^^^^^ ^^^^^^^^^^
    |    |      +----------------------- 上記メソッドの返却値を設定。
    |    |                               これ以外の値は渡してはいけない
    |    +------------------------------ オペレーション名は任意です
    +----------------------------------- 返却値はvoid固定です
};
サーバオブジェクトの事前生成機能
一般にオブジェクトの生成は、サーバ上のオブジェクトの生成だけでなくデータベースへのコネクト処理等多くの初期設定が行われるため、多くの処理時間を必要とします。WebOTXは、起動時にあらかじめオブジェクトを生成しておくことが可能です。 WebOTXはステートレスサーバオブジェクト、 常駐オブジェクトの二種類のオブジェクトを事前生成できます。 ステートレスサーバオブジェクトの事前生成 クライアントアプリケーションがステートレスサーバオブジェクトの生成を要求すると、WebOTXはあらかじめ生成しておいたサーバオブジェクトを直ちにクライアントアプリケーションに渡すことができます。「プロセスグループを事前起動する」と運用管理ツールで指定した場合、WebOTXは起動時に指定された数のサーバオブジェクトを事前生成します。 ただし、サーバオブジェクトを事前生成すると、クライアントが利用しているか否かに関わらず常に一定のリソース(事前生成機能で生成されるオブジェクト数は、同時処理要求数と同一)を確保してしまいますので、使用頻度が高く処理性能が要求される業務のみに使用するようにして下さい。 (なお、同時処理要求数=スレッド数×プロセス数です) 利用者が運用管理ツールを使って、あるクラスのサーバオブジェクトを事前生成しないと指定した場合、WebOTXは次のタイミングでサーバオブジェクトの生成、解放を行います。 ステートレスの場合は、あるスレッドに対して初めてオペレーションが投入された時点でサーバオブジェクトを生成します。生成されたサーバオブジェクトは、サービスが停止するまで解放されません。 ステートフルの場合は、クライアントアプリケーションがサーバオブジェクトの生成を要求した時点でサーバ上にオブジェクトを生成します。また、クライアントアプリケーションがサーバオブジェクトを解放(ファクトリオブジェクト経由でReleaseServerObject()オペレーションを呼び出す)すると、サーバ上のオブジェクトは消滅します。ステートフルサーバオブジェクトは事前生成できません。
常駐オブジェクト機能
ステートフルサーバオブジェクトは事前生成できません。このとき、オブジェクトのコンストラクタ内部で時間のかかる処理(例えばデータベースへの接続など)がある場合、クライアントから接続があって初期化が完了するまで時間がかかってしまいます。 そこで、WebOTXではサーバオブジェクトとは別に事前に生成することができるオブジェクトを用意しました。それが常駐オブジェクトです。 常駐オブジェクトはCORBAオブジェクトではなく、言語依存のオブジェクトです。利用者が運用管理ツールで常駐オブジェクトのDLL名(C++)あるいはクラス名(Java)を指定すると、 WebOTXは起動時に各オブジェクトを1スレッドにつき1つ生成します。 サーバアプリケーションは TPSGetPrecreatedUsersObject() (単一用。旧インタフェース) あるいは TPSGetPrecreatedUsersObjectForPluse() (複数用。新インタフェース) を用いて常駐オブジェクトを取得します。 常駐オブジェクトはスレッド毎に作成しますので、フリースレッドモデルでマルチスレッドで動作している場合(ステートフルの場合はほとんどそうですが)、オペレーション毎に実行スレッドが異なりますので、常駐オブジェクトはオペレーション毎に取得し直して利用してください。そうしないと複数のスレッドから同時に実行される恐れがありますので注意が必要です。例えば、データベースを扱う常駐オブジェクトを作成した場合、あるスレッドがデータベースの更新を行っている途中で、別のスレッドが割り込んできて値を書きかえる恐れがあります。このようなことが無いように、必ず取得し直すようにしてください。
共有プロパティ機能
プロセスグループには複数のコンポーネントが登録可能です。 コンポーネント間で共有データなどを参照する場合(ディスクに書き込む必要のない、変化の激しいデータ)は、グローバル変数を使うことにより実現できます。しかし、グローバル変数を用いた方法では幾つかの問題点が あります。一つは排他処理が必須であるが煩雑であること。もう一つはプロセス間におけるデータの共有ができないことです。WebOTXでは、これらの問題点を克服した共有プロパティという機能があります。 ここでは、共有プロパティについて説明します。
共有プロパティ概要
共有プロパティは以下の4つの要素から構成されています。
プロパティグループエリアとは、以下に説明するプロパティグループを作成する場所のことです。場所の種類は「ホスト内共有」、「システム内共有」、「アプリケーショングループ内共有」、「プロセスグループ内共有」の4種類です。 ホスト内共有の場合、複数のWebOTXシステムを一つのマシンで動かしたとき、すべてのプロセスから参照や更新をすることが出来ます。システム内共有の場合、そのシステム内のすべてのプロセスから参照や更新をすることができます。アプリケーショングループ内共有の場合は、そのアプリケーショングループ内のすべてのプロセスから参照や更新をすることが出来ます。プロセスグループ内共有の場合は、そのプロセスグループ内のすべてのプロセスから参照や更新をすることが出来ます。 プロパティグループとは、複数のプロパティを一つのグループとしてまとめた単位のことです。 共有プロパティを利用するときは必ずプロパティグループを作成しなければなりません。プロパティとは値を格納する単位のことです。値とは、プロパティに設定する数値や文字列のことです。 プロパティグループおよびプロパティには、プロパティグループエリア内で一意に識別する文字列を設定します。 この文字列をキーにコンポーネント間で値を受け渡します。
共有コンポーネント機能
汎用的なルーチンを複数のサーバAPから利用したい場合や、基底インタフェースを定義したIDLを複数のサーバAPで共有したい時は共有コンポーネント機能を使うことで実現できます。 また、共通に利用するサブルーチンを一まとめにして登録することもできます。登録方法に関しては「ドメイン構築・基本設定ガイド」をご覧ください。 共有コンポーネントの作成方法は各サーバAPの作り方をご覧ください。
データベース自動接続/切断機能
WebOTXでは、データベースへの自動接続/コミット機能があります。これは、データベースへのアクセスコーディングを減らすことを目的としています。 また、この機能を使用するときはWebOTX Transaction Service連携は使用できませんので注意してください。さらに、独自にコネクションやコミット制御を行うコーディングを行う場合はOracleに限らず任意のデータベースが利用でますが、マルチスレッド環境に対応している必要があります。
非同期トランザクション機能
通常、IDLコンパイラが生成したソースを用いてCORBAアプリケーションを作成した時は同期型か遅延同期型しかありません。DII(Dynamic Invocation Interface)を使用して非同期呼び出しを行うことも可能ですが難易度が高いのが現状です。また、非同期に呼び出したオペレーションの伝達保証もありません。 WebOTXでは以下に示す仮想宛先機能を使うことにより、呼び出し伝達の保証しつつ、コーディングの変更なしに非同期にオペレーションを呼び出すことができる 非同期トランザクション機能 を提供します。
WebOTX Transaction Serviceを用いたOTS連携機能
複数のデータベースを同時に更新してコミットしたい時、独自にコーディングすると膨大なエラー処理を考慮してコーディングする必要があります。 WebOTXでは、このような業務形態に対応する為に、分散オブジェクト環境で使われる標準仕様の開発と普及を目的とする非営利団体OMG(Object Management Group)によって策定されたCORBAトランザクションサービス1.1に完全に準拠したWebOTX Transaction Serviceと連携する機能があります。 WebOTX Transaction Serviceを使うと、1台のサーバで集中して処理を行う集中型のシステムや複数サーバ・クライアントが協調して処理を行う分散型のシステムなど、さまざまな業務形態に合わせたシステムを構築することができます。また、分散されたデータのコミット・ロールバックをトランザクションの結果にしたがってWebOTX Transaction Serviceが確実に実施しますので、簡単に堅牢なシステムを構築することができます。
コールバック機能
WebOTXでは、さまざまな状態に応じてサーバオブジェクトや常駐オブジェクトを呼び出す コールバック機能があります。以下に機能の一覧をまとめます。
表1.2.1.1-2
説明
C++言語
Java言語
DLL読み込み時/解放時
サーバアプリケーションDLL(コンポーネント)を読み込んだ時と解放時に特定の関数呼び出します。
×
プロセス起動時/終了時
プロセス初期化中および終了処理中に、特定のクラスファイル(InitTerm.class)のメソッドを呼び出します。
×
サーバオブジェクト生成時/解放時
サーバオブジェクト生成後と解放前に特定のインタフェースを実装している時に呼び出します。
×
常駐オブジェクト生成時/解放時
常駐オブジェクトを生成後と解放前に特定の関数を定義している時(あるいは特定のインタフェースを実装している時)に呼び出します。
オペレーション毎の常駐オブジェクトの呼び出し
各オペレーションが呼び出されたときや、正常終了、異常終了、サーバアプリケーション例外、クライアントとのセション切断時に特定の関数を定義している時(あるいは特定のインタフェースを実装している時)に呼び出します。
アプリケーション例外時
サーバアプリケーション処理中に例外したとき、WO_BASEインタフェースからの派生の時に限りOnTPSAbort()を呼び出します。
クライアントとのセション切断時
サーバアプリケーション処理中に例外したとき、WO_BASEインタフェースからの派生の時に限りOnTPSDisconnect()を呼び出します(ステートフルの時のみ)。
なお、運用管理ツールで指定した時間以上の処理時間がかかった時はプロセスを強制的に停止します。
クライアント管理ライブラリ機能
WebOTXでは、クライアントマシンの無通信監視や非同期メッセージ処理などを行うクライアント管理ライブラリを提供しています(逆にこのライブラリを使用しないと無通信監視や非同期メッセージ処理は利用できません)。
1.2.アプリケーション作成に必要なソフトウェア
WebOTXのアプリケーションを開発するのに必要なソフトウェアは[ セットアップガイド > 1. セットアップ > 1.1. 使用上の条件 ] および [ セットアップガイド > 1. 使用上の条件 ] を参照してください。

1.2.1.2. WebOTXプログラミングの流れ

システム全体の構成を決める
WebOTXのアプリケーションを作成するに当たって、以下の点を考慮に入れてシステム設計する必要があります。

業務内容
表1.2.1.2-1
単一オペレーション完結型
サーバはステートレスが利用できるので、クライアント台数に依存せず最小限度のメモリ消費で実行可能になる。欠点としては、各オペレーションの引数が多くなる傾向が強く、コーディングが煩雑になることがある。
このとき、ステートレスを利用した時はクライアント切断イベントに対する処理は必要ありません。
複数オペレーション完結型
サーバはステートフルのみ利用可能。同時接続クライアント数に応じてサーバオブジェクトも生成されるのでメモリ消費量が多くなることある。単一オペレーションとは異なり、前の状態をオブジェクト変数に保持できるので各オペレーションの引数は最小限度で済むのでコーディングは「単一オペレーション完結型」より簡素になることが多いです。
このとき、ステートフルを利用するのでクライアント切断イベントに対する処理が必要になります。
上記の複合型
上記二つの注意点を良く読んでください。

クライアント環境
表1.2.1.2-2
アプリケーション形態
リッチクライアント(Rich Client)
シンクライアント(Thin Client)
・VIsual C++クライアント 高速。Windowsのみ。VC++ランタイムの設定が必要。
・Javaアプリケーション 低速。Windows、Unixで実行可能。Java実行環境(JDKなど)とランタイムが必要。
・JSP/Java Servlet 基本的にOSは選ばないが、WebサーバはJSP/Java Servletに対応している必要があります。クライアントはHTMLを表示するので、クライアントのGUIはHTMLで表現できる範囲内となります。
・Java Applet 一般的なWebサーバなら利用可能。GUIはリッチクライアント並みに凝ったものが作成可能。ただし、クライアントのWebブラウザの種類とバージョンを統一しないと画面が乱れることがあります。
利用端末数
サーバのライセンス数に関わってくるので適切な台数を見積もる必要があります。

サーバ環境
表1.2.1.2-3
言語の選択
C++言語またはJava言語
同時利用端末数の見積もり
初期設定は100端末です。無闇に多く取ると無駄にメモリを消費します。利用規模に合わせて最適値を設定してください。
データベースの利用
データベースを利用する時は下記のいずれかを選択しなければなりません。
・ 独自に制御する場合。
・ 自動接続機能を利用する場合。
・ 2つ以上のデータベースを利用する場合。
・ 利用可能なデータベースに制限はありません。
・ WebOTX Transaction Service連携が必要です。
スレッド
アパートメントモデル
フリースレッドモデル
・ スレッド毎にオブジェクトを生成する。
・ スレッド数が多くなるとそれだけたくさんのオブジェクトを生成する。
・ スレッドをまたがっての呼び出しが無いので、グローバル変数のスレッド間排他制御が必要。
・ 1からスレッド数まで任意の数までのオブジェクトを生成する。
・ スレッド数が多くなってもオブジェクトの生成は指定した数以上は生成しない。
・ ステートレスの場合、スレッドをまたがっての呼び出しがあるので、グローバル変数はもちろん、オブジェクト変数をアクセスする時もスレッド間排他制御が必要。ステートフルの場合は、グローバル変数の排他制御が必要。
利用言語を決める
「システム全体の構成を決める」でシステムの概要が決まりましたら、それに合わせて利用言語を選んでアプリケーションを作成します。 各言語にはそれぞれメリット/デメリットがありますので、それらを考慮に入れて作成してください。
作成方法を決める
アプリケーションの作成方法には、R5形式とR4形式があり、使用するIDLコンパイラやIDL定義などが異なるので、どちらの形式で作成するかを決める必要があります。 また、ファクトリを使用するかどうかによっても作成方法が変わってきますので、これについても決める必要があります。 各形式にはそれぞれメリット/デメリットがありますので、それらを考慮に入れて決定してください。
IDLファイルを作成する
システム設計も決まり、利用言語も決まったらIDLファイルを作成します。 IDLとはCORBAの仕様で定められているインタフェース定義言語(Interface Definition Language)のことで、特定のプログラミング言語(C, C++, SmallTalkなど)から独立したかたちでメソッドの引数や戻り値などのインタフェースを記述するための言語です。 IDLの言語仕様にしたがって記述されたインタフェースをIDLコンパイラにかけることで、特定のプログラミング言語にマッチしたスタブ/スケルトンを自動生成します。スタブ/スケルトンをライブラリと共にリンクすることで比較的簡単にサーバ/クライアントアプリケーションを作成できます。 IDL言語の詳細については各Object Brokerのプログラミングマニュアルを参照してください。
IDLファイルをコンパイルする
IDLファイルが作成できましたらコンパイルを行います。 IDLファイルのコンパイルは言語毎に異なります。 Object BrokerはC++言語用に i2cc、Java言語用にi2jを用意しています。 WebOTXはそのフロントエンドとして、C++言語用にwoigenxx、Java言語用にwoi2jを用意しています。利用する言語に合わせてコンパイルしてください。
サーバAPの作成
IDLコンパイルが終わりましたら、サーバアプリケーションを作成します。 WebOTXのサーバアプリケーションは単独で動く実行モジュール形式ではなく、DLL(あるいはsl, so)ファイルとして作成します。 また、実際にコーディングするのは実装部分だけとなります。その他の部分(スケルトン、ファクトリオブジェクトの実装)はIDLコンパイル時に自動生成されます。
クライアントAPの作成
WebOTXのクライアントアプリケーションは、C++言語とJava言語の場合は通常のCORBAクライアントアプリケーションと変わりありません。使用するファイルはIDLコンパイル時に生成されたスタブ部分です。 コーディングの基本的な流れは以下の通りです。 ファクトリを使用しない場合:
  1. ORBの初期化
  2. 名前サーバからオブジェクトリファレンス(サーバオブジェクト)の取得
  3. オペレーションの呼び出し
  4. アプリケーションの終了
ファクトリを使用する場合:
  1. ORBの初期化
  2. 名前サーバからオブジェクトリファレンス(ファクトリオブジェクト)の取得
  3. サーバオブジェクトの取得(CreateServerObject())
  4. オペレーションの呼び出し
  5. サーバオブジェクトの解放(ReleaseServerObject())
  6. アプリケーションの終了
デバッグ
コーディングが終わったらデバッグを行います。デバッグ方法は、実際に運用管理ツールを使ってサーバアプリケーションを実行環境に登録する方法と、サーバシミュレータを使って行う方法があります。
表1.2.1.2-4
メリット
デメリット
サーバシミュレータ
ローカルマシンで評価ができる
サーバAPIを多用していると評価できないことがある
テスト用の実行環境
ほぼ実業務と同じ評価ができる
実行環境にWebOTXシステムを二つ以上起動しなければならない
実業務環境への登録
評価が終わりましたら、サーバアプリケーションは実行環境に、クライアントアプリケーションはWebサーバ環境に登録します。 それぞれの登録については「ドメイン構築・基本設定ガイド」をご覧ください。
再評価
実際に運用してみて問題が見つかったら再評価してください。このとき、トレースファイルを参照したり、 CORBA例外のマイナーコードを見たりすると解決が早くなります。
動作がおかしいと思ったら
どうしても動作がおかしいと思ったら以下の点を確認してください。
  1. VC++物件の場合、[プロジェクト]-[プロパティ]-[C/C++]-カテゴリ[コード生成]-[ランタイムライブラリ] が[マルチスレッド(DLL)}になっているか? 他の値の場合、主にdeleteの延長(オブジェクトのデストラクタ)で例外します。
  2. C++物件の場合、PATH環境変数やLD_LIBRARY_PATH環境変数(HP-UX(Itanium 2),Linux,SUN Solaris 10)は正しいでしょうか? Oracleや外部部品を使用している時は特に注意が必要です(開発環境には入って入るが、実行環境には無いなど)
  3. トレースファイルにエラー表示はないか? 異常時の多くの場合は、トレースファイルに何らかのエラーログを出力します。 内容によっては判断しにくいものもありますが、よるあるケースとしては以下のパターンです。
    1. DLL(sl,so)のロードエラー 上記参照。
    2. class not found jarファイル生成時に jp ディレクトリを付け忘れることがあります。jar tvf JARファイル名でjarファイルの内容を確認してください。
    3. bindエラー Object Brokerが起動していないか、名前サーバが起動されていません。 Object Brokerのログや設定を確認してください。
    4. resolveエラー Object Brokerが起動していないか、名前サーバが起動されていません。 あるいは名前サーバのラウンドロビン指定がoff(あるいは指定なし)になっています。 運用管理ツールから、使用しているドメインの[server]-[objectbrokerservice]-[namesv]-[名前サーバのラウンドロビン拡張機能]のチェックが入って いるか確認してください。
    5. ソケット初期化エラー 同一ホスト上でシステムIDが重複していると思われます。あるいは別のプロダクトが同一のポートを使用していると思われます。
WebOTXが使用しているポート番号一覧
表1.2.1.2-5
利用アプリケーション
ポート番号の指定方法
初期値
備考
IIOPリスナ
運用管理ツールで設定
5151
-
OLFTPリスナ
運用管理ツールで設定
5251
-
Watchサーバ
wsinfo.sg
5190
-
クライアント管理ライブラリ
運用管理ツールで設定
5220
0を指定されている場合は、5219+(システムID)

1.2.1.3. Java言語を用いたサーバアプリケーションの作成

WebOTXで利用することが可能なCORBAサーバアプリケーションは、実装部分だけ作成したJavaクラスファイルです。この章ではJava言語を使ったアプリケーションの作成方法について説明します。 Javaのサーバアプリケーションの作成には、 JDKやその他一般的なJava IDE(Integrated Development Environment:統合開発環境)が必要です。
Javaサーバアプリケーションの作成の流れ
WebOTXのJavaサーバアプリケーションの作成から実稼動までの流れは以下のようになります。以下の節ではそれぞれについて詳しく説明します。また、WebOTXが提供する機能についても説明します。
  1. IDLファイルの作成とコンパイル
  2. 実装部分のコーディングとコンパイル
  3. サーバシミュレータによる動作確認
  4. 実行環境への登録
開発環境の設定
一般にJava物件を作成する為には、 JDKかそれに準ずるJava IDE(Integrated Development Environment:統合開発環境)が必要になります。 これらの設定方法についてはそれぞれの説明書を良くお読みください。
UNIX
WebOTXのサーバAPを作成するには以下のファイルをCLASSPATH環境変数に登録する必要があります。
また、IDLコンパイラを実行する為にPATH環境変数に以下のディレクトリを加える必要があります。
さらに、LD_LIBRARY_PATH環境変数に以下のディレクトリを加える必要があります。
例としてHP-UX(Itanium 2)のcshの設定方法を示します(標準インストールディレクトリのパスを例にしています)。 pathだけshell変数に代入しているのは、cshがpathとPATH環境変数の同期を行うことを前提に設定しています。
>set path=( $path /opt/ObjectSpinner/bin )
>set path=( $path /opt/WebOTX/dev/bin )
:
:
>setenv LD_LIBRARY_PATH  /opt/ObjectSpinner/lib:/opt/WebOTX/dev/lib
:
:
>setenv CLASSPATH /opt/WebOTX/modules/jsocks.jar
>setenv CLASSPATH ${CLASSPATH}:/opt/WebOTX/modules/wo-orb110.jar
>setenv CLASSPATH ${CLASSPATH}:/opt/WebOTX/modules/omgorb110.jar
>setenv CLASSPATH ${CLASSPATH}:/opt/WebOTX/dev/javalib/svsimj.jar
>setenv CLASSPATH ${CLASSPATH}:/opt/WebOTX/dev/javalib/WOTXBS90.jar
:
Windows
WebOTXのサーバアプリケーションを作成するには以下のファイルを CLASSPATH環境変数に登録する必要があります。 (<WebOTX>はWebOTXのインストール先ディレクトリをあらわします)。 Windows版は基本的に各ユーザの環境変数CLASSPATHに自動的に設定されます。
もし、設定がおかしいと思ったら<WebOTX>\ObjectBroker\bin\orbjsenv.exe を実行してもう一度確認してください(画面には何も表示されません)。 それでも直らない場合は、以下のレジストリの値を編集してからもう一度orbjsenv.exe を実行してください。
また、IDLコンパイラを実行する為にPATH環境変数に以下のディレクトリを加える必要があります。
IDLファイルの作成とコンパイル(Java)
アプリケーション作成の方法には以下の方法があります。
ファクトリの使用については [サーバオブジェクトとファクトリオブジェクト] をご覧ください。
R5形式(ファクトリを使用しない場合)
IDLファイルとはインタフェース定義言語ファイルの略で、このファイルにサーバオブジェクトが提供するインタフェースやオペレーションなどを記述します。IDLファイルの記述例を以下に示します。行頭の数字は説明の為に付加した行番号です。実際の記述では必要ありません。
1: module sample
2: {
3:     interface LoopBackSample : WO_Base // (サンプルではWO_Baseからの派生はありません)
4:     {
5:         long LoopBack(in string inputChar, out string outputChar);
6:         long LowerCase(in string inputChar, out string outputChar);
7:         long UpperCase(in string inputChar, out string outputChar);
8:     };
9: };
一行目のmoduleはモジュールを宣言するときに記述します。interfaceを指定する場合、module定義の指定は必須です。三行目のinterfaceはインタフェースを宣言するときに記述します。続けてインタフェース名を記述します。これがJavaのクラス名になります。その後ろの : WO_BaseはWO_Baseインタフェースからの派生を意味しています。WO_BaseはWebOTX専用のインタフェースで、このインタフェースから派生することにより、アプリケーション例外時の呼出し(OnTPSAbort())やクライアント切断時の呼出し(OnTPSDisconnect())が行われます。これらの機能が不要なときは記述しなくても結構です。 WO_Baseの定義はWebOTXをインストールしたディレクトリ配下にwobase.idlとして定義しています。 五行目以降はオペレーションの宣言です。オペレーションの書式はJavaのインスタンスメソッドと同じように記述します。 Javaのインスタンスメソッドの定義と異なるのは、各引数に入出力属性を付けることです。上記例ではin属性とout属性(出力属性)を使用していますが、このほかにも、inout属性(入出力属性)があります。 このようにして出来上がったIDLファイルをIDLコンパイラに入力してスタブファイル、スケルトンファイルを作成します。詳しいIDLの構文やJava言語マッピングについてはObject Broker のマニュアルを参照してください。 なお、IDLファイルのファイル名の拡張子は必ず .idl としてください。この例題では、loopback.idlとして説明します。 IDLファイルを作成しましたら、次にIDLコンパイラを実行してスタブファイルとスケルトンファイル、Holderクラスファイル、Helperクラスファイルを生成します。 スタブファイルとは、クライアントアプリケーションがサーバオブジェクトをアクセスするためのアクセスクラスを定義しているファイルのことです。スケルトンファイルとは、ORBからサーバアプリケーションを呼び出すためのベースとなるクラスを定義したファイルのことです。 Holderファイルはoutおよびinoutパラメータモードをサポートするためのクラスを定義しています。 HelperクラスはAny型への挿入と取り出し、ストリームからの読み込みと書き出しに使われます。 WebOTXでは、上記ファイルのほかに以下の機能を定義したファイルが必要になります。
実装情報定義クラスとコンポーネント初期化クラスを作成するには、 [woixj] コマンドを使用するか、後述の記述例を参照し作成してください。 R5形式で使用するIDLコンパイラはObject Broker 提供の i2j です。オプションは以下の通りです。
i2j -i -lstub <IDLファイル名> (woi2jとは異なり、"loopback.idl"のように.idlも必要です)
    ^^ ^^^^^^
    |     +-----ローカルスタブを使用。非同期VD呼び出しには必須のオプションです
    +-----------ifファイルの生成を行います。WebOTXに登録するために必須のオプションです。
また、WO_Baseを派生している場合は以下のオプションを指定してください。この場合、事前にwobase.idlをカレントディレクトリにコピーしておく必要があります。wobase.idlは、WebOTX Developer (for CORBA Application)をインストールしたディレクトリ配下のidlfilesディレクトリにあります。
i2j -i -lstub -rpjp.co.nec.WebOTX -Rwobase.idl <IDLファイル名> (.idlも必要)
              ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^
                    |               +-----wobase.idl を参照します。
                    |                     WO_Baseを使用するために必須のオプションです。
                    +----------IDL定義が jp.co.nec.WebOTXパッケージに置かれているものとして生成します。
                               WO_Baseを使用するために必須のオプションです。
コマンドを実行すると以下のファイルを生成します。
このほかにもIDL定義にてmoduleを付けた場合や、typedef, structなどを使用しますと、様々なディレクトリが自動的に作成されます。このディレクトリ配下のファイルもコンパイル対象になりますので忘れないでください。 この例の場合は、sampleディレクトリ配下に以下のファイルが生成されます。
このようにして出来たファイルは、そのままjavacでコンパイルして、jarファイルにまとめます。同一インタフェースに複数の実装を持たせる場合は、「インタフェースコンポーネントファイル」として実装部分と分離し、共有コンポーネントファイルに登録してください。同一インタフェースに複数の実装を持たせない場合は、ここで生成したファイルをサーバコンポーネントファイルに含めてください。 次に [サーバント(実装部分)] を作成します。 注意:WebOTX R2.2以前に作成したxxxObj.javaをR3.1以上のバージョンでそのままコンパイルするには、 「i2j -oldname IDLファイル名」としてください。 このオプションを指定すると、~POA.javaのファイル名(およびクラス名)がPOA_xxx.javaになります。
R5形式(ファクトリを使用する場合)
IDLファイルとはインタフェース定義言語ファイルの略で、このファイルにサーバオブジェクトが提供するインタフェースやオペレーションなどを記述します。IDLファイルの記述例を以下に示します。行頭の数字は説明の為に付加した行番号です。実際の記述では必要ありません。
1: module sample 
2: {
3:     interface LoopBackSample : WO_Base 
4:                             // (サンプルではWO_Baseからの派生はありません)
5:     {
6:         long LoopBack(in string inputChar, out string outputChar);
7:         long LowerCase(in string inputChar, out string outputChar);
8:         long UpperCase(in string inputChar, out string outputChar);
9:     };
10:
11:     interface WO_Factory_LoopBackSample : WO_BaseFactory 
12:                           // (サンプルではWO_BaseFactoryからの派生はありません)
13:     {
14:         LoopBackSample CreateServerObject();
15:         void ReleaseServerObject(in LoopBackSample obj);
16:     };
17: };
一行目のmoduleはモジュールを宣言するときに記述します。interfaceを指定する場合、module定義の指定は必須です。三行目のinterfaceはインタフェースを宣言するときに記述します。続けてインタフェース名を記述します。これがJavaのクラス名になります。その後ろの : WO_BaseはWO_Baseインタフェースからの派生を意味しています。WO_BaseはWebOTX専用のインタフェースで、このインタフェースから派生することにより、アプリケーション例外時の呼出し(OnTPSAbort())やクライアント切断時の呼出し(OnTPSDisconnect())が行われます。これらの機能が不要なときは記述しなくても結構です。 WO_Baseの定義はWebOTXをインストールしたディレクトリ配下にwobase.idlとして定義しています。 六行目から八行目はオペレーションの宣言です。オペレーションの書式はJavaのインスタンスメソッドと同じように記述します。 Javaのインスタンスメソッドの定義と異なるのは、各引数に入出力属性を付けることです。上記例ではin属性とout属性(出力属性)を使用していますが、このほかにも、inout属性(入出力属性)があります。 十一行目以降はファクトリのインターフェースの宣言です。書式は通常のインターフェースと同様です。インターフェース名は任意の名前で定義できます。オブジェクトを生成するためのオペレーション(この例ではCreateServerObject())とオブジェクトを解放するためのオペレーション(この例ではReleaseServerObject())を宣言してください。また、クライアント管理ライブラリを使用する場合はWO_BaseFactoryインターフェースの派生にしてください。WO_BaseFactoryはWO_Baseと同様にwobase.idlに定義されています。 このようにして出来上がったIDLファイルをIDLコンパイラに入力してスタブファイル、スケルトンファイルを作成します。詳しいIDLの構文やJava言語マッピングについてはObject Broker のマニュアルを参照してください。 なお、IDLファイルのファイル名の拡張子は必ず .idl としてください。この例題では、loopback.idlとして説明します。 IDLファイルを作成しましたら、次にIDLコンパイラを実行してスタブファイルとスケルトンファイル、Holderクラスファイル、Helperクラスファイルを生成します。 スタブファイルとは、クライアントアプリケーションがサーバオブジェクトをアクセスするためのアクセスクラスを定義しているファイルのことです。スケルトンファイルとは、ORBからサーバアプリケーションを呼び出すためのベースとなるクラスを定義したファイルのことです。 Holderファイルはoutおよびinoutパラメータモードをサポートするためのクラスを定義しています。 HelperクラスはAny型への挿入と取り出し、ストリームからの読み込みと書き出しに使われます。 WebOTXでは、上記ファイルのほかに以下の機能を定義したファイルが必要になります。
実装情報定義クラスとコンポーネント初期化クラスを作成するには、 [woixj] コマンドを使用するか、後述の記述例を参照し作成してください。 R5形式で使用するIDLコンパイラはObject Broker 提供の i2j です。オプションは以下の通りです。
i2j -i -lstub <IDLファイル名> (woi2jとは異なり、"loopback.idl"のように.idlも必要です)
    ^^ ^^^^^^
    |    +-----ローカルスタブを使用。非同期VD呼び出しには必須のオプションです
    +----------ifファイルの生成を行います。WebOTXに登録するために必須のオプションです。
また、WO_Base,WO_BaseFactoryを派生している場合は以下のオプションを指定してください。この場合、事前にwobase.idlをカレントディレクトリにコピーしておく必要があります。wobase.idlは、WebOTX Developer (for CORBA Application)をインストールしたディレクトリ配下のidlfilesディレクトリにあります。
i2j -i -lstub -rpjp.co.nec.WebOTX -Rwobase.idl <IDLファイル名> (.idlも必要)
              ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
               |                   +-----wobase.idl を参照します。
               |                         WO_Baseを使用するために必須のオプションです。
               +----------IDL定義が jp.co.nec.WebOTXパッケージに置かれているものとして
               コードを生成します。WO_Baseを使用するために必須のオプションです。
コマンドを実行すると以下のファイルを生成します。
このほかにもIDL定義にてmoduleを付けた場合や、typedef, structなどを使用しますと、様々なディレクトリが自動的に作成されます。このディレクトリ配下のファイルもコンパイル対象になりますので忘れないでください。 この例の場合は、sampleディレクトリ配下に以下のファイルが生成されます。
このようにして出来たファイルは、そのままjavacでコンパイルして、jarファイルにまとめます。同一インタフェースに複数の実装を持たせる場合は、「インタフェースコンポーネントファイル」として実装部分と分離し、共有コンポーネントファイルに登録してください。同一インタフェースに複数の実装を持たせない場合は、ここで生成したファイルをサーバコンポーネントファイルに含めてください。 次に [サーバント(実装部分)] を作成します。 注意:WebOTX R2.2以前に作成したxxxObj.javaをR3.1以上のバージョンでそのままコンパイルするには、 「i2j -oldname IDLファイル名」としてください。 このオプションを指定すると、~POA.javaのファイル名(およびクラス名)がPOA_xxx.javaになります。
サーバント(実装部分)のコーディング(Java)
アプリケーション作成の方法には以下の方法があります。 ファクトリの使用については [サーバオブジェクトとファクトリオブジェクト] をご覧ください。
R5形式(ファクトリを使用しない場合)
IDLコンパイラを実行して出来たすべてのファイルを使用して作成します。 これに、実装部分をコーディングしたクラスを追加します。実装部分のコーディングにおいて、幾つかの決まりがあります。それを以下に示します。
このサンプルアプリケーションの場合は、LoopBackSampleObj.javaのファイルを作成する必要があります。以下に、LoopBackSampleObj.javaの記述例を示します。
//
// 実装クラス(LoopBackSampleObj.java)
//
package sample;

import jp.co.nec.WebOTX.orbsvwpr.WoServerWrapper;

public class LoopBackSampleObj extends LoopBackSamplePOA {

    public LoopBackSampleObj() {
    }

    public int LoopBack(java.lang.String inputChar, 
                        org.omg.CORBA.StringHolder outputChar) {
        outputChar.value = inputChar;
        return outputChar.value.length();
    }

    public int LowerCase(java.lang.String inputChar, 
                         org.omg.CORBA.StringHolder outputChar) {
        outputChar.value = inputChar.toLowerCase();
        return outputChar.value.length();
    }

    public int UpperCase(java.lang.String inputChar, 
                         org.omg.CORBA.StringHolder outputChar) {
        outputChar.value = inputChar.toUpperCase();
        return outputChar.value.length();
    }

    // WO_Base interface
    public void OnTPSAbort(int status) {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_ERR, 
                                     "*** OnTPSAbort() called. ***");
          WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_ERR, 
                                     "    status="+status);
      }

    public void OnTPSDisconnect() {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_INFO,
                                     "*** OnTPSDisconnect() called. ***");
    }

    public void OnTPSMessageNotified(java.lang.String mes) {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_INFO,
                                     "*** OnTPSMessageNotified("+mes+") called. ***");
    }
}
各オペレーションの定義は自分で記述することも出来ますが、IDLコンパイラが生成したLoopBackSampleOperation.javaの定義からコピーするのが簡単です。 OnTPSAbort()とOnTPSDisconnect()およびOnTPSMessageNotified()の定義はWO_Baseから派生したときのみ必要です。これは、サーバアプリケーションが例外したとき(OnTPSAbort)や端末が不意に切断したとき(OnTPSMessageNotified)、運用管理コマンドからのメッセージ送信(OnTPSMessageNotified)時にそれぞれWebOTXから呼ばれる関数です。 また、import jp.co.nec.WebOTX.orbsvwpr.WoServerWrapperはサーバAPIを使うときに必要になります。サーバAPIの詳細な使い方や、このほかのAPIついては、 [ リファレンス集 開発編(共通) > 4. CORBA > 4.2. WebOTX CORBA アプリケーション(Java) > 4.2.1. サーバAPI ] を参照してください。 次に実装情報定義クラスとコンポーネント初期化クラスの作成方法について説明します。 実装情報定義クラスとコンポーネント初期化クラスを作成するには、woixjコマンドを使用するか、後述の記述例を参照し作成してください。 woixjコマンドのインタフェースは以下のようになります。
woixj  <ifファイル名>  [-options] (拡張子ifは不要)
使用例: woixj loopback
オプションの指定方法については、 [コマンドリファレンス] を参照してください。 次に、実装情報定義クラスの記述例を示します。
//
// 実装情報定義クラス(LoopBackSampleObjInfo.java)
//
import jp.co.nec.WebOTX.WOServantCallback;
public class LoopBackSampleObjInfo implements WOServantCallback
{
    public String _name()
    {
        return "sample_LoopBackSampleJava";
    }
    public String _id()
    {
        return "IDL:sample/LoopBackSample:1.0";
    }
    public org.omg.PortableServer.Servant _newInstance()
    {
        return new sample.LoopBackSampleObj();
    }
}
実装情報定義クラスは、実装クラスをインスタンス化する時に使用されるクラスで、実装クラスごとに必要になります。 実装情報定義クラスを実装するためには、インターフェースWOServantCallbackをimplementsする必要があります。 _name() では、WebOTXが実装を識別するために使用する実装識別名を返却してください。この値は、コンポーネントファイル内で一意にする必要があります。 _id() では、対応する実装クラスのリポジトリIDを返却してください。 _newInstance() では、対応する実装クラスをインスタンス化して返却してください。 次に、コンポーネント初期化クラスの記述例を示します。
//
// コンポーネント初期化クラス(LoopBackInit.java)
//
import jp.co.nec.WebOTX.WOComponent;
import jp.co.nec.WebOTX.WOUserComponent;
public class LoopBackInit implements WOUserComponent {
    public void init() {
        WOComponent.add(new LoopBackSampleObjInfo());
    }
}
コンポーネント初期化クラスは、コンポーネントファイルが読み込まれるときに使用されるクラスで、コンポーネントファイルにつき1つ必要になります。 コンポーネント初期化クラスを実装するためには、インターフェースWOUserComponentをimplementsする必要があります。 init() では、WOComponent.add()を呼び出してコンポーネントファイル内に定義されている実装情報を登録する処理を記述してください。コンポーネントファイル内の全ての実装クラスについて実装情報を登録する必要があります。 作成したLoopBackSampleObj.java, LoopBackSampleObjInfo.java, LoopBackInit.javaとIDLコンパイラが作成したサーバアプリケーションに必要なファイルをすべてコンパイルします。 まず、コンパイル後に出来るクラスファイルを格納するディレクトリを作成します。ここではclassesディレクトリとしています。
>mkdir classes
次にJavaのソースファイルをコンパイルしてclassファイルを作成します。 JDKの場合、以下のように入力します。
Windows
>javac -d classes *.java sample\*.java
Unix
>javac -d classes *.java sample/*.java
この例では、classesディレクトリ配下にclassファイルを作成するようにしています。 無事にコンパイルができたら、JDKのjarコマンドを使って一つにまとめます。カレントディレクトリを先ほど指定したclassesディレクトリとした場合は、
>cd classes
>jar cvf LoopBackSample.jar *.class sample
とタイプします。これで、LoopBackSample.jarというファイルができます。これがWebOTXのコンポーネントになります。 この例では、サーバの実装とインタフェース部分を一つにまとめていますが、1インタフェースで複数の実装を作成する場合は「インタフェースコンポーネントファイル」、「サーバコンポーネントファイル」と別々に作成することをお勧めします。
R5形式(ファクトリを使用する場合)
IDLコンパイラを実行して出来たすべてのファイルを使用して作成します。 これに、実装部分をコーディングしたクラスを追加します。実装部分のコーディングにおいて、幾つかの決まりがあります。それを以下に示します。
このサンプルアプリケーションの場合は、LoopBackSampleObj.javaのファイルを作成する必要があります。以下に、LoopBackSampleObj.javaの記述例を示します。
//
// 実装クラス(LoopBackSampleObj.java)
//
package sample;

import jp.co.nec.WebOTX.orbsvwpr.WoServerWrapper;

public class LoopBackSampleObj extends LoopBackSamplePOA {

    public LoopBackSampleObj() {
    }

    public int LoopBack(java.lang.String inputChar, 
                        org.omg.CORBA.StringHolder outputChar) {
        outputChar.value = inputChar;
        return outputChar.value.length();
    }

    public int LowerCase(java.lang.String inputChar, 
                         org.omg.CORBA.StringHolder outputChar) {
        outputChar.value = inputChar.toLowerCase();
        return outputChar.value.length();
    }

    public int UpperCase(java.lang.String inputChar, 
                         org.omg.CORBA.StringHolder outputChar) {
        outputChar.value = inputChar.toUpperCase();
        return outputChar.value.length();
    }

    // WO_Base interface
    public void OnTPSAbort(int status) {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_ERR, 
                                     "*** OnTPSAbort() called. ***");
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_ERR, 
                                     "    status="+status);
    }

    public void OnTPSDisconnect() {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_INFO, 
                                     "*** OnTPSDisconnect() called. ***");
    }

    public void OnTPSMessageNotified(java.lang.String mes) {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_INFO, 
                                     "*** OnTPSMessageNotified("+mes+") called. ***");
    }
}
各オペレーションの定義は自分で記述することも出来ますが、IDLコンパイラが生成したLoopBackSampleOperation.javaの定義からコピーするのが簡単です。 OnTPSAbort()とOnTPSDisconnect()およびOnTPSMessageNotified()の定義はWO_Baseから派生したときのみ必要です。これは、サーバアプリケーションが例外したとき(OnTPSAbort)や端末が不意に切断したとき(OnTPSMessageNotified)、運用管理コマンドからのメッセージ送信(OnTPSMessageNotified)時にそれぞれWebOTXから呼ばれる関数です。 また、import jp.co.nec.WebOTX.orbsvwpr.WoServerWrapperはサーバAPIを使うときに必要になります。サーバAPIの詳細な使い方や、このほかのAPIついては [ リファレンス集 開発編(共通) > 4. CORBA > 4.2. WebOTX CORBA アプリケーション(Java) > 4.2.1. サーバAPI ] を参照してください。 次に実装情報定義クラスとコンポーネント初期化クラスの作成方法について説明します。 実装情報定義クラスとコンポーネント初期化クラスを作成するには、woixjコマンドを使用するか、後述の記述例を参照し作成してください。 woixjコマンドのインタフェースは以下のようになります。
woixj  <ifファイル名>  [-options] (拡張子ifは不要)
使用例: woixj loopback
オプションの指定方法については、[コマンドリファレンス]を参照してください。 次に、ファクトリの実装クラスの記述例を示します。
//
// ファクトリ実装クラス(WO_Factory_LoopBackSampleObj.java)
//
package sample;

import jp.co.nec.WebOTX.orbsvwpr.WoServerWrapper;
import jp.co.nec.WebOTX.WOServantCallback;
import jp.co.nec.WebOTX.WOServantManager;
import org.omg.CORBA.IntHolder;
import org.omg.CORBA.StringHolder;

public class WO_Factory_LoopBackSampleObj extends WO_Factory_LoopBackSamplePOA {
    public WO_Factory_LoopBackSampleObj() {
    }

    public LoopBackSample CreateServerObject() {
        WOServantCallback servInfo = new LoopBackSampleObjInfo();
        org.omg.CORBA.Object obj = WOServantManager.CreateServant(servInfo);
        return LoopBackSampleHelper.narrow(obj);
    }

    public void ReleaseServerObject(LoopBackSample obj) {
        WOServantCallback servInfo = new LoopBackSampleObjInfo();
        WOServantManager.ReleaseServant(servInfo, obj);
    }

    public void GetID(IntHolder port, StringHolder host, StringHolder termid) {
        WoServerWrapper.TPSGetIDs(port, host, termid);
    }
}
オブジェクト生成オペレーション(この例ではCreateServerObject())では、WOServantManager.CreateServant()を呼び出してオブジェクトを生成し返却してください。 オブジェクト解放オペレーション(この例ではReleaseServerObject())では、WOServantManager.ReleaseServant()を呼び出してオブジェクトを解放してください。 GetID()の定義はWO_BaseFactoryから派生したときのみ必要です。これは、クライアント管理ライブラリを使用する場合に内部的に呼び出される関数です。 WoServerWrapper.TPSGetIDs()を呼び出す処理を記述してください。 次に、実装情報定義クラスの記述例を示します。
//
// 実装情報定義クラス(LoopBackSampleObjInfo.java)
//
import jp.co.nec.WebOTX.WOServantCallback;

public class LoopBackSampleObjInfo implements WOServantCallback {
    public String _name() {
        return "sample_LoopBackSampleJava";
    }
 
    public String _id() {
        return "IDL:sample/LoopBackSample:1.0";
    }

    public org.omg.PortableServer.Servant _newInstance() {
        return new sample.LoopBackSampleObj();
    }
}
//
// 実装情報定義クラス(WO_Factory_LoopBackSampleObjInfo.java)
//
import jp.co.nec.WebOTX.WOServantCallback;

public class WO_Factory_LoopBackSampleObjInfo implements WOServantCallback {

    public String _name() {
        return "sample_WO_Factory_LoopBackSampleJava";
    }

    public String _id() {
        return "IDL:sample/WO_Factory_LoopBackSample:1.0";
    }

    public org.omg.PortableServer.Servant _newInstance() {
        return new WO_Factory_LoopBackSampleObj();
    }
}
実装情報定義クラスは、実装クラスをインスタンス化する時に使用されるクラスで、実装クラスごとに必要になります。 実装情報定義クラスを実装するためには、インターフェースWOServantCallbackをimplementsする必要があります。 _name() では、WebOTXが実装を識別するために使用する実装識別名を返却してください。この値は、コンポーネントファイル内で一意にする必要があります。 _id() では、対応する実装クラスのリポジトリIDを返却してください。 _newInstance() では、対応する実装クラスをインスタンス化して返却してください。 次に、コンポーネント初期化クラスの記述例を示します。
//
// コンポーネント初期化クラス(LoopBackInit.java)
//
import jp.co.nec.WebOTX.WOComponent;
import jp.co.nec.WebOTX.WOUserComponent;

public class LoopBackInit implements WOUserComponent
{
    public void init()
    {
        WOComponent.add(new LoopBackSampleObjInfo());
        WOComponent.add(new WO_Factory_LoopBackSampleObjInfo());
    }
}
コンポーネント初期化クラスは、コンポーネントファイルが読み込まれるときに使用されるクラスで、コンポーネントファイルにつき1つ必要になります。 コンポーネント初期化クラスを実装するためには、インターフェースWOUserComponentをimplementsする必要があります。 init() では、WOComponent.add()を呼び出してコンポーネントファイル内に定義されている実装情報を登録する処理を記述してください。コンポーネントファイル内の全ての実装クラスについて実装情報を登録する必要があります。 作成したLoopBackSampleObj.java, WO_Factory_LoopBackSampleObj.java, LoopBackSampleObjInfo.java, WO_Factory_LoopBackSampleObjInfo.java, LoopBackInit.javaとIDLコンパイラが作成したサーバアプリケーションに必要なファイルをすべてコンパイルします。 まず、コンパイル後に出来るクラスファイルを格納するディレクトリを作成します。ここではclassesディレクトリとしています。
>mkdir classes
次にJavaのソースファイルをコンパイルしてclassファイルを作成します。 JDKの場合、以下のように入力します。
Windows
>javac -d classes *.java sample\*.java
Unix
>javac -d classes *.java sample/*.java
この例では、classesディレクトリ配下にclassファイルを作成するようにしています。 無事にコンパイルができたら、JDKのjarコマンドを使って一つにまとめます。カレントディレクトリを先ほど指定したclassesディレクトリとした場合は、
>cd classes
>jar cvf LoopBackSample.jar *.class sample
とタイプします。これで、LoopBackSample.jarというファイルができます。これがWebOTXのコンポーネントになります。 この例では、サーバの実装とインタフェース部分を一つにまとめていますが、1インタフェースで複数の実装を作成する場合は「インタフェースコンポーネントファイル」、「サーバコンポーネントファイル」と別々に作成することをお勧めします。
複雑なIDLの場合のコーディング例(Java)
利用するシステムが複雑で大規模になるとIDLも大きくなり複雑な定義になります。ここでは、複雑なIDLを定義した時のコーディング例を記述します。詳しい解説はObject Broker Java(TM)のマニュアルを参照してください。 (a). moduleがネストしている場合
---- IDLファイル ---- IDLファイル ---- IDLファイル ----
module AAAA {
    module BBBB {
        module CCCC {
            interface DDDD {
                void op1();
            };
        };
    };
};
 
---- 実装部分(DDDDObj.java) ---- 実装部分(DDDDObj.java) ----
package AAAA.BBBB.CCCC;
 
import AAAA.BBBB.CCCC.DDDDPOA;
 
public class DDDDObj extends DDDDPOA {
    public DDDDObj() {
    }

    public void op1() {
    }
}
(b). sequence型とstruct型を利用している場合
---- IDLファイル ---- IDLファイル ---- IDLファイル ----
interface AAA {
    struct BBB {
        long ID;
        string NAME;
        short  AGE;
    };

    typedef sequence < BBB > SEQ001;
    void GET_DATA (in SEQ001 inARG, out SEQ001 outARG, inout SEQ001 inoutARG);
};
 
---- 実装部分(AAAObj.java) ---- 実装部分(AAAObj.java) ----
import AAA;
import AAAHelper;
import AAAHolder;
import AAAOperations;
import AAAPOA;
 
public class AAAObj extends AAAPOA {
    public AAAObj() {
    }

    public void GET_DATA(AAAPackage.BBB[] inARG,
                         AAAPackage.SEQ001Holder outARG,
                         AAAPackage.SEQ001Holder inoutARG) {
        int i=0;
        // inARGは値が設定されています。参照のみ可能です
        int inARGlen = inARG.length;
        for(i=0; i < inARGlen; i++) {
            int id = inARG[i].ID;
        }

        // outARGはBBB::SEQ001をnewしてAAAPackage.SEQ001Holder.valueに
        // 設定しなければなりません
        int outARGlen = 100;
        outARG.value = new AAAPackage.BBB[outARGlen];
        for(i=0; i < outARGlen; i++) {
            outARG.value[i] = new AAAPackage.BBB();
            outARG.value[i].ID = 10;
        }

        // inoutARGは値が設定されています。また書き換えもできます
        int inoutARGlen = inoutARG.value.length;
        for(i=0; i < inoutARGlen; i++) {
            inoutARG.value[i].ID = inoutARG.value[i].ID * 2;
        }
    }
}
TIEアプローチを用いたコーディング(Java)
前節では、LoopBackSamplePOAを継承してサーバアプリケーションを作成する方法を示しました。 実際のアプリケーション開発に当たっては、サーバオブジェクトでは、別のクラスを継承したい場合もあります。しかし、Java言語では多重継承を許していないため、このような場合には困ることもあります。 そこで、サーバオブジェクトでLoopBackSamplePOAクラスを継承しない方法も用意されています。これをTIEアプローチと呼びます。 TIEアプローチではLoopBackSamplePOAを継承する代わりにLoopBackSampleOperationsをimplementsします。また、TIEアプローチを行うときは
R5形式 
>i2j -tie -i -lstun loopback.idl
>woixj loopback -tie
と入力します。これでTIEアプローチが使用できるファイルが生成されます。以下にTIEアプローチ時のコーディング例を示します。
package sample;

import jp.co.nec.WebOTX.orbsvwpr.WoServerWrapper;

public class LoopBackSampleObj implements LoopBackSampleOperations {
///////////////////////////////^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ここが違います。
    public LoopBackSampleObj() {
    }

    public int LoopBack(java.lang.String inputChar, 
                        org.omg.CORBA.StringHolder outputChar) {
        outputChar.value = inputChar;
        return outputChar.value.length();
    }

    public int LowerCase(java.lang.String inputChar, 
                         org.omg.CORBA.StringHolder outputChar) {
        outputChar.value = inputChar.toLowerCase();
        return outputChar.value.length();
    }

    public int UpperCase(java.lang.String inputChar, 
                         org.omg.CORBA.StringHolder outputChar) {
        outputChar.value = inputChar.toUpperCase();
        return outputChar.value.length();
    }

    // WO_Base interface
    public void OnTPSAbort(int status) {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_ERR, 
                                     "*** OnTPSAbort() called. ***");
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_ERR, 
                                     "    status="+status);
    }

    public void OnTPSDisconnect() {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_INFO, 
                                     "*** OnTPSDisconnect() called. ***");
    }

    public void OnTPSMessageNotified(java.lang.String mes) {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_INFO,
                                     "*** OnTPSMessageNotified("+mes+") called. ***");
    }
}
サーバシミュレータによる動作確認(Java)
作成したサーバアプリケーションやクライアントアプリケーションをテストするには、二つの方法があります。 一つは運用管理ツールとWebAP管理ツールを使ってWebOTXに登録して評価する方法と、サーバシミュレータを使って行う方法があります。ここでは、サーバシミュレータを使ってデバッグする方法を述べます。 サーバシミュレータはWebOTXの機能の一部を提供しています。以下に通常のWebOTXと異なる点を示します。
サーバアプリケーションの準備が出来ましたら、まずObject Brokerを起動してください。起動の方法はObject Brokerのマニュアルを参照してください。 次にMS-DOSコマンドプロンプトで以下のコマンドを入力して、サーバシミュレータを起動してください。
>java -Dorg.omg.CORBA.ORBClass=jp.co.nec.orb.OSPORB 
      -Dorg.omg.CORBA.ORBSingletonClass=jp.co.nec.orb.OSPORBSingleton 
      ServerSimulator コンポーネント初期化クラス名
例えば、loopback.idlの場合は、
>java -Dorg.omg.CORBA.ORBClass=jp.co.nec.orb.OSPORB 
      -Dorg.omg.CORBA.ORBSingletonClass=jp.co.nec.orb.OSPORBSingleton 
      ServerSimulator LoopBackInit -B LoopBackSampleJava=
      corbaname://127.0.0.1#NEC/WebOTX/WO_Default/LoopBackSample/1
となります。サーバシミュレータを起動して、サーバの初期化が完了すると画面に "OK." と表示されます。この表示を確認後にクライアントアプリケーションを実行してください。このとき、サーバホストとクライアントホストは同一ホストでも実行できますし、違うホスト同士でも出来ます。別々のホストにするときに注意する点は、両方とも同じ名前サーバを参照しているか確認してください。 Object Brokerの設定を変更している場合は、Object Brokerのマニュアルを参考に実行してください。 アプリケーションの評価が終わりましたら、クライアントおよびサーバアプリケーションを停止してください。 サーバアプリケーションの停止の方法は[Ctrl]+C(Windows)です。 UNIXはquitあるいintrに割り当たっているキーを押してください。確認方法は stty -aで調べてください。
実行環境への登録(Java)
サーバアプリケーションをWebOTX上の分散環境で利用できるように設定します。運用管理ツールのインストール方法や利用方法の詳細については、 セットアップガイド や ドメイン構築・基本設定ガイド を参照してください。 まず、運用管理ツールを起動します。サーバアプリケーションのjarまたはzipファイルは運用マシンで運用管理ツールに読み込ませることにより、運用管理ツールが自動的にサーバ実行機へ転送し、環境を構築します。以下の手順にしたがって、サンプルプログラムを運用管理ツールで登録してみます。 R5形式(インタフェースと実装を分ける場合):
  1. 運用管理ツールを起動します。
  2. 「インタフェースコンポーネントファイル」を「共有コンポーネント」として配備します。
    登録するのはjarファイルとifファイルです。
    .spkファイルを作成して登録する事も出来ます。
    .spkの作成例は以下の通りです。
    例 :
    >/opt/WebOTX/bin/makecpk loopback.spk module=loopback.jar if=loopback.if
  3. アプリケーショングループとプロセスグループを新規に作成してください。 ここでは、sampleとsamplesvとします。プロセスグループを追加するとき、言語はJ2SEを選択してください。
  4. サーバコンポーネントを「CORBAコンポーネント」として配備します。
    「共有コンポーネントのifを利用するかどうか」にはチェックをして、共有コンポーネントとして登録しているifファイル名を入力します。
    「コンポーネント初期化関数」には、コンポーネント初期化クラス名(この例ではLoopBackInit)を入力します。
    .cpkファイルを作成して登録する事も出来ます。
    .cpkの作成例は以下の通りです。
    例 :
    >/opt/WebOTX/bin/makecpk loopback.cpk module=loopback.jar if=loopback.if \
                                       initfunc=LoopBackInit useshareif=true
    
  5. コンポーネントの設定の共有コンポーネントのタブを開いて、インタフェースコンポーネントファイルを選択します。
  6. アプリケーショングループの起動を選んで、アプリケーショングループを起動します。
    アプリケーショングループが起動されると、アイコンの色が赤から緑に変わります。
R5形式(インタフェースと実装をまとめる場合):
  1. 運用管理ツールを起動します。
  2. アプリケーショングループとプロセスグループを新規に作成してください。
    ここでは、sampleとsamplesvとします。プロセスグループを追加するとき、言語はJ2SEを選択してください。
  3. コンポーネントを「CORBAコンポーネント」として配備します。
    コンポーネント初期化関数」には、コンポーネント初期化クラス名(この例ではloopbackInit)を入力します。
    .cpkファイルを作成して登録する事も出来ます。
    .cpkの作成例は以下の通りです。
    例 :
    >/opt/WebOTX/bin/makecpk loopback.cpk module= LoopBackSample.jar if=loopback.if \
                                             initfunc=loopbackInit useshareif=false
  4. アプリケーショングループの起動を選んで、アプリケーショングループを起動します。
    アプリケーショングループが起動されると、アイコンの色が赤から緑に変わります。
WebOTX R4.2まではプロセス起動時にファクトリのIORを名前サーバに登録していましたが、 WebOTX R5.1からは事前登録がデフォルトになっています。詳しくは 高度な管理と運用サイクルガイド をご覧ください。 以上で、サーバアプリケーションの登録が完了しました。
常駐オブジェクトの使い方
常駐オブジェクトについては [常駐オブジェクト機能] をご覧ください。ここでは、具体的な利用方法を示します。
単一常駐オブジェクトのコーディング方法
WebOTXは常駐オブジェクト機能を提供します。これは、1つのプロセスグループに1つのオブジェクトを登録し、 WebOTX起動時にスレッド毎にオブジェクトを事前生成する機能です(単一常駐オブジェクトと呼びます)。サーバアプリケーション内で常駐オブジェクトを定義して利用するには、次の手順を実行します。
  1. 普通のJavaのクラスを定義してコンパイルします。
  2. このクラスファイルをWebOTX機に転送します。
  3. 運用管理ツールで先ほど転送したクラスファイルのパスとパッケージ名も含めたクラス名を常駐オブジェクトとして指定します。
  4. 以下にコーディング例を示します。
import jp.co.nec.WebOTX.WO_PUOObjectListener;
import jp.co.nec.WebOTX.WO_PUOOperationListener;

public class preObjhoo1 implements WO_PUOObjectListener, WO_PUOOperationListener {
    String m_ID;

    public preObjhoo1() {
    }

    public void OnTPSPUOCreateObject() {
       // 生成時に特別な処理を行うときに記述
    }

    public void OnTPSPUOReleaseObject() {
       // 解放時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationStart(String intf, String opname) {
        // オペレーション開始時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationNormal(String intf, String opname) {
        // オペレーション正常終了時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationAbnormal(String intf, String opname, int status) {
        // オペレーション異常終了時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationAbort(String intf, String opname, int status) {
        // オペレーションアボート時に特別な処理を行うときに記述
    }

    // 常駐オブジェクトとしてのオペレーション
    public int set(String ID) {
        m_ID = id;
        return m_ID.length();
    }
}
単一常駐オブジェクトのコーディング方法
常駐オブジェクトに対して以下に示すインタフェースを実装すると、特定の事象が発生したときにWebOTXからコールバックされます。常駐オブジェクトでより細かな制御を行いたいときに組み込んでください。
jp.co.nec.WebOTX.WO_PUOObjectListenerインタフェース

常駐オブジェクトがこのインタフェースを実装していると、
  • 常駐オブジェクト生成時にOnTPSPUOCreateObject()
  • 消滅時にOnTPSPUOReleaseObject()
をそれぞれ呼び出します。
public interface jp.co.nec.WebOTX.WO_PUOObjectListener {
    public void OnTPSPUOCreateObject();
    public void OnTPSPUOReleaseObject();
}
jp.co.nec.WebOTX.WO_PUOOperationListenerインタフェース

常駐オブジェクトがこのインタフェースを実装すると、
  • 各サーバオブジェクトの呼び出し(OnTPSOperationStart)
  • 正常終了時(OnTPSPUOOperationNormal)
  • 異常終了時(OnTPSPUOOperationAbnormal)
  • 例外時(OnTPSPUOOperationAbort)
にそれぞれ呼び出します。
public interface jp.co.nec.WebOTX.WO_PUOOperationListener {
    public void OnTPSPUOOperationStart(String intf, String opname);
    public void OnTPSPUOOperationNormal(String intf, String opname);
    public void OnTPSPUOOperationAbnormal(String intf, String opname, int status);
    public void OnTPSPUOOperationAbort(String intf, String opname, int status);
}
複数常駐オブジェクトのコーディング方法
常駐オブジェクトをより高度に利用しようとした時、一つの常駐オブジェクトでは難しい処理があります。例えば、データベース毎に常駐オブジェクトを作成したい、業務内容毎に常駐オブジェクトを作成したい、というケースです。このようなケースでも、一つの常駐オブジェクトで実現可能ですが、機能が増えるたびに常駐オブジェクトを利用しているすべてのサーバアプリケーションの再コンパイルが必要になりかねません。 そこで、常駐オブジェクトを用いて多数の機能を作成する場合は、ここで説明する複数常駐オブジェクトを利用することで作業効率および保守効率を上がります。 複数常駐オブジェクトのコーディングは単一常駐オブジェクトと変わりません。 作成したクラスファイルは必ずjarコマンドでまとめてください。 ここで作成したjar名(zip名)と常駐オブジェクトクラス名(xxx.yyy.zzzのように記述)を運用管理ツールに指定します。 サンプルコーディングを以下に示します。
preObjhoo2.java

import jp.co.nec.WebOTX.WO_PUOObjectListenerForPlural;
import jp.co.nec.WebOTX.WO_PUOOperationListenerForPlural;

public class preObjhoo2 implements WO_PUOObjectListenerForPlural, 
                                   WO_PUOOperationListenerForPlural {
    String m_ID;

    public preObjhoo2() {
    }

    public void OnTPSPUOCreateObject(String ident) {
       // 生成時に特別な処理を行うときに記述
    }

    public void OnTPSPUOReleaseObject(String ident) {
       // 解放時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationStart(String ident, String intf, String opname) {
        // オペレーション開始時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationNormal(String ident, String intf, String opname) {
        // オペレーション正常終了時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationAbnormal(String ident, String intf, 
                                          String opname, int status) {
        // オペレーション異常終了時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationAbort(String ident, String intf, 
                                       String opname, int status) {
        // オペレーションアボート時に特別な処理を行うときに記述
    }

    // 常駐オブジェクトとしてのオペレーション
    public int set(String ID) {
        m_ID = id;
        return m_ID.length();
    }
}
preObjhoo3.java
import jp.co.nec.WebOTX.WO_PUOObjectListener;
import jp.co.nec.WebOTX.WO_PUOOperationListener;

public class preObjhoo3 implements WWO_PUOObjectListenerForPlural, 
                                   WO_PUOOperationListenerForPlural {
    int m_len;
    public preObjhoo3() {
    }

    public void OnTPSPUOCreateObject(String ident) {
       // 生成時に特別な処理を行うときに記述
    }

    public void OnTPSPUOReleaseObject() {
       // 解放時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationStart(String ident, String intf, String opname) {
        // オペレーション開始時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationNormal(String ident, String intf, String opname) {
        // オペレーション正常終了時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationAbnormal(String ident, String intf, 
                                          String opname, int status) {
        // オペレーション異常終了時に特別な処理を行うときに記述
    }

    public void OnTPSPUOOperationAbort(String ident, String intf, 
                                       String opname, int status) {
        // オペレーションアボート時に特別な処理を行うときに記述
    }

    // 常駐オブジェクトとしてのオペレーション
    public void set(int len) {
        m_len = len;
    }
}
複数常駐オブジェクトのコールバックについて
複数常駐オブジェクトにもコールバックインタフェースがあります。但し、単一の時とは別のインタフェース名ですので注意してください。
jp.co.nec.WebOTX.WO_PUOObjectListenerForPluralインターフェース

常駐オブジェクトがこのインタフェースを実装していると、
  • 常駐オブジェクト生成時にOnTPSPUOCreateObject()
  • 消滅時にOnTPSPUOReleaseObject()
をそれぞれ呼び出します。
public interface jp.co.nec.WebOTX.WO_PUOObjectListenerForPlural {
    public void OnTPSPUOCreateObject(String ident);
    public void OnTPSPUOReleaseObject(String ident);
}
jp.co.nec.WebOTX.WO_PUOOperationListenerForPluralインターフェース

常駐オブジェクトがこのインタフェースを実装すると、
  • 各サーバオブジェクトの呼び出し(OnTPSOperationStart)
  • 正常終了時(OnTPSPUOOperationNormal)
  • 異常終了時(OnTPSPUOOperationAbnormal)
  • 例外時(OnTPSPUOOperationAbort)
をそれぞれ呼び出します。
public interface jp.co.nec.WebOTX.WO_PUOOperationListenerForPlural {
    public void OnTPSPUOOperationStart(String ident, String intf, String opname);
    public void OnTPSPUOOperationNormal(String ident, String intf, String opname);
    public void OnTPSPUOOperationAbnormal(String ident, String intf, 
                                          String opname, int status);
    public void OnTPSPUOOperationAbort(String ident, String intf, 
                                       String opname, int status);
}
常駐オブジェクトを用いたサーバアプリケーションの作成方法
以下に単一および複数常駐オブジェクトを使用した時の例を載せます。
import foo.*;
import preObjhoo1;
import preObjhoo2;
import preObjhoo3;
import jp.co.nec.WebOTX.orbsvwpr.*;

public class fooObj extends fooPOA {
    public fooObj() {
    }

    public int op1(java.lang.String ID) {
        preObjhoo1 preobj1;
        preObjhoo2 preobj2;
        preObjhoo3 preobj3;

        // 単一常駐オブジェクトの取得
        preObjhoo1 = (preObjhoo1)WoServerWrapper.TPSGetPrecreatedUsersObject();

        // メソッドの呼び出し(本来ならnullチェックが必要)
        if (preObjhoo1 != null) {
            preObjhoo1.set(ID);
        } else {
            // エラー処理
        }

        // 複数常駐オブジェクトの取得
        try{
            // hoo2とhoo3は運用管理ツールで指定。
            // 大文字小文字を区別するので注意が必要
            preObjhoo2 =
               (preObjhoo2)
                   WoServerWrapper.TPSGetPrecreatedUsersObjectForPlural("hoo2");
            preObjhoo3 =
               (preObjhoo3)
                   WoServerWrapper.TPSGetPrecreatedUsersObjectForPlural("hoo3");
        }catch(Exception e){
            e.printStackTrace();
            return -1;
        }

        // メソッドの呼び出し(例外処理しているので nullチェックは不要)
        return preObjhoo3.set(preObjhoo2.set(ID));
    }
}
共有プロパティの利用方法
プロセスグループには多数のコンポーネントが登録可能です。 コンポーネント間で共有データなどを参照する場合(ディスクに書き込む必要のない、変化の激しいデータ)は、グローバル変数を使うことにより実現できます。しかし、グローバル変数を用いた方法では幾つかの問題点が あります。一つは排他処理が必須であるが煩雑である。もう一つはプロセス間におけるデータの共有ができない。 WebOTXでは、これらの問題点を克服した共有プロパティという機能があります。 ここでは、共有プロパティについて説明します。
共有プロパティ概要
共有プロパティは以下の4つの要素から構成されています。
プロパティグループエリアとは、以下に説明するプロパティグループを作成する場所のことです。場所の種類は「ホスト内共有」、「システム内共有」、「アプリケーショングループ内共有」、「プロセスグループ内共有」の4種類です。 ホスト内共有の場合、複数のWebOTXシステムを一つのマシンで動かしたとき、すべてのプロセスから参照や更新をすることが出来ます。システム内共有の場合、そのシステム内のすべてのプロセスから参照や更新をすることができます。 アプリケーショングループ内共有の場合は、そのアプリケーショングループ内のすべてのプロセスから参照や更新をすることが出来ます。プロセスグループ内共有の場合は、そのプロセスグループ内のすべてのプロセスから参照や更新をすることが出来ます。 プロパティグループとは、複数のプロパティを一つのグループとしてまとめた単位のことです。 共有プロパティを利用するときは必ずプロパティグループを作成しなければなりません。プロパティとは値を格納する単位のことです。値とは、プロパティに設定する数値や文字列のことです。 プロパティグループおよびプロパティには、プロパティグループエリア内で一意に識別する文字列を設定します。 この文字列をキーにコンポーネント間で値の受け渡しを行います。 共有プロパティの利用方法概要を以下に示します。
プロパティグループの作成、取得、解放
プロパティグループはサーバAPIを利用して作成/取得/解放します。サーバAPIの説明については [ リファレンス集 開発編(共通) > 4. CORBA > 4.2. WebOTX CORBA アプリケーション(Java) > 4.2.1. サーバAPI ] を参照してください。ここでは、使用例を示します。エラー処理は省略しています。
    :
import jp.co.nec.WebOTX.WOPropertyGroupManager;
import jp.co.nec.WebOTX.WOPropertyGroup;
import jp.co.nec.WebOTX.WOProperty;
import jp.co.nec.WebOTX.orbsvwpr.WoServerWrapper;
import propPOA;

public class foo extends propPOA {

    WOPropertyGroupManager pgm = new WOPropertyGroupManager();

    public int Lock() {
        WOPropertyGroup[] pg = new WOPropertyGroup[1];      // オブジェクトを得るため
        int area = WOPropertyGroupManager.WOSP_AREATYPE_HOST; // ホスト内共通
        java.lang.String pgname = "SamplePGName";   // PropertyGroup名

        // プロパティグループの生成
        ong nRet = pgm.TPSCreatePropertyGroup(pgname, area, pg);
        if (nRet < 0) {
            WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                    " Lock(): TPSCreatePropertyGroup() ==> " + nRet);
            return (int)nRet;
        } else {
            WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                    " Lock(): TPSCreatePropertyGroup() ==> " + nRet);
        }

        // ロック(5秒間の待ち合わせあり)を行う
        int waitmode = WOPropertyGroup.WO_PG_WAIT;        // 待ち合わせあり
        int waittime = 5000;                              // 5秒間待ち合わせ(単位ms)

        nRet = pg[0].Lock(waitmode, waittime);
        if (nRet < 0) {
            WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                    " Lock(): Lock() ==> " + nRet);
            return (int)nRet;
        } else {
            WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                    " Lock(): Lock() ==> " + nRet);
        }

        // プロパティの生成
        WOProperty pro[] = new WOProperty[1];
        nRet = pg[0].CreateProperty(pname, pro);
        if (nRet < 0) {
            WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                    " SetValue(): CreateProperty() ==> " + nRet);
            return (int)nRet;
        } else {
            WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                    " SetValue(): CreateProperty() ==> " + nRet);
        }

        // 値の取得
        int[] getvalue = new int[1];
        nRet = pro[0].Get(getvalue);
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                     " GetValue(): Get() value ==> " +getvalue[0]);
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                     " GetValue(): Get() nRet ==> " + nRet);

        // プロパティグループのアンロック
        nRet = pg[0].Unlock();
        if (nRet != 0) {
            WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                     " Unlock(): Unlock() ==> " + nRet);
            return (int)nRet;
        } else {
            WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                     " Unlock(): Unlock() ==> " + nRet);
        }
        return (int)nRet;
    }
}
プロパティの生成/取得
プロパティは、プロパティグループクラス(WOPropertyGroup)のメソッドを使って生成/取得を行います。 プロパティの生成を行うにはCreateProperty()メソッド、取得を行うにはGetProperty()メソッドを使用します。使用例は上記プロパティグループの例題を参照してください。
値の設定/取得
値の設定や取得はプロパティクラス(WOProperty)のメソッドを使って行います。 値の設定はSet()メソッド、取得を行うにはGet()メソッドを使用します。 Set()メソッド、Get()メソッドを実行する前に必ず該当するプロパティグループをロックしてください。 使用例は上記プロパティグループの例題を参照してください。
プロパティグループのロック
多数のプロセスから同時にアクセスされるデータの場合、整合性を保つためにデータのロックを行ってから参照や更新を行う必要があります。共有プロパティではプロパティグループ単位にロック制御が可能になっています。
WebOTX Transaction Serviceとの連携
WebOTX Transaction Serviceと連携することによりXAインタフェースによるDBアクセス、 2フェーズコミットやネスティングトランザクションが可能となります。 以下にWebOTX Transaction Serviceとの連携アプリケーションを作成する場合の手順を示します。
共有コンポーネント機能
共有コンポーネントとは、複数のサーバアプリケーション上で共有に使えるインタフェースやその実装をまとめたものです。ここでは共有コンポーネントの作成方法と利用方法について説明します。
共有コンポーネントの作成方法
共有コンポーネントを作成する手順を以下に示します。
  1. IDLファイルを作成する(Animal.idlとします)
    interface Animal {
        string kind();
        string name();
    };
    
  2. i2jコマンドを用いて以下のようにコンパイルする
    >i2j -i Animal.idl
    
  3. 通常のサーバコンポーネントと同様にJarファイルを作成します
  4. ここで、実装コードを組み込む場合後は必要なロジックを組み込んでコンパイルし、jarファイルを作成します。
共有コンポーネントの利用方法
共有コンポーネントを利用したサーバアプリケーションの作成方法を以下に示します。
  1. 共有コンポーネントで定義したインタフェースを利用したIDLを作成する(pet.idl)
    module Pet {
        interface Dog : ::Animal {
            long bark();
        };
        interface Cat : ::Animal {
            long jump();
        };
    };
    
  2. 共有コンポーネントのIDLファイルを参照するようにwoi2jを実行する。
    >woi2j -R Animal.idl pet
    
    -Rは複数個記述することもできます。
    (例)>woi2j -R com1.idl -R com2.idl extends 
    
  3. 通常のサーバコンポーネントを作成するようにコーディングしてください。
    共有コンポーネントのインタフェースを継承していて、共有コンポーネントに実装がある場合は、tieアプローチによる実装を行ってください。 (woi2j -tie -R Animal.idl pet)
  4. あとはコンパイルして jar ファイルを作成してください。
共有コンポーネントの登録方法
作成した共有コンポーネントとサーバコンポーネントはそれぞれ運用管理ツールに登録します。登録方法は「ドメイン構築・基本設定ガイド」をご覧ください。 なお、登録した共有コンポーネントはクラスサーチパスの最後に加わります。
クライアントアプリケーションについて
クライアントアプリケーションは共有コンポーネントのjarファイルをCLASSPATHに加えることに注意してください。あとは通常の作成手順と同様に作成します。また、配布も共有コンポーネントのjarファイルまたはクラスファイルをいっしょに配布することを忘れないでください。
非同期トランザクションについて
非同期トランザクションとは
通常、IDLコンパイラが生成したソースを用いてCORBAアプリケーションを作成した時は同期型か遅延同期型しかありません。DII(Dynamic Invocation Interface)を使用して非同期呼び出しを行うことも可能ですが難易度が高いのが現状です。また、非同期に呼び出したオペレーションの伝達保証もありません。 WebOTXでは以下に示す仮想宛先機能を使うことにより、呼び出し伝達の保証しつつ、コーディングの変更なしに非同期にオペレーションを呼び出すことができる 非同期トランザクション機能 を提供します。 本節では、この非同期トランザクションについて説明します。
仮想宛先(VD:Vritual Destination)とは
仮想宛先とは様々なメッセージ送受信機能を可能にする為に導入された概念です。仮想宛先の実体は、メモリやファイルに実装されますが、サーバプログラムからはCORBAクライアントに見えます。
非同期トランザクションの利用方法
非同期トランザクションを利用する為には、IDLの定義と名前サーバからオブジェクトの取得、運用管理ツールによる定義が必要です。
  1. IDL定義
    非同期トランザクションとして呼び出されるオペレーションは以下のルールに従って記述しなければなりません。
    • ステートレス&ファクトリレスで動作すること
    • 引数はすべてin型で定義する
    • 返却値はlongで定義する
    以下に例を示します。
    interface foo {
        long AsyncOP(in string key, in long size);
    };
    
  2. 名前サーバからオブジェクトリファレンスの取得
    前述で定義したインタフェースのオブジェクトを呼び出す為に、 名前サーバからオブジェクトリファレンスを入手する必要があります。
    オブジェクトリファレンス取得の為のサンプルコーディングを以下に示します。
  3. 非同期トランザクションの呼び方
    前述で定義したインタフェースのオブジェクトを通常のアプリケーションのように呼び出してください。
  4. 非同期トランザクションの成功の可否の判断方法
    オペレーション返却値より判断してください。
    • 0: 正常終了
    • 80: エラー。ただし、VDサーバのプール数の上限に達した場合もあるので、間隔をおいてリトライすることをお勧めします。
    • 1以上の値: エラー。VD未起動あるいは運用管理ツールの設定ミスが考えられます。
    • -1以下の値: エラー。通常は発生しません(VDサーバへの送信パラメータミス)。もし、これが発生した場合は運用管理ツールの設定を再度行ってみてください。
  5. 運用管理ツールによる定義
    非同期トランザクションを利用する為には、運用管理ツールにて以下の設定が必要です。
    1. 「非同期トランザクションを利用する」と設定
      非同期オペレーションを使用するプロセスグループのプロパティで設定します。
    2. 「VD(仮想宛先)」の設定
      VDの作成時に指定する「VDの型」で「トランザクション型」を選択します。そして、対応するオペレーションを選択します。 上記例の場合、fooインタフェースのAsyncOPとなります。
    3. プロセスグループプロパティとインタフェースプロパティの設定
      非同期処理を行うプロセスグループの設定で以下のように指定してください。 下記パラメータ以外の設定は任意です。
      • プロセスグループプロパティ
        • オペレーションコールのモード
          • ステート:ステートレス
      • インタフェースプロパティ
        • 「事前生成を行う」をチェックする
  6. サーバコンポーネントの登録
    以下のように非同期トランザクションを呼び出すコンポーネントと処理をするコンポーネントでプロセスグループを別々に分けてください。
    tpsystem
      +-vdtest --------------------- アプリケーショングループ名
          +-TxFirst ----------------- プロセスグループ名
          |   +-TxFirst.jar --------- サーバコンポーネント
          |                           (非同期トランザクションを使用する)
          +-TxSecond --------------- プロセスグループ名
              |                        (ステートレス、ファクトリを使用しない)
              +-TxSecond.jar ------- サーバコンポーネント
                  |                    (非同期トランザクションを実行する)
                  +-インタフェース---- 事前生成を行う
上記構成を前提としたサンプルプログラムがありますので参照してください。
初期化/終了関数
ファクトリオブジェクトやサーバオブジェクトの生成より前に独自の初期化処理や終了処理を組み込みたい場合は、 jp.co.nec.WebOTX.Objectcreator.InitTerm.java を作成してコンパイルし、classファイルをサーバAPのjarファイルに含めて登録してください。 InitTermクラスはjp.co.nec.WebOTX.WO_InitTerm をimplementsする必要があります。
コーディング例:
package jp.co.nec.WebOTX.Objectcreator;

import org.omg.CORBA.ORB;
import jp.co.nec.WebOTX.WO_InitTerm;
import jp.co.nec.WebOTX.WebOTX_Information;
import jp.co.nec.WebOTX.orbsvwpr.WoServerWrapper;

public class InitTerm implements WO_InitTerm {
    public void initialize(ORB orb, WebOTX_Information info) {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                     "===***=== initialize");
    // 初期化処理
    }

    public void terminate(ORB orb, WebOTX_Information info) {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                     "===***=== terminate");
        // 終了処理
    }
}
既定値以外のValueファクトリを使用する場合にも、初期化関数でvalueファクトリを登録してください。
(例)
((org.omg.CORBA_2_3.ORB)orb).register_value_factory(NamesHelper.id(), new NamesValueFactory_impl());
オブジェクト生成/消滅のコールバックインタフェースについて
Java言語は、言語特性からC++言語で言うところデストラクタがありません。似たようなものにfinalizeがありますが、これはガーベージコレクターによってコレクション対象になったオブジェクトが解放された時に呼ばれる関数です。よって、いつ呼び出されるか分かりませんし、場合によっては呼び出されないこともあります。 そこで、WebOTXではサーバオブジェクトの生成後と消滅前にコールバックする機能を提供します。これを利用すれば、コンストラクタとは別な共通的な初期化処理や、オブジェクトの解放と同時にコネクションの切断やリソースの解放処理などを組み込むことができます。 サーバオブジェクトの生成/消滅時のコールバック機能を有効にするには、以下に示すインタフェースをサーバオブジェクトに実装してください (なお、常駐オブジェクトには別のインタフェースがありますのでそちらを使用してください)。
jp.co.nec.WebOTX.WO_ObjectListenerインタフェース
public interface jp.co.nec.WebOTX.WO_ObjectListener {
    public void OnTPSCreateObject();
    public void OnTPSReleaseObject();
}
OnTPSCreateObject()はサーバオブジェクト生成後に、 OnTPSReleaseObject()はサーバオブジェクト消滅前にそれぞれコールバックします。
アプリケーション初期プロセスについて
アプリケーション初期プロセスとは、アプリケーショングループ内部のプロセスグループの起動に先立って前処理を行うことが出来るサーバアプリケーションのことです。設定方法に関しては運用管理ツールの説明をご覧ください。ここでは、サーバAPの作成方法を示します。
アプリケーション初期プロセス用インタフェース
アプリケーション初期プロセスのためのアプリケーションは以下のインタフェースを有したclassファイルを作成する必要があります。起動と同時に呼び出されて、この関数の返却値によってアプリケーショングループの起動を継続するか停止するか指定できます。主な用途として、共有メモリの初期化に使用してください。
利用可能なサーバAPIについて
アプリケーション初期プロセス内部で使用できWebOTX APIの一覧を示します。
表1.2.1.3-1
オペレーション操作関連
TPSSetTxStatus() × オペレーション呼び出し中のみ意味があるため
TPSRegisterDB() × オペレーション呼び出し中のみ意味があるため
TPSAbort() × オペレーション呼び出し中のみ意味があるため
TPSRestart() × オペレーション呼び出し中のみ意味があるため
トレース関連
TPSUserTrace() △ トレースレベル1または2のときのみ出力可能
TPSGetUserTraceLevel
TPSEventJournal()
情報取得
TPSGetLid() × オペレーション呼び出し中のみ意味があるため
TPSGetArgument()
TPSGetServerInformation() △ 一部情報が欠落する(後述)
常駐オブジェクト関連
TPSGetPrecreatedUsersObject() × オペレーション呼び出し中のみ意味があるため
TPSGetPrecreatedUsersObjectForPlural()× オペレーション呼び出し中のみ意味があるため
SPA関連
TPSGetSpa() × オペレーション呼び出し中のみ意味があるため
TPSSetSpa() × オペレーション呼び出し中のみ意味があるため
TPSSetSpaFlag() × オペレーション呼び出し中のみ意味があるため
共有プロパティ関連
TPSCreatePropertyGroup()
TPSGetPropertyGroup()
TPSDeletePropertyGroup()
CreateProperty()
GetProperty()
DeleteProperty()
Lock()
Unlock()
Set()
Get()
WebOTXの情報
アプリケーショングループ名
プロセスグループ名 × プロセスグループ単位の指定パラメータのため
ステートフルかステートレスか × プロセスグループ単位の指定パラメータのため
スレッドモデル × プロセスグループ単位の指定パラメータのため
IIOPリスナポート番号
クライアント管理ライブラリポート
常駐オブジェクトクラス名 × プロセスグループ単位の指定パラメータのため
OTS連携を行うか × プロセスグループ単位の指定パラメータのため
システムID
接続サーバ名
名前サーバ名
Watchサーバを使用するか
名前サーバに登録するリファレンスの数
ファクトリを使うかどうか × プロセスグループ単位の指定パラメータのため
障害発生時の処理について
例外発生時のコールバックについて
WebOTXでは、サーバアプリケーション内部で例外が発生した時、例外があったことをサーバオブジェクトに通知する機能があります。 これを利用するには以下の条件を全て満たしている必要があります。
以上の条件を満たしていると、例外時にWO_Base::OnTPSAbort() の実装部分を呼び出します。ここに例外時の後処理などを記述してください。
クライアントとのセッション切断について
WebOTXでは、クライアントアプリケーションが切断した時、切断したことをサーバオブジェクトに通知する機能があります。 これを利用するには以下の条件を全て満たしている必要があります。
以上の条件を満たしていると、例外時にWO_Base::OnTPSDisconnect() の実装部分を呼び出します。ここにコネクション切断時の後処理などを記述してください。
サーバプロセスメッセージ通知について
WebOTXでは、フェイルオーバがあったときなどに運用管理コマンドでサーバプロセスメッセージ通知が行われた時にサーバオブジェクトにメッセージを通知する機能があります。 これを利用するには以下の条件を全て満たしている必要があります。
以上の条件を満たしていると、例外時にWO_Base::OnTPSMessageNotified() の実装部分を呼び出します。ここにフェイルオーバー時の処理などを記述してください。
データベースオブジェクトの登録と自動ロールバックについて
サーバアプリケーションで復旧できない例外が発生すると、 WebOTXはオペレーションの実行を中断し、そのオペレーションを閉塞しそれ以降実行できなくします。 このとき、WebOTXはサーバアプリケーション内で例外が発生したことを知らせるために、該当オブジェクトに対してWO_BaseインタフェースのOnTPSAbort()オペレーションを呼び出します。 OnTPSAbort()オペレーションを呼び出した後、事前に登録してあるデータベースオブジェクトに対してrollback()メソッドを発行します。 以下にWebOTX_DBインタフェースを使った簡単な定義例を示します。
import jp.co.nec.WebOTX.WebOTX_DB;
import jp.co.nec.WebOTX.orbsvwpr.WoServerWrapper;

public class MyDB implements WebOTX_DB {
    public MyDB () {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                     " **** called MyDB.");
        // データベース初期化処理
    }

    public void rollback() {
        WoServerWrapper.TPSUserTrace(WoServerWrapper.LOG_DEBUG,
                                     " **** called MyDB.rollback()");
        // データベースロールバック処理 (異常終了時に呼ばれる)
    }
}

1.2.1.4. Java言語を用いたクライアントアプリケーションの作成

Javaクライアントアプリケーションの作成の流れ
WebOTXのJavaクライアントアプリケーションの作成から実稼動までの流れは以下のようになります。以下の節ではそれぞれについて詳しく説明します。また、WebOTXが提供する機能についても説明します。
  1. IDLファイルの作成とコンパイル
  2. 実装部分のコーディングとコンパイル
開発環境の設定
一般にJava物件を作成する為には、 JDKかそれに準ずるJava IDE(Integrated Development Environment:統合開発環境)が必要になります。 これらの設定方法についてはそれぞれの説明書を良くお読みください。
UNIX
WebOTXのクライアントアプリケーションを作成するには以下のファイルをCLASSPATH環境変数に登録する必要があります。
また、IDLコンパイラを実行する為にPATH環境変数に以下のディレクトリを加える必要があります。
さらに、LD_LIBRARY_PATH環境変数に以下のディレクトリを加える必要があります。
例としてHP-UXのcshの設定方法を示します(標準インストールディレクトリのパスを例にしています)。 pathだけshell変数に代入しているのは、cshがpathとPATH環境変数の同期を行うことを前提に設定しています。
> set path=( $path /opt/ObjectSpinner/bin )
> set path=( $path /opt/WebOTX/dev/bin )
> setenv LD_LIBRARY_PATH> /opt/ObjectSpinner/lib:/opt/WebOTX/dev/lib
> setenv CLASSPATH /opt/WebOTX/modules/jsocks.jar
> setenv CLASSPATH ${CLASSPATH}:/opt/WebOTX/modules/wo-orb110.jar
> setenv CLASSPATH ${CLASSPATH}:/opt/WebOTX/modules/omgorb110.jar
> setenv CLASSPATH ${CLASSPATH}:/opt/WebOTX/dev/javalib/WOTXTRM.jar
> setenv CLASSPATH ${CLASSPATH}:/opt/WebOTX/dev/javalib/WOTXBS90.jar
Windows
WebOTXのクライアントアプリケーションを作成するには以下のファイルを CLASSPATH環境変数に登録する必要があります。 (<WebOTX>はWebOTXのインストール先ディレクトリをあらわします)。 Windows版は基本的に各ユーザのCLASSPATH環境変数に自動的に設定されます。
もし、設定がおかしいと思ったら<WebOTX>\ObjectBroker\bin\orbjsenv.exe を実行してもう一度確認してください(画面には何も表示されません)。 それでも直らない場合は、以下のレジストリの値を編集してからもう一度orbjsenv.exe を実行してください
また、IDLコンパイラを実行する為にPATH環境変数に以下のディレクトリを加える必要があります。
IDLファイルの作成とコンパイル(Java)
[IDLファイルの作成とコンパイル(Java)] を参照してください。
クライアントアプリケーションの作成方法(Java)
ファクトリを使用しない場合
サーバアプリケーションと同様にIDLコンパイラを実行して出来たファイルを使用して作成します。この例題の場合に必要なファイルは以下の通りです。
つまり ~POA.javaファイル(スケルトン)とサーバの実装(R4形式なら~Obj.javaファイル)は不要です。また、複雑なIDLになるとディレクトリも作成されます。これら全てが必要になります。 クライアントアプリケーションは通常のCORBAアプリケーションと同じように作成します。 ただし、WebOTXでは、以下の点に注意して作成する必要があります。
名前サーバにはサーバオブジェクトを登録します。それぞれのサーバに合わせて取得してください。 名前サーバへの登録は、運用管理ツールでの設定が「一時的」場合はWebOTXが自動的に行います。「永続的」場合は運用管理ツールから明示的に登録を行います。名前サーバに登録する名前のデフォルト値は以下のようになっています。この値は、運用管理ツールにて変更することができます。 /NEC/WebOTX/WO_Default/module名/module名/…/interface名/1 ( / はコンテキストの区切りをあらわします。最初の/はrootコンテキストをあらわします) クライアントアプリケーションは、以下の手順でサーバオブジェクトを利用することが出来ます。
  1. ORBに対してresolve_initial_references("NameService")を行って、名前サーバのオブジェクトリファレンスを取得し、 NamingContextにnarrow()します。
  2. NameComponentオブジェクトを生成し、idに文字列を設定し、kindには""(空の文字列)を設定してください。
  3. 名前サーバのオブジェクトリファレンスに対してresolve(NameComponentオブジェクト)を行って サー バオブジェクトリファレンスを取得してnarrow()してください。
以上のまとめとしてクライアントアプリケーションの例を以下に示します。
//
// クライアント(LoopBackSampleClient.java)
//
import org.omg.CosNaming.*;
import sample.*;

public class LoopBackSampleClient {
    private org.omg.CORBA.ORB orb = null;
    private LoopBackSample serverobj = null;

    public static void main(String args[]) {
        LoopBackSampleClient ap = new LoopBackSampleClient();

        if (ap.init(args) == false) {
            System.exit(1);
        }

        String org = "AbCdEfGhIj";
        String strRet;

        // call loopback 
        strRet = ap.call_LoopBack(org);
        if (strRet != null && strRet.equals(org)) {
            System.out.println("LoopBack OK!");
            System.out.println(" org=" + org);
            System.out.println(" res=" + strRet);
        } else {
            System.out.println("LoopBack NG!");

            if (strRet != null) {
                System.out.println(" org=" + org);
                System.out.println(" res=" + strRet);
            } else {
                System.out.println(" res=null");
            }

            System.exit(1);
        }

        // call lowercase 
        strRet = ap.call_LowerCase(org);
        if (strRet != null) {
            System.out.println("LowerCase OK!");
            System.out.println(" org=" + org);
            System.out.println(" res=" + strRet);
        } else {
            System.out.println("LowerCase NG!");
            System.out.println(" org=" + org);
            System.out.println(" res=null");
            System.exit(1);
        }

        // call uppercase 
        strRet = ap.call_UpperCase(org);
        if (strRet != null) {
            System.out.println("UpperCase OK!");
            System.out.println("  org=" + org);
            System.out.println("  res=" + strRet);
        } else {
            System.out.println("UpperCase NG!");
            System.out.println("  org=" + org);
            System.out.println("  res=null");
            System.exit(1);
        }

        ap.destroy();
    }

    public boolean init(String args[]) {
        try {
            orb = org.omg.CORBA.ORB.init(args, null);

            // get naming service object reference
            org.omg.CORBA.Object nsobj = null;
            NamingContext ns = null;
            nsobj = orb.resolve_initial_references("NameService");
            ns = NamingContextHelper.narrow(nsobj);

            // make name path of server object reference
            NameComponent ncseq[] = { 
                new NameComponent("NEC", ""),
                new NameComponent("WebOTX", ""),
                new NameComponent("WO_Default", ""),
                new NameComponent("sample", ""),
                new NameComponent("LoopBackSample", ""),
                new NameComponent("1", "")
            };

            serverobj = LoopBackSampleHelper.narrow(ns.resolve(ncseq));
            if (serverobj == null) {
                System.out.println("Server object is null.");
            }

            return true;
        } catch (Exception e) {
            System.out.println("ERROR : " + e) ;
            e.printStackTrace(System.out);
            return false;
        }
    }

    public void destroy() {
        if (serverobj != null) {
            serverobj = null;
        }
        if (orb != null) {
            try {
                // コネクション切断 (Object BrokerローカルAPI)
                jp.co.nec.orb.ConnectionManager.close_all_client_connections();
                boolean wait_for_completion = true;
                orb.shutdown(wait_for_completion); 
            } catch(Exception e) {
                System.out.println("ERROR : " + e) ;
                e.printStackTrace(System.out);
            }
        }
    }

    public String call_LoopBack(String in) {
        try{
            org.omg.CORBA.StringHolder outputChar = new org.omg.CORBA.StringHolder();
            serverobj.LoopBack(in,outputChar);
            returnoutputChar.value;
        }catch(Exception e){
            System.out.println("ERROR:" + e);
            e.printStackTrace(System.out);
            return null;
        }
    }

    public String call_LowerCase(String in) {
        try{
            org.omg.CORBA.StringHolder outputChar = new org.omg.CORBA.StringHolder();
            serverobj.LowerCase(in, outputChar);
            return outputChar.value;
        }catch(Exception e){
            System.out.println("ERROR:" + e);
            e.printStackTrace(System.out);
            return null;
        }
    }

    public String call_UpperCase(String in) {
        try{
            org.omg.CORBA.StringHolder outputChar = new org.omg.CORBA.StringHolder();
            serverobj.UpperCase(in, outputChar);
            return outputChar.value;
        }catch(Exception e){
            System.out.println("ERROR:" + e);
            e.printStackTrace(System.out);
            return null;
        }
    }
}
ファイルの作成が終わりましたら、コンパイルします。  まず、コンパイル後に出来るクラスファイルを格納するディレクトリを作成します。ここではclassesディレクトリとしています。
>mkdir classes
次にJavaのソースファイルをコンパイルしてclassファイルを作成します。 JDKの場合、以下のように入力します。
Windows
>javac -d classes *.java sample\*.java
Unix
>javac -d classes *.java sample/*.java
無事にコンパイルが終わりましたらJARファイルにまとめます。
>cd classes
>jar cvf LoopBackSampleClient.jar *.class sample
ファクトリを使用する場合
サーバアプリケーションと同様にIDLコンパイラを実行して出来たファイルを使用して作成します。この例題の場合に必要なファイルは以下の通りです。
つまり ~POA.javaファイル(スケルトン)とサーバの実装は不要です。また、複雑なIDLになるとディレクトリも作成されます。これら全てが必要になります。 クライアントアプリケーションは通常のCORBAアプリケーションと同じように作成します。 ただし、WebOTXでは、以下の点に注意して作成する必要があります。
名前サーバにはファクトリオブジェクトを登録します。名前サーバへの登録は、運用管理ツールでの設定が「一時的」場合はWebOTXが自動的に行います。「永続的」場合は運用管理ツールから明示的に登録を行います。名前サーバに登録する名前のデフォルト値は以下のようになっています。この値は、運用管理ツールにて変更することができます。 /NEC/WebOTX/WO_Default/module名/module名/…/interface名/1 ( / はコンテキストの区切りをあらわします。最初の/はrootコンテキストをあらわします) クライアントアプリケーションは、以下の手順でサーバオブジェクトを利用することが出来ます。
  1. ORBに対してresolve_initial_references("NameService")を行って、名前サーバのオブジェクトリファレンスを取得し、 NamingContextにnarrow()します。
  2. NameComponentオブジェクトを生成し、idに上記命名規則に従った文字列を設定し、kindには""(空の文字列)を設定してください。
  3. 名前サーバのオブジェクトリファレンスに対してresolve(NameComponentオブジェクト)を行って ファクトリオブジェクトリファレンスを取得してnarrow()してください。
  4. ファクトリオブジェクトリファレンスに対してCreateServerObject()を行うことにより、サーバオブジェクトリファレンスを取得できます。
  5. 使い終わりましたら、ファクトリオブジェクトリファレンスに対してReleaseServerObject()を行ってください。
以上のまとめとしてクライアントアプリケーションの例を以下に示します。
//
// クライアント(LoopBackSampleClient.java)
//
import org.omg.CosNaming.*;
import sample.*;

public class LoopBackSampleClient
{
    private org.omg.CORBA.ORB orb = null;
    private WO_Factory_LoopBackSample factoryobj = null;
    private LoopBackSample serverobj = null;

    public static void main(String args[]) {
        LoopBackSampleClient ap = new LoopBackSampleClient();
 
        if (ap.init(args) == false) {
            System.exit(1);
        }
 
        String org = "AbCdEfGhIj";
        String strRet;
 
        // call loopback 
        strRet = ap.call_LoopBack(org);
        if (strRet != null && strRet.equals(org)) {
            System.out.println("LoopBack OK!");
            System.out.println("  org=" + org);
            System.out.println("  res=" + strRet);
        } else {
            System.out.println("LoopBack NG!");
            if (strRet != null) {
                System.out.println("  org=" + org);
                System.out.println("  res=" + strRet);
            } else {
                System.out.println("  res=null");
            }
            System.exit(1);
        }
        
        // call lowercase 
        strRet = ap.call_LowerCase(org);
        if (strRet != null) {
            System.out.println("LowerCase OK!");
            System.out.println("  org=" + org);
            System.out.println("  res=" + strRet);
        } else {
            System.out.println("LowerCase NG!");
            System.out.println("  org=" + org);
            System.out.println("  res=null");
            System.exit(1);
        }

        // call uppercase 
        strRet = ap.call_UpperCase(org);
        if (strRet != null) {
            System.out.println("UpperCase OK!");
            System.out.println("  org=" + org);
            System.out.println("  res=" + strRet);
        } else {
            System.out.println("UpperCase NG!");
            System.out.println("  org=" + org);
            System.out.println("  res=null");
            System.exit(1);
        }
        ap.destroy();
    }

    public boolean init(String args[]) {
        try {
            orb = org.omg.CORBA.ORB.init(args, null);

            // get naming service object reference
            org.omg.CORBA.Object nsobj = null;
            NamingContext ns = null;
            nsobj = orb.resolve_initial_references("NameService");
            ns = NamingContextHelper.narrow(nsobj);

            // make name path of server object reference
            NameComponent ncseq[] = { 
                new NameComponent("NEC", ""),
                new NameComponent("WebOTX", ""),
                new NameComponent("WO_Default", ""),
                new NameComponent("sample", ""),
                new NameComponent("WO_Factory_LoopBackSample", ""),
                new NameComponent("1", "")
            };

            factoryobj = WO_Factory_LoopBackSampleHelper.narrow(ns.resolve(ncseq));

            if (factoryobj == null) {
                System.out.println("Factory object is null.");
            }

            serverobj = factoryobj.CreateServerObject();
            if (serverobj == null) {
                System.out.println("Server object is null.");
            }

            return true;
        } catch (Exception e) {
            System.out.println("ERROR : " + e) ;
            e.printStackTrace(System.out);
            return false;
        }
    }

    public void destroy() {
        if (factoryobj != null && serverobj != null) {
            factoryobj.ReleaseServerObject(serverobj);
            serverobj = null;
            factoryobj = null;
        }

        if (orb != null) {
            try {
                // コネクション切断 (Object BrokerローカルAPI)
                jp.co.nec.orb.ConnectionManager.close_all_client_connections();
                boolean wait_for_completion = true;
                orb.shutdown(wait_for_completion); 
            } catch(Exception e) {
                System.out.println("ERROR : " + e) ;
                e.printStackTrace(System.out);
            }
        }
    }

    public String call_LoopBack(String in) {
        try{
            org.omg.CORBA.StringHolder outputChar = new org.omg.CORBA.StringHolder();
            serverobj.LoopBack(in,outputChar);
            return outputChar.value;
        } catch (Exception e) {
             System.out.println("ERROR : " + e) ;
             e.printStackTrace(System.out);
             return null;
        }
    }

    public String call_LowerCase(String in) {
        try{
            org.omg.CORBA.StringHolder outputChar = new org.omg.CORBA.StringHolder();
            serverobj.LowerCase(in,outputChar);
            return outputChar.value;
        } catch (Exception e) {
             System.out.println("ERROR : " + e) ;
             e.printStackTrace(System.out);
             return null;
        }
    }

    public String call_UpperCase(String in) {
        try{
            org.omg.CORBA.StringHolder outputChar = new org.omg.CORBA.StringHolder();
            serverobj.UpperCase(in,outputChar);
            return outputChar.value;
        } catch (Exception e) {
             System.out.println("ERROR : " + e) ;
             e.printStackTrace(System.out);
             return null;
        }
    }
}
ファイルの作成が終わりましたら、コンパイルします。 まず、コンパイル後に出来るクラスファイルを格納するディレクトリを作成します。ここではclassesディレクトリとしています。
> mkdir classes
次にJavaのソースファイルをコンパイルしてclassファイルを作成します。 JDKの場合、以下のように入力します。
Windows
> javac -d classes *.java sample\*.java
Unix
> javac -d classes *.java sample/*.java
無事にコンパイルが終わりましたらJARファイルにまとめます。
> cd classes
> jar cvf LoopBackSampleClient.jar *.class
複雑なIDLの場合のコーディング例(Java)
サーバアプリケーションの作成の [複雑なIDLの場合のコーディング例] を参照してください。クライアントの場合は、入力と出力が逆になります。
Javaのクライアント管理ライブラリ
WebOTXでは、クライアントマシンの無通信監視や非同期メッセージ処理などを行うクライアント管理ライブラリを提供しています。この機能を使用するためにはファクトリオブジェクトが必要になります。ここではその使い方を述べます。 クライアント管理ライブラリの使い方は簡単です。まず、CLASSPATH環境変数に<WebOTX>\dev\javalib\WOTXTRM.jarを追加します。次に、jp.co.nec.WebOTX.TerminalManagerをimportします。最後に、TerminalManagerクラスのオブジェクトを生成して、SetFactoryObject()を呼び出します。SetFactoryObject()の引数にはorbとファクトリオブジェクトリファレンスを指定します。 上記クライアントアプリケーションのサンプルプログラムを基にコーディング例を示します。
//
// クライアント(LoopBackSampleClient.java)
//
import org.omg.CosNaming.*;
import sample.*;
import jp.co.nec.WebOTX.TerminalManager;

public class LoopBackSampleClient {
    private org.omg.CORBA.ORB orb = null;
    private WO_Factory_LoopBackSample factoryobj = null;
    private LoopBackSample serverobj = null;
    private TerminalManager tm = new TerminalManager();

    public static void main(String args[]) {
        LoopBackSampleClient ap = new LoopBackSampleClient();

        if (ap.init(args) == false) {
            System.exit(1);
        }

        String org = "AbCdEfGhIj";
        String strRet;

        // call loopback 
        strRet = ap.call_LoopBack(org);
        if (strRet != null && strRet.equals(org)) {
            System.out.println("LoopBack OK!");
            System.out.println("     org=" + org);
            System.out.println("     res=" + strRet);
        } else {
            System.out.println("LoopBack NG!");

            if (strRet != null) {
                System.out.println("     org=" + org);
                System.out.println("     res=" + strRet);
            } else {
                System.out.println("     res=null");
            }

            System.exit(1);
        }

        // call lowercase 
        strRet = ap.call_LowerCase(org);
        if (strRet != null) {
            System.out.println("LowerCase OK!");
            System.out.println("     org=" + org);
            System.out.println("     res=" + strRet);
        } else {
            System.out.println("LowerCase NG!");
            System.out.println("     org=" + org);
            System.out.println("     res=null");
            System.exit(1);
        }

        // call uppercase 
        strRet = ap.call_UpperCase(org);
        if (strRet != null) {
            System.out.println("UpperCase OK!");
            System.out.println("     org=" + org);
            System.out.println("     res=" + strRet);
        } else {
            System.out.println("UpperCase NG!");
            System.out.println("     org=" + org);
            System.out.println("     res=null");
            System.exit(1);
        }
        ap.destroy();
    }

    public boolean init(String args[]) {
        try {
            orb = org.omg.CORBA.ORB.init(args, null);

            // get naming service object reference
            org.omg.CORBA.Object nsobj = null;
            NamingContext ns = null;
            nsobj = orb.resolve_initial_references("NameService");
            ns = NamingContextHelper.narrow(nsobj);

            // make name path of server object reference
            NameComponent ncseq[] = { 
                new NameComponent("NEC", ""),
                new NameComponent("WebOTX", ""),
                new NameComponent("WO_Default", ""),
                new NameComponent("sample", ""),
                new NameComponent("WO_Factory_LoopBackSample", ""),
                new NameComponent("1", "")
            };

            factoryobj = WO_Factory_LoopBackSampleHelper.narrow(ns.resolve(ncseq));
            if (factoryobj == null) {
                System.out.println("Factory object is null.");
            }

            serverobj = factoryobj.CreateServerObject();
            if (serverobj == null) {
                System.out.println("Server object is null.");
            }

            tm.SetFactoryObject(orb, factoryobj);
            tm.SetMessageType(TerminalManager.TM_MESSAGE_SYSTEMOUT);

            return true;
        } catch (Exception e) {
            System.out.println("ERROR : " + e) ;
            e.printStackTrace(System.out);
            return false;
        }
    }

    public void destroy() {
        if (factoryobj != null && serverobj != null) {
            factoryobj.ReleaseServerObject(serverobj);
            serverobj = null;
            factoryobj = null;
        }

        tm.Term();

        tm = null;
        if (orb != null) {
            try {
                // コネクション切断 (Object BrokerローカルAPI)
                jp.co.nec.orb.ConnectionManager.close_all_client_connections();

                boolean wait_for_completion = true;
                orb.shutdown(wait_for_completion); 
            } catch(Exception e) {
                System.out.println("ERROR : " + e) ;
                e.printStackTrace(System.out);
            }
        }
    }

    public String call_LoopBack(String in) {
        try{
            org.omg.CORBA.StringHolder outputChar = new org.omg.CORBA.StringHolder();
            serverobj.LoopBack(in,outputChar);

            return outputChar.value;
        } catch (Exception e) {
            System.out.println("ERROR : " + e) ;
            e.printStackTrace(System.out);
            return null;
        }
    }

    public String call_LowerCase(String in) {
        try{
            org.omg.CORBA.StringHolder outputChar = new org.omg.CORBA.StringHolder();
            serverobj.LowerCase(in,outputChar);

            return outputChar.value;
        } catch (Exception e) {
            System.out.println("ERROR : " + e) ;
            e.printStackTrace(System.out);

            return null;
        }
    }

    public String call_UpperCase(String in) {
        try{
            org.omg.CORBA.StringHolder outputChar = new org.omg.CORBA.StringHolder();
            serverobj.UpperCase(in,outputChar);

            return outputChar.value;
        } catch (Exception e) {
            System.out.println("ERROR : " + e) ;
            e.printStackTrace(System.out);
            return null;
        }
    }
}
修正個所には下線をつけています。これで、無通信監視機能、非同期メッセージ表示機能が使えます。なお、クライアント管理ライブラリの有効期間はTerm()メソッドを呼び出すまでです。 非同期メッセージ表示機能にはダイアログボックスを表示するほかに、メッセージを送信する拡張機能があります。これを使うことより、非同期メッセージを受信した後の動作を独自に実装することが出来ます。クライアント管理ライブラリに関するAPIについては [ リファレンス集 開発編(共通) > 4. CORBA > 4.2. WebOTX CORBA アプリケーション(Java) > 4.2.3. クライアント管理ライブラリAPI ] を参照してください。
ORBのプロパティ定義
ORB初期化時に設定できるいくつかのパラメータについては Object Broker マニュアルの「プログラミングマニュアル」-「ORBの初期化」をご覧ください。 自ホスト以外の名前サーバを指定する時やwstringのコードセットの設定方法等が書かれています。また、JavaアプリケーションとJavaアプレットでは指定方法が異なりますので注意して読んでください。
例外処理について
CORBAの例外はJava言語の例外にマッピングされています。例外の種類には大きく「システム例外」と「ユーザ例外」の2種類あります。 システム例外は、CORBAで規定されたもので主にORBが使用し生成します。システム例外にはマイナーコードが設定されています。マイナーコードはどこでどのような障害が発生したかを示しています。デバッグ効率上げたり、本番運用における障害箇所の特定が可能になりますので、クライアントアプリケーションでは例外の名前とマイナーコードを表示したり記録するロジックを作ったりすることを推奨いたします。 もう一つの例外はユーザ例外です。ユーザ例外はIDLに記述します。例外をうまく設計することで、呼び出した関数が正常に終わったのか異常終了したのかを関数返却値で判断するのではなく、try catch節で処理することが出来ます。

1.2.1.5. C++言語を用いたサーバアプリケーションの作成

WebOTXで利用することが可能なCORBAサーバアプリケーションは、実装部分だけ作成したDLLまたはSO,SLファイルです。この章ではC++言語を使ったアプリケーションの作成方法について説明します。 Windows(Intelx86)上ではC++のサーバアプリケーションおよびクライアントアプリケーションの作成は、VC++2005、VC++2008、VC++2010又はVC++2012を利用して作成することが可能です。 Windows(x64)上ではC++のサーバアプリケーションおよびクライアントアプリケーションの作成は、VC++2005、VC++2008、VC++2010又はVC++2012を利用して作成することが可能です。 HP-UXはaCC, Linuxはg++(4.2), SolarisはCCといったC++コンパイラを利用して作成することが可能です。
C++サーバアプリケーションの作成の流れ
WebOTX用のサーバアプリケーションの作成の流れは以下のようになります。
  1. IDLファイルの定義
  2. IDLファイルのコンパイル
  3. ヘッダファイルの定義(xxx_i.h)
  4. 実装部分の定義(xxx_i.cpp or xxx_i.C)
  5. コンパイル & リンク
  6. サーバシミュレータによる動作確認
  7. 運用管理ツールから実行環境への登録
  8. テストを行う
開発環境の設定
プラットフォーム別に開発環境の設定を示します。
UNIX
WebOTXのサーバアプリケーションを作成するにはPATH環境変数に以下のディレクトリを加える必要があります。
さらに、LD_LIBRARY_PATH環境変数に以下のディレクトリを加える必要があります。
例としてcshの設定方法を示します(標準インストールディレクトリのパスを例にしています)。 pathだけshell変数に代入しているのは、cshがpathとPATH環境変数の同期を行うことを前提に設定しています。
   :
set path=( $path /opt/ObjectSpinner/bin )
set path=( $path /opt/WebOTX/dev/bin )
   :
setenv LD_LIBRARY_PATH /opt/ObjectSpinner/lib: \
                       /opt/ObjectSpinner/namespace/lib: \
                       /opt/WebOTX/dev/lib
   :
Windows(Intel x86)
WebOTXのクライアントAPを作成するにはPATH環境変数に以下のディレクトリを加える必要があります(<WebOTX>はWebOTXのインストール先ディレクトリをあらわします)。
IDLコンパイラはVC++プリプロセッサを使用しています。よって、コマンドプロンプトからVC++-の実行ファイルを使えるように環境変数を設定する必要があります。プリプロセッサのための環境変数の設定方法は2種類あります。一つは、静的に環境変数を設定する方法([コントロールパネル]-[システム]-[環境]にて設定)。もう一つは、VC++をインストールしたディレクトリ配下にあるvcvars32.batというバッチファイルを実行する方法です。いずれかの方法で環境変数の設定を行ってください。
Windows(Intel 64)
WebOTXのサーバAPを作成するにはPATH環境変数に以下のディレクトリを加える必要があります(<WebOTX>はWebOTXのインストール先ディレクトリをあらわします)。
IDLコンパイラはVC++2005、VC++2008、VC++2010、VC++2012のプリプロセッサをサポートしています。よって、コマンドプロンプトからVC++2005、VC++2008、VC++2010、VC++2012 の実行ファイルを使えるように環境変数を設定する必要があります。プリプロセッサのための環境変数の設定方法は2種類あります。一つは、静的に環境変数を設定する方法([コントロールパネル]-[システム]-[環境]にて設定)。もう一つは、VC++2005、VC++2008、VC++2010、VC++2012 をインストールしたディレクトリ配下にあるvcvarsall.batを実行する方法です。いずれかの方法で環境変数の設定を行ってください。
IDLファイルの作成とコンパイル(C++)
アプリケーション作成の方法には以下の方法があります。
ファクトリの使用については [サーバオブジェクトとファクトリオブジェクト] をご覧ください。
R5形式(ファクトリを使用しない場合)
IDLファイルとはインタフェース定義言語ファイルの略で、このファイルにサーバオブジェクトが提供するインタフェースやオペレーションなどを記述します。IDLファイルの記述例を以下に示します。行頭の数字は説明の為に付加した行番号です。実際の記述では必要ありません。
1:  module sample
2:  {
3:       interface LoopBackSample : WO_Base 
4:                        // (サンプルではWO_Baseからの派生はありません)
5:       {
6:            long LoopBack(in string inputChar, out string outputChar);
7:            long LowerCase(in string inputChar, out string outputChar);
8:            long UpperCase(in string inputChar, out string outputChar);
9:       };
10: };
一行目のmoduleはモジュールを宣言するときに記述します。interfaceを指定する場合、module定義の指定は必須です。三行目のinterfaceはインタフェースを宣言するときに記述します。続けてインタフェース名を記述します。これがC++のクラス名になります。その後ろの : WO_BaseはWO_Baseインタフェースからの派生を意味しています。WO_BaseはWebOTX専用のインタフェースで、このインタフェースから派生することにより、アプリケーション例外時の呼出し(OnTPSAbort())やクライアント切断時の呼出し(OnTPSDisconnect())が行われます。これらの機能が不要なときは記述しなくても結構です。また、WO_Baseの定義はWebOTXをインストールしたディレクトリ配下にwobase.idlとして定義しています。 六行目以降はオペレーションの宣言です。オペレーションの書式はC++の関数宣言のように記述します。 C++の関数宣言と異なるのは、各引数に入出力属性を付けることです。上記例ではin属性、out属性を指定しています。このほかにもinout属性(入出力属性)があります。また、オペレーション名は256バイト以内で記述してください。 このようにして出来上がったIDLファイルをIDLコンパイラに入力してスタブファイル、スケルトンファイルを作成します。 なお、IDLファイルのファイル名の拡張子は必ず .idl としてください。この例題では、loopback.idlとして説明します。 IDLファイルを作成しましたら、次にIDLコンパイラを実行します。 IDLコンパイラを実行するとスタブファイルとスケルトンファイルを生成します。スタブファイルとは、クライアントアプリケーションがサーバオブジェクトをアクセスするためのアクセスクラス群を定義しているファイルのことです。スケルトンファイルとは、ORBからサーバアプリケーションを呼び出すためのベースとなるクラス群を定義したファイルのことです。 WebOTXでは、スタブファイルおよびスケルトンファイルのほかに以下のコードが必要になります。
実装情報定義クラスとコンポーネント初期化クラスを作成するには、[woixcpp]コマンドを使用するか、後述の記述例を参照し作成してください。 R5形式で使用するIDLコンパイラはObject Broker 提供の i2cc です。オプションは以下の通りです。
i2cc -i -Xdii -lstub <IDLファイル名> 
     ^^ ^^^^^ ^^^^^^       (woigenxx とは異なり、"loopback.idl"のように.idlも必要です)
      |    |     +-----ローカルスタブを使用。非同期VD呼び出しには必須のオプションです。
      |    +-----------フックが使用可能になります。
      |                非同期VD呼び出しには必須のオプションです。
      +----------------ifファイルの生成を行います。
                       WebOTXに登録するために必須のオプションです。
同一インタフェースに複数の実装を持たせる場合は、、インタフェース部分を分離して共有ライブラリを作成する必要があります。この場合は-Eオプションを指定してください。同一インタフェースに複数の実装を持たせない場合は、-Eオプションは指定しないでください。
i2cc -i -Xdii -lstub -E <IDLファイル名> 
     ^^ ^^^^^ ^^^^^^ ^^    (woigenxx とは異なり、"loopback.idl"のように.idlも必要です)
      |    |     |    +--スタブとスケルトンを__declspec(dllexport)可能にします。
      |    |     +-------ローカルスタブを使用。
      |    |             非同期VD呼び出しには必須のオプションです
      |    +-------------フックが使用可能になります。
      |                  非同期VD呼び出しには必須のオプションです
      +------------------ifファイルの生成を行います。
                         WebOTXに登録するために必須のオプションです。
また、WO_Baseを派生している場合は-Rオプションを以下のように指定してください。この場合、事前にwobase.idlをカレントディレクトリにコピーしておく必要があります。 wobase.idlは、WebOTX Developer (for CORBA Application)をインストールしたディレクトリ配下のidlfilesディレクトリにあります。
i2cc -i -Xdii -lstub -Rwobase.idl <IDLファイル名> (woigenxx とは異なり、
     ^^ ^^^^^ ^^^^^^ ^^^^^^^^^^^^                  "loopback.idl"のように.idlも必要です)
      |    |     |       +--wobase.idl を参照します。
      |    |     |          WO_Baseを使用するために必須のオプションです。
      |    |     +----------ローカルスタブを使用。
      |    |                非同期VD呼び出しには必須のオプションです。
      |    +------------フックが使用可能になります。
      |                 非同期VD呼び出しには必須のオプションです。
      +-----------------ifファイルの生成を行います。
                        WebOTXに登録するために必須のオプションです。

このコマンドを実行すると以下のファイルが生成されます。
次に [サーバント(実装部分)]を作成します。
R5形式(ファクトリを使用する場合)
IDLファイルとはインタフェース定義言語ファイルの略で、このファイルにサーバオブジェクトが提供するインタフェースやオペレーションなどを記述します。IDLファイルの記述例を以下に示します。行頭の数字は説明の為に付加した行番号です。実際の記述では必要ありません。
1:  module sample
2:  {
3:      interface LoopBackSample : WO_Base 
4:                         //(サンプルではWO_Baseからの派生はありません)
5:      {
6:          long LoopBack(in string inputChar, out string outputChar);
7:          long LowerCase(in string inputChar, out string outputChar);
8:          long UpperCase(in string inputChar, out string outputChar);
9:      };
10
11:     interface WO_Factory_LoopBackSample : WO_BaseFactory 
12:                        // (サンプルではWO_BaseFactoryからの派生はありません)
13:     {
14:         LoopBackSample CreateServerObject();
15:         void ReleaseServerObject(in LoopBackSample obj);
16:     };
17: };
 
一行目のmoduleはモジュールを宣言するときに記述します。interfaceを指定する場合、module定義の指定は必須です。三行目のinterfaceはインタフェースを宣言するときに記述します。続けてインタフェース名を記述します。これがC++のクラス名になります。その後ろの : WO_BaseはWO_Baseインタフェースからの派生を意味しています。WO_BaseはWebOTX専用のインタフェースで、このインタフェースから派生することにより、アプリケーション例外時の呼出し(OnTPSAbort())やクライアント切断時の呼出し(OnTPSDisconnect())が行われます。これらの機能が不要なときは記述しなくても結構です。また、WO_Baseの定義はWebOTXをインストールしたディレクトリ配下にwobase.idlとして定義しています。 六行目から八行目はオペレーションの宣言です。オペレーションの書式はC++の関数宣言のように記述します。 C++の関数宣言と異なるのは、各引数に入出力属性を付けることです。上記例ではin属性、out属性を指定しています。このほかにもinout属性(入出力属性)があります。また、オペレーション名は256バイト以内で記述してください。 十一行目以降はファクトリのインターフェースの宣言です。書式は通常のインターフェースと同様です。インターフェース名は任意の名前で定義できます。オブジェクトを生成するためのオペレーション(この例ではCreateServerObject())とオブジェクトを解放するためのオペレーション(この例ではReleaseServerObject())を宣言してください。また、クライアント管理ライブラリを使用する場合はWO_BaseFactoryインターフェースの派生にしてください。WO_BaseFactoryはWO_Baseと同様にwobase.idlに定義されています。 このようにして出来上がったIDLファイルをIDLコンパイラに入力してスタブファイル、スケルトンファイルを作成します。 なお、IDLファイルのファイル名の拡張子は必ず .idl としてください。この例題では、loopback.idlとして説明します。 IDLファイルを作成しましたら、次にIDLコンパイラを実行します。 IDLコンパイラを実行するとスタブファイルとスケルトンファイルを生成します。スタブファイルとは、クライアントアプリケーションがサーバオブジェクトをアクセスするためのアクセスクラス群を定義しているファイルのことです。スケルトンファイルとは、ORBからサーバアプリケーションを呼び出すためのベースとなるクラス群を定義したファイルのことです。 WebOTXでは、スタブファイルおよびスケルトンファイルのほかに以下のコードが必要になります。
実装情報定義クラスとコンポーネント初期化クラスを作成するには、[woixcpp]コマンドを使用するか、後述の記述例を参照し作成してください。 R5形式で使用するIDLコンパイラはObject Broker 提供の i2cc です。オプションは以下の通りです。
  i2cc -i -Xdii -lstub <IDLファイル名> 
       ^^ ^^^^^ ^^^^^^       (woigenxx とは異なり、"loopback.idl"のように.idlも必要です)
        |    |     +-----ローカルスタブを使用。
        |    |           非同期VD呼び出しには必須のオプションです
        |    +-----------フックが使用可能になります。
        |                非同期VD呼び出しには必須のオプションです
        +----------------ifファイルの生成を行います。
                         WebOTXに登録するために必須のオプションです。

同一インタフェースに複数の実装を持たせる場合は、インタフェース部分を分離して共有ライブラリを作成する必要があります。この場合は-Eオプションを指定してください。同一インタフェースに複数の実装を持たせない場合は、-Eオプションは指定しないでください。
  i2cc -i -Xdii -lstub -E <IDLファイル名> 
       ^^ ^^^^^ ^^^^^^ ^^    (woigenxx とは異なり、"loopback.idl"のように.idlも必要です)
        |    |     |    +--スタブとスケルトンを__declspec(dllexport)可能にします。
        |    |     +-------ローカルスタブを使用。
        |    |             非同期VD呼び出しには必須のオプションです。
        |    +-------------フックが使用可能になります。
        |                  非同期VD呼び出しには必須のオプションです。
        +------------------ifファイルの生成を行います。
                           WebOTXに登録するために必須のオプションです。
また、WO_Base,WO_BaseFactoryを派生している場合は-Rオプションを以下のように指定してください。この場合、事前にwobase.idlをカレントディレクトリにコピーしておく必要があります。 wobase.idlは、WebOTX Developer (for CORBA Application)をインストールしたディレクトリ配下のidlfilesディレクトリにあります。
  i2cc -i -Xdii -lstub -Rwobase.idl <IDLファイル名> (woigenxx とは異なり、
       ^^ ^^^^^ ^^^^^^ ^^^^^^^^^^^^                  "loopback.idl"のように.idlも必要です)
        |    |     |       +---wobase.idl を参照します。
        |    |                 WO_Baseを使用するために必須のオプションです。
        |    |     +-----------ローカルスタブを使用。
        |    |                 非同期VD呼び出しには必須のオプションです。
        |    +-----------------フックが使用可能になります。
        |                      非同期VD呼び出しには必須のオプションです。
        +----------------------ifファイルの生成を行います。
                               WebOTXに登録するために必須のオプションです。
このコマンドを実行すると以下のファイルが生成されます。
次に [サーバント(実装部分)] を作成します。
サーバント(実装部分)のコーディング(C++)
アプリケーション作成の方法には以下の方法があります。
ファクトリの使用については [サーバオブジェクトとファクトリオブジェクト] をご覧ください。

R5形式

R5形式におけるUNIXのMakefileについて

IDLコンパイラが生成したファイルを使用して、サーバアプリケーションの共有ライブラリを作成します。 必要なファイルは、以下のほかに利用者が作成した実装コードとヘッダファイル(サンプルではloopback_i.hとloopback_i.C)です。

コンパイル時のオプション

リンク時のオプション

以下にMakeファイルの記述例を示します。同じディレクトリに loopback_i.C, loopback_i.hを作成し、make idl ; make を実行してください。 同一インタフェースに複数の実装を持たせる場合は、インタフェースコンポーネントファイルとサーバコンポーネントファイルを別々のライブラリにする必要があります。この場合、サーバコンポーネントは明示的にインタフェースコンポーネントをリンクしてください。また、インタフェースコンポーネントファイルをビルドするにはコンパイル時のオプションに以下の指定が必要です。
     -DOB_<IDLファイル名の大文字>CMN_EXPORT -DOB_<IDLファイル名の大文字>IMP_EXPORT
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           |                 +-------スケルトンをdllexportする
                           +-------------------------スタブをdllexportする
#-----------------------------------------------------------------------
#  for HP-UX(Itanium 2)
#-----------------------------------------------------------------------

CC      = /opt/aCC/bin/aCC
I2CC    = /opt/ObjectSpinner/bin/i2cc
IDLFLAGS= -i -Xdii -lstub -Rwobase.idl
BASENAME= loopback
LIBS    =
OBJS    = ${BASENAME}cmn.o \
          ${BASENAME}imp.o \
          ${BASENAME}_i.o
INC     = -I/opt/WebOTX/dev/include \
          -I/opt/ObjectSpinner/namespace/include
LDFLAGS = -b -mt -Wl,-E +DD64
C++FLAGS= +Z -mt -DOB_HPUX_KT +DD64
TARGET  = ${BASENAME}.so
all : ${OBJS} ${TARGET}
${TARGET} : ${OBJS}
       ${CC} -o $@ ${C++FLAGS} ${LDFLAGS} ${OBJS} ${LIBS}
${BASENAME}cmn.o :      ${BASENAME}cmn.C ${BASENAME}.h
${BASENAME}imp.o :      ${BASENAME}imp.C ${BASENAME}.h
${BASENAME}_i.o :       ${BASENAME}_i.C ${BASENAME}.h ${BASENAME}_i.h

.C.o :
       ${CC} ${INC} ${C++FLAGS} -c $*.C
idl:
       ${I2CC} ${IDLFLAGS} ${BASENAME}.idl
clean:
       /bin/rm -rf *.o ${TARGET}
#-----------------------------------------------------------------------
#  for Linux
#-----------------------------------------------------------------------

CC      = /usr/bin/g++
I2CC    = /opt/ObjectSpinner/bin/i2cc
IDLFLAGS= -i -Xdii -lstub -Rwobase.idl
BASENAME= loopback
LIBS    =
OBJS    = ${BASENAME}cmn.o \
          ${BASENAME}imp.o \
          ${BASENAME}_i.o
INC     = -I/opt/WebOTX/dev/include \
          -I/opt/ObjectSpinner/namespace/include
LDFLAGS = -shared
C++FLAGS= -D_REENTRANT -D_GNU_SOURCE -fPIC
TARGET  = ${BASENAME}.so
all : ${OBJS} ${TARGET}
${TARGET} : ${OBJS}
       ${CC} -o $@ ${C++FLAGS} ${LDFLAGS} ${OBJS} ${LIBS}
${BASENAME}cmn.o :      ${BASENAME}cmn.C ${BASENAME}.h
${BASENAME}imp.o :      ${BASENAME}imp.C ${BASENAME}.h
${BASENAME}_i.o :       ${BASENAME}_i.C ${BASENAME}_i.h

.C.o :
       ${CC} ${INC} ${C++FLAGS} -c $*.C
idl:
       ${I2CC} ${IDLFLAGS} ${BASENAME}.idl
clean:
       /bin/rm -rf *.o ${TARGET}
#-----------------------------------------------------------------------
#  for SUN Solaris 10
#-----------------------------------------------------------------------

CC      = /opt/SUNWspro/bin/CC
I2CC    = /opt/ObjectSpinner/bin/i2cc
IDLFLAGS= -i -Xdii -lstub -Rwobase.idl
BASENAME= loopback
LIBS    =
OBJS    = ${BASENAME}cmn.o \
          ${BASENAME}imp.o \
          ${BASENAME}_i.o
INC     = -I/opt/WebOTX/dev/include \
          -I/opt/ObjectSpinner/namespace/include
LDFLAGS = -G -mt -m64
C++FLAGS= -D_REENTRANT -mt -m64 -xcode=pic32
TARGET  = ${BASENAME}.so
all : ${OBJS} ${TARGET}
${TARGET} : ${OBJS}
       ${CC} -o $@ ${C++FLAGS} ${LDFLAGS} ${OBJS} ${LIBS}
${BASENAME}cmn.o :      ${BASENAME}cmn.C ${BASENAME}.h
${BASENAME}imp.o :      ${BASENAME}imp.C ${BASENAME}.h
${BASENAME}_i.o :       ${BASENAME}_i.C ${BASENAME}_i.h

.C.o :
       ${CC} ${INC} ${C++FLAGS} -c $*.C
idl:
       ${I2CC} ${IDLFLAGS} ${BASENAME}.idl
clean:
       /bin/rm -rf *.o ${TARGET}
R5形式 Windows(Intel x86)のプロジェクト設定について
IDLコンパイラが生成したファイルを使用して、サーバアプリケーション作成します。まず、VC++を起動して、新規プロジェクトを作成します。作成するプロジェクトのタイプはWin32プロジェクト(アプリケーションの設定にて、DLLを選択)です。次に、上記例にて作成したファイルをプロジェクトに追加します。必要なファイルは、以下のほかに利用者が作成した実装コードとヘッダファイル(サンプルではloopback_i.hとloopback_i.cpp)です。
同一インタフェースに複数の実装を持たせる場合は、インタフェースコンポーネントファイルとサーバコンポーネントファイルを別々にコンパイルしてDLLにする必要があります。この場合、サーバコンポーネントは明示的にインタフェースコンポーネントをリンクしてください。また、インタフェースコンポーネントファイルをビルドする時には、プロジェクトの設定にて[C/C++]-「プリプロセッサ」を選択し、「プリプロセッサの定義」に以下の記述を追加してください。
     OB_<IDLファイル名の大文字>CMN_EXPORT,OB_<IDLファイル名の大文字>IMP_EXPORT
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           |                        +-------スケルトンをdllexportする
                           +--------------------------------スタブをdllexportする
次に、プロジェクトの設定にて、[C/C++]-「コード生成」を選択してください。ここで、使用するランタイムライブラリを「マルチスレッド DLL」(デバッグなら「マルチスレッド デバッグ DLL)」)を指定してください。 この指定を忘れるとプログラムは正常に動作しません。 次に、ライブラリの追加を行います。同じくプロジェクトの設定にて、[リンク]-「入力」を選択してください。ここの「追加の依存ファイル」に以下のライブラリを追加してください。
VC++ 2005 を使用して作成する場合 VC++ 2008 を使用して作成する場合 VC++ 2010 を使用して作成する場合 VC++ 2012 を使用して作成する場合
また、サーバシミュレータ使用時は上記ライブラリの代わりに以下のライブラリを追加してください。
VC++ 2005 を使用して作成する場合 VC++ 2008 を使用して作成する場合 VC++ 2010 を使用して作成する場合 VC++ 2012 を使用して作成する場合
次に、インクルードパスとライブラリパスを設定します。以下に示すパスを追加してください。
R5形式 Windows(Intel 64)のMakefile(プロジェクト設定)について
IDLコンパイラが生成したファイルを使用して、サーバアプリケーション作成します。必要なファイルは、以下のほかに利用者が作成した実装コードとヘッダファイル(サンプルではloopback_i.hとloopback_i.cpp)です。
コンパイル時のオプション リンク時のオプション
以下にMakeファイルの記述例を示します。同じディレクトリに loopback_i.cpp, loopback_i.hを作成してください。そしてVC++ 2005、VC++2008、VC++2010、VC++2012 の実行ファイルを使えるように環境変数を設定してIDLコンパイルを行った後にビルドを実行してください。 同一インタフェースに複数の実装を持たせる場合は、インタフェースコンポーネントファイルとサーバコンポーネントファイルを別々のライブラリにする必要があります。この場合、サーバコンポーネントは明示的にインタフェースコンポーネントをリンクしてください。また、インタフェースコンポーネントファイルをビルドするにはコンパイル時のオプションに以下の指定が必要です。
/D "OB_<IDLファイル名の大文字>CMN_EXPORT" /D "OB_<IDLファイル名の大文字>IMP_EXPORT"
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           |                    +----------------スケルトンをdllexportする
                           +-------------------------------------スタブをdllexportする
#-----------------------------------------------------------------------
#  for Windows(Intel 64)
#-----------------------------------------------------------------------

!include 

OUTDIR=.\Release
INTDIR=.\Release
# Begin Custom Macros
OutDir=.\Release
# End Custom Macros

OTXDIR=C:\Program Files\NEC\WebOTX
OSPIDIR=$(OTXDIR)\ObjectBroker

ALL : "$(OUTDIR)\$(BASENAME).dll"

"$(OUTDIR)" :
    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"

CPP=cl.exe
CPP_PROJ=/nologo /MD /W3 /EHsc /O2 \
    /I "$(OSPIDIR)\namespace\include" \
    /I "$(OTXDIR)\dev\include" \
    /D "WIN32" /D "WIN64" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" \
    /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /c 

.c{$(INTDIR)}.obj::
   $(CPP) @<<

   $(CPP_PROJ) $< 
<<

.cpp{$(INTDIR)}.obj::
   $(CPP) @<<
   $(CPP_PROJ) $< 
<<

.cxx{$(INTDIR)}.obj::
   $(CPP) @<<
   $(CPP_PROJ) $< 

<<

LINK=link.exe
LINK_FLAGS=nosp9011.lib nOrbW971.lib nWOBS97.lib \
    /nologo /dll /incremental:no /pdb:"$(OUTDIR)\$(BASENAME).pdb" \
    /machine:AMD64 /out:"$(OUTDIR)\$(BASENAME).dll" \
    /implib:"$(OUTDIR)\$(BASENAME).lib" \
    /libpath:"$(OSPIDIR)\namespace\lib" \
    /libpath:"$(OTXDIR)\dev\lib" 

LINK_OBJS= \
    "$(INTDIR)\$(BASENAME)_i.obj" \
    "$(INTDIR)\$(BASENAME)cmn.obj" \
    "$(INTDIR)\$(BASENAME)imp.obj"

"$(OUTDIR)\$(BASENAME).dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK_OBJS)
    $(LINK) @<<

  $(LINK_FLAGS) $(LINK_OBJS)
<<

SOURCE=.\$(BASENAME)_i.cpp
"$(INTDIR)\$(BASENAME)_i.obj" : $(SOURCE) "$(INTDIR)"

SOURCE=.\$(BASENAME)cmn.cpp
"$(INTDIR)\$(BASENAME)cmn.obj" : $(SOURCE) "$(INTDIR)"

SOURCE=.\$(BASENAME)imp.cpp
"$(INTDIR)\$(BASENAME)imp.obj" : $(SOURCE) "$(INTDIR)"
R5形式 コーディング(ファクトリを使用しない場合)
これでサーバアプリケーションを作成するための準備が出来ました。次に実装部分をコーディングします。 R5形式では実装するクラス名やヘッダファイルに制限はありません。その代わり実装情報の定義が必要になります。具体的にはサンプルのreadme.txtをご覧ください。 実装情報の定義にはwoixcppコマンドを使用することもできますwoixcppコマンドのインタフェースは以下のようになります。
woixcpp <ifファイル名>  [-options] (拡張子ifは不要)
使用例: woixcpp loopback
オプションの指定方法については、[コマンドリファレンス]を参照してください。 このサンプルアプリケーションの場合は、loopback_i.hファイルと、loopback_i.C(Windowsの場合は.cpp)の二つのファイルを作成します。以下に、loopback_i.hの記述例を示します。
// loopback_i.h //
// loopback_i.h //
#ifndef LOOPBACK_I_H
#define LOOPBACK_I_H
#include "loopback.h"

namespace sample
{
// 実装クラスの定義
class LoopBackSample_i : public virtual POA_sample::LoopBackSample
{
public:
    // constructor
    LoopBackSample_i();
    // destructor
    virtual ~LoopBackSample_i();
public:
    CORBA::Long LoopBack(
     const char* inputChar,
char*& outputChar,
           CORBA::Environment& _env = Ob_default_environment());
    CORBA::Long LowerCase(
           const char* inputChar,
char*& outputChar,
           CORBA::Environment& _env = Ob_default_environment());
    CORBA::Long UpperCase(
           const char* inputChar,
char*& outputChar,
           CORBA::Environment& _env = Ob_default_environment());
    void OnTPSAbort(
           CORBA::Long status,
CORBA::Environment& _env = Ob_default_environment());
    void OnTPSDisconnect(
           CORBA::Environment& _env = Ob_default_environment());
    void OnTPSMessageNotified(
           const char* mes,
           CORBA::Environment& _env = Ob_default_environment());
};
};
//////////////////////////////////////////////////////
// 実装情報の定義
class loopbackCallback_i : public virtual WebOTX::WOServantCallback
{
public:
       loopbackCallback_i() {}
       const char* _name();
       const char* _id();
       PortableServer::Servant _newInstance();
       void _deleteInstance(PortableServer::Servant servant);
};
#endif
実装クラス定義は自分で記述することも出来ますが、IDLコンパイラが生成したloopback.hのPOA_sample::LoopBackSampleクラスの定義からコピーするのが簡単です。ただし、OnTPSAbort()とOnTPSDisconnect()の宣言はloopback.hにはありませんので、上記のようにタイプしてください。 次に、実装部分のコーディングです。
//loopback_i.C
#include "orb.h"
#include "wotxexps.h"
#include "loopback.h"
#include "loopback_i.h"
#include <string.h>
#include <ctype.h>

// constructor
sample::LoopBackSample_i::LoopBackSample_i()
{
}
// destructor
sample::LoopBackSample_i::~LoopBackSample_i()
{
}
CORBA::Long sample::LoopBackSample_i::LoopBack(
           const char* inputChar,
           char*& outputChar,
           CORBA::Environment& _env)
{
    outputChar = CORBA::string_dup(inputChar);
    return strlen(outputChar);
}
CORBA::Long sample::LoopBackSample_i::LowerCase(
           const char* inputChar,
           char*& outputChar,
           CORBA::Environment& _env)
{
    int len = strlen(inputChar);
    char* tmpstring = new char[len+1];
    for (int i = 0; i < len && inputChar[i] != '\n'; i++)
        tmpstring[i] = tolower((char)inputChar[i]);
    tmpstring[len] = '\0';
    outputChar = CORBA::string_dup((const char*)tmpstring);
    delete[] tmpstring;
    return len;
}
CORBA::Long sample::LoopBackSample_i::UpperCase(
           const char* inputChar,
           char*& outputChar,
           CORBA::Environment& _env)
{
    int len = strlen(inputChar);
    char* tmpstring = new char[len+1];
    for (int i = 0; i < len && inputChar[i] != '\n'; i++)
        tmpstring[i] = toupper((char)inputChar[i]);
    tmpstring[len] = '\0';
    outputChar = CORBA::string_dup((const char*)tmpstring);
    delete[] tmpstring;
    return len;
}
void sample::LoopBackSample_i::OnTPSAbort(
           CORBA::Long status,
           CORBA::Environment& _env)
{
    char buf[256];
    sprintf(buf, "Called OnTPSAbort.");
    TPSUserTrace(LOG_ERR, buf);
    // Abort時の処理を記述
}
void sample::LoopBackSample_i::OnTPSDisconnect(
           CORBA::Environment& _env)
{
    char buf[256];
    sprintf(buf, "Called OnTPSDisconnect");
    TPSUserTrace(LOG_ERR, buf);
    // クライアント切断時の処理を記述
}
void sample::LoopBackSample_i::OnTPSMessageNotified(
    const char* mes,
    CORBA::Environment& _env)
{
    // フェールオーバ時の処理を記述
}
//////////////////////////////////////////////////////
// コンポーネント初期化関数
#ifdef              _WINDOWS
#define            LOOPBACKEXPORT  __declspec(dllexport)
#else
#define            LOOPBACKEXPORT
#endif
extern "C" LOOPBACKEXPORT void loopbackinit();
//                             ^^^^^^^^^^^^これがコンポーネント初期化関数になります
extern "C" LOOPBACKEXPORT void loopbackinit()
{
//      実装情報を登録します
        WebOTX::WOComponent::add(new loopbackCallback_i);
}
//////////////////////////////////////////////////////
// 実装情報の設定部分
const char* loopbackCallback_i::_name()
{
       return (const char*)"loopback";
}
const char* loopbackCallback_i::_id()
{
       return (const char*)"IDL:sample/LoopBackSample:1.0";
}
PortableServer::Servant loopbackCallback_i::_newInstance()
{
    sample::LoopBackSample_i* iobj = new sample::LoopBackSample_i;
    return iobj;
}
void loopbackCallback_i::_deleteInstance(PortableServer::Servant servant)
{
       delete servant;
}
コーディングそのものは通常のC++のコーディングと何ら変わりません。 WebOTXにはサーバアプリケーションの開発に役立つサーバAPIを用意しています(上記例ではTPSUserTrace()を使用しています)。サーバAPIの使い方については [ リファレンス集 開発編(共通) > 4. CORBA > 4.5. WebOTX CORBA アプリケーション(C++) > 4.5.1. サーバAPI ] を参照してください。 これで、サーバアプリケーションは完成しました。これをコンパイルしてライブラリを作成してください。
補足
コンパイル中...
U:\TestAPcl\loopbackcmn.cpp(980) : fatal error C1010: 
プリコンパイル済みヘッダーの検索中に予期しない EOF を検出しました。
R5形式 コーディング(ファクトリを使用する場合)
これでサーバアプリケーションを作成するための準備が出来ました。次に実装部分をコーディングします。 R5形式では実装するクラス名やヘッダファイルに制限はありません。その代わり実装情報の定義が必要になります。具体的にはサンプルのreadme.txtをご覧ください。 実装情報の定義にはwoixcppコマンドを使用することもできますwoixcppコマンドのインタフェースは以下のようになります。
woixcpp <ifファイル名>  [-options] (拡張子ifは不要)
使用例: woixcpp loopback
オプションの指定方法については、[コマンドリファレンス]を参照してください。 このサンプルアプリケーションの場合は、loopback_i.hファイルと、loopback_i.C(Windowsの場合は.cpp)の二つのファイルを作成します。以下に、loopback_i.hの記述例を示します。
// loopback_i.h //
#ifndef LOOPBACK_I_H
#define LOOPBACK_I_H
#include "loopback.h"

namespace sample
{
// 実装クラスの定義
class LoopBackSample_i : public virtual POA_sample::LoopBackSample
{
public:
    // constructor
    LoopBackSample_i();
    // destructor
    virtual ~LoopBackSample_i();
public:
    CORBA::Long LoopBack(
              const char* inputChar,
char*& outputChar,
              CORBA::Environment& _env = Ob_default_environment());
    CORBA::Long LowerCase(
              const char* inputChar,
char*& outputChar,
              CORBA::Environment& _env = Ob_default_environment());
    CORBA::Long UpperCase(
              const char* inputChar,
char*& outputChar,
              CORBA::Environment& _env = Ob_default_environment());
    void OnTPSAbort(
              CORBA::Long status,
CORBA::Environment& _env = Ob_default_environment());
    void OnTPSDisconnect(
              CORBA::Environment& _env = Ob_default_environment());
    void OnTPSMessageNotified(
              const char* mes,
              CORBA::Environment& _env = Ob_default_environment());
};
class WO_Factory_LoopBackSample_i : public virtual POA_sample
                                  ::WO_Factory_LoopBackSample
{
public:
    // constructor
    WO_Factory_LoopBackSample_i();
    // destructor
    virtual ~WO_Factory_LoopBackSample_i();
public:
    LoopBackSample_ptr CreateServerObject(
              CORBA::Environment& _env = Ob_default_environment());
    void ReleaseServerObject(
              LoopBackSample_ptr obj,
              CORBA::Environment& _env = Ob_default_environment());
};
};
//////////////////////////////////////////////////////
// 実装情報の定義
class loopbackCallback_i : public virtual WebOTX::WOServantCallback
{
public:
    loopbackCallback_i() {}
    const char* _name();
    const char* _id();
    PortableServer::Servant _newInstance();
    void _deleteInstance(PortableServer::Servant servant);
};
class WO_Factory_loopbackCallback_i : public virtual WebOTX::WOServantCallback
{
public:
    WO_Factory_loopbackCallback_i() {}
    const char* _name();
    const char* _id();
    PortableServer::Servant _newInstance();
    void _deleteInstance(PortableServer::Servant servant);
};
#endif
実装クラスの定義は自分で記述することも出来ますが、IDLコンパイラが生成したloopback.hの POA_sample::LoopBackSampleクラスの定義からコピーするのが簡単です。ただし、OnTPSAbort()とOnTPSDisconnect()の宣言はloopback.hにはありませんので、上記のようにタイプしてください。 次に、実装部分のコーディングです。
//loopback_i.C
//loopback_i.C
#include "orb.h"
#include "wotxexps.h"
#include "loopback.h"
#include "loopback_i.h"
#include <string.h>
#include <ctype.h>

// constructor
sample::LoopBackSample_i::LoopBackSample_i()
{
}
// destructor
sample::LoopBackSample_i::~LoopBackSample_i()
{
}
CORBA::Long sample::LoopBackSample_i::LoopBack(
           const char* inputChar,
           char*& outputChar,
           CORBA::Environment& _env)
{
    outputChar = CORBA::string_dup(inputChar);
    return strlen(outputChar);
}
CORBA::Long sample::LoopBackSample_i::LowerCase(
           const char* inputChar,
           char*& outputChar,
           CORBA::Environment& _env)
{
    int len = strlen(inputChar);
    char* tmpstring = new char[len+1];
    for (int i = 0; i < len && inputChar[i] != '\n'; i++)
        tmpstring[i] = tolower((char)inputChar[i]);
    tmpstring[len] = '\0';
    outputChar = CORBA::string_dup((const char*)tmpstring);
    delete[] tmpstring;
    return len;
}
CORBA::Long sample::LoopBackSample_i::UpperCase(
           const char* inputChar,
           char*& outputChar,
           CORBA::Environment& _env)
{
    int len = strlen(inputChar);
    char* tmpstring = new char[len+1];
    for (int i = 0; i < len && inputChar[i] != '\n'; i++)
        tmpstring[i] = toupper((char)inputChar[i]);
    tmpstring[len] = '\0';
    outputChar = CORBA::string_dup((const char*)tmpstring);
    delete[] tmpstring;
    return len;
}
void sample::LoopBackSample_i::OnTPSAbort(
           CORBA::Long status,
           CORBA::Environment& _env)
{
    char buf[256];
    sprintf(buf, "Called OnTPSAbort.");
    TPSUserTrace(LOG_ERR, buf);
    // Abort時の処理を記述
}
void sample::LoopBackSample_i::OnTPSDisconnect(
           CORBA::Environment& _env)
{
    char buf[256];
    sprintf(buf, "Called OnTPSDisconnect");
    TPSUserTrace(LOG_ERR, buf);
    // クライアント切断時の処理を記述
}
void sample::LoopBackSample_i::OnTPSMessageNotified(
    const char* mes,
    CORBA::Environment& _env)
{
    // フェールオーバ時の処理を記述
}
//////////////////////////////////////////////////////
// constructor
sample::WO_Factory_LoopBackSample_i::WO_Factory_LoopBackSample_i()
{
}
// destructor
sample::WO_Factory_LoopBackSample_i::~WO_Factory_LoopBackSample_i()
{
}
sample::LoopBackSample_ptr sample::WO_Factory_LoopBackSample_i::CreateServerObject(
           CORBA::Environment& _env)
{
    WebOTX::WOServantCallback* servInfo = new loopbackCallback_i();
    CORBA::Object_ptr obj = WebOTX::WOServantManager::CreateServant(servInfo);
    delete servInfo;
    return LoopBackSample::_narrow(obj);
}
void sample::WO_Factory_LoopBackSample_i::ReleaseServerObject(
           sample::LoopBackSample_ptr obj,
           CORBA::Environment& _env)
{
    WebOTX::WOServantCallback* servInfo = new WO_Factory_loopbackCallback_i();
    WebOTX::WOServantManager::ReleaseServant(servInfo, obj);

    delete servInfo;
}
//////////////////////////////////////////////////////
// コンポーネント初期化関数
#ifdef              _WINDOWS
#define            LOOPBACKEXPORT  __declspec(dllexport)
#else
#define            LOOPBACKEXPORT
#endif
extern "C" LOOPBACKEXPORT void loopbackinit();
//                             ^^^^^^^^^^^^これがコンポーネント初期化関数になります
extern "C" LOOPBACKEXPORT void loopbackinit()
{
    // 実装情報を登録します
    WebOTX::WOComponent::add(new loopbackCallback_i);
    WebOTX::WOComponent::add(new WO_Factory_loopbackCallback_i);
}
//////////////////////////////////////////////////////
// 実装情報の設定部分
const char* loopbackCallback_i::_name()
{
    return (const char*)"loopback";
}
const char* loopbackCallback_i::_id()
{
    return (const char*)"IDL:sample/LoopBackSample:1.0";
}
PortableServer::Servant loopbackCallback_i::_newInstance()
{
    sample::LoopBackSample_i* iobj = new sample::LoopBackSample_i;
    return iobj;
}
void loopbackCallback_i::_deleteInstance(PortableServer::Servant servant)
{
    delete servant;
}
//////////////////////////////////////////////////////
const char* WO_Factory_loopbackCallback_i::_name()
{
    return (const char*)"WO_Factory_loopback";
}
const char* WO_Factory_loopbackCallback_i::_id()
{
    return (const char*)"IDL:sample/WO_Factory_LoopBackSample:1.0";
}
PortableServer::Servant WO_Factory_loopbackCallback_i::_newInstance()
{
    sample::WO_Factory_LoopBackSample_i* iobj = 
                                     new sample::WO_Factory_LoopBackSample_i;
    return iobj;
}
void WO_Factory_loopbackCallback_i::_deleteInstance(PortableServer::Servant servant)
{
    delete servant;
}
コーディングそのものは通常のC++のコーディングと何ら変わりません。 WebOTXにはサーバアプリケーションの開発に役立つサーバAPIを用意しています(上記例ではTPSUserTrace()を使用しています)。サーバAPIの使い方については [ リファレンス集 開発編(共通) > 4. CORBA > 4.5. WebOTX CORBA アプリケーション(C++) > 4.5.1. サーバAPI ] を参照してください。 これで、サーバアプリケーションは完成しました。これをコンパイルしてライブラリを作成してください。
補足
コンパイル中...
U:\TestAPcl\loopbackcmn.cpp(980) : fatal error C1010: 
プリコンパイル済みヘッダーの検索中に予期しない EOF を検出しました。
複雑なIDLの場合のコーディング例(C++)
利用するシステムが複雑で大規模になるとIDLも大きくなり複雑な定義になります。ここでは、複雑なIDLを定義した時のコーディング例を記述します。詳しい説明はObject Broker C++のマニュアルを参照してください。 (a). moduleがネストしている場合
IDL: test1.idl
module AAAA {
   module BBBB {
     module CCCC {
       interface DDDD {
         void op1();
       };
     };
   };
};
C++: test1_i.h
namespace AAAA {
  namespace BBBB {
    namespace CCCC {
      class DDDD_i : public virtual POA_AAAA::BBBB::CCCC::DDDD {
public:
          DDDD_i();
          virtual ~DDDD_i();
          void op1(CORBA::Environment& _env = Ob_default_environment());
      };
    };
  };
};

C++: test1_i.C(test1_i.cpp)

AAAA::BBBB::CCCC::DDDD_i::DDDD_i()
{
   :
}

AAAA::BBBB::CCCC::DDDD_i::~DDDD_i()
{
   :
}

void AAAA::BBBB::CCCC::DDDD_i::op1(CORBA::Environment& _env)
{
   :
}
(b). sequence型とstruct型を利用している場合
IDL: test2.idl
interface AAA {
   struct BBB {
      long   ID;
      string NAME;
      short  AGE;
    };
    typedef sequence < BBB > SEQ001;
    void GET_DATA (in SEQ001 inARG, out SEQ001 outARG, inout SEQ001 inoutARG);
};

C++: test2_i.h
class AAA_i : public virtual POA_AAA {
public:
   AAA_i();
   virtual ~AAA_i();
   void GET_DATA(const AAA::SEQ001& inARG,
                 AAA::SEQ001*& outARG,
                 AAA::SEQ001& inoutARG,
                 CORBA::Environment& _env = Ob_default_environment()
   );
};

C++: test2_i.C(test2_i.cpp)

AAA_i::AAA_i()
{
   :
}

AAA_i::~AAA_i()
{
   :
}

void AAA_i::GET_DATA(
     const AAA::SEQ001& inARG,
     AAA::SEQ001*& outARG,
     AAA::SEQ001& inoutARG,
     CORBA::Environment& _env
   )
{
   // inARGは値が設定されています。参照のみ可能です
   CORBA::ULong inARGlen = inARG.length();
   CORBA::ULong i;
   for(i=0; i < inARGlen; i++) {
      CORBA::ULong id = inARG[i].ID;
          :
   }

   // outARGはAAA::SEQ001をnewして値を設定しなければなりません
   CORBA::ULong outARGlen = 5000;
   outARG = new AAA::SEQ001;
   outARG->length(outARGlen);
   for(i=0; i < outARGlen; i++) {
      (*outARG)[i].ID = 10;
          :
   }

   // inoutARGは値が設定されている。また書き換えもできます
   CORBA::ULong inoutARGlen = inoutARG.length();
   for(i=0; i < outARGlen; i++) {
      inoutARG[i].ID = 10;
          :
   }
      :
}

サーバシミュレータによる動作確認(C++)
作成したサーバアプリケーションやクライアントアプリケーションをテストするには、二つの方法があります。一つは運用管理ツールとWebAP管理ツールを使ってWebOTXに登録して評価する方法で、もう一つはサーバシミュレータを使って行う方法です。ここでは、サーバシミュレータを使ってデバッグする方法を述べます。
サーバシミュレータはWebOTXの機能の一部を提供しています。以下に通常のWebOTXと異なる点を示します。
サーバアプリケーションの準備が出来ましたら、まずObject Brokerを起動してください。起動の方法はObject Brokerのマニュアルを参照してください。 次にUNIXではシェル、WindowsではMS-DOSコマンドプロンプトで以下のコマンドを入力して、サーバシミュレータを起動してください。
nsvsimc コンポーネントファイル名 コンポーネント初期化関数名
例えば、loopback.idlの場合は、
HP-UX(Itanium 2),  Linux,  SUN Solaris 10: 
nsvsimc loopback.so loopbackinit -b \
        loopback=corbaname://127.0.0.1#NEC/WebOTX/WO_Default/sample/LoopBackSample/1

Windows:
nsvsimc loopback.dll loopbackinit -b \
        loopback=corbaname://127.0.0.1#NEC/WebOTX/WO_Default/sample/LoopBackSample/1
となります。サーバシミュレータを起動して、サーバの初期化が完了すると画面に"OK."と表示します。この表示を確認後にクライアントアプリケーションを実行してください。このとき、サーバホストとクライアントホストは同一ホストでも実行できますし、違うホスト同士でも出来ます。別々のホストにするときに注意する点は、両方とも同じ名前サーバを参照しているか確認してください。 アプリケーションの評価が終わりましたら、サーバアプリケーションを停止してください。停止の方法は[Ctrl]+Cです。 常駐オブジェクトを使用する場合は以下のように指定してください。(常駐オブジェクトに関しては常駐オブジェクトの使い方を参照してください)
nsvsimc コンポーネントファイル名 コンポーネント初期化関数名 \
        -p 常駐オブジェクト共有ライブラリファイル名(or DLL名)
例えば、loopback.idlで、常駐オブジェクトとして libprecreated.sl(Windowsの場合はprecreated.dll,Linuxの場合はlibprecreated.so) を使用する場合
HP-UX(Itanium 2), Linux,  SUN Solaris 10: 
nsvsimc loopback.so loopbackinit -p libprecreated.so \
        -b loopback=corbaname://127.0.0.1#NEC/WebOTX/WO_Default/sample/LoopBackSample/1

Windows:
nsvsimc loopback.dll loopbackinit -p precreated.dll \
        -b loopback=corbaname://127.0.0.1#NEC/WebOTX/WO_Default/sample/LoopBackSample/1
となります。 その他にも以下のオプションがあります。
-t 秒: サーバ処理時間の指定(単位は秒)
処理に時間のかかるアプリケーションの場合、サーバ処理時間をオーバしCORBA::NO_RESPONSE例外が発生することがあります(既定値は30秒)。 このオプションでサーバの処理時間の最大値を設定することができます。 0で無制限になります。最大値は2147483647秒(2^31-1)です。 クライアントアプリケーション側にもタイムアウトの設定がありますがそれとは異なります。 クライアント側のタイムアウトの設定は使用する言語に合わせて設定してください。
実行環境への登録(C++)
作成したサーバアプリケーションをWebOTX上の分散環境で利用できるように設定します。運用管理ツールのインストール方法や利用方法の詳細については、リリースメモや「ドメイン構築・基本設定ガイド」を参照してください。 まず、運用管理ツールを起動します。サーバアプリケーションのdll(sl,so)は運用マシンで運用管理ツールに読み込ませることにより、運用管理ツールが自動的にサーバ実行機へ転送して環境を構築します。ただし、アプリケーションを実行するための環境はサーバ実行機にあらかじめ作成しておく必要があります。たとえば、VC++.NETでサーバアプリケーションを作成した場合は、 VC++.NETのランタイムライブラリなどの関連ファイルをサーバ実行機にインストールしておく必要があります。以下の手順にしたがって、サンプルプログラムを運用管理ツールで登録してください。
R5形式(インタフェースと実装を分ける場合):
  1. 運用管理ツールを起動します。
  2. 「インタフェースコンポーネントファイル」を「共有コンポーネント」として配備します。
    .spkファイルを作成して登録する事も出来ます。作成例は以下の通りです。
    /opt/WebOTX/bin/makecpk loopback.spk module=loopback.so if=loopback.if
    
  3. アプリケーショングループとプロセスグループを新規に作成してください。 ここでは、sampleとsamplesvとします。プロセスグループを追加するとき、言語は登録するアプリケーションをコンパイルした言語を選択してください。
  4. サーバコンポーネントを「CORBAコンポーネント」として配備します。
    「共有コンポーネントのifを利用するかどうか」にはチェックをして、共有コンポーネントとして登録しているifファイル名を入力します。
    「コンポーネント初期化関数」には、コンポーネント初期化関数名(この例ではloopbackinit)を入力します。
    .cpkファイルを作成して登録する事も出来ます。作成例は以下の通りです。
    /opt/WebOTX/bin/makecpk loopback.cpk module=loopback.so if=loopback.if \
                            initfunc=loopbackinit useshareif=true
    
  5. コンポーネントの設定の共有コンポーネントのタブを開いて、インタフェースコンポーネントファイルを選択します。
  6. アプリケーショングループの起動を選んで、アプリケーショングループを起動します。
    アプリケーショングループが起動されると、アイコンの色が赤から緑に変わります。
R5形式(インタフェースと実装をまとめる場合):
  1. 運用管理ツールを起動します。
  2. アプリケーショングループとプロセスグループを新規に作成してください。 ここでは、sampleとsamplesvとします。プロセスグループを追加するとき、言語は登録するアプリケーションをコンパイルした言語を選択してください。
  3. コンポーネントを「CORBAコンポーネント」として配備します。
    「コンポーネント初期化関数」には、コンポーネント初期化関数名(この例ではloopbackinit)を入力します。
    .cpkファイルを作成して登録する事も出来ます。作成例は以下の通りです。
    /opt/WebOTX/bin/makecpk loopback.cpk module=loopback.so if=loopback.if \
                            initfunc=loopbackinit useshareif=false
    
    
  4. アプリケーショングループの起動を選んで、アプリケーショングループを起動します。
    アプリケーショングループが起動されると、アイコンの色が赤から緑に変わります。
R4形式:
  1. 運用管理ツールを起動します。
  2. アプリケーショングループとプロセスグループを新規に作成してください。 ここでは、sampleとsamplesvとします。プロセスグループを追加するとき、言語は登録するアプリケーションをコンパイルした言語を選択してください。
  3. コンポーネントを「CORBAコンポーネント」として配備します。
    「コンポーネント初期化関数」には、何も入力しません。
    .cpkファイルを作成して登録する事も出来ます。作成例は以下の通りです。
    /opt/WebOTX/bin/makecpk loopback.cpk module=loopback.so \
                            if=loopback.if useshareif=false
    
  4. アプリケーショングループの起動を選んで、アプリケーショングループを起動します。
    アプリケーショングループが起動されると、アイコンの色が赤から緑に変わります。
WebOTX R4.2まではプロセス起動時にファクトリのIORを名前サーバに登録していましたが、 WebOTX R5.1からは事前登録がデフォルトになっています。詳しくは 高度な管理と運用サイクルガイド をご覧ください。 以上で、サーバアプリケーションの登録が完了しました。
常駐オブジェクトの使い方
単一常駐オブジェクトのコーディング方法
WebOTXは常駐オブジェクト機能を提供します。これは、1つのプロセスグループに1つのオブジェクトを登録し、WebOTX起動時にオブジェクトを事前生成する機能です。 まず常駐オブジェクトの定義方法を示します。
単一常駐オブジェクト生成用関数と解放用関数には以下の形式の関数を定義します。
表1.2.1.5-1
単一常駐オブジェクト生成用関数 extern "C"DLLEXPORT void* OnTPSPrecreatedUsersObject ()
単一常駐オブジェクト解放用関数 extern "C"DLLEXPORT void OnTPSReleasePrecreatedUsersObject (void * preobj)
ここにあるDLLEXPORTは、Windowsのときは __declspec(dllexport) と定義する必要があります。 UNIXは空白にします(下記コーディングを参照)。

単一常駐オブジェクトコーディング例

preobj1.def(Windowsのみ必要)
-------------------------------
EXPORTS
       OnTPSPrecreatedUsersObject
       OnTPSReleasePrecreatedUsersObject
       OnTPSOperationStart
       OnTPSOperationNormal
       OnTPSOperationAbnormal
       OnTPSOperationAbort

preobj1.h
-------------------------------
#ifndef            PREOBJ1_H_
#define            PREOBJ1_H_

#if defined(WIN32)
#if defined(PREOBJ1_EXPORTS)
#ifndef            PREOBJ1_EXPORTDEF
#define PREOBJ1_EXPORTDEF __declspec(dllexport)
#endif
#else // !defined(PREOBJ1_EXPORTS)
#define PREOBJ1_EXPORTDEF __declspec(dllimport)
#endif
#endif
#else              // !WIN32
#define            PREOBJ1_EXPORTDEF
#endif
#endif

class PREOBJ1_EXPORTDEF preobj1 {
       int m_db;
public:
       preobj1();
       ~preobj1();

       void set(int db);
       int get();
};

#endif

preobj1.C(Windowsの場合は.cpp)
-------------------------------
#include 

#include "preobj1.h"
#include "wotxexps.h"

extern "C" PREOBJ1_EXPORTDEF
   void* OnTPSPrecreatedUsersObject();
extern "C" PREOBJ1_EXPORTDEF
   void  OnTPSReleasePrecreatedUsersObject(void* ptr);
extern "C" PREOBJ1_EXPORTDEF
   void  OnTPSOperationStart(void* ptr, 
                             const char* repositoryID, 
                             const char* opname);
extern "C" PREOBJ1_EXPORTDEF
   void  OnTPSOperationNormal(void* ptr, 
                              const char* repositoryID, 
                              const char* opname);
extern "C" PREOBJ1_EXPORTDEF
   void  OnTPSOperationAbnormal(void* ptr, 
                                const char* repositoryID, 
                                const char* opname, int status);
extern "C" PREOBJ1_EXPORTDEF
   void  OnTPSOperationAbort(void* ptr, 
                             const char* repositoryID, 
                             const char* opname, int status);

//==========================================================//
PREOBJ1_EXPORTDEF  preobj1::preobj1()
{
  // 単一常駐オブジェクトのコンストラクタ
  m_db = 0;
}

PREOBJ1_EXPORTDEF  preobj1::~preobj1()
{
  // 単一常駐オブジェクトのデストラクタ
}

PREOBJ1_EXPORTDEF void preobj1::set(int db)
{
  // 単一常駐オブジェクトのメソッド
  m_db = db;
}

PREOBJ1_EXPORTDEF int preobj1::get()
{
  // 単一常駐オブジェクトのメソッド
  return m_db;

//==========================================================//
extern "C" PREOBJ1_EXPORTDEF
    void* OnTPSPrecreatedUsersObject()
{
    // 単一常駐オブジェクトオブジェクトの生成
    return (void*)new preobj1;
}

extern "C" PREOBJ1_EXPORTDEF
    void OnTPSReleasePrecreatedUsersObject(void* ptr)
{
    // 単一常駐オブジェクトオブジェクトの解放
    delete (preobj1*)ptr;
}

extern "C" PREOBJ1_EXPORTDEF
    void OnTPSOperationStart(void* ptr, 
                             const char* repositoryID, 
                             const char* opname)
{
    // オペレーション開始時に特別な処理を行う時に記述
}

extern "C" PREOBJ1_EXPORTDEF
    void OnTPSOperationNormal(void* ptr, 
                              const char* repositoryID, 
                              const char* opname)
{
    // オペレーション正常終了時に特別な処理を行う時に記述
}

extern "C" PREOBJ1_EXPORTDEF
    void OnTPSOperationAbnormal(void* ptr, 
                                const char* repositoryID, 
                                const char* opname, 
                                int status)
{
    // オペレーション異常終了時に特別な処理を行う時に記述
}

extern "C" PREOBJ1_EXPORTDEF
    void OnTPSOperationAbort(void* ptr, 
                             const char* repositoryID, 
                             const char* opname, 
                             int status)
{
    // オペレーションアボート時に特別な処理を行う時に記述
}
//==========================================================//
単一常駐オブジェクトのコールバックについて
常駐オブジェクト用のDLL(SL,SO)に以下の外部関数を定義すると特定の事象が発生したときにコールバックされるようになります。常駐オブジェクトでより細かな制御を行いたいときに組み込んでください。各関数の定義方法はOnTPSPrecreatedUsersObject()やOnTPSReleasePrecreatedUsersObject()と同様に組み込んでください。
表1.2.1.5-2
オペレーションの開始 extern "C"DLLEXPORT void OnTPSOperationStart ( void * preobj, const char* intf, const char* op )
オペレーションの正常終了 extern "C"DLLEXPORT void OnTPSOperationNormal ( void * preobj, const char* intf, const char* op )
オペレーションの異常終了(TPSSetTxStatus()で0以外を設定したとき) extern "C"DLLEXPORT void OnTPSOperationAbnormal ( void *preobj, const char* intf, const char* op, int status )
アボート(AbortExit()が呼ばれたときに、サーバオブジェクトのOnTPSAbort()より前に呼び出す) extern "C"DLLEXPORT void OnTPSOperationAbort ( void *preobj, const char* intf, const char* op, int status )
複数常駐オブジェクトのコーディング方法
常駐オブジェクトをより高度に利用しようとした時、単一常駐オブジェクトでは難しい処理があります。例えば、データベース毎に常駐オブジェクトを作成したい、業務内容毎に常駐オブジェクトを作成したい、というケースです。 もちろん、上記例のケースにおいても単一常駐オブジェクトで実現可能ですが、機能が増えるたびに常駐オブジェクトを利用しているすべてのサーバアプリケーションの再コンパイルが必要になるかもしれません。 ですから、常駐オブジェクトで多数の機能を作成する場合は、ここで説明する複数常駐オブジェクトを利用することで作業効率および保守効率を上がります。 複数常駐オブジェクトと単一常駐オブジェクトの使い分けは開発規模やプロジェクトに応じて変えてください。大規模システムの場合は複数常駐オブジェクトを使うことをお勧めします。 複数常駐オブジェクトのコーディングは単一常駐オブジェクトと変わりません。ただし、常駐オブジェクトの生成関数と解放関数およびコールバックの関数名は複数常駐オブジェクト専用に変わります。
表1.2.1.5-3
複数常駐オブジェクトの生成用関数定義 extern "C" DLLEXPORT void* OnTPSPrecreatedUsersObjectForPlural( const char* ident );
複数常駐オブジェクトの解放用関数定義 extern "C" DLLEXPORT void OnTPSReleasePrecreatedUsersObjectForPlural( void* preobj, const char* ident )
複数常駐オブジェクトコーディング例
mpreobj2.def(Windowsのみ必要)
-------------------------------
EXPORTS
       OnTPSPrecreatedUsersObjectForPlural
       OnTPSReleasePrecreatedUsersObjectForPlural
       OnTPSOperationStartForPlural
       OnTPSOperationNormalForPlural
       OnTPSOperationAbnormalForPlural
       OnTPSOperationAbortForPlural

mpreobj2.h
-------------------------------
#ifndef            MPREOBJ2_H_
#define            MPREOBJ2_H_

#if defined(WIN32)
#if defined(MPREOBJ2_EXPORTS)
#ifndef            MPREOBJ2_EXPORTDEF
#define MPREOBJ2_EXPORTDEF __declspec(dllexport)
#endif
#else // !defined(PREOBJ1_EXPORTS)
#define MPREOBJ2_EXPORTDEF __declspec(dllimport)
#endif
#endif
#else              // !WIN32
#define            MPREOBJ2_EXPORTDEF
#endif
#endif

class MPREOBJ2_EXPORTDEF mpreobj2 {
       int m_db;
public:
       mpreobj2();
       ~mpreobj2();

       void set(int db);
       int get();
};

#endif

mpreobj2.C(Windowsの場合は.cpp)
-------------------------------
#include 

#include "mpreobj2.h"
#include "wotxexps.h"

extern "C" MPREOBJ2_EXPORTDEF
   void* OnTPSPrecreatedUsersObjectForPlural(
       const char* ID
   );
extern "C" MPREOBJ2_EXPORTDEF
   void OnTPSReleasePrecreatedUsersObjectForPlural(
       void* ptr,
       const char* ID
   );
extern "C" MPREOBJ2_EXPORTDEF
   void OnTPSOperationStartForPlural(
       void* ptr,
       const char* ID,
       const char* repositoryID,
       const char* opname
   );
extern "C" MPREOBJ2_EXPORTDEF
   void  OnTPSOperationNormalForPlural(
       void* ptr,
       const char* ID,
       const char* repositoryID,
       const char* opname
   );
extern "C" MPREOBJ2_EXPORTDEF
   void  OnTPSOperationAbnormalForPlural(
       void* ptr,
       const char* ID,
       const char* repositoryID,
       const char* opname,
       int status
   );
extern "C" MPREOBJ2_EXPORTDEF
   void  OnTPSOperationAbortForPlural(
       void* ptr,
       const char* ID,
       const char* repositoryID,
       const char* opname,
       int status
   );

//==========================================================//
MPREOBJ2_EXPORTDEF  mpreobj2::mpreobj2()
{
  // 複数常駐オブジェクトのコンストラクタ
  m_db = 0;
}

MPREOBJ2_EXPORTDEF  mpreobj2::~mpreobj2()
{
  //  複数常駐オブジェクトのデストラクタ
}

MPREOBJ2_EXPORTDEF void mpreobj2::set(int db)
{
  // 複数常駐オブジェクトのメソッド
  m_db = db;
}

MPREOBJ2_EXPORTDEF int mpreobj2::get()
{
  // 複数常駐オブジェクトのメソッド
  return m_db;
}

//==========================================================//
extern "C" MPREOBJ2_EXPORTDEF
    void* OnTPSPrecreatedUsersObjectForPlural(
              const char* ID
    )
{
    // 複数常駐オブジェクトオブジェクトの生成
    return (void*)new mpreobj2;
}

extern "C" MPREOBJ2_EXPORTDEF
    void OnTPSReleasePrecreatedUsersObjectForPlural(
        void* ptr,
        const char* ID
    )
{
    // 複数常駐オブジェクトオブジェクトの解放
    delete (mpreobj2*)ptr;
}

extern "C" MPREOBJ2_EXPORTDEF
    void OnTPSOperationStartForPlural(
        void* ptr,
        const char* ID,
        const char* repositoryID,
        const char* opname
    )
{
    // オペレーション開始時に特別な処理を行う時に記述
}

extern "C" MPREOBJ2_EXPORTDEF
    void OnTPSOperationNormalForPlural(
        void* ptr,
        const char* ID,
        const char* repositoryID,
        const char* opname
    )
{
    // オペレーション正常終了時に特別な処理を行う時に記述
}

extern "C" MPREOBJ2_EXPORTDEF
    void OnTPSOperationAbnormalForPlural(
        void* ptr,
        const char* ID,
        const char* repositoryID,
        const char* opname,
        int status
        )
{
    // オペレーション異常終了時に特別な処理を行う時に記述
}

extern "C" MPREOBJ2_EXPORTDEF
    void OnTPSOperationAbortForPlural(
        void* ptr,
        const char* ID,
        const char* repositoryID,
        const char* opname,
        int status
    )
{
    // オペレーションアボート時に特別な処理を行う時に記述
}
//==========================================================//
複数常駐オブジェクトのコールバックについて
複数常駐オブジェクト用のDLL(sl,so)に以下の外部関数を定義すると特定の事象が発生したときにコールバックされるようになります。常駐オブジェクトでより細かな制御を行いたいときに組み込んでください。 各関数の定義方法はOnTPSPrecreatedUsersObjectForPlural()やOnTPSReleasePrecreatedUsersObjectForPlural()と同様に組み込んでください
表1.2.1.5-4
オペレーションの開始 extern "C"DLLEXPORT void OnTPSOperationStartForPlural ( void * preobj, const char* ident, const char* intf, const char* op)
オペレーションの正常終了 extern "C"DLLEXPORT void OnTPSOperationNormalForPlural ( void * preobj, const char* ident, const char* intf, const char* op)
オペレーションの異常終了(TPSSetTxStatus()で0以外を設定したとき) extern "C"DLLEXPORT void OnTPSOperationAbnormalForPlural ( void *preobj, const char* ident, const char* intf, const char* op, int status)
アボート(AbortExit()が呼ばれたときに、サーバオブジェクトのOnTPSAbort()より前に呼び出す) extern "C"DLLEXPORT void OnTPSOperationAbortForPlural ( void *preobj, const char* ident, const char* intf, const char* op, int status)
常駐オブジェクトを用いたサーバアプリケーションの作成方法
最後に、サーバアプリケーションのコーディング例を示します。
#include "orb.h"
#include "wotxexps.h"

#include "preobj1.h"

#include "mpreobj2.h"

CORBA_Long foo_i::op1(CORBA_Long id, CORBA::Environment& _env)
{
       // 常駐オブジェクトの変数を設定
       preobj1*  pPreobj1 = NULL;
       mpreobj2* pMpreobj2 = NULL;

       // 単一常駐オブジェクトの取得と呼び出し
       TPSGetPrecreatedUsersObject((void**)&pPreobj1);
       if (pPreobj1 != NULL) {
正常時の処理
常駐オブジェクトのメソッドを呼び出す
       } else {
異常時の処理
ユーザ定義の例外やエラー返却値を設定
       }
       // 複数常駐オブジェクトの取得と呼び出し
       int nRet = TPSGetPrecreatedUsersObjectForPlural(
                     "mpreobj2",
                     (void**)&pMpreobj2
       );

       if (nRet == ERROR_PREOBJ_NO) {
正常時の処理
常駐オブジェクトのメソッドを呼び出す
       } else {
異常時の処理
ユーザ定義の例外やエラー返却値を設定
       }
}
共有プロパティの利用方法
プロセスグループには複数のコンポーネントが登録可能です。 コンポーネント間で共有データなどを参照する場合(ディスクに書き込む必要のない、変化の激しいデータ)は、グローバル変数を使うことにより実現できます。しかし、グローバル変数を用いた方法では幾つかの問題点が あります。一つは排他処理が必須であるが煩雑であること。もう一つはプロセス間におけるデータの共有ができないことです。WebOTXでは、これらの問題点を克服した共有プロパティという機能があります。 ここでは、共有プロパティについて説明します。
共有プロパティ概要
共有プロパティは以下の4つの要素から構成されています。
プロパティグループエリアとは、以下に説明するプロパティグループを作成する場所のことです。場所の種類は「ホスト内共有」、「システム内共有」、「アプリケーショングループ内共有」、「プロセスグループ内共有」の4種類です。 ホスト内共有の場合、複数のWebOTXシステムを一つのマシンで動かしたとき、すべてのプロセスから参照や更新をすることが出来ます。システム内共有の場合、そのシステム内のすべてのプロセスから参照や更新をすることができます。 アプリケーショングループ内共有の場合は、そのアプリケーショングループ内のすべてのプロセスから参照や更新をすることが出来ます。プロセスグループ内共有の場合は、そのプロセスグループ内のすべてのプロセスから参照や更新をすることが出来ます。 プロパティグループとは、複数のプロパティを一つのグループとしてまとめた単位のことです。 共有プロパティを利用するときは必ずプロパティグループを作成しなければなりません。プロパティとは値を格納する単位のことです。値とは、プロパティに設定する数値や文字列のことです。 プロパティグループおよびプロパティには、プロパティグループエリア内で一意に識別する文字列を設定します。 この文字列をキーにコンポーネント間で値を受け渡します。
共有プロパティの利用方法概要を以下に示します。
プロパティグループの作成、取得、解放
プロパティグループはサーバAPIを利用して作成/取得/解放します。サーバAPIの説明については [ リファレンス集 開発編(共通) > 4. CORBA > 4.5. WebOTX CORBA アプリケーション(C++) > 4.5.1. サーバAPI ] を参照してください。ここでは、使用例を示します。エラー処理は省略しています。
:
    :
    :
void foo::hoo ()
{
    const char* pgname = "PropertyGroupFoo"; // プロパティグループ名
    long area = WOSP_AREATYPE_HOST;  // ホスト内共有
    WOPropertyGroup* wopg = NULL;
    long result = TPSCreatePropertyGroup(pgname, area, &wopg);
    if (result == WOSP_RC_DONE) {
        // 新規作成なのでプロパティも新規作成する
        const char* propertyName = "fooProperty";
        WOProperty* woproperty = NULL;
        result = wopg->CreateProperty(propertyName, &woproperty);
        if (result != WOSP_RC_DONE) {
            :
        }
        // プロパティグループのロック
        WO_PG_WAITFLAG inWaitflag;
        inWaitflag = WO_PG_WAIT;  // ロック取得まで待ち合わせる
        long waitsec = 3 * 1000;  // 待ちあわせ時間
        result = wopg->Lock(inWaitflag, waitsec);
        if (result != WOSP_RC_DONE) {
               :
        }
        // 値を設定
        int nValue = 100;
        if (result == WOSP_RC_DONE || result == WOSP_RC_ALREADY) {
            woproperty->Set(nValue);
        } else {
            // 異常系処理
            :
            :
 }
:
:
        // プロパティグループのアンロック
        result = wopg->Unlock();
        if (result != WOSP_RC_DONE) {
            :
        }
    } else {
        // 既に存在するので、プロパティを取得する
        const char* propertyName = "fooProperty";
        WOProperty* woproperty = NULL;
        result = wopg->GetProperty(propertyName, &woproperty);
        if (result != WOSP_RC_DONE) {
            :
        }
        // プロパティグループのロック
        WO_PG_WAITFLAG inWaitflag;
        inWaitflag = WO_PG_WAIT;    // ロック取得まで待ち合わせる
        long waitsec = 3 * 1000;    // 待ちあわせ時間
        result = wopg->Lock(inWaitflag, waitsec);
        if (result != WOSP_RC_DONE) {
             :
        }
        // 値の取得
        int nValue;
        if (result == WOSP_RC_DONE || result == WOSP_RC_ALREADY) {
            woproperty->Get(nValue);
        } else {
            // 異常系処理
            :
            :
        }
            :
            :
        // プロパティグループのアンロック
        result = wopg->Unlock();
        if (result != WOSP_RC_DONE) {
            :
        }
    }
}
    :
    :
プロパティの生成/取得
プロパティは、プロパティグループクラス(WOPropertyGroup)のメソッドを使って生成/取得を行います。 プロパティの生成を行うにはCreateProperty()メソッド、取得を行うにはGetProperty()メソッドを使用します。使用例は上記プロパティグループの例題を参照してください。
値の設定/取得
値の設定や取得はプロパティクラス(WOProperty)のメソッドを使って行います。値の設定はSet()メソッド、 取得を行うにはGet()メソッドを使用します。Set()およびGet()メソッドを使う前に必ず該当するプロパティグループをロックしてください。使用例は上記プロパティグループの例題を参照してください。
プロパティグループのロック
複数のプロセスから同時にアクセスされるデータの場合、整合性を保つためにデータのロックを行ってから参照や更新を行う必要があります。共有プロパティではプロパティグループ単位にロック制御が可能になっています。
データベース自動接続/切断機能の利用方法
WebOTXでは、Oracleにおいてデータベースコネクションの自動接続機能が使えます。これは、WebOTX Transaction Service連携や独自にデータベースコネクションを管理する方式とは共存できませんので注意してください。
環境設定について
データベース自動接続機能を使用する為には開発環境および実行環境にて環境設定が必要です。
Windows:
  1. Oracleを開発環境および実行環境にそれぞれインストールしてください。Oracleのインストールに関してはOracleのマニュアルをご覧ください。
  2. "MS-DOS窓"を実行してください。
  3. VC++.NETの環境変数の設定を行ってください。
  4. ORACLE_HOME環境変数を設定します。
    > set ORACLE_HOME=<ORACLEインストール先ディレクトリ>
    
  5. DB自動接続用ライブラリTPDBlib.dllを作成します。
    > cd <WebOTX>\dev\dblib
    > nmake PROC
    
  6. WebOTXのシステムを停止する(運用管理ツールから操作してください)
  7. <WebOTX>\Trnsv\bin\TPDBlib.dllを削除してください。
  8. <WebOTX>\dev\bin\TPDBlib.dllを<WebOTX>\Trnsv\bin\TPDBlib.dllにコピーしてください。
次にシステムの環境変数PATHの設定が必要です。これは、通常Oracleをインストールした時に自動的に設定されるので再設定する必要はありません。Oracleのインストールに関してはOracleのマニュアルをご覧ください。
HP-UX(Itanium 2):
  1. Oracleを開発環境および実行環境にそれぞれインストールしてください。Oracleのインストールに関してはOracleのマニュアルをご覧ください。
  2. 開発環境にてDB自動接続用ライブラリと、Oracleのアクセスライブラリlibclntsh.soをリンクした実行モジュールTHTPPDB8 を作成する必要があります。以下の手順に従って作成してください。作成したファイルは、実行環境の/opt/WebOTX/Trnsv/binにコピーしてください(Cシェルでの操作を例にしています。また、ORACLE_HOMEはOracleをインストールする時に作成したアカウントのホームディレクトリを設定します。例として/home/oralceを使用しています)。
    % setenv ORACLE_HOME /home/oracle
    % cd /opt/WebOTX/dev/THTPPDB/dblib
    % make PROC
    % cd ../lib
    % ftp 実行環境ホスト名
    > bin
    > cd /opt/WebOTX/Trnsv/lib
    (デフォルトはファイルのownerがrootになっているので書き込めません。
    別のディレクトリに書き込んでからcpしてください)
    > put libTPDB<作成日付>.so
    > bye
    % cd ..
    % make
    % ftp 実行環境ホスト名
    > bin
    > cd /opt/WebOTX/Trnsv/bin
    > put THTPPDB8
    
  3. 次に実行環境にORACLE_HOME環境変数の設定とlibclntsh.soがあるディレクトリをLD_LIBRARY_PATH環境変数の設定を行ってください。
  4. ファイル名は/etc/rc.config.d/WebOTX に記述します。記述形式はsh形式です。
    ORACLE_HOME=/home/oracle
    LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${ORACLE_HOME}/lib
    export ORACLE_HOME LD_LIBRARY_PATH
    
  5. OS再起動、あるいはtpsystemの再起動をしてください。
サーバアプリケーションの作成方法
データベース自動接続機能を使用する為にはPro*C/C++を使用する必要があります。また、コーディング時の注意もあります。
.pcファイルの作成について
  1. 以下のヘッダファイルを必ずincludeしてください。
    #include "thtplib.h"
    #define SQLCA_NONE
    #include <sqlca.h>
  2. 各関数の先頭に以下のEXEC SQL文を記述してください。
    struct sqlca sqlca;
    EXEC SQL INCLUDE TPSQLCTX;
    EXEC SQL INCLUDE SQLERRC;
  3. エラー処理を行うには以下のようなエラー処理関数を定義してEXEC SQL文を記述してください。これまでの処理をまとめて以下に記述します。
    #include "thtplib.h"
    #define SQLCA_NONE
    #include <sqlca.h>
    void sql_error(int*);
    void sql_error(int* dberror)
    {
       struct sqlca sqlca;
       EXEC SQL INCLUDE TPSQLCTX;
       EXEC SQL INCLUDE SQLERRC;
       *dberror = -1;
       EXEC SQL WHENEVER SQLERROR CONTINUE;
       return;
    }
    int SampleDBUpdate(int tid, const char* data)
    {
       struct sqlca sqlca;
       EXEC SQL INCLUDE TPSQLCTX;
       EXEC SQL INCLUDE SQLERRC;
       EXEC SQL BEGIN DECLARE SECTION;
         int id;
         VARCHAR text[32];
       EXEC SQL END DECLARE SECTION;
       int dberror = 0;
       id = tid;
       strcpy((char *)text.arr, data);
       text.len = (short) strlen((char *)text.arr);
       EXEC SQL WHENEVER SQLERROR DO sql_error(&dberror);
       EXEC SQL UPDATE SampleDB SET TEXT=:text WHERE ID=:id;
       if (dberror != 0) {
       // エラー処理 (エラーコードによってはリトライ)
       }
       return dberror
    }
    
.pcファイルのコンパイルについて
  1. 以下のパラメータの指定を必須としています。
    HOLD_CURSOR=NO
    RELEASE_CURSOR=NO
    DBMS=NATIVE
    THREAD=YES
    INCLUDE=/opt/WebOTX/dev/include
  2. 上記以外のパラメータに関してはOracleのマニュアルを参照してください。
WebOTX Transaction Service
本章の説明はOTS1.1のものです。最新版はOTS1.4です。詳細についてはTransaction Serviceの説明をご覧ください。 WebOTX Transaction Serviceと連携することによりXAインタフェースによるDBアクセス、 2フェーズコミットが可能となります。 以下にWebOTX TransactionServiceとの連携アプリケーションを 作成する場合の手順を示します。
共有コンポーネント機能
作成した共有コンポーネントとサーバコンポーネントはそれぞれ運用管理ツールに登録します。登録方法は「ドメイン構築・基本設定ガイド」をご覧ください。
共有コンポーネントの作成方法
共有コンポーネントを作成する手順を以下に示します。
  1. IDLファイルを作成する(Animal.idlとします)
    interface Animal {
        string kind();
        string name();
    };
    
  2. i2ccコマンドを用いて以下のようにコンパイルする
    i2cc -lstub -Xdii -i -E Animal.idl
    
  3. 通常のサーバコンポーネントと同様にプロジェクトファイルやMakefileを作成します。このとき、プリプロセッサに以下の定義を加えてください。
    -DOB_<大文字のIDLファイル名>CMN_EXPORT -DOB_<大文字のIDLファイル名>IMP_EXPORT
    上記例の場合、
    -DOB_ANIMALCMN_EXPORT -DOB_ANIMALIMP_EXPORTとなります。
  4. 後は必要なロジックを組み込んでコンパイルします。このとき、Windowsにて実装コードを記述するときは、コンストラクタ、デストラクタ、オペレーションのすべてを__declspec(dllexport)をつけてexportしてください。OB_<大文字のIDLファイル名>CMN_DS(OB_ANIMALCMN_DS)を使用するとコーディングしやすいと思います。
    class Animal_i : public virtual POA_Animal {
        public:
        OB_ANIMALCMN_DS Animal_i();
        OB_ANIMALCMN_DS virtual ~Animal_i();
        OB_ANIMALCMN_DS char* kind(
                       CORBA::Environment& _env = Ob_default_environment());
        OB_ANIMALCMN_DS char* name(
                       CORBA::Environment& _env = Ob_default_environment());
    };
    
    
共有コンポーネントの利用方法
共有コンポーネントを利用したサーバアプリケーションの作成方法を以下に示します。
  1. 共有コンポーネントで定義したインタフェースを利用したIDLを作成する(pet.idl)
    module Pet {
        interface Dog : ::Animal {
            long bark();
        };
        interface Cat : ::Animal {
            long jump();
        };
    };
    
  2. 共有コンポーネントのIDLファイルを参照するようにwoigenxxを実行する。
    woigenxx -R Animal.idl pet
    -Rは複数個記述することもできます。
    woigenxx -R com1.idl -R com2.idl extends
    
  3. 通常のサーバコンポーネントを作成するようにコーディングしてください。
    実装部分のヘッダ定義(pet_i.h)は共有コンポーネントの作りによって変えてください。
    共有コンポーネントに実装がある場合のクラス定義(実装しているクラス名を Animal_iとする):
    #include "Animal.h"
    #include "Animal_i.h"
    class Pet_dog_i : public virtual POA_Pet_dog , public virtual Animal_i{ : } 
    
    共有コンポーネントに実装がない場合のクラス定義(実装しているクラス名を Animal_iとする):
    #include "Animal.h"
    class Pet_dog_i : public virtual POA_Pet_dog
    {
        <dd>:
    }
    
  4. 共有コンポーネントのヘッダファイルをインクルードパスに加えてください。
  5. Windowsの場合は、リンクするライブラリに共有コンポーネントのライブラリ(Animal.lib)を加えてください。
共有コンポーネントの登録方法
作成した共有コンポーネントとサーバコンポーネントはそれぞれ運用管理ツールに登録します。登録方法は「ドメイン構築・基本設定ガイド」をご覧ください。
クライアントアプリケーションについて
クライアントアプリケーションは通常の作り方に加えて以下の作業が必要です。
  1. 共有コンポーネントDLLに実装がない場合
    共有コンポーネントのヘッダファイルをインクルードパスに加えてください。
    リンクするライブラリに共有コンポーネントのライブラリ(Animal.lib)を加えてください。
    アプリケーションを配布するときは共有コンポーネントのDLL(Animal.dll)も加えてください。
  2. 共有コンポーネントDLLに実装がある場合
    共有コンポーネントの IDL ファイルを以下のように再コンパイルしてください。以後、ここで作成したファイルを使用します。
    igenxx -i Animal.idl
    
    共有コンポーネントのヘッダファイルをインクルードパスに加えてください。
    共有コンポーネントのスタブ部分(Animalcmn.cpp)をプロジェクトに加えてください。
非同期トランザクションについて
非同期トランザクションとは

通常、IDLコンパイラが生成したソースを用いてCORBAアプリケーションを作成した時は同期型か遅延同期型しかありません。DII(Dynamic Invocation Interface)を使用して非同期呼び出しを行うことも可能ですが難易度が高いのが現状です。また、非同期に呼び出したオペレーションの伝達保証もありません。 WebOTXでは以下に示す仮想宛先機能を使うことにより、呼び出し伝達の保証しつつ、コーディングの変更なしに非同期にオペレーションを呼び出すことができる 非同期トランザクション機能 を提供します。 本節では、この非同期トランザクションについて説明します。
仮想宛先(VD:Vritual Destination)とは
仮想宛先とは様々なメッセージ送受信機能を可能にする為に導入された概念です。仮想宛先の実体は、メモリやファイルに実装されますが、サーバプログラムからはCORBAクライアントに見えます。

仮想宛先の特徴
非同期トランザクションの利用方法
非同期トランザクションを利用する為には、IDLの定義と名前サーバからオブジェクトの取得、運用管理ツールによる定義が必要です。
  1. IDL定義
    非同期トランザクションとして呼び出されるオペレーションは以下のルールに従って記述しなければなりません。
    • ステートレス&ファクトリレスで動作すること
    • 引数はすべてin型で定義する
    • 返却値はlongで定義する
    以下に例を示します。
    interface foo {
      long AsyncOP(in string key, in long size);
    };
    
  2. 名前サーバからオブジェクトリファレンスの取得
    前述で定義したインタフェースのオブジェクトを呼び出す為に、 名前サーバからオブジェクトリファレンスを入手する必要があります。 オブジェクトリファレンス取得の為のサンプルコーディングを以下に示します。
  3. 非同期トランザクションの呼び方
    前述で定義したインタフェースのオブジェクトを通常のアプリケーションのように呼び出してください。 ただし、現在のWebOTXでは、このオペレーション呼び出しを行う時は すべての例外を無視しなければなりません(C++言語だけの制限です)。
    VD送信への成功の可否は、TPSGetAsyncVDSendResult()にて取得してください。
  4. 非同期トランザクションの成功の可否の判断方法
    TPSGetAsyncVDSendResult()にて取得した値により判断してください。
    • 0: 正常終了
    • 80: エラー。ただし、VDサーバのプール数の上限に達した場合もあるので、間隔をおいてリトライすることをお勧めします。
    • 1以上の値: エラー。VD未起動あるいは運用管理ツールの設定ミスが考えられます。
    • -1以下の値: エラー。通常は発生しません(VDサーバへの送信パラメータミス)。もし、これが発生した場合は運用管理ツールの設定を再度行ってみてください。
  5. 運用管理ツールによる定義
    非同期トランザクションを利用する為には、運用管理ツールにて以下の設定が必要です。
    1. 「非同期トランザクションを利用する」と設定
      非同期オペレーションを使用するプロセスグループのプロパティで設定します。
    2. 「VD(仮想宛先)」の設定
      VDの作成時に指定する「VDの型」で「トランザクション型」を選択します。 そして、対応するオペレーションを選択します。 上記例の場合、fooインタフェースのAsyncOPとなります。
    3. プロセスグループプロパティとインタフェースプロパティの設定
      非同期処理を行うプロセスグループの設定で以下のように指定してください。 下記パラメータ以外の設定は任意です。
      • プロセスグループプロパティ
        • オペレーションコールのモード
          • ステート:ステートレス
      • インタフェースプロパティ
        • 「事前生成を行う」をチェックする
  6. サーバコンポーネントの登録
    以下のように非同期トランザクションを呼び出すコンポーネントと処理をするコンポーネントでプロセスグループを別々に分けてください。
    tpsystem
    +-vdtest ------------------- アプリケーショングループ名
    +-TxFirst --------------- プロセスグループ名
    |   +-TxFirst.dll ------- サーバコンポーネント
    |                         (非同期トランザクションを使用する)
    +-TxSecond -------------- プロセスグループ名
    |                     (ステートレス、ファクトリを使用しない)
    +-TxSecond.dll ------ サーバコンポーネント
    |                 (非同期トランザクションを実行する)
    +-インタフェース-- 事前生成を行う
    
上記構成を前提としたサンプルプログラムがありますので参照してください。
初期化/終了関数
ファクトリオブジェクトやサーバオブジェクトの生成より前に独自の初期化処理や終了処理を組み込みたい場合は、<IDLファイル名>_Entry.C(Windowsの場合は.cpp)にある以下の関数に定義してください。なお、_Entry.C(Windowsは.cpp)はIDLコンパイルすると上書きされますので十分に注意してください。
extern "C" WO_USER_EXPORT int WebOTX_Init()
{
  return 0;
}
extern "C" WO_USER_EXPORT void WebOTX_Term()
{
  return ;
}
アプリケーション初期プロセスについて
アプリケーション初期プロセスとは、アプリケーショングループ内部のプロセスグループの起動に先立って前処理を行うことが出来るサーバアプリケーションのことです。設定方法に関しては運用管理ツールの説明をご覧ください。ここでは、サーバAPの作成方法を示します。
アプリケーション初期プロセス用インタフェース
アプリケーション初期プロセスのためのアプリケーションは以下のインタフェースを有したDLL、SL、SOを作成する必要があります。起動と同時に呼び出されて、この関数の返却値によってアプリケーショングループの起動を継続するか停止するか指定できます。主な用途として、共有メモリの初期化に使用してください。
初期化関数:
  • 形式
    #include "woapgint.h"
    UNIX: extern "C" int WebOTX_APG_initialize();
    Windows: extern "C" __declspec(dllexport) int WebOTX_APG_initialize();
  • 機能
    アプリケーション初期プロセス起動時に、登録したDLL内に本関数を呼び出す。
    本関数の返却値がWOAPGINT_SUCCESS以外は、アプリケーショングループを停止する。
  • 返却値:
    WOAPGINT_SUCCESS ( 0) 初期化正常終了。該当アプリケーショングループの起動を続けます。
    WOAPGINT_FAILURE (-1) 初期化異常終了。該当アプリケーショングループの起動を終了します。
利用可能なサーバAPIについて
アプリケーション初期プロセス内部で使用できWebOTX APIの一覧を示します。
表1.2.1.5-5
オペレーション操作関連
TPSSetTxStatus() × オペレーション呼び出し中のみ意味があるため
TPSRegisterDB() × オペレーション呼び出し中のみ意味があるため
TPSAbort() × オペレーション呼び出し中のみ意味があるため
TPSRestart() × オペレーション呼び出し中のみ意味があるため
トレース関連
TPSUserTrace() △ トレースレベル1または2のときのみ出力可能
TPSGetUserTraceLevel()
TPSEventJournal()
情報取得
TPSGetLid() × オペレーション呼び出し中のみ意味があるため
TPSGetTerminalIP() × オペレーション呼び出し中のみ意味があるため
TPSGetArgumentCount()
TPSGetArgumentValue()
TPSGetServerInformation() △ 一部情報が欠落する(後述)
CORBAオブジェクト関連
TPSGetORB()
TPSGetMyPOA()
TPSGetInitialReference()
常駐オブジェクト関連
TPSGetPrecreatedUsersObject() × オペレーション呼び出し中のみ意味があるため
TPSGetPrecreatedUsersObjectForPlural() × オペレーション呼び出し中のみ意味があるため
SPA関連
TPSGetSpa() × オペレーション呼び出し中のみ意味があるため
TPSSetSpaFlag() × オペレーション呼び出し中のみ意味があるため
共有プロパティ関連
TPSCreatePropertyGroup()
TPSGetPropertyGroup()
VDサーバ関連(OLF/TP-UT)
TPSVDSend()
WebOTXの情報:
アプリケーショングループ名
プロセスグループ名 × プロセスグループ単位の指定パラメータのため
ステートフルかステートレスか × プロセスグループ単位の指定パラメータのため
スレッドモデル × プロセスグループ単位の指定パラメータのため
IIOPリスナポート番号
クライアント管理ライブラリポート
常駐オブジェクトクラス名 × プロセスグループ単位の指定パラメータのため
OTS連携を行うか × プロセスグループ単位の指定パラメータのため
システムID
接続サーバ名
名前サーバ名
Watchサーバを使用するか
名前サーバに登録するリファレンスの数
ファクトリを使うかどうか × プロセスグループ単位の指定パラメータのため
Oracle連携するかどうか × プロセスグループ単位の指定パラメータのため
SQL/Netを使用するか × プロセスグループ単位の指定パラメータのため
Oracle連携用のSID名 × プロセスグループ単位の指定パラメータのため
Oracle連携用のユーザ名とパスワード × プロセスグループ単位の指定パラメータのため
障害発生時の処理について
例外発生時のコールバックについて

サーバアプリケーションで不正なアドレス参照などにより例外が発生すると、 WebOTXはオペレーションの実行を中断し、そのオペレーションを閉塞し、それ以降実行できなくします。 このとき、例外があったことをサーバオブジェクトに通知する機能があります。これを利用するには以下の条件を全て満たしている必要があります。
以上の条件を満たしていると、例外時にWO_Base::OnTPSAbort() の実装部分を呼び出します。ここに例外時の後処理などを記述してください。

クライアントとのセッション切断について

WebOTXでは、クライアントアプリケーションが切断した時、切断したことをサーバオブジェクトに通知する機能があります。 これを利用するには以下の条件を全て満たしている必要があります。
以上の条件を満たしていると、例外時にWO_Base::OnTPSDisconnect() の実装部分を呼び出します。ここにコネクション切断時の後処理などを記述してください。

データベースオブジェクトの登録と自動ロールバックについて

サーバアプリケーションで不正なアドレス参照などにより例外が発生すると、 WebOTXはオペレーションの実行を中断し、そのオペレーションを閉塞し、それ以降実行できなくします。 このとき、WebOTXはサーバアプリケーション内で例外が発生したことを知らせるために、該当オブジェクトに対してWO_BaseインタフェースのOnTPSAbort()オペレーションを呼び出します。 OnTPSAbort()オペレーションを呼び出した後、事前に登録してあるデータベースオブジェクトに対してrollback()メソッドを発行します。 この、事前に登録するデータベースオブジェクトはWebOTXが提供するWebOTX_DB.hヘッダファイルにて定義しているWebOTX_DBクラスを基底にしたクラスです。また、登録するにはサーバAPIのTPSRegisterDB()を使用します。 以下に簡単な定義例と使用例を示します。
// MyDB.hファイル
#include "orb.h"
#include "wotxexps.h"
#ifndef            MYDB_H
#define            MYDB_H
class MyDB : public WebOTX_DB
{
  public:
  MyDB();
  ~MyDB();
  独自の機能
  void commit();                          // 独自の機能
  void rollback();                        // 純仮想関数に対する定義
};
#endif
// MyDB.C(WindowsではMyDB.CPP)ファイル
#include "orb.h"
#include "wotxexps.h"
#include "MyDB.h"
MyDB::MyDB()
{
  // DBへの接続処理(独自処理)
}
MyDB::~MyDB()
{
  // DBとの切断処理(独自処理)
}
void MyDB::insert(char* data1, char* data2)
{
  // テーブルにデータを追加(独自処理)
}
void MyDB::commit()
{
  // コミット処理(独自処理)
}
void MyDB::rollback()
{
  // ロールバック処理(例外時に呼ばれる)
}
以上のクラス定義を行い、サーバオブジェクト内にてMyDB db = new MyDB;を行ってTPSRegisterDB(db)を実行してください。

1.2.1.6. C++言語を用いたクライアントアプリケーションの作成

C++クライアントアプリケーションの作成の流れ
WebOTXのJavaクライアントアプリケーションの作成から実稼動までの流れは以下のようになります。以下の節ではそれぞれについて詳しく説明します。また、WebOTXが提供する機能についても説明します。
  1. IDLファイルの作成とコンパイル
  2. 実装部分のコーディングとコンパイル
開発環境の設定
プラットフォーム別に開発環境の設定を示します。
UNIX
WebOTXのサーバアプリケーションを作成するにはPATH環境変数に以下のディレクトリを加える必要があります。
さらに、LD_LIBRARY_PATH環境変数に以下のディレクトリを加える必要があります。
例としてcshの設定方法を示します(標準インストールディレクトリのパスを例にしています)。 pathだけshell変数に代入しているのは、cshがpathとPATH環境変数の同期を行うことを前提に設定しています。
:
>set path=( $path /opt/ObjectSpinner/bin )
>set path=( $path /opt/WebOTX/dev/bin )
:
>setenv LD_LIBRARY_PATH /opt/ObjectSpinner/lib:\
/opt/ObjectSpinner/namespace/lib:\
/opt/WebOTX/dev/lib
:
Windows(Intel x86)
WebOTXのクライアントAPを作成するにはPATH環境変数に以下のディレクトリを加える必要があります(<WebOTX>はWebOTXのインストール先ディレクトリをあらわします)。
IDLコンパイラはVC++のプリプロセッサを使用しています。よって、コマンドプロンプトからVC++の実行ファイルを使えるように環境変数を設定する必要があります。プリプロセッサのための環境変数の設定方法は2種類あります。一つは、静的に環境変数を設定する方法([コントロールパネル]-[システム]-[環境]にて設定)。もう一つは、VC++をインストールしたディレクトリ配下にあるvcvars32.batというバッチファイルを実行する方法です。いずれかの方法で環境変数の設定を行ってください。
Windows(Intel 64)
WebOTXのサーバAPを作成するにはPATH環境変数に以下のディレクトリを加える必要があります(<WebOTX>はWebOTXのインストール先ディレクトリをあらわします)。
IDLコンパイラはVC++2005、VC++2008、VC++2010、VC++2012 のプリプロセッサをサポートしています。よって、コマンドプロンプトからVC++2005、VC++2008、VC++2010、VC++2012 の実行ファイルを使えるように環境変数を設定する必要があります。プリプロセッサのための環境変数の設定方法は2種類あります。一つは、静的に環境変数を設定する方法([コントロールパネル]-[システム]-[環境]にて設定)。もう一つはVC++2005、VC++2008、VC++2010、VC++2012 をインストールしたディレクトリ配下にあるvcvarsall.batを実行する方法です。いずれかの方法で環境変数の設定を行ってください。
IDLファイルの作成とコンパイル(C++)
[IDLファイルの作成とコンパイル(C++)] を参照してください。
6.4. クライアントアプリケーションの作成方法(C++)
UNIXのMakefileについて
サーバアプリケーションと同様にIDLコンパイラを実行して出来たファイルを使用して作成します。必要なファイルは以下の通りです。
コンパイル時のオプション
リンク時のオプション
以下にMakeファイルの記述例を示します。 make idl ; make を実行してください。ここではクライアントの実装のソースファイルをloopbackcl.Cとしています。
#-----------------------------------------------------------------------
#  for HP-UX(Itanium 2)
#-----------------------------------------------------------------------
CC       = /opt/aCC/bin/aCC
WOIGENXX = /opt/WebOTX/dev/bin/woigenxx
BASENAME = loopback
LIBS     = -L/opt/ObjectSpinner/namespace/lib -lnsospi \
-L/opt/WebOTX/dev/lib -lnWOBSE91
OBJS     = ${BASENAME}cmn.o \
${BASENAME}cl.o
INC      = -I/opt/WebOTX/dev/include \
-I/opt/ObjectSpinner/namespace/include
LDFLAGS  = -mt -Wl,-E +DD64
C++FLAGS = +Z -mt -DOB_HPUX_KT +DD64
TARGET   = ${BASENAME}cl
all : ${OBJS} ${TARGET}
${TARGET} : ${OBJS}
${CC} -o $@ ${C++FLAGS} ${LDFLAGS} ${OBJS} ${LIBS}
${BASENAME}cmn.o :      ${BASENAME}cmn.C ${BASENAME}.h
.C.o :
${CC} ${INC} ${C++FLAGS} -c $*.C
idl:
${WOIGENXX} ${BASENAME}
clean:
/bin/rm -rf *.o ${TARGET}
#-----------------------------------------------------------------------
#  for Linux
#-----------------------------------------------------------------------
CC       = /usr/bin/g++
WOIGENXX = /opt/WebOTX/dev/bin/woigenxx
BASENAME = loopback
LIBS     = -lpthread -ldl \
-L/opt/ObjectSpinner/namespace/lib -lnsospi \
-L/opt/WebOTX/dev/lib -lnWOBSE91
OBJS     = ${BASENAME}cmn.o \
${BASENAME}cl.o
INC      = -I/opt/WebOTX/dev/include \
-I/opt/ObjectSpinner/namespace/include
LDFLAGS  = 
C++FLAGS = -D_REENTRANT -D_GNU_SOURCE -fPIC
TARGET   = ${BASENAME}cl
all : ${OBJS} ${TARGET}
${TARGET} : ${OBJS}
${CC} -o $@ ${C++FLAGS} ${LDFLAGS} ${OBJS} ${LIBS}
${BASENAME}cmn.o :      ${BASENAME}cmn.C ${BASENAME}.h
.C.o :
${CC} ${INC} ${C++FLAGS} -c $*.C
idl:
${WOIGENXX} ${BASENAME}
clean:
/bin/rm -rf *.o ${TARGET}
#-----------------------------------------------------------------------
#  for SUN Solaris 10
#-----------------------------------------------------------------------
CC       = /opt/SUNWspro/bin/CC
WOIGENXX = /opt/WebOTX/dev/bin/woigenxx
BASENAME = loopback
LIBS     = -m -m64 -ldl -lgen -lsocket -lnsl -lposix4 \
-L/opt/ObjectSpinner/namespace/lib -lnsospi \
-L/opt/WebOTX/dev/lib -lnWOBSE91
OBJS     = ${BASENAME}cmn.o \
${BASENAME}cl.o
INC      = -I/opt/WebOTX/dev/include \
-I/opt/ObjectSpinner/namespace/include
LDFLAGS  = -mt
C++FLAGS = -D_REENTRANT -mt -m64 -xcode=pic32
TARGET   = ${BASENAME}cl
all : ${OBJS} ${TARGET}
${TARGET} : ${OBJS}
${CC} -o $@ ${C++FLAGS} ${LDFLAGS} ${OBJS} ${LIBS}
${BASENAME}cmn.o :      ${BASENAME}cmn.C ${BASENAME}.h
.C.o :
${CC} ${INC} ${C++FLAGS} -c $*.C
idl:
${WOIGENXX} ${BASENAME}
clean:
/bin/rm -rf *.o ${TARGET}
Windows(Intel x86)のプロジェクト設定について
サーバアプリケーションと同様にIDLコンパイラを実行して出来たファイルを使用して作成します。必要なファイルは以下の通りです。
次に、プロジェクトの設定にて、[C/C++]タブを開き、カテゴリ「コード生成」を選択してください。ここで、使用するランタイムライブラリを「マルチスレッド(DLL)」(デバッグなら「マルチスレッド(DLL、デバッグ)」)を指定してください。この指定を忘れるとプログラムは正常に動作しません。 次に、ライブラリの追加を行います。同じくプロジェクトの設定にて、[リンク]タブを開き、カテゴリ「インプット」を選択してください。ここのオブジェクト/ライブラリモジュールに以下のライブラリを追加してください。
デバッグ版を作成するときは以下のライブラリをリンクしてください。
次に、インクルードパスとライブラリパスを設定します。以下に示すパスを追加してください。
Windows(Intel 64)のMakefileについて
サーバアプリケーションと同様にIDLコンパイラを実行して出来たファイルを使用して作成します。必要なファイルは以下の通りです。
コンパイル時のオプション
リンク時のオプション
以下にMakeファイルの記述例を示します。ここではクライアントの実装のソースファイルをloopbackcl.cppとしています。そしてVC++2005、VC++2008、VC++2010、VC++2012 の実行ファイルを使えるように環境変数を設定してIDLコンパイルを行った後にビルドを実行してください。
#-----------------------------------------------------------------------
#  for Windows(Intel 64)
#-----------------------------------------------------------------------
!include 
OUTDIR=.\Release
INTDIR=.\Release
# Begin Custom Macros
OutDir=.\Release
# End Custom Macros
OTXDIR=C:\Program Files\NEC\WebOTX
OSPIDIR=$(OTXDIR)\ObjectBroker
ALL : "$(OUTDIR)\$(BASENAME)cl.exe"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
CPP=cl.exe
CPP_PROJ = /nologo /MD /W3 /GX /O2 \
/I "$(OSPIDIR)\namespace\include" \
/I "$(OTXDIR)\dev\include" \
/D "WIN32" /D "WIN64" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" \
/Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /c 
.c{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $< 
<< 
.cpp{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $< 
<< 
.cxx{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $< 
<< 
LINK=link.exe
LINK_FLAGS=nosp9011.lib nWOBS97.lib \
/nologo /incremental:no /pdb:"$(OUTDIR)\$(BASENAME)cl.pdb" \
/machine:AMD64 /out:"$(OUTDIR)\$(BASENAME)cl.exe" \
/libpath:"$(OSPIDIR)\namespace\lib" \
/libpath:"$(OTXDIR)\dev\lib" 
LINK_OBJS= \
"$(INTDIR)\$(BASENAME)cl.obj" \
"$(INTDIR)\$(BASENAME)cmn.obj"
"$(OUTDIR)\$(BASENAME)cl.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<< 
SOURCE=.\$(BASENAME)cl.cpp
"$(INTDIR)\$(BASENAME)cl.obj" : $(SOURCE) "$(INTDIR)"
SOURCE=.\$(BASENAME)cmn.cpp
"$(INTDIR)\$(BASENAME)cmn.obj" : $(SOURCE) "$(INTDIR)"
コーディング(ファクトリを使用しない場合)
これでクライアントアプリケーションを作成するための準備が出来ました。次に実装部分をコーディングします。 クライアントアプリケーションは通常のCORBAアプリケーションと同じように作成します。ただし、WebOTXでは、以下の点に注意して作成する必要があります。
名前サーバにはサーバオブジェクトを登録します。それぞれのサーバに合わせて取得してください。 名前への登録は、運用管理ツールでの設定が「一時的」場合はWebOTXが自動的に行います。「永続的」場合は運用管理ツールから明示的に登録を行います。名前サーバに登録する名前のデフォルト値は以下のようになっています。この値は、運用管理ツールにて変更することができます。 /NEC/WebOTX/WO_Default/module名/module名/…/interface名/1 ( / はコンテキストの区切りをあらわします。最初の/はrootコンテキストをあらわします) クライアントアプリケーションは、以下の手順でサーバオブジェクトを利用することが出来ます。
  1. ORBに対してresolve_initial_references("NameService")を行って、名前サーバのオブジェクトリファレンスを取得し、CosNaming::NamingContext::_narrow()を実行します。
  2. CosNaming::Nameオブジェクトを生成し、CosNaming::Name.length(n)を指定してください。nにはコンテキストの深さ+1を指定してください
  3. idに文字列を設定してください。kindには""(空の文字列)を設定してください。
  4. 名前サーバのオブジェクトリファレンスに対してresolve(CosNaming::Nameオブジェクト)を行ってサーバオブジェクトリファレンスを取得して_narrow()してください。
以上のまとめとしてクライアントアプリケーションのサンプルコーディングを以下に示します。このサンプルは、コンソールアプリケーションのmain()の例で、エラー処理は省略しています。
#include <stdio.h>
#include "orb.h"
#include "loopback.h"
int main (int argc, char **argv) {
  // ORBの初期化
  try {
    CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "");

    // 名前サーバオブジェクトリファレンスの取得
    CORBA::Object_var obj = orb->resolve_initial_references("NameService");
    CosNaming::NamingContext_var nmctx = CosNaming::NamingContext::_narrow(obj);

    // サーバオブジェクトリファレンスの取得
    CosNaming::Name objname;
    objname.length(6);   // コンテキスト+1
    objname[0].id = (const char*)"NEC";
    objname[0].kind = (const char*)"";
    objname[1].id = (const char*)"WebOTX";
    objname[1].kind = (const char*)"";
    objname[2].id = (const char*)"WO_Default";
    objname[2].kind = (const char*)"";
    objname[3].id = (const char*)"sample";
    objname[3].kind = (const char*)"";
    objname[4].id = (const char*)"LoopBackSample";
    objname[4].kind = (const char*)"";
    objname[5].id = (const char*)"1";   // バージョン番号
    objname[5].kind = (const char*)"";
    obj = nmctx->resolve(objname);
    sample::LoopBackSample_ptr svobj = sample::LoopBackSample::_narrow(obj);

    // オペレーション呼出し
    const char* instr = "AaBbCc";
    char* outstr;
    int result = svobj->LoopBack (instr,outstr);
    printf("LoopBack %s -> %s\n",instr,outstr);
    CORBA::string_free(outstr);
    result = svobj->LowerCase (instr,outstr);
    printf("LowerCase %s -> %s\n",instr,outstr);
    CORBA::string_free(outstr);
    result = svobj->UpperCase (instr,outstr);
    printf("UpperCase %s -> %s\n",instr,outstr);
    CORBA::string_free(outstr);

    // サーバオブジェクトリファレンスの解放
    CORBA::release(svobj);
    return 0;
  } catch (CORBA::SystemException& e) {
    printf("Occurred exception.");
    printf(" ID=%s minor=%d\n",e.__id(), e.minor());
    return -1;
  } catch (CORBA::Exception& e) {
    printf("Occurred exception.");
    printf(" ID=%s \n", e.__id());
    return -1;
  }
}
コーディング(ファクトリを使用する場合)
これでクライアントアプリケーションを作成するための準備が出来ました。次に実装部分をコーディングします。 クライアントアプリケーションは通常のCORBAアプリケーションと同じように作成します。ただし、WebOTXでは、以下の点に注意して作成する必要があります。
名前サーバにはファクトリオブジェクトを登録します。それぞれのサーバに合わせて取得してください。 名前サーバへの登録は、運用管理ツールでの設定が「一時的」場合はWebOTXが自動的に行います。「永続的」場合は運用管理ツールから明示的に登録を行います。名前サーバに登録する名前のデフォルト値は以下のようになっています。この値は、運用管理ツールにて変更することができます。
/NEC/WebOTX/WO_Default/module名/module名/…/interface名/1 ( / はコンテキストの区切りをあらわします。最初の/はrootコンテキストをあらわします)
クライアントアプリケーションは、以下の手順でサーバオブジェクトを利用することが出来ます。
  1. ORBに対してresolve_initial_references("NameService")を行って、名前サーバのオブジェクトリファレンスを取得し、CosNaming::NamingContext::_narrow()を実行します。
  2. CosNaming::Nameオブジェクトを生成し、CosNaming::Name.length(n)を指定してください。nにはコンテキストの深さ+1を指定してください。
  3. idに上記命名規則に従った文字列を設定してください。kindには""(空の文字列)を設定してください。
  4. 名前サーバのオブジェクトリファレンスに対してresolve(CosNaming::Nameオブジェクト)を行ってファクトリオブジェクトリファレンスを取得して_narrow()してください。
  5. ファクトリオブジェクトリファレンスに対してCreateServerObject()を行うことにより、サーバオブジェクトリファレンスを取得できます。
  6. 使い終わりましたら、ファクトリオブジェクトリファレンスに対してReleaseServerObject()を行ってください。
以上のまとめとしてクライアントアプリケーションのサンプルコーディングを以下に示します。このサンプルは、コンソールアプリケーションのmain()の例で、エラー処理は省略しています。
#include <stdio.h>
#include "orb.h"
#include "loopback.h"
int main (int argc, char **argv) {
  // ORBの初期化
  try {
    CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "");

    // 名前サーバオブジェクトリファレンスの取得
    CORBA::Object_var obj = orb->resolve_initial_references("NameService");
    CosNaming::NamingContext_var nmctx = CosNaming::NamingContext::_narrow(obj);

    // ファクトリオブジェクトリファレンスの取得
    CosNaming::Name objname;
    objname.length(6);   // コンテキスト+1
    objname[0].id = (const char*)"NEC";
    objname[0].kind = (const char*)"";
    objname[1].id = (const char*)"WebOTX";
    objname[1].kind = (const char*)"";
    objname[2].id = (const char*)"WO_Default";
    objname[2].kind = (const char*)"";
    objname[3].id = (const char*)"sample";
    objname[3].kind = (const char*)"";
    objname[4].id = (const char*)"WO_Factory_LoopBackSample";
    objname[4].kind = (const char*)"";
    objname[5].id = (const char*)"1";   // バージョン番号
    objname[5].kind = (const char*)"";
    obj = nmctx->resolve(objname);
    sample::WO_Factory_LoopBackSample_ptr fobj = 
    sample::WO_Factory_LoopBackSample::_narrow(obj);

    // サーバオブジェクトリファレンスの取得
    sample::LoopBackSample_ptr svobj = fobj->CreateServerObject();

    // オペレーション呼出し
    const char* instr = "AaBbCc";
    char* outstr;
    int result = svobj->LoopBack (instr,outstr);
    printf("LoopBack %s -> %s\n",instr,outstr);
    CORBA::string_free(outstr);
    result = svobj->LowerCase (instr,outstr);
    printf("LowerCase %s -> %s\n",instr,outstr);
    CORBA::string_free(outstr);
    result = svobj->UpperCase (instr,outstr);
    printf("UpperCase %s -> %s\n",instr,outstr);
    CORBA::string_free(outstr);

    // サーバオブジェクトリファレンスの解放
    fobj->ReleaseServerObject(svobj);
    CORBA::release(svobj);

    // ファクトリオブジェクトリファレンスの解放
    CORBA::release(fobj);
    return 0;
  } catch (CORBA::SystemException& e) {
    printf("Occurred exception.");
    printf(" ID=%s minor=%d\n",e.__id(), e.minor());
    return -1;
  } catch (CORBA::Exception& e) {
    printf("Occurred exception.");
    printf(" ID=%s \n", e.__id());
    return -1;
  }
}
複雑なIDLの場合のコーディング例(C++)
サーバアプリケーションの作成の [ 複雑なIDLの場合のコーディング例] を参照してください。クライアントの場合は、入力と出力が逆になります。
C++のクライアント管理ライブラリ
WebOTXでは、クライアントマシンの無通信監視や非同期メッセージ処理などを行うクライアント管理ライブラリを提供しています。ここではその使い方を述べます。 クライアント管理ライブラリの使い方は簡単です。 まず、本機能を使用するためにはファクトリオブジェクトが必要になります。そして、Windowsの場合はwotermn2012.lib(VC++2012の場合)とwsock32.libを、HP-UX(Itanium 2), Linux, SUN Solaris 10の場合はlibwoterm.soをリンクするようにプロジェクト(Makefile)の設定に追加します。次に、WOTrmMan.hをプログラムに追加します。最後に、WO_TerminalManagerクラスのオブジェクトを生成して、SetFactoryObject()を呼び出します。SetFactoryObject()の引数にはファクトリオブジェクトリファレンスを指定します。 上記クライアントアプリケーションのサンプルプログラムを基にコーディング例を示します。
#include <stdio.h>
#include "orb.h"
#include "loopback.h"
#include "WOTrmMan.h"
int main (int argc, char **argv)
{
  try {
    // ORBの初期化
    CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "");

    // 名前サーバオブジェクトリファレンスの取得
    CORBA::Object_var obj = orb->resolve_initial_references("NameService");
    CosNaming::NamingContext_var nmctx = CosNaming::NamingContext::_narrow(obj);

    // ファクトリオブジェクトリファレンスの取得
    CosNaming::Name objname;
    objname.length(6);
    objname[0].id = (const char*)"NEC";
    objname[0].kind = (const char*)"";
    objname[1].id = (const char*)"WebOTX";
    objname[1].kind = (const char*)"";
    objname[2].id = (const char*)"WO_Default";
    objname[2].kind = (const char*)"";
    objname[3].id = (const char*)"sample";
    objname[3].kind = (const char*)"";
    objname[4].id = (const char*)"WO_Factory_LoopBackSample";
    objname[4].kind = (const char*)"";
    objname[5].id = (const char*)"1";   // バージョン番号
    objname[5].kind = (const char*)"";
    obj = nmctx->resolve(objname);
    sample::WO_Factory_LoopBackSample_ptr fobj = 
    sample::WO_Factory_LoopBackSample::_narrow(obj);

    // クライアント管理ライブラリへの登録
    WO_TerminalManager woterm;
    woterm.SetFactoryObject(fobj);

    // サーバオブジェクトリファレンスの取得
    sample::LoopBackSample_ptr svobj = fobj->CreateServerObject();

    // オペレーション呼出し
    const char* instr = "AaBbCc";
    char* outstr;
    int result = svobj->LoopBack (instr,outstr);
    printf("Loopback %s -> %s\n",instr,outstr);
    CORBA::string_free(outstr);
    result = svobj-> LowerCase (instr,outstr);
    printf("LowerCase %s -> %s\n",instr,outstr);
    CORBA::string_free(outstr);
    result = svobj-> UpperCase (instr,outstr);
    printf("UpperCase %s -> %s\n",instr,outstr);
    CORBA::string_free(outstr);

    // サーバオブジェクトリファレンスの解放
    fobj->ReleaseServerObject(svobj);
    CORBA::release(svobj);

    // ファクトリオブジェクトリファレンスの解放
    CORBA::release(fobj);
    return 0;
  } catch (CORBA::SystemException& e) {
    printf("Occurred exception.");
    printf(" ID=%s minor=%d\n",e.__id(), e.minor());
    return -1;
  } catch (CORBA::Exception& e) {
    printf("Occurred exception.");
    printf(" ID=%s \n", e.__id());
    return -1;
  }
}
修正個所には下線をつけています。これで、無通信監視機能、非同期メッセージ表示機能が使えます。 なお、クライアント管理ライブラリの有効範囲はWO_TerminalManagerオブジェクトが有効な間だけです。 非同期メッセージ表示機能にはダイアログボックスを表示するほかに、メッセージを送信する拡張機能があります。これを使うことより、非同期メッセージを受信した後の動作を独自に実装することが出来ます。クライアント管理ライブラリに関するAPIについては [ リファレンス集 開発編(共通) > 4. CORBA > 4.5. WebOTX CORBA アプリケーション(C++) > 4.5.3. クライアント管理ライブラリAPI ] を参照してください。
例外処理について
CORBAの例外はC++の例外にマッピングされています。例外の種類には大きく「システム例外」と「ユーザ例外」の2種類あります。 システム例外は、CORBAで規定されたもので主にORBが使用し生成します。システム例外にはマイナーコードが設定されています。マイナーコードはどこでどのような障害が発生したかを示しています。デバッグ効率上げたり、本番運用における障害箇所の特定が可能になりますので、クライアントアプリケーションでは例外の名前とマイナーコードを表示したり記録するロジックを作ったりすることを推奨いたします。 もう一つの例外はユーザ例外です。ユーザ例外はIDLに記述します。例外をうまく設計することで、呼び出した関数が正常に終わったのか異常終了したのかを関数返却値で判断するのではなく、try catch節で処理することが出来ます。

1.2.1.7. COBOL言語を用いたサーバアプリケーションの作成

本章ではCOBOLを使ったサーバコンポーネントの作成方法について記述しています。
COBOLとは
COBOL(COmmon Business Oriented Language)は、事務処理および管理分野のデータ処理に最も広く使用されているプログラミング言語です。一般にCOBOL言語はANSI X3.23-1974(ISO 1989-1978)、ANSI X3.23-1985 (IS 1989:1985)、ANSI X3.23a-1989 (IS 1989:1985/AM1)、及びANSI X3.23b-1993 (IS 1989:1985/AM2) として規定されています。 WebOTXは以下のCOBOL言語に対応しています。
Open COBOL Factoryについては付属の説明書をご覧ください。 なお、COBOL一般およびCOBOLコンパイラの使用方法の詳細については熟知しているものとして記述しています。
COBOLサーバコンポーネントの構成
COBOLのサーバアプリケーションを動作させるためには、C++サーバコンポーネントとして共有ライブラリを作成して登録することで動作可能になります。 COBOLのサーバコンポーネントは以下のような構成になります。
+----------------------------------------+
|C++スタブ/スケルトンコードのオブジェクト| IDLコンパイラが自動生成部分
+----------------------------------------+
|COBOLを呼び出すC++のコードのオブジェクト| サーバント部分
+==============extern "C"================+
|       COBOLコードのオブジェクト        | COBOL部分
+----------------------------------------+
表1.2.1.7-1
IDLコンパイラが自動生成部分
WebOTXおよびObject BrokerのIDLコンパイラがIDLファイルを入力することで生成されるものです。
サーバント部分
ユーザが任意の処理を記述する部分です。 C++言語のみのサーバコンポーネントはここにビジネスロジックを記述しますが、 COBOL言語使用時は主にCOBOLコードを呼び出し値を返却するロジックを記述します。
COBOL部分
ビジネスロジックを記述します。 COBOLサーバコンポーネントを作成する場合は、 COBOLのソースファイルからネイティブオブジェクト(.o)ファイルを生成してリンクします。
この図が示すようにCOBOLサーバコンポーネントを作成するためには、COBOLコンパイラのほかにも IDLコンパイラ(WebOTX提供)とC++コンパイラが必要になります。 また、COBOLサーバコンポーネントはC++コンポーネント同じ扱いなので、1プロセスグループに他のC++サーバコンポーネントと混在は可能です。
COBOLサーバコンポーネントの注意/制限事項
WebOTXのCOBOLコンポーネントにおける制限事項を以下に示します。

1.2.1.8. コマンドリファレンス

Java用
C++用

1.2.1.9. WebOTXのORBについて

WebOTXが使用しているORBはObject Brokerです。よって、ORBとしての基本的な機能はObject Brokerのマニュアルに記載されています。 ただし、WebOTXの特性上、いくつか利用できない機能や型などが存在します。この節ではこれらについて説明します。
利用できない機能
WebOTXのORBとして以下の機能が使用できません。
利用できない型
現在はありません。
利用できないAPI
ここでは、サーバアプリケーションで使用できないAPIについてまとめています。基本的にサーバのソケット関連のAPIは全て使用できません。また、ORB.init()前に呼び出す必要があるAPIも使用できません。ここに載っていないObject Brokerの内部関数においても、基本的に同様の制限を受けますので注意してください。
推奨しない機能
現在はありません。
推奨しない型
現在はありません。
推奨しないAPI
主にクライアントからサーバプロセスの状態を変更するようなAPIの利用は推奨しません。 あと、サーバアプリケーションプロセスの動作を変更するような機能(フック)も推奨しません。

1.2.1.10. WebOTXが使用しているPOAについて

全体構成
WebOTXでは、実装毎にPOAを作成しています。それぞれどのようなポリシーになっているかを示します。
/
+---- リポジトリID;ファイル名 (例: IDL:LoopBackSample:1.0;loopback.jar)
+---- リポジトリID;ファイル名
|                 :
|                 :
+---- リポジトリID;ファイル名
よって、WebOTXが生成するPOAを使用したい場合は、上記命名規則に従って検索してください。
ステートレスオブジェクト用のPOA
以下のポリシーを指定しています。