10.1 概要
RMIプロトコルは、ワイヤー上の形式のために、他に2つのプロトコルを利用します。Javaオブジェクト直列化プロトコルとHTTPプロトコルです。 オブジェクト直列化プロトコルは、呼出しと戻りのデータを整列化するために使用します。 HTTPプロトコルは、リモート・メソッド呼出しを「POST」し、条件が許せば戻り値を取得するために使用します。 それぞれのプロトコルは、別々の文法としてドキュメント化されます。 生成規則の非ターミナル・シンボルは、別のプロトコルが制御する規則を参照します(オブジェクト直列化またはHTTP)。 プロトコルの境界を越える場合は、それ以後の生成規則は、組み込まれたプロトコルを使用します。
文法表記についてのノート
- ここで使用する表記方法はJava言語仕様(Java Language Specification)で使用されているものとほぼ同じです。
- ストリームの制御コードは、16進数のリテラル値で表現します。
- 文法上の非ターミナル・シンボルは、メソッド呼出しで与えられるアプリケーションに特有な値であることを表します。 このような非ターミナルの定義はJava言語のデータ型から構成されます。 それぞれの非ターミナルからそれぞれの型へのテーブル・マッピングは、文法規則に従います。
10.2 RMIトランスポート・プロトコル
RMIのワイヤー形式は、Streamで表されます。 ここで採用している用語は、クライアントからみたものです。 Outは出力メッセージを示し、Inは入力メッセージを示します。 トランスポート・ヘッダーの内容は、オブジェクト直列化を使用した形式ではありません。
Stream:
Out
In
RMIの入力と出力ストリームは対になっています。 各Outストリームには、対応するInストリームがあります。 文法内のOutストリームは、ソケット(クライアントのパースペクティブから)の出力ストリームにマップされます。 Inストリーム(文法で)は、対応するソケットの入力ストリームとペアになります。 出力ストリームと入力ストリームは対になっているので、入力ストリームで必要になるヘッダー情報は、プロトコルを認識できたかどうかの確認のみです。それ以外のヘッダー情報(マジック番号やバージョン番号)は、ストリーム対のコンテキストに含めることが可能です。
10.2.1出力ストリームの形式
RMIの出力ストリームは、トランスポートHeader情報と、続いて一連のMessagesで構成されます。 交互に出力ストリームはHTTPプロトコルに組み込まれた呼出しを含めることができます。
Out:
Header Messages
HttpMessage
Header:
0x4a 0x52 0x4d 0x49 Version Protocol
Version:
0x00 0x01
Protocol:
StreamProtocol
SingleOpProtocol
StreamProtocol:
0x4b
SingleOpProtocol:
0x4c
Messages:
Message
Messages Message
Messagesは、Protocolで指定された特定のプロトコル内でラップされます。 SingleOpProtocolの場合、Headerの後にはMessageが1つのみ存在し、Messageがラップされる追加データは存在しません。 SingleOpProtocolは、単一のリクエストおよびレスポンスを超える相互作用は不可能なHTTPリクエストに埋め込まれた呼出しに使用されます。
StreamProtocolの場合、サーバーはプロトコルのサポートを確認するバイト0x4eで応答する必要があり、サーバーが確認できるホスト名とポート番号を含むEndpointIdentifierがクライアントによって使用されています。 この情報を使ってクライアントは、セキュリティ上の理由でできない場合もありますが、自分のホスト名を知ることができます。 クライアントは、接続を受け入れるためにクライアントのデフォルト・エンドポイントを含む別のEndpointIdentifierで応答する必要があります。
StreamProtocolの場合、このエンドポイント・ネゴシエーションの後、Messagesは、データの追加のラッピングなしで出力ストリームを介して送信されます。
出力メッセージには3つのタイプがあります: Call、PingおよびDgcAck。 Callは、メソッド呼出しをエンコードします。 Pingは、リモート仮想マシンの有効性をテストするためのトランスポート・レベルのメッセージです。 DgcAckは、サーバーからの戻り値のリモート・オブジェクトがクライアントによって受信されたことを示す、サーバーの分散ガベージ・コレクタに送信される確認です。
Message:
Call
Ping
DgcAck
Call:
0x50 CallData
Ping:
0x52
DgcAck:
0x54 UniqueIdentifier
ノート: 廃止されたProtocol MultiplexProtocol (0x4d)は、Java SE 9で削除されました。
10.2.2入力ストリームの形式
現在3つのタイプの入力メッセージがあります: ReturnData、HttpReturnおよびPingAck。 ReturnDataは、"normal" RMIコールの結果です。 HttpReturnは、HTTPプロトコルに埋め込まれた起動からの戻り値です。 PingAckは、Pingメッセージの確認です。
In:
ProtocolAck Returns
ProtocolNotSupported
HttpReturn
ProtocolAck:
0x4e
ProtocolNotSupported:
0x4f
Returns:
Return
Returns Return
Return:
ReturnData
PingAck
ReturnData:
0x51 ReturnValue
PingAck:
0x53
10.3 RMIによるオブジェクト直列化の使用
RMI呼出しにおける呼び出しと戻りのデータは、Javaオブジェクト直列化プロトコルに従って整形されます。 各メソッドの呼出しのCallDataは、ObjectIdentifier (コールのターゲット)、Operation (呼び出されるメソッドを表す数値)、Hash (クライアント・スタブとリモート・オブジェクト・スケルトンが同じスタブ・プロトコルを使用していることを検証する番号)、およびコールの0以上のArgumentsのリストを含むJavaオブジェクト出力ストリームに書き込まれます。
JDK1.1スタブ・プロトコルでは、Operationはrmic,によって割り当てられたメソッド番号を表し、Hashはスタブのインタフェース・ハッシュであるスタブ/スケルトン・ハッシュです。 Java 2スタブ・プロトコル(Java 2スタブは、-v1.2オプションとrmicを使用して生成されます)の時点では、Operationの値は -1で、Hashはコールするメソッドを表すハッシュです。 ハッシュについては、セクション"RemoteRefインタフェース"で説明しています。
CallData:
ObjectIdentifier Operation Hash Arguments[opt]
ObjectIdentifier:
ObjectNumber UniqueIdentifier
UniqueIdentifier:
Number Time Count
Arguments:
Value
Arguments Value
Value:
Object
Primitive
RMIコールのReturnValueは、通常または例外の戻り値を示すリターン・コード、戻り値(必要に応じてDGCAckの送信に使用)にタグを付けるUniqueIdentifier、その後に戻り結果で構成されます: 戻されたValueまたはスローされたExceptionのいずれか。
ReturnValue:
0x01 UniqueIdentifier Value[opt]
0x02 UniqueIdentifier Exception
ノート: ObjectIdentifier、UniqueIdentifier,およびEndpointIdentifierは、デフォルトの直列化では書き出されませんが、それぞれ独自の特殊なwriteメソッド(これはオブジェクトの直列化で使用されるwriteObjectメソッドではありません)を使用します。識別子の各タイプのwriteメソッドは、そのコンポーネント・データを出力ストリームに連続して追加します。
10.3.1クラスの注釈およびロード
RMIは、ObjectOutputStreamのannotateClassメソッドおよびObjectInputStreamのresolveClassメソッドをそれぞれオーバーライドします。 各クラスには、コード・ベースのURL (クラスをロードする元の場所)を使用して注釈が付けられています。 annotateClassメソッドでは、クラスをロードしたクラス・ローダーに対し、そのクラス・ローダーのコード・ベースのURLを問い合わせます。 クラス・ローダーが非nullで、非nullコード・ベースを持っている場合は、そのコード・ベースは、ObjectOutputStream.writeObjectメソッドを使用してストリームに書き込まれます。それ以外の場合は、writeObjectメソッドを使用して、ストリームにnullが書き込まれます。 ノート: 最適化のため、「java」パッケージ内のクラスには、ノートが付けられません。これは、これらのクラスは受信側が常に利用できるからです。
クラスの注釈は、直列化復元中にObjectInputStream.resolveClassメソッドを使用して解決されます。 resolveClassメソッドは、最初にObjectInputStream.readObjectメソッドを使用して、注釈を読み取ります。 注釈(コード・ベースURL)がnullでない場合は、そのURLのクラス・ローダーを取得して、クラスをロードしようとします。
10.4 RMIによるHTTP POSTプロトコルの使用
プロキシ経由のファイアウォール経由のRMI呼び出しの実装は、JDK 9では削除されています。
10.5 RMIのアプリケーション固有の値
この表では、RMIで使用されるアプリケーション固有の値を表現する非ターミナル・シンボルを示します。 この表では、それぞれのシンボルがそれぞれの持つ型に対応しています。 各シンボルは、それが埋め込まれるプロトコルを使用して整形されます。
| シンボル | type |
|---|---|
Count |
short |
Exception |
java.lang.Exception |
Hash |
long |
Hostname |
UTF |
Number |
int |
Object |
java.lang.Object |
ObjectNumber |
long |
Operation |
int |
PortNumber |
int |
Primitive |
byte, int, short, long ... |
Time |
long |