7 リモート・オブジェクト起動


7.1 概要

非推奨通知: RMIアクティブ化メカニズムは非推奨になり、将来のバージョンのプラットフォームから削除される可能性があります。 詳細は、JEP 385を参照してください。

分散オブジェクト・システムは、存続期間の長い永続オブジェクトをサポートするように設計されています。 たとえば、きわめて多数の永続オブジェクト(たとえば数百万個)で構成される分散オブジェクト・システムがあるとします。このシステムで、オブジェクトの実装が起動された後、ずっと起動された状態のままにするのは、貴重なシステム・リソースを無期限に占有し続けることになり、合理的ではありません。 また、一般に分散オブジェクトへの参照は、そのオブジェクトが起動されている間のみ有効であるため、システム・クラッシュ後にオブジェクト間の通信を確立しなおすことができるように、クライアント側ではオブジェクトへの永続性のある参照を保持しておく機能が必要になります。

オブジェクト起動は、オブジェクトへの永続性のある参照を提供するとともに、オブジェクトの実装の実行を管理するためのメカニズムです。 RMIでは、起動により必要に応じてオブジェクトの実行を開始できるようになっています。 メソッド呼出しにより、起動可能なリモート・オブジェクトへのアクセスがあったとき、そのリモート・オブジェクトが現在実行中でない場合は、適切なJVM内でそのオブジェクトの実行が開始されます。

7.1.1 用語

アクティブなオブジェクトとは、任意のシステム内の任意のJVM上でインスタンスが生成され、エクスポートされたリモート・オブジェクトを指します。 パッシブなオブジェクトとは、JVM上でまだインスタンスの生成(またはエクスポート)は行われていないが、アクティブな状態に移行可能なリモート・オブジェクトを指します。 パッシブなオブジェクトをアクティブなオブジェクトにすることを、起動といいます。 起動を行うためには、オブジェクトをJVMに関連付ける、つまり、そのオブジェクトのクラスをJVMにロードし、その永続状態を復元するオブジェクトを必要とします。

RMIシステムでは、遅延起動が使用されています。 遅延起動では、メソッドを呼び出すなど、クライアントがオブジェクトを最初に使用するまで、オブジェクトの起動が保留されます。

7.1.2遅延起動

リモート・オブジェクトの遅延起動は、フォルト・リモート参照 (フォルト・ブロックとも呼ばれる)により実現されています。 リモート・オブジェクトへのフォルト・リモート参照は、そのリモート・オブジェクトに対してメソッド呼出しが最初に行われたとき、アクティブなオブジェクトの参照で「障害を発生」させます。 それぞれのフォルト参照は、対象となるリモート・オブジェクトの永続ハンドル(起動識別子)と一時リモート参照の両方を保持しています。 リモート・オブジェクトの起動識別子には、該当するオブジェクトの起動時に第三者とやりとりするのに十分な情報が含まれています。 一時参照は、動作中のオブジェクトへのアクセスに使用できる、アクティブなリモート・オブジェクトへの実際の「ライブ」参照です。

フォルト参照では、リモート・オブジェクトへのライブ参照がnullの場合、そのオブジェクトはアクティブではないものと見なされます。 メソッドの呼出しが発生すると、該当するオブジェクトのフォルト参照は、起動プロトコルを使用して、新たに起動されたオブジェクトのリモート参照(ユニキャスト・リモート参照など)である「ライブ」参照を取得します。 フォルト参照は、ライブ参照を取得すると、メソッド呼出しを背後のリモート参照に転送し、リモート参照は、今度はそれをリモート・オブジェクトに転送します。

より具体的に言えば、リモート・オブジェクトのスタブには、次の2つを含む「faulting」リモート参照型が含まれます。

ノート: RMIシステムは、リモート呼び出しのために"最大で1回"セマンティクスを保持します。 言い換えれば、起動可能またはユニキャストなリモート・オブジェクトの呼出しは、最大で1回までしか送られないということです。 したがって、リモート・オブジェクトの呼出しが失敗した場合(RemoteExceptionがスローされた場合)、クライアントは、そのリモート・メソッドが最大で1回しか実行されていない(通常は1回も実行されていない)ということを判断できます。

7.2 起動プロトコル

リモート・メソッドの呼出し時に、対象となるオブジェクトの「ライブ」参照がわからない場合、フォルト参照は起動プロトコルを利用します。 起動プロトコルは、いくつかのエンティティとかかわります。これらのエンティティは、フォルト参照、アクティベータ起動グループおよび起動されているリモート・オブジェクトです。

アクティベータ(通常、ホストごとに1つ)は、起動を管理するエンティティで、次の2つの役割を持ちます。

アクティベータは、現在の起動識別子とアクティブなオブジェクトとのマッピング情報をキャッシュとして保持しているので、起動要求のたびに起動グループに問い合わせをする必要はありません。

JVMごとに1つだけ存在する起動グループは、JVM内のオブジェクトの起動要求を受け取り、起動されたオブジェクトをアクティベータに返すエンティティです。

起動プロトコルは、次のような働きをします。 まず、フォルト参照は起動識別子を使用してアクティベータ(内部RMIインタフェース)を呼び出し、起動識別子に関連付けられたオブジェクトを起動します。 次に、アクティベータはオブジェクトの起動記述子 (前に登録したもの)を参照します。 オブジェクトの記述子には、次の情報が含まれます。

該当するオブジェクトが属すべき起動グループが存在する場合は、アクティベータは起動要求をそのグループに転送します。 そのような起動グループが存在しない場合は、JVMに起動グループを起動させ、その起動グループに起動要求を転送します。

起動グループは、該当するオブジェクトのクラスをロードし、いくつかの引数(前に登録した起動記述子など)をとる特別なコンストラクタを使ってオブジェクトのインスタンスを生成します。

オブジェクトの起動が完了すると、起動グループは整列化されたオブジェクトの参照をアクティベータに返し、それを受け取ったアクティベータは、起動識別子とアクティブな参照のペアを記録して、アクティブな(ライブ)参照をフォルト参照に返します。 次に、フォルト参照(スタブ内)は、リモート・オブジェクトへの直接のライブ参照を介してメソッド呼出しを転送します。

ノート: Java 2 SDK、Standard Edition、v 1.2では、RMIはシステム・インタフェースの実装を提供します。 起動を使用するには、事前に起動システム・デーモンrmidを動作させておく必要があります。

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がスローされます。 オブジェクト識別子がアクティベータに認識されない識別子である場合、メソッドは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クラスを拡張しているかどうかに依存しません。 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メソッドは、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リモート・オブジェクトの作成

オブジェクトを起動できるようにするには、「起動可能」オブジェクトの実装クラス(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ランタイムにエクスポート処理します。したがって、Activatableクラスを拡張しているオブジェクトの実装では、適切なスーパー・クラスのコンストラクタを呼び出す場合を除いて、オブジェクトを明示的にエクスポートする必要はありません。 Activatableクラスを拡張していないオブジェクトの実装では、staticメソッドActivatable.exportObjectのいずれかを呼び出してオブジェクトを明示的にエクスポートする必要があります。

次の例では、ServerImplActivatableではなく別のクラスを拡張しています。したがって、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を実装したオブジェクトを取るメソッドにパラメータとして渡すことができます。

7.4 起動インタフェース

RMI起動プロトコルでは、システムの正常な動作のため、アクティベータに関して守るべき次の2つの約束事があります。

アクティベータは、起動処理に関与するグループとオブジェクトに対する適切な情報のデータベースを保持します。

7.4.1 Activatorインタフェース

アクティベータは、起動プロセス中に関与するエンティティの1つです。 前述したように、フォルト参照(スタブ内)は、起動可能リモート・オブジェクトへの「ライブ」参照を取得するため、アクティベータのactivateメソッドを呼び出します。 アクティベータは、起動要求を受け取ると、指定された起動識別子idに対応する起動記述子を探し、そのオブジェクトを起動すべきグループを特定して、その起動グループのインスタンシエータのnewInstanceメソッドを呼び出します(リモート・インタフェースActivationGroupについては後述)。 必要であれば、アクティベータは起動グループの実行を開始します。 たとえば、特定のグループ記述子に対応する起動グループがまだ実行されていない場合、アクティベータはその起動グループの子JVMを生成し、生成したJVM内で起動グループを立ち上げます。

アクティベータは、起動グループのエラーを監視、検出し、エラーの際は、その内部テーブルから古いリモート参照を削除します。

package java.rmi.activation;
public interface Activator extends java.rmi.Remote
{
        java.rmi.MarshalledObject activate(ActivationID id,
                                           boolean force)
                throws UnknownObjectException, ActivationException,
                       java.rmi.RemoteException;
}

activateメソッドは、起動識別子idに関連付けられたオブジェクトを起動します。 そのオブジェクトがすでにアクティブな状態にあることをアクティベータが知っており、なおかつforceパラメータがfalseの場合は、スタブが「ライブ」参照とともにただちに呼出し側に返されます。一方、対応するリモート・オブジェクトがアクティブな状態にあることをアクティベータが知らないか、forceパラメータがtrueの場合は、アクティベータは起動記述子情報(前にidを取得するため登録したもの)を使用して、オブジェクトを起動する必要があるグループ(JVM)を特定します。 特定したオブジェクトのグループに対応するActivationInstantiatorがすでに存在する場合、アクティベータは起動インスタンシエータのnewInstanceメソッドを呼び出し、オブジェクトのidと起動記述子を引数として渡します。

特定したオブジェクトのグループ記述子に対応する起動インスタンシエータまたはグループがまだ存在しない場合は、アクティベータは、子プロセスを生成するなどの方法によりActivationInstantiatorの実行の新規生成を開始させます。 アクティベータは、特定のグループのActivationInstantiatorを再作成するときは、そのグループの生成番号をインクリメントしなければなりません。 生成番号はゼロから始まります。 起動システムは、生成番号により、新しいActivationSystem.activeGroupおよびActivationMonitor.inactiveGroupの呼出しを検出します。 同じグループで、現在の生成番号よりも若い生成番号を持つ呼出しは破棄されます。

ノート: ベータは、新しいグループを起動するときに、グループ識別子、記述子、およびインカネーション番号の両方を通知する必要があります。 アクティベータは、独立したJVM内で(たとえば、別のプロセスや子プロセスとして)起動グループを生成します。したがって、アクティベータは、ActivationGroup.createGroupメソッドで起動グループを作成するのに必要な情報を引き渡す必要があります。 この情報を生成されたプロセスにどのように引き渡すかについては規定されていませんが、整列化されたオブジェクトの形式で子プロセスの標準入力に送ることが可能です。

アクティベータは、ActivationSystem.activeGroupメソッドにより起動グループの参照と生成番号が含まれる起動グループのコールバックを受け取ると、その起動インスタンシエータのnewInstanceメソッドを呼び出して、保留状態になっている起動要求を起動インスタンシエータに転送し、結果(整列化されたリモート・オブジェクトの参照、つまりスタブ)をそれぞれの呼出し側に返すことができます。

アクティベータは、RemoteオブジェクトではなくMarshalledObjectを受け取ることによって、オブジェクトのコードのロードやオブジェクトの分散ガベージ・コレクションへの関与の必要性をなくしています。 リモート・オブジェクトへの強い参照を保持していれば、通常の分散ガベージ・コレクション・メカニズムの下では、アクティベータはリモート・オブジェクトがガベージ・コレクトされるのを防ぐことができます。

起動が失敗した場合、activateメソッドはActivationExceptionをスローします。 起動が失敗する原因としては、クラスが見つからない、起動グループにアクセスできないなど、様々な要因があります。指定された起動識別子idに対応する起動記述子がこのアクティベータに登録されていない場合、activateUnknownObjectExceptionをスローします。 アクティベータへのリモート呼出しが失敗した場合は、RemoteExceptionがスローされます。

7.4.2 ActivationSystemインタフェース

ActivationSystemは、グループ、およびその中にある起動可能なオブジェクトのうちで起動しておくものを登録する方法を提供します。 ActivationSystemは、ActivationSystemで登録されたオブジェクトを起動するActivatorと、アクティブなオブジェクトや、アクティブでないオブジェクト、またはアクティブでないグループに関する情報を取得するActivationMonitorの双方と密接に関連しながら動作します。

package java.rmi.activation;
public interface ActivationSystem extends java.rmi.Remote
{
        public static final int SYSTEM_PORT = 1098;

        ActivationGroupID registerGroup(ActivationGroupDesc desc)
                throws ActivationException, java.rmi.RemoteException;

        ActivationMonitor activeGroup(ActivationGroupID id,
                                      ActivationInstantiator group,
                                      long incarnation)
                throws UnknownGroupException, ActivationException,
                       java.rmi.RemoteException;

        void unregisterGroup(ActivationGroupID id)
                throws ActivationException, UnknownGroupException,
                       java.rmi.RemoteException;

        ActivationID registerObject(ActivationDesc desc)
                throws ActivationException, UnknownGroupException,
                       java.rmi.RemoteException;

        void unregisterObject(ActivationID id)
                throws ActivationException, UnknownObjectException,
                       java.rmi.RemoteException;

        void shutdown() throws java.rmi.RemoteException;
}

ノート: セキュリティ対策として、上記のすべてのメソッド(registerGroupactiveGroupunregisterGroupregisterObjectunregisterObject、およびshutdown)は、起動システムと同じホストに存在しないクライアントから呼び出された場合、java.rmi.RemoteException,のサブクラスjava.rmi.AccessExceptionをスローします。

registerObjectメソッドは、起動記述子descの登録と、起動可能リモート・オブジェクトの起動識別子の取得に使用します。 ActivationSystemは、起動記述子descで指定されたオブジェクトのActivationID (起動識別子)を作成し、後の使用に備えて起動記述子と、それに関連付けられた識別子を安定ストレージに記録します。 Activatorは、特定の識別子を対象としたactivate要求を受け取ると、指定された識別子に対応する起動記述子(前に登録したもの)を探し、その情報を使用してオブジェクトを起動します。 descで参照されているグループがこのシステムに登録されていない場合は、メソッドはUnknownGroupExceptionをスローします。 データベースの更新の失敗などが原因で登録が失敗した場合は、ActivationExceptionをスローします。 リモート呼出しが失敗した場合は、RemoteExceptionをスローします。

unregisterObjectは、起動識別子idと、それに関連付けられ、ActivationSystemに登録されている記述子を削除します。 呼出し完了後は、オブジェクトはその起動idでは起動できなくなります。 指定されたオブジェクトidが起動システムに認識されない(登録されていない)識別子である場合は、メソッドはUnknownObjectExceptionをスローします。 データベース更新の失敗などが原因で登録解除処理が失敗した場合は、ActivationExceptionをスローします。 リモート呼出しが失敗した場合は、RemoteExceptionをスローします。

registerGroupメソッドは、グループ記述子descで指定された起動グループを起動システムに登録し、そのグループに割り当てられたActivationGroupIDを返します。 オブジェクトを起動グループに登録する前に、その起動グループをActivationSystemに登録しておく必要があります。 グループの登録が失敗した場合は、このメソッドはActivationExceptionをスローします。 リモート呼出しが失敗した場合は、RemoteExceptionをスローします。

activeGroupメソッドは、ActivationGroupからのコールバック(識別子idを伴う)であり、groupが現在アクティブな状態にあり、そのJVMのActivationInstantiatorになっていることを起動システムに知らせます。 このメソッドは、そのグループ内のグループまたはオブジェクトがアクティブでなくなったなど、オブジェクトとグループのステータスの変化をシステムに伝えるためにグループが使用するActivationMonitorを取得するため、ActivationGroup.createGroupメソッドにより内部的に呼び出されます。 指定されたグループが登録されていない場合は、メソッドはUnknownGroupExceptionをスローします。 指定されたグループがすでにアクティブな状態にある場合は、ActivationExceptionをスローします。 起動システムのリモート呼出しが失敗した場合は、RemoteExceptionをスローします。

unregisterGroupメソッドは、指定された識別子id持つ起動グループを起動システムから削除します。 起動グループは、自分自身を破棄すべきであることをアクティベータに伝えるため、このコールバックを行います。 この呼出しが成功した場合は、そのグループにオブジェクトを登録したり、そのグループ内でオブジェクトを起動したりすることはできなくなります。 そのグループに関する情報と、そのグループに関連付けられたオブジェクトはすべてシステムから削除されます。 指定されたグループが登録されていない場合は、このメソッドはUnknownGroupExceptionをスローします。 リモート呼出しが失敗した場合は、RemoteExceptionをスローします。 データベースの更新の失敗などが原因で登録解除に失敗した場合は、ActivationExceptionをスローします。

shutdownメソッドは、起動システムおよび関連するすべての起動プロセス(アクティベータ、モニター、グループ)を正常に(非同期に)終了させます。 起動デーモンにより生成されたすべてのグループは破棄され、起動デーモンは終了します。 起動システム・デーモンrmidをシャットダウンするためには、次のコマンドを実行します。

rmid -stop [-port num]

このコマンドにより、指定されたポートで起動デーモンがシャットダウンされます。ポートを指定しない場合、デフォルト・ポート上のデーモンがシャットダウンされます。

7.4.3 ActivationMonitorクラス

ActivationMonitorActivationGroupに固有のクラスで、ActivationSystem.activeGroupの呼び出し(ActivationGroup.createGroupメソッドにより内部的に呼び出される)によりグループの報告が行われたときに取得されます。 次の場合には、起動グループは、ActivationMonitorに報告する必要があります。

  1. そのオブジェクトがアクティブになり、
  2. オブジェクトが非アクティブになる、または
  3. グループ全体が非アクティブになります。
package java.rmi.activation;
public interface ActivationMonitor
        extends java.rmi.Remote
{

        public abstract void inactiveObject(ActivationID id)
                throws UnknownObjectException, RemoteException;

        public void activeObject(ActivationID id,
                                 java.rmi.MarshalledObject mobj)
                throws UnknownObjectException, java.rmi.RemoteException;

        public void inactiveGroup(ActivationGroupID id,
                                  long incarnation)
                throws UnknownGroupException, java.rmi.RemoteException;
}

起動グループは、グループ内のオブジェクトが停止したときに、グループのモニターのinactiveObjectメソッドを呼び出します。 起動グループは、起動グループのinactiveObjectメソッドの呼出しにより、そのJVM内のオブジェクト(グループがその起動にかかわったオブジェクト)がアクティブでなくなったことを検出します。

inactiveObject呼出しは、起動識別子idを持つオブジェクトを指すリモート・オブジェクト参照が有効でなくなったことをActivationMonitorに知らせます。 モニターはidに関連した参照を無効な参照と見なします。 参照が無効と見なされるので、以後同じ起動識別子へのactivateの呼出しでは、リモート・オブジェクトがふたたび起動されます。 指定されたオブジェクトがActivationMonitorに認識されないオブジェクトである場合は、メソッドはUnknownObjectExceptionをスローします。 リモート呼出しが失敗した場合は、RemoteExceptionをスローします。

activeObjectは、idに関連付けられたオブジェクトが現在アクティブな状態にあることをActivationMonitorに知らせます。 パラメータobjには、オブジェクトの整列化された形式のスタブを指定します。 ActivationGroupは、グループ内のオブジェクトがシステムにより直接起動される以外の方法でアクティブになった場合(オブジェクトが自分自身で登録して「起動した」場合など)は、それをモニターに知らせなければなりません。 指定されたオブジェクトidが登録されていない場合は、メソッドはUnknownObjectExceptionをスローします。 リモート呼出しが失敗した場合は、RemoteExceptionをスローします。

inactiveGroupは、idincarnationで指定されたグループが現在アクティブでないことをモニターに知らせます。 グループ内のオブジェクトを起動する要求がそれ以降発生すると、グループはより大きな生成番号で再作成されます。 グループは、その中にあるすべてのオブジェクトが停止していると報告されると停止します。 指定されたグループidが登録されていないか、指定された生成番号がグループの現在の生成番号よりも小さい場合は、メソッドはUnknownGroupExceptionをスローします。 リモート呼出しが失敗した場合は、RemoteExceptionをスローします。

7.4.4 ActivationInstantiatorクラス

ActivationInstantiatorは、起動可能オブジェクトのインスタンスを生成する役割を持ちます。 ActivationGroupの具象サブクラスでは、グループ内でのオブジェクトの作成を処理するためnewInstanceを実装しています。

package java.rmi.activation;
public interface ActivationInstantiator
        extends java.rmi.Remote
{
        public MarshalledObject newInstance(ActivationID id,
                                            ActivationDesc desc)
                throws ActivationException, java.rmi.RemoteException;

}

アクティベータは、起動識別子idと起動記述子descを持つオブジェクトをグループ内に再作成するため、インスタンシエータのnewInstanceメソッドを呼び出します。 インスタンシエータは、次の処理を行います。

また、インスタンシエータは、適切なinactiveObjectを呼び出せるように、作成または起動したオブジェクトがアクティブでなくなったことをそのActivationMonitorに報告する役割も持ちます(詳細はActivationGroupクラスを参照)。

オブジェクトの起動が失敗した場合は、newInstanceメソッドはActivationExceptionをスローします。 リモート呼出しが失敗した場合は、RemoteExceptionをスローします。

7.4.5 ActivationGroupDescクラス

起動グループ記述子(ActivationGroupDesc)には、同じJVM内でオブジェクトを起動する起動グループを作成または再作成するのに必要な情報が含まれます。

次の情報が格納されています。

グループのクラスは必ずActivationGroupの具象サブクラスになります。 ActivationGroupのサブクラスは、次の2つの引数をとる特別なコンストラクタを呼び出すstaticメソッドActivationGroup.createGroupにより作成または再作成されます。

package java.rmi.activation;
public final class ActivationGroupDesc
        implements java.io.Serializable
{

        public ActivationGroupDesc(java.util.Properties props,
                                   CommandEnvironment env);;

        public ActivationGroupDesc(String className,
                                   String codebase,
                                   java.rmi.MarshalledObject data,
                                   java.util.Properties props,
                                   CommandEnvironment env);

        public String getClassName();

        public String getLocation();

        public java.rmi.MarshalledObject getData();

        public CommandEnvironment getCommandEnvironment();

        public java.util.Properties getPropertiesOverrides();

}

1つ目のコンストラクタは、グループの実装とコード位置としてシステムのデフォルト値を使用するグループ記述子を作成します。 プロパティは、Javaアプリケーション環境のオーバーライドを指定します(グループ実装のJVM内のシステム・プロパティをオーバーライドします)。 コマンド環境では、子JVMの起動に使用される正確なコマンドやオプションを制御するか、またはnullを設定してrmidのデフォルトを受け入れることが可能です。 このコンストラクタはnullグループのクラス名を使ってActivationGroupDescを作成します。これはシステムのデフォルトであるActivationGroup実装を示すものです。

2番目のコンストラクタは最初と同じですが、PropertiesおよびCommandEnvironmentを指定できるようになっています。

getClassNameメソッドは、グループのクラス名(nullの場合が多い)を返します。 nullグループのクラス名は、システムのデフォルトであるActivationGroup実装を示します。

getLocationメソッドは、グループのクラスのロード元となるコードベース・パスを返します。

getDataメソッドは、整列化された形式のグループの初期化データを返します。

getCommandEnvironmentメソッドは、コマンド環境(nullの場合が多い)を返します。

getPropertiesOverridesメソッドは、この記述子のプロパティ・オーバーライド(nullの場合が多い)を返します。

7.4.6 ActivationGroupDesc.CommandEnvironmentクラス

CommandEnvironmentクラスを使用すると、デフォルトのシステム・プロパティのオーバーライド、および実装で定義されたActivationGroupのオプション指定が可能になります。

public static class CommandEnvironment
        implements java.io.Serializable
{
        public CommandEnvironment(String cmdpath, String[] args);
        public boolean equals(java.lang.Object);
        public String[] getCommandOptions();
        public String getCommandPath();
        public int hashCode();

}

コンストラクタは、指定されたコマンド、cmdpath、および追加コマンド行オプションargsを使ってCommandEnvironmentを作成します。

equalsは、コマンド環境オブジェクトに等しい内容を実装します。 必要に応じてCommandEnvironmentがハッシュ・テーブルに格納されるように、hashCodeメソッドが適宜に実装されます。

getCommandOptionsメソッドは、環境オブジェクトのコマンド行オプションを返します。

getCommandPathメソッドは、環境オブジェクトのコマンド文字列を返します。

7.4.7 ActivationGroupIDクラス

登録された起動グループの識別子は、次のような役割を持ちます。

ActivationGroupIDは、ActivationSystem.registerGroupを呼び出すことで取得でき、起動システム内でのグループの識別に使用されます。 このグループ識別子は、起動グループの作成または再作成時に、起動グループの特別なコンストラクタに引数として引き渡すことができます。

package java.rmi.activation;
public class ActivationGroupID implements java.io.Serializable
{
        public ActivationGroupID(ActivationSystem system);

        public ActivationSystem getSystem();

        public boolean equals(Object obj);

        public int hashCode();
}

ActivationGroupIDのコンストラクタは、ActivationSystemがsystemで指定された一意のグループ識別子を作成します。

getSystemメソッドは、グループの起動システムを返します。

hashCodeメソッドは、グループの識別子のハッシュ・コードを返します。 同じリモート・グループを参照する2つのグループ識別子は、同じハッシュ・コードを持ちます。

equalsメソッドは、2つのグループ識別子を比較して、内容が等しいかどうかを調べます。 このメソッドは、1)一意の識別子が内容的に同一であり、なおかつ、2)それぞれの識別子で指定された起動システムが同一のリモート・オブジェクトを参照している場合は、trueを返します。

7.4.8 ActivationGroupクラス

ActivationGroupは、そのグループ内に起動可能オブジェクトの新しいインスタンスを生成し、次の場合にActivationMonitorに通知します。

  1. そのオブジェクトがアクティブになり、
  2. オブジェクトが非アクティブになる、または
  3. グループ全体が非アクティブになります。

ActivationGroup最初、次のどれかの方法で作成します。

ActivationGroup再作成できるのはアクティベータだけです。 アクティベータは、登録されている起動グループごとに、必要に応じて独立したJVM (たとえば、子プロセスとして)を生成し、起動要求を適切なグループに転送します。 JVMをどのように生成するかは、実装に任せられます。 起動グループは、staticメソッドActivationGroup.createGroupにより作成します。 createGroupメソッドには、作成するグループに関して、1)グループはActivationGroupの具象サブクラスでなければならない、2)グループは次の2つの引数をとるコンストラクタを持っていなければならない、という決まりがあります。

作成時、ActivationGroupのデフォルトの実装では、システム・プロパティはActivationGroupDescが作成されたときのシステム・プロパティ値に設定され、セキュリティ・マネージャはjava.rmi.RMISecurityManagerに設定されます。 グループ内でオブジェクトが起動されるときに、いくつかのプロパティについては独自の値を設定する場合は、任意のActivationDescが作成される前、つまり、デフォルトのActivationGroupDescが作成される前に設定するようにすべきです。

package java.rmi.activation;
public abstract class ActivationGroup
        extends UnicastRemoteObject
        implements ActivationInstantiator
{
        protected ActivationGroup(ActivationGroupID groupID)
                throws java.rmi.RemoteException;

        public abstract MarshalledObject newInstance(ActivationID id,
                                                     ActivationDesc desc)
                throws ActivationException, java.rmi.RemoteException;

        public abstract boolean inactiveObject(ActivationID id)
                throws ActivationException, UnknownObjectException,
                       java.rmi.RemoteException;

        public static ActivationGroup createGroup(ActivationGroupID id,
                                                  ActivationGroupDesc desc,
                                                  long incarnation)
                throws ActivationException;

        public static ActivationGroupID currentGroupID();

        public static void setSystem(ActivationSystem system)
                throws ActivationException;

        public static ActivationSystem getSystem()
                throws ActivationException;

        protected void activeObject(ActivationID id,
                                    java.rmi.MarshalledObject mobj)
                throws ActivationException, UnknownObjectException,
                       java.rmi.RemoteException;

        protected void inactiveGroup()
                throws UnknownGroupException, java.rmi.RemoteException;

}

アクティベータは、起動記述子descを持つオブジェクトを起動するため、起動グループのnewInstanceメソッドを呼び出します。 起動グループは、次のような役割を持ちます。

指定された記述子に対応するインスタンスを生成できなかった場合は、メソッドはActivationExceptionをスローします。

グループのinactiveObjectメソッドは、Activatable.inactiveメソッドの呼出しを介して間接的に呼び出されます。 リモート・オブジェクトの実装では、そのオブジェクトがアクティブでなくなったとき(アクティブでなくなったと見なされるとき)にActivatableinactiveメソッドを呼び出さなければなりません。 オブジェクトが終了時にActivatable.inactiveを呼び出さないと、グループは自身が作成したオブジェクトへの強参照を保持するので、オブジェクトは決してガベージ・コレクトされません。

グループのinactiveObjectメソッドは、リモート・オブジェクトがクライアントからのRMI呼出しに応じられないようにするため、idに関連付けられたリモート・オブジェクトをRMIランタイムからアンエクスポートします(リモート・オブジェクトに対する保留状態の呼び出しや実行中の呼出しがない場合に限る)。 オブジェクトへの保留状態の呼び出しや実行中の呼出しがある場合、inactiveObjectfalseを返し、アクションをとりません。

unexportObjectオペレーションが成功すると(オブジェクトには保留状態または実行中の呼出しがないことを意味する)、グループは、リモート・オブジェクトが現在アクティブでない状態にあり、したがって、それ以降の起動要求時にはアクティベータによって再度起動できることを、そのActivationMonitorに知らせます(モニターのinactiveObjectを使用)。 オペレーションが成功すると、inactiveObjecttrueを返します。 ActivationGroupによりオブジェクトがアクティブであると見なされる場合でも、すでにアンエクスポートされている場合は、このメソッドの呼出しは成功することがあります。

このオブジェクトがアクティブでないとすでに報告されている場合や、この起動グループで一度も起動されたことがないなどの理由から、起動グループがこのオブジェクトを知らない場合は、inactiveObjectメソッドはUnknownObjectExceptionをスローします。 アクティベータまたは起動グループのリモート呼出しが失敗するなどの非起動処理が失敗した場合は、RemoteExceptionをスローします。

createGroupメソッドは、現在のJVM用に起動グループを作成し、設定を行います。 起動グループを設定できるのは、それが現在設定されていない場合だけです。 起動グループがcreateGroupメソッドを使用して設定されるのは、着信するactivate要求を実行するために、Activatorが起動グループの再作成を開始したときです。 グループをこのメソッドで作成する前には、グループ記述子をActivationSystemに登録しておく必要があります(前の登録から得たActivationIDを渡す)。

ActivationGroupDesc (desc)で指定するグループは、ActivationGroupの具象サブクラスでなければならず、そのグループのActivationGroupIDと、そのグループの初期化データが含まれたMarshalledObject (ActivationGroupDescから取得)の2つの引数を取るpublicコンストラクタを持っている必要があります。 ActivationGroupDesc.getClassNameメソッドがnullを返す場合は、システムのデフォルト・グループ実装が使用されます。 ノート: 独自のカスタム起動グループを作成する場合は、グループのコンストラクタでセキュリティ・マネージャを設定する必要があります。コンストラクタ内にセキュリティ・マネージャを設定しないと、グループの中でオブジェクトを起動できません。

グループが作成されたら、グループのActivationMonitorを返すactiveGroupメソッドの呼出しによりグループがアクティブな状態になったことが、ActivationSystemに知らされます。 このコールバックの処理はcreateGroupメソッドが行うので、アプリケーション側で独自にactiveGroupを呼び出す必要はありません。

グループが作成されると、それがアクティブでなくなるまでcurrentGroupIDメソッドによりこのグループの識別子が返されます。グループがアクティブでなくなると、currentGroupIDメソッドはnullを返します。

パラメータincarnationは、グループの現在の生成番号(このグループが起動された回数を表す)を示します。 生成番号は、グループの作成に成功したあと、activeGroupメソッドへのパラメータとして使用されます。 生成番号はゼロから始まります。 指定されたグループがすでに存在する場合、またはグループの作成中にエラーが発生した場合は、createGroupメソッドはActivationExceptionをスローします。

setSystemメソッドは、JVMのActivationSystem (system)を設定します。 起動システムを設定できるのは、アクティブな状態のグループがない場合だけです。 setSystemの明示的な呼出しにより起動システムが設定されなかった場合、getSystemメソッドは、アクティベータのレジストリからjava.rmi.activation.ActivationSystemという名前を探すことでActivationSystemへの参照の取得を試みます。 デフォルトでは、起動システムの検索に使用されるポート番号は、ActivationSystem.SYSTEM_PORTで定義されています。 このポート定義は、プロパティjava.rmi.activation.portを設定することによりオーバーライドできます。 setSystemメソッドを呼び出したときにすでに起動システムが設定されている場合は、メソッドはActivationExceptionをスローします。

getSystemメソッドは、JVMの起動システムを返します。 起動システムはsetSystemメソッドで設定できます(前述)。

activeObjectメソッドは、protectedメソッドで、サブクラスが、グループのモニターへのactiveObjectコールバックを行なって、指定された起動idを持ち、スタブがmobjに含まれるリモート・オブジェクトが現在アクティブな状態にあることをグループのモニターに知らせるために使用します。 この呼出しは、グループのActivationMonitorにすぐに転送されます。

inactiveGroupメソッドは、グループがアクティブでなくなったことをグループのモニターに知らせるため、サブクラスが使用するprotectedメソッドです。 サブクラスは、JVMの中でグループが起動にかかわっているオブジェクトがアクティブでなくなるたびに、このメソッドを呼び出します。

7.4.9 MarshalledObjectクラス

MarshalledObjectはオブジェクトのコンテナであり、RMI呼出しの際にオブジェクトをパラメータとして引き渡せるようにするものですが、受け取った側でのオブジェクトの直列化復元は、コンテナ・オブジェクトの呼出しを介してアプリケーションがそのオブジェクトを明示的に要求するまで延期されます。 MarshalledObjectに含まれるSerializableオブジェクトは、RMI呼出しの際に引き渡されたパラメータと同じセマンティックスで、要求時に直列化および直列化復元されます。これは、MarshalledObject内のすべてのリモート・オブジェクトが、そのスタブの直列化されたインスタンスによって表現されることを意味します。 MarshalledObjectに含まれるオブジェクトは、リモート・オブジェクト、非リモート・オブジェクト、リモート・オブジェクトと非リモート・オブジェクトのグラフ全体のいずれかになります。

オブジェクトがMarshalledObjectラッパーの中に置かれると、直列化されたそのオブジェクトにコード・ベースURL (クラスのロード元)の情報が付加されます。同様に、MarshalledObjectラッパーからオブジェクトが取り出されるときは、そのオブジェクトのコードがローカルになければ、直列化の際に付加されたURLから、そのオブジェクトのクラスのバイト・コードが特定されロードされます。

package java.rmi;
public final class MarshalledObject implements java.io.Serializable
{
        public MarshalledObject(Object obj)
                throws java.io.IOException;

        public Object get()
                throws java.io.IOException, ClassNotFoundException;

        public int hashCode();

        public boolean equals();
}

MarshalledObjectのコンストラクタは、引数として直列化可能なオブジェクトobjをとり、オブジェクトがバイト・ストリームに整列化された形式のものを保持します。 整列化された形式のオブジェクトは、次のように、RMI呼出しの際に引き渡されるオブジェクトのセマンティックスを保持します。

MarshalledObjectクラスのインスタンスがjava.io.ObjectOutputStreamに書き出されるときは、その中に含まれる整列化された形式のオブジェクト(構築時に作成されたもの)がストリームに書き出されます。したがって、バイト・ストリームだけが直列化されます。

MarshalledObjectjava.io.ObjectInputStreamから読み出されるときは、その中に含まれるオブジェクトは具象オブジェクトに直列化復元はされません。整列化されたオブジェクトのgetメソッドが呼び出されるまで、オブジェクトは整列化された形式のままです。

getメソッドは、常に、整列化された形式で含められているオブジェクトの新しいコピーを再構築します。 内部表現は、RMI呼出しの非整列化パラメータに対して使用されるセマンティックスで直列化復元されます。 したがって、オブジェクトの表現を直列化復元すると、直列化されたオブジェクトのストリームに埋め込まれたURL情報を使用してクラス・コードがロードされます(ローカルにない場合)。

整列化された形式のオブジェクトのhashCodeは、コンストラクタに引き渡されたオブジェクトと同じです。 equalsメソッドは、整列化された形式のオブジェクトどうしを比較し、それらが等価であればtrueを返します。 equalsが比較を実行する際、クラスのコード・ベース注釈は無視されます。これは、2つのオブジェクトが同じ直列化表現を保持する場合、それらは等価であることを意味します(直列化表現内の各クラスのコード・ベースを除く)。