このチュートリアルでは、おなじみの Hello World プログラムの分散システム版を JavaTM の RMI (Remote Method Invocation、リモートメソッド呼び出し) を使って作成する手順を説明します。このチュートリアルを学習するうちに、関連する多くの疑問に直面することでしょう。それらの解決方法については、RMI FAQ や、RMI ユーザの電子メールアーカイブエイリアスで調べることができます。RMI ユーザの電子メールエイリアスを購読するには、ここをクリックしてください。
分散型の Hello World では、アプレットを使って、そのアプレットのダウンロード元のホスト上で稼動している RMI サーバにリモートメソッド呼び出しを行います。アプレットを実行すると、クライアントのブラウザに、「Hello World!」と表示されます。
このチュートリアルの構成は、次のとおりです。
このチュートリアルの実行に必要なファイルは、次のとおりです。Hello.java - リモートインタフェース
HelloImpl.java - examples.hello.Hello を実装するリモートオブジェクトの実装
HelloApplet.java - リモートメソッド sayHello を呼び出すアプレット
hello.html - アプレットを参照する HTML ページ
examples.hello.HelloImpl を指します。
このチュートリアルで使うソースコードは、次の形式から選択できます。
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 つあります。
Remote インタフェースを実装するクラスのインスタンスです。リモートインタフェースには、ほかの JavaTM 仮想マシン* (JVM) から呼び出すメソッドをすべて宣言します。リモートインタフェースには、次の特性があります。
public として宣言する必要がある。そうしないと、クライアントがリモートインタフェースと同じパッケージ内にある場合を除いて、リモートインタフェースを実装しているリモートオブジェクトをクライアントがロードしようとした時点でエラーが発生する
java.rmi.Remote インタフェースを継承する
throws 節内で java.rmi.RemoteException (または RemoteException のスーパークラス) を宣言する必要がある
HelloImpl) ではなく、リモートインタフェースの型 (Hello) として宣言する必要がある
以下は、リモートインタフェース 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 ソケットファクトリの使用」で学ぶことができます。
- 通信に 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復習: リモートオブジェクトの実装クラスが行う必要のある事柄は、次のとおりです。以下に、
- リモートインタフェースを実装する
- オブジェクトをエクスポートして、着信するリモートメソッド呼び出しを受け入れ可能にする
- 少なくとも
java.rmi.RemoteExceptionのスローだけは実行するように、コンストラクタを定義するexamples.hello.HelloImplクラスのコンストラクタを示します。public HelloImpl() throws RemoteException { super(); }次の点に注意してください。
superメソッド呼び出しは、リモートオブジェクトをエクスポートするjava.rmi.server.UnicastRemoteObjectの引数なしのコンストラクタを呼び出す- 通信リソースが利用できない場合は、RMI がリモートオブジェクトを構築中にエクスポートしようとすると失敗する可能性があるため、コンストラクタは
java.rmi.RemoteExceptionをスローする必要がある
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 では、次のようになります。クラスは、リモートインタフェースで指定されていないメソッドを定義できますが、これらのメソッドは、サービスを実行する仮想マシン内でしか呼び出すことはできず、リモートから呼び出すことはできません。
- デフォルトでは、ローカルオブジェクトはコピーによって渡される。つまり、
staticまたはtransientとマークされたもの以外は、オブジェクトのすべてのデータメンバ (またはフィールド) がコピーされる。直列化のデフォルト動作を変更する方法については、「Java オブジェクト直列化仕様」を参照- リモートオブジェクトは参照によって渡される。リモートオブジェクトへの参照は、実際にはスタブ (クライアント側でのリモートオブジェクトのプロキシ) への参照である。スタブの詳細については、「Java Remote Method Invocation」を参照。スタブの作成法については、「
rmicを使ってスタブおよびスケルトンを生成する」で説明するセキュリティマネージャを作成およびインストールする
サーバの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メソッド呼び出しの引数については、次の点に注意してください。セキュリティ上の理由により、アプリケーションがバインド、またはアンバインドできるのは、同一ホスト上で動作中のレジストリに対してだけです。この制限により、クライアントがサーバのリモートレジストリを削除したり上書きしたりすることはありません。ただし、ルックアップはどのホストからでも可能です。
- 最初のパラメータは、URL 形式の
java.lang.Stringで、リモートオブジェクトの位置および名前を表す
- URL 形式の文字列にプロトコルを指定する必要はない
myhostの値をサーバマシンの名前または IP アドレスに変える必要がある。変えなかった場合は、リモートオブジェクトのホストはデフォルトで現在のホストになる。たとえば、「HelloServer」は、ローカルホスト上で実行中の、名前HelloServerにバインドされたリモートオブジェクトを参照する有効な名前の文字列である- オプションで、ポート番号を URL 形式の文字列に提供できる。接続する必要のあるレジストリがデフォルトの 1099 ポート以外のポート上で実行されている場合は、ポート番号を指定する必要がある。 たとえば、
「//myhost:1234/HelloServer」は、HelloServerリモートオブジェクトの有効な名前文字列である。この文字列には、myhostホスト上で実行され、ポート 1234 で入接続呼を待機している RMI レジストリを使って接続できる
- 2 番目のパラメータは、オブジェクトの実装への参照で、このオブジェクトに対してリモートメソッドが呼び出される
- オブジェクトがエクスポートされると、それ以降 RMI ランタイムは、
obj引数に指定された実際のリモートオブジェクトの参照の代わりに、リモートオブジェクトのスタブへの参照を使う。クライアントがサーバのリモートオブジェクトのレジストリでルックアップを実行すると、実装に対するスタブのインスタンスが直列化されて返される
この例のアプレットは、アプレットを実行したときに「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);
}
}
rmiregistry からリモートオブジェクトの実装 (HelloServer として公示されている) への参照を取得する。Naming.lookup メソッドは、Naming.rebind メソッドと同様に、URL 形式の java.lang.String をとる。この例では、アプレットは getCodeBase メソッドを getHost メソッドとともに使用して URL 文字列を構築する。Naming.lookup は、次の作業を行う
Naming.lookup への引数として提供されたホスト名およびポート番号を使って、レジストリスタブのインスタンスを構築し、サーバのレジストリに接続する
HelloServer) を使ってレジストリ上のリモート lookup メソッドを呼び出す
HelloImpl_Stub のインスタンスを返す
lookup メソッドは、リモートオブジェクト (HelloImpl) のスタブインスタンスを受け取り、CLASSPATH またはアプレットのコードベースからスタブクラス (examples.hello.HelloImpl_Stub) をロードする
Naming.lookup は、呼び出し側 (HelloApplet) にスタブを返す
sayHello を呼び出す
message という名前の変数に格納する
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>次の点に注意してください。
codebase は、Web ページ自体のロード元ディレクトリの下のディレクトリを指定する。通常は、このように相対パスを使うとよい。たとえば、アプレットの HTML によって参照される (アプレットのクラスファイルがある) codebase ディレクトリが、その HTML ディレクトリの上のディレクトリにある場合は、相対パス「../」を使う
code 属性は、アプレットの絶対パスによるパッケージ名を指定する。この例では、examples.hello.HelloApplet となる
code="examples.hello.HelloApplet"
$HOME/mysrc/examples/hello ディレクトリには 4 つのファイルが存在しています。
Hello.java - Hello リモートインタフェースのソースコードが含まれる
HelloImpl.java - HelloImpl リモートオブジェクトの実装およびアプレットの RMI サーバのソースコードが含まれる
HelloApplet.java - アプレットのソースコードが含まれる
hello.html - Hello World アプレットを参照する Web ページ
.java ソースファイルをコンパイルして、.class ファイルを作成します。次に、rmic コンパイラを実行して、スタブとスケルトンを作成します。スタブとは、リモートオブジェクトのクライアント側のプロキシのことで、RMI 呼び出しをサーバ側のディスパッチャーに転送します。次に、ディスパッチャーが、呼び出しを実際のリモートオブジェクトの実装に転送します。
javac や rmic コンパイラを使うときは、生成されるクラスファイルをどのディレクトリに置くかを指定しなければなりません。アプレットの場合には、すべてのファイルをアプレットのコードベースディレクトリに置く必要があります。この例では、コードベースディレクトリは $HOME/public_html/myclasses になります。
Web サーバの中には、「http://host/‾username/」 の形式で構成された HTTP URL 経由でユーザの public_html ディレクトリにアクセスできるものがあります。Web サーバでこの変換がサポートされていない場合は、テストで 「file:/home/username/public_html」 形式のファイル URL を使うことができます。ただし、同一の物理ファイルシステムにアクセスするクライアントとサーバ間以外で通信することはできません。この場合、システム上に最小限の機能を備えた Web サーバを設定すれば、HTTP URL を使うことができます。このサーバは、ここからダウンロードすることもできます。
ここで行う作業は 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.class、HelloImpl.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フラグをオンにした状態で実行されます。生成されるスタブおよびスケルトンは、次のオブジェクトへのアクセスをサポートします。JDK 1.1 のクライアントをサポートする必要がない場合は、
- JDK 1.1 のクライアントからの
Activatableでないユニキャストリモートオブジェクト- 1.2 以降のクライアントからのすべての型のリモートオブジェクト
rmicに-v1.2オプションを指定して実行しても構いません。rmicオプションの詳細については、Solaris 用rmicのマニュアルページまたは Win32 用rmicのマニュアルページを参照してください。たとえば、
HelloImplリモートオブジェクトの実装のスタブおよびスケルトンを作成するには、次のようにrmicを実行します。
rmic -d $HOME/public_html/myclassesexamples.hello.HelloImpl
「-d」オプションは、コンパイルされたスタブおよびスケルトンクラスファイルが置かれるルートディレクトリを示します。このため、上のコマンドを実行すると、次のファイルがディレクトリ$HOME/public_html/myclasses/examples/helloに作成されます。生成されたスタブクラスは、リモートオブジェクト自体とまったく同じリモートインタフェースのセットを実装します。つまり、クライアントは、キャストや型チェックに Java プログラミング言語に組み込まれた演算子を使用することができます。また、Java プラットフォーム用に作成されたリモートオブジェクトでは、真のオブジェクト指向の多相性がサポートされます。
HelloImpl_Stub.classHelloImpl_Skel.classHTML ファイルを配置ディレクトリに移す
アプレットを参照する Web ページにクライアントがアクセスできるように、hello.htmlファイルを開発ディレクトリからアプレットのcodebaseディレクトリに移動する必要があります。例を示します。
mv $HOME/mysrc/examples/hello/hello.html $HOME/public_html/
ランタイムパスを設定する
HelloImplサーバの実行時に、サーバのローカルCLASSPATHから $HOME/public_html/myclassesディレクトリにアクセスできることを確認しておいてください。
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 20011099 以外のポートでレジストリを実行している場合は、レジストリを呼び出すときに、
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ファイルを使ってアクセス権を適切に指定する方法については、次のドキュメントを参照してください。
デフォルトの 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 内でスタブを検索したため、別の点にも問題があります。出力は、次のようになります。
アプレットを実行する
レジストリおよびサーバがいったん実行されると、アプレットの実行が可能になります。アプレットの実行は、ブラウザに 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 |