2.2.7. Object Broker Javaの機能

本項の記述は、Object Broker Javaにのみ当てはまります。

2.2.7.1. Object Broker Javaのプロパティ設定
Object Broker Javaに対して属性を設定することができます。設定した属性はORB初期化時に読み込まれます。
設定可能なプロパティの一覧は、 [構築運用 > ドメインの拡張機能 > Object Broker] を参照してください。
Javaアプリケーションでのプロパティ設定方法は以下のとおりです。優先度が高い順に記載しています。

Caution
org.omg.CORBA.ORBClassおよびorg.omg.CORBA.ORBSingletonClassはJavaシステムプロパティに指定する方法で設定してください。それ以外の設定方法では有効になりません。

Javaアプレットの場合の設定方法は以下のとおりです。優先度が高い順に記載しています。

Caution
org.omg.CORBA.ORBClassおよびorg.omg.CORBA.ORBSingletonClassはHTMLのPARAMタグに記述する方法で設定してください。それ以外の設定方法では有効になりません。

2.2.7.2. 呼び出しタイムアウトの設定
オブジェクト呼び出しのタイムアウトは、次に示す単位で設定することができます。以下の順に優先度は低くなります。
設定しない場合の既定値は30秒です。

Caution
タイムアウト時間の既定値は、WebOTX Ver6.1から30秒に変更になりました。WebOTX Ver5およびそれ以前のバージョンでは、無制限(タイムアウトしない)が既定値です。

オペレーションを呼び出してから応答が返るまでの間に、設定した時間が過ぎてしまったときは、org.omg.CORBA.NO_RESPONSEシステム例外(マイナーコード5130)が返されます。
  1. プロセス内一律のタイムアウト設定
    • プロパティによる設定
      クライアントプログラムのRequestTimeoutプロパティに秒単位で設定します。 設定方法は、本節の「Object Broker Javaのプロパティ設定」の項を参照してください。
    • APIによる設定
      クライアントプログラム上でjp.co.nec.orb.Config.setTimeout(int)を呼び出して設定します。パラメータには、タイムアウト時間をミリ秒単位で設定します。
      // タイムアウトを10秒に設定
      jp.co.nec.orb.Config.setTimeout(10000);
      
  2. インタフェース単位のタイムアウト設定
    • APIによる設定
      クライアントプログラム上でjp.co.nec.orb.Config.setTimeout(String, int)を呼び出して設定します。パラメータには、タイムアウト時間をミリ秒単位で設定します。
      // Helloインタフェースのタイムアウトを10秒に設定
      jp.co.nec.orb.Config.setTimeout("Hello", 10000);
      
  3. オブジェクト単位のタイムアウト設定
    • APIによる設定
      クライアントプログラム上でjp.co.nec.orb.Config.setTimeout(org.omg.CORBA.Object, int)を呼び出して設定します。パラメータには、タイムアウト時間をミリ秒単位で設定します。
      // CORBAオブジェクトのタイムアウトを10秒に設定
      org.omg.CORBA.Object obj = ....
      jp.co.nec.orb.Config.setTimeout(obj, 10000);
      
2.2.7.3. フック
Object Broker Javaでは、あらかじめ登録されたユーザ定義メソッドをオペレーション呼び出しの処理中にコールバックする機能を提供しています。この機能をフックと呼びます。 フックはCORBA仕様では定義されていない、Object Broker独自の機能です。 Object Broker Javaのフックには、以下の2種類のレベルがあります。
また、これらのフックを次に示すレベルで登録することができます。

フックの登録

フックは、jp.co.nec.orb.HookObjクラスを継承して、メソッドをオーバーライドすることで実装します。フックの登録は、フックの実装クラス(HookObj)の次のメソッドを呼び出します。登録後に呼び出しが実行されると、オーバーライドしたメソッドがコールバックされます。

フックの削除

フックの削除は、フックの実装クラス(HookObj)の次のメソッドを呼び出します。
インタフェースレベルの登録、削除で指定するインタフェース名はリポジトリIDを指定してください。リポジトリIDはHelperクラスのid()メソッドで取得することができます。

パラメータレベルのフック

パラメータレベルのフックには、次の4ヶ所のコールバックポイントがあります。各コールバックメソッドがオーバーライドされていれば、各ポイントで呼び出されます。
  1. クライアントアプリケーションのオブジェクト呼び出し直後
    public int ClientBeforeSend(Request req, ObjectImpl execobj)
  2. サーバアプリケーションのオブジェクト呼び出し直前
    public int ServerAfterReceive(ServerRequest req, Servant execobj)
  3. サーバアプリケーションのオブジェクトの戻り直後
    public int ServerBeforeSend(ServerRequest req, Servant execobj)
  4. クライアントアプリケーションのオブジェクトの戻り直前
    public int ClientAfterReceive(Request req, ObjectImpl execobj)

Caution
パラメータレベルのフックは、スタブ/スケルトンがDSI/DIIで生成された場合のみ使用することができます。スタブ/スケルトンをDSI/DIIで生成するには、IDLコンパイラに-notstreamを指定する必要があります。DSI/DIIでない場合、フックを登録してもエラーになりませんが、コールバックは呼び出されません。

Caution
ServerAfterReceiveでは、ServerRequestクラスのメソッドで最初に値を取得する時に、引数、コンテキストの順で値を取得しなければなりません。

メッセージレベルのフック

メッセージレベルのフックには、次の4ヶ所のコールバックポイントがあります。各コールバックメソッドがオーバーライドされていれば、各ポイントで呼び出されます。
  1. クライアントアプリケーションのオブジェクト呼び出し直後
    public int ClientBeforeSend(MessageBuffer buffer)
  2. サーバアプリケーションのオブジェクト呼び出し直前
    public int ServerAfterReceive(MessageBuffer buffer)
  3. サーバアプリケーションのオブジェクトの戻り直後
    public int ServerBeforeSend(MessageBuffer buffer)
  4. クライアントアプリケーションのオブジェクトの戻り直前
    public int ClientAfterReceive(MessageBuffer buffer)
MessageBufferクラスは、リクエスト、リプライメッセージを取り扱うためのクラスで、このクラスのメソッドを用いてメッセージの値の取得や、新しいメッセージの登録を行うことができます。

Caution
ServerAfterReceive、ClientAfterReceiveでは、引数のMessageBufferクラスが保持するバッファのサイズはメッセージサイズに関係なく一定です。メッセージがフラグメントで分割されていてメッセージサイズがバッファサイズより長い場合は、メッセージの先頭からバッファサイズ分までが渡されます。

次の図は各メソッドが実行される順番を示しています。矢印がメッセージの流れ、アルファベットが各メソッドを表しています。


Caution
動的スケルトンインタフェース(DSI)の場合、サーバ側のフックは使用できません。

Caution
各レベルで登録できるメソッドは、以下のとおりです。
パラメータレベル メッセージレベル
A B C D E F G H
システムレベル
インタフェースレベル - - - - - -
オブジェクトレベル - -

戻り値によるフック実行の制御

フックは、オブジェクトレベル、インタフェースレベル、システムレベルの順に実行されます。また、同じレベルで登録されたフックは、登録された順番で実行されます。メソッドの戻り値によって、処理の中断やスキップを行うことができます。フックを作成するときには、戻り値に注意しなければなりません。 戻り値による制御は次の通りです。

Caution
戻り値で3を指定できるのはパラメータレベルのフックのA,Bの場合だけです。これ以外のメソッドで戻り値に3を指定すると、フック処理を中断します。

2.2.7.4. インタフェースリポジトリ
インタフェースリポジトリはCORBAオブジェクトのインタフェース情報を管理します。インタフェースリポジトリにはインタフェース情報の登録、削除、および参照という機能があります。 動的起動インタフェース(DII)を使った呼び出しを行うとき、ターゲットとなるオブジェクトのインタフェース情報が必要になります。このようなとき、インタフェースリポジトリから情報を取り出します。 WebOTX Object Brokerではinstif, rmifコマンドを使うことでインタフェース情報の登録と削除を簡単に行うことができます。ここでは参照する方法を説明します。

リポジトリオブジェクトの取得

インタフェースリポジトリは、リポジトリオブジェクトを頂点とする階層構造をしています。インタフェースリポジトリを利用するには、まず、リポジトリオブジェクトのオブジェクトリファレンスを取得する必要があります。
import org.omg.CORBA.*;
public class MyProg {
    public static void main(String args[]) {
        ORB orbobj = ORB.init(args, null);
 
        org.omg.CORBA.Object ir_in_obj =
            orbobj.resolve_initial_references("InterfaceRepository");
        Repository repository = 
            RepositoryHelper.narrow(ir_in_obj);
             :
             :
    }
}

インタフェース情報の取得

あるオブジェクトが内包しているオブジェクトの一覧を返すものや、内包しているオブジェクトから手がかりになる文字列を使って検索するものなどさまざまな取得方法があります。 ここでは、org.omg.CORBA.Container.describe_contentsとorg.omg.CORBA.InterfaceDef.describe_interfaceの例を示します。を参照してください。 次のIDL定義がinstifコマンドによりインタフェースリポジトリに登録されているものとします。
interface myintf {
    void op(in short i);
};
このデータをインタフェースリポジトリから取り出す例を以下に示します。なお、例外処理や複数のインタフェースやオペレーションが含まれていた場合の考慮などは省略します。
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
 
public class client {
    public static void main(String args[]) {
        //引数モード別
        final String[] opemode = {
            "in", "out", "inout"
        };
 
        //型別
        final String[] tckind = {
            "null", "void", "short", "long", "ushort", "ulong",
            "float", "double", "boolean", "char", "octet",
            "any", "TypeCode", "Principal", "object", "struct",
            "union", "enum", "string", "sequence", "array",
            "typedef", "exception", "longlong", "ulonglong",
            "longdouble", "wchar", "wstring", "fixed", "value",
            "value_box", "native", "abstract", 0
        };
 
        try {
           // 初期化
           ORB orbobj = ORB.init(args, null);
 
           // リポジトリオブジェクトの取り出し
           org.omg.CORBA.Object ir_in_obj =
               orbobj.resolve_initial_references(
                       "InterfaceRepository");
           Repository repository =
               RepositoryHelper.narrow(ir_in_obj);
 
           // リポジトリオブジェクトから
           // InterfaceDefオブジェクトだけを取り出す
           // CORBA_dk_Interface   : 取り出すのはインタフェースのみ
           // true         :継承されたオブジェクトは含まない
           //-1          : 数量制限なし
           org.omg.CORBA.ContainerPackage.Description descseq[] =
               repository.describe_contents(
                   DefinitionKind.dk_Interface, true, -1);
 
           // シーケンスの最初のオブジェクトをnarrowする
           InterfaceDef intfobj =
                   InterfaceDefHelper.narrow(
                   descseq[0].contained_object);
 
           // インタフェース情報を取り出す
           org.omg.CORBA.InterfaceDefPackage.FullInterfaceDescription
               intfdesc = intfobj.describe_interface();
 
           // インタフェース名
           System.out.println("interface " + intfdesc.name + "{");
 
           // オペレーションのシーケンスから1つ取り出す
           OperationDescription opedesc = intfdesc.operations[0];
 
           // オペレーションのモード
           if(opedesc.mode == OperationMode.OP_ONEWAY)
               System.out.println("    oneway ");
 
           // パラメータのシーケンスから1つ取り出す
           ParameterDescription paradesc = opedesc.parameters[0];
 
           // 戻り値の型, オペレーション名, 引数のモード, 引数を表示
           System.out.println("    "
               + tckind[opedesc.result.kind().value()] + " "
               + opedesc.name + "("
               + opemode[paradesc.mode.value()] + " "
               + tckind[paradesc.type.kind().value()]  + " "
               + paradesc.name + ")");
 
           System.out.println("};");
        } catch(Exception e) {
           System.out.println("ERROR : " + e);
        }
    }
}
org.omg.CORBA.Container.describe_contents()は、そのオブジェクトが内包しているオブジェクトの一覧をorg.omg.CORBA.ContainerPackage.Descriptionの配列で返します。上記の例ではInterfaceDefに限定して検索をしています。 org.omg.CORBA.ContainerPackage.Descriptionクラスの定義は以下のとおりです。
package org.omg.CORBA.ContainerPackage;
 
final public class Description {
    // instance variables
    public org.omg.CORBA.Contained contained_object;
    public org.omg.CORBA.DefinitionKind kind;
    public org.omg.CORBA.Any value;
 
    // constructors
    public Description(
       org.omg.CORBA.Contained _contained_object,
       org.omg.CORBA.DefinitionKind _kind, org.omg.CORBA.Any_value
    ) {
        contained_object = _contained_object;
        kind = _kind;
        value = _value;
    }
 
    public Description() {}
 
}
contained_objectにはInterfaceDefオブジェクトが入っています。そこで、org.omg.CORBA.InterfaceDef.describe_interface()を使って、そのorg.omg.CORBA.InterfaceDefオブジェクトが内包しているオペレーションのリストを取り出します。オペレーションのリストはorg.omg.CORBA.InterfaceDefPackage.FullInterfaceDescriptionとして返されます。 org.omg.CORBA.InterfaceDefPackage.FullInterfaceDescriptionクラスの定義は以下のとおりです。
package org.omg.CORBA.InterfaceDefPackage;
 
final public class FullInterfaceDescription {
    // instance variables
    public java.lang.String name;
    public java.lang.String id;
    public java.lang.String defined_in;
    public java.lang.String version;
    public org.omg.CORBA.OperationDescription[] operations;
    public org.omg.CORBA.AttributeDescription[] attributes;
    public java.lang.String[] base_interfaces;
    public org.omg.CORBA.TypeCode type;
    public boolean is_abstract;
 
    // constructors
    public FullInterfaceDescription(
        java.lang.String _name,
        java.lang.String _id,
        java.lang.String _defined_in,
        java.lang.String _version,
        org.omg.CORBA.OperationDescription[] _operations,
        org.omg.CORBA.AttributeDescription[] _attributes,
        java.lang.String[] _base_interfaces,
        org.omg.CORBA.TypeCode _type,
        boolean _is_abstract
    ) {
        name = _name;
        id = _id;
        defined_in = _defined_in;
        version = _version; operations = _operations;
        attributes = _attributes;
        base_interfaces = _base_interfaces; type = _type;
        is_abstract = _is_abstract;
    }
 
    public FullInterfaceDescription() {}
}
さらに、operationsから目的のオペレーションの型情報を取り出します。 operationsはorg.omg.CORBA.OperationDescriptionクラスの配列です。org.omg.CORBA.OperationDescriptionクラスの定義を以下に示します。
package org.omg.CORBA;
 
final public class OperationDescription {
    /* instance variables*/
    public java.lang.String name;
    public java.lang.String id;
    public java.lang.String defined_in;
    public java.lang.String version;
    public org.omg.CORBA.TypeCode result;
    public OperationMode mode;
    public java.lang.String[] contexts;
    public ParameterDescription[] parameters;
    public ExceptionDescription[] exceptions;
    /* constructors*/
    public OperationDescription(
        java.lang.String _name,
        java.lang.String _id,
        java.lang.String _defined_in,
        java.lang.String _version,
        org.omg.CORBA.TypeCode _result,
        OperationMode _mode,
        java.lang.String[] _contexts,
        ParameterDescription[] _parameters,
        ExceptionDescription[] _exceptions
    ) {
        name = _name;
        id = _id;
        defined_in = _defined_in;
        version = _version;
        result = _result;
        mode = _mode;
        contexts = _contexts;
        parameters = _parameters;
        exceptions = _exceptions;
    }
 
    public OperationDescription() {}
}
parametersからパラメータ情報を取り出します。 parametersはorg.omg.CORBA.ParameterDescriptionクラスの配列です。org.omg.CORBA.ParameterDescriptionクラスの定義を以下に示します。
// 引数の種別
// PARAM_IN : inパラメータ
// PARAM_OUT : outパラメータ
// PARAM_INOUT : inoutパラメータ
package org.omg.CORBA;
final public class ParameterMode {
    private int _v;
    public static final int _PARAM_IN = 0;
    public static final int _PARAM_OUT = 1;
    public static final int _PARAM_INOUT = 2;
    public static final ParameterMode PARAM_IN = new ParameterMode(_PARAM_IN);
    public static final ParameterMode PARAM_OUT = new ParameterMode(_PARAM_OUT);
    public static final ParameterMode PARAM_INOUT = new ParameterMode(_PARAM_INOUT);
    public int value() { return _v; }
    private ParameterMode(int v) { _v = v; }
    ...
}
 
// ParameterDescription
package org.omg.CORBA;
final public class ParameterDescription {
    // instance variables public java.lang.String name;
    public org.omg.CORBA.TypeCode type; public IDLType type_def; public ParameterMode
    mode;
    // constructors
    public ParameterDescription(
        java.lang.String _name,
        org.omg.CORBA.TypeCode _type,
        IDLType _type_def,
        ParameterMode _mode
    ) {
        name = _name;
        type = _type;
        type_def = _type_def;
        mode = _mode;
    }
    public ParameterDescription() {}
}
org.omg.CORBA.OperationDescriptionクラスのメンバexceptionsがnull以外ならば、exceptionsからユーザ定義例外情報を取り出します。 exceptionsはorg.omg.CORBA.ExceptionDescriptionクラスの配列です。org.omg.CORBA.ExceptionDescriptionクラスの定義を以下に示します。
package org.omg.CORBA;
 
final public class ExceptionDescription {
    /* instance variables*/
    public java.lang.String name;
    public java.lang.String id;
    public java.lang.String defined_in;
    public java.lang.String version;
    public org.omg.CORBA.TypeCode type;
    /* constructors*/
    public ExceptionDescription(
        java.lang.String _name,
        java.lang.String _id,
        java.lang.String _defined_in,
        java.lang.String _version,
        org.omg.CORBA.TypeCode _type
    ) {
        name = _name;
        id = _id;
        defined_in = _defined_in;
        version = _version;
        type = _type;
    }
 
    public ExceptionDescription() {}
}
これらのインタフェース情報により、DIIによる呼び出しに必要なパラメータを組み立てることができます。
2.2.7.5. Dynamic Invocation Interface (DII)
DIIを使うと、静的なオペレーション情報がクライアント側にリンクされていなくても、オペレーションを動的に呼び出すことができます。DIIはアプリケーション作成時に呼び出すインタフェースが決まっていないような特殊なアプリケーションを作成する場合にだけ使います。このようなアプリケーションの例としては、インタフェースの情報を動的に与えてオブジェクトをテストする汎用のテストツールなどが考えられます。

基本的な呼び出し

DIIを使って呼び出す手順として、引数リストなどを先に作っておきorg.omg.CORBA.Requestオブジェクトを作成する方法と、org.omg.CORBA.Requestオブジェクトを先に作っておく方法があります。 先に引数リストを作成するにはorg.omg.CORBA.ORB.create_listかorg.omg.CORBA.ORB.create_operation_listを使います。前者はorg.omg.CORBA.NVList.addなどを使って引数を1つずつ追加していかなければいけません。後者はインタフェースリポジトリに登録されているインタフェース情報をもとに自動的に追加されます。 org.omg.CORBA.Requestオブジェクトを作成するには、org.omg.CORBA._requestまたはorg.omg.CORBA._create_requestを使います。org.omg.CORBA._create_requestは引数リストにnullを設定しておいて、後から引数を追加することもできます。 作成したorg.omg.CORBA.Requestに引数を追加するには、org.omg.CORBA.Request.argumentsで引数リストを取り出す方法と、org.omg.CORBA.Request.add_in_argなどを使う方法があります。以下の例では後者を使います。 以下ではもっとも基本的な呼び出し手順を示します。 DIIによるオペレーションの呼び出しを行うには、org.omg.CORBA.Requestオブジェクトにオペレーションの情報(引数や戻り値の型など)をセットする必要があります。 org.omg.CORBA.Requestオブジェクトを作成するには、呼び出すオブジェクトのオブジェクトリファレンスが必要です。オブジェクトリファレンスの取得方法は静的な呼び出しと同じです。不特定のオブジェクトを呼び出すクライアントを作成する場合、名前サービスのorg.omg.CosNaming.NamingContext.resolveを使うのが一般的です。 また、不特定のオブジェクトを呼び出すクライアントを作成する場合は、インタフェースの定義を取得する必要があります。WebOTX Object Broker JavaTMではインタフェース定義を取得するには、org.omg.CORBA._get_interface_defを使います。org.omg.CORBA._get_interface_def()はあらかじめインタフェースリポジトリに登録されていたインタフェースを返します。
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
 
public class client {
    public static void main(String args[]) {
        try {
            // 何らかの手段でオブジェクトリファレンスを取得
            org.omg.CORBA.Object obj = ...;
 
            // インタフェースを定義しているオブジェクトの取得
            InterfaceDef intfobj = 
                org.omg.CORBA.InterfaceDefHelper.narrow(obj._get_interface());
                :
            // インタフェース情報を取り出す
            org.omg.CORBA.InterfaceDefPackage.FullInterfaceDescription
                intfdesc = intfobj.describe_interface();
                :
                :
intfdescにはオブジェクトリファレンスが指し示すオブジェクトのすべてのインタフェース情報が入っています。この中から、目的のオペレーションを選びます。
int count = intfdesc.operations.length;
OperationDescription opedesc = new OperationDescription();
 
for (int i = 0; i < count; i++) {
    // オペレーションのシーケンスから1つ取り出す
    opedesc = intfdesc.operations[i];
 
    // オペレーション名が一致するものを探す(仮に"myop"を探すことにします)
    if (opedesc.name.equals("myop")) {
        break;
    }
}
名前が一致するオペレーションを取得できたら、org.omg.CORBA.Requestオブジェクトを作成します。引数には、オペレーション名を渡します。
Request req = obj._request(opedesc.name);
作成したorg.omg.CORBA.Requestオブジェクトに戻り値の型を指定します。
req.set_return_type(opedesc.result);
オペレーションの引数を登録します。引数にはin, out, inoutの3種類があり、それぞれ別のメソッド(add_XXX_arg)が用意されています。引数はメソッドを呼び出すたびに引数リストの後ろへ追加されます。add_XXX_argは、org.omg.CORBA.Anyを返します。返されたorg.omg.CORBA.Anyに引数を挿入します。
count = opedesc.parameters.length;
 
ParameterDescription paradesc;
Any value;
 
for (int i = 0; i < count; i++) {
    // パラメータのシーケンスから1つ取り出す
    paradesc = opedesc.parameters[i];
 
    // パラメータの設定
    switch (paradesc.mode.value()){
    case ParameterMode._PARAM_IN:
        switch (paradesc.type.kind().value()) {
        case TCKind._tk_short:
            short in_param = ...;
            req.add_named_in_arg(paradesc.name).insert_short(in_param);
            break;
        ...
        }
        break;
    case ParameterMode._PARAM_INOUT:
        switch (paradesc.type.kind().value()) {
        case TCKind._tk_short:
            short inout_param = ...;
            req.add_named_inout_arg(paradesc.name).insert_short(inout_param);
            break;
        ...
        }
        break;
    default:
        req.add_named_out_arg(paradesc.name);
        break;
    }
}
引数の組み立てが終わったら、サーバの呼び出しを行います。サーバの呼び出し方法には単方向と双方向の2種類があります。これらはIDL定義をしたときに決まります。
if (opedesc.mode == OperationMode.OP_ONEWAY) {
    req.send_oneway();  // 単方向呼び出しのとき
}
else {
    req.invoke();       // 双方向呼び出しのとき
}
双方向呼び出しで、かつ、戻り値を持っていた場合は、戻り値を取得する必要があります。戻り値は、org.omg.CORBA.Any型で取得します。
if (opedesc.result.kind() != TCKind.tk_void) {
    switch(opedesc.result.kind().value()) {
    case TCKind._tk_short:
        short result = req.return_value().extract_short();
        break;
    ...
    }
}

リクエストの発行

リクエストの発行には、4つの方法があります。
2.2.7.6. Dynamic Skeleton Interface (DSI)
DSIを使うと、静的なオペレーション情報がサーバ側にリンクされていなくとも、オペレーションを動的に呼び出すことができます。 DIIはorg.omg.CORBA.Requestオブジェクトにオペレーションの情報(引数や戻り型など)をセットし、org.omg.CORBA.Request.invoke()を呼び出すことにより、オブジェクト呼び出しの入口を共通化しています。 DSIは、org.omg.PortableServer.DynamicImplementation.invoke()を共通の入口としています。オペレーションの情報はorg.omg.CORBA.ServerRequestオブジェクトに入ってい

DSIに必要なクラス

DSIを利用するためにはorg.omg.PortableServer.DynamicImplementationクラスを継承したクラスを作成します。このクラスがリクエストの処理を実装するDSIサーバント(DSIの実装オブジェクト)になります。DSIサーバントは、次のメソッドをオーバライドする必要があります。
package org.omg.PortableServer;
abstract public class Servant {
    ・・・    // methods for which the skeleton or application
    // programmer must provide an an implementation
    abstract public String[] _all_interfaces(POA poa, byte[] objectId);
    ・・・
}
package org.omg.PortableServer;
abstract public class DynamicImplementation extends Servant
{
     abstract public void invoke(org.omg.CORBA.ServerRequest request);
}
このクラスでは、各オペレーションのほかにinvokeメソッドと_all_interfacesメソッドの実装が必要です。 以下に、例を示します。
interface MyInterface {
    long MyOperation(in long arg);
};
public class MyDynamicImpl extends org.omg.PortableServer.DynamicImplementation {
    public MyDynamicImpl() {}
    private int MyOperation1(int a) {
        return a+1;
    }
    private int MyOperation2(int a) {
        return a+2;
    }
 
    String[] _ids = {"IDL:MyInterface:1.0"};
    public String[] _all_interfaces(org.omg.PortableServer.POA poa,
                                            byte[] objectId) {
        return _ids;
    }
 
    public void invoke(org.omg.CORBA.ServerRequest request) {
        try {
            org.omg.CORBA.ORB orb = _orb();
            org.omg.CORBA.Any rslt = orb.create_any();
            // どのオペレーションが呼ばれたか調べる
            String op_name = request.operation();
            if ("MyOperation".equals(op_name)) {
                // 引数のデコードに必要な情報をセットする
                org.omg.CORBA.NVList arg = orb.create_list(1);
                org.omg.CORBA.Any param =
                    arg.add(org.omg.CORBA.ARG_IN.value).value();
                param.type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_long));
                // 引数をデコードする
                request.arguments(arg);
                // IN引数を取り出す
                int a = param.extract_long();
                // オペレーションを呼び出す
                org.omg.CORBA.IntHolder ret = new org.omg.CORBA.IntHolder();
                // オブジェクトIDによりオペレーションを切り換える
                if ("myimpl1".equals(new String(_object_id())))
                    ret.value = MyOperation1(a);
                else
                    ret.value = MyOperation2(a);
                // 戻り値をrequestにセットする
                rslt.type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_long));
                rslt.insert_long(ret.value);
                request.set_result(rslt);
                return;
            }
            // エラー処理または例外をrequestにセットする
            // org.omg.CORBA.BAD_OPERATION例外をrequestにセットする場合
            org.omg.CORBA.Any exp = _orb().create_any();
            org.omg.CORBA.BAD_OPERATIONHelper.insert(
                exp, new org.omg.CORBA.BAD_OPERATION(
                    0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE));
        } catch (Exception e) {
            // エラー処理または例外をrequestにセットする
            e.printStackTrace();
        }
    }
 
    public static void main(String[]args) {
        try {
            org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
            org.omg.CORBA.Object o = orb.resolve_initial_references("RootPOA");
            org.omg.PortableServer.POA rootPOA =
                org.omg.PortableServer.POAHelper.narrow(o);
            org.omg.CORBA.Policy policies[] = new org.omg.CORBA.Policy[1];
            policies[0] = rootPOA.create_id_assignment_policy(
                org.omg.PortableServer.IdAssignmentPolicyValue.USER_ID);
            org.omg.PortableServer.POA myPOA =
                rootPOA.create_POA("myPOA", null, policies);
            // 文字列をオブジェクトIDに変換
            byte[] oid1 = new String("myimpl1").getBytes();
            byte[] oid2 = new String("myimpl2").getBytes();
            // MyOperation1,MyOperation2を呼び出すインスタンスを作成
            MyDynamicImpl impl1 = new MyDynamicImpl();
            MyDynamicImpl impl2 = new MyDynamicImpl();
            // サーバントを活性化
            myPOA.activate_object_with_id(oid1, impl1);
            myPOA.activate_object_with_id(oid2, impl2);
            // オブジェクトリファレンスを名前サーバに登録
            org.omg.CORBA.Object obj1 = myPOA.servant_to_reference(impl1);
            org.omg.CORBA.Object obj2 = myPOA.servant_to_reference(impl2);
            org.omg.CORBA.Object nsv =
                orb.resolve_initial_references("NameService");
            org.omg.CosNaming.NamingContext ns =
                org.omg.CosNaming.NamingContextHelper.narrow(nsv);
            org.omg.CosNaming.NameComponent ncseq1[] =
                {new org.omg.CosNaming.NameComponent("implobj1", "")};
            org.omg.CosNaming.NameComponent ncseq2[] =
                {new org.omg.CosNaming.NameComponent("implobj2", "")};
            ns.rebind(ncseq1, obj1);
            ns.rebind(ncseq2, obj2);
            // POAマネージャの活性化
            myPOA.the_POAManager().activate();
            orb.run();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
2.2.7.7. サーバ処理のスレッドポリシー選択
Object Broker Javaは、サーバ処理を実行するスレッドの動作を指定するスレッドポリシーの機能を提供しています。次のポリシーから選択することができます。 スレッドポリシーは、サーバプログラムのThreadPolicyプロパティにPerClientThreadもしくはPooledThreadを指定して設定します。設定しない場合の既定値はPerClientThreadです。 また、PooledThreadの場合のプール数をPooledThreadNumberプロパティで設定することができます。設定しない場合の既定値は10です。 設定方法は、本節の「Object Broker Javaのプロパティ設定」の項を参照してください。

Caution
スレッドポリシーの設定は、POAのThreadPolicyがORB_CTRL_MODELである場合のみ有効です。ポリシーにSINGLE_THREAD_MODELが設定されている場合は、PooledThreadであっても、単一のスレッドで順次処理されます。

Caution
PooledThreadが選択されているとき、onewayオペレーション、遅延同期オペレーション、複数リクエスト発行を使用すると、必ずしもクライアントからの要求順序通りにサーバがで処理されません(順序性が保証されません)。

2.2.7.8. 文字コードセット
CORBA呼び出しで文字列データを通信する場合に、サーバとクライアントとの間で、文字コードの意識が合っていることが重要です。 文字コードセットは、ネイティブコードセットとコンバージョンコードセットの2つに分けられます。
ネイティブコードセット ORBがプログラム内部で取り扱う文字コードを示します。通常は変更することはできません。
コンバージョンコードセット ネイティブコードセットに変換することが可能な文字コードを示します。
Object Broker Javaでは、以下のように設定しています。
char型、string型 wchar型、wstring型
ネイティブコードセット UCS2L1 UCS2L1
コンバージョンコードセット OSF_SJIS1 JIS_eucJP ISO8859-1 ISO646 UTF16

コードセットのネゴシエーション機能

CORBA仕様では、クライアントとサーバの間で文字および文字列のデータを受渡しするときに、どの文字コードセットを使用するかについて意識を合わせるためのネゴシエーション機能が規定されています。 コードセットのネゴシエーション機能では、おもに次の処理をおこないます。
  1. サーバ側の ORB は、通信に使用することができるコードセットをオブジェクトリファレンスに設定します。
  2. クライアント側の ORB は、オブジェクトリファレンスに設定されたコードセットが使用可能であれば、そのコードセットで通信を行います。

Caution
コードセットのネゴシエーション機能を使用するためには、IIOP および GIOP のバージョンが1.1以上である必要があります(Object Brokerは1.1もしくは1.2で動作しますので、通常は指定する必要はありません)。IIOP および GIOP のバージョンが1.0である場合は、char 型、string 型はISO8859-1 を、wchar 型、wstring 型は UCS2L1 を使用して通信します。

コンバージョンコードセットの変更

コンバージョンコードセットは、ConversionCodeSetsプロパティ、ConversionCodeSetsWプロパティを設定することによって変更することができます。

Caution
既定値の設定で通信をおこなうことが可能ですので、通常は設定を変更する必要はありません。

char型、string型のコンバージョンコードセットで指定可能なコードセットは下表のとおりです。太字は指定を変更しなかった場合の既定値です。UCS2L1はネイティブコードセットに設定されています。
コードセット名 コードセット番号 説明 エンコーディング
ISO8859-1 0x00010001 ISO 8859-1:1987; Latin Alphabet No. 1

ISO8859-2 0x00010002 ISO 8859-2:1987; Latin Alphabet No. 2 8859_2
ISO8859-3 0x00010003 ISO 8859-3:1988; Latin Alphabet No. 3 8859_3
ISO8859-4 0x00010004 ISO 8859-4:1988; Latin Alphabet No. 4 8859_4
ISO8859-5 0x00010005 ISO/IEC 8859-5:1988; Latin-Cyrillic Alphabet 8859_5
ISO8859-6 0x00010006 ISO 8859-6:1987; Latin-Arabic Alphabet 8859_6
ISO8859-7 0x00010007 ISO 8859-7:1987; Latin-Greek Alphabet 8859_7
ISO8859-8 0x00010008 ISO 8859-8:1988; Latin-Hebrew Alphabet 8859_8
ISO8859-9 0x00010009 ISO/IEC 8859-9:1989; Latin Alphabet No. 5 8859_9
ISO646 0x00010020 ISO 646:1991 IRV (International Reference Version)

UCS2L1 0x00010100 ISO/IEC 10646-1:1993; UCS-2, Level 1

JIS0201 0x00030001 JIS X0201:1976; Japanese phonetic characters JIS
JIS0208:1978 0x00030004 JIS X0208:1978 Japanese Kanji Graphic Characters JIS
JIS0208:1983 0x00030005 JIS X0208:1983 Japanese Kanji Graphic Characters JIS
JIS0208 0x00030006 JIS X0208:1990 Japanese Kanji Graphic Characters JIS
JIS0212 0x0003000a JIS X0212:1990; Supplementary Japanese Kanji Graphic Chars JIS
JIS_eucJP 0x00030010 JIS eucJP:1993; Japanese EUC EUCJIS
OSF_UJIS 0x05000010 OSF Japanese UJIS EUCJIS
OSF_SJIS1 0x05000011 OSF Japanese SJIS-1 SJIS
OSF_SJIS2 0x05000012 OSF Japanese SJIS-2 SJIS
UTF8 0x05010001 X/Open UTF-8; UCS Transformation Format 8 (UTF-8)

JVC_eucJP 0x05020001 JVC_eucJP EUCJIS
JVC_SJIS 0x05020002 JVC_SJIS SJIS
Cp437 0x100201b5 IBM-437 (CCSID 00437); PC USA Cp437
Cp850 0x10020352 IBM-850 (CCSID 00850); Multilingual IBM PC Data-MLP 222 Cp850
Cp852 0x10020354 IBM-852 (CCSID 00852); Multilingual Latin-2 Cp852
Cp855 0x10020357 IBM-855 (CCSID 00855); Cyrillic PC Data Cp855
Cp857 0x10020359 IBM-857 (CCSID 00857); Turkish Latin-5 PC Data Cp857
Cp861 0x1002035d IBM-861 (CCSID 00861); PC Data Iceland Cp861
Cp862 0x1002035e IBM-862 (CCSID 00862); PC Data Hebrew Cp862
Cp863 0x1002035f IBM-863 (CCSID 00863); PC Data Canadian French Cp863
Cp864 0x10020360 IBM-864 (CCSID 00864); Arabic PC Data Cp864
Cp866 0x10020362 IBM-866 (CCSID 00866); PC Data Cyrillic 2 Cp866
Cp869 0x10020365 IBM-869 (CCSID 00869); Greek PC Data Cp869
Cp874 0x1002036a IBM-874 (CCSID 00874); Thai PC Display Extended SBCS Cp874
Cp932 0x100203a4 IBM-932 (CCSID 00932); Japanese PC Data Mixed MS932
Cp1250 0x100204e2 IBM-1250 (CCSID 01250); MS Windows Latin-2 Cp1250
Cp1251 0x100204e3 IBM-1251 (CCSID 01251); MS Windows Cyrillic Cp1251
Cp1252 0x100204e4 IBM-1252 (CCSID 01252); MS Windows Latin-1 Cp1252
Cp1253 0x100204e5 IBM-1253 (CCSID 01253); MS Windows Greek Cp1253
Cp1254 0x100204e6 IBM-1254 (CCSID 01254); MS Windows Turkey Cp1254
Cp1255 0x100204e7 IBM-1255 (CCSID 01255); MS Windows Hebrew Cp1255
Cp1256 0x100204e8 IBM-1256 (CCSID 01256); MS Windows Arabic Cp1256
Cp1257 0x100204e9 IBM-1257 (CCSID 01257); MS Windows Baltic Cp1257
wchar 型、wstring 型で指定可能なコードセットは以下のとおりです。太字は指定を変更しなかった場合の既定値です。UCS2L1はネイティブコードセットに設定されています。
コードセット名 コードセット番号 説明 エンコーディング
UCS2L1 0x00010100 ISO/IEC 10646-1:1993; UCS-2, Level 1

UTF16 0x00010109 ISO/IEC 10646-1:1993; UTF-16, UCS Transformation Format 16-bit form

コードセットとエンコーディング

Java VMは、内部的な文字コードとしてUnicodeを用います。したがって、通信で使用されている文字コードがUnicodeではない場合、文字コードを変換する必要があります。 通信で使用されるコードセットがUCS2L1, ISO8859-1, ISO646, UTF-8, UTF-16の場合は、Object Broker Java独自の機能によってコード変換をおこないます。それ以外のコードセットが通信に使用された場合は、Javaの機能によってコード変換をおこないます。 それぞれの文字コードセットに対応するエンコーディングは上表のとおりです。また、CodeSetEncoding プロパティを設定することによって文字コードセットに対応するエンコーディング名を変更することができます。

文字化けの発生について

サーバとクライアントのうち、一方がC++、もう一方がJavaである場合、通常はコードセットのネゴシエーションによって通信に使用されるコードセットにOSF_SJIS1(シフトJIS)が選択されます。 このとき、既定値では、シフトJISとUnicodeの変換のためのエンコーディングにSJISを使用しますが、下表に示す文字で文字化けが発生する場合があります。文字化けが発生する文字が以下に該当する場合は、CodeSetEncoding プロパティに「OSF_SJIS1=MS932」と設定してください。
文字 シフトJISでのコード
0x8160
0x8161
0x817C
¢ 0x8191
£ 0x8192
¬ 0x81CA
NEC 特殊文字 0x8740 - 0x87FC
IBM 拡張文字 (NEC 選定) 0xED40 - 0xEEFC
ユーザ定義文字 (外字領域) 0xF040 - 0xF9FC
IBM 拡張文字 0xFA40 - 0xFC4B

2.2.7.9. コードベース
valuetypeの実装クラスおよびValueFactoryの実装クラスをWebサーバからダウンロードする機能について説明します。

コードベースダウンロード機能

CORBAでは、valuetypeに関する情報をリモートの環境から取得するためのSendingContextRunTimeサービスが規定されています。 valuetypeの実装クラスおよびValueFactoryの実装クラスをローカルな環境に持っていないとき、HTTP を利用してWebサーバからダウンロードする機能をコードベースダウンロード機能と呼びます。実装クラスをダウンロードするためのURLのことをコードベースと呼びます。 通信する相手のORBからコードベースを取得し、valuetypeの実装クラスおよびValueFactoryの実装クラスをダウンロードして、valuetypeのインスタンスを作成する処理はObject Broker Javaが自動的におこないますので、アプリケーションで意識してプログラミングする必要はありません。 コードベースダウンロード機能を使用するためには、valuetypeの送信側のORBで、この機能を有効にするための設定が必要です。
コードベースダウンロード機能を有効にするための設定には以下の 3 つがあります。

コードベースの設定単位

コードベースの設定は、1つのプロセスの中で複数の設定を使い分けることができます。 サーバ側は、オブジェクトID毎に設定します。コードベースの設定は、そのオブジェクトIDに対応するサーバントにのみ有効になります。オブジェクトIDはPOA.activate_object()の戻り値として取得できます。 クライアント側は、ORB毎に設定します。コードベースの設定は、そのORBに対応するリクエストにのみ有効です。ORBはORB.init()の戻り値として取得できます。 アプリケーションのプログラムでオブジェクトID(クライアントではORB)と、設定を区別するためのコードベースプロパティ名を登録する必要があります。 登録はConfig.setCodeBaseIdent()を呼び出すことによっておこないます。登録した時点でコードベースプロパティ名に対応するコードベースプロパティファイルに記述されたURLからダウンロードが可能になります。 異なるオブジェクトID(クライアントではORB)に対して同じコードベースプロパティ名を登録すれば、同じ設定を使用することができます。 プログラム内でコードベースプロパティ名の登録をしないオブジェクトID(クライアントではORB)については、プロセスで共通の設定を使用することができます。

コードベースプロパティファイル

コードベースプロパティファイルは、valuetypeの実装クラスおよびValueFactoryの実装クラスをダウンロードするために、そのクラスファイルが置かれている場所を示すURLを記述するファイルです。 ただし、 コードベースプロパティファイルには ValueFactoryの実装クラスファイルのURLのみを記述します。 ValueFactoryの実装クラスでvaluetypeの実装クラスを使用していれば、そのクラスファイルも同時にダウンロードされますので、valuetypeの実装クラスファイルのURLを記述する必要はありません。
コードベースプロパティファイルは、テキストファイルとして作成します。行単位に複数のアイテムを空白もしくはタブで区切って記述します。構文は以下のとおりです。
* <URL> ... <URL>
<Repository-ID> <URL> ... <URL>
    :
    :
<Implementation-class> <URL> ...
<URL>
    :
    :
'*' で始まる行は、デフォルトの URL を記述します。<Repository-ID> での指定も <Implementation-class>での指定もない場合、デフォルトの URL から検索します。 いずれの指定でも URL を複数書くことができます。記述順に検索してダウンロードできた場合はそのクラスを使用します。 コードベースプロパティ名に対応するコードベースプロパティファイルのファイル名は、以下のようになります。 <コードベースプロパティ名>.cbp ファイルを格納するディレクトリはカレントディレクトリ (アプリケーションを実行したディレクトリ) になります。このディレクトリはCodeBasePropertyFileDirプロパティで変更できます。 プロセスで共通のコードベースプロパティファイルのファイル名は、以下のようになります。 カレントディレクトリ/codebase.conf このファイル名はCodeBasePropertyFileプロパティでディレクトリを含めた形で変更できます。(この指定はCodeBasePropertyFileDirプロパティより優先されます) Object Broker Javaでは、コードベースダウンロード機能を使用する場合、アプリケーションでセキュリティマネージャが設定されていなければ、RMISecurityManagerを設定して使用します(アプレットではブラウザによってセキュリティマネージャが設定されます)。 そのため、アクセス権の設定をポリシーファイルに記述する必要があります。
アプリケーションの場合:
grant {
    permission java.util.PropertyPermission "*", "read, write";
    permission java.io.FilePermission "${user.home}\\orb.properties", "read";
    permission java.io.FilePermission "${java.home}\\lib\\orb.properties", "read";
    permission java.lang.RuntimePermission "getClassLoader";
    permission java.io.FilePermission "<コードベースプロパティファイル名>", "read";
    permission java.net.SocketPermission "<WebサーバのIPアドレス>[:<Webサーバのポート番号>]", "connect, resolve";
    permission java.net.SocketPermission "<サーバプロセスが動作するマシン名>[:<ポート番号>]", "connect, resolve";
    permission java.net.SocketPermission "<サーバAPが動作するマシン名>[:<ポート番号>]", "connect, resolve";
    permission java.net.SocketPermission "<クライアントAPが動作するマシン名>[:<ポート番号>]", "accept, resolve";
};
アプレットの場合:
grant {
    permission java.io.FilePermission "<コードベースプロパティファイル名>", "read";
    permission java.net.SocketPermission "<WebサーバのIPアドレス>[:<Webサーバのポート番号>]", "connect, resolve";
};
2.2.7.10. クライアント側コネクションの強制切断
クライアントとサーバとの間で確立されたコネクションは要求が完了した後も再利用のために保持しています。システム構成によっては、利用頻度の低いコネクションが保持されたままになり、システム資源を無駄に消費しているともいえます。これを解消するために、以下のメソッドを提供します。このメソッドはjp.co.nec.orb.ConnectionManagerクラスに定義されています。
処理中の要求が存在する場合には、その完了を待ち合わせて切断します。他のスレッドからの要求が破棄されることはありません。その待ち合わせ中に新たな要求を受け付けた場合にもさらに待ち合わせします。 また、コネクションが確立されているか否かを確認するために、以下のメソッドを提供します。このメソッドはjp.co.nec.orb.ConnectionManagerクラスに定義されています。

2.2.8. Object Brokerが提供するサービス

2.2.8.1. インタオペラブル名前サービスの使用方法
インタオペラブル名前サービスとは、リモートホスト上の初期サービスのオブジェクトリファレンスを相互に取得/提供するための仕組みです。
インタオペラブル名前サービスには2つの仕様案がOMGに提出されていました。1つはiioploc URL, iiopname URLで表される形式、もう1つはcorbalocURL, corbaname URLで表される形式です。両者は細部を除いてよく似ています。旧製品ObjectSpinnerでは、この2つの仕様をサポートしていました。
Object Brokerは、この2つの仕様との互換性を保持したまま、CORBA2.4.2(ptc/01-02-01)で正式に取り込まれた仕様に準拠しています。CORBA2.4.2ではcorbalocURL/corbanameURLの形式が採択され、rirプロトコルが追加されました。

オブジェクトリファレンスを文字列で表わす形式として、従来使われていたIOR形式のほかに、iioploc(corbaloc) URL形式とiiopname (corbaname) URL形式が追加されました。

iioploc URL形式とiiopname URL形式 iioploc URL形式とiiopname URL形式のシンタックスを説明します。
<iioploc> = "iioploc://"[<addr_list>]["/"<key_string>]    
<iiopname> = "iiopname://"[<addr_list>]["/"<string_name>]    
<addr_list> = [<address>","]* <address>    
<address> = [<version> <host> [":" <port>]]    
<version> = <major> "." <minor> "@" | ""    
<major> = IIOPのmajorバージョン番号    
<minor> = IIOPのminorバージョン番号    
<host> = ホスト名 | IPアドレス (未指定時はlocalhost)    
<port> = corbalocサーバのポート番号 (未指定時は2809)    
<key_string> = 文字列化したオブジェクトキー | ""    
<string_name> = 文字列化した名前シーケンス    
corbaloc URL形式とcorbaname URL形式 corbaloc URL形式とcorbaname URL形式のシンタックスを説明します。
<corbaloc> = "corbaloc:"<obj_addr_list>"/"<key_string>    
<corbaname> = "corbaname:"<corbaloc_obj>["#"<string_name>]    
<corbaloc_obj> = <obj_addr_list>["/"<key_string>]    
<obj_addr_list> = [<obj_addr>","]* <obj_addr>    
<obj_addr> = <prot_addr> | <future_prot_addr>    
<prot_addr> = <rir_prot_addr> | <iiop_prot_addr>    
<iiop_prot_addr> = <iiop_id><iiop_addr>    
<iiop_id> = <iiop_default> | <iiop_prot_token>":" ["//"]    
<iiop_default> = ":"    
<iiop_prot_token> = "iiop"    
<iiop_addr> = [<version> <host> [":" <port>]]    
<version> = <major> "." <minor> "@" | ""    
<major> = IIOPのmajorバージョン番号    
<minor> = IIOPのminorバージョン番号    
<host> = ホスト名 | IPアドレス (未指定時はlocalhost)    
<port> = corbalocサーバのポート番号 (未指定時は2809)    
<rir_prot_addr> = <rir_prot_token>":"    
<rir_prot_token> = "rir"    
<key_string> = 文字列化したオブジェクトキー | ""    
<string_name> = 文字列化した名前シーケンス    
初期サービスのオブジェクト指定 初期サービスのオブジェクトは、ORBInitRefプロパティで指定します。 「<ObjectID>=<ObjectURL>」の形式で指定してください。
オブジェクトURLの省略部分の指定 オブジェクトURLの省略部分は、ORBDefaultInitRefプロパティで指定します。 org.omg.CORBA.ORB.resolve_initial_references()が、指定された内容を補完したURLが表すオブジェクトリファレンスを返します。
WebOTX Object Brokerがサポートしているオブジェクトキー iioploc URLやiiopname URLに指定するオブジェクトキーとしてWebOTX Object Brokerがサポートしているオブジェクトキーは以下のとおりです。
オブジェクトキー オブジェクト
"NameService" そのホスト上の名前サーバのルートコンテキスト
"InterfaceRepository" そのホスト上のIRサーバのRepositoryオブジェクト
(注) iiopname URLでは、オブジェクトキーを指定できません。"NameService"に固定されます。

2.2.9. アプリケーション設計/コーディング時の秘訣

この章では、CORBAを使用したアプリケーションを作成するときに気をつけなければならないこと、デバッグ時のためにあらかじめ注意しておいた方が良いことについて説明します。
2.2.9.1. インタフェースの設計
アプリケーションを設計するときは、ネットワークを使用した通信(つまりCORBAを使用したメソッド呼び出し)の数が最小限になるように設計してください。ネットワークの通信速度も高速になってはきていますが、プロセッサの速度と比較すると非常に遅いことにかわりがありません。CORBAを使用すると、ネットワークの低レベルAPIを意識せずにコーディングすることが可能ですが、そのために 逆にネットワークのオーバヘッドのことを忘れてしまうこともあるようです。アプリケーションでネットワークを使用した通信がどの 程度行われるかは、IDLによるインタフェース定義の段階でほぼ確定してしまいます。CORBAを使用するということはネットワークによる通信を行うことだということを忘れないことが重要です。IDLの定義をアプリケーションの構築後に変更すると、後戻り工数が非常に大きくなります。IDL定義の段階でネットワーク遅延を考慮したインタフェースを定義することが重要です。たとえば、サーバオブジェクトから情報を取り出したいとしたとき、次のようなIDL記述があるとします。
interface StateObject {
 
    attribute long state1;
    attribute long state2;
    attribute long state3;
    attribute long state4;
 
};
このIDLで、StateObjectから、state1, state2, state3, state4の全ての情報を得たいとすると次のようなプログラムになります。
//Java
long s1 = StateObjectObj.state1();
long s2 = StateObjectObj.state2();
long s3 = StateObjectObj.state3();
long s4 = StateObjectObj.state4();
 
//C++
long s1 = StateObjectObj->state1();
long s2 = StateObjectObj->state2();
long s3 = StateObjectObj->state3();
long s4 = StateObjectObj->state4();
この場合、4回の通信が発生します。
これに対して、先のIDL定義を次のようにしていたとします。
interface StateObject {
 
    struct State {
        long state1;
        long state2;
        long state3;
        long state4;
    };
 
    State getState();
 
};
この場合、先程のクライアントプログラムは次のように書くことができます。
//Java
State state = StateObjectObj.getState();
long s1 = state.state1;
long s2 = state.state2;
long s3 = state.state3;
long s4 = state.state4;
 
//C++
State state = StateObjectObj->getState();
long s1 = state.state1;
long s2 = state.state2;
long s3 = state.state3;
long s4 = state.state4;
これだと、通信はgetStatus()の部分の1回しか起こりません。この例は非常に単純な例ですが、CORBAを使用した呼び出しがアプリケーション全体で最小限になるように、全体のオブジェクト構成を設計するように注意してください。

2.2.9.2. ロギングの組み込み
CORBAを用いたアプリケーションは、ネットワークを使用したプログラムであることを常に意識しておく必要があります。ネットワークを利用したアプリケーションでは、一つのCPU上で動作する単独のアプリケーションでは起きないようなエラーが起こります。ネットワークを使用して、多数のプログラムが多数のホスト間で協調して動作するプログラムを書く場合、ある一つのホストが障害を起こして動作しなくなったとしてもアプリケーション全体が動作しなくなるというようなことは許されません。
また、複数のマシンで協調動作するプログラムのどこかで何らかのエラーが起こった時に、あらかじめプログラム中にエラー情報を保存しておくしくみなどが組み込まれていないと、何が起こっているのかを判断することが非常に困難になります。
プログラムを作成するときは、エラー処理に細心の気を配ってコーディングしてください。たとえば、次に示すような足し算をする関数では、通常の1プロセスで動作するプログラムならばエラー処理を考慮する必要はありません。

//Java
public class adder {
      return l1+l2;
    }
}
 
//C++
class adder {
  public:
    long add(long l1, long l2) {
      return l1+l2;
    }
}
呼び出し側では
//Java
long result = adderobj.add(1L, 2L);
 
//C++
long result = addreobj->add(1L, 2L);
で十分であり、エラーが起こる余地はありません。
しかし、CORBAを使用したネットワーク経由での呼び出しの場合は、リモートホストがダウン中の場合や、リモートホストは動作中であるがネットワークに障害があり通信不能である場合等、いろいろな要因を考慮しなければなりません。このようなケースでは、CORBAは例外を発生させます。プログラムでは、この例外を捕らえ、ロギングのメカニズムを導入して、記録しておくことが障害解析のために必要です。これにより、アプリケーション全体で何が起こったかの把握が可能になります。
プログラム作成の時には、ロギング機構を組み込み、エラー(例外)を無視せずにこれに記録するように注意してください。
アプリケーションでCORBAの例外をロギングする場合には、最低以下の情報を出力することをお勧めします。
マイナーコードを記録しておくことにより、何が起こったかがわかります。システム例外の種別だけでは、具体的に何が起こったかがわからないことが多々あります。
また、注意すべき点として、システム例外やマイナーコードは、OMGの仕様で明確に規定されているわけではないことがあります。つまり、WebOTX Object Brokerではある例外を返すケースでも、別のベンダのORBでは別の種別の例外を返すケースがありえます。また、マイナーコードは完全にベンダ依存であり、個々のORBベンダがコードを定義することになっています。したがって、プログラム中で、システム例外Xが起こったときに処理Xを行い、システム例外Yが起こった時にYを行うという具合に、例外種別により、ロジックが違うようなコードを書くと、移植性の悪いプログラムになります。
ロギングの仕方は、アプリケーションの性質や使用するOSの持つ機能を考慮に入れて、アプリケーションで最適な方法を決定してください。一般的には、ファイルに記録しておく、OSがロギングの機能を提供している場合にはその機能を使用するなどが考えられます。

2.2.10. CORBA/IIOPによる通信の仕組み

CORBA2.0以上に準拠したORBは、他社のORBとの通信にIIOPを使用することが義務づけられています。IIOPはCORBA2.0で規定された通信のプロトコルです。WebOTX Object Brokerは、他社製のORBと通信する場合はもちろん、WebOTX Object Brokerを使用したアプリケーション同志の通信についてもIIOPを使用します。
プロトコルの詳細を理解する必要はありませんが、ある程度の知識は、性能上の問題が発生した時に役に立ちます。本章では、IIOPの動作の仕組みを説明し、どのようなコーディングをすると性能に影響するか等についての指針を示します。
IIOPはトランスポート層のプロトコルにTCP/IPを使用します。前提知識として、TCP/IPでは、通信相手のアドレス情報は、IPアドレス(マシンを識別するアドレス)とそのマシン内でのポート番号のペアであらわされます。IPアドレスは、32ビットの数値ですが、人間が分かりやすいような名前をホストにつけることもできます。この場合はオペレーティングシステムのhostsファイルに、ホスト名とIPアドレスのペアを記録しておくことにより、IPアドレスの代わりにホスト名を指定することもできるようになります。また、ホスト名とIPアドレスのペアの管理をDNSと呼ばれるサーバで行い、管理を一元的に行う機能を使用する場合もあります。ただし、TCP/IPのアドレス情報としては、あくまでIPアドレスが必要となりますので、ホスト名を指定した場合には最終的にIPアドレスへ変換する作業が一連の処理のなかのどこかで行われることになります。したがって、DNSの検索が遅い場合には、結果としてオブジェクト呼び出しも遅くなってしまいます。
CORBAではオブジェクト呼び出しの際にオブジェクトリファレンスと呼ばれるものをオブジェクトの識別子として使用します。
クライアントからオブジェクトを呼び出す時、次のようなコーディングをします。
// Java
obj.add(1L,2L);
 
// C++
obj->add(1L,2L);
 
※以降の図では、C++言語でのコーディング例は省略します。
objはリモートプロセスで実装されるCORBAオブジェクトのオブジェクトリファレンスです。
このコードが実行されるとCORBAの仕組みでどう動作するかをみていきます。
  1. サーバのアドレス情報の取得
    ORBが正しい相手にリクエストを転送するには、objで表されるCORBAオブジェクトが、ネットワーク上のどのマシンで動作する、どのプロセス上で動作しているのかという情報が必要になります。つまり、TCP/IPの用語でいうと、IPアドレスとポート番号を知る必要があります。実は、この二つの情報はobjのデータ構造にすでに含まれています(オブジェクトリファレンスにはこのほかにも様々な情報が含まれています)。したがって、ORBはこの情報を使用して、対象のプロセスにコネクトすることができます。objのデータ構造に含まれるホストアドレスはIPアドレスでもホスト名でもよいことになっています。
  2. マーシャリング(marshaling)
    次に、引数を対象オブジェクトに渡す必要がありますので、ORBは引数の1L、2Lをネットワークでの転送ができるようにメモリの連続領域に詰め込んでいきます。この処理をマーシャリング(marshaling)と呼びます。
  3. メッセージ送信
    マーシャリングが終了すると、ORBは先程確立したコネクションを使用して、IIOP_REQUESTという種別をヘッダにつけて、マーシャリングしたデータを送信します。IIOP_REQUESTというメッセージはクライアントからサーバに対してリクエストを発行する時に使用されるメッセージ種別です。
  4. サーバでのアンマーシャリング(unmarshaling)/実装オブジェクトの呼び出し
    IIOP_REQUESTを受信したサーバは、受信したメッセージの内容を個々の引数に分解します。この処理をアンマーシャリング (unmarshaling)と呼びます。その後、プログラマが定義した実装オブジェクトをこの引数を使用して呼び出します。実装オブジェクトからリターンするとORBには返り値やout引数が返されます。ORBはこの情報をマーシャリングし、IIOP_REQUESTを受け取ったTCP/IPコネクションを使用して、IIOP_REPLY種別を持ったヘッダを添付して送信します。IIOP_REPLYというメッセージは、サーバからクライアントに対してIIOP_REQUESTに対する返事を返す時に使用されるメッセージ種別です。
  5. クライアントでのアンマーシャリング/呼び出し元へのリターン
    IIOP_REPLYメッセージを受け取ったクライアントは、メッセージをアンマーシャルし、out引数、返り値情報を呼び出し元に返します。
このケースでは、クライアントからサーバオブジェクトのメソッド呼び出し1回につき、TCP/IPを使用した通信は2回行われており、必要とされる通信回数としては最も効率のよいものとなります。
しかし、IIOPでは次のようなシーケンスで呼び出しが起こることもあります。
上記1-3までは同じです。
4において、IIOP_REQUESTを受け取ったサーバが、別のサーバに要求を転送させることができます。 WebOTX Object Brokerで具体的にはどのような場合に転送が起こるかは後程説明しますが、ここでは、サーバが自分でIIOP_REQUESTを処理することができない場合に、実際に処理が可能なサーバに要求を転送させる場合の動きとして理解してください。
サーバがIIOP_REQUESTを受け取ったがその処理をできない場合、クライアントに対して、「すいませんが、わたしはこのリクエストを処理できません。これこれのアドレスに接続すれば処理をしてもらえますので、こちらにもう一度要求をだしてください。」という内容の返事を返します。IIOPのプロトコルでいうとIIOP_REPLYメッセージに特殊なフラグ(LOCATION_FORWARD)をたて、接続先のアドレス情報を含めて返事を返します。
LOCATION_FORWARDのリプライを受け取ったクライアントは、先程送信したリクエストをLOCATION_FORWARDで示されたアドレスに再送します。
以降の処理は最初の説明と同様になります。
上記の動作はIIOPで規定されているシーケンスであり、CORBA2.0準拠のORBでは常にサポートされているものです。ただし、1つの呼び出しに対して、クライアントから1つ目のサーバに対する要求、その返事、2つ目のサーバに対する要求、その返事というように、最低4回の通信が行われます。通常、一度LOCATION_FORWARDを受け取ったクライアントはアドレス情報を記憶しておき、2回目以降の同一オブジェクトリファレンスを使用した呼び出しでは、最初から実際に要求を処理できるサーバに要求を出すようになります。
// 足し算オブジェクトのリファレンスを取得。
obj = someobj.getAdderObj();
// 1回目の呼び出し。 4回の通信が起こる。
obj.add(...);
 
// 同一オブジェクトリファレンスによる2回目の呼び出し。
// 2回の通信しか起こらない。
obj.add(...);
しかし、これを次のように記述すると効率が非常に悪くなります。
// 足し算オブジェクトのリファレンス取得。
obj = someobj.getAdderObj();
 
// 1回目の呼び出し。4回の通信が起こる。
obj.add(...);
 
// 同一の足し算オブジェクトのリファレンス再取得。
obj = someobj.getAdderObj();
 
// 2回目の呼び出し。4回の通信が起こる。
obj.add(...);
上記のような記述では、同じオブジェクトに対する2回目の要求でも4回の通信が起きてしまいます。
上記の例は非常に単純なので実際にこのようなプログラムを書くことはないと思いますが、プログラム内の様々な処理の中で、結果として上記のようなケースになってしまっている可能性がないかどうか気をつけてください。
それでは、LOCATION_FORWARDはどのようなケースで発生するかを説明します。必ずしもこのケースに限られるわけではなく、いろいろな場面で、また個々のベンダの実装方法により違いがありますが、WebOTX Object Broker JavaTM では、サーバの自動起動(Automatic Activation)を実行する時に使用されます。
オブジェクトリファレンスには、ホストアドレスとポート番号が埋め込まれていますが、自動起動可能なサーバのオブジェクトリファレンスのポート番号として、WebOTX Object Broker C++ではOAD(Object Activation Daemon)のポート番号が埋め込まれています。
クライアントからの要求は、まずOADに送信されます。OADはリクエストメッセージ中の情報から、どのサーバを起動するかを判断しサーバを起動します。起動されたサーバは、これから使用する自分のポート番号をOADに通知します。通知を受けたOADは、クライアントに対してLOCATION_FORWARDメッセージを返します。この時、サーバから通知を受けた実際のポート番号も一緒に通知されます。LOCATION_FORWARDを受け取ったクライアントは、今度は実際のサーバオブジェクトにIIOP_REQUESTメッセージを送信するというように動作します。
IIOPには上記で説明した他にもメッセージ種別がありますが、オブジェクト呼び出しで何が起こるかを理解するには、上記の種別を理解すれば十分です。

2.2.11. Javaマッピング

IDL言語のそれぞれの構成要素をJava言語で使用する規則を定めているのがJava言語マッピングです。

2.2.11.1. 名前付けのルール
ユーザが定義した型やインタフェースがJavaの予約語と同じ名前のとき、名前が衝突しないように、IDLコンパイラが自動的に、定義名の前に"_"を付けて出力します。またJavaマッピングにより規定される次の名前についても、名前の衝突が起きないように"_"をつけて出力します。
名前が以下の場合には"_"をつけた名前が使用されるようになります。
2.2.11.2. module
IDLのmoduleは同じ名前でJavaのpackageにマッピングされます。そして、module内で定義されたすべてのIDLタイプは、そのpackageの中のJavaクラスやinterfaceとしてマッピングされます。

2.2.11.3. 基本型
基本型のマッピングは下表のとおりです。各型で例外名の書かれているものは、マーシャリング時にデータのサイズや内容が調べられ、規定どおりでなければそれぞれの例外が返ることを示します。
IDLでの型 Javaでの型 Holder 例外
boolean boolean BooleanHolder  
char char CharHolder CORBA::DATA_CONVERSION
wchar char CharHolder CORBA::DATA_CONVERSION
octet byte ByteHolder  
string java.lang.String StringHolder CORBA::BAD_PARAM CORBA::DATA_CONVERSION
wstring java.lang.String StringHolder CORBA::BAD_PARAM  CORBA::DATA_CONVERSION
short short ShortHolder  
unsigned short short ShortHolder  
long int IntHolder  
unsigned long int IntHolder  
long long long LongHolder  
unsigned long long long LongHolder  
float float FloatHolder  
double double DoubleHolder  
fixed java.math.BigDecimal FixedHolder CORBA::DATA_CONVERSION
Helperクラス すべてのユーザ定義型に対してHelperクラスが用意されます。名前はユーザ定義型の後ろに"Helper"がつきます。このクラスは次の用途に使われます。
Holderクラス outおよびinoutパラメータモードをサポートするためのクラスです。このクラスは、org.omg.CORBAパッケージに入っているすべてのIDL基本型や、すべての名前つきユーザ定義型(typedefは除く)に対して生成されます。ユーザ定義型に対するHolderクラス名はユーザ定義型名の後ろに"Holder"が付いたものです。
空のオブジェクトリファレンスやvaluetypeを表現するために、Javaのnullを用いることができます。ただし、空の文字列や配列を表現するためには、それぞれ長さ0の文字列や配列を用いなければなりません。

boolean IDL boolean定数のTRUEとFALSEは、Javaのtrueとfalseにマッピングされます。
char、wchar IDL charおよびIDL wcharはJavaのcharにマッピングされます。しかし、JavaのcharはUnicodeを表現する16ビットですが、IDLのcharは8ビットで表現します。IDL wcharは16ビットで表現されます。charが範囲外の値を表現していたなら、CORBA::DATA_CONVERSION例外が返ります。
octet IDL octetは8ビットで、Javaのbyteにマッピングされます。
string、wstring IDL stringおよびIDL wstringは固定長でも可変長でもjava.lang.Stringにマッピングされます。IDL stringは8ビットキャラクタの文字列を表します。IDL wstringは16ビットキャラクタの文字列を表します。型の違反があれば、CORBA::DATA_CONVERSION例外が返ります。固定長文字列の長さチェックで違反があれば、CORBA::BAD_PARAM例外が返ります。
fixed IDL fixedはjava.math.BigDecimalにマッピングされます。

2.2.11.4. 定数
interface内で定義された定数は、Javaのinterface内のクラス変数にマッピングされます。
interfaceの外で定義された定数は、定数の値を持ったvalueという名前のクラス変数を含む、定数と同じ名前のpublic interfaceにマッピングされます。

// IDL
module Example { 
    interface Face { 
        const long aLongerOne = -321;
    };
    const long aLongOne = -123;
};

// Generated Java 
package Example; 
public interface FaceOperations {
}
 
public interface Face extends FaceOperations,
org.omg.CORBA.Object,
                             
org.omg.CORBA.portable.IDLEntity { 
    int aLongerOne = (int) (-321L);
}
 
public interface aLongOne { 
    int value = (int) (-123L);
}

2.2.11.5. enum
IDL enumはenum型と同じ名前のJavaのclassにマッピングされます。
// IDL
enum EnumType {a, b, c};

// Generated Java 
public class EnumType implements
org.omg.CORBA.portable.IDLEntity { 
    public static final int _a = 0; 
    public static final EnumType a = new EnumType(_a); 
    public static final int _b = 1; 
    public static final EnumType b = new EnumType(_b); 
    public static final int _c = 2; 
    public static final EnumType c = new EnumType(_c); 
    public int value() {...} 
    public static EnumType from_int(int value) {...} 
 
    // コンストラクタ 
    protected EnumType(int) {...}
};

2.2.11.6. struct
IDL structは、それぞれのメンバ、デフォルトコンストラクタ、各メンバを引数にとるコンストラクタをもつ、同じ名前のJavaのfinal classにマッピングされます。

2.2.11.7. union
IDL unionは、次のメソッドをもつJavaのfinal classにマッピングされます。
型名やメンバ名が弁別子名と衝突した場合は、弁別子のメソッド名は "_" を付けたものになります。
メンバアクセスメソッドと変更メソッドはメンバ名と同じ名前でオーバロードされます。値をセットする前にアクセスメソッドが呼ばれたときは、CORBA::BAD_OPERATION例外が返ります。
デフォルトcaseラベルのメンバの変更メソッドは、デフォルト値を弁別子にセットします。また、弁別子の値を明示的に指定できる変更メソッドも生成されます。
弁別子にセットできるすべてのラベルがcaseラベルとして定義されているとき、さらにデフォルトcaseラベルを定義することはできません。このときはIDLコンパイラがエラーを通知します。
デフォルト変更メソッド__default()は、デフォルトcaseラベルが明示的に定義されなかったときや、弁別子にセットできるすべてのラベルがcaseラベルとして定義されなかったときに生成されます。


2.2.11.8. sequence
IDL sequenceは、同じ名前のJavaの配列にマッピングされます。固定長シーケンスの場合、ストリームへの書込み時に長さがチェックされます。長さに違反していたらCORBA::MARSHAL例外が返ります。

2.2.11.9. array
IDL arrayはIDL固定長sequenceと同じ方法でマッピングされます。長さ違反チェックはマーシャリング時に行われ、違反していたらCORBA::MARSHAL例外が返ります。

2.2.11.10. interface
interfaceクラス IDL interfaceは同じ名前のJavaのpublic interfaceにマッピングされます。Javaのinterfaceはorg.omg.CORBA.Objectインタフェースを基底インタフェースとします。
IDL operationは、対応するJava interfaceのメソッドにマッピングされます。
interfaceのHelperクラスにはstaticのnarrowメソッドが追加されます。これは、基底インタフェースのorg.omg.CORBA.ObjectからIDL interfaceに対応するJava interfaceに変換するためのメソッドです。narrowの実行に失敗したら、CORBA::BAD_PARAM例外が返ります。
nilオブジェクトリファレンスの値はJavaのnullを使います。
IDL attributeはJavaの取り出しと書き替えの2つのメソッドにマッピングされます。これらは同じ名前でオーバロードされます。IDL readonly attributeは取り出しメソッドのみにマッピングされます。
IDLでinterfaceの継承があるときは、直接Javaのinterfaceの継承を使います。

abstract interface IDL abstract interfaceは、オブジェクトリファレンスとvaluetypeのどちらも扱うことが可能です。通常のIDL interfaceと同様に、同じ名前のJavaのpublic interfaceにマッピングされますが、org.omg.CORBA.Objectインタフェースの明示的な継承はしていません。
Parameter Passing Modes Javaは、渡された引数の値を変更することができません。このため、呼び出し元から渡された値を変更するためのしくみとして、Holderクラスが存在します。IDLのinパラメタに対してはJavaマッピングで規定されているJavaの型を直接渡します。これに対してout引数については、メソッドからの変更結果がHolderオブジェクトに挿入されて返ってきます。inout引数については呼び出し元からHolderに引数の値を挿入してメソッド呼び出しを行い、メソッドからの返却値がHolderに設定された状態で返ってきます。

2.2.11.11. exception
IDL exceptionのマッピングはstructとほとんど同じです。Javaのクラスにマッピングされ、そのクラスは、メンバに対応したインスタンス変数と、デフォルトコンストラクタ、メンバの初期値を指定できるコンストラクタを持ちます。
CORBAシステム例外(SystemException)は、java.lang.RuntimeExceptionを継承します。
ユーザ例外(UserException)は、java.lang.Exceptionを継承します。SystemExceptionはJavaのコード中にthrows句やcatch節が必要ありませんが、UserExceptionに関しては明示的にthrows句もしくはcatch節を記述する必要があります。

SystemException CORBAシステム例外は、org.omg.CORBA.SystemExceptionから継承したJavaのpublic final クラスにマッピングされます。それぞれのIDL標準例外は下表のとおりです。
IDLの例外 Javaクラス名
CORBA::UNKNOWN org.omg.CORBA.UNKNOWN
CORBA::BAD_PARAM org.omg.CORBA.BAD_PARAM
CORBA::NO_MEMORY org.omg.CORBA.NO_MEMORY
CORBA::IMP_LIMIT org.omg.CORBA.IMP_LIMIT
CORBA::COMM_FAILURE org.omg.CORBA.COMM_FAILURE
CORBA::INV_OBJREF org.omg.CORBA.INV_OBJREF
CORBA::NO_PERMISSION org.omg.CORBA.NO_PERMISSION
CORBA::INTERNAL org.omg.CORBA.INTERNAL
CORBA::MARSHAL org.omg.CORBA.MARSHAL
CORBA::INITIALIZE org.omg.CORBA.INITIALIZE
CORBA::NO_IMPLEMENT org.omg.CORBA.NO_IMPLEMENT
CORBA::BAD_TYPECODE org.omg.CORBA.BAD_TYPECODE
CORBA::BAD_OPERATION org.omg.CORBA.BAD_OPERATION
CORBA::NO_RESOURCES org.omg.CORBA.NO_RESOURCES
CORBA::NO_RESPONSE org.omg.CORBA.NO_RESPONSE
CORBA::PERSIST_STORE org.omg.CORBA.PERSIST_STORE
CORBA::BAD_INV_ORDER org.omg.CORBA.BAD_INV_ORDER
CORBA::TRANSIENT org.omg.CORBA.TRANSIENT
CORBA::FREE_MEM org.omg.CORBA.FREE_MEM
CORBA::INV_IDENT org.omg.CORBA.INV_IDENT
CORBA::INV_FLAG org.omg.CORBA.INV_FLAG
CORBA::INTF_REPOS org.omg.CORBA.INTF_REPOS
CORBA::BAD_CONTEXT org.omg.CORBA.BAD_CONTEXT
CORBA::OBJ_ADAPTER org.omg.CORBA.OBJ_ADAPTER
CORBA::DATA_CONVERSION org.omg.CORBA.DATA_CONVERSION
CORBA::OBJECT_NOT_EXIST org.omg.CORBA.OBJECT_NOT_EXIST
CORBA::TRANSACTION_REQUIRED org.omg.CORBA.TRANSACTION_REQUIRED
CORBA::TRANSACTION_ROLLEDBACK org.omg.CORBA.TRANSACTION_ROLLEDBACK
CORBA::INVALID_TRANSACTION org.omg.CORBA.INVALID_TRANSACTION
CORBA::INV_POLICY org.omg.CORBA.INV_POLICY
CORBA::CODESET_INCOMPATIBLE org.omg.CORBA.CODESET_INCOMPATIBLE
UserException ユーザ例外は、org.omg.CORBA.UserExceptionから継承したJavaのfinal classにマッピングされます。クラスの内容はIDL structに対して生成されるものと同様です。HelperクラスとHolderクラスも生成されます。生成されたJavaクラスは完全なコンストラクタを持ち、String型のパラメータはベースのUserExceptionクラスのコンストラクタを呼ぶ時のidに連結されます。
例外がネストしたIDLスコープ内で定義された場合は、Javaクラス名はそのスコープ内で定義されます。そうでなければ、Javaクラス名は例外が定義されているIDL moduleに対応したJava package内に定義されます。


2.2.11.12. Any
IDL any型はJavaクラスorg.omg.CORBA.Anyにマッピングされます。このクラスはあらかじめ定義されているすべての型のインスタンスを出し入れするメソッドを持っています。もし取り出しオペレーションで型がマッチしなければ、CORBA::BAD_OPERATION例外が返ります。ユーザ定義型のための出し入れメソッドは、それぞれの型のHelperクラスで実装されます。
挿入オペレーションは値をセットして、TypeCodeを新たにセットします。
引数付きのtype(org.omg.CORBA.TypeCode)メソッドによってTypeCodeをセットすると、現在挿入されている値はクリアされ、Anyの内部の型として指定されたTypeCodeが設定されます。このオペレーションは、IDL out parameterをセットするときに使います。値をセットする前に値を取り出そうとしたときは、CORBA::BAD_OPERATION例外が返ります。
AnyのインスタンスはORB.create_any()で作成します。


2.2.11.13. Nested Type
IDLではインタフェースの中に型を定義できますがJavaでは許されていません。Javaのクラスにマッピングされる型がインタフェース内で定義されたときは、少し特殊なマッピングになります。まずインタフェース名に"Package"という名前をつけたパッケージを定義し、そのパッケージ内で、インタフェース内で定義されたクラスが定義されます。

2.2.11.14. typedef
IDL基本型のtypedefは、オリジナルの型にマッピングされます。つまり、基本型に対するtypedefが使用されているところでは、すべてtypedefのもとになったオリジナルの型を使用します。
配列とシーケンス以外のIDL型のtypedefは、オリジナルの型(基本型もしくはtypedefされていないユーザ定義型)にマッピングされます。
Helperクラスがすべてのtypedef型に対して生成されます。Holderクラスは、配列とシーケンスのtypedefに対してのみ生成されます。


2.2.11.15. valuetype
concrete valuetype IDL valuetypeは、同じ名前のJavaのabstractクラスと、<valuetype名>ValueFactoryという名前のJavaインタフェースにマッピングされます。また、HelperクラスとHolderクラスが生成されます。
valuetypeがマッピングされているabstractクラスは、定義されたステートに対応するインスタンス変数を持ちます。IDLでpublicと指定されたフィールドはpublicのインスタンス変数に、privateと指定されたフィールドはprotectedのインスタンス変数にマッピングされます。
オペレーションとattributeは、このvaluetypeが継承、サポートしているvaluetypeやインタフェース内で定義されたのものも含めて、abstractメソッドとして展開されます。valuetypeの実装者は、このJavaクラスを継承した実装クラスを定義して、これらのabstractメソッドの実装コードを記述します。
このJavaクラスは、IDLのvaluetype定義にcustom指定があるかどうかによって、org.omg.CORBA.portable.CustomValueかorg.omg.CORBA.portable.StreamableValue のどちらかを継承し、ValueBaseインタフェースの実装を提供します。custom指定がないvaluetypeのJavaクラスは、org.omg.CORBA.portable.Streamableインタフェースの実装を提供します。custom指定があるvaluetypeの場合、org.omg.CORBA.portable.CustomValueの実装は、valuetypeの実装者が行います。他のvaluetypeを継承する場合は、継承するvaluetypeにマッピングされたJavaクラスが継承されます。
ValueFactoryインタフェースは、org.omg.CORBA.portable.ValueFactoryを継承して、IDLでfactory宣言されたそれぞれのファクトリに対応するメソッドを含んでいます。メソッド名はファクトリ名と同じで、ファクトリの引数は IDL operationのパラメータと同じ方法で展開されます。valuetypeの実装者は、生成されたValueFactoryインタフェースのメソッドを実装したファクトリクラスを提供する必要があります。ファクトリがIDLで宣言されていないときは、ファクトリインタフェースは生成されません。この場合、valuetypeの実装者は、read_value()のメソッドを実装するためにorg.omg.CORBA.portable.ValueFactoryの実装クラスを作成します。
Object Broker Javaでは、ValueFactoryの実装クラスの雛形を、<valuetype名>DefaultFactoryという名前で生成します。すでに、この名前のファイルが存在する場合は上書きされません。この雛形ファイルは、ValueFactoryインタフェースを実装するJavaクラスで、valuetypeの実装クラス名を<valuetype名>Implとして記述しています。valuetypeの実装者は、この雛形ファイルのvaluetypeの実装クラス名部分を実装に合わせて書き換えることによって、ValueFactoryの実装クラスを作成することができます。

abstract valuetype IDL abstract valuetypeは同じ名前のJavaのpublic interfaceにマッピングされます。
abstract valuetype内に記述したIDL operationおよびIDL attributeに対応するメソッドは、abstractメソッドとして展開されます。
abstract valuetype自体を直接実装することはできません。abstract valuetypeを実装するには、これを継承するconcrete valuetypeを定義し、実装します。
Helper、Holderクラスはconcrete valuetypeと同様に展開されます。


2.2.11.16. boxed valuetype
boxed valuetypeには、Javaプリミティブ型にマッピングされるものと、同じ名前のJavaクラスにマッピングされるものがあります。Holderクラスは他のvaluetypeと同様に生成されます。Helperクラスも生成されますが、boxed valuetype固有の形式で展開されます。
boxed valuetypeの型がプリミティブ型(float, long, char, wchar, boolean, octetなど)の場合は、boxed valuetypeと同じ名前で生成されるJavaクラスにマッピングされます。このクラスは、boxed valuetypeのIDL型に対応する型の、valueという名前のpublicデータを1つだけ持っています。
boxed valuetypeの型がJavaクラス(string, wstring, enum, struct, sequence, array, any, interfaceなど)の場合は、boxed valuetypeはそのクラスにマッピングされます。


2.2.11.17. 複雑型のための読み書きAPI
Streamable Interface APIは、複雑型の値の読み出しおよび書き込みをサポートしています。これはHelperクラスのstaticメソッドとして実装されています。また、Holderクラスの中でもoutおよびinoutパラメータのcomplexデータタイプを読み書きするために使われます。

2.2.11.18. Streaming API
Streaming APIは、マッピングされたIDL型をストリームに対して読み書きするときに使用するAPIです。これらは、ORBが、パラメータをマーシャリングしたり、Anyにcomplexデータタイプを出し入れしたりするときに使います。
Streaming APIはorg.omg.CORBA.portableおよびorg.omg.CORBA_2_3.portableパッケージで定義されています。
OutputStreamはORBオブジェクトによって生成され、InputStreamはOutputStreamから生成されます。