アクティベーションの使用: 持続性
|
ドキュメントの目次 |
このチュートリアルでは、実装時に持続状態を使用する起動可能なリモートオブジェクトを実装する方法について説明します。このチュートリアルでは、Setup
プログラム (「アクティベーションの使用: Setup
プログラム」チュートリアルを参照) を使用します。このプログラムは、起動可能なリモートオブジェクトに関する情報を JavaTM Remote Method Invocation (Java RMI) 起動システムデーモン (rmid
) に登録し、rmiregistry
でそのリモートオブジェクトのスタブをバインドして、クライアントが検索できるようにします。このチュートリアルの前に、前述のチュートリアルを読むことをお勧めします。
このチュートリアルでは、次の手順を実行します。
このチュートリアルの実行に必要なファイルは、次のとおりです。
Counter.java
- カウント用のリモートインタフェースCounterImpl
- リモートインタフェースの「起動可能な」実装CounterClient.java
- リモートインタフェースを使用するクライアントclient.policy
- クライアントのセキュリティポリシーファイル 起動可能なリモートオブジェクトを実装するには、いくつかの基本的な方法があります。このチュートリアルでは、実装時に持続状態を使用する起動可能なリモートオブジェクトを実装する方法について説明します。
リモートオブジェクトは、クライアントが起動可能なリモートオブジェクトのスタブでリモートメソッドを呼び出すときに起動されます。起動可能なリモートオブジェクトのスタブには、リモートオブジェクトの起動識別子と、そのリモートオブジェクトの Java RMI 起動システムデーモン (
rmid
) にコンタクトする方法に関する情報が含まれます。スタブは、リモートオブジェクトの最新のアドレス (つまり、ホスト/ポート) に接続できない場合、リモートオブジェクトのアクティベータ (rmid
) にコンタクトしてそのオブジェクトを起動します。rmid
は、起動要求を受け取ると、リモートオブジェクトの起動グループがまだ実行されていない場合は、そのグループ (またはコンテナ) の仮想マシン (VM) を起動します。次に、rmid
は、グループにそのリモートオブジェクトのインスタンスを作成するように要求します。グループは、リモートオブジェクトを構築すると、そのリモートオブジェクトのスタブをrmid
に返します。次に、rmid
は実際のスタブを起動スタブに返して、起動スタブが将来そのリモートオブジェクトにコンタクトする方法についての情報を更新できるようにします。このアクティベーションを行う前に、アプリケーションでは、使用する必要のある起動可能なリモートオブジェクトに関する情報を登録する必要があります。次の別個のチュートリアルでは、リモートオブジェクトの起動に必要な情報と、その情報を
rmid
に登録する方法について説明します。この例では、リモートインタフェース
Counter
を 1 つのincrement
操作を使って定義します。CounterImpl
実装クラスは、increment
操作の結果をファイルに持続的に保存します。そのため、increment
操作の結果は、オブジェクトの起動/終了のサイクルを越えて存在し続けます。また、マシンのリブート後やクラッシュ後でも存在します。この処理をすべて行うには、CounterImpl
オブジェクトが起動している場合、このオブジェクトにはカウンタ値を読み取って保存するのに使用するファイル名が必要です。ユーザは、このファイル名を初期化データとしてMarshalledObject
内に含む起動記述子を登録できます。オブジェクトの起動グループは、グループが起動時にオブジェクトを構築するときに、このあらかじめ登録された整列化データ (ファイル名) をオブジェクトのコンストラクタに渡します。リモートインタフェース
examples.activation.Counter
は次のように定義されます。package examples.activation; import java.rmi.Remote; import java.io.IOException; public interface Counter extends Remote { int increment() throws IOException; }起動可能なリモートオブジェクトの
examples.activation.CounterImpl
実装クラスは次のとおりです。package examples.activation; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.rmi.MarshalledObject; import java.rmi.activation.Activatable; import java.rmi.activation.ActivationID; public class CounterImpl implements Counter { private RandomAccessFile raf; private int count; private final Object countLock = new Object(); public CounterImpl(ActivationID id, MarshalledObject data) throws Exception { if (data != null) { String filename = (String) data.get(); synchronized (countLock) { count = openFile(filename); } System.err.println("count upon activation = " + count); } Activatable.exportObject(this, id, 0); } private int openFile(String filename) throws IOException { if (filename != null && !filename.equals("")) { File file = new File(filename); boolean fileExists = file.exists(); raf = new RandomAccessFile(file, "rws"); return (fileExists) ? raf.readInt() : writeCount(0); } else { throw new IOException("invalid filename"); } } private int writeCount(int value) throws IOException { raf.setLength(0); raf.writeInt(value); return value; } public int increment() throws IOException { synchronized (countLock) { return writeCount(++count); } } }
CounterImpl
クラスは、Counter
リモートインタフェースを実装しますが、どのクラスも拡張しません。このクラスは、起動グループが起動プロセス中にインスタンスを構築するために呼び出す特別な起動コンストラクタを宣言します。この特別なコンストラクタは、次の 2 つのパラメータを取ります。
- 1 つ目のパラメータは
ActivationID
で、起動可能なリモートオブジェクトの識別子です。アプリケーションが起動記述子をrmid
に登録すると、rmid
はそれに起動識別子を割り当て、この起動識別子が記述子に関連する情報を参照します。リモートオブジェクトが起動されると、この同じ起動識別子 (リモートオブジェクトのスタブにも含まれている) がコンストラクタに渡されます。- 2 つ目のパラメータは
MarshalledObject
で、rmid
にあらかじめ登録された初期化データが含まれています。この例では、整列化されたデータは、最新のカウンタ値であるオブジェクトの持続状態を含むファイルの名前です。コンストラクタは、2 つ目のパラメータとして渡された
MarshalledObject
に含まれるファイル名を取得します。次に、コンストラクタは、ローカルメソッドopenFile
を呼び出して、そのファイルを開き、現在のカウンタ値を返します。ファイルが存在する場合、openFile
メソッドは最後にファイルに保存された値を読み取ります。ファイルが存在しない場合は、新しいファイルを作成して、カウントを 0 に初期化します。次に、コンストラクタは、static メソッドActivatable.exportObject
を呼び出し、実装自体 (この
)、起動識別子、およびポート番号0
を渡して、オブジェクトを匿名の TCP ポートでエクスポートする必要があることを示します。この実装では、パラメータとしてコンストラクタに渡された起動識別子は使いませんが、別の実装では、将来の使用に備えて、たとえばオブジェクトを終了するために、起動識別子を保存することもできます。最後に、クラスは、リモートインタフェースの単一メソッドである
increment
を実装して、カウントを増分し、そのカウントをファイルに保存して、増分したカウントを返します。writeCount
メソッドの実装には弱点があることに注意してください。setLength
とwriteInt
の呼び出しの間にマシンがクラッシュすると、カウンタの値が失われます。この実装を小さなウィンドウ内のクラッシュに対してより堅牢なものにすることは、読者に残された課題です。
CounterClient
プログラムは、オプションの第 1 引数として提供されたホストのレジストリ内のリモートオブジェクトのスタブ (リモートインタフェースCounter
を実装するスタブ) を検索して、そのスタブのincrement
メソッドを呼び出し、結果を表示します。レジストリから獲得したスタブでこのクライアントがリモートメソッドを呼び出すと、リモートオブジェクトが起動されていない場合にはリモートオブジェクトが起動されます。プログラムのソースは以下のとおりです。
package examples.activation; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class CounterClient { public static void main(String args[]) throws Exception { String hostname = "localhost"; if (args.length < 1) { System.err.println( "usage: java [options] examples.activation.CounterClient [host]"); System.exit(1); } else { hostname = args[0]; } if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); } String name = System.getProperty("examples.activation.name"); Registry registry = LocateRegistry.getRegistry(hostname); Counter stub = (Counter) registry.lookup(name); System.err.println("Obtained stub from the registry."); System.err.println("Invoking increment method..."); int count = stub.increment(); System.err.println("Returned from increment remote call."); System.err.println("count = " + count); } }このプログラムを次のように実行します。
java -cp clientDir \ -Djava.security.policy=client.policy \ -Dexamples.activation.client.codebase=clientCodebase \ -Dexamples.activation.name=name \ examples.activation.CounterClient [host]説明
- clientDir は、クライアントプログラム (そのクラスパス) のルートディレクトリ
- client.policy は、このプログラムのセキュリティポリシーファイル
- clientCodebase は、このプログラムのクラス (client.policy ファイルでこのプログラムにアクセス権を付与するときに使用) の場所 (URL)
- name は、レジストリ内のオブジェクトのスタブの名前
- host は、サーバのホスト
注: このプログラムを実行する前に、
rmid
がそのデフォルトポートで稼動し、rmiregistry
がそのデフォルトポート (両方ともリモートホスト上) で稼動している必要があります。アクティベーションの例として、適切なアクセス権を付与する
client.policy
ファイルの例を以下に示します。grant codeBase "${examples.activation.client.codebase}" { // permissions to read system properties required by the client permission java.util.PropertyPermission "examples.activation.name","read"; // permission to connect to the registry, activation system, and remote host permission java.net.SocketPermission "*:1024-","connect"; };アクセス権が付与されるコードベースは、クライアントのクラスの場所を指定するファイル URL です。このファイル URL は、
examples.activation.client.codebase
システムプロパティの値で、クライアントプログラムの実行時に定義されます。クライアントには 2 つのアクセス権が必要です。
java.util.PropertyPermission
- レジストリ内のスタブの名前を指定するシステムプロパティexamples.activation.name
を読み取るjava.net.SocketPermission
- レジストリ、起動システム、およびリモートオブジェクトのホストに接続する
この例のソースファイルは、次のようにしてコンパイルできます。
javac -d implDir Counter.java CounterImpl.java javac -d clientDir Counter.java CounterClient.javaimplDir は実装のクラスファイルを配置する生成先ディレクトリで、clientDir はクライアントのクラスファイルを配置する生成先ディレクトリです。
Setup
プログラムの実行実装段階が完了したら、起動可能なオブジェクトに関する情報を登録して、クライアントが使えるようにする必要があります。
Setup
プログラムは、「アクティベーションの使用:Setup
プログラム」チュートリアルで説明されているように、起動可能なオブジェクトの起動記述子をrmid
に登録し、rmiregistry
でリモートオブジェクトのスタブをバインドして、クライアントが検索できるようにします。この例の
Setup
プログラムを実行するには、Setup
プログラムのチュートリアルの「rmid
、rmiregistry
、およびSetup
プログラムの起動」を参照してください。rmid
、rmiregistry
、およびSetup
プログラム自体の起動方法について説明しています。
Setup
チュートリアルの手順に従ってrmid
とrmiregistry
を実行したら、Setup
プログラムを実行して、examples.activation.CounterImpl
クラスを実装する起動可能なオブジェクトの起動記述子を登録する必要があります。次のコマンド行では、Setup
プログラムを実行して、使用される各コードベースの適切なファイル URL を提供します。java -cp setupDir:implDir \ -Djava.security.policy=setup.policy \ -Djava.rmi.server.codebase=file:/implDir/ \ -Dexamples.activation.setup.codebase=file:/setupDir/ \ -Dexamples.activation.impl.codebase=file:/impDir/ \ -Dexamples.activation.name=examples.activation.Counter \ -Dexamples.activation.policy=group.policy \ -Dexamples.activation.file=file \ examples.activation.Setup examples.activation.CounterImpl説明
- setupDir は、
Setup
プログラムのクラスのルートディレクトリ- implDir は、実装のクラスのルートディレクトリ
- setup.policy は、
Setup
プログラムのセキュリティポリシーファイル- group.policy は、起動グループのセキュリティポリシーファイル
- file は、オブジェクトの起動記述子に
data
として登録されているオブジェクトの持続状態が書かれたファイルの名前前述の各ファイル URL には、必須の末尾のスラッシュがあることに注意してください。このチュートリアルに適したグループとセットアップポリシーファイルの例は、
Setup
のチュートリアルに示されていますが、以下にも示しておきます。
Setup
プログラムからの出力は、次のようになります。Activation group descriptor registered. Activation descriptor registered. Stub bound in registry.
正常に
CounterImpl
実装の起動記述子を登録したら、クライアントプログラムを実行できるようになります。クライアントプログラムは、最初の実行時に起動可能なオブジェクトを起動します。次のコマンド行では、クライアントコードベースのファイル URL を指定するクライアントプログラムの実行方法を示します。
java -cp clientDir \ -Djava.security.policy=client.policy \ -Dexamples.activation.client.codebase=file:/clientDir/ \ -Dexamples.activation.name=examples.activation.Counter \ examples.activation.CounterClient [host]説明
- clientDir は、クライアントプログラム (そのクラスパス) のルートディレクトリ
- client.policy は、このプログラムのセキュリティポリシーファイル
- name は、レジストリ内のオブジェクトのスタブの名前
- host は、サーバのホスト
注:
- クライアントコードベースには、末尾にスラッシュが必要です。
- name は、
Setup
プログラムに提供される名前と一致する必要があります。この例では、examples.activation.Counter
という名前を使用しました。rmid
とrmiregistry
は、サーバのホスト上で稼動している必要があります。サーバのホストがローカルホストでない場合、host 引数は、それらが稼動しているリモートホストを指定する必要があります。クライアントからの出力は、次のようになります。
Obtained stub from the registry. Invoking increment method... Returned from increment remote call. count = 1
Copyright 2004 Sun Microsystems, Inc.All Rights Reserved. コメントの送付先: rmi-comments@java.sun.com |