Java IDL:ImplBase サーバー側モデルを使った「Hellow World」の例


このドキュメントは、インタフェースを定義する IDL (Interface Definiton Language) とスタブおよびスケルトンを生成する Java IDL コンパイラを使い、完全な CORBA (Common Object Request Broker Architecture) アプリケーションを作成する方法について、高レベルの概要を説明したものです。このドキュメントでは、ImplBase 継承サーバー側モデルの使い方を説明します。

idlj コンパイラは POA 継承モデルに基づくサーバー側マッピングをデフォルトで生成します。既存のアプリケーションとの互換性を保つため、idlj コンパイラに新しいフラグ -oldImplBase を追加して、ImplBase 継承モデルに基づくサーバー側マッピングを作成することができます。J2SE バージョン 1.3 以前で作成したサーバーと接続する必要がある既存のアプリケーションは、MAKEFILE を更新してこのフラグが利用できるようにする必要があります。ただし、そのような要求がない新規アプリケーションではこうしたマッピングは作成しないことをお勧めします。

注: ImplBase は POA モデルがあるので推奨されませんが、バージョン 1.3 以前の J2SE で記述されたサーバーと互換性を持つために提供されています。これは非標準モデルなので、これを使って新しいサーバーを作成することはお勧めしません。

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

インタフェース定義 (Hello.idl)

CORBA アプリケーション作成の第一段階は、OMG のインタフェース定義言語 (IDL) を使って、オブジェクトとインタフェースをすべて記述することです。IDL には C++ に似た構文があり、これを使ってモジュール、インタフェース、データ構造などを定義することができます。IDL はさまざまなプログラミング言語にマッピングできます。IDL を Java にマッピングする方法は「IDL と Java 言語のマッピングの概要」で説明しています。

次のコードは OMG IDL で記述されたもので、CORBA オブジェクトの sayHello() オペレーションが文字列を返し 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 のインスタンスにより実装されます。このサーバントは idltojava コンパイラにより上記の IDL から生成される _HelloImplBase のサブクラスです。 例題 IDL から idlj コンパイラにより生成されます。 サーバントには、IDL のオペレーションごとに 1 つのメソッドが含まれます。 この例では sayHello() メソッドと shutdown() メソッドが含まれます。サーバントメソッドは、 Java の通常のメソッドと変わりません。ORB 関連処理を行うコードは 引数や結果の整列化などを行い、 スケルトンで提供されます。

HelloServer クラスにはサーバーの main() メソッドが含まれます。この main() メソッドでは、次の処理を行います。

注: ImplBase は POA モデルがあるので推奨されませんが、バージョン 1.3 以前の J2SE で記述されたサーバーと互換性を持つために提供されています。これは非標準モデルなので、これを使って新しいサーバーを作成することはお勧めしません。

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

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

この例ではネームサービスが必要です。ネームサービスとは、オブジェクト参照に名前をバインドして CORBA オブジェクトに命名することができる CORBA サービスです。「ネームバインディング」はネームサービスに格納され、クライアントは名前を与えて目的のオブジェクト参照を取得できます。今回のバージョンの Java SE に同梱されているネームサービスには、2 つのオプションがあります。一時ネーミングサービスである tnameserv と、ブートストラップサービス、一時ネーミングサービス、持続ネーミングサービス、またはサーバーマネージャーを含むデーモンプロセスである orbd です。この例では orbd を使用します。

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

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

  1. プログラムファイルを作成するか、HelloImplBase.zip をダウンロードして解凍します。

  2. Hello.idl ファイルが置かれているディレクトリに移動します。

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

    注: ImplBase は POA モデルがあるので推奨されませんが、バージョン 1.3 以前の J2SE で記述されたサーバーと互換性を持つために提供されています。これは非標準モデルなので、これを使って新しいサーバーを作成することはお勧めしません。

      idlj -fall -oldImplBase Hello.idl
    

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

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

    • _HelloImplBase.java

      この抽象クラスはサーバースケルトンで、サーバー用に基本的な CORBA 機能を提供します。このクラスで、InvokeHandlerHello インタフェースが実装されます。これは org.omg.CORBA.portable.ObjectImpl を継承します。サーバークラス HelloImpl_HelloImplBase を継承します。

    • _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

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

    • HelloOperations.java

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

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

    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 プログラム」を参照してください。

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

    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 のようになります。

    サーバーが実行中になると、次のようなメッセージが端末に表示されます。

    HelloServer ready and waiting ...
     
  7. クライアントアプリケーションを実行します。

      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 と入力すると停止します。UNIX シェルでは、プロセスを検出して終了 (kill) します。サーバーを明示的に停止するまでは、呼び出し待機状態が続きます。

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


ホーム

Copyright © 1995-2004 Sun Microsystems, Inc. All Rights Reserved.