このドキュメントは、インタフェースを定義するIDL (Interface Definiton Language)とスタブおよびスケルトンを生成するJava IDLコンパイラを使い、完全なCORBA (Common Object Request Broker Architecture)アプリケーションを作成する方法について、高レベルの概要を説明したものです。このドキュメントでは、POA-Tieサーバー側モデルの使い方を説明します。他の実装から継承しなければならない場合、標準の継承モデルではなくTieモデルを使用することがあります。Javaの場合は、インタフェースの継承の個数に制限はありませんが、クラスの継承に使用できるスロットは1つだけです。継承モデルを使用した場合は、そのスロットが占有されます。Tieモデルを使用した場合は、そのスロットが使用されず、ユーザーが独自の目的で使用できます。ただし、間接参照のレベルが1つ導入されるという短所があります。つまり、メソッドを呼び出すときに余分なメソッド呼出しが発生します。
このプログラミング・モデルの別の側面にはポータブル・オブジェクト・アダプタ (POA)があり、次の目標を満たすように設計されています。
このドキュメントでは、次の内容について説明します。
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()メソッドが含まれます。
デフォルトのチュートリアルと異なるコードは、太字で強調表示されます。
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; } public String sayHello(){ return "\nHello world !!\n"; } 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); // create a tie, with servant being the delegate. HelloPOATie tie = new HelloPOATie(helloImpl, rootpoa); // obtain the objectRef for the tie // this step also implicitly activates the object Hello href = tie._this(orb); // get the root naming context org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); // Use NamingContextExt which is part of the Interoperable // Naming Service 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
)後述のアプリケーション・クライアントの例は、デフォルトのチュートリアルにあるものと同じです。この例で変更するファイルはサーバー実装だけです。クライアント・アプリケーションの例:
HelloClient.java
// Copyright and License import HelloApp.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; public class HelloClient{ 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"; 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つのオプションがあります。一時ネーム・サービスである tnameserv (Solaris、Linux、Mac OS XまたはWindows)と、ネーム・サービスを含むorbd (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 -fallTie Hello.idl
idljコンパイラの-fallオプションを使って、クライアントとサーバー側のバインディングの両方を生成する必要があります。このコマンド行でデフォルトのサーバー側バインディングが生成されます。これはPOAプログラミング・モデルであることを前提にしています。-fallTieオプションで別のファイルHelloPOATieを作成し、Tieの作成に使用します。idljのオプションの詳細は、idljのマニュアル・ページ(Solaris、Linux、Mac OS XまたはWindows)を参照してください。
idljコンパイラではいくつかのファイルが生成されます。実際に生成されるファイルの数は、IDLファイルのコンパイル時に選択されたオプションによって異なります。生成されたファイルには標準の機能があるので、プログラムを配置して実行するまでは無視してもかまいません。Hello.idlのidljコンパイラで、-fallコマンド行オプションを使って生成されるファイルは次のとおりです。
このabstractクラスは、ストリーム・ベースのサーバー・スケルトンで、サーバー用に基本的なCORBA機能を提供します。これはorg.omg.PortableServer.Servantを拡張し、InvokeHandlerインタフェースとHelloOperationsインタフェースを実装します。サーバー・クラスHelloImplはHelloPOAを拡張します。
このクラスはクライアント・スタブで、クライアント用にCORBA機能を提供します。これはorg.omg.CORBA.portable.ObjectImplを拡張し、Helloインタフェースを実装します。
このインタフェースには作成したIDLインタフェースのJava版が含まれます。Helloインタフェースは、標準的な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インタフェースで定義されたオペレーションをすべてこのファイルに組込み、スタブとスケルトンで共有します。
Hello.idlのidljコンパイラで、-fallTieコマンド行オプションを使って生成されるファイルは次のとおりです。
MyPOATieのコンストラクタはdelegateとpoa、またはそのいずれかを引数として取ります。delegateとpoa、またはそのどちらかに実装を提供する必要があります。ただし、このdelegateは、HelloOperationsインタフェース以外に、他のクラスから継承する必要はありません。詳細については、IDLからJava言語へのマッピング仕様を参照してください。
javac *.java HelloApp/*.java
Solaris、LinuxまたはMac OS Xのコマンド・シェルでorbdを起動するには、次のように入力します。
orbd -ORBInitialPort 1050 -ORBInitialHost localhost&
WindowsのMS-DOSシステム・プロンプトでは、次のように入力します。
start orbd -ORBInitialPort 1050 -ORBInitialHost localhost
1050はネーム・サーバーを実行するポートです。-ORBInitialPortは必須のコマンド行引数です。Solarisソフトウェアの使用時は、1024より小さいポートでプロセスを開始する場合は、rootユーザーになる必要があります。このため、1024以上のポートを使用することをお薦めします。
-ORBInitialHostは、オプションのコマンド行引数です。この例では、クライアントとサーバーはどちらも開発マシンで実行しているので、ホストをlocalhostに設定しました。複数のマシンで開発する場合は、ホスト名に置き換えます。このプログラムを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
この例の-ORBInitialHost localhostは、ネーム・サーバーがHelloサーバーとして同一ホスト上で動作しているため、省略できます。ネーム・サーバーが別のホストで動作している場合は、IDLネーム・サーバーが動作しているホストを-ORBInitialHost nameserverhostで指定します。
前回の手順と同様にネーム・サーバー(orbd)のポートを指定します(たとえば-ORBInitialPort 1050)。
サーバーが起動して、次のようなメッセージが端末に表示されます。
HelloServer ready and waiting ...
java HelloClient -ORBInitialPort 1050 -ORBInitialHost localhost
この例の-ORBInitialHost localhostは、ネーム・サーバーがHelloクライアントとして同一ホスト上で動作しているため、省略できます。ネーム・サーバーが別のホストで動作している場合は、IDLネーム・サーバーが動作しているホストを-ORBInitialHost nameserverhostで指定します。
前回の手順と同様にネーム・サーバー(orbd)のポートを指定します(たとえば-ORBInitialPort 1050)。
クライアントが実行されて、次のような情報が端末に表示されます。
Obtained a handle on server object: IOR: ... Hello World! Hello Server Exiting ...
このチュートリアルを終了したら、ネーム・サーバー(orbd)を停止するか終了してください。DOSプロンプトでは、orbdを実行しているウィンドウを選択してCtrl+Cと入力すると停止します。Solaris、LinuxまたはMac OS Xのシェルでは、プロセスを見つけて終了(kill)します。ネーム・サーバーを明示的に停止するまでは、呼出し待機状態が続きます。
「2台のマシンで実行するHello Worldプログラム」では、クライアントとサーバーという2台のマシンで簡単なアプリケーションを分散させる方法の一例を示します。