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 (Solaris、Linux、Mac OS XまたはWindows)で、ブートストラップ・サービス、一時ネーム・サービス、持続ネーム・サービスおよびサーバー・マネージャが含まれています。もう1つは、一時ネーム・サービスであるtnameserv (Solaris、Linux、Mac OS XまたはWindows)で、下位互換性を維持するために用意されています。この例では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のオプションの詳細は、idljのマニュアル・ページ(Solaris、Linux、Mac OS XまたはWindows)を参照してください。

    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を起動します。

    Solaris、LinuxまたはMac OS Xのコマンド・シェルでorbdを起動するには、次のように入力します。

      orbd -ORBInitialPort 1050&
    

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

      start orbd -ORBInitialPort 1050
    

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

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

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

    Solaris、LinuxまたはMac OS Xのコマンド・シェルで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と入力すると停止します。Solaris、LinuxまたはMac OS Xのシェルでは、プロセスを見つけて終了(kill)します。サーバーを明示的に停止するまでは、呼出し待機状態が続きます。

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


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