このドキュメントは、インタフェースを定義するIDL (Interface Definiton Language)とスタブおよびスケルトンを生成するJava IDLコンパイラを使い、完全なCORBA (Common Object Request Broker Architecture)アプリケーションを作成する方法について、高レベルの概要を説明したものです。このドキュメントでは、ImplBase継承サーバー側モデルの使い方を説明します。
idljコンパイラはPOA継承モデルに基づくサーバー側マッピングをデフォルトで生成します。既存のアプリケーションとの互換性を保つため、idljコンパイラに新しいフラグ-oldImplBaseが追加されました。これにより、ImplBase継承モデルに基づくサーバー側マッピングを作成できます。
注: ImplBaseはPOAモデルがあるので非推奨ですが、バージョン1.3以前のJ2SEで記述されたサーバーと互換性を持つために提供されています。この非標準モデルを使って新しいサーバーを作成することはお薦めしません。
このドキュメントでは、次の内容について説明します。
Hello.idl
)CORBAアプリケーション作成の第一段階は、OMGのインタフェース定義言語(IDL)を使って、オブジェクトとインタフェースをすべて記述することです。IDLにはC++に似た構文があり、これを使ってモジュール、インタフェース、データ構造などを定義することができます。IDLはさまざまなプログラミング言語にマッピングできます。IDLをJavaにマッピングする方法は「IDLとJava言語のマッピングのサマリー」で説明しています。
次のコードはOMG IDLで記述されたもので、sayHello()オペレーションが文字列(string)を返しshutdown()オペレーションがORBを停止させるCORBAオブジェクトを記述しています。OMG IDLの構文とセマンティックスの詳細は、OMGのWebサイトでCORBA Specificationの第3章を参照してください。
Hello.idl
module HelloApp { interface Hello { string sayHello(); oneway void shutdown(); }; };注: OMG IDLでコードを記述する場合、モジュール名にインタフェース名を使用しないでください。モジュール名にインスタンス名を使用すると、異なるベンダーのツールを使用したコンパイル実行時に、結果の整合性が維持されなくなる危険があります。その結果、コードの移植性が損なわれます。たとえば、同じ名前を含むコードをIDL-to-Javaコンパイラを使用してコンパイルすると、1つの結果が得られます。同じコードを別のベンダーのIDL-to-Javaコンパイラを使用してコンパイルすると、別の結果になる場合があります。
アプリケーションを完成させるには、サーバー(HelloServer.java
)およびクライアント(HelloClient.java
)実装を提供します。
HelloServer.java
)ここで紹介するサーバーは、サーバントとサーバーの2つのクラスで構成されます。サーバントHelloImplはHello IDLインタフェースの実装で、各HelloインスタンスはHelloImplインスタンスによって実装されます。サーバントは、idljコンパイラにより例のIDLから生成される_HelloImplBaseのサブクラスです。サーバントには、IDLオペレーションごとに1つのメソッドが含まれます(この例では、sayHello()およびshutdown()メソッド)。サーバント・メソッドは、Javaの通常のメソッドと変わりはありません。ORBの処理、引数や結果の整列化などを行うコードは、スケルトンで実装します。
HelloServerクラスにはサーバーのmain()メソッドが含まれます。
ImplBaseサーバー側実装のHelloServerは、POA実装の場合とは少し異なります。ルートPOAの参照を取得してPOAManagerを起動するPOAベースのサーバーのセクションは必要ありません。次のようになります。
HelloServer.java
// Copyright and License import HelloApp.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; import java.util.Properties; class HelloImpl extends _HelloImplBase{ 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); // create servant and register it with the ORB HelloImpl helloImpl = new HelloImpl(); helloImpl.setORB(orb); // get the root naming context org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); Hello href = HelloHelper.narrow(helloImpl); // bind the Object Reference in Naming NameComponent nc = new NameComponent("Hello", ""); NameComponent path[] = {nc}; 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
)後述のアプリケーション・クライアントの例はデフォルトのチュートリアルで示したものと似ていますが、この例では下位互換性を保つために、新機能のInteroperable Naming Serviceは使用されていません。クライアント・アプリケーションの例:
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"); NamingContext ncRef = NamingContextHelper.narrow(objRef); // resolve the Object Reference in Naming NameComponent nc = new NameComponent("Hello", ""); NameComponent path[] = {nc}; Hello helloImpl = HelloHelper.narrow(ncRef.resolve(path)); 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と、ブートストラップ・サービス、一時ネーム・サービス、持続ネーム・サービスおよびサーバー・マネージャを含むデーモン・プロセスであるorbd (Solaris、Linux、Mac OS XまたはWindows)です。この例ではorbdを使用しています。
この例を実行するにあたって、Solarisソフトウェアの使用時は、ポート1024未満でプロセスを開始する場合、rootになる必要があることを思い出してください。このため、1024以上のポートを使用することをお薦めします。この例では、-ORBInitialPortオプションを使ってデフォルトのポート番号をオーバーライドします。次の説明では、Java IDL Object Request Broker Daemon orbd用にポート1050を使用できることを前提としています。必要であれば別のポートに変更してください。Windowsでこの例を実行する場合は、パス名にバックスラッシュ(\)を使用します。
開発マシンでこのクライアント・サーバー・アプリケーションを実行するには、次のようにします。
注: ImplBaseはPOAモデルがあるので非推奨ですが、バージョン1.3以前のJ2SEで記述されたサーバーと互換性を持つために提供されています。この非標準モデルを使って新しいサーバーを作成することはお薦めしません。
idlj -fall -oldImplBase Hello.idl
idljコンパイラの-fallオプションを使って、クライアントとサーバー側のバインディングの両方を生成する必要があります。このコマンド行でデフォルトのサーバー側バインディングが生成されます。これはPOAプログラミング・モデルであることを前提にしています。-oldImplBaseオプションは、デフォルトのPOA継承モデル・サーバー側バインディングではなくImplBase継承モデル・サーバー側バインディングを生成するよう、コンパイラに指示します。idljのオプションの詳細は、idljのマニュアル・ページ(Solaris、Linux、Mac OS XまたはWindows)を参照してください。
idljコンパイラではいくつかのファイルが生成されます。実際に生成されるファイルの数は、IDLファイルのコンパイル時に選択されたオプションによって異なります。生成されたファイルには標準の機能があるので、プログラムを配置して実行するまでは無視してもかまいません。Hello.idlのidljコンパイラで、-fallコマンド行オプションを使って生成されるファイルは次のとおりです。
このabstractクラスはサーバー・スケルトンで、サーバー用に基本的なCORBA機能を提供します。このクラスで、InvokeHandlerとHelloインタフェースが実装されます。これはorg.omg.CORBA.portable.ObjectImplを継承します。サーバー・クラスHelloImplは_HelloImplBaseを継承します。
このクラスはクライアント・スタブで、クライアント用にCORBA機能を提供します。これはorg.omg.CORBA.portable.ObjectImplを継承し、Helloインタフェースを実装します。
このインタフェースには作成した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 -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 !! HelloServer Exiting ...
このチュートリアルを終了したら、ネーム・サーバー(orbd)を停止するか終了してください。DOSプロンプトからこれを実行するには、サーバーを実行しているウィンドウを選択してCtrl+Cと入力すると停止します。Solaris、LinuxまたはMac OS Xのシェルでは、プロセスを見つけて終了(kill)します。サーバーを明示的に停止するまでは、呼出し待機状態が続きます。
「2台のマシンで実行するHello Worldプログラム」では、クライアントとサーバーという2台のマシンで簡単なアプリケーションを分散させる方法の一例を示します。