15-3 分散オブジェクトによるアプリケーション構築


・ 分散オブジェクトの本質は 自由度の高さと多様性にあります。 分散オブジェクトによるアプリケーションは原理的には「境界」を持ちません。 小規模なLANからインターネット規模まで自然に拡張が行えます。 分散オブジェクトの形態もさまざまならば、 利用するオブジェクトの個数やその組み合わせも無限です。 分散オブジェクトの技術の登場によって、従来は存在しなかったような まったく新しいスタイルのアプリケーションが生み出される可能性もあるのです。
 今回紹介するサンプルもそれぼど複雑なものではありません。 簡単なチャットシステムを実現しようというものですが、 分散オブジェクトの一端を見るきっかけになればと思います。

・ まず全体の構成について説明することにしましょう。 まず第一段階の実験バージョンでは、 アプリケーションは以下のクラスから構成されています。

TalkServerと複数の MessageReceiver および MessageSender が異なるマシン上で起動されます。ユーザーの多くは MessageReceiver と MessageSenderの両者を同時に起動しているでしょう。 ただし、常にそうである必要はありません。たとえば会話の様子を単にモニタリング する目的で MessageReceiverのみを利用していることもありえます。 TalkServerも複数存在することが可能です。 それぞれの TalkServerが1つの「チャットルーム」に対応すると考えてください。 MessageReceiverおよび MessageSenderは起動時に参加する TalkServerを選択します。

 通信はどのようにして実現されるのかをたどってみましょう。 (リンク先のソースコードをもう一度ながめてみてください。) ユーザーの1人が MessageSenderにメッセージを入力したとしましょう。 するとその MessageSenderは TalkServerの updateMessage()メソッドを呼び出します。 TalkServer の updateMessage() は登録されているすべての MessageReceiver の updateMessage()メソッドを呼び出します。MessageReceiverの updateMessage() メソッドはその実装に応じてユーザーに対して新しいメッセージの内容を表示すること になります。 要するに処理の流れはスタンドアロンの Javaアプリケーションの場合と形式的に 何ら変わるところがありません。 分散オブジェクトを導入したことで、 ネットワークの存在を「特別なもの」として意識しなくてもかまわなくなったわけです。

・ サンプルのアプリケーションの動作確認は以下のようにして行います。 実行のパターンはいろいろな可能性が考えられますが、 まず実験のため TalkServer, MessageReceiver, MessageSenderを1個ずつ 起動する最小構成で試してみましょう。 資源(バイトコード)をネットワーク上にどのように分散させるかも、 選択肢が多く存在します。 ここでは TalkServerの分散オブジェクトを提供するマシンと MessageReceiverの分散オブジェクトを提供するマシンは別に存在すると 仮定し、それぞれのマシン上に資源が分割されているような場合を想定します。 分散オブジェクトを生成するためには以下のような起動用の サンプル ServerTestClientTest を用意します。
便宜上 ServerTest と ClientTest という名前を付けました。 しかし実際にはどちらも分散オブジェクト TalkServer と MessageReceiver を生成して提供している点に注意してください。 それぞれのオブジェクトの実装は TalkServerImplクラスと SimpleMessageReceiverクラスを用いることにします。 ServerTest と ClientTestは一般に異なるマシンで起動されます。 それぞれがローカルに持っていなければならない資源(バイトコード) を表にまとめておきましょう。

図4:分散オブジェクトを起動するために必要な資源
ServerTest側ClientTest側
TalkServer.class
TalkServerImpl.class
TalkServerImpl_Stub.class
TalkServerImpl_Skel.class
MessageReceiver.class
Message.class
ServerTest.class
TalkServer.class
MessageReceiver.class
SimpleMessageReceiver.class
SimpleMessageReceiver_Stub.class
SimpleMessageReceiver_Skel.class
MessageSender.class
Message.class
ClientTest.class

さて以下では説明をわかりやすくするために、便宜的に起動するマシン名と その中での資源の場所を仮に定めることにしましょう。 (実際に実行する場合には、それぞれのシステムの現実の名前に置き換えて ください。) TalkServer の分散オブジェクトは host1.wakhok.ac.jp 内にあり、 "http://host1.wakhok.ac.jp/server/" という URLでアクセスできるとします。 同様に、 MessageReceiver の分散オブジェクトは host2.wakhok.ac.jp 内 にあり、 "http://host2.wakhok.ac.jp/client/" という URLでアクセスできるとします。
 まずそれぞれのプログラムを起動する以前にネームサーバが動いている 必要がありました。今回もネームサーバとしては JDKにツールとして提供されている rmiregistry を利用することにします。 host1 も host2 もいずれも分散オブジェクトを提供しますから、どちらの マシン上でも rmiregistry をバックグラウンドで起動することになります。
 host1 では ServerTestのプログラムを起動しますが、 host2上の MessageReceiver のオブジェクトを手に入れる必要があります。 そのためには SimpleMessageReceiver_Stub のバイトコードをロードしなくてはなりません。 host2側についても事情は全く同じです。 host2上で実行される ClientTestは host1 の上にある TalkServerImpl_Stub をロードしなくてはいけません。 このロード先の情報は VMの起動時にコマンドラインのオプションとして VMのプロパティ java.rmi.server.codebase に与えることができます。 この場合指定するのは自分が提供する分散オブジェクトの資源の場所です。 具体的には次のようにコマンドを実行することになります。 (セキュリティの方針を記述したファイルは前回同様 policy という名前で 用意されているとします。)


host1側:
java  -Djava.rmi.server.codebase="http://host1.wakhok.ac.jp/server/"
-Djava.security.policy="policy"  ServerTest

host2側:
java  -Djava.rmi.server.codebase="http://host2.wakhok.ac.jp/client/"
-Djava.security.policy="policy"  ClientTest  host1

 これで通信が始まるはずです。host1の側の端末から行単位がで入力された メッセージは、host2のサーバーによって処理され再び host1 の端末に エコーバックされます。現在は参加者が1名のため、それ以外のことは起りません。 参加者を増やすことは容易です。host2 で行ったのと同じようにして 他のマシンでも ClientTestのプログラムを走らせればいいからです。 (もちろん、新しい参加者のマシンに SimpleMessageReceiver もしくはそれと同様に MessageReceiverを実装した分散オブジェクトの資源が存在することが前提です。) サーバーを複数立ち上げる場合も同様です。