- PR -

【コードへの指摘をお願いします】RMI+Observerパターン

投稿者投稿内容
しんい
ベテラン
会議室デビュー日: 2005/09/01
投稿数: 55
投稿日時: 2007-07-11 05:35
お世話になっております。
表題の通り、RMIでObserverパターンを実現したいと考えております。
実現の目的は、サーバー側からユーザーへの通知の仕組みの確立です。

一通りプログラムを作成したのですが意図通り動いてくれません。
サンプルコードを提示致しますので、ご指摘頂ければありがたいです。
よろしくお願いします。

・リモートインターフェイス
public interface Rface extends Remote{
  void add(Receive receive) throws RemoteException;
}

・Observerインターフェイス
public interface Receive {
  void update(String str);
}

・サーバー(5秒に一回、オブザーバーを呼び出して更新します)
public class Server extends UnicastRemoteObject implements Rface{
  private static final long serialVersionUID = 858454002682425130L;

  public Server() throws RemoteException {}

  ArrayList<Receive> list = new ArrayList<Receive>();
  public void add(Receive receive) throws RemoteException {
    list.add(receive);
  }

  public static void main(String[] args) {
    System.setSecurityManager(new RMISecurityManager());
    try {
      Server server = new Server();
      Naming.rebind("rmi://127.0.0.1/Server",server);
      count c = server.new count();
      c.start();
    } catch (Exception e) {}
  }

  class count extends Thread{
    public void run(){
      int x=0;
      while(x<100){
        x++;
        while(list.iterator().hasNext()){
        ((Receive)list.iterator().next()).update("update"+x);
        }
        try {sleep(5000);} catch (InterruptedException e) {}
      }
    }
  }
}

・クライアント
public class Client {
  public static void main(String[] args) throws MalformedURLException, RemoteException, NotBoundException {
    Rface rface = (Rface)Naming.lookup("rmi://127.0.0.1/Server");
    Client client = new Client();
    rface.add(client.new Receiver());
    while(true);
  }
  class Receiver implements Receive,Serializable{
    private static final long serialVersionUID = 1L;
    public void update(String str) {
      System.out.println(str);
    }
  }
}
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-07-11 10:14
Receiverが単なる直列化可能なオブジェクトなのが問題なのでは?
リモートオブジェクトにして、スタブをServerに渡してみましょう。

この構造だとサーバー側で直列化して渡されたReceiverのupdate()を
ローカルに呼び出しているだけになってしまうと思います。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-07-11 10:31
引用:

しんいさんの書き込み (2007-07-11 05:35) より:
    while(true);


提示されたコードはほとんど見ていませんが、ここはスリープすることなく無限ループになっていて、CPUの実行時間を奪い取ってしまいます。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2007-07-11 12:19
通知する仕組みは JMX を使うといいかもしれません。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-07-11 12:22
引用:

しんいさんの書き込み (2007-07-11 05:35) より:
一通りプログラムを作成したのですが意図通り動いてくれません。
サンプルコードを提示致しますので、ご指摘頂ければありがたいです。
よろしくお願いします。



どのように意図してコードを書いのか?
実際にはどのような挙動を示すのか?

を書きましょう。一からコードを解析するのはそれなりに骨が折れますので。
しんい
ベテラン
会議室デビュー日: 2005/09/01
投稿数: 55
投稿日時: 2007-07-11 13:50
あしゅさん、unibonさん、インギさん、nagiseさん、ご返信ありがとうございました。少しの間にたくさんコメントを頂き、感謝しております。
ただ、言葉足らずで問いかけました事、お詫び致します。

グループウェアの中に、メッセンジャーのような機能を付加したいと考えております。Socketを使うと出来るのはわかっているのですが、折角RMIサーバーを立てているので、その中で解決できればと思いました。
また、重要な事を書いていないと気付きましたが、RMIサーバーとRMIクライアントは別の端末で動かす予定です。さらにrmiregistryはサーバー側のみの起動にしたいと考えております。
RMIが最適なソリューションかははっきりと掴めていないのですが、可能であれば実現したいと思っております。

今回のプログラムは、その前段になります。
登録したオブジェクトを介して、サーバーからクライアントに通知する仕組みが出来上がれば構造が掴めるので、肉付けするだけで良いと考え出来る限り簡単にプログラムを作成しました。(もちろん、未熟なものでツッコミどころは多いかと思います)

今回のプログラムが目的とする挙動は、下記の通りです。
Receiveインターフェイスを持つオブジェクトをクライアントが作成し、サーバーに登録します。
そしてサーバーは何らかの処理を持って、登録しているオブジェクトに通知をします。
その通知をクライアントは受け取り、クライアントサイドの処理をします。

あしゅさんのご指摘通り、Receiver(Receiveも含めて)にRemoteを実装しましたが、残念ながら期待通りに動いてくれませんでした。
ちなみに、どのような挙動になるかと申しますと、サーバー側で、ClientのReceiverを実行しようとします。
つまり、サーバーのJARにクライアントを含めると、サーバー側のコンソールに文字が表示されます。

JMXですか。すみません、勉強不足なもので初めて聞きました。ありがとうございます。
ちょっとWebで調べてみたいと思います。

よろしくお願い致します。

すみません、追記です。
端的にいうと、JMSのような仕組みを簡易で構わないからRMIで実現したいという事です。
RMIで実現できると思ったのは、J2EEサーバのEJB関連もRMIを使用して通信を行っていると書籍で読んだからです。
間違えていればそれまでなのですが、、、
よろしくお願い致します。

[ メッセージ編集済み 編集者: しんい 編集日時 2007-07-11 14:01 ]
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-07-11 17:54
引用:

しんいさんの書き込み (2007-07-11 13:50) より:
あしゅさんのご指摘通り、Receiver(Receiveも含めて)にRemoteを実装しましたが、残念ながら期待通りに動いてくれませんでした。


Remoteを実装しただけですか?
ReceiverをUnicastRemoteObjectを拡張するか、
exportObject()から取得したスタブな必要があると思います。

このオブジェクトはrmiregistryに登録する必要はありません。
Serverをrmiregistryから取得してクライアントが登録するので、
サーバー側から名前で検索できる必要がないからです。
こくぼ
大ベテラン
会議室デビュー日: 2003/08/11
投稿数: 229
お住まい・勤務地: 国境の南、太陽の西。
投稿日時: 2007-07-11 21:15
引用:

しんいさんの書き込み (2007-07-11 05:35) より:
   count c = server.new count();
...
    rface.add(client.new Receiver());


そもそもこの構文でコンパイルできましたっけ?

引用:

while(true);


無限ループの書き方はこちらを参考にすると心が和みますよ。
http://d.hatena.ne.jp/nowokay/20070710#1184063857

_________________
『Life's rich Tapestry!!』

スキルアップ/キャリアアップ(JOB@IT)