RMI 入門


このチュートリアルでは、おなじみの Hello World プログラムの分散システム版を JavaTM の RMI (Remote Method Invocation、リモートメソッド呼び出し) を使って作成する手順を説明します。このチュートリアルを学習するうちに、関連する多くの疑問に直面することでしょう。それらの解決方法については、RMI FAQ や、RMI ユーザの電子メールアーカイブエイリアスで調べることができます。RMI ユーザの電子メールエイリアスを購読するには、ここをクリックしてください。

分散型の Hello World では、アプレットを使って、そのアプレットのダウンロード元のホスト上で稼動している RMI サーバにリモートメソッド呼び出しを行います。アプレットを実行すると、クライアントのブラウザに、「Hello World!」と表示されます。

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

  1. ソースファイルと HTML ファイルの記述
  2. クラスファイルと HTML ファイルのコンパイルおよび配置
  3. RMI レジストリ、サーバ、およびアプレットを起動する
このチュートリアルの実行に必要なファイルは、次のとおりです。 注: 以降のチュートリアルで、「リモートオブジェクトの実装」、「オブジェクトの実装」、および「実装」と言った場合、すべて、リモートインタフェースを実装するクラス examples.hello.HelloImpl を指します。

このチュートリアルで使うソースコードは、次の形式から選択できます。


ソースファイルと HTML ファイルの記述

JavaTM プログラミング言語では、絶対パスで指定したクラスのパッケージ名とそのクラスへのディレクトリパスとの間にマッピングが必要なので、Java プログラミング言語でコードを書き始める前に、パッケージとディレクトリの名前を特定する必要があります。このマッピングにより、Java プログラミング言語用のコンパイラは、プログラム中に指定されたクラスファイルに関して、どのディレクトリを検索したらよいかを知ることができます。このチュートリアルのプログラムでは、パッケージ名は examples.hello、ソースディレクトリは $HOME/mysrc/examples/hello です。

SolarisTM オペレーティング環境でソースファイル用ディレクトリを作成するには、次のコマンドを実行します。

    mkdir -p $HOME/mysrc/examples/hello
Microsoft Windows プラットフォームでは、目的のディレクトリに移動してから、次のように入力します。
    mkdir mysrc
    mkdir mysrc¥examples
    mkdir mysrc¥examples¥hello

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

  1. リモートクラスの関数を Java プログラミング言語で作成されたインタフェースとして定義する
  2. 実装クラスおよびサーバクラスを記述する
  3. リモートサービスを利用するクライアントプログラムを作成する

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

Java プログラミング言語では、リモートオブジェクトは、Remote インタフェースを実装するクラスのインスタンスです。リモートインタフェースには、ほかの JavaTM 仮想マシン* (JVM) から呼び出すメソッドをすべて宣言します。リモートインタフェースには、次の特性があります。

以下は、リモートインタフェース examples.hello.Hello のインタフェース定義です。このインタフェースに含まれているメソッドは sayHello 1 つだけで、このメソッドは呼び出し側に文字列を返します。


    package examples.hello;

    import java.rmi.Remote;
    import java.rmi.RemoteException;

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

実装クラスおよびサーバクラスを記述する

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

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

この例では、main メソッドは、examples.hello.HelloImpl の一部です。サーバプログラムが行う事柄は、以下のとおりです。

HelloImpl.java: のソースをもとにして、上記の 6 つの各ステップを説明します。
	package examples.hello;

	import java.rmi.Naming;
	import java.rmi.RemoteException;
	import java.rmi.RMISecurityManager;
	import java.rmi.server.UnicastRemoteObject;

	public class HelloImpl extends UnicastRemoteObject implements Hello {

	    public HelloImpl() throws RemoteException {
		super();
	    }

	    public String sayHello() {
		return "Hello World!";
	    }

	    public static void main(String args[]) {

		//Create and install a security manager
		if (System.getSecurityManager() == null) {
		    System.setSecurityManager(new RMISecurityManager());
		}

		try {
		    HelloImpl obj = new HelloImpl();

		    // Bind this object instance to the name "HelloServer"
		    Naming.rebind("//myhost/HelloServer", obj);

		    System.out.println("HelloServer bound in registry");
		} catch (Exception e) {
		    System.out.println("HelloImpl err: " + e.getMessage());
		    e.printStackTrace();
		}
	    }
	}

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

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

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

	public class HelloImpl extends UnicastRemoteObject
	    implements Hello {
実装クラスはリモートクラスを継承できます。この例では、リモートクラスは、java.rmi.server.UnicastRemoteObject です。UnicastRemoteObject を継承することにより、HelloImpl クラスから以下の機能を持つリモートオブジェクトを作成できます。 常時稼動するのではなく、クライアントの要求時に起動 (作成) できるリモートオブジェクトが必要な場合は、このチュートリアルを終了したあとで、「リモートオブジェクト起動」を参照してください。また、RMI がデフォルトで使う TCP ソケットではなく、独自の通信プロトコルを使う方法については、「カスタム RMI ソケットファクトリの使用」で学ぶことができます。

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

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

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

UnicastRemoteObject または Activatable 以外のクラスからリモートオブジェクトを継承する場合は、クラスのコンストラクタ (または適切な別の初期化メソッド) から UnicastRemoteObject.exportObject メソッドまたは Activatable.exportObject メソッドを呼び出すことにより、明示的にリモートオブジェクトをエクスポートする必要があります。

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

	HelloImpl.java:13: Exception java.rmi.RemoteException must be caught, or it must be
        declared in the throws clause of this method. 
                super(); 
                     ^ 
        1 error
復習: リモートオブジェクトの実装クラスが行う必要のある事柄は、次のとおりです。 以下に、examples.hello.HelloImpl クラスのコンストラクタを示します。
    public HelloImpl() throws RemoteException {
	super();
    }
次の点に注意してください。

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

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

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

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

リモートオブジェクトの実装クラスは、リモートインタフェースで指定された各リモートメソッドを実装するコードを含みます。次に sayHello メソッドの実装例を示します。この例では、呼び出し側に「Hello World!」という文字列が返されます。
    public String sayHello() throws RemoteException {
	return "Hello World!";
    }
リモートメソッドに渡す引数、またはリモートメソッドからの戻り値は、Java プラットフォーム用のどのデータ型であっても構いません。さらに、インタフェース java.io.Serializable を実装したオブジェクトであれば、オブジェクト型であっても構いません。java.lang および java.util 内のコア Java クラスの大部分は、Serializable インタフェースを実装しています。RMI では、次のようになります。 クラスは、リモートインタフェースで指定されていないメソッドを定義できますが、これらのメソッドは、サービスを実行する仮想マシン内でしか呼び出すことはできず、リモートから呼び出すことはできません。

セキュリティマネージャを作成およびインストールする

サーバの main メソッドは、まず、RMISecurityManager または独自に定義したセキュリティマネージャの、作成およびインストールを行う必要があります。例を示します。
if (System.getSecurityManager() == null) {

        System.setSecurityManager(new RMISecurityManager());
}
セキュリティマネージャは、ロードされたクラスが許可されていない操作を行わないことを保証するもので、必ず実行されなければなりません。セキュリティマネージャが指定されない場合は、ローカルの CLASSPATH 内のクラス以外には、RMI クライアントまたはサーバによるクラスのロードは許可されません。 この例では、すでにクライアントブラウザにインストールされているセキュリティマネージャがアプレットで使われるので、セキュリティマネージャはクライアントにインストールされていません。ただし、クライアントがアプレットではなくアプリケーションの場合は、上記と同じ手順でクライアントにセキュリティマネージャをインストールする必要があります。セキュリティマネージャは、JVM でコードをダウンロードするときに必要になります。RMI クライアントでは、RMI サーバとの通信に必要なすべてのカスタムクラスまたはインタフェース以外に、RMI スタブをダウンロードする必要があります。

リモートオブジェクトの 1 つ以上のインスタンスを生成する

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

リモートオブジェクトを登録する

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

ブートストラップ用に、RMI システムはリモートオブジェクトのレジストリを提供します。これにより、//host/objectname という URL 形式の名前をリモートオブジェクトにバインドできます。この URL 形式の objectname は単なる文字列名です。

RMI レジストリは、単純なサーバ側のネームサービスで、これによりリモートクライアントは、リモートオブジェクトへの参照を取得できます。通常、RMI レジストリは、RMI クライアントが最初に通信するリモートオブジェクトの場所を特定するためだけに使われます。次に、RMI クライアントが最初に通信したオブジェクトが、ほかのオブジェクトを見つける上で必要なアプリケーション固有のサポートを行います。

たとえば、参照は、別のリモートメソッド呼び出しに渡すパラメータ、またはリモートメソッド呼び出しからの戻り値として取得できます。詳細は、「RMI にファクトリパターンを適用する」を参照してください。

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

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

Naming.rebind("//myhost/HelloServer", obj);
rebind メソッド呼び出しの引数については、次の点に注意してください。 セキュリティ上の理由により、アプリケーションがバインド、またはアンバインドできるのは、同一ホスト上で動作中のレジストリに対してだけです。この制限により、クライアントがサーバのリモートレジストリを削除したり上書きしたりすることはありません。ただし、ルックアップはどのホストからでも可能です。

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

この例のアプレットは、アプレットを実行したときに「Hello World!」という文字列を表示するために、sayHello メソッドのリモート呼び出しを行います。次にこのアプレットのコードを示します。

package examples.hello;

import java.applet.Applet;
import java.awt.Graphics;
import java.rmi.Naming;
import java.rmi.RemoteException;

public class HelloApplet extends Applet {

    String message = "blank";

    // "obj" is the identifier that we'll use to refer
    // to the remote object that implements the "Hello"
    // interface
    Hello obj = null;

    public void init() {
        try {
            obj = (Hello)Naming.lookup("//" +
                getCodeBase().getHost() + "/HelloServer");
            message = obj.sayHello();
        } catch (Exception e) {
            System.out.println("HelloApplet exception: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public void paint(Graphics g) {
        g.drawString(message, 25, 50);
    }
}
  1. アプレットは、最初にサーバホストの rmiregistry からリモートオブジェクトの実装 (HelloServer として公示されている) への参照を取得する。Naming.lookup メソッドは、Naming.rebind メソッドと同様に、URL 形式の java.lang.String をとる。この例では、アプレットは getCodeBase メソッドを getHost メソッドとともに使用して URL 文字列を構築する。Naming.lookup は、次の作業を行う

  2. アプレットは、サーバのリモートオブジェクトのリモートメソッド sayHello を呼び出す

  3. アプレットは、paint メソッドを呼び出す。この結果、文字列 Hello World! がアプレットの描画領域に表示される
Naming.lookup メソッドにパラメータとして渡される、URL 形式の文字列には、サーバのホスト名が含まれている必要があります。サーバのホスト名が含まれていないと、アプレットのルックアップはデフォルトでクライアントに対して実行されるため、アプレットはローカルシステムにアクセスできず、アプレットのホストとの通信だけに制限されます。このため、AppletSecurityManager は例外をスローします。

Hello World アプレットを参照する Web ページの HTML コードを次に示します。

	<HTML>
	<title>Hello World</title>
	<center> <h1>Hello World</h1> </center>
	<applet codebase="myclasses/"
	        code="examples.hello.HelloApplet"
	        width=500 height=120>
	</applet>
	</HTML>
次の点に注意してください。

クラスファイルと HTML ファイルをコンパイルおよび配置する

これでこの例題のソースコードが完成しました。 $HOME/mysrc/examples/hello ディレクトリには 4 つのファイルが存在しています。 この節では、.java ソースファイルをコンパイルして、.class ファイルを作成します。次に、rmic コンパイラを実行して、スタブとスケルトンを作成します。スタブとは、リモートオブジェクトのクライアント側のプロキシのことで、RMI 呼び出しをサーバ側のディスパッチャーに転送します。次に、ディスパッチャーが、呼び出しを実際のリモートオブジェクトの実装に転送します。

javacrmic コンパイラを使うときは、生成されるクラスファイルをどのディレクトリに置くかを指定しなければなりません。アプレットの場合には、すべてのファイルをアプレットのコードベースディレクトリに置く必要があります。この例では、コードベースディレクトリは $HOME/public_html/myclasses になります。

Web サーバの中には、「http://host/‾username/」 の形式で構成された HTTP URL 経由でユーザの public_html ディレクトリにアクセスできるものがあります。Web サーバでこの変換がサポートされていない場合は、テストで 「file:/home/username/public_html」 形式のファイル URL を使うことができます。ただし、同一の物理ファイルシステムにアクセスするクライアントとサーバ間以外で通信することはできません。この場合、システム上に最小限の機能を備えた Web サーバを設定すれば、HTTP URL を使うことができます。このサーバは、ここからダウンロードすることもできます。

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

  1. ソースファイルをコンパイルする
  2. rmic を使ってスタブおよびスケルトンを生成する
  3. HTML ファイルを配置ディレクトリに移す
  4. ランタイムパスを設定する

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

コンパイルする前に、生成ファイルの配置ディレクトリ $HOME/public_html/myclasses および開発ディレクトリ $HOME/mysrc/examples/hello の両方に、開発マシン上のローカル CLASSPATH からアクセスできることを確認してください。

ソースファイルをコンパイルするには、次の javac コマンドを実行します。

javac  -d  $HOME/public_html/myclasses Hello.java  HelloImpl.java  HelloApplet.java

このコマンドは、ディレクトリ examples/hello をディレクトリ $HOME/public_html/myclasses 内に作成します (まだ存在していない場合)。次に、このコマンドは、examples/hello ディレクトリにファイル Hello.classHelloImpl.class、および HelloApplet.class を書き込みます。これらのファイルはそれぞれ、リモートインタフェース、実装、アプレットです。javac オプションの詳細は、Solaris 用 javac のマニュアルページまたは Win32 用 javac のマニュアルページを参照してください。

rmic を使ってスタブまたはスケルトンを生成する

スタブおよびスケルトンファイルを作成するには、my.package.MyImpl のようなリモートオブジェクトの実装を含んだ、コンパイルするクラスファイルの絶対パスによるパッケージ名を指定して、rmic を実行します。rmic コマンドは、引数に 1 つ以上のクラス名をとり、MyImpl_Skel.class および MyImpl_Stub.class の形式のクラスファイルを生成します。

Java 2 SDK, v1.2 以降では、rmic はデフォルトで -vcompat フラグをオンにした状態で実行されます。生成されるスタブおよびスケルトンは、次のオブジェクトへのアクセスをサポートします。

  1. JDK 1.1 のクライアントからの Activatable でないユニキャストリモートオブジェクト
  2. 1.2 以降のクライアントからのすべての型のリモートオブジェクト
JDK 1.1 のクライアントをサポートする必要がない場合は、rmic-v1.2 オプションを指定して実行しても構いません。rmic オプションの詳細については、Solaris 用 rmic のマニュアルページまたは Win32 用 rmic のマニュアルページを参照してください。

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

rmic  -d  $HOME/public_html/myclasses  examples.hello.HelloImpl

「-d」オプションは、コンパイルされたスタブおよびスケルトンクラスファイルが置かれるルートディレクトリを示します。このため、上のコマンドを実行すると、次のファイルがディレクトリ $HOME/public_html/myclasses/examples/hello に作成されます。

生成されたスタブクラスは、リモートオブジェクト自体とまったく同じリモートインタフェースのセットを実装します。つまり、クライアントは、キャストや型チェックに Java プログラミング言語に組み込まれた演算子を使用することができます。また、Java プラットフォーム用に作成されたリモートオブジェクトでは、真のオブジェクト指向の多相性がサポートされます。

HTML ファイルを配置ディレクトリに移す

アプレットを参照する Web ページにクライアントがアクセスできるように、hello.html ファイルを開発ディレクトリからアプレットの codebase ディレクトリに移動する必要があります。例を示します。

mv  $HOME/mysrc/examples/hello/hello.html  $HOME/public_html/

ランタイムパスを設定する

HelloImpl サーバの実行時に、サーバのローカル CLASSPATH から $HOME/public_html/myclasses ディレクトリにアクセスできることを確認しておいてください。

RMI レジストリ、サーバ、およびアプレットを起動する

ここで行う作業は 3 つあります。
  1. RMI レジストリを起動する
  2. サーバを起動する
  3. アプレットを実行する

RMI レジストリを起動する

RMI レジストリは、単純なサーバ側のネームサーバで、これによりリモートクライアントは、リモートオブジェクトへの参照を取得できます。通常、RMI レジストリは、アプリケーションが最初に通信するリモートオブジェクトの場所を特定するためだけに使われます。次いで、アプリケーションが最初に通信したオブジェクトが、ほかのオブジェクトを見つける上で必要なアプリケーション固有のサポートを行います。

注: rmiregistry を開始する前に、レジストリを実行するシェルまたはウィンドウに CLASSPATH が設定されていないこと、あるいは設定されていても、クライアントにダウンロードするクラスへのパス (リモートオブジェクトの実装クラスのスタブを含む) が含まれていないことを確認してください。

rmiregistry が、その開始時に CLASSPATH 内でスタブクラスを見つけると、サーバの java.rmi.server.codebase プロパティは無視されます。その結果、クライアントは、そのリモートオブジェクトのスタブコードをダウンロードできません。RMI を使ったコードのダウンロードについては、チュートリアルの「RMI の使用による動的なコードのダウンロード」を参照してください。

サーバ上でレジストリを開始するには、rmiregistry コマンドを実行します。このコマンドからは何の出力もありません。通常、バックグラウンドで実行されます。rmiregistry の詳細は、Solaris 用の rmiregistry のマニュアルページまたは Win32 用の rmiregistry のマニュアルページを参照してください。

Solaris オペレーティング環境での例:

rmiregistry &

Microsoft Windows 95 システムでの例:

start rmiregistry 

(start コマンドが使えない場合は javaw を使う)

デフォルトでは、レジストリはポート番号 1099 で実行されます。別のポート上でレジストリを実行するには、コマンド行でポート番号を指定します。たとえば、Microsoft Windows NT システム上のポート 2001 でレジストリを起動するには、次のようにします。

start rmiregistry 2001

1099 以外のポートでレジストリを実行している場合は、レジストリを呼び出すときに、java.rmi.Naming クラスの URL ベースのメソッドに渡す名前の中でポート番号を指定する必要があります。たとえば、この例題で、レジストリをポート番号 2001 で実行する場合、名前「HelloServer」をリモートオブジェクト参照にバインドする次の呼び出しが必要になります。

Naming.rebind("//myhost:2001/HelloServer", obj);

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

サーバを起動する

サーバの起動時に、スタブクラスがレジストリ、次いでクライアントに動的にダウンロードされるように、java.rmi.server.codebase プロパティが指定されている必要があります。コードベースのプロパティを実装スタブの位置に設定して、サーバを実行します。この例題のコードベースのプロパティはディレクトリを参照するので、ダウンロードされる可能性があるその他すべてのクラスも java.rmi.server.codebase によって参照されるディレクトリにインストールしておきます。コードベース設定のコマンド行の例については、チュートリアルの「RMI の使用による動的なコードのダウンロード」も参照してください。

java.rmi.server プロパティの説明は、ここをクリックしてください。利用可能なすべての java.rmi.activation プロパティの詳細は、ここをクリックしてください。java のオプションの詳細は、Solaris 用 java のマニュアルページまたは Win32 用 java マニュアルページを参照してください。サンプルコードの実行に問題がある場合は、RMI とオブジェクト直列化の FAQ を参照してください。

注: スタブクラスは、クラスがまだローカルで利用できない場合で、java.rmi.server.codebase プロパティがサーバ上のクラスファイルの位置に適切に設定されている場合だけ、クライアントの仮想マシンに動的にダウンロードされます。

java コマンド、プロパティの「名前」=「値」の 2 つのペア (codebase プロパティには「-D」から最後の「/」まで空白文字がないことに注意)、および絶対パスで指定されたサーバプログラムのパッケージ名の 4 つをこの順序で同じコマンド行に記述する必要があります。空白文字は、java という語の直後に 1 つと、2 つのプロパティの間に 1 つと、(ブラウザまたは紙上では見にくいのですが) examples という語の直前に 1 つ必要です。次のコマンドは、java.rmi.server.codebase および java.security.policy プロパティを指定して、HelloImpl サーバを開始する方法を示します。

java  -Djava.rmi.server.codebase=http://myhost/‾myusrname/myclasses/  -Djava.security.policy=$HOME/mysrc/policy  examples.hello.HelloImpl

このコードをシステム上で実行するには、policy ファイルの位置を、サンプルソースコードをインストールしたシステム上のディレクトリの位置に変更する必要があります。

: ここでは、例を単純にするために、すべての位置のすべてのユーザにグローバルなアクセス権を与える policy ファイルを使用します。このポリシーファイルは、実稼働環境では使用しないでください。java.security.policy ファイルを使ってアクセス権を適切に指定する方法については、次のドキュメントを参照してください。

コードベースプロパティは、URL として解釈処理されます。このため、コードベースプロパティはhttp://aHost/somesource/file:/myDirectory/location/ の形式、またはオペレーティングシステムによっては file:///myDirectory/location/ (file: のあとにスラッシュが 3 つ) の形式で指定する必要があります。

これらのサンプル URL の各文字列には、末尾に「/」があることに注意してください。java.rmi.server.codebase プロパティで指定する URL では、実装がクラス定義を適切に解釈処理 (検索) するために、末尾のスラッシュが必要です。

codebase プロパティ上の末尾のスラッシュを忘れたり、ソースファイルで指定された位置にクラスファイルが見つからない (ダウンロード可能でない) 場合、またはプロパティ名を間違って入力した場合は、java.lang.ClassNotFoundException がスローされます。この例外は、リモートオブジェクトを rmiregistry にバインドしようとした場合、または最初のクライアントがそのオブジェクトのスタブにアクセスしようとした場合にスローされます。後者の場合は、rmiregistry が CLASSPATH 内でスタブを検索したため、別の点にも問題があります。

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

HelloServer bound in registry

アプレットを実行する

レジストリおよびサーバがいったん実行されると、アプレットの実行が可能になります。アプレットの実行は、ブラウザに Web ページをロードするか、または次に示すように appletviewer によって行います。
appletviewer http://myhost/‾myusrname/hello.html &
appletviewer を実行すると、次のような出力が画面に表示されます。

* この Web サイトで使用されている用語「Java 仮想マシン」または「JVM」は、Java プラットフォーム用の仮想マシンを表します。


Copyright © 2001 Sun Microsystems, Inc. All Rights Reserved. 
コメントの送付先: rmi-comments@java.sun.com 
Sun