Java IDL: 「Hello World」の例

POA、持続サーバー、および持続ネームサービスの使用

このドキュメントは、インタフェースを定義する 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 でコードを記述する場合、モジュール名にインタフェース名を使用しないでください。モジュール名にインスタンス名を使用すると、異なるベンダーのツールを使ったコンパイル実行時に、結果の整合性が維持されなくなる危険があります。その結果、コードの移植性が損なわれます。たとえば、同じ名前を含むコードを Sun Microsystems の 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)

サーバント例 PersistentHelloServantHello 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」の構築方法と実行方法

Hello World プログラムは単純ですが、このプログラムを通して、静的な呼び出しを使用するほとんどの CORBA プログラムの開発に必要なタスクすべてを学び、経験できます。

この例ではネームサービスが必要です (オブジェクト参照に名前をバインドして CORBA オブジェクトに命名できる CORBA サービス)。ネームバインディングはネームサービスに格納され、クライアントは名前を与えて目的のオブジェクト参照を取得できます。この例では、持続ネームサービスとサーバーマネージャーを含む orbd を使用します。

この例を実行するにあたって、Solaris ソフトウェアの使用時は、ポート 1024 未満でプロセスを開始する場合、root ユーザーになる必要があります。このため、1024 以上のポートを使用することをお勧めします。次の説明では、-ORBInitialPort オプションを使って、Java IDL Object Request Broker Daemon (orbd) 用にポート 1050 を使用するように設定できることを前提としています。必要であれば別のポートに変更してください。

開発マシンでこのクライアントサーバーアプリケーションを実行するには、次のようにします。

  1. この例の IDL ファイルと Java ファイルを作成するか、ダウンロードします。
  2. PersistentHello.idl ファイルが置かれているディレクトリに移動します。
  3. IDL ファイルから IDL-to-Java コンパイラ idlj を実行して、スタブとスケルトンを作成します。この手順は、java/bin ディレクトリのパスを、使用するパスに含めていることを前提にしています。
      idlj  -fall -td . -verbose  PersistentHello.idl
    

    idlj コンパイラの -fall オプションを使って、クライアントとサーバー側のバインディングの両方を生成する必要があります。このコマンド行でデフォルトのサーバー側バインディングが生成されます。これは POA 継承サーバー側モデルであることを前提にしています。idlj オプションの詳細については、IDL-to-Java コンパイラオプションを参照してください。

    idlj コンパイラではいくつかのファイルが生成されます。実際に生成されるファイルの数は、IDL ファイルのコンパイル時に選択されたオプションによって異なります。生成されたファイルには標準の機能があるので、プログラムを配置して実行するまでは無視してもかまいません。PersistentHello.idlidlj コンパイラで、-fall コマンド行オプションを使って生成されるファイルは次のとおりです。

    • HelloPOA.java

      この abstract クラスは、ストリームベースのサーバースケルトンで、サーバー用に基本的な CORBA 機能を提供します。これは org.omg.PortableServer.Servant を拡張し、InvokeHandler インタフェースと HelloOperations インタフェースを実装します。サーバークラス PersistentHelloServantHelloPOA を拡張します。

    • _HelloStub.java

      このクラスはクライアントスタブで、クライアント用に CORBA 機能を提供します。これは org.omg.CORBA.portable.ObjectImpl を拡張し、Hello インタフェースを実装します。

    • Hello.java

      このインタフェースには作成した IDL インタフェースの Java 版が含まれます。Hello.java インタフェースは、標準的な CORBA オブジェクト機能を提供する org.omg.CORBA.Object を拡張します。また HelloOperations インタフェースおよび org.omg.CORBA.portable.IDLEntity も拡張します。

    • HelloHelper.java

      このクラスは補助機能、特に CORBA オブジェクト参照を適切な型にキャストする必要がある narrow() メソッドを提供します。Helper クラスは CORBA ストリームへのデータ型の読み取りおよび書き込みと、Any のデータ型の挿入と抽出を扱います。Holder クラスは、Helper クラスのメソッドに読み取りおよび書き込みを委譲します。

    • HelloHolder.java

      この 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 を実装します。

    • HelloOperations.java

      このインタフェースには sayHello() メソッドおよび shutdown() メソッドが含まれます。IDL-to-Java マッピングは、IDL インタフェースで定義されたオペレーションをすべてこのファイルに組み込み、スタブとスケルトンで共有します。

  4. Persistent ディレクトリにあるスタブとスケルトンも含め、.java ファイルをコンパイルします。この手順は、java/bin ディレクトリが実行パスに含まれていることを前提にしています。
       javac *.java Persistent/*.java
    
  5. orbd を起動します。

    orbd を起動するには、次のいずれかを入力します。

    • Unix オペレーティングシステム:

      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 ミリ秒に設定します。サーバーの障害が検出された場合は、適切な状態になるようにサーバーが再起動されます。

  6. Hello サーバーを起動します。

    持続サーバーを ORBD に登録するには、servertool を使用してサーバーを起動する必要があります。servertool は、アプリケーションプログラマが、持続サーバーの登録、登録解除、起動、および停止を行うためのコマンド行インタフェースです。servertool を起動したら、orbd が実行されているポートとホスト (異なる場合) を指定する必要があります。

    Hello サーバーを起動するには

    • 次のように、別の端末ウィンドウのコマンド行またはコマンドプロンプトから servertool を起動します。
        servertool -ORBInitialPort 1050        (Unix operating system)
        
        start servertool -ORBInitialPort 1050  (Windows operating system) 
      

      前回の手順と同様にネームサーバー (orbd) のポートを指定します。たとえば -ORBInitialPort 1050 のようになります。servertool は、ネームサーバーと同じポート上で起動する必要があります。

      servertool コマンド行インタフェースが表示されます。

      Server Tool
    • 次に示すように、servertool のプロンプトから PersistentServer を登録します。次の情報は、改行しないで 1 つの長い文字列として入力します。
        servertool  > register -server PersistentServer -applicationName s1 
                      -classpath path_to_server_class_files 
      

      servertool によってサーバーが登録されて、「s1」という名前がサーバーに割り当てられ、サーバー ID が表示されます。

  7. 次のように、別の端末ウィンドウのコマンド行またはコマンドプロンプトからクライアントアプリケーションを実行します。
      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 と入力すると停止します。UNIX シェルでは、端末ウィンドウから pkill ordb と入力します。サーバーを明示的に停止するまでは、呼び出し待機状態が続きます。

2 台のマシンで実行する Hello World プログラム」では、クライアントとサーバーという 2 台のマシンで簡単なアプリケーションを分散させる方法の一例を示します。

UNIX 上での Makefile を使用した例の実行

次のコードは、この例を実行するために使用できる Makefile の例を示しています。JAVA_HOME の場所は、実際に J2SE 5.0 をインストールした場所に変更してください。CLASSPATH 変数は、サンプルアプリケーションを作成したディレクトリに変更してください。この例は、UNIX オペレーティングシステムを想定して作成されています。 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 を使用してアプリケーションを実行するには、次のコマンドを入力します。

  1. gnumake build
  2. gnumake runorbd
  3. gnumake runservertool
  4. servertool で、上記のコマンドを入力します。
  5. gnumake runc

Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.