Java IDL 入門:
Hello World サーバの開発


ここで紹介するサーバは、サーバントとサーバの 2 つのクラスで構成されます。サーバントである HelloImpl は、Hello IDL インタフェースの実装です。つまり、Hello の各インスタンスは、HelloImpl のインスタンスにより実装されます。サーバントは、idlj コンパイラにより例の IDL から生成される HelloPOA のサブクラスです。

サーバントには、IDL 操作ごとに 1 つのメソッドが含まれます。この例では、sayHello() および shutdown() メソッドです。サーバントメソッドは、Java の通常のメソッドと変わりはありません。ORB の処理、引数や結果の整列化などを行うコードは、スケルトンで実装します。

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

このレッスンでは、CORBA サーバ作成の基本を学びます。持続オブジェクトサーバを備えた「Hello World」プログラムの例は、「例 2: 持続性を備えた Hello World」を参照してください。CORBA サーバの詳細については、「サーバの開発」を参照してください。

このレッスンの手順は次のとおりです。

  1. HelloServer.java の生成
  2. HelloServer.java の理解
  3. Hello World サーバのコンパイル


HelloServer.java の生成

HelloServer.java を生成するには、次のようにします。

  1. テキストエディタを起動して、HelloServer.java という名前のファイルをメインプロジェクトディレクトリの Hello に作成します。

  2. HelloServer.java の次のコードをテキストファイルに記述します。コードの各行の詳細については、次の「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
          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 ...");
    	
      }
    }
     

  3. HelloServer.java を保存して閉じます。

HelloServer.java の理解

ここでは、HelloServer.java の各行について、コードが何をしているか、またこのアプリケーションでなぜ必要なのかについて説明します。

基本設定

CORBA サーバプログラムの構造は、ほとんどの Java アプリケーションと同じです。つまり、必要なライブラリパッケージをインポートし、サーバクラスを宣言し、main() メソッドを定義し、そして例外の処理を行います。

必要なパッケージのインポート

まず、サーバクラスに必要なパッケージをインポートします。

// The package containing our stubs
import HelloApp.*;

// HelloServer will use the naming service
import org.omg.CosNaming.*;

// The package containing special exceptions thrown by the name service
import org.omg.CosNaming.NamingContextPackage.*;

// All CORBA applications need these classes
import org.omg.CORBA.*;

// Classes needed for the Portable Server Inheritance Model
import org.omg.PortableServer.*;
import org.omg.PortableServer.POA;

// Properties to initiate the ORB
import java.util.Properties;

サーバントクラスの定義

この例では、HelloServer.java 内の HelloServer クラスの外側に、サーバントオブジェクトのクラスを定義しています。

class HelloImpl extends HelloPOA
{
  // The sayHello() and shutdown() methods go here.
}

このサーバントは HelloPOA のサブクラスなので、コンパイラが HelloPOA のために生成した汎用の CORBA 機能を継承します。

まず、setORB(ORB) メソッドで使用されるプライベート変数 orb を作成します。setORB メソッドは、サーバントに ORB (値) を設定できるようにアプリケーション開発者により定義されるアプリケーション固有のメソッドです。この ORB 値は、クライアントからの shutdown() メソッドの呼び出しに応じて、固有の ORB 上で shutdown() を呼び出すために使用されます。

  private ORB orb;
  
  public void setORB(ORB orb_val) {
    orb = orb_val; 
  }

次に、必要な sayHello() メソッドを、宣言して実装します。

  public String sayHello()
  {
    return "\nHello world!!\n";   
  }

最後に、shutdown() メソッドを同様の方法で実装します。shutdown() メソッドは、ORB 用に org.omg.CORBA.ORB.shutdown(boolean) メソッドを呼び出します。shutdown(false) 操作は、ORB が処理の完了を待たずに、すぐにシャットダウンする必要があることを指示します。

  public void shutdown() {
    orb.shutdown(false);
  }

サーバクラスの宣言

次に、サーバクラスを宣言します。

public class HelloServer 
{
  // The main() method goes here.
}

main() メソッドの定義

すべての Java アプリケーションには main メソッドが必要です。このメソッドを次のように、HelloServer クラスのスコープ内で宣言します。

  public static void main(String args[])
  {
    // The try-catch block goes here.
  }

CORBA システム例外の処理

どの CORBA プログラムでも、実行時に CORBA システム例外が発生する可能性があるので、main() メソッドの機能は、すべて try-catch ブロック内に記述します。CORBA プログラムは、呼び出しに伴うプロセス (整列化、非整列化、アップコール) で問題が発生すると、システム例外を発生させます。このレッスンの例外ハンドラは簡単なもので、どんな問題が起こったかが分かるように、例外の名前とそのスタックトレースを標準出力に出力します。

main() の中に、次の try-catch ブロックを記述します。

    try{
    
      // The rest of the HelloServer code goes here.
    
    } catch(Exception e) {
        System.err.println("ERROR: " + e);
        e.printStackTrace(System.out);
      }

ORB オブジェクトの生成および初期化

CORBA サーバには、CORBA クライアントと同様にローカル ORB オブジェクトが必要です。各サーバは ORB のインスタンスを生成し、それが呼び出しを受けたときにサーバを検索できるように、そのサーバントオブジェクトを登録します。

try-catch ブロックの中で、ORB 変数を宣言して初期化します。

      ORB orb = ORB.init(args, null);

ORB の init() メソッドの呼び出しは、サーバのコマンド行引数に渡されるので、実行時に特定のプロパティを設定できます。

ルート POA への参照の取得および POAManager の起動

ORB は、resolve_initial_references メソッドを使用するネームサービスなどのサービスに対する初期のオブジェクト参照を取得します。

ルート POA への参照が取得され、POAManager が try-catch ブロックの中で起動されます。

      POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
      rootpoa.the_POAManager().activate();

activate() 操作は、POA マネージャの状態をアクティブに変更します。その結果、関連付けられた POA は要求の処理を開始します。POA マネージャは、関連付けられている POA の処理状態をカプセル化します。各 POA オブジェクトには、1 つの POAManager オブジェクトが関連付けられています。POA マネージャは、1 つ以上の POA オブジェクトに関連付けられていることがあります。

サーバントオブジェクトの管理

サーバとは、1 つ以上のサーバントオブジェクトのインスタンスを生成するプロセスです。サーバントは、idlj が生成したインタフェースから継承し、そのインタフェース上で実際の操作を行います。このレッスンの HelloServer には 1 つの HelloImpl が必要です。

サーバントオブジェクトのインスタンスの生成

次のように、POA マネージャを起動した直後に、try-catch ブロックの中でサーバントオブジェクトのインスタンスを生成します。

      HelloImpl helloImpl = new HelloImpl();

サーバントクラスを記述するコードについては、すでに説明されています。

次のコード行は、ORB.shutdown() をシャットダウン操作の一部として呼び出せるようにするため、setORB(orb) はサーバントで定義されています。この手順が必要なのは、shutdown() メソッドが Hello.idl に定義されているからです。

      helloImpl.setORB(orb); 

シャットダウン操作の実装には、他の方法もあります。この例では、Object 上で呼び出された shutdown() メソッドは、ORB のシャットダウンを行います。別の実装例では、シャットダウンメソッドの実装はフラグを設定するだけで済みます。サーバがフラグを確認し shutdown() を呼び出します。

次の一連のコードは、サーバントに関連付けられたオブジェクト参照の取得に使用されます。narrow() メソッドは、CORBA オブジェクト参照を適切な型に変換するために必要です。

      org.omg.CORBA.Object ref = rootpoa.servant_to_reference(helloImpl);
      Hello href = HelloHelper.narrow(ref);

COS ネーミングの利用

HelloServer は COS (Common Object Services) ネームサービスを利用して、クライアント側からサーバントオブジェクトの操作を利用可能にします。サーバは、さまざまなインタフェースを実装しているオブジェクトの参照を発行できるようにするため、ネームサービスへのオブジェクト参照が必要です。これらのオブジェクト参照は、クライアントがメソッドを呼び出すのに使用されます。サーバントがオブジェクトをクライアント側から呼び出させることができるようにするもう 1 つの方法は、ファイルへのオブジェクト参照を文字列化することです。

J2SE v1.4 に付属しているネームサービスには、次の 2 つのオプションがあります。

この例では orbd を使用します。

初期ネーミングコンテキストの取得

try-catch ブロックの中で、サーバントのオブジェクト参照を取得すると、次に orb.resolve_initial_references() を呼び出してネームサーバへのオブジェクト参照を取得します。

      org.omg.CORBA.Object objRef =
          orb.resolve_initial_references("NameService");

文字列 「NameService」 は、すべての CORBA ORB に対して定義されています。この文字列を渡すと、ORB はネームサービスへのオブジェクト参照であるネーミングコンテキストオブジェクトを返します。文字列 NameService は、次のことを示しています。

独自の文字列 TNameService は、ORBD のネームサービスを使用するときは、一時ネームサービスとなることを示しています。

オブジェクト参照のナロー変換

CORBA のどのオブジェクト参照とも同様に、objRef は汎用の CORBA オブジェクトです。これを NamingContextExt object として使うには、適切な型にナロー変換する必要があります。narrow() の呼び出しは、前の文の直後にあります。

      NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

これは、idlj から生成されるヘルパークラスの使用方法です。それらは HelloHelper に機能的に類似しています。ここで ncRef オブジェクトは org.omg.CosNaming.NamingContextExt になったので、次のステップで指示されるように、これを使ってネームサービスにアクセスし、サーバを登録することができます。

NamingContextExt オブジェクトは、J2SE v1.4 で新たに追加されたもので、Interoperable Naming Service の仕様の一部です。

ネームサーバへのサーバントの登録

narrow() の呼び出しの直後に、新しい NameComponent 配列を作成します。NamingContext.resolve には作業用に配列が必要です。Hello オブジェクトへのパスには要素が 1 つしかないので、単一要素の配列を作成します。

      String name = "Hello";
      NameComponent path[] = ncRef.to_name( name );

path とサーバントオブジェクトをネームサービスに引き渡して、サーバントオブジェクトを 「Hello」id に結びつけます。

      ncRef.rebind(path, href);

これで、クライアントが初期ネーミングコンテキストで resolve("Hello") を呼び出すと、ネームサービスから Hello サーバントへのオブジェクト参照が返されます。

呼び出し待ち

前の節では、サーバを準備するためのコードの説明をしました。次の節では、クライアントがサービスを要求するのを待つコードについて説明します。try-catch ブロック内の最後にある次のコードは、これを実行するためのものです。

      orb.run();

ORB.run() は、メインスレッドによって呼び出されると、ORB がそのメインスレッドを使って動作できるようになるため、ORB からの呼び出しを受け取るまで待機します。呼び出しは main() の try-catch ブロックの中にあるので 、呼び出しが終了して sayHello() が復帰したのち、サーバは再び呼び出し待ちに戻ります。タスクの終了後に HelloClient が明示的に ORB をシャットダウンするのはこのためです。


Hello World サーバのコンパイル

ここで HelloServer.java をコンパイルし、エラーを修正してからレッスンを続けます。

Windows ユーザは、このマニュアルのパスのスラッシュ (/) をバックスラッシュ (\) に置き換えてください。

HelloServer.java をコンパイルするには、次のようにします。

  1. Hello ディレクトリへ移動します。

  2. HelloServer.java に対して Java コンパイラを実行します。
    javac HelloServer.java HelloApp/*.java
    
  3. ファイルにエラーがあれば、修正してコンパイルし直します。

  4. HelloServer.classHelloImpl.class ファイルは、Hello ディレクトリ内に生成されます。

Hello World サーバの実行

ドキュメント「Hello World アプリケーションの実行」では、HelloServer と残りのアプリケーションの実行について述べています。


サーバ側の実装モデルの理解

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

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


詳細情報

例外: システム例外
CORBA のシステム例外の動作と、Java IDL のシステム例外のマイナーコードの詳細な説明
サーバの開発
CORBA サーバのプログラミングに関するトピック
Java IDL ネームサービス
COS ネームサービスの詳細な説明


前のレッスン: インタフェース定義の記述
次のレッスン: クライアントアプリケーションの開発
チュートリアルのホーム
Java IDL トップへ


Copyright © 1996-2001 Sun Microsystems, Inc., 2550 Garcia Ave., Mtn. View, CA.94043-1100 USA., All rights reserved.