このドキュメントは、インタフェースを定義するIDL (Interface Definiton Language)とスタブおよびスケルトンを生成するJava IDLコンパイラを使い、完全なCORBA (Common Object Request Broker Architecture)アプリケーションを作成する方法について、高レベルの概要を説明したものです。開発プロセスの詳細情報と、IDLを使ってCORBAアプリケーションを作成する方法の詳細なチュートリアルは、「Java IDL入門: Hello Worldのチュートリアル」を参照してください。また、Javaプログラミング言語でインタフェースを定義してCORBAアプリケーションを作成することもできます。この開発プロセスの詳細とチュートリアルについては、Java RMI-IIOPドキュメントを参照してください。
一時サーバーと持続サーバーの比較の詳細については、「サーバーの開発」を参照してください。
このドキュメントでは、次の内容について説明します。
PersistentHello.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章を参照してください。
PersistentHello.idl
module Persistent { interface Hello { string sayHello( ); oneway void shutdown(); }; };注: OMG IDLでコードを記述する場合、モジュール名にインタフェース名を使用しないでください。モジュール名にインスタンス名を使用すると、異なるベンダーのツールを使用したコンパイル実行時に、結果の整合性が維持されなくなる危険があります。その結果、コードの移植性が損なわれます。たとえば、同じ名前を含むコードをIDL-to-Javaコンパイラを使用してコンパイルすると、1つの結果が得られます。同じコードを別のベンダーのIDL-to-Javaコンパイラを使用してコンパイルすると、別の結果になる場合があります。
アプリケーションを完成させるには、サーバー(PersistentServer.java
)、サーバント(PersistentHelloServant.java
)、およびクライアント(PersistentClient.java
)を実装します。
PersistentServer.java
)このサーバー例(PersistentServer)にはサーバーのmain()メソッドが含まれます。このmain()メソッドでは、次の処理を行います。
この例では、持続オブジェクト・サーバーの例を示します。一時オブジェクト・サーバーを使用する「Hello World」プログラムの例については、「一時サーバーを使ったHello Worldの例」を参照してください。CORBAサーバーの詳細については、「サーバーの開発」を参照してください。
PersistentServer.java
// PersistentServer.java // Copyright and License import java.util.Properties; import org.omg.CORBA.Object; import org.omg.CORBA.ORB; import org.omg.CosNaming.NameComponent; import org.omg.CosNaming.NamingContextExt; import org.omg.CosNaming.NamingContextExtHelper; import org.omg.CORBA.Policy; import org.omg.PortableServer.POA; import org.omg.PortableServer.*; import org.omg.PortableServer.Servant; public class PersistentServer { public static void main( String args[] ) { Properties properties = System.getProperties(); properties.put( "org.omg.CORBA.ORBInitialHost", "localhost" ); properties.put( "org.omg.CORBA.ORBInitialPort", "1050" ); try { // Step 1: Instantiate the ORB ORB orb = ORB.init(args, properties); // Step 2: Instantiate the servant PersistentHelloServant servant = new PersistentHelloServant(orb); // Step 3 : Create a POA with Persistent Policy // ******************* // Step 3-1: Get the rootPOA POA rootPOA = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); // Step 3-2: Create the Persistent Policy Policy[] persistentPolicy = new Policy[1]; persistentPolicy[0] = rootPOA.create_lifespan_policy( LifespanPolicyValue.PERSISTENT); // Step 3-3: Create a POA by passing the Persistent Policy POA persistentPOA = rootPOA.create_POA("childPOA", null, persistentPolicy ); // Step 3-4: Activate PersistentPOA's POAManager, Without this // All calls to Persistent Server will hang because POAManager // will be in the 'HOLD' state. persistentPOA.the_POAManager().activate( ); // *********************** // Step 4: Associate the servant with PersistentPOA persistentPOA.activate_object( servant ); // Step 5: Resolve RootNaming context and bind a name for the // servant. // NOTE: If the Server is persistent in nature then using Persistent // Name Service is a good choice. Even if ORBD is restarted the Name // Bindings will be intact. To use Persistent Name Service use // 'NameService' as the key for resolve_initial_references() when // ORBD is running. org.omg.CORBA.Object obj = orb.resolve_initial_references( "NameService" ); NamingContextExt rootContext = NamingContextExtHelper.narrow( obj ); NameComponent[] nc = rootContext.to_name( "PersistentServerTutorial" ); rootContext.rebind( nc, persistentPOA.servant_to_reference( servant ) ); // Step 6: We are ready to receive client requests orb.run(); } catch ( Exception e ) { System.err.println( "Exception in Persistent Server Startup " + e ); } } }
PersistentHelloServant.java
)サーバント例PersistentHelloServantはHello IDLインタフェースの実装で、各HelloインスタンスはPersistentHelloServantインスタンスによって実装されます。サーバントは、idljコンパイラにより例のIDLから生成されるHelloPOAのサブクラスです。サーバントには、IDLオペレーションごとに1つのメソッドが含まれます(この例では、sayHello()およびshutdown()メソッド)。サーバント・メソッドは、Javaの通常のメソッドと変わりはありません。ORBの処理、引数や結果の整列化などを行うコードは、スケルトンで実装します。
PersistentHelloServant.java
// PersistentHelloServant.java // Copyright and License import org.omg.CORBA.ORB; public class PersistentHelloServant extends Persistent.HelloPOA { private ORB orb; public PersistentHelloServant( ORB orb ) { this.orb = orb; } /** * sayHello() method implementation returns a simple message. */ public String sayHello( ) { return "Hello From Persistent Server..."; } /** * shutdown() method shuts down the Persistent Server. * See NOTE below. */ public void shutdown( ) { orb.shutdown( false ); } }
注: この例では、説明のために、shutdown()メソッドをサーバントの一部として含めています。このメソッドが含まれるのは、この例のサーバーの持続性を示すためです。この方法は、次の理由により、プログラミング方法としては非推奨です。
PersistentClient.java
)このアプリケーション・クライアントでは、次の処理を行います。
PersistentClient.java
// Copyright and License import java.util.Properties; import org.omg.CORBA.ORB; import org.omg.CORBA.OBJ_ADAPTER; import org.omg.CosNaming.NamingContext; import org.omg.CosNaming.NamingContextHelper; import org.omg.CosNaming.NameComponent; import org.omg.PortableServer.POA; import Persistent.HelloHelper; import Persistent.Hello; public class PersistentClient { public static void main(String args[]) { try { // Step 1: Instantiate the ORB ORB orb = ORB.init(args, null); // Step 2: Resolve the PersistentHelloServant by using INS's // corbaname url. The URL locates the NameService running on // localhost and listening on 1050 and resolve // 'PersistentServerTutorial' from that NameService org.omg.CORBA.Object obj = orb.string_to_object( "corbaname::localhost:1050#PersistentServerTutorial"); Hello hello = HelloHelper.narrow( obj ); // Step 3: Call the sayHello() method every 60 seconds and shutdown // the server. Next call from the client will restart the server, // because it is persistent in nature. while( true ) { System.out.println( "Calling Persistent Server.." ); String helloFromServer = hello.sayHello(); System.out.println("Message From Persistent Server: " + helloFromServer ); System.out.println( "Shutting down Persistent Server.." ); hello.shutdown( ); Thread.sleep( 60000 ); } } catch ( Exception e ) { System.err.println( "Exception in PersistentClient.java..." + e ); e.printStackTrace( ); } } }
Hello Worldプログラムは単純ですが、このプログラムを通して、静的な呼び出しを使用するほとんどのCORBAプログラムの開発に必要なタスクすべてを学び、経験できます。
この例ではネーム・サービスが必要です(オブジェクト参照に名前をバインドしてCORBAオブジェクトに命名できるCORBAサービス)。ネーム・バインディングはネーム・サービスに格納され、クライアントは名前を与えて目的のオブジェクト参照を取得できます。この例では、持続ネーム・サービスとサーバー・マネージャを含むorbd (Solaris、Linux、Mac OS XまたはWindows)を使用します。
この例を実行するにあたって、Solarisソフトウェアの使用時は、ポート1024未満でプロセスを開始する場合、rootユーザーになる必要があります。このため、1024以上のポートを使用することをお薦めします。次の説明では、-ORBInitialPortオプションを使って、Java IDL Object Request Broker Daemon (orbd)用にポート1050を使用するように設定できることを前提としています。必要であれば別のポートに変更してください。
開発マシンでこのクライアント・サーバー・アプリケーションを実行するには、次のようにします。
idlj -fall -td . -verbose PersistentHello.idl
idljコンパイラの-fallオプションを使って、クライアントとサーバー側のバインディングの両方を生成する必要があります。このコマンド行でデフォルトのサーバー側バインディングが生成されます。これはPOA継承サーバー側モデルであることを前提にしています。idljのオプションの詳細は、idljのマニュアル・ページ(Solaris、Linux、Mac OS XまたはWindows)を参照してください。
idljコンパイラではいくつかのファイルが生成されます。実際に生成されるファイルの数は、IDLファイルのコンパイル時に選択されたオプションによって異なります。生成されたファイルには標準の機能があるので、プログラムを配置して実行するまでは無視してもかまいません。PersistentHello.idlのidljコンパイラで、-fallコマンド行オプションを使って生成されるファイルは次のとおりです。
このabstractクラスは、ストリーム・ベースのサーバー・スケルトンで、サーバー用に基本的なCORBA機能を提供します。これはorg.omg.PortableServer.Servantを拡張し、InvokeHandlerインタフェースとHelloOperationsインタフェースを実装します。サーバー・クラスPersistentHelloServantはHelloPOAを拡張します。
このクラスはクライアント・スタブで、クライアント用に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 Persistent/*.java
orbdを起動するには、次のいずれかを入力します。
Solaris、LinuxまたはMac OS Xオペレーティング・システム:
orbd -ORBInitialPort 1050 -serverPollingTime 200&
Windowsオペレーティング・システム:
start orbd -ORBInitialPort 1050 -serverPollingTime 200&
1050はネーム・サーバーを実行するポートです。-ORBInitialPort引数は必須のコマンド行引数です。Solarisソフトウェアの使用時は、1024より小さいポートでプロセスを開始する場合は、rootユーザーになる必要があります。このため、1024以上のポートを使用することをお薦めします。
-serverPollingTime 200引数は、servertoolを使用して登録された持続サーバーが正常に動作していることをORBDが確認する回数を指定します。デフォルト値は1,000ミリ秒です。この例では、頻繁に障害をモニタリングできるように、このパラメータを200ミリ秒に設定します。サーバーの障害が検出された場合は、適切な状態になるようにサーバーが再起動されます。
持続サーバーをORBDに登録するには、servertool (Solaris、Linux、Mac OS XまたはWindows)を使用してサーバーを起動する必要があります。servertoolは、アプリケーション・プログラマが、持続サーバーの登録、登録解除、起動および停止を行うためのコマンド行インタフェースです。servertoolを起動したら、orbdが実行されているポートとホスト(異なる場合)を指定する必要があります。
Helloサーバーを起動するには
servertool -ORBInitialPort 1050 (Solaris, Linux, or Mac OS X operating system) start servertool -ORBInitialPort 1050 (Windows operating system)
前回の手順と同様にネーム・サーバー(orbd)のポートを指定します。たとえば-ORBInitialPort 1050のようになります。servertoolは、ネーム・サーバーと同じポート上で起動する必要があります。
servertoolコマンド行インタフェースが表示されます。
servertool > register -server PersistentServer -applicationName s1 -classpath path_to_server_class_files
servertoolによってサーバーが登録されて、「s1」という名前がサーバーに割り当てられ、サーバーIDが表示されます。
java -classpath . PersistentClient
端末ウィンドウまたはDOSプロンプトに次のメッセージが表示されます。
Calling Persistent Server.. Message From Persistent Server: Hello From Persistent Server... Shutting down Persistent Server.. Calling Persistent Server.. Message From Persistent Server: Hello From Persistent Server... Shutting down Persistent Server..
この例では、クライアントが1分間に一度sayHello()メソッドを起動し、持続サーバーを終了します。持続サーバーは、次にクライアントがsayHello()メソッドを起動したときに自動的に再起動されます。
このチュートリアルを終了したら、ネーム・サーバー(orbd)を停止するか終了してください。DOSプロンプトからこれを実行するには、サーバーを実行しているウィンドウを選択してCtrl+Cと入力すると停止します。Solaris、LinuxまたはMac OS Xのシェルでは、端末ウィンドウからpkill ordbと入力します。サーバーを明示的に停止するまでは、呼出し待機状態が続きます。
「2台のマシンで実行するHello Worldプログラム」では、クライアントとサーバーという2台のマシンで簡単なアプリケーションを分散させる方法の一例を示します。
次のコードは、この例を実行するために使用できるMakefileの例を示しています。JAVA_HOMEの場所は、実際にJ2SE 5.0をインストールした場所に変更してください。CLASSPATH変数は、サンプル・アプリケーションを作成したディレクトリに変更してください。この例は、Solaris、LinuxまたはMac OS Xオペレーティング・システムを想定して作成されています。Windowsオペレーティング・システムを使用している場合は、適宜変更を加えてください。
#Change to location of your Java SE installation. JAVA_HOME=/home/user_name/j2sdk1.5.0/ CLASSPATH=. JAVAC=$(JAVA_HOME)/bin/javac JAVA=$(JAVA_HOME)/bin/java ORB_INITIAL_PORT=1050 ORB_INITIAL_HOST=localhost ORB_ACTIVATION_PORT=1049 #Change ClassPath based on where your PersistentServer is located. export CLASSPATH=<path to server class files> IDLJ :=$(JAVA_HOME)/bin/idlj ORB_PROPS=-Dorg.omg.CORBA.ORBInitialHost=$(ORB_INITIAL_HOST) -Dorg.omg.CORBA.ORBInitialPort=$(ORB_INITIAL_PORT) IDLJ_FLAGS=-fall -td . -verbose ORBD=${JAVA_HOME}/bin/orbd -ORBInitialPort ${ORB_INITIAL_PORT} -port ${ORB_ACTIVATION_PORT} -serverPollingTime 200 -serverStartupDelay 1000 SERVERTOOL=${JAVA_HOME}/bin/servertool all: clean build run build: stubs stubs: $(IDLJ) $(IDLJ_FLAGS) PersistentHello.idl $(JAVAC) *.java $(JAVAC) Persistent/*.java runc: $(JAVA) -classpath . PersistentClient runorbd: $(ORBD) # Enter the following command in servertool to register server: # (without the # sign) # register -server PersistentServer -applicationName s1 -classpath path_to_server_class_files servertool: $(SERVERTOOL) -ORBInitialPort $(ORB_INITIAL_PORT) clean: rm -rf Persistent rm -rf *.class
Makefileを使用してアプリケーションを実行するには、次のコマンドを入力します。