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 ドキュメントを参照してください。

Java SE の今回のリリースで idlj コンパイラを使用して生成したサーバー側実装は Portable Servant Inheritance Model で、POA モデルとも呼ばれます。POA (ポータブルオブジェクトアダプタ) については「ポータブルオブジェクトアダプタ」で説明します。このドキュメントでは idlj コンパイラのデフォルトの動作を使って作成したサンプルアプリケーションを扱い、POA サーバー側モデルを使用します。

CORBA は IDL インタフェースを実装するサーバー側マッピングのうち、少なくとも次の 2 種類をサポートしています。

このチュートリアルでは、サーバー側実装の POA 継承モデルを扱います。ほかのサーバー側実装を使用するチュートリアルは、次のドキュメントを参照してください。

このドキュメントでは、次の内容について説明します。

この例を作成するには、サンプルアプリケーションを開発する場所として hello/ という名前のディレクトリを作成し、各ファイルをこのディレクトリ内に作成します。または、コード例をダウンロードし、サンプルアプリケーションのディレクトリに解凍します。

インタフェースの定義 (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 つのクラスで構成されます。サーバント HelloImplHello IDL インタフェースの実装で、各 Hello インスタンスは HelloImpl インスタンスによって実装されます。サーバントは、idlj コンパイラにより例の IDL から生成される HelloPOA のサブクラスです。サーバントには、IDL オペレーションごとに 1 つのメソッドが含まれます (この例では、sayHello() および shutdown() メソッド)。サーバントメソッドは、Java の通常のメソッドと変わりはありません。ORB の処理、引数や結果の整列化などを行うコードは、スケルトンで実装します。

HelloServer クラスにはサーバーの main() メソッドが含まれます。

この例では、一時オブジェクトサーバーの例を示します。持続オブジェクトサーバーを使用する「Hello World」プログラムの例については、「例 2: 持続性を備えた Hello World」を参照してください。CORBA サーバーの詳細については、「サーバーの開発」を参照してください。

コードの詳細は、チュートリアルの「Java IDL 入門: Hello World サーバーの開発」を参照してください。

HelloServer.java

// 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; 
  }
    
  // implement sayHello() method
  public String sayHello() {
    return "\nHello world !!\n";
  }
    
  // implement shutdown() method
  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); 

      // get object reference from the servant
      org.omg.CORBA.Object ref = rootpoa.servant_to_reference(helloImpl);
      Hello href = HelloHelper.narrow(ref);
          
      // get the root naming context
      // NameService invokes the name service
      org.omg.CORBA.Object objRef =
          orb.resolve_initial_references("NameService");
      // Use NamingContextExt which is part of the Interoperable
      // Naming Service (INS) 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)

このアプリケーションクライアントでは、次の処理を行います。

コードの詳細は、「Java IDL 入門: クライアントアプリケーションの開発」を参照してください。

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");
        // 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」の構築方法と実行方法

Hello World プログラムは単純ですが、このプログラムを通して、静的な呼び出しを使用するほとんどの CORBA プログラムの開発に必要なタスクすべてを学び、経験できます。コンパイル時にオブジェクトのインタフェースが既知の場合、呼び出しにはクライアントスタブを使用し、呼び出されるサービスにはサーバースケルトンを使用する静的な呼び出しが使用されます。コンパイル時にインタフェースが不明な場合は、動的呼び出しを使用する必要があります。

この例ではネームサービスが必要です (オブジェクト参照に名前をバインドして CORBA オブジェクトに命名できる CORBA サービス)。ネームバインディングはネームサービスに格納され、クライアントは名前を与えて目的のオブジェクト参照を取得できます。今回リリースされた Java SE に同梱されている 2 つのネームサービスのうち、1 つは、デーモンプロセスである orbd で、ブートストラップサービス、一時ネームサービス、持続ネームサービス、およびサーバーマネージャーが含まれています。もう 1 つは、一時ネームサービスである tnameserv で、下位互換性を維持するために用意されています。この例では orbd を使用しています。

この例を実行するにあたって、Solaris ソフトウェアの使用時は、ポート 1024 未満でプロセスを開始する場合、root になる必要があることを思い出してください。このため、1024 以上のポートを使用することをお勧めします。この例では、-ORBInitialPort オプションを使ってデフォルトのポート番号をオーバーライドします。次の説明では、Java IDL Object Request Broker Daemon orbd 用にポート 1050 を使用できることを前提としています。必要であれば別のポートに変更してください。Windows でこの例を実行する場合は、パス名にバックスラッシュ (\) を使用します。

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

  1. Hello.idl ファイルを格納しているディレクトリに変更します。
  2. IDL ファイルから IDL-to-Java コンパイラ idlj を実行して、スタブとスケルトンを作成します。この手順は、java/bin ディレクトリのパスを、使用するパスに含めていることを前提にしています。
      idlj -fall  Hello.idl
    

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

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

    • HelloPOA.java

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

    • _HelloStub.java

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

    • 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 インタフェースで定義されたオペレーションをすべてこのファイルに組み込み、スタブとスケルトンで共有します。

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

    UNIX コマンドシェルで orbd を起動するには、次のように入力します。

      orbd -ORBInitialPort 1050&
    

    Windows の MS-DOS システムプロンプトでは、次のように入力します。

      start orbd -ORBInitialPort 1050
    

    1050 はネームサーバーを実行するポートです。-ORBInitialPort 引数は必須のコマンド行引数です。Solaris ソフトウェアの使用時は、1024 より小さいポートでプロセスを開始する場合は、root ユーザーになる必要があります。このため、1024 以上のポートを使用することをお勧めします。

    このプログラムを 2 台のマシンで実行する方法の例は、「2 台のマシンで実行する Hello World プログラム」を参照してください。

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

    UNIX コマンドシェルで Hello サーバーを起動するには、次のように入力します。

      java HelloServer -ORBInitialPort 1050 -ORBInitialHost localhost&
    

    Windows の MS-DOS システムプロンプトでは、次のように入力します。

      start java HelloServer -ORBInitialPort 1050 -ORBInitialHost localhost
    

    サーバーが起動すると、HelloServer ready and waiting... と表示されます。

    この例の -ORBInitialHost localhost は、ネームサーバーが Hello サーバーとして同一ホスト上で動作しているため、省略できます。ネームサーバーが別のホストで動作している場合は、IDL ネームサーバーが動作しているホストを -ORBInitialHost nameserverhost で指定します。

    前回の手順と同様にネームサーバー (orbd) のポートを指定します (たとえば -ORBInitialPort 1050)。

  6. クライアントアプリケーションを実行します。
      java HelloClient -ORBInitialPort 1050 -ORBInitialHost localhost
    

    クライアントが実行されると、たとえば次のような応答が端末に表示されます。 Obtained a handle on server object: IOR: (binary code) Hello World! HelloServer exiting...

    この例の -ORBInitialHost localhost は、ネームサーバーが Hello クライアントとして同一ホスト上で動作しているため、省略できます。ネームサーバーが別のホストで動作している場合は、IDL ネームサーバーが動作しているホストを -ORBInitialHost nameserverhost で指定します。

    前回の手順と同様にネームサーバー (orbd) のポートを指定します (たとえば -ORBInitialPort 1050)。

このチュートリアルを終了したら、ネームサーバー (orbd) を停止するか終了してください。DOS プロンプトからこれを実行するには、サーバーを実行しているウィンドウを選択して Ctrl+C と入力すると停止します。UNIX シェルでは、プロセスを検出して終了 (kill) します。サーバーを明示的に停止するまでは、呼び出し待機状態が続きます。

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


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