localhost で実行しているときに RMI レジストリに正しくバインドする RMI サーバーがあります (正しくセットアップされていることを示すため)。これを行うコードは次のとおりです。
private void exposeTickHistoryRemoteProvider(TickHistoryRemoteInterface aTickHistoryServer) {
if (System.getSecurityManager() == null) {
SecurityManager mySecurityManager = getSecurityManager();
System.setSecurityManager(mySecurityManager);
}
String rmiServerHostname = System.getProperties().getProperty("java.rmi.server.hostname");
try {
TickHistoryRemoteInterface stub =
(TickHistoryRemoteInterface) UnicastRemoteObject.exportObject(aTickHistoryServer, 0);
Registry registry = LocateRegistry.getRegistry(rmiServerHostname);
String[] services = registry.list();
registry.rebind(RMI_SERVICENAME_REUTERS_TICKHISTORY_SERVER, stub);
log.info(RMI_SERVICENAME_REUTERS_TICKHISTORY_SERVER + " bound");
} catch (Exception e) {
log.error(RMI_SERVICENAME_REUTERS_TICKHISTORY_SERVER + " exception:" + e.toString());
e.printStackTrace();
}
}
私のローカルホストは、次のバージョンの Java で Windows を実行しています。
C:\eclipse>java -version
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode)
ここで、私の問題は、別のマシン (OpenJDK IcedTea6 1.8.1、Java バージョン 1.6.0_18 を使用して Ubuntu 10.04 を実行) で実行されている RMIRegistry にバインドしたいということです。
この Ubuntu マシンでは、CLASSPATH に何もなく (echo $CLASSPATH)、OpenJDK RMIRegistry を実行しています (Ubuntu にバンドルされているものとは対照的に):
sudo /usr/lib/jvm/java-6-openjdk/jre/bin/rmiregistry &
上記のコードで、変数 rmiServerHostname が "localhost" で、RMIRegistry が Windows localhost で実行されている場合、コードは正しく機能します (RMI サーバー コードは RMI レジストリにバインドされます)。ただし、rmiServerHostname がリモート Ubuntu マシン (「deity」) の場合、「rebind」呼び出しで次の例外がスローされます。
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: com.relative.tickhistory.provider.TickHistoryRemoteInterface
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: com.relative.tickhistory.provider.TickHistoryRemoteInterface
RMIRegistry を強制終了すると、別のエラー メッセージが表示されます (当然のことですが)。
java.rmi.ConnectException: Connection refused to host: deity; nested exception is:
java.net.ConnectException: Connection refused: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
at sun.rmi.server.UnicastRef.newCall(Unknown Source)
at sun.rmi.registry.RegistryImpl_Stub.list(Unknown Source)
これらの RMIRegistry の実装 (Windows Java6 と Ubuntu OpenJDK 6) の間に非互換性はないと思いますが、この問題を解決する方法がわかりません。特に、コードが正しく機能することを知っているためです (最初の Windows/localhost の例)。
これまでの進捗
役立つ回答をありがとうございます。rmiServerHostname (ローカルホストで実行) と rmiRegistryHostname ('deity' で実行) の間で混乱していたことは理解しています。次のようにコードを修正しましたが、まだ同じ問題が発生しています (「Registry registry = LocateRegistry.getRegistry( rmiRegistryHostname )」という行の変更に注意してください)。
String rmiServerCodebase = System.getProperties().getProperty("java.rmi.server.codebase");
String rmiServerHostname = System.getProperties().getProperty("java.rmi.server.hostname");
String rmiRegistryHostname = "deity";
System.out.println("rmiServerCodebase=" + rmiServerCodebase + "; rmiServerHostname=" + rmiServerHostname);
try {
TickHistoryRemoteInterface stub =
(TickHistoryRemoteInterface) UnicastRemoteObject.exportObject(aTickHistoryServer, 0);
Registry registry = LocateRegistry.getRegistry(rmiRegistryHostname);
printステートメントの出力は次のとおりです(注、私のローカルホストは「RTPC-16」です)
"rmiServerCodebase=file:///C:/workspace/DEV/ReutersTickHistoryServer/ReutersTickHistoryInterface.jar; rmiServerHostname=RTPC-16"
このファイルは存在します:
C:\>dir c:\workspace\DEV\ReutersTickHistoryServer\ReutersTickHistoryInterface.jar
Volume in drive C is OS
Volume Serial Number is 7AEB-A105
Directory of c:\workspace\DEV\ReutersTickHistoryServer
22/10/2010 12:21 PM 9,467 ReutersTickHistoryInterface.jar
1 File(s) 9,467 bytes
したがって、もう一度要約すると、次のようになります。
- このコードは、RMIRegistry と RMIServer が同じ物理ホスト (例: localhost) にある場合に機能します。
- この問題は、別のホストで RMIRegistry プロセスのみを実行しようとしたときに発生します (つまり、RMIServer がローカルホストの「RTPC-16」で実行されているときに、RMIRegistry が「deity」で実行されている場合)。
- クライアントとサーバーの両方に RMI インターフェイス コードベース ("ReutersTickHistoryInterface.jar") をバンドルしていたので、RMI がクラス定義を転送する必要があるとは予想していませんでした。RMI はクライアント上でスタブ クラスを作成し、実際の RMI 呼び出しを処理するだけです。