目次|| Java Remote Method Invocation


7.3「起動可能」リモート・オブジェクトの実装モデル

起動識別子を介してアクセスできるリモート・オブジェクトを作成するには、次のような準備が必要です。 起動記述子(ActivationDesc)は、次のどれかの方法で登録できます。 起動用にオブジェクトを登録するときは、前述のどれか1つの方法のみを使用してください。複数の方法を使用しないでください。起動可能オブジェクトの実装方法の例については、後述する「起動可能リモート・オブジェクトの構築」のセクションを参照してください。


7.3.1 ActivationDescクラス

ActivationDescには、オブジェクトの起動に必要な情報が含まれます。具体的には、オブジェクトの起動グループ識別子、オブジェクトのクラス名、オブジェクトのコードのロード元のコードベース・パス(URL)、および、起動のたびに使用されるオブジェクト固有の初期化データが含まれるMarshalledObjectが含まれます。

起動システムに登録された記述子は、オブジェクトの再作成または起動に必要な情報を取得するため、起動プロセス中に参照されます。オブジェクトの記述子に含まれるMarshalledObjectは、オブジェクトのリモート・オブジェクトのコンストラクタに2番目の引数として、起動時に使用するために渡されます。

package java.rmi.activation;
public final class ActivationDesc implements java.io.Serializable { public ActivationDesc(String className, String codebase, java.rmi.MarshalledObject data) throws ActivationException; public ActivationDesc(String className, String codebase, java.rmi.MarshalledObject data, boolean restart) throws ActivationException; public ActivationDesc(ActivationGroupID groupID, String className, String codebase, java.rmi.MarshalledObject data, boolean restart); public ActivationDesc(ActivationGroupID groupID, String className, String codebase, java.rmi.MarshalledObject data); public ActivationGroupID getGroupID(); public String getClassName(); public String getLocation(); public java.rmi.MarshalledObject getData() public boolean getRestartMode(); }
ActivationDescの1つ目のコンストラクタは、オブジェクト記述子を構築します。対象となるオブジェクトは、クラスがcodebaseで指定されたコードベース・パスからロードできるclassNameであり、整列化された形式の初期化情報がdataであるオブジェクトです。この形式のコンストラクタが使用される場合、オブジェクトのグループ識別子は、デフォルトでそのJVMのActivationGroupの現在の識別子になります。同じActivationGroupIDを持つオブジェクトは、すべて同じJVM内で起動されます。現在のグループがアクティブでない場合は、ActivationExceptionをスローします。groupIDnullの場合は、IllegalArgumentExceptionがスローされます。

ActivationDescの2つ目のコンストラクタは、1つ目のコンストラクタと同じようにしてオブジェクト記述子を構築しますが、パラメータrestartも指定する必要があります。オブジェクトの再起動サービスを必要とする場合、つまり、アクティベータの再起動時にオブジェクトが自動的に再起動されるようにするには(必要なときに遅延起動するのとは反対)、restarttrueを指定します。restartfalseを指定すると、オブジェクトは必要なときにのみリモート・メソッド呼出しにより起動されます。

ActivationDescの3つ目のコンストラクタは、グループ識別子がgroupIDで、クラス名が、codebaseで指定されたコードベース・パスからロードできるclassName、および初期化情報がdataであるオブジェクトのオブジェクト記述子を構築します。同じgroupIDを持つオブジェクトは、すべて同じJVM内で起動されます。

ActivationDescの4つ目のコンストラクタは、3つ目のコンストラクタと同じようにしてオブジェクト記述子を構築しますが、再起動モードを指定できるようになっています。前述したオブジェクトの再起動サービスが必要な場合は、restarttrueを指定します。

getGroupIDメソッドは、記述子で指定されたオブジェクトのグループ識別子を返します。グループは、複数のオブジェクトを1つのJava仮想マシンにまとめる役割を果たします。

getClassNameメソッドは、起動記述子で指定されたオブジェクトのクラス名を返します。

getLocationメソッドは、オブジェクトのクラスのダウンロード元となるコードベース・パスを返します。

getDataメソッドは、記述子で指定されたオブジェクトの初期化または起動データが含まれる「整列化されたオブジェクト」を返します。

getRestartModeメソッドは、このオブジェクトの再起動モードが有効になっている場合はtrueを返し、無効になっている場合はfalseを返します。


7.3.2 ActivationIDクラス

起動プロトコルでは、起動識別子を使用して、しばらく起動可能なリモート・オブジェクトを表します。起動識別子(ActivationIDクラスのインスタンス)には、オブジェクトを起動するために必要な次のような情報が含まれています。 オブジェクトの起動識別子は、オブジェクトを起動システムに登録することで取得できます。登録は次のような方法で行えます(前述の内容にも留意のこと)。
package java.rmi.activation;
public class ActivationID implements java.io.Serializable { public ActivationID(Activator activator); public Remote activate(boolean force) throws ActivationException, UnknownObjectException, java.rmi.RemoteException; public boolean equals(Object obj); public int hashCode(); }
ActivationIDのコンストラクタは、activatorという引数のみを取ります。この引数には、この起動識別子に関連付けられたオブジェクトを起動するアクティベータへのリモート参照を指定します。ActivationIDのインスタンスは、大域的に一意です。

activateメソッドは、起動識別子に関連付けられたオブジェクトを起動します。forceパラメータにtrueを指定すると、キャッシュされているリモート・オブジェクトの参照は古い参照であると見なされ、オブジェクトの起動時にはグループへの問い合わせが強制的に行われます。forceにfalseを指定すると、キャッシュされた値が使用されます。起動に失敗した場合は、ActivationExceptionがスローされます。オブジェクト識別子がアクティベータに認識されない識別子である場合、activateメソッドはUnknownObjectExceptionをスローします。アクティベータへのリモート呼出しが失敗した場合は、RemoteExceptionがスローされます。

equalsメソッドは、内容が等しいかどうかをチェックするメソッドです。このメソッドは、すべてのフィールドが等価(各フィールドのObject.equalsのセマンティックスに照らし合わせて同一または等価)である場合はtrueを返します。p1p2ActivationIDクラスのインスタンスであるとすると、p1.equals(p2)trueを返す場合は、hashCodeメソッドは同じ値を返します。


7.3.3 Activatableクラス

Activatableクラスは、永続的なアクセスを必要とし、システムから起動できるリモート・オブジェクトをサポートします。Activatableクラスは、起動可能オブジェクトの実装および管理に使用する必要のある中心的なAPIです。なお、オブジェクトの登録や起動を行うためには、事前に起動システム・デーモンrmidを動作させておく必要があります。

package java.rmi.activation;
public abstract class Activatable extends java.rmi.server.RemoteServer { protected Activatable(String codebase, java.rmi.MarshalledObject data, boolean restart, int port) throws ActivationException, java.rmi.RemoteException; protected Activatable(String codebase, java.rmi.MarshalledObject data, boolean restart, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws ActivationException, java.rmi.RemoteException; protected Activatable(ActivationID id, int port) throws java.rmi.RemoteException; protected Activatable(ActivationID id, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws java.rmi.RemoteException; protected ActivationID getID(); public static Remote register(ActivationDesc desc) throws UnknownGroupException, ActivationException, java.rmi.RemoteException; public static boolean inactive(ActivationID id) throws UnknownObjectException, ActivationException, java.rmi.RemoteException; public static void unregister(ActivationID id) throws UnknownObjectException, ActivationException, java.rmi.RemoteException; public static ActivationID exportObject(Remote obj, String codebase, MarshalledObject data, boolean restart, int port) throws ActivationException, java.rmi.RemoteException; public static ActivationID exportObject(Remote obj, String codebase, MarshalledObject data, boolean restart, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws ActivationException, java.rmi.RemoteException; public static Remote exportObject(Remote obj, ActivationID id, int port) throws java.rmi.RemoteException; public static Remote exportObject(Remote obj, ActivationID id, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws java.rmi.RemoteException; public static boolean unexportObject(Remote obj, boolean force) throws java.rmi.NoSuchObjectException; }
起動可能リモート・オブジェクトの実装は、Activatableクラスをextends節で拡張しているかどうかに依存しません。Activatableクラスを拡張するリモート・オブジェクトの実装では、スーパー・クラスjava.rmi.server.RemoteObjectから適切なhashCodeメソッドとequalsメソッドの定義が継承されます。したがって、同一のActivatableリモート・オブジェクトを参照する2つのリモート・オブジェクト参照は等価になります(equalsメソッドがtrueを返す)。また、Activatableクラスのインスタンスは、その適切なスタブ・オブジェクトと等しくなります。たとえば、Object.equalsメソッドを、その引数にオブジェクトの実装に対応するスタブ・オブジェクトを指定して呼び出すと、trueが返されます(逆の場合も同様)。


Activatableクラス・メソッド

Activatableクラスの1つ目のコンストラクタは、オブジェクトの登録と指定されたポート(port)でのオブジェクトのエクスポートに使用します。portにゼロを指定した場合は匿名ポートが選ばれます。codebaseには、オブジェクトのクラス・コードのダウンロード元となるURLパスを指定し、dataにはその初期化データを指定します。restarttrueを指定すると、アクティベータが再起動し、かつグループがクラッシュした場合に、オブジェクトが自動的に再起動されるようになります。restartfalseを指定すると、オブジェクトは必要なときにのみリモート・メソッド呼出しによって起動されるようになります。

このコンストラクタは、オブジェクトを最初の構築時に登録およびエクスポートするため、Activatableクラスの具象サブクラスから呼び出さなければなりません。起動可能オブジェクト構築の副作用として、クライアントからの呼出しに応じられるように、リモート・オブジェクトが起動システムに「登録」されると同時にRMIランタイムに「エクスポート」されます(portにゼロを指定した場合は匿名ポートで)。

このコンストラクタは、起動システムへのオブジェクトの登録が失敗した場合はActivationExceptionをスローします。RMIランタイムへのオブジェクトのエクスポートが失敗した場合はRemoteExceptionをスローします。

2つ目のコンストラクタは、Activatableの最初のコンストラクタと同じですが、この起動可能オブジェクトとのやりとりに使用するクライアント・ソケット・ファクトリとサーバー・ソケット・ファクトリを指定できるようになっています。詳細は、「RMIソケット・ファクトリ」に関するセクションを参照してください。

3つ目のコンストラクタは、オブジェクトの起動と指定されたポートportでのオブジェクトのエクスポート(ActivationID idを使用)に使用します。このコンストラクタは、オブジェクト自身が、次のパラメータをとる特別な「起動」コンストラクタにより起動されるときにActivatableクラスの具象サブクラスから呼び出さなければなりません。

起動可能なオブジェクトを構築すると、指定されたport上のRMIランタイムにリモート・オブジェクトが「エクスポート」され、クライアントからの着信呼出しの受け付けに使用できるようになります。このコンストラクタは、RMIランタイムへのオブジェクトのエクスポートが失敗した場合はRemoteExceptionをスローします。

4つ目のコンストラクタは3つ目のコンストラクタと同じですが、この起動可能オブジェクトとのやりとりに使用するクライアント・ソケット・ファクトリとサーバー・ソケット・ファクトリを指定できるようになっています。

getIDメソッドは、オブジェクトの起動識別子を返します。このメソッドは、サブクラスだけがオブジェクトの識別子を取得できるように保護されています。オブジェクトの識別子は、オブジェクトがアクティブでないことを報告する場合、またはオブジェクトの起動記述子の登録を解除する場合に使用します。

registerメソッドは、起動可能リモート・オブジェクトを必要なときに起動できるように、そのオブジェクト記述子descを起動システムに登録します。このメソッドを使用するのは、起動可能オブジェクトを事前に作成しないで登録するときです。このメソッドは、起動可能オブジェクトのRemoteスタブを返します。これを保存し、後で呼び出すことにより、起動可能オブジェクトが初めて作成および起動されます。descのグループ識別子が起動システムに登録されていない場合、このメソッドはUnknownGroupExceptionをスローします。起動システムが動作していない場合は、ActivationExceptionがスローされます。また、起動システムのリモート呼出しが失敗した場合はRemoteExceptionをスローします。

inactiveメソッドは、指定した起動idを持つオブジェクトが現在アクティブでないことをシステムに知らせるために使用します。現時点でアクティブとされているオブジェクトは、クライアントからの呼出しを受けないようにRMIランタイムからアンエクスポートされます(保留状態の呼出しや実行中の呼出しがない場合のみ)。また、このメソッドを呼び出すと、このJVMのActivationGroupにもオブジェクトがアクティブでないことが知らされ、これを受けて、ActivationGroupは、そのActivationMonitorにオブジェクトがアクティブでないことを知らせます。このメソッドの呼出しが成功した場合、それ以降、アクティベータに対して起動要求があると、オブジェクトは再度起動されます。inactiveメソッドは、オブジェクトのアンエクスポートに成功した場合、つまり、保留状態の呼出しや実行中の呼出しがない場合はtrueを返し、保留状態の呼出しや実行中の呼出しが存在するためにオブジェクトをアンエクスポートできなかった場合はfalseを返します。指定したオブジェクトがアクティベータに認識されないオブジェクトである場合(すでにアクティブでなくなっている可能性がある)、このメソッドはUnknownObjectExceptionをスローします。グループがアクティブでない場合はActivationExceptionをスローします。モニターにオブジェクトがアクティブでないことを知らせるのに失敗した場合はRemoteExceptionをスローします。オブジェクトがアクティブであると見られる場合であっても、すでにアンエクスポートされている場合は、このメソッドの呼出しは成功することがあります。

unregisterメソッドは、idに関連付けられた起動記述子の登録を解除します。オブジェクトはそのidで起動できなくなります。オブジェクトidが起動システムの知らない識別子である場合は、UnknownObjectExceptionがスローされます。起動システムが動作していない場合は、ActivationExceptionがスローされます。起動システムのリモート呼出しが失敗した場合は、RemoteExceptionがスローされます。

1つ目のexportObjectメソッドは、extends節でActivatableクラスを拡張していない「起動可能」オブジェクトから明示的に呼び出すことができます。このメソッドは、次の2つの目的に使用します。

エクスポートされたオブジェクトは、RMI呼出しを受け取ることができるようになります。

このexportObjectメソッドは、起動記述子descを起動システムに登録して取得した起動識別子を返します。起動グループがJVMでアクティブになっていない場合は、ActivationExceptionがスローされます。オブジェクトの登録またはエクスポートが失敗した場合は、RemoteExceptionがスローされます。

objがextends節でActivatableを拡張している場合は、Activatableの1つ目のコンストラクタがこのメソッドを呼び出すため、このメソッドを呼び出す必要はありません。

2つ目のexportObjectメソッドは、1つ目のexportObjectメソッドと同じですが、起動可能オブジェクトとのやりとりに使用するクライアント・ソケット・ファクトリとサーバー・ソケット・ファクトリを指定できるようになっています。

3つ目のexportObjectメソッドは、識別子idを持つ「起動可能」リモート・オブジェクト(必ずしもActivatable型である必要はない)をRMIランタイムにエクスポートし、オブジェクトobjがクライアントからの呼出しに応じられるようにします。portにゼロを指定した場合は、オブジェクトは匿名ポートでエクスポートされます。

起動時に、exportObjectメソッドは、Activatableクラスを拡張しない「起動可能な」オブジェクトから明示的に呼び出される必要があります。Activatableクラスを拡張しているオブジェクトの場合は、このメソッドを直接呼び出す必要はありません。この場合、このメソッドは前述の3つ目のコンストラクタ(サブクラスがその特別な起動コンストラクタから呼び出すコンストラクタ)により呼び出されます。

このexportObjectメソッドは、起動可能オブジェクトのRemoteスタブを返します。オブジェクトのエクスポートに失敗した場合は、このメソッドはRemoteExceptionをスローします。

4つ目のexportObjectメソッドは3つ目のexportObjectメソッドと同じですが、この起動可能オブジェクトとのやりとりに使用するクライアント・ソケット・ファクトリとサーバー・ソケット・ファクトリを指定できるようになっています。

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


起動可能リモート・オブジェクトの構築

オブジェクトを起動できるようにするには、「起動可能」オブジェクトの実装クラス(Activatableクラスを拡張しているかどうかにかかわらず)で、その起動識別子(ActivationID型のもの)と、その起動データjava.rmi.MarshalledObject (登録時に使用した起動識別子で提供したもの)の2つの引数をとる特別なpublicコンストラクタを定義する必要があります。起動グループは、そのJVM内でリモート・オブジェクトを起動するときに、この特別なコンストラクタを使用してリモート・オブジェクトを構築します(詳細は後述)。リモート・オブジェクトの実装では、適切な方法により自分自身を初期化するために、起動データが使用される可能性があります。また、Activatable.inactiveメソッド呼出しによりアクティブでなくなったときに起動グループにそれを知らせることができるように、リモート・オブジェクトで、その起動識別子を保持しておくこともできます。

Activatableの1つ目と2つ目のコンストラクタは、起動可能オブジェクトの登録と、指定されたポート(port)でのオブジェクトのエクスポートの両方に使用されます。このコンストラクタは、オブジェクトを最初に構築するときに使用してください。3つ目のコンストラクタは、オブジェクトを再度起動するときに使用します。

Activatableの具象サブクラスでは、最初の構築時には1つ目または2つ目のコンストラクタ形式を呼び出して、オブジェクトの登録とエクスポートを行う必要があります。このコンストラクタは、まず、オブジェクトのクラス名とオブジェクト用に提供されたcodebaseおよびdataにより起動記述子(ActivationDesc)を作成します。また、その起動グループはJVMのデフォルトのグループになります。次に、コンストラクタはこの記述子をデフォルトのActivationSystemに登録します。最後に、起動可能オブジェクトを特定のポート(port)でRMIランタイムにエクスポートし(portにゼロを指定した場合は匿名ポートが選ばれる)、オブジェクトをactiveObjectとしてローカルなActivationGroupに報告します。登録中かエクスポート中にエラーが発生した場合は、このコンストラクタはRemoteExceptionをスローします。なお、それ以降のprotectedメソッドgetIDの呼出しでオブジェクトの起動識別子が返されるように、このコンストラクタはオブジェクトのActivationID (登録により取得したもの)の初期化も行います。

Activatableの3つ目のコンストラクタ形式は、指定されたポートでのオブジェクトのエクスポートに使用されます。この3つ目のコンストラクタ形式は、オブジェクト自身が次の2つの引数をとるオブジェクト自身の「起動」コンストラクタにより起動されるときにActivatableクラスの具象サブクラスから呼び出さなければなりません。

このコンストラクタは、指定したポート (portにゼロを指定した場合は匿名ポートが選ばれる)で起動可能オブジェクトをRMIランタイムにエクスポートするだけです。オブジェクトはActivationGroupによって起動されており、オブジェクトがアクティブになっていることはすでに知られているため、オブジェクトがアクティブであることをActivationGroupに知らせることはしません。

次のコードは、リモート・オブジェクト・インタフェースServerと、extends節でActivatable拡張したServerImplの実装例です。

package examples;

public interface Server extends java.rmi.Remote {
        public void doImportantStuff() 
                throws java.rmi.RemoteException;
}

public class ServerImpl extends Activatable implements Server
{
        // Constructor for initial construction, registration and export
        public ServerImpl(String codebase, MarshalledObject data) 
                throws ActivationException, java.rmi.RemoteException
        {
                // register object with activation system, then
                // export on anonymous port
                super(codebase, data, false, 0);
        }

        // Constructor for activation and export; this constructor
        // is called by the ActivationInstantiator.newInstance
        // method during activation in order to construct the object.
        public ServerImpl(ActivationID id, MarshalledObject data) 
                throws java.rmi.RemoteException
        {
                // call the superclass's constructor in order to
                // export the object to the RMI runtime.
                super(id, 0);
                // initialize object (using data, for example)
        }

        public void doImportantStuff() { ... }
}
オブジェクトのエクスポートは、オブジェクトそのものが担当します。Activatableのコンストラクタは、UnicastRemoteObject型のライブ参照によりオブジェクトをRMIランタイムにエクスポート処理します。したがって、extends節でActivatableクラスを拡張しているオブジェクトの実装では、適切なスーパー・クラスのコンストラクタを呼び出す場合を除いて、オブジェクトを明示的にエクスポートする必要はありません。extends節でActivatableクラスを拡張していないオブジェクトの実装では、staticメソッドActivatable.exportObjectのいずれかを呼び出してオブジェクトを明示的にエクスポートする必要があります。

次の例では、ServerImplActivatableではなく別のクラスをextends節で拡張しています。したがって、ServerImplは、最初の構築時と起動時に自分自身のエクスポートを担当します。このクラス定義には、ServerImplの初期化コンストラクタと特別な「起動」コンストラクタがあります。それぞれのコンストラクタの中では、オブジェクトをエクスポートするため、所定の呼出しを行っています。

package examples;
public class ServerImpl extends SomeClass implements Server { // constructor for initial creation public ServerImpl(String codebase, MarshalledObject data) throws ActivationException, java.rmi.RemoteException { // register and export the object Activatable.exportObject(this, codebase, data, false, 0); } // constructor for activation public ServerImpl(ActivationID id, MarshalledObject data) throws java.rmi.RemoteException { // export the object Activatable.exportObject(this, id, 0); } public void doImportantStuff() { ... } }


オブジェクトを作成しないで起動記述子を登録する

起動可能リモート・オブジェクトを、先に作成しないで起動システムに登録するには、その起動記述子(ActivationDescクラスのインスタンス)を登録するのみでかまいません。起動記述子には、必要時に起動システムがオブジェクトを起動するのに必要なすべての情報が含まれています。examples.ServerImplクラスのインスタンスの起動記述子は、次のようにして登録できます。なお、例外処理は省略しています。

Server server;
ActivationDesc desc;
String codebase = "http://zaphod/codebase/";

MarshalledObject data = new MarshalledObject("some data");
desc = new ActivationDesc( "examples.ServerImpl", codebase, data);
server = (Server)Activatable.register(desc);

registerの呼出し行では、examples.ServerImplオブジェクトのスタブであり、examples.ServerImplで実装されているのと同じリモート・インタフェースを実装したRemoteスタブが返されます。たとえば、このRemoteスタブではリモート・インタフェースServerが実装されています。キャストされてserverに代入されている、このスタブ・オブジェクトは、リモート・インタフェースexamples.Serverを実装したオブジェクトを取るメソッドにパラメータとして渡すことができます。



目次||
Copyright 1997, 2010, Oracle and/or its affiliates. All rights reserved.