このドキュメントは、インタフェースを定義する IDL (Interface Definiton Language) とスタブおよびスケルトンを生成する Java IDL コンパイラを使い、完全な CORBA (Common Object Request Broker Architecture) アプリケーションを作成する方法について、高レベルの概要を説明したものです。開発プロセスの詳細情報と、IDL を使って CORBA アプリケーションを作成する方法の詳細なチュートリアルは、「Java IDL 入門: Hello World のチュートリアル」を参照してください。また、Java プログラミング言語でインタフェースを定義して CORBA アプリケーションを作成することもできます。この開発プロセスの詳細とチュートリアルについては、Java RMI-IIOP ドキュメントを参照してください。
Java SE の今回のリリースで idlj コンパイラを使用して生成したサーバー側実装は Portable Servant Inheritance Model で、POA モデルとも呼ばれます。POA (ポータブルオブジェクトアダプタ) については「ポータブルオブジェクトアダプタ」で説明します。このドキュメントでは idlj コンパイラのデフォルトの動作を使って作成したサンプルアプリケーションを扱い、POA サーバー側モデルを使用します。
CORBA は IDL インタフェースを実装するサーバー側マッピングのうち、少なくとも次の 2 種類をサポートしています。
継承モデルを使って、コンパイラが作成したスケルトンの拡張も行う実装クラスを使い、IDL インタフェースを実装します。
継承モデルには、次のものが含まれています。
注: ImplBase は POA モデルがあるので非推奨ですが、バージョン 1.3 以前の J2SE で記述されたサーバーと互換性を持つために提供されています。これは非標準モデルなので、これを使って新しいサーバーを作成することはお勧めしません。
委譲モデルを使い、次の 2 つのクラスを使って IDL インタフェースを実装します。
委譲モデルは、Tie モデルや Tie 委譲モデルとしても知られています。このモデルは POA または ImplBase コンパイラで作成されたスケルトンのどちらかを継承するので、このドキュメントでは POA/Tie または ImplBase/Tie モデルのように記述されます。
このチュートリアルでは、サーバー側実装の POA 継承モデルを扱います。ほかのサーバー側実装を使用するチュートリアルは、次のドキュメントを参照してください。
Tie モデルは委譲モデルです。サーバー側バインディングをはじめて生成する場合は idlj を使用します。2 回目は -fallTie オプションを使って idlj コンパイラを実行し、Tie モデルのサーバー側バインディングを生成します。Hello インタフェースには、HelloPOATie.java というファイルが生成されます。HelloPOATie のコンストラクタは delegate と poa、またはそのいずれかを引数として取ります。delegate と poa、またはそのどちらかに実装を提供する必要があります。ただし、この delegate は、HelloOperations インタフェース以外に、ほかのクラスから継承する必要はありません。詳細については、IDL から Java 言語へのマッピング仕様を参照してください。
ほかの実装から継承しなければならない場合、標準の継承モデルではなく Tie モデルを使用することがあります。Java の場合は、インタフェースの継承の個数に制限はありませんが、クラスの継承に使用できるスロットは 1 つだけです。継承モデルを使用した場合は、そのスロットが占有されます。Tie モデルを使用した場合は、そのスロットが使用されず、ユーザーが独自の目的で使用することができます。ただし、間接参照のレベルが 1 つ導入されるという欠点があります。つまり、メソッドを呼び出すときに余分なメソッド呼び出しが発生します。
ImplBase サーバー側のモデルは、POA モデルと同じく継承モデルです。idlj コンパイラに -oldImplBase フラグを指定して使用することにより、J2SE 1.4 より前のバージョンの Java IDL と互換性があるサーバー側バインディングを生成します。Hello.idl で定義されたインタフェース Hello があれば、ファイル _HelloImplBase.java が生成されます。Hello に対して実装を提供する必要があり、さらに、この実装は _HelloImplBase から継承されている必要があります。
ただし、-oldImplBase フラグを使用するのは、標準的ではありません。これらの API は推奨されていません。このフラグを使用するのは、J2SE 1.3 以前で書かれた既存のサーバーとの互換性を取る場合だけです。その場合、既存の MAKEFILE を変更して idlj コンパイラに -oldImplBase フラグを追加する必要があり、そうしない場合、POA ベースのサーバー側マッピングが生成されます。
このドキュメントでは、次の内容について説明します。
この例を作成するには、サンプルアプリケーションを開発する場所として hello/ という名前のディレクトリを作成し、各ファイルをこのディレクトリ内に作成します。または、コード例をダウンロードし、サンプルアプリケーションのディレクトリに解凍します。
Hello.idl
)CORBA アプリケーション作成の第一段階は、OMG のインタフェース定義言語 (IDL) を使って、オブジェクトとインタフェースをすべて記述することです。IDL には C++ に似た構文があり、これを使ってモジュール、インタフェース、データ構造などを定義することができます。IDL はさまざまなプログラミング言語にマッピングできます。IDL を Java にマッピングする方法は「IDL と Java 言語のマッピングのサマリー」で説明しています。
次のコードは OMG IDL で記述されたもので、sayHello() オペレーションが文字列 (string) を返し shutdown() メソッドが ORB を停止させる CORBA オブジェクトを記述しています。OMG IDL の構文とセマンティクスの詳細は、CORBA 2.3.1 仕様の第 3 章を参照してください。
Hello.idl
module HelloApp { interface Hello { string sayHello(); oneway void shutdown(); }; };注: OMG IDL でコードを記述する場合、モジュール名にインタフェース名を使用しないでください。モジュール名にインスタンス名を使用すると、異なるベンダーのツールを使ったコンパイル実行時に、結果の整合性が維持されなくなる危険があります。その結果、コードの移植性が損なわれます。たとえば、同じ名前を含むコードを Sun Microsystems の IDL-to-Java コンパイラを使ってコンパイルすると、1 つの結果が得られます。同じコードを別のベンダーの IDL-to-Java コンパイラを使ってコンパイルすると、別の結果になる場合があります。
アプリケーションを完成させるには、サーバー (HelloServer.java
) およびクライアント (HelloClient.java
) 実装を提供します。
HelloServer.java
)ここで紹介するサーバーは、サーバントとサーバーの 2 つのクラスで構成されます。サーバント HelloImpl は Hello IDL インタフェースの実装で、各 Hello インスタンスは HelloImpl インスタンスによって実装されます。サーバントは、idlj コンパイラにより例の IDL から生成される HelloPOA のサブクラスです。サーバントには、IDL オペレーションごとに 1 つのメソッドが含まれます (この例では、sayHello() および shutdown() メソッド)。サーバントメソッドは、Java の通常のメソッドと変わりはありません。ORB の処理、引数や結果の整列化などを行うコードは、スケルトンで実装します。
HelloServer クラスにはサーバーの main() メソッドが含まれます。
この例では、一時オブジェクトサーバーの例を示します。持続オブジェクトサーバーを使用する「Hello World」プログラムの例については、「例 2: 持続性を備えた Hello World」を参照してください。CORBA サーバーの詳細については、「サーバーの開発」を参照してください。
コードの詳細は、チュートリアルの「Java IDL 入門: Hello World サーバーの開発」を参照してください。
HelloServer.java
// HelloServer.java // Copyright and License import HelloApp.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; import org.omg.PortableServer.*; import org.omg.PortableServer.POA; import java.util.Properties; class HelloImpl extends HelloPOA { private ORB orb; public void setORB(ORB orb_val) { orb = orb_val; } // implement sayHello() method public String sayHello() { return "\nHello world !!\n"; } // implement shutdown() method public void shutdown() { orb.shutdown(false); } } public class HelloServer { public static void main(String args[]) { try{ // create and initialize the ORB ORB orb = ORB.init(args, null); // get reference to rootpoa & activate the POAManager POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); rootpoa.the_POAManager().activate(); // create servant and register it with the ORB HelloImpl helloImpl = new HelloImpl(); helloImpl.setORB(orb); // get object reference from the servant org.omg.CORBA.Object ref = rootpoa.servant_to_reference(helloImpl); Hello href = HelloHelper.narrow(ref); // get the root naming context // NameService invokes the name service org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); // Use NamingContextExt which is part of the Interoperable // Naming Service (INS) specification. NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef); // bind the Object Reference in Naming String name = "Hello"; NameComponent path[] = ncRef.to_name( name ); ncRef.rebind(path, href); System.out.println("HelloServer ready and waiting ..."); // wait for invocations from clients orb.run(); } catch (Exception e) { System.err.println("ERROR: " + e); e.printStackTrace(System.out); } System.out.println("HelloServer Exiting ..."); } }
HelloClient.java
)このアプリケーションクライアントでは、次の処理を行います。
コードの詳細は、「Java IDL 入門: クライアントアプリケーションの開発」を参照してください。
HelloClient.java
// Copyright and License import HelloApp.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; public class HelloClient { static Hello helloImpl; public static void main(String args[]) { try{ // create and initialize the ORB ORB orb = ORB.init(args, null); // get the root naming context org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); // Use NamingContextExt instead of NamingContext. This is // part of the Interoperable naming Service. NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef); // resolve the Object Reference in Naming String name = "Hello"; helloImpl = HelloHelper.narrow(ncRef.resolve_str(name)); System.out.println("Obtained a handle on server object: " + helloImpl); System.out.println(helloImpl.sayHello()); helloImpl.shutdown(); } catch (Exception e) { System.out.println("ERROR : " + e) ; e.printStackTrace(System.out); } } }
Hello World プログラムは単純ですが、このプログラムを通して、静的な呼び出しを使用するほとんどの CORBA プログラムの開発に必要なタスクすべてを学び、経験できます。コンパイル時にオブジェクトのインタフェースが既知の場合、呼び出しにはクライアントスタブを使用し、呼び出されるサービスにはサーバースケルトンを使用する静的な呼び出しが使用されます。コンパイル時にインタフェースが不明な場合は、動的呼び出しを使用する必要があります。
この例ではネームサービスが必要です (オブジェクト参照に名前をバインドして CORBA オブジェクトに命名できる CORBA サービス)。ネームバインディングはネームサービスに格納され、クライアントは名前を与えて目的のオブジェクト参照を取得できます。今回リリースされた Java SE に同梱されている 2 つのネームサービスのうち、1 つは、デーモンプロセスである orbd で、ブートストラップサービス、一時ネームサービス、持続ネームサービス、およびサーバーマネージャーが含まれています。もう 1 つは、一時ネームサービスである tnameserv で、下位互換性を維持するために用意されています。この例では orbd を使用しています。
この例を実行するにあたって、Solaris ソフトウェアの使用時は、ポート 1024 未満でプロセスを開始する場合、root になる必要があることを思い出してください。このため、1024 以上のポートを使用することをお勧めします。この例では、-ORBInitialPort オプションを使ってデフォルトのポート番号をオーバーライドします。次の説明では、Java IDL Object Request Broker Daemon orbd 用にポート 1050 を使用できることを前提としています。必要であれば別のポートに変更してください。Windows でこの例を実行する場合は、パス名にバックスラッシュ (\) を使用します。
開発マシンでこのクライアントサーバーアプリケーションを実行するには、次のようにします。
idlj -fall Hello.idl
idlj コンパイラの -fall オプションを使って、クライアントとサーバー側のバインディングの両方を生成する必要があります。このコマンド行でデフォルトのサーバー側バインディングが生成されます。これは POA 継承サーバー側モデルであることを前提にしています。idlj オプションの詳細については、IDL-to-Java コンパイラオプションを参照してください。
idlj コンパイラではいくつかのファイルが生成されます。実際に生成されるファイルの数は、IDL ファイルのコンパイル時に選択されたオプションによって異なります。生成されたファイルには標準の機能があるので、プログラムを配置して実行するまでは無視してもかまいません。Hello.idl の idlj コンパイラで、-fall コマンド行オプションを使って生成されるファイルは次のとおりです。
この abstract クラスは、ストリームベースのサーバースケルトンで、サーバー用に基本的な CORBA 機能を提供します。これは org.omg.PortableServer.Serva nt を拡張し、InvokeHandler インタフェースと HelloOperations インタフェースを実装します。サーバークラス HelloImpl は HelloPOA を拡張します。
このクラスはクライアントスタブで、クライアント用に CORBA 機能を提供します。これは org.omg.CORBA.portable.ObjectImpl を拡張し、Hello.java インタフェースを実装します。
このインタフェースには作成した IDL インタフェースの Java 版が含まれます。Hello.java インタフェースは、標準的な CORBA オブジェクト機能を提供する org.omg.CORBA.Object を拡張します。また HelloOperations インタフェースおよび org.omg.CORBA.portable.IDLEntity も拡張します。
このクラスは補助機能、特に CORBA オブジェクト参照を適切な型にキャストする必要がある narrow() メソッドを提供します。Helper クラスは CORBA ストリームへのデータ型の入出力と、Any のデータ型の挿入と抽出を扱います。Holder クラスは、Helper クラスのメソッドに入出力を委譲します。
この final クラスは、Hello 型の public インスタンスメンバーを保持します。IDL 型のパラメータが out または inout であれば Holder クラスが使用されます。これは、org.omg.CORBA.portable.OutputStream および org.omg.CORBA.portable.InputStream 引数 (CORBA は許可しますが、Java のセマンティクスには簡単にマッピングできません) に対するオペレーションを提供します。Holder クラスは Helper クラスのメソッドに入出力を委譲します。これは org.omg.CORBA.portable.Streamable を実装します。
このインタフェースには sayHello() メソッドおよび shutdown() メソッドが含まれます。IDL-to-Java マッピングは、IDL インタフェースで定義されたオペレーションをすべてこのファイルに組み込み、スタブとスケルトンで共有します。
javac *.java HelloApp/*.java
UNIX コマンドシェルで orbd を起動するには、次のように入力します。
orbd -ORBInitialPort 1050&
Windows の MS-DOS システムプロンプトでは、次のように入力します。
start orbd -ORBInitialPort 1050
1050 はネームサーバーを実行するポートです。-ORBInitialPort 引数は必須のコマンド行引数です。Solaris ソフトウェアの使用時は、1024 より小さいポートでプロセスを開始する場合は、root ユーザーになる必要があります。このため、1024 以上のポートを使用することをお勧めします。
このプログラムを 2 台のマシンで実行する方法の例は、「2 台のマシンで実行する Hello World プログラム」を参照してください。
UNIX コマンドシェルで Hello サーバーを起動するには、次のように入力します。
java HelloServer -ORBInitialPort 1050 -ORBInitialHost localhost&
Windows の MS-DOS システムプロンプトでは、次のように入力します。
start java HelloServer -ORBInitialPort 1050 -ORBInitialHost localhost
サーバーが起動すると、HelloServer ready and waiting... と表示されます。
この例の -ORBInitialHost localhost は、ネームサーバーが Hello サーバーとして同一ホスト上で動作しているため、省略できます。ネームサーバーが別のホストで動作している場合は、IDL ネームサーバーが動作しているホストを -ORBInitialHost nameserverhost で指定します。
前回の手順と同様にネームサーバー (orbd) のポートを指定します (たとえば -ORBInitialPort 1050)。
java HelloClient -ORBInitialPort 1050 -ORBInitialHost localhost
クライアントが実行されると、たとえば次のような応答が端末に表示されます。 Obtained a handle on server object: IOR: (binary code) Hello World! HelloServer exiting...
この例の -ORBInitialHost localhost は、ネームサーバーが Hello クライアントとして同一ホスト上で動作しているため、省略できます。ネームサーバーが別のホストで動作している場合は、IDL ネームサーバーが動作しているホストを -ORBInitialHost nameserverhost で指定します。
前回の手順と同様にネームサーバー (orbd) のポートを指定します (たとえば -ORBInitialPort 1050)。
このチュートリアルを終了したら、ネームサーバー (orbd) を停止するか終了してください。DOS プロンプトからこれを実行するには、サーバーを実行しているウィンドウを選択して Ctrl+C と入力すると停止します。UNIX シェルでは、プロセスを検出して終了 (kill) します。サーバーを明示的に停止するまでは、呼び出し待機状態が続きます。
「2 台のマシンで実行する Hello World プログラム」では、クライアントとサーバーという 2 台のマシンで簡単なアプリケーションを分散させる方法の一例を示します。