8 スタブ・インタフェースとスケルトン・インタフェース
このセクションでは、rmic
コンパイラによって生成されるスタブとスケルトンが使用するインタフェースとクラスを説明します。
8.1 RemoteStub
クラス
java.rmi.server.RemoteStub
クラスは、リモート・オブジェクトのスタブで共通のスーパー・クラスです。 スタブ・オブジェクトは代理であり、リモート・オブジェクトの実際の実装が定義するのとまったく同じインタフェースのセットをサポートします。
package java.rmi.server;
public abstract class RemoteStub extends java.rmi.RemoteObject {
protected RemoteStub() {...}
protected RemoteStub(RemoteRef ref) {...}
protected static void setRef(RemoteStub stub, RemoteRef ref) {...}
}
RemoteStub
の1つ目のコンストラクタは、リモート参照としてnull
をとるスタブを作成します。 2つ目のコンストラクタは、指定されたリモート参照refを引数にとるスタブを作成します。
setRef
メソッドは、Java 2 SDK, Standard Edition, v1.2では非推奨です(サポートもされません)。
8.1.1リモート・オブジェクトとスタブ・クラスとの型の等価性
クライアントは、リモート・オブジェクトのクラスが定義するのと厳密に同じセットのリモート・インタフェースを持ったスタブ(代理)オブジェクトと対話します。スタブ・クラスには、オブジェクトの型グラフを構成するクラス階層の非リモート部分は含まれません。 これは、スタブ・クラスが1つ以上のリモート・インタフェースを実装するもっとも細分化された実装クラスから生成されるためです。 たとえば、CがBを継承し、BがAを継承したとして、Bのみがリモート・インタフェースを実装する場合は、スタブが生成されるのはBからであり、Cからではありません。
スタブは、リモート・オブジェクト・クラスと同じリモート・インタフェース群を実装するため、スタブはサーバー・オブジェクトの型のリモート部分と同じ型を持つことになります。 このため、クライアントは、Java言語の組込み演算を利用してリモート・オブジェクトの型チェックや、あるリモート・インタフェースから別のインタフェースへのキャストを行うことができます。
スタブはrmic
コンパイラによって生成されます。
8.1.2 final
宣言されたObjectメソッドのセマンティックス
次のメソッドはjava.lang.Object
クラスでfinal
宣言されているため、どの実装によってもオーバーライドできません。
getClass
notify
notifyAll
wait
getClass
のデフォルト実装は、Java言語で記述されたすべてのオブジェクト(ローカルとリモート両方)に適用可能です。このため、リモート・オブジェクトの場合でも、特別な実装は必要ありません。 リモート・スタブに使用された場合には、rmic
によって生成されたスタブ・オブジェクトの正確な型がgetClass
メソッドによってレポートされます。 ただし、スタブの型はリモート・オブジェクトにより実装されたリモート・インタフェースのみを反映したもので、そのオブジェクトのローカル・インタフェースは反映しません。
java.lang.Object
のwait
とnotify
メソッドはJava言語のスレッド・モデルに則して待機と通知を扱います。 これらのメソッドをリモート・スタブに対して使うことがJavaのスレッド・モデルに違反するわけではありませんが、これらのメソッドは、Javaプログラミング言語で書かれたローカル・オブジェクトを扱う場合とはセマンティックスが異なります。 特に、これらのメソッドは、クライアントのリモート・オブジェクト(スタブ)へのローカル参照に作用し、リモートにある実際のオブジェクトには作用しません。
8.2 RemoteCall
インタフェース
RemoteCall
インタフェースは、リモート・オブジェクトのスタブとスケルトンがリモート・オブジェクトへの呼出しを実行するための抽象化です。
ノート: RemoteCall
インタフェースは、Java 2 SDK、Standard Edition、v1.2の時点で非推奨です。 1.2のスタブ・プロトコルは、このインタフェースを使いません。 Java 2 SDK, Standard Edition, v1.2では、スタブは、パラメータとしてRemoteCall
を必要としない新しいinvoke
メソッドを使います。
package java.rmi.server;
import java.io.*;
public interface RemoteCall {
ObjectOutput getOutputStream() throws IOException;
void releaseOutputStream() throws IOException;
ObjectInput getInputStream() throws IOException;
void releaseInputStream() throws IOException;
ObjectOutput getResultStream(boolean success)
throws IOException, StreamCorruptedException;
void executeCall() throws Exception;
void done() throws IOException;
}
getOutputStream
メソッドは、スタブが引数を整列化する、またはスケルトンが結果を整列化する先へ出力ストリームを返します。
releaseOutputStream
メソッドは、出力ストリームを解放します。トランスポートによっては、このメソッドはストリーム自体を解放します。
getInputStream
メソッドは、スタブが結果を非整列化する、またはスケルトンが引数を非整列化する先からInputStream
を返します。
releaseInputStream
メソッドは、入力ストリームを解放します。 この結果いくつかのトランスポートは、接続の入力側を早期に解放できます。
getResultStream
メソッドは、出力ストリームを返します(呼出しが成功したかどうかを示すヘッダー情報を書き込んだあと)。 結果ストリームを得ることができるのは、1回のリモート呼出しに対して1回だけです。 successがtrue
であれば、転送のため整列化される結果は正常終了であり、それ以外の結果は例外になります。 StreamCorruptedException
は、そのリモート呼出しに対しての結果ストリームがすでに得られている場合にスローされます。
executeCall
メソッドは、どのような値が与えられてもその値により呼出しを実行します。
done
メソッドは、リモート呼出しが完了したあとのクリーンアップを許可します。
8.3 RemoteRef
インタフェース
RemoteRef
インタフェースは、リモート・オブジェクトへのハンドルを表します。 それぞれのスタブは、RemoteRef
のインスタンスを持ち、そのインスタンスは参照の具体的な表現を含みます。 このリモート参照は、参照されているリモート・オブジェクトへのリモート呼出し実行に使われます。
package java.rmi.server;
public interface RemoteRef extends java.io.Externalizable {
Object invoke(Remote obj,
java.lang.reflect.Method method,
Object[] params,
long opnum)
throws Exception;
RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum,
long hash) throws RemoteException;
void invoke(RemoteCall call) throws Exception;
void done(RemoteCall call) throws RemoteException;
String getRefClass(java.io.ObjectOutput out);
int remoteHashCode();
boolean remoteEquals(RemoteRef obj);
String remoteToString();
}
invoke(Remote,Method,Object[],long)
メソッドは、メソッド呼出しをスタブの(obj)リモート参照に委譲します。委譲により、この参照はリモート・ホストへの接続の設定処理を引き受け、methodおよびパラメータparamsの表現を整列化してから、リモート・ホストへのメソッド呼出しを伝えます。 このメソッドは、リモート・ホスト上のリモート・オブジェクトへのメソッド呼出しの結果を返すか、または呼出しが失敗した場合はRemoteException
をスローし、リモート呼出しによって例外をスローした場合はアプリケーション・レベルの例外をスローします。 操作番号opnumは、メソッド・シグネチャのハッシュを表し、転送用のメソッドのエンコードに使用することもできます。
opnumパラメータに使用されるメソッド・ハッシュは、64ビット(long)の整数で、米国国立標準技術研究所(NIST)のSecure Hash Algorithm (SHA-1)を使用する特定のバイト・ストリームのメッセージ・ダイジェストの最初の2つの32ビット値から計算されます。 このバイト・ストリームには、java.io.DataOutput.writeUTF
メソッドを使用して記述された場合と同様に、リモート・メソッドの名前とそれに続くメソッド記述子からなる文字列が含まれています。メソッド記述子の説明については、『Java仮想マシン仕様』(JVMS)を参照してください。
たとえば、リモート・インタフェースのメソッドが次の名前とシグニチャを持っている場合、
void myRemoteMethod(int count, Object obj, boolean flag)
リモート・メソッドの名前および記述子を含む文字列は、次のようになります。
myRemoteMethod(ILjava/lang/Object;Z)V
64ビット・ハッシュ値は、8バイト・シーケンスのリトルエンディアン構成です。最初の4バイトはメッセージ・ダイジェストの最初の32ビット値(ビッグエンディアンのバイト順)で、後の4バイトはメッセージ・ダイジェストの2番目の32ビット値(ビッグエンディアンのバイト順)です。 たとえば、メッセージ・ダイジェストの最初の2つの32ビット値が0xB0B1B2B3
および0xB4B5B6B7
の場合、ハッシュ値は0xB7B6B5B4B3B2B1B0
になります。
ノート: Java 2 SDK、Standard Edition、v1.2では、メソッドnewCall(RemoteObject,Operation[],int,long)
、invoke(RemoteCall)
およびdone(RemoteCall)
は非推奨です。 1.2のスタブ・プロトコル・バージョンを使ったrmic
によって生成されたスタブは、これらのメソッドを現在は使用しません。 newCall
、invoke
、およびdone
で構成される呼出しのシーケンスは、Method
オブジェクトをパラメータの1つにとる新しいinvoke
メソッドに置き換えられました。
newCall
メソッドは、リモート・オブジェクトobj上での新しいリモート・メソッド呼出し用の適切な呼出しオブジェクトを作成します。 操作配列opは、リモート・オブジェクト上で利用可能な複数の操作を含みます。 操作番号opnumは、操作配列のうち、今回のリモート呼出しで使用する特定の操作を指定するためのインデックスです。 インタフェース・ハッシュは、v1.1スタブ・プロトコルを使用するスタブとスケルトン間の互換性維持に使用する64ビット値です。 インタフェース・ハッシュは、SHA-1を使用する特定のバイト・ストリームのメッセージ・ダイジェストの最初の2つの32ビット値から計算されます。 このバイト・ストリームに含まれるデータの書込みは、java.io.DataOutput
インタフェースのwriteInt
およびwriteUTF
メソッドを使用した場合と同じ方法で行われます。データには次の項目が含まれます。
- (
int
)スタブのバージョン番号(常に1) - リモート・メソッドごと、かつ操作番号順:
- (UTF-8)リモート・メソッド名
- (UTF-8)リモート・メソッド記述子(『Java仮想マシン仕様』を参照)
- 宣言された例外ごと、かつバイナリ名の辞書式順:
- (UTF-8)例外クラスの名前
インタフェース・ハッシュ値をメッセージ・ダイジェストから作成する方法は、invoke
メソッドで使用するメソッド・ハッシュに関してすでに説明した方法と同じです。
invoke(RemoteCall)
メソッドは、リモート呼出しを実行します。invoke
は、「ユーザー(user)定義」例外を発生させます。この例外は、スタブではキャッチせずに通過させる必要があります。 リモート呼出しの途中でなんらかの例外が発生した場合、invoke
はユーザー定義例外またはRemoteException
を発生させる前に接続のクリーンアップを行うべきです。
done
メソッドは、リモート参照に接続のクリーンアップ(または再利用)を許可します。done
が呼び出されるのは、invoke
呼出しが正常に行われて(例外を発生させずに)終了し、スタブに戻った場合だけです。
getRefClass
メソッドは、直列化されてストリームに出力(out)される参照タイプ内でパッケージ修飾されていないクラス名を返します。
remoteHashCode
メソッドは、リモート・オブジェクトのハッシュ・コードを返します。 同一のリモート・オブジェクトを参照する2つのリモート・オブジェクト・スタブは(リモート・オブジェクトをハッシュ・テーブル上のキーとしてサポートするために)同じハッシュ・コードを持ちます。 RemoteObject
は、hashCode
メソッドへの呼出しをリモート参照のremoteHashCode
メソッドへ転送します。
remoteEquals
メソッドは、2つのリモート・オブジェクトを比較して異同判定します。 2つのリモート・オブジェクトは、両者が同一のリモート・オブジェクトを参照するとき等しいとされます。 たとえば、2つのスタブは両者が同一のリモート・オブジェクトを参照するならば等しいとされます。 RemoteObject
は、equals
メソッドへの呼出しをリモート参照のremoteEquals
メソッドへ転送します。
remoteToString
メソッドは、そのリモート・オブジェクトへの参照を表すString
を返します。
8.4 ServerRef
インタフェース
ServerRef
インタフェースは、リモート・オブジェクトの実装に対するサーバー側のハンドルを表します。
package java.rmi.server;
public interface ServerRef extends RemoteRef {
RemoteStub exportObject(java.rmi.Remote obj, Object data)
throws java.rmi.RemoteException;
String getClientHost() throws ServerNotActiveException;
}
exportObject
メソッドは、与えられたRemote
オブジェクトの実装objに対するクライアント・スタブ・オブジェクトを探すかあるいは作成します。パラメータdataには、オブジェクトをエクスポートするのに必要となる情報(たとえばポート番号)が含まれます。
getClientHost
メソッドは、現在のクライアントのホスト名を返します。 現在、リモート・メソッド呼出しを操作中のスレッドから呼び出された場合には、呼出しを実行中のクライアントのホスト名が返されます。 リモート・メソッドへの呼出しが現在実行中でなければ、ServerNotActiveException
が呼び出されます。
8.5 Skeleton
インタフェース
Skeleton
インタフェースは、rmic
コンパイラにより作成されたスケルトンの実装によってだけ使用されます。 リモート・オブジェクトに対するスケルトンとは、実際のリモート・オブジェクトの実装へ呼出しをディスパッチする、サーバー側のエンティティです。
ノート: Skeleton
インタフェースは、Java 2 SDK、Standard Edition、v 1.2の時点で非推奨になりました。 rmic
スタブ・コンパイラによって生成された1.1の各スケルトン・クラス(およびデフォルトのrmic -vcompat
を使用して1.2で生成された、バージョン1.1互換のスケルトン)は、このインタフェースを実装しています。 Java 2 SDK, Standard Edition, v1.2互換のバージョンでは、リモート・メソッド呼出しのディスパッチに、スケルトンが必要なくなりました。 1.2以上のバージョンと互換性のあるスタブを生成するには、コマンドrmic
をオプション-v1.2
とともに使用します。
package java.rmi.server;
public interface Skeleton {
void dispatch(Remote obj, RemoteCall call, int opnum, long hash)
throws Exception;
Operation[] getOperations();
}
dispatch
メソッドは、callオブジェクトで取得した入力ストリームのすべての引数を非整列化し、実際のリモート・オブジェクトの実装であるobj上のメソッド(操作番号opnumで示される)を呼び出します。そして戻り値をストリームに流すため整列化するか、または呼出し中に例外が発生した場合には例外をスローします。
getOperations
メソッドは、リモート・オブジェクトのメソッドに対する操作記述子が書かれた配列を返します。
8.6 Operation
クラス
Operation
クラスは、リモート・オブジェクト用のJava言語でのメソッドの記述を保持します。
ノート: Operation
インタフェースは、Java 2 SDK、Standard Edition、v1.2の時点で非推奨です。 1.2のスタブ・プロトコルは、Operation
を引数の1つとしてとる、以前のRemoteRef.invoke
を使いません。 Java 2 SDK, Standard Edition, v1.2では、スタブは、パラメータとしてOperation
を必要としない新しいinvoke
メソッドを使います。
package java.rmi.server;
public class Operation {
public Operation(String op) {...}
public String getOperation() {...}
public String toString() {...}
}
Operation
オブジェクトは、多くの場合メソッドのシグニチャ付きで生成されます。
getOperation
メソッドは、操作記述子の内容を返します(初期化されたときの値)。
toString
メソッドもまた操作記述子の文字列による表現を返します(一般的にはメソッドのシグニチャ)。