このドキュメントは、インタフェースを定義する IDL (Interface Definiton Language) とスタブおよびスケルトンを生成する Java IDL コンパイラを使い、完全な CORBA (Common Object Request Broker Architecture) アプリケーションを作成する方法について、高レベルの概要を説明したものです。 このドキュメントでは、POA-Tie サーバ側モデルの使い方を説明します。 他の実装から継承しなければならない場合、標準の継承モデルではなく Tie モデルを使用することがあります。 Java の場合は、インタフェースの継承の個数に制限はありませんが、クラスの継承に使用できるスロットは 1 つだけです。 継承モデルを使用した場合は、そのスロットが占有されます。 Tie モデルを使用した場合は、そのスロットが使用されず、ユーザが独自の目的で使用することができます。 ただし、間接参照のレベルが 1 つ導入されるという欠点があります。 つまり、メソッドを呼び出すときに余分なメソッド呼び出しが発生します。
このプログラミングモデルの別の側面にはポータブルオブジェクトアダプタ (POA) があり、次の目標を満たすように設計されています。
CORBA は IDL インタフェースを実装するサーバ側マッピングのうち、少なくとも次の 2 種類をサポートしています。
継承モデルを使って、コンパイラが作成したスケルトンの拡張も行う実装クラスを使い、IDL インタフェースを実装します。
継承モデルには、次のものが含まれています。
注: ImplBase は POA モデルがあるので推奨されませんが、バージョン 1.3 以前の J2SE で記述されたサーバと互換性を持つために提供されています。 これは非標準モデルなので、これを使って新しいサーバを作成することはお勧めしません。
委譲モデルを使い、次の 2 つのクラスを使って IDL インタフェースを実装します。
委譲モデルは、Tie モデルや Tie 委譲モデルとしても知られています。 このモデルは POA または ImplBase コンパイラで作成されたスケルトンのどちらかを継承するので、このドキュメントでは POA/Tie または ImplBase/Tie モデルのように記述されます。
このチュートリアルでは、サーバ側実装の Tie 委譲/POA モデルを扱います。 他のサーバ側実装を使用するチュートリアルは、次のドキュメントを参照してください。
このドキュメントは完全な CORBA アプリケーションの作成を説明したチュートリアルで、IDL を使ってインタフェースを定義し、Java IDL コンパイラを使って POA 継承モデルであるデフォルトの IDL-to-Java 言語マッピングを生成します。 バージョン 1.3 以前の J2SDK で記述されたサーバとの互換性を保つには、ImplBase 継承モデルを使用します。
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 ベースのサーバ側マッピングが生成されます。
このドキュメントでは、次の内容について説明します。
CORBA アプリケーション作成の第一段階は、OMG のインタフェース定義言語 (IDL) を使って、オブジェクトとインタフェースをすべて記述することです。 IDL には C++ に似た構文があり、これを使ってモジュール、インタフェース、データ構造などを定義することができます。 IDL はさまざまなプログラミング言語にマッピングできます。 IDL を Java にマッピングする方法は「IDL と Java 言語のマッピングの概要」で説明しています。
次のコードは OMG IDL で記述されたもので、CORBA オブジェクトの sayHello() オペレーションが文字列 (string) を返し shutdown() メソッドが ORB を停止させています。 OMG IDL の構文とセマンティクスの詳細は、OMG の Web サイトで CORBA Specification の第 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 は、IDL インタフェース Hello の実装です。つまり、Hello の各インスタンスは、 HelloImpl のインスタンスにより実装されます。 このサーバントは HelloPOA のサブクラスで、 例題 IDL から idlj コンパイラにより生成されます。 サーバントには、IDL のオペレーションごとに 1 つのメソッドが含まれます。 この例では sayHello() メソッドと shutdown() メソッドが含まれます。 サーバントメソッドは、 Java の通常のメソッドと変わりません。ORB 関連処理を行うコードは 引数や結果の整列化などを行い、 スケルトンで提供されます。
HelloServer クラスにはサーバの main() メソッドが含まれます。この 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 // 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"; 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 サービスです。 ネームバインディングはネームサービスに格納され、クライアントは名前を提供して目的のオブジェクト参照を取得できます。 J2SE v.1.4 のネーミングサービスには 2 つのオプションがあります。一時ネーミングサービスである tnameserv と、ネームサービスを含む orbd です。 この例では 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 オプションの内容については、IDL-to-Java コンパイラのオプションを参照してください。
idlj コンパイラでは多数のファイルが生成されます。 実際に生成されるファイルの数は、IDL ファイルのコンパイル時に選択されたオプションによって異なります。 生成されたファイルには標準の機能があるので、プログラムを配置して実行するまでは無視してもかまいません。 Hello.idl の idlj コンパイラで、コマンド行の -fall オプションを使って生成されるファイルは次のとおりです。
この抽象クラスはストリームベースのサーバスケルトンで、サーバ用に基本的な CORBA 機能を提供します。 これは org.omg.PortableServer.Servant を継承し、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 型のパブリックインスタンスメンバが入ります。 IDL 型のパラメータが out または inout であれば Holder クラスが使用されます。 ここでは、org.omg.CORBA.portable.OutputStream および org.omg.CORBA.portable.InputStream 引数に対するオペレーションが規定されます。これらの引数は CORBA には存在しますが、Java のセマンティクスには簡単にマッピングできません。 Holder クラスは Helper クラスのメソッドに入出力を委譲します。 Holder クラスは 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
UNIX コマンドシェルで 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 プログラム」を参照してください。
UNIX コマンドシェルで 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 のようになります。
java HelloClient -ORBInitialPort 1050 -ORBInitialHost localhost
この例の -ORBInitialHost localhost は省略することができます。ネームサーバが Hello クライアントとして同一ホスト上で動作しているからです。 ネームサーバが別のホストで動作している場合は、IDL ネームサーバが動作しているホストを -ORBInitialHost nameserverhost で指定します。
前回の手順と同様にネームサーバ (orbd) のポートを指定します。たとえば -ORBInitialPort 1050 のようになります。
このチュートリアルを終了したら、ネームサーバ (orbd) を停止するか終了してください。 DOS プロンプトでは、orbd を実行しているウィンドウを選択して Ctrl+C と入力すると停止します。 UNIX シェルでは、プロセスを検出して終了 (kill) します。 ネームサーバを明示的に停止するまでは、呼び出し待機状態が続きます。
「2 台のマシンで実行する Hello World プログラム」では、クライアントとサーバという 2 台のマシンで簡単なアプリケーションを分散させる方法の一例を示します。
ホーム |
Copyright © 1995-2001 Sun Microsystems, Inc. All Rights Reserved.