RMIでリモートコールしてくれない件
以下のようなクラスがあって、
Echo.java
package rmitest; import java.io.Serializable; import java.rmi.Remote; import java.rmi.RemoteException; public interface Echo extends Remote, Serializable{ public String sayEcho(String message) throws RemoteException; }
EchoImpl.java
package rmitest; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class EchoImpl implements Echo{ public String sayEcho(String message) { System.out.println("server=" + message); return message; } public static void main(String[] args) throws Exception{ Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT); Echo echo = new EchoImpl(); //Remote remote= UnicastRemoteObject.exportObject(echo, 0); //registry.rebind("echo", remote); registry.rebind("echo", echo); System.out.println("wait"); synchronized(EchoImpl.class){ EchoImpl.class.wait(); } System.out.println("end"); } }
EchoClient.java
package rmitest; import java.rmi.Naming; public class EchoClient { public static void main(String[] args) throws Exception { Echo echo = (Echo)Naming.lookup("echo"); String message = echo.sayEcho("hoge"); System.out.println("client=" + message); } }
EchoImplを実行、EchoClientを実行すると、期待している動作では、
サーバーのコンソール
server=hoge
クライアントのコンソール
client=hoge
となるはずであるが、
実際は、以下のようになる。
クライアントのコンソール
server=hoge client=hoge
exportObject(あるいはUnicastRemoteObjectを継承)せずに、レジストリにバインドすると、リモート呼び出しにならずに、ローカル呼び出し(newして実行?)になるらしい。RMIってそういう挙動だったのか。今日はじめて知りました。これで朝1時間ははまった。
なんちゃって構成管理
人に配るわけでもない場合、サーバーもクライアントもインターフェイスも全部の場所に全部のファイルを置くのが簡単
セキュリティポリシーとコードベース
全部の場所に全部置いた場合コードベース指定はいらない。セキュリティポリシーはどういう場合に必要なのかイマイチはっきりしないが、上のような簡単なコードの場合で自分ちのLAN内な場合、指定しなくても普通に動いてはいる。
スタブ不要なRMI
http://www.02.246.ne.jp/~torutk/javahow2/rmi_nostub.html
オプション指定でちょっとはまった。レジストリ側で、セキュリティポリシーとクラスパス(コードベース)の指定が必要みたい。
rmiregistryコマンドで起動する場合は、オプションを指定する。
Javaプログラム内でLocateRegistry#createRegistryで作る場合は、Javaプログラムの起動パラメータで必要に応じて指定(同じプロセスでレジストリ作ってバインドとかなら、セキュリティやコードベースの指定も不要かも)。
あと、UnicastRemoteObjectをextendsしてないと、リモートコールしてくれないのにはまった。
UnicastRemoteObject#exportObject(Remote)つかえないみたいだから、継承しないといかんのかなー
RMIでコールバック
クライアントからサーバーにリスナー(コールバック用)としてわたすオブジェクトもUnicastRemoteObjectを継承したものにする