17-4 Activationのアイディアと仕組み


・ 先のサンプルではサーバーのプログラムは前もって起動されていて、 常にクライアントの要求を受け取るために待機していなくてはいけません。 クライアントの問い合わせがまったく来ない状態でも、 分散オブジェクトは存在し、それを生成した VMも動き続けています。 これは必ずしも効率のいい方法ではありません。 特に多数の分散オブジェクトが存在し、 それらの呼び出しがそれほど頻繁には行われない場合は無駄が増大します。
 この問題に対する解決策が Activationの機構です。 サーバーをあらかじめ起動しておくのではなく、 クライアントの要求が生じた時点で自動的に VMを起動し、 サービスを提供する分散オブジェクトを動的に生成しようという考え方です。
 このように目的は比較的理解しやすいものですが、 実現するためにはいくつか技術的な問題がありそうです。 たとえば、クライアントからの要求を受け付けるためには、 結局は何かが要求を待ち続ける働きを担わなければなりません。 そのためには専用のプロセスがバックグラウンドで動かす必要があるでしょう。 JDK1.2から追加された rmid がその役割をするツールです。 rmid が先のサンプルのサーバーの VMに代わって、 クライアントからの要求を一元的に受け付けることになります。 複数の分散オブジェクトが存在する場合には、 サービスを行っていない状態でのシステムに対する付加は明らかに低減することが できます。
 この他にも rmidがどうやって必要なサービスの分散オブジェクトの 情報を手に入れるのかという問題もあります。 こうした部分を、以下に紹介するサンプルプログラムを通じて見ていきましょう。

・ Activationの機構によって分散オブジェクトが VMとともに起動されるような サンプル ActivatableRemoteDictionaryImpl.java を紹介しましょう。 先の RemoteDictionary を元にして設計します。 インターフェイス RemoteDictionaryの仕様はそのまま利用します。 非常に長いクラス名になってしまいましたが、内容は先ほどの RemoteDictionaryImpl とほとんど同じです。 異なる点は以下の2点のみです。
 まず UnicastRemoteObject ではなく Activatable という名前のクラスの サブクラスになっています。 Activatable は java.rmi.activationパッケージによって提供される新しいクラスです。 UnicastRemoteObjectと同じくネットワークのコネクションを確立し、 オブジェクトのデータをやりとりする機能を提供します。 そしてそれに加え、システムに対して自分自身を呼び出してもらうための 登録を行う機能も提供します。
 第2の違いはコンストラクタの引数に見慣れないクラスのデータが渡されて いることです。 最初の ActivationID はシステムに対してオブジェクトが自分自身を登録するため の情報です。MarshalledObject は VMが起動される際に細かい情報を 与えたい場合に用います。 (たとえば Activationによる VMの起動の場合にはコマンドライン引数 を直接渡すことはできません。それに相当するデータの代用などに必要となります。) 今回のサンプルでは簡単のために取り扱いは省略します。

・ 次に分散オブジェクトの準備を行うクラス SetupRemoteDictionary.java のサンプルを見てみましょう。
 このサンプルは先のサーバーのプログラムの役割に対応します。 ただし、このプログラム自身はサーバーとして実行されるわけではありません。 ひととおりの作業が済むとクライアントの問い合わせを待つことなく、 さっさと終了してしまいます。 分散オブジェクトの生成もこのサンプルの中で直接行われるわけではありません。 分散オブジェクトが必要になった時に正しく生成されるための登録を行います。 そのために分散オブジェクトの資源の場所を指定する必要があります。 文字列 url はそのための情報で、 分散オブジェクトの存在するディレクトリの URLを記憶します。 登録の情報はそれを記述するための専用のクラス ActivationDesc のオブジェクト の形で与えます。ActivationDescのコンストラクタの引数は順に、 分散オブジェクトのクラス名、その資源が存在する場所の URL、 もし必要ならば MarshalledObjectのデータ(このサンプルでは省略して null) となります。
 ところで、この「登録」の相手は誰なのでしょうか? これもまた各ネットワークのサイトのシステムごとに異なります。 JDK1.2 では rmid という名前の簡単なサーバーを提供しています。 つまり rmid が VMを自動的に起動し、その中に分散オブジェクトが生成される 仕組みになっています。 その詳細は後で実行の手順として解説します。
 Activationによって起動される分散オブジェクトのサービスを受ける クライアントの側のサンプルはどうなるのでしょうか?  実はこれは特に新しいものを用意する必要はありません。 先ほどの DictonaryClientがそのまま利用できます。 クライアントの側は RemoteDictionaryに定義された機能さえ実装していれば、 サーバーの側がどんなスタイルで実現されているのかに依存しない (してはいけない)からです。

・ Activationを用いたサンプルを実行する手順を解説しましょう。 手順は次のようになります。

  1. Javaのソースのコンパイル
  2. RMIのコンパイル
  3. rmiregistryサーバーの起動
  4. rmidサーバーの起動
  5. rmidへの登録プログラムの実行
  6. クライアントプログラムの起動

 ソースのコンパイル、RMIのコンパイルの手順は先ほどと同じです。 ActivatableRemoteDictionaryImpl.javaから ActivatableRemoteDictionaryImpl.class, ActivatableRemoteDictionaryImpl_Stub.class, ActivatableRemoteDictionaryImpl_Skel.classの3個のバイトコードを生成します。
 rmiregistryサーバの起動もほぼ同じですが、 今回はセキュリティ関連の情報をオプションとしてつけ加えてください。 というのも、Activationによって起動される VMはコマンドラインから オプションを指定できませんから、なんらかの方法でその情報を 伝えなくてはいけません。 それを rmiregistryコマンドのコマンドラインを通じて行います。 したがってオプション名が -J-D という複雑なスタイルになっています。


rmiregistry  -J-Djava.security.policy=policy  &         (UNIXの場合)
start  rmiregistry  -J-Djava.security.policy=policy     (Windowsの場合)

 これに加えて新たに rmid サーバーを起動する必要があります。 このサーバーが通常の分散オブジェクトに代わってクライアントの 要求を受け取り VMの起動を行います。


rmid   &         (UNIXの場合)
start  rmid      (Windowsの場合)

 先ほどのサンプルではここでサーバーの役割を行うプログラムを実行しました。 今度はその代わりに rmid への登録を行う SetupRemoteDictionaryを実行します。 実行時にオプションが必要なのは同様です。 ただし、このプログラムは実行後直ちに終了し、後の処理は rmid に委ねます。


java  -Djava.rmi.server.codebase=http://www.wakhok.ac.jp/java/rmi/sample/
      -Djava.security.policy=policy  SetupRemoteDictionary

 上記のプログラムの実行が正常に終了したら準備は整ったことになります。 クライアント側のプログラムは先のサンプルと全く同じもですから、 起動の方法も全く同じです。 他のマシンからサーバー名を指定して実行してみてください。 うまくいったでしょうか?