起動に関するチュートリアルについて、このチュートリアルから読み始めることはお勧めしません。このチュートリアルは、起動に関する 3 つの導入チュートリアルのうち、すでに 1 つ以上を読み終えていることを想定しています。
UnicastRemoteObject
の場合は、実装クラスにコマンド行引数を渡すのは容易です。 これは、引数を受け取るサーバプログラムが、リモートオブジェクトの実装が有効な間ずっと実行されているからです。しかし、起動可能オブジェクトの場合、セットアップクラスは、起動記述子を RMI デーモンに登録し、スタブを rmiregistry
に登録したあと、ただちに終了する可能性があります。
MarshalledObject
クラスは、実装クラスのファイルに値をハードコーディングするのではなく、rmid
に登録された ActivationDesc
を使って持続 (初期化) データの引き渡しを可能にする柔軟な機構を提供します。
注: 以降のチュートリアルで、「起動可能オブジェクトの実装」、「起動可能オブジェクト」、および「実装」と言った場合、すべて、リモートインタフェースを実装する起動可能クラス examples.activation.MyPersistentClass
を指します。
このチュートリアルでは、セットアップクラス examples.activation.Setup4
は 2 つの処理を行います。
java.util.Properties
オブジェクトを構築して、ActivationGroupDescriptor
のコンストラクタに java.security.properties
ファイルの位置を渡す。 この情報は、ActivationDesc
のコンストラクタにも渡される
ActivationDesc
コンストラクタに渡す MarshalledObject
を使って、持続データの格納位置を表す java.io.File
オブジェクトを格納する
この例では、persistentObjectStore.ser
ファイルが存在する場合は、起動可能オブジェクトの実装は、そのファイルの持続データを使って初期化されます。ファイルが存在しない場合は、起動可能オブジェクトは、クライアントが最初にデータを送信する場合のように、自分自身を初期化します。
クライアントプログラム examples.activation.Client4
は、起動可能オブジェクトにトランザクションデータのようなベクトルを渡し、そのデータを実装オブジェクトのベクトルに追加します。クライアントが実装を呼び出してトランザクションデータを追加するたびに、起動可能な実装は MarshalledObject
によって指定されたファイルに実装の状態を格納 (ベクトルを記述) します。
このチュートリアルの構成は、次のとおりです。
このチュートリアルの実行に必要なファイルは、次のとおりです。Client4.java
- 起動可能オブジェクトのメソッドを呼び出すクラス
YetAnotherRemoteInterface.java
- java.rmi.Remote
を継承するインタフェース。
MyPersistentClass.java
- 起動可能なクラス
Setup4.java
- 起動可能クラスに関する情報を RMI レジストリおよび RMI デーモンに登録するクラス
ここでは、クライアントコードも示しますが、実装クラスやセットアップクラスの場合のように、手順を追った説明はしません。これは、起動可能オブジェクトのクライアントコードが、起動可能でないリモートオブジェクトにアクセスするための RMI クライアントコードと同じであるためです。起動は、厳密にはサーバ側での実装によって決定されます。
このチュートリアルで使われているソースコードは、次のファイル形式から選ぶことができます。
リモートで呼び出す各メソッドを記述するインタフェースを作成します。この例のリモートインタフェースは examples.activation.YetAnotherRemoteInterface
です。リモートインタフェースの作成には、次の 3 つのステップがあります。
java.rmi.Remote
を継承する
ステップ 1:
インタフェースに対し適切なインポートを実行するimport java.rmi.*; import java.util.Vector;ステップ 2:
java.rmi.Remote を継承するpublic interface YetAnotherRemoteInterface extends Remote {ステップ 3:
リモートに呼び出す可能性のあるメソッドをそれぞれ宣言するpublic Vector calltheServer(Vector v) throws RemoteException;
この例の実装クラスは、examples.activation.MyPersistentClass
です。MarshalledObject
を使用する、起動可能な実装クラスを作成するには、次の 5 つのステップを実行します。
java.rmi.activation.Activatable
からクラスを継承する
MarshalledObject
を使用するメソッドを記述して、オブジェクトのデータ状態を保存および復元する
ステップ 1:
実装クラスに対し適切なインポートを実行するimport java.io.*; import java.rmi.*; import java.rmi.activation.*; import java.util.Vector;ステップ 2:
java.rmi.activation.Activatable
からクラスを継承するpublic class MyPersistentClass extends Activatable implements examples.activation.YetAnotherRemoteInterface {ステップ 3:
2 つの引数をとる実装クラスのコンストラクタを宣言するこの例のコンストラクタでは、スーパークラスのコンストラクタへの通常の呼び出しのほかに、
MarshalledObject
を使用して持続データを格納するファイル名を指定します。ファイルが存在する場合は、そのファイルを使ってこのオブジェクトの変数であるtransactions
という名のVector
が初期化されます。ファイルオブジェクトが存在しない場合は、ベクトルは手動で初期化します。ファイルの読み取りにエラーが発生した場合は、オブジェクトの構築は失敗します。private Vector transactions; private File holder; public MyPersistentClass(ActivationID id, MarshalledObject data) throws RemoteException, ClassNotFoundException, java.io.IOException { // Register the object with the activation system // then export it on an anonymous port super(id, 0); // Extract the File object from the MarshalledObject that was // passed to the constructor // holder = (File)data.get(); if (holder.exists()) { // Use the MarshalledObject to restore my state // this.restoreState(); } else { transactions = new Vector(1,1); transactions.addElement("Initializing transaction vector"); } }ステップ 4:
MarshalledObject
を使用するメソッドを記述して、オブジェクトのデータ状態を保存および復元する// If the MarshalledObject that was passed to the constructor was // a file, then use it to recover the vector of transaction data // private void restoreState() throws IOException, ClassNotFoundException { File f = holder; FileInputStream fis = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(fis); transactions = (Vector)ois.readObject(); ois.close(); } private void saveState() { try { File f = holder; FileOutputStream fos = new FileOutputStream(f); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(getTransactions()); oos.close(); } catch (Exception e) { throw new RuntimeException("Error saving vector of data"); } }クライアントから渡されたベクトルの各要素をオブジェクトのインスタンスに追加し、更新されたベクトルをファイルに保存します。
public Vector calltheServer(Vector v) throws RemoteException { int limit = v.size(); for (int i = 0; i < limit; i++) { transactions.addElement(v.elementAt(i)); } // Save this object's data out to file // this.saveState(); return transactions; }
「セットアップ」クラスの役割は、リモートオブジェクトのインスタンスを生成しない場合でも、起動可能クラスに必要なすべての情報を作成することです。この例のセットアップクラスは、 examples.activation.Setup4
です。
セットアップクラスは、起動可能クラスに関する情報を rmid
に渡し、リモート参照 (実行可能クラスのスタブクラスのインスタンス) および識別子 (名前) を rmiregistry
に登録します。 そのあと、セットアップクラスは終了できます。セットアップクラスは、7 つのステップで作成します。
SecurityManager
をインストールする
ActivationGroup
のインスタンスを生成する
ActivationDesc
のインスタンスを生成する
rmid
に起動記述子を登録する
rmiregistry
の名前にバインドする
ステップ 1:
セットアップクラスで適切なインポートを実行するimport java.io.File; import java.rmi.*; import java.rmi.activation.*; import java.util.Properties;ステップ 2:
SecurityManager
をインストールするSystem.setSecurityManager(new RMISecurityManager());ステップ 3:
ActivationGroup
のインスタンスを生成する注: ここでは、例を単純にするために、すべての位置のすべてのユーザにグローバルなアクセス権を与える policy ファイルを使用します。このポリシーファイルは、実稼働環境では使用しないでください。
java.security.policy
ファイルを使ってアクセス権を適切に指定する方法については、次のドキュメントを参照してください。
デフォルトの Policy の実装とポリシーファイルの構文
セットアップアプリケーションにおける起動グループ記述子の役割は、
rmid
が適切な既存の Java TM 仮想マシン* (JVM) にアクセスしたり、起動可能オブジェクト用の新しい JVM を生成したりする際に必要になるすべての情報を提供することです。注 - このコードを実際にシステム上で実行するには、ポリシーファイルの位置を、ソースコードに付属するサンプルのポリシーファイルをインストールした絶対パスに変更する必要があります。
// Because of the Java 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);ステップ 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/"; // Pass the file that we want to persist to as the Marshalled // object MarshalledObject data = new MarshalledObject (new File( "/home/rmi_tutorial/activation/persistentObjectStore.ser")); // The location 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 (agi, "examples.activation.ActivatableImplementation", location, data);ステップ 5:
リモートインタフェースのインスタンスを宣言し、rmid
に起動記述子を登録するYetAnotherRemoteInterface yari = (YetAnotherRemoteInterface)Activatable.register(desc); System.out.println("Got the stub for MyPersistentClass");ステップ 6:
Activatable.register
メソッドによって返されたスタブをrmiregistry
の名前にバインドするNaming.rebind("MyPersistentClass", yari); System.out.println("Exported MyPersistentClass");System.exit(0);
コードのコンパイルおよび実行は、次の 6 つのステップで行います。
rmic
を実行する
rmiregistry
を開始する
rmid
を開始する
ステップ 1:
リモートインタフェース、実装、クライアント、およびセットアップの各クラスをコンパイルする% javac -d . YetAnotherRemoteInterface.java % javac -d . MyPersistentClass.java % javac -d . Client4.java % javac -d . Setup4.java% rmic -d . examples.activation.MyPersistentClass
% rmiregistry &
注 - rmiregistry を開始する前に、
registry
を実行するシェルまたはウィンドウに CLASSPATH が設定されていないこと、あるいは設定されていても、クライアントにダウンロードするクラスへのパス (リモートオブジェクトの実装クラスのスタブを含む) が含まれていないことを確認してください。
rmiregistry
が、その開始時に CLASSPATH 内でスタブクラスを見つけると、サーバのjava.rmi.server.codebase
プロパティは無視されます。その結果、クライアントは、そのリモートオブジェクトのスタブコードをダウンロードできません。% rmid -J-Djava.security.policy=rmid.policy &rmid.policy
は、rmid
のセキュリティポリシーファイル名です。注: デフォルトでは、
rmid
は現在、セキュリティポリシーファイルを要求します。 このファイルは、起動グループ用の JVM の起動に、各ActivationGroupDescriptor
の情報を使用できるかどうかを確認するために使用されます。完全な詳細については、rmid
の Solaris オペレーティング環境用マニュアルページおよびrmid
の Microsoft の Windows プラットフォーム用マニュアルページを参照してください。コードベースのプロパティを実装スタブの位置に設定して、セットアップを実行します。次の 4 つを同じコマンド行に記述する必要があります。
空白文字は、
java
」コマンド- セキュリティポリシーファイルの位置を指定するプロパティの「名前」=「値」のペア
- スタブコードの位置を指定するプロパティ (「-D」から最後の「/」まで空白文字は含めない)
- セットアッププログラムの完全指定されたパッケージ名
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.Setup4
コードベースプロパティは、URL として解釈処理されます。 このため、プロパティは
http://aHost/somesource/
かfile:/myDirectory/location/
の形式、またはオペレーティングシステムによってはfile:///myDirectory/location/
(file:
のあとにスラッシュが 3 つ続く) の形式でなければなりません。サンプルコードを実行するには
file:
形式の URL の方が使いやすい場合があります。しかし、この場合、サーバにアクセスできるクライアントは、(サーバと同じマシン上で実行したり NFS などの共用ファイルシステムを使用して) サーバと同じファイルシステムにアクセスできるクライアントだけになります。HTTP サーバがまだ稼動していない場合は、米国サン・マイクロシステムズ社またはその関係会社の HTTP サーバからダウンロードすることができます。これらのサンプル URL の各文字列には、末尾に「/」があることに注意してください。
java.rmi.server.codebase
プロパティで指定する URL では、実装がクラス定義を適切に解釈処理 (検索) するために、末尾のスラッシュが必要です。コマンド行からのjava.rmi.server.codebase
プロパティの設定についての詳細は、java.rmi.server.codebase
プロパティを使用した動的なコードのダウンロードについてのチュートリアルを参照してください。プロパティ上の末尾のスラッシュを忘れたり、ソースファイルで指定された位置にクラスファイルが見つからない (ダウンロード可能でない) 場合、またはプロパティ名を間違って入力した場合は、
java.lang.ClassNotFoundException
がスローされます。この例外は、リモートオブジェクトをrmiregistry
にバインドしようとした場合、または最初のクライアントがそのオブジェクトのスタブにアクセスしようとした場合にスローされます。後者の場合は、rmiregistry
が CLASSPATH 内でスタブを検索したため、別の点にも問題があります。サーバ側の出力は、次のようになります。
Got the stub for MyPersistentClass Exported MyPersistentClassステップ 6:
クライアントを実行するクライアントプログラムへの引数は、実装サーバのホスト名で、この場合は
vector
です。% java -Djava.security.policy=/home/rmi_tutorial/activation/policy examples.activation.Client4 vectorこの実装に対してクライアントが最初に実行されたときの出力は、次のようになります。
Got a remote reference to the class MyPersistentClass Called the remote method Result: Initializing transaction vector Deposited money Withdrew money Transferred money from Savings Check cleared Point-of-sale charge at grocery storeこの実装に対してクライアントが 2 回目に実行されたときの出力には、さらに 5 つの「トランザクション」が含まれ、次のようになります。Got a remote reference to the class MyPersistentClass Called the remote method Result: Initializing transaction vector Deposited money Withdrew money Transferred money from Savings Check cleared Point-of-sale charge at grocery store Deposited money Withdrew money Transferred money from Savings Check cleared Point-of-sale charge at grocery store以降、クライアント呼び出しごとにpersistentObjectStore.ser
ファイルのサイズが増えていきます。 * この Web サイトで使用されている用語「Java 仮想マシン」または「JVM」は、Java プラットフォーム用の仮想マシンを表します。
Copyright © 1999 Sun Microsystems, Inc. All Rights Reserved.
コメントの送付先: rmi-comments@java.sun.com