5 サーバー・インタフェース


java.rmi.serverパッケージには、リモート・オブジェクトの実装に使われる典型的なインタフェースとクラスが含まれています。

5.1 RemoteObjectクラス

RemoteObject APIドキュメントを参照してください。

5.2 RemoteServerクラス

RemoteServer APIドキュメントを参照してください。

5.3 UnicastRemoteObjectクラス

java.rmi.server.UnicastRemoteObjectクラスは、リモート・オブジェクトの作成とエクスポートをサポートします。 このクラスは、次の特性を持ったリモート・サーバー・オブジェクトを実装します。

package java.rmi.server;

public class UnicastRemoteObject extends RemoteServer {

        protected UnicastRemoteObject()
                throws java.rmi.RemoteException {...}
        protected UnicastRemoteObject(int port)
                throws java.rmi.RemoteException {...}
        protected UnicastRemoteObject(int port,
                                      RMIClientSocketFactory csf,
                                      RMIServerSocketFactory ssf)
                throws java.rmi.RemoteException {...}

        public Object clone()
                throws java.lang.CloneNotSupportedException {...}
        public static RemoteStub exportObject(java.rmi.Remote obj)
                throws java.rmi.RemoteException {...}
        public static Remote exportObject(java.rmi.Remote obj, int port)
                throws java.rmi.RemoteException {...}
        public static Remote exportObject(Remote obj, int port,
                                          RMIClientSocketFactory csf,
                                          RMIServerSocketFactory ssf)
                throws java.rmi.RemoteException {...}
        public static boolean unexportObject(java.rmi.Remote obj,
                                             boolean force)
                throws java.rmi.NoSuchObjectException {...}
}

5.3.1新しいリモート・オブジェクトを作成する

1つ以上のリモート・インタフェースを実装するリモート・オブジェクト実装を作成し、エクスポートする必要があります。 リモート・オブジェクトをエクスポートすることにより、そのオブジェクトは、クライアントからの着信呼出しを受け入れることができるようになります。 UnicastRemoteObjectとしてエクスポートされるリモート・オブジェクト実装の場合、エクスポートにはTCPポートでの待機が含まれます。ただし、同じポート上で複数のリモート・オブジェクトが着信呼出しを受け入れるので、必ずしも新しいポートで待機する必要はありません。 リモート・オブジェクト実装では、UnicastRemoteObjectクラスを拡張してオブジェクトをエクスポートするコンストラクタを利用するか、あるいは他のいくつかのクラスを拡張して(またはまったく拡張せずに) UnicastRemoteObjectexportObjectメソッドを使用してオブジェクトをエクスポートできます。

引数を取らないコンストラクタは、リモート・オブジェクトを作成し、実行時に選択された匿名(または任意)のポートでエクスポートします。 2つ目の形式のコンストラクタは、portという引数を1つのみ取ります。この引数は、リモート・オブジェクトが着信呼出しを受け入れるポート番号を指定します。 3つ目のコンストラクタは、RMIServerSocketFactoryから作成されたServerSocketを使用して、指定されたportの着信呼出しを受け入れるリモート・オブジェクトを作成してエクスポートします。クライアントは、RMIClientSocketFactoryから提供されたSocketを使用してリモート・オブジェクトに接続します。

ソケット・ファクトリを指定せずにリモート・オブジェクトをエクスポートするか、RMIClientSocketFactoryおよびRMIServerSocketFactory型のパラメータを含まないバージョンのUnicastRemoteObject.exportObjectメソッドまたはUnicastRemoteObjectコンストラクタを使用してオブジェクトをエクスポートすると、リモート・オブジェクトはすべてのローカル・アドレスにエクスポートされます。 リモート・オブジェクトを特定のアドレスにエクスポートするには、"RMIソケット・ファクトリ"セクションを参照してください。

5.3.2 RemoteObjectからの拡張ではない実装のエクスポート

exportObjectメソッド(すべての形式)は、UnicastRemoteObjectクラスを拡張することでは実装されない単純なピアツーピア・リモート・オブジェクトをエクスポートするために使用します。 exportObjectメソッドの1つ目の形式は、objというパラメータを1つのみ取ります。これは、着信するRMI呼出しを受け入れるリモート・オブジェクトです。このexportObjectメソッドは、実行時に選択された匿名(または任意)のポートにオブジェクトをエクスポートします。 2つ目のexportObjectメソッドは、リモート・オブジェクトobj、およびリモート・オブジェクトが着信呼出しを受け入れるポート番号portの2つのパラメータを取ります。 3つ目のexportObjectメソッドは、指定されたRMIClientSocketFactorycsfRMIServerSocketFactory ssfを使用して、指定されたportにオブジェクトobjをエクスポートします。

exportObjectメソッドは、リモート・オブジェクトobjのスタブであり、リモート・オブジェクトの代わりにRMI呼出しで渡されたRemoteStubを返します。

5.3.3 RMI呼出しでUnicastRemoteObjectを渡す

上述したように、RMI呼出しの中で、エクスポートされたUnicastRemoteObject型のオブジェクトがパラメータまたは戻り値として渡されると、このオブジェクトは、リモート・オブジェクトのスタブに代わります。 エクスポートされたリモート・オブジェクトの実装は、それが作成された仮想マシン内にとどまり、仮想マシンから(値渡しによってさえ)移動しません。 すなわち、エクスポートされたオブジェクトはRMI呼出しでは参照渡しであり、エクスポートされたリモート・オブジェクトの実装は、値では渡すことができないということになります。

5.3.4 UnicastRemoteObjectを直列化する

UnicastRemoteObjectに含まれている情報は一時的であり、その型のオブジェクトがユーザー定義のObjectOutputStreamに書き込まれた場合には保存されません(たとえば、オブジェクトが直列化を使用してファイルに書き込まれる場合)。 ただし、UnicastRemoteObjectのユーザー定義サブクラスのインスタンスであるオブジェクトは、そのオブジェクトが直列化された場合でも保存可能な、非常駐データでないデータを持つことができます。

UnicastRemoteObjectが、UnicastRemoteObjectreadObjectメソッドを使ってObjectInputStreamから読み込まれる場合、そのリモート・オブジェクトは、RMI呼出しを受け取れるようにRMIランタイムに自動的にエクスポートされます。 オブジェクトのエクスポートが何らかの原因で失敗した場合には、オブジェクトの直列化復元は、例外とともに途中で終了します。

5.3.5 UnicastRemoteObjectのアンエクスポート

unexportObjectメソッドを使うと、着呼がリモート・オブジェクトobjを利用できなくなります。 パラメータforceがtrueに設定されていると、リモート・オブジェクトへの保留状態の呼出しがある場合や、進行中の呼出しがある場合でも、オブジェクトは強制的にアンエクスポートされます。 forceパラメータがfalseの場合は、オブジェクトに対する保留中または進行中の呼出しがない場合だけ、オブジェクトがアンエクスポートされます。 オブジェクトが正常にアンエクスポートされた場合は、RMIのランタイムによってそのオブジェクトが内部テーブルから削除されます。 このような強制的な方法でオブジェクトをアンエクスポートすると、クライアントがリモート・オブジェクトへの無効なリモート参照を保持したままになることがあります。 オブジェクトが事前にRMIランタイムにエクスポートされなかった場合は、このメソッドはjava.rmi.NoSuchObjectExceptionをスローします。

5.3.6 cloneメソッド

オブジェクトの複製は、オブジェクトがjava.lang.Cloneableインタフェースをサポートしている場合に、Java言語のデフォルトのメカニズムを使用することによってのみ可能になります。 java.rmi.server.UnicastRemoteObjectクラスは、このインタフェースを実装していませんが、サブクラスがCloneableを実装する必要がある場合に、そのリモート・オブジェクトが正しく複製されるように、cloneメソッドを実装しています。 サブクラスは、cloneメソッドを使用して、始めの部分は同じ内容のリモート・オブジェクトの複製を作成できます。ただし、この複製は、エクスポートされてリモート呼出しを受け入れるため、元のオブジェクトとは別のオブジェクトです。

5.4 Unreferencedインタフェース

package java.rmi.server;

public interface Unreferenced {
        public void unreferenced();
}

java.rmi.server.Unreferencedインタフェースを使うと、サーバー・オブジェクトが、自身に対するリモート参照を持っているクライアントがないという通知を受けることができます。 分散ガベージ・コレクション・メカニズムは、各リモート・オブジェクトについて、そのリモート・オブジェクトを参照しているクライアント仮想マシン群を保持しています。 あるクライアントがあるリモート・オブジェクトに対するリモート参照を持っている間は、RMIランタイムもそのリモート・オブジェクトへのローカル参照を保持し続けます。 リモート・オブジェクトの「参照」のセットが空になるたびに(つまり、そのオブジェクトを参照するクライアントの数が0になると)、リモート・オブジェクトがUnreferencedインタフェースを実装していれば、Unreferenced.unreferencedメソッドが呼び出されます。 リモート・オブジェクトがUnreferencedインタフェースをサポートするのは必須ではありません

リモート・オブジェクトに対するローカル参照が存在している間は、それをリモート呼出しで渡すこともできますし、クライアントへの戻り値にもなります。 参照を受け取ったプロセスは、そのリモート・オブジェクトに対するセットに追加されます。 参照セットが空になったとき、そのリモート・オブジェクトのunreferencedメソッドが呼び出されます。 このため、unreferencedメソッドは、参照セットがあらためて空になるたびに、何回も呼び出されます。 リモート・オブジェクトは、それに対する参照(ローカル参照またはクライアントが保持している参照)がなくなったときに回収されます。

5.5 RMISecurityManagerクラス

RMISecurityManager APIドキュメントを参照してください。

5.6 RMIClassLoaderクラス

RMIClassLoader APIドキュメントを参照してください。

5.7 LoaderHandlerインタフェース

LoaderHandler APIドキュメントを参照してください。

5.8 RMIソケット・ファクトリ

RMIランタイム実装には、接続のためにjava.net.Socketおよびjava.net.ServerSocketが必要です。RMIランタイム実装は、これらのクラスのオブジェクトを直接インスタンス化するのではなく、staticメソッドRMISocketFactory.getSocketFactoryによって返される、現在のRMISocketFactoryオブジェクトのcreateSocketおよびcreateServerSocketメソッドを呼び出します。 これにより、アプリケーションは、RMI転送で使われるソケットの種類(java.net.Socketおよびjava.net.ServerSocketクラスの代替サブクラスなど)をカスタマイズするためのフックを保持できます。 使用されるRMISocketFactoryのインスタンスは、信頼できるシステム・コードによって一度設定できます。 JDK1.1では、このカスタマイズは、ソケットの種類についての全般的な設定を行う場合に限られていました。これは、ファクトリのメソッドに渡されるパラメータが、createSockethostport、およびcreateServerSocketportのみであったためです。

Java SEプラットフォームでは、リモート・オブジェクトとの通信にどのプロトコルを使うかについて、より柔軟にカスタマイズできるようにするため、新しいインタフェースRMIServerSocketFactoryおよびRMIClientSocketFactoryが導入されました。

RMIを使ったアプリケーションで、これらの新しいソケット・ファクトリ・インタフェースを利用するために、UnicastRemoteObjectjava.rmi.activation.Activatable.の両方に、いくつかの新しいコンストラクタおよびexportObjectメソッドが追加されました。これらのコンストラクタおよびメソッドは、クライアントおよびサーバー・ソケット・ファクトリを追加されたパラメータとして利用します。

この新しいコンストラクタまたはexportObjectメソッドのどちらかによって(RMIClientSocketFactoryおよびRMIServerSocketFactoryパラメータを使って)エクスポートされるリモート・オブジェクトは、RMIランタイムにより特別に扱われます。 リモート・オブジェクトの存続期間中、ランタイムは、ServerSocketを作成してリモート・オブジェクトへの着呼を受け入れるために、カスタムのRMIServerSocketFactoryを使用し、Socketを作成してクライアントをリモート・オブジェクトに接続するために、カスタムのRMIClientSocketFactoryを使用します。

カスタム・ソケット・ファクトリとともにエクスポートされるリモート・オブジェクトのスタブおよびスケルトン内で使われるRemoteRefおよびServerRefの実装は、それぞれUnicastRef2およびUnicastServerRef2です。 UnicastRef型のワイヤーの表現では、接続するための「エンド・ポイント」の表現に、UTF形式のホスト名文字列とそれに続く整数のポート番号のみを使用していました。UnicastRef2型のワイヤーの表現には、これとは異なる表現が含まれています。 UnicastRef2では、エンド・ポイントのワイヤー表現は、残りのエンド・ポイント表現の内容を指定する形式のバイト(将来のエンド・ポイント表現の拡張用)、およびそれに続く指定された形式のデータによって構成されています。 現在のところ、データは、UTF形式のホスト名、ポート番号、および(エンド・ポイントの形式バイトによって指定されたときは)クライアントがこのエンド・ポイントでリモート・オブジェクトへのソケット接続を生成するために使用するRMIClientSocketFactoryオブジェクトの直列化表現で構成されます。 エンド・ポイントの表現には、リモート・オブジェクトのエクスポート時に指定されたRMIServerSocketFactoryオブジェクトは含まれません。

UnicastRef2型の参照を使用して呼出しが行われた場合、ランタイムは、指定されたリモート・オブジェクトへの接続用ソケットの作成時に、エンド・ポイントのRMIClientSocketFactoryオブジェクトのcreateSocketメソッドを使用します。 また、ランタイムが特定のリモート・オブジェクトに対してDGCの「dirty」および「clean」呼出しを実行する際に、リモート参照で指定されたのと同じRMIClientSocketFactoryオブジェクトから生成された接続を使用して、リモートJVM上のDGCを呼び出す必要があります。サーバー側のDGC実装は、この処理が正しく行われたことを確認する必要があります。

カスタム・ソケット・ファクトリを引数として取らないUnicastRemoteObject上の古いコンストラクタまたはメソッドを使用してエクスポートされたリモート・オブジェクトでは、以前と同様に、UnicastRefおよびUnicastServerRef型のRemoteRefおよびServerRefが使用されます。このようなオブジェクトには、エンド・ポイントの古いワイヤー表現である、UTF形式のホスト文字列とそれに続くポート番号を指定する整数が使用されます。 これは、新しい1.2の機能を使用しないRMIサーバーが、以前のバージョンのRMIクライアントとの相互運用を可能にするためです。

ソケット・ファクトリを指定せずにリモート・オブジェクトをエクスポートするか、RMIClientSocketFactoryおよびRMIServerSocketFactory型のパラメータを含まないバージョンのUnicastRemoteObject.exportObjectメソッドまたはUnicastRemoteObjectコンストラクタを使用してリモート・オブジェクトをエクスポートした場合、JavaランタイムはシステムのデフォルトのRMIソケット・ファクトリを使用します。このソケット・ファクトリは、すべてのインタフェースで受信待機するソケットをワイルドカード・アドレスで開きます。 その結果、リモート・オブジェクトはすべてのローカル・アドレスにエクスポートされます。 リモート・オブジェクトを特定のアドレスにエクスポートするには、次のいずれかを行います。

5.8.1 RMISocketFactoryクラス

java.rmi.server.RMISocketFactoryクラスは、トランスポートがソケットを取得する方法を指定するインタフェースを提供します。 次のクラスは、java.netパッケージのSocketおよびServerSocketを使用します。

package java.rmi.server;

public abstract class RMISocketFactory
        implements RMIClientSocketFactory, RMIServerSocketFactory
{

        public abstract Socket createSocket(String host, int port)
                throws IOException;
   public abstract ServerSocket createServerSocket(int port)
                throws IOException;
        public static void setSocketFactory(RMISocketFactory fac)
                throws IOException {...}
        public static RMISocketFactory getSocketFactory() {...}
        public static void setFailureHandler(RMIFailureHandler fh) {...}
        public static RMIFailureHandler getFailureHandler() {...}
}

staticメソッドsetSocketFactoryは、RMIがソケットを取得するためのソケット・ファクトリを設定します。 アプリケーションが自身のRMISocketFactoryインスタンスのためにこのメソッドを呼び出せるのは1回のみです。 アプリケーションで定義するRMISocketFactoryの実装は、たとえば接続要求に対して事前にフィルタリングを行って例外をスローしたり、java.net.Socketまたはjava.net.ServerSocketクラスの独自の拡張(セキュアな通信チャネルを提供するものなど)を返したりできます。 RMISocketFactoryを設定できるのは、実行中のセキュリティ・マネージャがソケット・ファクトリの設定を許可している場合のみです。ソケット・ファクトリの設定が許可されていない場合には、SecurityExceptionがスローされます。

staticメソッドgetSocketFactoryは、RMIによって使用されるソケット・ファクトリを返します。 ソケット・ファクトリが設定されていなければ、このメソッドはnullを返します。

トランスポート層は、トランスポートでソケットの作成が必要になると、getSocketFactoryメソッドが値を返したRMISocketFactory上でcreateSocketcreateServerSocketメソッドを呼び出します。 次に例を示します。

RMISocketFactory.getSocketFactory().createSocket(myhost, myport)

createSocketメソッドは、指定されたホストポートに接続されるクライアント・ソケットを作成するものです。 createServerSocketは、指定されたポート上にサーバー・ソケットを作成するものです。

setFailureHandlerメソッドは、サーバー・ソケットの作成に失敗すると失敗用ハンドラをRMIランタイムにより呼び出されるように設定します。 失敗用ハンドラはブール値を返して、リトライを行なってよいかどうかを示します。 デフォルトの失敗用ハンドラはfalseを返し、デフォルト条件ではランタイムはソケット作成のリトライを行わないことを示します。

getFailureHandlerメソッドは、ソケット作成失敗の現在のハンドラを返し、失敗用ハンドラが設定されていなければ、nullを返します。

5.8.2 RMIServerSocketFactoryインタフェース

RMIServerSocketFactory APIドキュメントを参照してください。

5.8.3 RMIClientSocketFactoryインタフェース

RMIClientSocketFactory APIドキュメントを参照してください。

5.9 RMIFailureHandlerインタフェース

java.rmi.server.RMIFailureHandlerインタフェースは、サーバー・ソケットの作成に失敗した場合(オブジェクトのエクスポートの実行中を除く)に、RMIランタイムがどのように対応すればよいかを指定する手段を提供します。

package java.rmi.server;

public interface RMIFailureHandler {

        public boolean failure(Exception ex);
}

failureメソッドは、RMIランタイムがjava.net.ServerSocketの作成に失敗した時の例外を引数として呼び出されます。 ランタイムがリトライするべき場合にメソッドはtrueを返し、そうでない場合にはfalseを返します。

このメソッドが呼び出される前に、失敗用ハンドラがRMISocketFactory.setFailureHandlerの呼出しによって登録されていなければなりません。 失敗用ハンドラが設定されていなければ、RMIランタイムはしばらく待ったあとに、ServerSocketを再度作成しようとします。

オブジェクトの最初のエクスポート時にServerSocketの作成に失敗した場合は、RMIFailureHandlerは呼び出されません。 作成の失敗がServerSocket上で受け入れられたあとで、ServerSocketを作成しようとすると、RMIFailureHandlerが呼び出されます。

5.10 LogStreamクラス

LogStream APIドキュメントを参照してください。

5.11 スタブとスケルトン・コンパイラ

スタブおよびスケルトン・コンパイラrmicは、特定のリモート・オブジェクト実装のためのスタブとスケルトンをコンパイルします。

rmicの詳細については、次のURLを参照してください。

    https://docs.oracle.com/javase/8/docs/technotes/tools/unix/rmic.html
    https://docs.oracle.com/javase/8/docs/technotes/tools/windows/rmic.html