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

ここで紹介するサーバーは、サーバントとサーバーの 2 つのクラスで構成されます。サーバント HelloImplHello 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
    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 機能を継承します。

まず、ssetORB(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 オブジェクトとして使うには、適切な型にナロー変換する必要があります。narrow() の呼び出しは、前の文の直後にあります。

      NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

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

NamingContextExt オブジェクトは 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() の中にあるため、呼び出しが終了して 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 ネームサービスの詳細な説明

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