このドキュメントは、インタフェースを定義する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または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 (Solaris、Linux、Mac OS XまたはWindows)で、ブートストラップ・サービス、一時ネーム・サービス、持続ネーム・サービスおよびサーバー・マネージャが含まれています。もう1つは、一時ネーム・サービスであるtnameserv (Solaris、Linux、Mac OS XまたはWindows)で、下位互換性を維持するために用意されています。この例ではorbdを使用しています。
この例を実行するにあたって、Solarisソフトウェアの使用時は、ポート1024未満でプロセスを開始する場合、rootになる必要があることを思い出してください。このため、1024以上のポートを使用することをお薦めします。この例では、-ORBInitialPortオプションを使ってデフォルトのポート番号をオーバーライドします。次の説明では、Java IDL Object Request Broker Daemon orbd用にポート1050を使用できることを前提としています。必要であれば別のポートに変更してください。Windowsでこの例を実行する場合は、パス名にバックスラッシュ(\)を使用します。
開発マシンでこのクライアント・サーバー・アプリケーションを実行するには、次のようにします。
idlj -fall Hello.idl
idljコンパイラの-fallオプションを使って、クライアントとサーバー側のバインディングの両方を生成する必要があります。このコマンド行でデフォルトのサーバー側バインディングが生成されます。これはPOA継承サーバー側モデルであることを前提にしています。idljのオプションの詳細は、idljのマニュアル・ページ(Solaris、Linux、Mac OS XまたはWindows)を参照してください。
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
Solaris、LinuxまたはMac OS Xのコマンド・シェルでorbdを起動するには、次のように入力します。
orbd -ORBInitialPort 1050&
WindowsのMS-DOSシステム・プロンプトでは、次のように入力します。
start orbd -ORBInitialPort 1050
1050はネーム・サーバーを実行するポートです。-ORBInitialPort引数は必須のコマンド行引数です。Solarisソフトウェアの使用時は、1024より小さいポートでプロセスを開始する場合は、rootユーザーになる必要があります。このため、1024以上のポートを使用することをお薦めします。
このプログラムを2台のマシンで実行する方法の例は、「2台のマシンで実行するHello Worldプログラム」を参照してください。
Solaris、LinuxまたはMac OS Xのコマンド・シェルで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と入力すると停止します。Solaris、LinuxまたはMac OS Xのシェルでは、プロセスを見つけて終了(kill)します。サーバーを明示的に停止するまでは、呼出し待機状態が続きます。
「2台のマシンで実行するHello Worldプログラム」では、クライアントとサーバーという2台のマシンで簡単なアプリケーションを分散させる方法の一例を示します。