チュートリアル: 入門: RMI-IIOP の使用法


このチュートリアルでは、おなじみの「Hello World」プログラムの分散システム版を、Java TM の RMI (Remote Method Invocation、リモートメソッド呼び出し) を Internet Inter-ORB Protocol (IIOP) 経由で使用して作成する手順を説明します。 RMI-IIOP は、Java RMI に CORBA (Common Object Request Broker Architecture) 機能を追加することにより、標準規格に基づいた相互運用性と接続性を、ほかの多くのプログラミング言語およびプラットフォームに提供します。 RMI-IIOP を利用すると、Web ベースの分散 Java アプリケーションから、Object Management Group によって定義された業界標準である IIOP を使用しているリモートネットワークサービス上の操作を、透過的に呼び出すことができます。 ランタイムコンポーネントには、IIOP 通信を使った分散コンピューティング用の Java ORB が含まれています。

RMI-IIOP は、IIOP を背後のトランスポートとして使用して、RMI インタフェースに対するプログラムを作成したい Java プログラマ向けです。 RMI-IIOP はさまざまな言語で実装される CORBA オブジェクトとの相互運用性を提供しますが、リモートインタフェースをあらかじめ Java RMI インタフェースとして定義しておく必要があります。 EJB のリモートオブジェクトモデルは RMI ベースなので、Enterprise JavaBeans (EJB) を使うプログラマには特に有用です。

分散アプリケーションを作成するためのその他のオプションは次のとおりです。


チュートリアル: 「Hello World」アプリケーション

ここで例として紹介する分散型の「Hello World」プログラムでは、クライアントアプリケーションから IIOP 経由でサーバ (そのクライアントアプリケーションのダウンロード元のホスト上で稼動している) に対してリモートメソッド呼び出しを行います。 このクライアントアプリケーションを実行すると、「Hello from MARS!」が表示されます。

このチュートリアルの構成は、次のとおりです。

  1. ソースファイルを作成する手順
  2. 例のコンパイル手順
  3. 例の実行手順

チュートリアルに含まれる各手順は、このイラストで表されます。


ソースファイルの作成

ここで行う作業は 4 つあります。

  1. リモートクラスの関数を Java プログラミング言語で作成されたインタフェースとして定義する
  2. 実装クラスを作成する
  3. サーバクラスを作成する
  4. リモートサービスを利用するクライアントプログラムを作成する
このチュートリアルで作成するソースファイルは、次のとおりです。

リモートクラスの関数を Java プログラミング言語で作成されたインタフェースとして定義する

Java プログラミング言語では、リモートオブジェクトは、Remote インタフェースを実装するクラスのインスタンスです。 作成するリモートインタフェースでは、ほかのマシンから呼び出したい各メソッドを宣言します。 リモートインタフェースには、次の特性があります。

この例では、すべてのソースファイルを同じディレクトリ (たとえば、$HOME/mysrc/helloWorld) 内に作成します。

HelloInterface.java ファイルを作成します。 次のコードは、リモートインタフェース HelloInterface のインタフェース定義です。この定義には、ただひとつのメソッド sayHello が含まれています。

リモートメソッド呼び出しは、ローカルメソッド呼び出しとは異なる方法でエラーが発生します。 これは、ネットワーク通信上の問題とサーバ上の問題によるものです。 このため、リモートメソッドは、java.rmi.RemoteException をスローすることにより通信エラーを報告します。分散システム上のエラーおよび復元の詳細については、「A Note on Distributed Computing」を参照してください。

実装クラスを作成する

リモートオブジェクトの実装クラス HelloImpl.java は、少なくとも次の条件を満たしていなければなりません。

HelloImpl.java ファイルを作成します。 このファイルのコードは以下のとおりです。 ソースコードを紹介したあと、上記の各ステップについて説明します。

リモートインタフェースを実装する

Java プログラミング言語では、あるインタフェースを実装することをクラスが宣言すると、そのクラスとコンパイラの間で契約が結ばれます。 この契約によって、そのクラスは、そのインタフェース内で宣言された各メソッドシグニチャーに対して、メソッドの本体 (つまり定義) を提供することを約束します。 インタフェースのメソッドは、暗黙のうちに public および abstract として宣言されているため、実装クラスでその契約が果たされない場合、そのクラスは定義に基づき abstract になります。そのクラスが abstract として宣言されていない場合は、コンパイラによってその事実が指摘されます。

この例では、実装クラスは HelloImpl です。 このクラスは、どのリモートインタフェースを実装するのかを宣言します。 HelloImpl クラスの宣言は、次のとおりです。

  public class HelloImpl extends PortableRemoteObject
    implements HelloInterface{
便宜上、実装クラスはリモートクラスを継承できます。この例では、リモートクラスは javax.rmi.PortableRemoteObject です。 PortableRemoteObject を継承していることにより、HelloImpl クラスを、通信に IIOP ベースのトランスポートを使うリモートオブジェクトを作成するために利用できます。

リモートオブジェクトのコンストラクタを定義する

リモートクラスのコンストラクタは、リモート以外のクラスのコンストラクタと同じ機能を提供します。 つまり、そのクラスの新しく作成されたインスタンスごとに変数を初期化して、コンストラクタを呼び出したプログラムにそのクラスのインスタンスを返します。

さらに、リモートオブジェクトのインスタンスは「エクスポート」される必要があります。 リモートオブジェクトをエクスポートすると、そのオブジェクトは、匿名ポート上でリモートオブジェクトへの着呼を監視することによって、着信したリモートメソッド要求を受け入れることができるようになります。 javax.rmi.PortableRemoteObject を継承すると、そのクラスは作成時に自動的にエクスポートされます。

オブジェクトのエクスポートは、java.rmi.RemoteException をスローする可能性があるため、コンストラクタがほかに何も行わない場合でも、RemoteException をスローするコンストラクタを定義する必要があります。 コンストラクタを定義しなかった場合は、javac は、次のエラーメッセージを生成します。

	HelloImpl.java:3: unreported exception java.rmi.RemoteException; must be
	caught or declared to be thrown.

        public class HelloImpl extends PortableRemoteObject implements HelloInterface{
               ^
        1 error
復習: リモートオブジェクトの実装クラスが行う必要のある事柄は、次のとおりです。 HelloImpl クラスのコンストラクタは、次のとおりです。
  public HelloImpl() throws java.rmi.RemoteException {
    super();
  }
次の点に注意してください。

java.rmi.RemoteException が実行時例外ではなくチェックされる例外である理由については、rmi-users 電子メールリストの下記のアーカイブを参照してください。

http://java.sun.com/products/jdk/rmi/archives/3490.html

スーパークラスの引数なしのコンストラクタ super() への呼び出しは、もし省略したとしてもデフォルトで発生しますが、この例では、クラスの前にスーパークラスが構築されることを明確にするために、この呼び出しを省略せずに記述しました。

各リモートメソッドに実装を提供する

リモートオブジェクトの実装クラスは、リモートインタフェースで指定された各リモートメソッドを実装するコードを含みます。 次に sayHello メソッドの実装例を示します。 この例では、呼び出し側に「Hello from MARS!!」という文字列が返されます。
   public void sayHello( String from ) throws java.rmi.RemoteException {
       System.out.println( "Hello from " + from + "!!");
       System.out.flush();
   }

リモートメソッドに渡す引数、またはリモートメソッドからの戻り値は、Java プラットフォーム用のどのデータ型であっても構いません。さらに、インタフェース java.io.Serializable を実装したオブジェクトであれば、オブジェクト型であっても構いません。 java.lang および java.util 内のコア Java クラスの大部分は、Serializable インタフェースを実装しています。 RMI では、次のようになります。

サーバクラスを作成する

サーバクラスは、リモートオブジェクト実装のインスタンスを生成し、そのインスタンスをネームサービスの名前にバインドする main メソッドを持ちます。 この main メソッドを含むクラスは、実装クラスそのものである場合も、まったく別のクラスである場合もあります。

この例では、mainHelloServer.java の一部として含まれており、次の処理を実行します。

HelloServer.java ファイルを作成します。 このファイルのソースコードは以下のとおりです。 ソースコードを紹介したあと、上記の各ステップについて説明します。

リモートオブジェクトのインスタンスを作成する

サーバの main メソッドでは、リモートオブジェクト実装のインスタンス (つまり「サーバント」) を作成する必要があります。 例を示します。
    HelloImpl helloRef = new HelloImpl();
コンストラクタはリモートオブジェクトをエクスポートします。これは、リモートオブジェクトが作成された時点で、そのリモートオブジェクトは着呼を受け入れる準備ができていることを意味します。

オブジェクト参照を公開する

呼び出し側 (クライアント、ピア、またはクライアントアプリケーション) がリモートオブジェクトのメソッドを呼び出すには、呼び出し側はまずリモートオブジェクトへの参照を取得する必要があります。

リモートオブジェクトがサーバに登録されたあとは、呼び出し側は、オブジェクトを名前で検索し (ネームサービスを利用する)、リモートオブジェクトへの参照を取得してはじめて、そのオブジェクトのメソッドをリモートから呼び出せるようになります。 この例では、Object Request Broker Daemon (orbd) の一部であるネームサービスを使用します。

たとえば、次のコードは、「HelloService」という名前をリモートオブジェクトへの参照にバインドします。

            // STEP 2: Publish the reference in the Naming Service
            // using JNDI API
            Context initialNamingContext = new InitialContext();
            initialNamingContext.rebind("HelloService", helloRef );

rebind メソッド呼び出しの引数については、次の点に注意してください。

リモートサービスを利用するクライアントプログラムを作成する

この例のクライアントアプリケーションは、リモートから sayHello メソッドを呼び出して、クライアントアプリケーションが実行されたときに「Hello from MARS!!」という文字列を表示します。

HelloClient.java ファイルを作成します。 クライアントアプリケーションのソースコードは、次のとおりです。

まず、クライアントアプリケーションは、リモートオブジェクト実装 (「HelloService」として公開されている) への参照を、Java Naming and Directory Interface [TM] (JNDI) 呼び出しを使用してネームサービスから取得します。 Naming.rebind メソッドと同じく、Naming.lookup メソッドも、検索するオブジェクトの名前を表す java.lang.String 値を引数として取ります。 検索したいオブジェクトの名前を Naming.lookup() に提供すると、その名前にバインドされたオブジェクトが返されます。 Naming.lookup() は、呼び出し側 (HelloClient) に Hello インタフェースのリモート実装のスタブを返します。

  • クライアントアプリケーションは、サーバのリモートオブジェクトにある sayHello() メソッドをリモートから呼び出して、コマンド行に「Hello from MARS!!」という文字列を表示させる

    プログラム例のコンパイル

    この例のソースコードは、これで完成しました。ディレクトリには、次の 4 つのファイルが入っているはずです。 ここでは、リモートオブジェクト実装のファイル HelloImpl.java をコンパイルして、rmic を実行するのに必要な .class ファイルを作成します。 次に、rmic コンパイラを実行して、スタブとスケルトンを作成します。 スタブとは、リモートオブジェクトのクライアント側のプロキシのことで、RMI-IIOP 呼び出しをサーバ側のディスパッチャに転送します。続いて、ディスパッチャは、その呼び出しを実際のリモートオブジェクト実装に転送します。 最後に、残りの .java ソースファイルをコンパイルして、.class ファイルを作成します。

    このセクションで実行する作業は次のとおりです。

    1. リモートオブジェクト実装をコンパイルする
    2. rmic を使ってスタブおよびスケルトンを生成する
    3. ソースファイルをコンパイルする

    リモートオブジェクト実装をコンパイルする

    スタブファイルとスケルトンファイルを作成するには、リモートオブジェクト実装の入ったコンパイル済みクラスファイルの完全指定のパッケージ名について、rmic を実行する必要があります。 この例では、リモートオブジェクト実装の入ったファイルは HelloImpl.java です。 スタブとスケルトンを生成するには、

    次のようにして HelloImpl.java をコンパイルします。

        javac -d . -classpath . HelloImpl.java
    

    -d .」オプションは、生成されたファイルを、コンパイラを実行しているのと同じディレクトリに置くことを示します。 「-classpath .」オプションは、HelloImpl.java が依存しているファイルが、このディレクトリ内にあることを示します。

    rmic を使ってスタブおよびスケルトンを生成する

    CORBA 対応のスタブおよびスケルトンファイルを作成するには、rmic を、-iiop オプションを指定して実行します。 rmic コマンドは、引数に 1 つ以上のクラス名をとり、_HelloImpl_Tie.class および _HelloInterface_Stub.class の形式のクラスファイルを生成します。 この例では、リモート実装ファイル HelloImpl.class のクラス名を渡します。

    rmic のオプションの詳細は、Solaris 用 rmic のマニュアルページまたは Win32 用 rmic のマニュアルページを参照してください。

    HelloImpl リモートオブジェクト実装のスタブおよびスケルトンを作成するには、次のように rmic を実行します。

        rmic -iiop HelloImpl
    

    上記のコマンドによって、次のファイルが作成されます。

    ソースファイルをコンパイルする

    次の方法で、すべてのソースファイルをコンパイルします。

        javac -d . -classpath . HelloInterface.java HelloServer.java HelloClient.java
    

    このコマンドにより、HelloInterface.classHelloServer.class、および HelloClient.class の各クラスファイルが作成されます。 これらのファイルはそれぞれ、リモートインタフェース、サーバ、そしてクライアントアプリケーションです。 javac のオプションの詳細は、Solaris 用 javac のマニュアルページまたは Win32 用 javac のマニュアルページを参照してください。


    プログラム例の実行

    このセクションで実行する作業は次のとおりです。
    1. ネームサービスを起動する
    2. サーバを起動する
    3. クライアントアプリケーションを実行する

    ネームサービスを起動する

    この例では、Object Request Broker Daemon (orbd) を使用します。これには、一時ネームサービスと持続ネームサービスの両方が組み込まれており、J2SE 1.4 以降をダウンロードすれば入手できます。

    呼び出し側 (クライアント、ピア、またはクライアントアプリケーション) がリモートオブジェクトのメソッドを呼び出すには、呼び出し側はまずリモートオブジェクトへの参照を取得する必要があります。

    リモートオブジェクトがサーバに登録されると、呼び出し側は、そのオブジェクトを名前によって検索して、リモートオブジェクトへの参照を取得できます。そうすれば、そのオブジェクトのメソッドをリモートから呼び出せます。

    ネームサービスを起動するには、コマンド行から orbd を実行します。

    この例の場合、Solaris オペレーティングシステムでは次のコマンドを実行します。

        orbd -ORBInitialPort 1050&
    

    Windows オペレーティングシステムでは、次のコマンドを実行します。

        start orbd -ORBInitialPort 1050
    

    このコマンドでは、orbd を実行するポートを指定しなければなりません。 1024 より番号の小さいポート上でプロセスを開始するにはスーパーユーザになる必要があるため、この例では、ポート 1050 が選択されています。Solaris オペレーティング環境では、orbd ツールの詳細については、orbd のマニュアルページを参照してください。

    リモートインタフェースを変更したり、変更または追加されたリモートインタフェースをリモートオブジェクトの実装で使用する場合は、必ずサーバをいったん停止してから再起動する必要があります。 そうしないと、ネームサービスでバインドされるオブジェクト参照の型が、修正されたクラスと一致しなくなります。

    サーバを起動する

    端末ウィンドウをもう 1 つ開き、この例のソースファイルが入っているディレクトリに移ります。 クライアントを実行するための下記のコマンドは、読みやすくするために複数行に分けてありますが、実際にコマンドを入力するときには改行を入れないでください。 このコマンドは、HelloServer サーバを起動する方法を示しています。 orbd ツールを起動するときに 1050 以外のポートや localhost 以外のホストを使用した場合には、下記のコマンドの該当する値を、orbd を起動するときに使用した実際の値で置き換えてください。

    次のようにして、Hello サーバを起動します。

        java
          -classpath .
          -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory
          -Djava.naming.provider.url=iiop://localhost:1050
          HelloServer
    

    java のオプションの詳細は、Solaris 用 java のマニュアルページまたは Win32 用 java マニュアルページを参照してください。

    出力は、次のようになります。

    Hello Server: Ready ...
    

    クライアントアプリケーションを実行する

    ネームサービスとサーバを起動したあとは、クライアントアプリケーションを実行することができます。 新しい端末ウィンドウから、ソースコードのディレクトリに移り、下記の例のようにしてコマンド行からクライアントアプリケーションを実行します。 クライアントを実行するための下記のコマンドは、読みやすくするために複数行に分けてありますが、実際にコマンドを入力するときには改行を入れないでください。 orbd ツールを起動するときに 1050 以外のポートや localhost 以外のホストを使用した場合には、下記のコマンドの該当する値を、orbd を起動するときに使用した実際の値で置き換えてください。

    次のようにして、クライアントアプリケーションを起動します。

        java
          -classpath .
          -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory
          -Djava.naming.provider.url=iiop://localhost:1050
          HelloClient
    
    クライアントアプリケーションを実行すると、次のような出力が画面に表示されます。
    Client: Obtained a ref. to Hello server.
    Hello from  MARS
    

    ORBD および Hello サーバは、明示的に停止しないかぎり継続して実行されます。 これらのプロセスを停止したい場合、Solaris では、端末ウィンドウから pkill orbd および pkill HelloServer コマンドを実行します。 Windows の場合は、プロンプトウィンドウ内で Ctrl+C と入力します。

    これで基礎的な RMI-IIOP チュートリアルを終わります。 さらに複雑なアプリケーションの作成に進む場合は、次に挙げる情報が役に立ちます。


    RMI-IIOP ドキュメントホーム

    コメントの送付先: rmi-iiop@sun.com