UnicastRemoteObject を起動可能にする


このページでは、既存の UnicastRemoteObject に対し、java.rmi.activation.Activatable を継承させることにより起動可能オブジェクトにする手順を説明します。特に、既存のクラスを UnicastRemoteObject のサブクラスから java.rmi.activation.Activatable のサブクラスに変更する開発者にとって有用な情報です。また、起動可能オブジェクトの作成または java.rmi.activation.Activatable を継承しないオブジェクトの起動方法に関するチュートリアルとしても役立ちます。

JDK 1.2 をリリースする前は、UnicastRemoteObject のインスタンスへのアクセスは、(1) リモートオブジェクトのインスタンスを生成し、かつ (2) 常時稼動中である、サーバプログラムからアクセスできました。現在では、java.rmi.activation.Activatable クラスおよび RMI デーモン rmid の導入により、常時ではなく「必要に応じて」作成され、実行されるリモートオブジェクトの実装情報を登録するプログラムの記述が可能になりました。RMI デーモン rmid は、Java Virtual Machine (JVM) を提供します。この JVM からほかの JVM のインスタンスを生成させることも可能です。

:  以降のチュートリアルでは、「起動可能オブジェクトの実装」、「起動可能オブジェクト」、および「実装」と言った場合、すべて、リモートインタフェースを実装する起動可能なクラス examples.activation.MyRemoteInterfaceImpl を指します。

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

このチュートリアルの実行に必要なファイルは、以下のとおりです。

ここでは、クライアントコードも示しますが、実装クラスやセットアップクラスの場合のように、手順を追った説明はしません。これは、起動可能オブジェクトのクライアントコードが、起動可能でないリモートオブジェクトにアクセスするための RMI クライアントコードと同じであるためです。起動は、厳密にはサーバ側での実装によって決定されます。

このチュートリアルで使われているソースコードは、次のファイル形式から選ぶことができます。




実装クラスの作成

この例の実装クラスは、examples.activation.MyRemoteInterfaceImplです。UnicastRemoteObject から継承した既存の実装クラスを移行させるには、次の 4 つのステップを実行します。

  1. 実装クラスに対し、適切なインポートを実行する
  2. クラス宣言を変更し、クラスを java.rmi.activation.Activatable から継承する
  3. 引数をとらない古いコンストラクタを削除またはコメントアウトする
  4. 実装クラスに 2 つの引数をとるコンストラクタを宣言する
ステップ 1:
実装クラスに対し、適切なインポートを実行する
import java.rmi.*;
import java.rmi.activation.*;

ステップ 2:
クラス宣言を変更し、クラスを java.rmi.activation.Activatable から継承する

public class MyRemoteInterfaceImpl extends Activatable
    implements examples.activation.MyRemoteInterface {
ステップ 3:
引数をとらない古いコンストラクタを削除またはコメントアウトする
// public MyRemoteInterfaceImpl() throws RemoteException
// {
// }

ステップ 4:
実装クラスに 2 つの引数をとるコンストラクタを宣言する

public MyRemoteInterfaceImpl(ActivationID id, MarshalledObject data) 
    throws RemoteException {

    // Register the object with the activation system
    // then export it on an anonymous port
    //
    super(id, 0);
}

「セットアップ」クラスの作成

実装が利用可能な間はずっと稼動する必要のある RMI サーバクラスと異なり、「セットアップ」クラスは、リモートオブジェクトのインスタンスを生成しなくても、起動可能クラスに必要なすべての情報を作成することができます。この例のセットアップクラスは、examples.activation.Setup2 です。

セットアップクラスは、起動可能クラスに関する情報を rmid に渡し、リモート参照 (実行可能クラスのスタブクラスのインスタンス) および識別子 (名前) を rmiregistry に登録します。そのあと、セットアップクラスは終了できます。セットアップクラスは、7 つのステップで作成します。

  1. セットアップクラスで適切なインポートを実行する
  2. SecurityManager をインストールする
  3. ActivationGroup のインスタンスを生成する
  4. ActivationDesc のインスタンスを生成する
  5. 実装クラス作成への参照を削除し、rmid に登録する
  6. rmiregistry の名前にスタブをバインドする
  7. セットアップアプリケーションを終了する

ステップ 1:
セットアップクラスで適切なインポートを実行する

import java.rmi.*;
import java.rmi.activation.*
import java.util.Properties;

ステップ 2:
SecurityManager をインストールする

System.setSecurityManager(new RMISecurityManager());

ステップ 3:
ActivationGroup のインスタンスを生成する

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

セットアップアプリケーションにおける起動グループ記述子の役割は、rmid が適切な既存の VM にアクセスしたり、起動可能オブジェクト用の新しい VM を生成したりする際に必要になるすべての情報を提供することです。

: このコードを実際にシステム上で実行するには、ポリシーファイルの位置を、ソースコードに付属するサンプルのポリシーファイルをインストールした絶対パスに変更する必要があります。

// After JDK1.2Beta4, ActivationGroups are no longer created
// implicitly as a side-effect of creating or registering the
// first Activatable object
//
// Because of the 1.2 security model, a security policy should 
// be specified for the ActivationGroup VM. The first argument
// to the Properties put method, inherited from Hashtable, is 
// the key and the second is the value 
// 
Properties props = new Properties(); 
props.put("java.security.policy", 
   "/home/rmi_tutorial/activation/policy"); 

ActivationGroupDesc.CommandEnvironment ace = null; 
ActivationGroupDesc exampleGroup = new ActivationGroupDesc(props, ace);

// Once the ActivationGroupDesc has been created, register it 
// with the activation system to obtain its ID
//
ActivationGroupID agi = 
   ActivationGroup.getSystem().registerGroup(exampleGroup);

// Now explicitly create the group
//
ActivationGroup.createGroup(agi, exampleGroup, 0);

ステップ 4:
ActivationDesc のインスタンスを生成する

セットアップアプリケーションにおける起動記述子の役割は、rmid が実装クラスの新しいインスタンスの生成に必要とする、すべての情報を提供することです。

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

// Don't forget the trailing slash at the end of the URL 
// or your classes won't be found 
// 
String location = "file:/home/rmi_tutorial/activation/"; 

// Create the rest of the parameters that will be passed to 
// the ActivationDesc constructor 
// 
MarshalledObject data = null; 

// The second argument to the ActivationDesc constructor will be used 
// to uniquely identify this class; it's location is relative to the 
// URL-formatted String, location. 
// 
ActivationDesc desc = new ActivationDesc 
    ("examples.activation.MyRemoteInterfaceImpl", location, data); 

ステップ 5:
実装クラス作成への参照を削除して、リモートインタフェースのインスタンスを宣言し、rmid に起動記述子を登録する

// MyRemoteInterfaceImpl mri = new MyRemoteInterfaceImpl(); 
// the above line is replaced with the following: 
// 
MyRemoteInterface mri = (MyRemoteInterface)Activatable.register(desc); 
System.out.println("Got the stub for the MyRemoteInterfaceImpl"); 

ステップ 6:
Activatable.register メソッドによって返されたスタブを rmiregistry の名前にバインドする

Naming.rebind("MyRemoteInterfaceImpl", mri);
System.out.println("Exported MyRemoteInterfaceImpl");

ステップ 7:
セットアップアプリケーションを終了する

System.exit(0);

コードのコンパイルおよび実行

コードのコンパイルおよび実行は、次の 6 つのステップで行います。

  1. リモートインタフェース、実装、クライアント、およびセットアップの各クラスをコンパイルする
  2. 実装クラス上で rmic を実行する
  3. rmiregistry を開始する
  4. 起動デーモン rmid を開始する
  5. セットアッププログラムを実行する
  6. クライアントを実行する

ステップ 1:
リモートインタフェース、実装、クライアント、およびセットアップの各クラスをコンパイルする

% javac -d . MyRemoteInterface.java
% javac -d . MyRemoteInterfaceImpl.java
% javac -d . Client2.java
% javac -d . Setup2.java

ステップ 2:
実装クラス上で rmic を実行する

% rmic -d . examples.activation.MyRemoteInterfaceImpl

ステップ 3:
rmiregistry を開始する

% rmiregistry &

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

rmiregistry が、その開始時に CLASSPATH 内でスタブクラスを見つけると、サーバの java.rmi.server.codebase プロパティは無視されます。その結果、クライアントは、そのリモートオブジェクトのスタブコードをダウンロードできません。

ステップ 4:
起動デーモン rmid を開始する

% rmid &

ステップ 5:
セットアッププログラムを実行する

コードベースプロパティを実装スタブの位置に設定して、セットアップを実行します。次の 4 つを同じコマンド行に記述する必要があります。
 

  1. java コマンド
  2. セキュリティポリシーファイルの位置を指定するプロパティの「名前」=「値」のペア
  3. スタブコードの位置を指定するプロパティ (「-D」から最後の「/」まで、空白文字は含めない)
  4. セットアッププログラムの完全指定されたパッケージ名

空白文字は、java という語の直後に 1 つ、2 つのプロパティの間に 1 つ、および (ブラウザまたは紙上では判別しにくいですが) examples という語の直前に 1 つ必要です。

% java  -Djava.security.policy=/home/rmi_tutorial/activation/policy  -Djava.rmi.server.codebase=file:/home/rmi_tutorial/activation/  examples.activation.Setup2

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

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

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

サーバ側の出力は、次のようになります。

    Got the stub for the MyRemoteInterfaceImpl
    Exported MyRemoteInterfaceImpl
ステップ 6:
クライアントを実行する

クライアントプログラムへの引数は、実装サーバのホスト名で、この場合は vector です。

    % java examples.activation.Client2 vector

クライアント側の出力は次のようになります。

    Got a remote reference to the newly-Activatable object
    Returned from remote call
    Result: Successful execution of callMeRemotely() in MyRemoteInterfaceImpl

Copyright © 1998 Sun Microsystems, Inc. All Rights Reserved.