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 and 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つの方法は、ファイルへのオブジェクト参照を文字列化することです。

ネーム・サービスには、次の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, 2020, Oracle and/or its affiliates. All rights reserved.