Java IDL: 内容

IDL と Java のマッピング

5


5.1 はじめに

ここでは、IDL と Java 言語の完全なマッピングについて説明します。

設計に関する論理的な基礎については、「4. 全体設計の論理的基礎」を参照してください。

多くの場合、マッピングの例が示してあります。ただし、紹介されている例は断片的なコードで、あくまでも説明されている言語構造を例示するためだけのものです。通常、これらのコードを使う場合は、モジュールに埋め込んで Java パッケージにマッピングします。

5.2 名前

通常、IDL で使われている名前と識別子は、そのまま Java の名前と識別子にマッピングされます。マッピングされた Java コードで名前の衝突が発生した場合は、マッピングされた名前の前に下線 (_) を付けることで衝突が解決されます。

また、Java 言語の性質上、IDL の単一の構造が Java では異なる名前を持つ複数の構造にマッピングされる場合があります。「追加される」名前は、内容を表す接尾辞を付け加えて作成されます。たとえば、IDL のインタフェース foo は、Java のインタフェース foo、および追加される Java クラス fooHelperfooHolder にマッピングされます。

「追加される」名前がマッピングされたほかの IDL 名と衝突するような例外的な場合は、上記で説明した衝突解決ルールがほかの IDL 名のマッピングに適用されます。つまり、要求した「追加」名の命名と使用が優先されます。

たとえば、fooHelper または fooHolder という名前のインタフェースは、それぞれ _fooHelper または _fooHolder にマッピングされます。foo という名前のインタフェースが存在するかどうかは関係ありません。インタフェース fooHelper のヘルパークラスとホルダークラスの名前は、_fooHelperHelper および _fooHelperHolder になります。

通常、IDL の名前は同じ名前で Java の識別子にマッピングされますが、Java の予約語と衝突する場合は、衝突解決のルールが適用されます。

5.2.1 予約された名前

マッピングでは、マッピング自体の目的のために、いくつかの名前の使用が予約されています。このような名前を次に示します。

これらのキーワードの中で IDL の名前として有効なものを IDL のユーザ定義型またはインタフェースとして使用した場合、マッピングされた名前の前には下線 (_) が付きます。

5.3 モジュールのマッピング

IDL のモジュールは、同じ名前の Java のパッケージにマッピングされます。モジュールに含まれる IDL の型宣言はすべて、生成されるパッケージの中の対応する Java のクラス宣言やインタフェース宣言にマッピングされます。

どのモジュールにも囲まれていない IDL 宣言は、(名前のない) Java の大域スコープにマッピングされます。

5.3.1 例

// IDL
module Example {...}
// generated Java
package Example;
	...

5.4 基本型のマッピング

5.4.1 はじめに

次の表は、基本的なマッピングを示しています。IDL の型とそれをマッピングした Java の型が一致しない可能性がある場合については、表の「例外」の列に、発生する可能性のある CORBA の標準例外の一覧を示してあります。IDL のシステム例外がマッピングされる仕組みの詳細については、「5.13 例外のマッピング」を参照してください。

Java の型の範囲が IDL の型より「大きい」場合、不一致が発生する可能性があります。実行時に in パラメータとして (または inout に対する input として) 整列化される時点で、値は完全に検査されなければなりません。たとえば、Java の char は、IDL の char のスーパーセットになっています。

Java で unsigned 型を使う場合は、注意が必要です。Java 言語では unsigned 型はサポートされていないので、IDL の unsigned 型で表された大きな値が Java では負の整数値として正しく処理されるよう、ユーザは配慮する必要があります。

図 5-1 基本型のマッピング
IDL のデータ型
Java のデータ型
例外

boolean

boolean

 

char

char

CORBA::DATA_CONVERSION

wchar

char

 

octet

byte

 

string

java.lang.String

CORBA::MARSHAL

CORBA::DATA_CONVERSION

wstring

java.lang.String

CORBA::MARSHAL

short

short

 

unsigned short

short

 

long

int

 

unsigned long

int

 

long long

long

 

unsigned long long

long

 

float

float

 

double

double

 

詳細については、以下の節で説明します。

5.4.1.1 将来のサポート

将来的には、IDL の「新しい」拡張データ型である fixed と long double が、Java で直接サポートされる予定です。現在、JDK 1.0.2 ではこれらの型はサポートされていないため、実際問題として、ORB ベンダーによって広くサポートされるという状況にもまだ至っていません。これら 2 つの型は、次のようにマッピングされる予定です。

IDL のデータ型
Java のデータ型
例外

long double

???

 

fixed

java.math.BigDecimal

CORBA::DATA_CONVERSION

今後のバージョンの仕様では、このマッピングが標準的にサポートされるようになる予定です。

5.4.1.2 ホルダークラス

out と inout のパラメータ引き渡しモードをサポートするには、特別な「ホルダー」クラス群を使う必要があります。これらのクラスは、org.omg.CORBA パッケージの IDL の基本データ型のすべてで利用でき、typedef で定義されたものを除くすべての名前が指定されたユーザ定義型に対して生成されます。

IDL のユーザ定義型に対するホルダークラスの名前は、マッピングされた Java の型名のあとに Holder が付け加えられたものになります。

IDL の基本データ型に対するホルダークラスの名前は、IDL のデータ型がマッピングされた Java のデータ型の名前 (先頭文字は大文字) のあとに Holder が付け加えられたものになります。たとえば、IntHolder のようになります。ユーザ定義名との衝突の可能性については、「5.2 名前」を参照してください。

個々のホルダークラスには、インスタンスからのコンストラクタ、つまりデフォルトコンストラクタがあります。また、インスタンスの public メンバ value があり、これは型指定のある値です。デフォルトコンストラクタは、Java 言語で定義されている型の既定値を値のフィールドに設定します。boolean 型には false が、数値型と文字型には 0 が、文字列型には null が、オブジェクト参照には null が、それぞれ設定されます。

移植性のあるスタブとスケルトンをサポートするには、ユーザ定義型のホルダークラスは、org.omg.CORBA.portable.Streamable インタフェースも実装する必要があります。

基本型のホルダークラスの定義を、次に示します。Streamable インタフェースが実装されていないことに注意してください。これらのインタフェースは、org.omg.CORBA パッケージの中にあります。

// Java
package org.omg.CORBA;
final public class ShortHolder {
	public short value;
	public ShortHolder() {}
	public ShortHolder(short initial) {
		value = initial;
	}
}
final public class IntHolder {
	public int value;
	public IntHolder() {}
	public IntHolder(int initial) {
		value = initial;
	}
}
final public class LongHolder {
	public long value;
	public LongHolder() {}
	public LongHolder(long initial) {
		value = initial;
	}
}
final public class ByteHolder {
	public byte value;
	public ByteHolder() {}
	public ByteHolder(byte initial) {
		value = initial;
	}
}
final public class FloatHolder {
	public float value;
	public FloatHolder() {}
	public FloatHolder(float initial) {
		value = initial;
	}
}
final public class DoubleHolder {
	public double value;
	public DoubleHolder() {}
	public DoubleHolder(double initial) {
		value = initial;
	}
}
final public class CharHolder {
	public char value;
	public CharHolder() {}
	public CharHolder(char initial) {
		value = initial;
	}
}
final public class BooleanHolder {
	public boolean value;
	public BooleanHolder() {}
	public BooleanHolder(boolean initial) {
		value = initial;
	}
}
final public class StringHolder {
	public java.lang.String value;
	public StringHolder() {}
	public StringHolder(java.lang.String initial) {
		value = initial;
	}
}
final public class ObjectHolder {
	public org.omg.CORBA.Object value;
	public ObjectHolder() {}
	public ObjectHolder(org.omg.CORBA.Object initial) {
		value = initial;
	}
}
final public class AnyHolder {
	public Any value;
	public AnyHolder() {}
	public AnyHolder(Any initial) {
		value = initial;
	}
}
final public class TypeCodeHolder {
	public TypeCode value;
	public typeCodeHolder() {}
	public TypeCodeHolder(TypeCode initial) {
		value = initial;
	}
}
final public class PrincipalHolder {
	public Principal value;
	public PrincipalHolder() {}
	public PrincipalHolder(Principal initial) {
		value = initial;
	}
}
ユーザ定義型 <foo> に対するホルダークラスを、以下に示します。

// Java
final public class <foo>Holder 
	implements org.omg.CORBA.portable.Streamable {
	public <foo> value;
	public <foo>Holder() {}
	public <foo>Holder(<foo> initial) {}
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
	}

5.4.1.3 Java の null の使用

Java の null は、「null」オブジェクトの参照を表すためだけに使用できます。たとえば、空の文字列を表すには、null ではなく、長さが 0 の文字列を使う必要があります。配列についても同様です。

5.4.2 boolean

IDL の boolean 定数 TRUEFALSE は、Java の対応する boolean リテラル truefalse にマッピングされます。

5.4.3 文字型

Java の文字型データは符号なし 16 ビット長で Unicode 文字を表していますが、IDL の文字型データは 8 ビット長で文字セットの要素を表しています。型が安全に処理されるようにするため、メソッドの呼び出しでパラメータが整列化された時点で、Java CORBA の実行時環境は、IDL の char 型からマッピングされた Java の char 型のすべてについて、範囲の妥当性を明らかにします。char が文字セットで定義されている範囲の外にある場合は、例外 CORBA::DATA_CONVERSION がスローされます。

IDL の wchar は、Java のプリミティブ型 char にマッピングされます。

5.4.4 octet

IDL の octet 型のサイズは 8 ビットで、Java の byte 型にマッピングされます。

5.4.5 文字列型

IDL の string 型は、バウンド形式もアンバウンド形式も、java.lang.String にマッピングされます。文字列内の個々の文字に対する範囲検査と併せて、文字列のバウンド検査が整列化時に行われます。文字範囲の違反があると、例外 CORBA::DATA_CONVERSION が発生します。バウンドの違反がある場合は、例外 CORBA:: MARSHAL が発生します。

IDL の wstring 型は、バウンド形式もアンバウンド形式も、java.lang.String にマッピングされます。文字列のバウンド検査が、整列化時に行われます。バウンドの違反がある場合は、例外 CORBA:: MARSHAL が発生します。

5.4.6 整数型

整数の各型は、図 5-1 に示すようにマッピングされます。

5.4.7 浮動小数点型

IDL の float と double は、図 5-1 に示すようにマッピングされます。

5.4.8 固定小数点型の将来的なサポート

IDL の fixed 型は、Java の java.math.BigDecimal クラスにマッピングされます。サイズ違反がある場合は、例外 CORBA::DATA_CONVERSION が発生します。

fixed 型のサポートは、今後のバージョンで行われます。

5.4.9 long double 型の将来的なサポート

現在、Java は IDL の long double 型をサポートしていません。現時点では、この型が追加されるかどうか、また追加されるとすればいつか、そしてその場合はプリミティブ型になるのか、あるいは java.math.* の新しいパッケージ (たとえば java.math.BigFloat) になるのかなどについては、明らかになっていません。

long double 型に関する仕様の決定は、今後のバージョンで行われます。

5.5 ヘルパークラス

IDL のすべてのユーザ定義型には、Java の「ヘルパー」クラスが追加されます。ヘルパークラスの名前は、生成された型の名前に接尾辞 Helper が付け加えられたものになります。型での処理に必要な static メソッドが、いくつか提供されます。このようなメソッドの機能としては、その型について Any 型の挿入や抽出を行う操作、リポジトリ ID の取得、タイプコードの取得、ストリームからの型の読み出しやストリームへの型の書き込みなどがあります。

以下は、任意のユーザ定義の IDL 型 <typename> に対して生成される Java コードです。さらに、マッピングされた IDL インタフェースに対するヘルパークラスには、そのインタフェースに定義されたナロー変換オペレーションもあります。

// generated Java helper
public class <typename>Helper {
	public static void 
		insert(org.omg.CORBA.Any a, <typename> t) {...}
	public static <typename> extract(Any a) {...}
	public static org.omg.CORBA.TypeCode type() {...}
	public static String id() {...}
	public static <typename> read(
		org.omg.CORBA.portable.InputStream istream)
		{...}
	public static void write(
		org.omg.CORBA.portable.OutputStream ostream,
		<typename> value) 
		{...}

	// only for interface helpers
	public static 
		<typename> narrow(org.omg.CORBA.Object obj);
}
IDL インタフェースに関連付けられたヘルパークラスには、narrow メソッドも含まれています (「5.12 インタフェースのマッピング」を参照)。

5.5.1 例

// IDL - named type
struct st {long f1; string f2;};
// generated Java
public class stHelper {
	public static void insert(org.omg.CORBA.Any any,
		st s) {...}
	public static st extract(Any a) {...}
	public static org.omg.CORBA.TypeCode type() {...}
	public static String id() {...}
	public static st read(org.omg.CORBA.InputStream is) {...}
	public static void write(org.omg.CORBA.OutputStream os,
		 st s) {...}
}
// IDL - typedef sequence
typedef sequence <long> IntSeq;
// generated Java helper
public class IntSeqHelper {
	public static void insert(org.omg.CORBA.Any any,
		int[] seq);
	public static int[] extract(Any a){...}
	public static org.omg.CORBA.TypeCode type(){...}
	public static String id(){...}
	public static int[] read(
		org.omg.CORBA.portable.InputStream is)
		{...}
	public static void write(
		org.omg.CORBA.portable.OutputStream os,
		int[] seq)
		{...}
}

5.6 定数のマッピング

定数のマッピングは、定数が含まれるスコープによって異なります。

5.6.1 インタフェース内の定数

IDL インタフェースの中で宣言された定数は、IDL インタフェースに対応する Java インタフェースの public static final フィールドにマッピングされます。

5.6.1.1 例

// IDL
module Example {
		interface Face {
		const long aLongerOne = -321;
	};
};
// generated Java
package Example;
public interface Face {
	public static final int aLongerOne = (int) (-321L);
}

5.6.2 インタフェースの内部にない定数

IDL インタフェースの中で宣言されていない定数は、定数と同じ名前の public interface にマッピングされます。このインタフェースには value という名前の public static final フィールドがあり、ここに定数の値が格納されます。Java コンパイラは、通常、クラスがほかの Java コードで使われる時点で値をインラインにします。

5.6.2.1 例

// IDL
module Example {
	const long aLongOne = -123;
	};
package Example;
public interface aLongOne {
	public static final int value = (int) (-123L);
}

5.7 enum 型のマッピング

IDL の enum 型は、同じ名前の Java の final class にマッピングされます。このクラスでは、value メソッド、ラベルごとに 2 つの static データメンバ、整数値変換メソッド、および private コンストラクタが宣言されています。その例を次に示します。

// generated Java
public final class <enum_name> {
	// one pair for each label in the enum	
	public static final int _<label> = <value>;
	public static final <enum_name> <label> = 
		new <enum_name>(_<label>);
	public int value() {...}
	// get enum with specified value
	public static <enum_name> from_int(int value);
	// constructor
	private <enum_name>(int) { ... }
}
メンバの 1 つは public static final で、IDL の enum のラベルと同じ名前が与えられます。もう 1 つのメンバには名前の先頭に下線 (_) が付いており、switch 文で使います。

value メソッドは、整数型の値を返します。0 から始まる値が順番に割り当てられます。value という名前のラベルがある場合でも、Java の value() メソッドで衝突は発生しません。

enum のインスタンスは 1 つだけです。インスタンスが 1 つだけなので、一致検査が正しく機能します。つまり、デフォルトの java.lang.Object に実装されている equals() メソッドと hash() メソッドは、enum の単独オブジェクトに対し、自動的に正しく動作します。

enum 型に対する Java クラスには、from_int() メソッドが追加されます。このメソッドからは、指定した値に対応する enum の値が返されます。

enum 型に対するホルダークラスも生成されます。ホルダークラスの名前は、enum 型マッピングされた Java のクラス名に Holder が付け加えられたものになります。その例を次に示します。

public class <enum_name>Holder implements 
		org.omg.CORBA.portable.Streamable {
	public <enum_name> value;
	public <enum_name>Holder() {}
	public <enum_name>Holder(<enum_name> initial) {...}
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}

5.7.1 例

// IDL
enum EnumType {a, b, c};
// generated Java
public final class EnumType {
	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) {...};
	
	// constructor
	private EnumType(int) {...}

	};

5.8 struct 型のマッピング

IDL の struct 型は、同じ名前を持つ Java の final クラスにマッピングされます。このクラスでは、IDL のメンバと同じ順番に宣言されたフィールドのインスタンス変数と、すべての値に対するコンストラクタが提供されます。あとからフィールドを埋められるように、null コンストラクタも用意されています。

struct 型に対するホルダークラスも生成されます。名前は、struct 型がマッピングされた Java のクラス名のあとに Holder が付け加えられたものになります。その例を次に示します。

final public class <class>Holder implements 
		org.omg.CORBA.portable.Streamable {
	public <class> value;
	public <class>Holder() {}
	public <class>Holder(<class> initial) {...}
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}

5.8.1 例

// IDL
struct StructType {
	long field1;
	string field2;
};
// generated Java
final public class StructType {
	// instance variables
	public int field1;
	public String field2;
	// constructors
	public StructType() {}
	public StructType(int field1, String field2)
		{...}
	}
final public class StructTypeHolder
		implements org.omg.CORBA.portable.Streamable {
	public StructType value;
	public StructTypeHolder() {}
	public StructTypeHolder(StructType initial) {...}
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}

5.9 union 型のマッピング

IDL の union 型は、同じ名前の Java の final クラスにマッピングされます。次のものが作成されます。

マッピングされた union 型の名前またはいずれかのフィールド名に名前の衝突がある場合、通常の名前衝突解決ルール (名前の前に下線 "_" を付ける) が判別子に適用されます。

要素のアクセス用メソッドと変更用メソッドはオーバーロードされて、要素名に基づいて名前が付けられます。目的の要素が設定されていない場合は、アクセス用メソッドからシステム例外 CORBA::BAD_OPERATION が発生します。

要素に対応して複数の case ラベルがある場合、その要素に対する単純な変更用メソッドにより、最初の case ラベルの値に判別変数が設定されます。さらに、明示的な判別子パラメータを使用する特別な変更用メソッドが生成されます。

要素が default という case ラベルに対応している場合、変更用メソッドは、ほかのどの case ラベルとも一致しない値を判別変数に設定します。

case ラベルの集合が判別変数として可能性のある値を完全にカバーしている場合、union に default の case ラベルを指定することは誤りです。このような状況を検出し、不当なコードの生成を防ぐのは、Java コードジェネレータ (ILD コンパイラなどのツール) が備える機能です。

デフォルトの変更用メソッドの名前は default() (名前が衝突している場合は _default()) です。default という case ラベルが指定されていなくて、case ラベルの集合が判別変数として考えられる値を完全にカバーしていない場合に、このメソッドが作成されます。このメソッドは、union の値に範囲外の値を設定します。

union 型には、ホルダークラスも生成されます。その名前は、union 型がマッピングされた Java のクラス名のあとに Holder が付け加えられたものになります。その例を次に示します。

final public class <union_class>Holder
			implements org.omg.CORBA.portable.Streamable {
	public <union_class> value;
	public <union_class>Holder() {}
	public <union_class>Holder(<union_class> initial) {...}
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}

5.9.1 例

// IDL
union UnionType switch (EnumType) {               
		case first: long win;                 
 		case second: short place;                  
		case third:                  
		case fourth: octet show;                  
		default:     boolean other;               
	};    
// generated Java
final public class UnionType {              
	// constructor              
	public UnionType() {....}
	// discriminator accessor               
	public <switch-type> discriminator() {....}
	// win               
	public int win() {....}
	public void win(int value) {....} 
	// place               
	public short place() {....}
	public void place(short value) {....}
	// show              
	public byte show() {....}
	public void show(byte value) {....} 
	public void show(int discriminator, byte value){....}
	// other
	public boolean other() {....}
	public void other(boolean value) {....}
}
final public class UnionTypeHolder
		implements org.omg.CORBA.portable.Streamable {
	public UnionType value;
	public UnionTypeHolder() {}
	public UnionTypeHolder(UnionType initial) {...}
   	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}      

5.10 sequence 型のマッピング

IDL の sequence 型は、同じ名前で Java の配列にマッピングされます。マッピングでは、sequence 型が必要とされるすべての個所で、sequence の要素の型がマッピングされた型の配列が使用されます。バウンドシーケンスについては、IDL のオペレーションのパラメータとして整列化された時点で、バウンド検査が行われます。その結果必要があれば、IDL の CORBA::MARSHAL が発生します。

sequence 型には、ホルダークラスも生成されます。その名前は、sequence 型がマッピングされた Java のクラス名のあとに Holder が付け加えられたものになります。その例を次に示します。

final public class <sequence_class>Holder {
	public <sequence_element_type>[] value;
	public <sequence_class>Holder() {};
	public <sequence_class>Holder(
			<sequence_element_type>[] initial) {...};
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}

5.10.1 例

// IDL
typedef sequence< long > UnboundedData;
typedef sequence< long, 42 > BoundedData;
// generated Java
final public class UnboundedDataHolder
			implements org.omg.CORBA.portable.Streamable {
	public int[] value;
	public UnboundedDataHolder() {};
	public UnboundedDataHolder(int[] initial) {...};
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}
final public class BoundedDataHolder
			implements org.omg.CORBA.portable.Streamable {
	public int[] value;
	public BoundedDataHolder() {};
	public BoundedDataHolder(int[] initial) {...};
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}

5.11 配列のマッピング

IDL の配列は、IDL のバウンドシーケンスと同じ方法でマッピングされます。マッピングでは、配列型が必要とされるすべての個所で、配列要素の型がマッピングされた型の配列が使用されます。Java では、Java 本来の添字指定演算子が、マッピングされた配列に適用されます。IDL のオペレーションの引数として配列が整列化された時点で配列のバウンドが検査されて、バウンド違反がある場合は、例外 CORBA::MARSHAL が発生します。配列の長さを Java で利用できるようにするには、IDL の定数で配列のバウンドを指定します。この値は定数用の規則に従ってマッピングされます。

配列には、ホルダークラスも生成されます。その名前は、配列がマッピングされた Java のクラス名のあとに Holder が付け加えられたものになります。その例を次に示します。

final public class <array_class>Holder
		implements org.omg.CORBA.portable.Streamable {
	public <array_element_type>[] value;
	public <array_class>Holder() {}
	public <array_class>Holder(
				<array_element_type>[] initial) {...}
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}

5.11.1 例

// IDL
const long ArrayBound = 42;
typedef long larray[ArrayBound];
// generated Java
final public class larrayHolder
		implements org.omg.CORBA.portable.Streamable {
	public int[] value;
	public larrayHolder() {}
	public larrayHolder(int[] initial) {...}
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}

5.12 インタフェースのマッピング

5.12.1 基本

IDL の interface は、同じ名前で Java の public interface にマッピングされます。また、Java の「ヘルパー」クラスが追加されて、その名前はインタフェース名のあとに接尾辞 Helper が付け加えられたものになります。Java のインタフェースは、マッピングされた基底インタフェース org.omg.CORBA.Object を継承したものになります。

Java のインタフェースには、マッピングされたオペレーションのシグニチャーが含まれます。このインタフェースに対するオブジェクト参照で、メソッドを呼び出すことができます。

ヘルパークラスには narrow という名前の static メソッドがあり、このメソッドを使うと、org.omg.CORBA.Object をより範囲の限定された型のオブジェクト参照にナロー変換できます。ナロー変換に失敗した場合は、例外 CORBA::BAD_PARAM がスローされます。

特殊な「nil」オブジェクトの参照はありません。オブジェクト参照が必要な場所であればどこでも、Java の null をそのまま渡すことができます。

属性は、アクセス用メソッドと変更用メソッドの対にマッピングされます。これらのメソッドは IDL の属性と同じ名前を持ち、オーバーロードされています。IDL の readonly 属性に対しては、変更用メソッドは作成されません。

インタフェースには、ホルダークラスも生成されます。その名前は、インタフェースがマッピングされた Java のクラス名のあとに Holder が付け加えられたものになります。その例を次に示します。

final public class <interface_class>Holder
		implements org.omg.CORBA.portable.Streamable {
	public <interface_class> value;
	public <interface_class>Holder() {}
	public <interface_class>Holder(
				<interface_class> initial) {
		value = initial;
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}
IDL で規定されているインタフェースの継承は、Java のインタフェース階層に直接反映されます。

5.12.1.1 例

// IDL
module Example {
	interface Face {
		long method (in long arg) raises (e);
		attribute long assignable;
		readonly attribute long nonassignable;
	}
}
// generated Java
package Example;
public interface Face extends org.omg.CORBA.Object {
	int method(int arg)
		throws Example.e;
	int assignable();
	void assignable(int i);
	int nonassignable();
}
public class FaceHelper {

	// ... other standard helper methods

	public static Face narrow(org.omg.CORBA.Object obj)
		{...}
}
final public class FaceHolder 
		implements org.omg.CORBA.portable.Streamable {
	public Face value;
	public FaceHolder() {}
	public FaceHolder(Face initial) {...}
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}

5.12.2 パラメータの引き渡しモード

IDL の in パラメータは値による呼び出しの方式を実装するもので、Java の通常の実パラメータにマッピングされます。IDL のオペレーションの結果は、Java の対応するメソッドの結果として返されます。

IDL の out パラメータと inout パラメータは、結果による呼び出し、および値/結果による呼び出しの形式を実装するもので、Java のパラメータ引き渡し機構に直接マッピングすることはできません。このマッピングでは、IDL の基本型とユーザ定義型のすべてに対するホルダークラスが新しく定義されて、このクラスを使って out と inout のパラメータ引き渡しモードが Java に実装されます。クライアントは、Java の適切なホルダークラスのインスタンスを提供し、このインスタンスが IDL の out パラメータまたは inout パラメータに値で渡されます。ホルダークラスのインスタンスの内容 (インスタンス自体ではない) がこの呼び出しで変更されて、クライアントは呼び出しから返されたあとの変更された内容を使用します。

5.12.2.1 例

// IDL
module Example {
	interface Modes {
		long operation(	in long inArg,
		    		out long outArg,
		    		inout long inoutArg);
	};
	};
// Generated Java
package Example;
public interface Modes {
	int operation(	int inArg,
			IntHolder outArg,
			IntHolder inoutArg);
}
上の例では、結果は実際の結果として返され、in モードの実パラメータについては実際の値だけが返されます。一方、out パラメータと inout パラメータについては、適切なホルダーが作成される必要があります。典型的な使用例を次に示します。

// user Java code
// select a target object
Example.Modes target = ...;
// get the in actual value
int inArg = 57; 
// prepare to receive out
IntHolder outHolder = new IntHolder();
// set up the in side of the inout   
IntHolder inoutHolder = new IntHolder(131);
// make the invocation
int result =target.operation(inArg, outHolder, inoutHolder);
// use the value of the outHolder
... outHolder.value ...								
// use the value of the inoutHolder              
... inoutHolder.value ...								
呼び出しの前に、inout パラメータの入力値を、実パラメータとなるホルダーインスタンスに設定する必要があります。値から新しいホルダーを作成するか、あるいは適切な型の既存のホルダーの値に割り当てることで、inout ホルダーに値を設定できます。呼び出しが終了したあと、クライアントは outHolder.value を使って out パラメータの値にアクセスし、inoutHolder.value を使って inout パラメータの出力値にアクセスします。IDL のオペレーションから返される結果は、呼び出しの結果として利用できます。




5.13 例外のマッピング

IDL の例外は、struct 型とよく似た方法でマッピングされます。IDL の例外は、例外のフィールドのインスタンス変数とコンストラクタを提供する Java クラスにマッピングされます。

CORBA のシステム例外は、検査されない例外です。java.lang.RuntimeException から間接的に継承します。

ユーザ定義の例外は、検査される例外です。java.lang.Exception から間接的に継承します。

図 5-1 Java の Exception クラスの継承

5.13.1 ユーザ定義の例外

ユーザ定義の例外は、org.omg.CORBA.UserException を継承する Java の final クラスにマッピングされます。それを除くと、ヘルパークラスとホルダークラスの作成を含めて、IDL の struct 型と同様にマッピングされます。

例外が入れ子の IDL スコープ (特にインタフェース) の中で定義されている場合、Java のクラス名は専用のスコープの中で定義されます。詳細については、「5.15 入れ子構造の型のマッピング」を参照してください。入れ子になっていない場合は、Java のクラス名は、例外を囲む IDL モジュールに対応する Java パッケージのスコープ内で定義されます。

5.13.1.1 例

// IDL
module Example {
	exception ex1 { string reason; };
};
// Generated Java
package Example;
final public class ex1 extends org.omg.CORBA.UserException {
	public String reason;		// instance
	public ex1() {...}		// default constructor
	public ex1(String r) {...}		// constructor
}
final public class ex1Holder
		implements org.omg.CORBA.portable.Streamable {
	public ex1 value;
	public ex1Holder() {}
	public ex1Holder(ex1 initial) {...}
	public void _read(org.omg.CORBA.portable.InputStream i)
		{...}
	public void _write(org.omg.CORBA.portable.OutputStream o)
		{...}
	public org.omg.CORBA.TypeCode _type() {...}
}

5.13.2 システム例外

IDL 標準のシステム例外は、org.omg.CORBA.SystemException を継承する Java の final クラスにマッピングされます。このクラスは、IDL のメジャー例外コードとマイナー例外コード、および例外の理由を示すテキストへのアクセスを提供します。org.omg.CORBA.SystemException には public コンストラクタはありません。このクラスを継承するクラスに対してだけインスタンスを生成できます。

IDL の標準例外に対する Java のクラス名は IDL の名前と同じで、org.omg.CORBA パッケージの中で宣言されます。デフォルトコンストラクタは、マイナーコードには 0 を、完了コードには COMPLETED_NO を、原因の文字列には "" をそれぞれ設定します。原因を取得し、ほかのフィールドには規定値を設定するコンストラクタ、および 3 つのパラメータすべてに指定を必要とするコンストラクタもあります。IDL の名前と Java のクラス名のマッピングを、次の表に示します。

表  5-1

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::TRANSACTIONREQUIRED

org.omg.CORBA.TRANSACTIONREQUIRED

CORBA::TRANSACTIONROLLEDBACK

org.omg.CORBA.TRANSACTIONROLLEDBACK

CORBA::INVALIDTRANSACTION

org.omg.CORBA.INVALIDTRANSACTION

関連するクラスの定義を次に示します。

// from org.omg.CORBA package
package org.omg.CORBA;
public final class CompletionStatus {
	// Completion Status constants
	public static final int 	_COMPLETED_YES = 0,
					_COMPLETED_NO = 1,
					_COMPLETED_MAYBE = 2;
	public static final CompletionStatus COMPLETED_YES =
		new CompletionStatus(_COMPLETED_YES);
	public static final CompletionStatus COMPLETED_NO =
		new CompletionStatus(_COMPLETED_NO);
	public static final CompletionStatus COMPLETED_MAYBE =
		new CompletionStatus(_COMPLETED_MAYBE);
	public int value() {...}
	public static final CompletionStatus from_int(int) {...}
	private CompletionStatus(int) {...}
}
abstract public class 
	SystemException extends java.lang.RuntimeException {
		public int minor;
		public CompletionStatus completed;
		// constructor
		protected SystemException(String reason,
					  int minor,
					  CompletionStatus status) {
					  super(reason);
					  this.minor = minor;
					  this.status = status;
		}
	}
final public class 
	UNKNOWN extends org.omg.CORBA.SystemException {
	public UNKNOWN() ...
	public UNKNOWN(int minor, CompletionStatus completed) ...
	public UNKNOWN(String reason) ...
	public UNKNOWN(String reason, int minor, 
		       CompletionStatus completed)	...
}
...
// there is a similar definition for each of the standard
// IDL system exceptions listed in the table above

5.14 Any 型のマッピング

IDL の Any 型は、Java の org.omg.CORBA.Any クラスにマッピングされます。このクラスには、定義済みの型のインスタンスを挿入および取得するために必要なメソッドがすべて備わっています。取得オペレーションで型の不一致が発生した場合は、例外 CORBA::BAD_OPERATION が発生します。

さらに、移植性のあるスタブやスケルトンが使用する高速インタフェースを提供するため、ホルダークラスを使用する挿入メソッドと取得メソッドが定義されています。IDL の各プリミティブ型に対して挿入メソッドと取得メソッドが定義されているだけでなく、IDL の非プリミティブ型の処理のために、汎用のストリーマブルに対する一対のメソッドも定義されています。また、符号なし型の情報を保持するため、通常のホルダークラスを使用する符号なし型のメソッドが、適切な個所で定義されています。

挿入オペレーションでは、指定した値が設定されて、必要に応じて any の型がリセットされます。

アクセス用メソッド type() を使ってタイプコードを設定すると、値がクリアされます。値が設定される前に値を取得しようとすると、例外 CORBA::BAD_OPERATION が発生します。IDL の out パラメータに適切な値を設定できるように、このオペレーションはあらかじめ提供されています。

package org.omg.CORBA;
abstract public class Any {
abstract public boolean equal(org.omg.CORBA.Any a);
// type code accessors
abstract public org.omg.CORBA.TypeCode type();
abstract public void type(org.omg.CORBA.TypeCode t);
// read and write values to/from streams
// throw excep when typecode inconsistent with value
abstract public void read_value(
	org.omg.CORBA.portable.InputStream is,
	org.omg.CORBA.TypeCode t) throws org.omg.CORBA.MARSHAL;
abstract public void 
	write_value(org.omg.CORBA.portable.OutputStream os);
abstract public org.omg.CORBA.portable.OutputStream
			create_output_stream();
abstract public org.omg.CORBA.portable.InputStream
			create_input_stream();
// insert and extract each primitive type
abstract public short extract_short()
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_short(short s);
abstract public int extract_long()
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_long(int i);
abstract public long extract_longlong()
	 throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_longlong(long l);
abstract public short extract_ushort() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_ushort(short s);
abstract public int extract_ulong() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_ulong(int i);
abstract public long extract_ulonglong() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_ulonglong(long l);
abstract public float extract_float() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_float(float f);
abstract public double extract_double() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_double(double d);
abstract public boolean extract_boolean() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_boolean(boolean b);
abstract public char extract_char() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_char(char c)
	throws org.omg.CORBA.DATA_CONVERSION;
abstract public char extract_wchar() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_wchar(char c);
abstract public byte extract_octet() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_octet(byte b);
abstract public org.omg.CORBA.Any extract_any() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_any(org.omg.CORBA.Any a);
abstract public org.omg.CORBA.Object extract_Object() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_Object(
			org.omg.CORBA.Object o);
// throw excep when typecode inconsistent with value
abstract public void insert_Object(
			org.omg.CORBA.Object o,
			org.omg.CORBA.TypeCode t)
			throws org.omg.CORBA.MARSHAL;
abstract public String extract_string() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_string(String s)
	throws org.omg.CORBA.DATA_CONVERSION, org.omg.CORBA.MARSHAL;
abstract public String extract_wstring() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_wstring(String s)
	throws org.omg.CORBA.MARSHAL;
// insert and extract typecode
abstract public org.omg.CORBA.TypeCode extract_TypeCode() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_TypeCode(
			org.omg.CORBA.TypeCode t);
// insert and extract Principal
abstract public org.omg.CORBA.Principal extract_Principal() 
	throws org.omg.CORBA.BAD_OPERATION;
abstract public void insert_Principal(
			org.omg.CORBA.Principal p);
// insert non-primitive IDL types
abstract public void insert_Streamable(
			org.omg.CORBA.portable.Streamable s);
}

5.15 入れ子構造の型のマッピング

IDL では、インタフェース内で入れ子の型宣言が認められています。Java の場合、インタフェース内でクラスを入れ子にすることは認められていません。したがって、Java のクラスにマッピングされる IDL の型で、インタフェースのスコープの中で宣言されているものについては、Java にマッピングされる際に、専用の 「スコープ」パッケージに入れる必要があります。

このような型宣言を含む IDL インタフェースに対しては、マッピングされた Java クラスの宣言を含むスコープパッケージが作成されます。スコープパッケージの名前は、IDL の型の名前に Package が付け加えられたものになります。

5.15.1 例

// IDL
module Example {
	interface Foo {
		exception e1 {};
	};
};
// generated Java
package Example.FooPackage;
final public class e1 extends org.omg.CORBA.UserException
	 {...}						

5.16 typedef のマッピング

Java には、typedef という構造はありません。

5.16.1 IDL の単純な型

Java の単純な型にマッピングされる IDL の型は、Java の中でサブクラス化されることはありません。したがって、単純な型の型宣言に使われている typedef はすべて、本来マッピングされることになっている型にマッピングされます。

この規則が適用される IDL の型については、「5.4 基本型のマッピング」を参照してください。

すべての typedef に対して、ヘルパークラスが作成されます。

5.16.2 IDL の複雑な型

配列でもシーケンスでもない typedef は、IDL の単純な型またはユーザ定義型 (typedef 以外の種類) が得られるまで、元の型へと「分解」されます。

ホルダークラスは、シーケンスと配列の typedef にだけ作成されます。

5.16.2.1 例

// IDL
struct EmpName {
	string firstName;
	string lastName;
};
typedef EmpName EmpRec;
// generated Java
// regular struct mapping for EmpName
// regular helper class mapping for EmpRec

final public class EmpName {
	...
}
public class EmpRecHelper {
	...
}