目次 | 前の項目 | 次の項目 | JavaBeans の拡張可能ランタイム包含関係およびサービスプロトコル |
BeanContext の階層構造およびその一般的な機能は、次のように提供されます。
public interface java.beans.beancontext.BeanContext extends java.beans.beancontext.BeanContextChild, java.util.Collection, java.beans.DesignMode, java.beans.Visibility { Object instantiateChild(String beanName) throws IOException, ClassNotFoundException; public InputStream getResourceAsStream(String name, BeanContextChild requestor ); public java.net.URL getResource(String name, BeanContextChild requestor ); void addBeanContextMembershipListener( BeanContextMembershipListener bcml ); void removeBeanContextMembershipListener{ BeanContextMembershipListener bcml ); public static final Object globalHierarchyLock; }
BeanContext のメンバシップ内の変更通知は、次のようにモデル化されます。
public interface BeanContextMembershipListener extends java.util.Listener { void childrenAdded(BeanContextMembershipEvent bcme); void childrenRemoved(BeanContextMembershipEvent bcme); }
イベント関連のすべての BeanContext の基底クラスは、次のように定義されます。
public abstract class BeanContextEvent extends java.util.EventObject { public BeanContext getBeanContext(); public synchronized void setPropagatedFrom(BeanContext bc); public synchronized BeanContext getPropagatedFrom(); public synchronized boolean isPropagated() }
BeanContextMembershipEvent は、次のように定義されます。
public class BeanContextMembershipEvent extends BeanContextEvent { public BeanContextMembershipEvent(BeanContext bc, Object[] deltas); public BeanContextMembershipEvent(BeanContext bc, Collection deltas); public int size(); public boolean contains(Object child); public Object[] toArray(); public Iterator iterator(); }
BeanContext の役割の 1 つに、BeanContext および JavaBean インスタンスの階層的入れ子構造という概念の導入があります。この構造をモデル化するために、BeanContext は、構造または階層内の関係を定義する API を公開する必要があります。BeanContext は、後述するように java.beans.beancontext.BeanContextChild インタフェースを実装することにより、そのスーパーストラクチャを公開します。 このインタフェースを利用すると、BeanContext の入れ子の BeanContext の検出および操作が可能になります。 その結果、BeanContexts の階層作成機能が導入されます。
BeanContext は、java.util.Collection インタフェースセマンティクスによりモデル化された多数のインタフェースメソッドを使って、そのサブストラクチャを公開します。
BeanContexts は、すべての必須 Collection API で、add() および remove() 用の特定のセマンティクスを使用する際に必要とされます。
add() メソッドは、新規オブジェクトである BeanContextChild または BeanContext をターゲットの BeanContext 内で入れ子にするために呼び出されます。 次のセマンティクスに従うためには、仕様に準拠して実装された add() が必要です。
- BeanContext.globalHierarchyLock 上で同期を実行します。
- 各子オブジェクトは、指定された BeanContext の子セット内に 1 度だけ現れます。インスタンスが既に BeanContext のメンバである場合、メソッドは false を返します。
- 有効な子オブジェクトは、それぞれ指定されたソース BeanContext の子セットに追加されます。 その結果、remove()、removeAll()、retainAll()、または clear() が呼び出されて、入れ子になった BeanContext から削除される時まで、子オブジェクトは子セットに表示され、toArray() メソッドまたは iterator() メソッドを使って取得可能になります。
- 子は入れ子にされた子セットに追加され、そこで子は java.beans.beancontext.BeanContextChild インタフェース (または BeanContextProxy、詳細は後述) を実装するため、BeanContext は、その子に対して自らを参照する setBeanContext() メソッドを呼び出します。呼び出されても、子がなんらかの理由で BeanContext 内で動作不可であるかまたは動作の準備ができていない場合、子は PropertyVetoException をスローして入れ子になっている BeanContext を通知します。 子がこの種の例外をスローすると、BeanContext は入れ子になった子セットへの子の追加 (およびこの追加操作の副作用として生じた、BeanContext の他の部分的な状態変更) を取り消して IllegalStateException をスローします。
- java.beans.Visibility インタフェースを実装する JavaBeans は、適切なメソッドである dontUseGui() または okToUseGui() 経由で、GUI を描画する現在の能力を、BeanContext のポリシーで定義されたものとして通知されます。
- 新規に追加された子が BeanContextChild を実装する場合、BeanContext は、その VetoableChangeListener および PropertyChangeListener インタフェースの両方の子に自らを登録して、少なくとも BeanContextChild の「beanContext」プロパティを監視します。
- このようにして、BeanContext はその子を監視し、子がサードパーティ (通常は別の BeanContext) によって削除された場合に setBeanContext() を呼び出して検出できるようになります。 BeanContext は、その時点で子がメンバではないことを判別すると、サードパーティによる変更を拒否することができます。
- 追加された JavaBean が BeanContext をソースとする Listener インタフェースを実装する場合、BeanContext は新たに追加されたオブジェクトを、入れ子による許容可能な副作用として適切なリスナー登録メソッドを使って登録できます。
- 追加された JavaBean が特定の BeanContext が関係するイベントのイベントソースである場合、その BeanContext は、子の追加による副作用として、子に対するリスナーを登録できます。 BeanContext は、直列化可能なリスナーの使用を避ける必要があります。 これは、子が自らを直列化した場合、その必要のない構造を直列化してしまうことを避けるためです。
- targetChild の処理が成功すると、BeanContext は、新規追加された targetChild への参照を含む java.beans.beancontext.BeanContextMembershipEvent を、現在登録されているすべての BeanContextMemebrshipListeners の childrenAdded() メソッドに対してトリガします。
- 成功すると、メソッドは true を返します。
remove() メソッドは、既存の子 JavaBean または BeanContext をターゲットの BeanContext から削除する場合に呼び出されます。 remove() メソッドは、既存の子 JavaBean または次のセマンティクスに従うためには、仕様に準拠して実装された remove() が必要です。
- BeanContext.globalHierarchyLock と同期します。
- 特定の子が、ソースである BeanContext の子セット内に存在しない場合、メソッドは false を返します。
- ソースである BeanContext の子セットから有効な targetChild を削除し、同時に入れ子の副作用として、暗黙のうちに登録された BeanContext 用の他のすべてのリスナーインタフェースから子を削除します。
- 結果として、targetChild が java.beans.beancontext.BeanContextChild インタフェース (または BeanContextProxy、詳細は後述) を実装する場合、BeanContext は setBeanContext() を null1 BeanContext 値で呼び出して、BeanContext 内の入れ子ではなくなった子を通知します。
- 特定の BeanContextChild は、入れ子になった BeanContext から入れ子状態を解除できない場合、PropertyVetoException をスローします。 受け取った BeanContext は、このインスタンスの削除操作を呼び出して、IllegalStateException をスローします。 無限回帰を避けるため、子にはその後の削除通知を繰り返し取り消すことは許可されません。実際、子は、入れ子になった現在の BeanContext からその削除を無効にする条件 (一時的な場合) の解決を試みる必要があります。
- targetChild が java.beans.beancontext.BeanContextChild を実装する場合、BeanContext は、子の PropertyChangeListener および VetoableChangeListener ソースから自らを登録解除します。
- BeanContext が、リスナーとして削除されたオブジェクトを、これらのオブジェクトを入れ子にする際の副作用として BeanContext により実装されたイベントソース上で登録してある場合、BeanContext は、適切なリスナー登録解除メソッドを使って、新たに削除されたオブジェクトを、適用可能なソースから登録解除します。
- BeanContext が削除されたオブジェクトのリスナーを以前に登録してある場合、BeanContext はこれらのリスナーをオブジェクトから削除します。
- targetChild が子セットから削除されると、BeanContext は、削除されたばかりの targetChild への参照を含む java.beans.beancontext.BeanContextMembershipEvent を、現在登録されているすべての BeanContextMembershipListeners の childrenRemoved() メソッドに対してトリガします。
- 操作が成功すると、メソッドは最後に true を返します。
入れ子になった BeanContext のすべての子の寿命は、少なくとも、指定された BeanContext 内での子の包含関係の継続期間になります。 BeanContext 内の包含関係を意識しない単純な JavaBeans の場合、これは、入れ子になった BeanContext の有効期間中は少なくとも JavaBean が存在することを意味します。BeanContext では、java.util.Collection API によって定義された、オプションの addAll()、removeAll()、retainAll()、または clear() メソッドのいずれかを実装する必要性はありませんが、実装する場合には、前述の add() と remove() 用に定義されたセマンティクスをオブジェクトごとに実装する必要があります。 失敗時には、これらのメソッドは部分的に適用されたすべての変更を無効にし、複合操作が呼び出されて失敗する前の状態に BeanContext を戻します。 失敗時には、上記の add() および remove() の定義に合わせて、BeanContextEvents はトリガされません。
BeanContextMembershipListeners の追加および削除は、addBeanContextMembershipListener() および removeBeanContextMembershipListener() の呼び出しを通して実行されます。
toArray() メソッドは、現在の JavaBean セットのコピーまたはターゲットの BeanContext 内で入れ子になった BeanContext のインスタンスを返します。 また、iterator() メソッドは、子の同じセットに java.util.Iterator オブジェクトを提供します。
指定されたオブジェクトが現在 BeanContext の子である場合、contains() メソッドは true を返します。
size() メソッドは、入れ子になった現在の子の数を返します。
isEmpty() メソッドは、BeanContext に子がない場合、true を返します。
すべての Collection メソッドは、マルチスレッド環境で正しく機能するために、指定された実装による適切な同期化を相互に必要とします。 これにより、指定された BeanContext 内で入れ子になった JavaBeans セットのメンバシップへのすべての変更が、不可分で確実に適用されます。すべての実装で、BeanContext.globalHierarchyLock を使ってこれらのメソッドの実装を同期化する必要があります。
ある状況では、add() および remove() (またはその変化形) 操作が入れ子状態で行われる場合があります。 その場合、Thread を同時に呼び出すスタック上で複数の操作が同時に発生します。 次に例を示します。 BeanContextChild の A が追加 (または削除) されると、setBeanContext() メソッドは別の BeanContextChild の B も追加 (または削除) します。 特定の BeanContext 実装は、2 つの BeanContextMembershipListener 通知を発行することがあります。その場合、B の add()/remove() 操作に対して 1 つ発行し、その後 A の操作に対して 1 つ発行する (B が A の前に追加されたためにこの順序になる) か、または A と B の両方を含む 1 つの通知にまとめます。 どのような理由でも A を追加または削除できない場合には、この条件を示す PropertyVetoException をスローする前に、副作用として発生する B に対するすべての追加または削除操作の実行または取り消しは行われません。 つまり、独自のメンバシップの状態に対する変更を拒否する前に、副作用として発生するメンバシップの変更は避けるかまたは取り消す必要があります。
instantiateChild() メソッドは、新たな JavaBean インスタンスを目的の BeanContext の子としてインスタンス生成する際に呼び出すことのできる簡易メソッドです。JavaBean の実装は、beanName の実パラメータの値から導かれ、java.beans.Beans.instantiate() メソッドによって定義されます。
一般に、これは目的の BeanContext の ClassLoader を使用して、適切な java.beans.Beans.instantiate() メソッドを呼び出すことにより実装されます。ただし、特定の BeanContext 実装は、このメソッドの実装内のインスタンス生成操作に対する副作用を引き起こす場合があります。
BeanContextEvent は、BeanContext の定義済みセマンティクスの状態変化に属するすべてのイベントに対する抽象ルート EventObject クラスです。この抽象ルートクラスは、通知元である BeanContexts を定義し、BeanContexts の階層を通じて BeanContextEvent サブクラスの伝播を可能にする機構を導入します。 setPropagatedFrom() および getPropagatedFrom() メソッドを使用すると、BeanContext は伝播されるイベントのソースとして自らを識別するため、イベントは BeanContext に伝播されます。 これは一般的な伝播機構であり、大規模な階層を経由して伝播が行われる場合、パフォーマンス面で重要な影響があるため、注意して使用する必要があります。setPropagatedFrom() および getPropagatedFrom() メソッドを使用すると、BeanContext は伝播されるイベントのソースとして自らを識別するため、イベントは BeanContext に伝播されます。これは一般的な伝播機構であり、大規模な階層を経由して伝播が行われる場合、パフォーマンス面で重要な影響があるため、注意して使用する必要があります。
BeanContextMembershipEvent は、特定の BeanContext インスタンスのメンバシップ内で発生する変更を記述します。このイベントは、特定の BeanContext インスタンスのメンバシップ (すなわち、メンバシップセット内のデルタ) に対して、追加または削除された子のリストをカプセル化します。
特定のインスタンスに対して呼び出された add()、remove()、addAll()、retainAll()、removeAll()、または clear() が成功する場合はいつでも、BeanContextMembershipEvent がトリガされてこの操作による影響を受ける子を記述します。
BeanContext は、getResourceAsStream() および getResource() という 2 つのメソッドを定義します。これらのメソッドは、java.lang.ClassLoader 上のメソッドに類似しています。BeanContext 内で入れ子になった BeanContextChild インスタンスは、入れ子構造の BeanContext に対するメソッドを、ClassLoader のメソッドに優先して呼び出します。 このため、子と基本的な ClassLoader セマンティクス間に動作を割り込ませることにより、BeanContext 実装からセマンティクスを拡張することができます。
BeanContext のサービス機能は、次のようにして提供されます。
public interface BeanContextServices extends BeanContext,BeanContextServicesListener { boolean addService(Class serviceClass, BeanContextServiceProvider service); boolean revokeService(Class serviceClass, BeanContextServiceProvider bcsp, boolean revokeNow ); boolean hasService(Class serviceClass); Object getService(BeanContextChild bcc, Object requestor. Class serviceClass, Object serviceSelector, BeanContextServicesRevokedListener sl ) throws TooManyListenersException; void releaseService(BeanContextChild bcc, Object requestor, Object service); Iterator getCurrentServiceClasses(); public Iterator getCurrentServiceSelectors(Class sc); addBeanContextServicesListener( BeanContextServicesListener bcsl ); removeBeanContextServicesListener( BeanContextServicesListener bcsl ); }
BeanContextServiceProvider インタフェースは、次のように定義されます。
public interface BeanContextServiceProvider { Object getService(BeanContext bc, Object requestor, Class serviceCls, Object serviceSelector); void releaseService(BeanContext bc, Object requestor, Object service); Iterator getCurrentServiceSelectors(BeanContext bc, Class serviceCls); }
BeanContextServiceRevokedListener は、次のように定義されます。
public interface BeanContextServiceRevokedListener extends java.util.EventListener { void serviceRevoked( BeanContextServiceRevokedEvent bcsre ); }
BeanContextServicesListener は、次のように定義されます。
public interface BeanContextServicesListener extends BeanContextServiceRevokedListener { void serviceAvailable( BeanContextServiceAvailableEvent bcsae ); }
BeanContextServiceAvailableEvent は、次のように定義されます。
public class BeanContextServiceAvailableEvent extends BeanContextEvent { public BeanContextServiceAvailableEvent( BeanContextServices bcs, Class sc ); BeanContextServices getSourceAsBeanContextServices(); public Class getServiceClass(); public boolean isServiceClass(Class serviceClass); public Iterator getCurrentServiceSelectors(); }
BeanContextServiceRevokedEvent は、次のように定義されます。
public class BeanContextServiceRevokedEvent extends BeanContextEvent { public BeanContextServiceRevokedEvent( BeanContextServices bcs, Class sc, boolean invalidNow ); public BeanContextServices getSourceAsBeanContextServices(); public Class getServiceClass(); public boolean isServiceClass(Class service); public boolean isCurrentServiceInvalidNow(); }
BeanContextServiceProviderBeanInfo は、次のように定義されます。
public interface BeanContextServicesProviderBeanInfo extends java.beans.BeanInfo { java.beans.BeanInfo[] getServicesBeanInfo(); }
構造化された階層を提供することを除く、BeanContext の主要な役割は、JavaBean コンポーネントがコンテキスト固有の機能またはサービスを環境から取得するための標準的な機構を提供することです。Class オブジェクトにより提供されるサービスは、通常、インタフェース、または public としてのインスタンス生成が不可能な実装への参照です。この Class は、BeanContextServiceProvider、サービスのファクトリ、およびサービスが登録されている BeanContext 内で現在入れ子になっている BeanContextChild と関連付けられた任意のオブジェクト間のインタフェースプロトコルまたは規約を定義します。 一般に、この種のプロトコルは、BeanContextChild の実装を依存関係から孤立させる、コンテキスト固有またはコンテキスト依存の動作をカプセル化します。 このため、実装の単純化、高い相互運用性および移植性が実現します。
BeanContextServiceProvider は、1 つ以上のサービスの「ファクトリ」です。これは、サービスが BeanContextServices に登録されていない場合、adService() メソッドを介して自らを特定の BeanContextServices に登録します。 BeanContextServices は、指定されたサービスを BeanContextServiceProvider に関連付け、serviceAvailable() メソッド経由で BeanContextServiceAvailableEvent を現在登録されている BeanContextServicesListeners にトリガし、その後 true を返します。 それ以外の場合は false を返し、サービスが BeanContextServices に登録されていることを示します。
いったん登録されたサービスは、取り消されるまで、BeanContextServices getService() メソッドを介して利用可能になります。
hasService() メソッドは、特定のサービスが存在するかどうかをテストするために使用可能です。また、getCurrentServices() メソッドは、BeanContextServices で現在利用可能なサービスに対して反復子を返します。
BeanContextChild または BeanContextChild と関連付けられた任意のオブジェクトは、getService() メソッドの呼び出しを介して、入れ子になった BeanContextServices から現在登録されているサービスへの参照を取得できます。getService() メソッドが指定するのは、BeanContextChild、関連付けられた要求者、要求されたサービスの Class、サービスに依存したパラメータ (サービスセレクタとして知られる)、およびその後、 BeanContextServiceProvider により取り消されたサービスクラスを要求者に通知するために使用される BeanContextServicesRevokedListener です。 リスナーは、要求者およびサービスクラスごとに、ユニキャストイベントソースに自動的に登録されます。 また、要求者が指定されたサービスクラスの参照すべてを放棄するか、BeanContextServiceProvider を提供することによりサービスが強制的に取り消された場合にその副作用として、自動的に登録解除されます。
BeanContextServices は、この getService() 呼び出しを、関連する BeanContextServiceProvider (存在する場合) に渡し、その getService() メソッドの呼び出しを介して条件が満たされるようにします。BeanContextServiceProvider は、BeanContext、提供されるサービスのクラス、サービスに依存したサービスパラメータ (サービスセレクタ)、およびサービスを要求するオブジェクトへの参照に渡されます。
BeanContext への参照は、BeanContextServiceProvider に対し、複数のソースからのサービス要求を識別可能にすることを目的としています。BeanContextServiceProvider には、このようにして取得されたすべての BeanContext への弱参照を保持することだけが許可されます。
サービスセレクタのパラメータは、サービスの要求者により特定のサービスで使用される、サービスに依存した値です。 これには、BeanContextServiceProvider により提供されるサービスをパラメータ化する目的があります。その使用例としては、サービス実装クラスのコンストラクタへのパラメータ、特定のサービスプロパティの値、既存の実装マップ内へのキーとしての使用などを挙げることができます。
要求者への参照には、BeanContextServiceProvider に対して要求者の状態調査を許可し、サービスのカスタマイズまたはパラメータ化を行う目的があります。 このため、この参照は、BeanContextServicesProvider により「不変である」と見なされます。また、getService() 呼び出しからの復帰後に、BeanContextServiceProvider は、要求者と BeanContextChild の両方への弱く不変の参照だけを保持する許可が与えられます。
BeanContextServiceProvider は要求に応えて、要求されたサービスの Class インスタンスへの参照を返す (返される参照は、<serviceRefence> instanceof <serviceClass> が true になる) か、null を返すか、または検査されない例外をスローします。
入れ子になった BeanContextServices が、BeanContextServiceProvider を持たない特定のサービスに対して要求される場合、BeanContextServices は、要求されたサービスを、自らの入れ子になった BeanContextServices に委譲して要求を満たします。このようにして、委譲要求は葉である BeanContextServices からルートである BeanContextServices へ伝搬可能になります。
特定のサービスクラスが、ネストした BeanContextServices.getCurrentServiceSelectors() メソッドを介してサービスクラスの演算値の有限リストを実装し、次に BeanContextServiceProvider.getCurrentServiceSelectors() を介して現在利用可能なサービスセレクタ (存在する場合) を取得する場合、BeanContextChild は、特定の BeanContextServices に対して、現在利用可能なサービスクラスおよび割り当てられたすべてのサービスセレクタのリストを (getCurrentServiceClasses() メソッドを介して) 問い合わせます。
問題のサービスは、有効なサービスセレクタセットの有限な演算値セットを実装しない場合、null を返します。
BeanContextChild により getService() を介して取得された参照は、参照が BeanContextChild により、入れ子になった BeanContextServices の releaseService() メソッドの呼び出しを介して解放されるまで有効です。 ただし、BeanContextServices が BeanContextServiceRevokedEvent をトリガし、そのイベントの isCurrentServiceInvalidNow() メソッドが true を返す場合を除きます。この場合、BeanContextServices またはサービスを提供した BeanContextServiceProvider は、現在のサービス参照がただちに無効にされた、つまり「強制的に取り消された」(一般的には以下の状況で発生) と判断します。
BeanContextChild インスタンスが特定の BeanContextServices インスタンスから削除されると、BeanContextChild インスタンスは、適切な releaseService() を呼び出すことにより、BeanContextServices から取得したサービスへの参照をすべて破棄します。 入れ子状態を解除する BeanContextChild も BeanContextServices インスタンスである場合、およびこれらのサービス参照のすべてが、既に定義されたように、委譲された getService() 要求の結果として、入れ子状態を解除する BeanContextServices 自身のメンバに公開されている場合には、BeanContextServiecs は、BeanContextServiceRevokedEvent をトリガして、入れ子になった子に対して「サービスが強制的に取り消された」ことを通知します。入れ子状態の解除時に委譲されたサービスへの現在の参照をただちに無効化することにより、階層構造に依存するサービスの位置が変化した場合に、要求者によってそのサービスが使用されることを防ぐことができます。
サービスクラスの「強制的な取り消し」を受ける BeanContextChild インスタンスは、保持する可能性のあるその種の参照用の releaseService() を呼び出しません。 この場合、BeanContextServiceProvider または BeanContextChild へのサービス参照を提供した BeanContextServices は、そのサービスへの参照をすべて無効にしてしまっているからです。
BeanContextServiceProvider は、revokeService() メソッドを呼び出して BeanContextServices へ登録したあとであれば、いつでもサービスクラスを呼び出すことができます。BeanContextServices が BeanContextServiceRevokedEvent をトリガして、現在登録された BeanContextServiceRevokedListeners および現在サービスを利用できない BeanContextServicesListeners を通知すると、そのサービスクラスが再度登録されるまで、取り消されたサービスに対する新たなサービス要求には対応できなくなります取り消される前に BeanContextChild の要求者により取得されたサービスへの参照は、有効のままになります。 このため、サービスは、そのサービスへのすべての参照が解放されるまで有効のままになり、現存する参照を満たします。 ただし、例外的な状況で、サービスの取り消し時に BeanContextServiceProvider または BeanContextServices が現在の参照すべてへのサービスをただちに終了させる場合を除きます。即時取り消しは、BeanContextServices .revokeService() メソッドを、実パラメータ値 revokeNow == true で呼び出すことにより実行されます。現在のサービス参照の即時無効化の実行後に、サービス実装が、即時取り消し通知を無視してサービスへの参照を誤って保持しているサービスの要求者が呼び出すサービスを引き続き使用しようとする試みに応答して、サービス固有の検査されない例外をスローする場合があります。
(サービス要求の委譲時に) マルチスレッド環境で正しく動作するためには、BeanContextServices の実装は、addService()、hasService()、 getCurrentServiceClasses()、getCurrentServiceSelectors()、getService()、releaseService() の実装を、BeanContext.globalHierarhyLock と同期させる必要があります。
BeanContextServicesProvider は、BeanContextServicesProviderBeanInfo を実装する BeanInfo クラスを提供することにより、実装を提供するサービスクラスに対して BeanInfo を公開します。このようにして、BeanInfo の配列を公開することにより、各サービスクラス用の BeanInfo がサポートされます。たとえば、開発用ツールは、この情報を利用してアプリケーション開発者に対し、アプリケーションに含まれるサービスクラスのパレットを提供できます。
BeanContext の主な役割の 1 つは、JavaBean コンポーネントの論理的な入れ子構造および BeanContext のインスタンス階層の表現です。このため、階層が持続的であるさまざまなシナリオを期待するのは当然のことです。階層が持続的であるとは、つまり、BeanContext が持続性機構、特に java.io.Serializable または java.io.Externalizable のいずれかに参加する場合のことを指します。後者の場合、BeanContext は、子のサブグラフ用の持続性コンテナ、クラス情報の符号化および復号化、および直列化解除後のサブグラフ相当機能の維持など、基本的に ObjectOutputStream および ObjectInputStream による直列化に対応した機能を提供します。特に、BeanContext は、自身が持続性を付与されるか復元された場合、持続性を持ち、かつ適切な持続性インタフェースを実装する現在の子を復元します。
上記の要件の結果として、入れ子になっている BeanContext へのすべての参照、または入れ子になっている BeanContextServices 経由で取得された委譲者すべてへの参照を持続性のないものにするために、持続性を持つ BeanContextChild の実装が求められます。
BeanContexts は、持続状態からのインスタンスを復元する際に、新たにインスタンス生成された BeanContextChild への add() の呼び出しと等価な動作を実行する必要があります。 その結果、ネストした BeanContext の新たに復元されたインスタンスが通知されるため、BeanContextChild はその環境への依存関係を十分に再確立できるようになります。
また、BeanContext は java.beans.beancontext.BeanContextChild を実装するため、このインタフェースの実装を扱う際には、以下に定義された持続性要件に準拠する必要があることにも留意してください。
必須ではありませんが、多くの BeanContext は java.awt.Container および java.awt.Component の表示階層内で関連付けることができます。Container は BeanContext を直接実装することはできません2 が、そこに記述された BeanContextProxy インタフェースを実装することにより BeanContext に関連付けることができます。
public interface BeanContextProxy { BeanContext getBeanContext(); }
BeanContext インタフェースを直接実装しない (そのコンポーネントやサブクラスの場合は、実装できない) クラスのインスタンスが、その実装のインスタンスに関連付けられている場合、(デリゲーションを介して) そのインスタンスは BeanContextProxy インタフェースを実装することにより、この関連付けを公開できます。このようにして、構築ツールなどの任意のサードパーティが、そのオブジェクトと関連付けられた BeanContext の問い合わせおよび検出を行い、関連付けられた BeanContext 内で入れ子になったオブジェクトからメンバシップ変更を検出するか、またはそのサービスを取得することが可能になります。これにより、複数の個別のオブジェクト (コンテナなど) が 1 つの BeanContext を共有することが可能になります。この場合、共有された BeanContext は BeanContextContainerProxy を実装しないことに留意してください。 これは、単一の BeanContext とそのインタフェースを実装するコンテナ間のピアツーピアの関係であるためです。
getBeanContext() から返される値は、実装するインスタンスの有効期間中変化しません。 つまり、BeanContextProxy と関連付けられた BeanContext の関係は静的であるため、どちらかが有効である間は変化しません。
BeanContext (または BeanContextChild) と BeanContextProxy インタフェースの両方を実装するクラスは存在しません。 これらを一緒に使用することはできません。
BeanContextProxy の実装元によっては、Collection に基づく BeanContext を維持することに加え、そして恐らくそれとは別個に、java.util.Collection または他のなんらかのコレクションに似た API (java.awt.Container など) を実装する場合があります。
この場合、Collection API 経由で BeanContext から要素を追加または削除するか、あるいはコレクションに似た API (public boolean java.awt.Container.add(Component) など) を使って BeanContextProxy の実装元から要素を追加または削除することが可能です。 BeanContext のコレクションまたは BeanContextProxy の実装元のコレクションに対して追加または削除されたオブジェクトが、対応するオブジェクトのコレクションに対しても追加または削除されるかどうか (つまり、Container.add() は BeanContext.add() も推測するかどうか、およびその逆) は、実装に依存しています。 そのような状況では、両者 (BeanContextProxy の実装元および BeanContext 自体) が 1) ほかと同じ追加/削除セマンティクスを実装する (つまり、x.add(o) が x.getBeanContext().add(o) の副作用を受ける場合、x.getBeanContext().add(o) も x.add(o) の副作用を受ける)、および 2) ほかの当該コレクションに対して追加/削除操作を実行する前に、そのオブジェクトがほかの当該コレクションのメンバであるかどうか (同期化を) テストする (両者へのコレクション操作で無限再帰が発生するのを避けるため) 必要があります (つまり、x.getBeanContext().contains(o) が true の場合に x.add(o) は x.getBeanContext().add(o) を呼び出さない、およびその逆)。
BeanContextProxy を実装するオブジェクトが BeanContext に対して追加または削除された場合、そのオブジェクトに操作を実行することに加え、同じ操作を BeanContextProxy.getBeanContext() から返された BeanContext に対しても実行する必要があることに留意してください。つまり、BeanContextProxy の実装元は、任意の入れ子になった BeanContext により、直接実装された BeanContext と同じ扱いを受ける必要があります操作が BeanContext に適用される場合は、対応する BeanContextProxy にも適用される必要があります。
次のインタフェースは、BeanContext が、関連付けられたコンテナへの参照を公開して、その BeanContextChild メンバが関連付けられたコンポーネントオブジェクトの追加または削除をコンテナに対して行うこと、またはコンテナの状態を検査することを可能にします。
public interface BeanContextContainerProxy { Container getContainer() }
関連付けられたコンポーネントを持つ BeanContextChild が、関連付けられたコンテナを持つ BeanContext に追加される場合、結果として、コンテナ内のコンポーネントの入れ子に関連して相互作用のモデルが 3 つ存在します。
- 関連付けられたコンポーネントが、関連付けられたコンテナに、コンテナ API 経由で追加される場合、BeanContext 内の BeanContextChild の入れ子状態は、その副作用として生じるものであり、それ以上の操作は必要ありません。
- コンポーネントおよびコンテナが入れ子になっていない場合、入れ子状態の BeanContext は、副作用として、BeanContextChild に関連付けられたコンポーネントを、その関連付けられたコンテナに追加します。
または
- コンポーネントおよびコンテナが入れ子になっていない場合、入れ子状態の BeanContextChild は、副作用として、そのコンポーネントを、入れ子になった BeanContext に関連付けられたコンテナに関連付けます。
このようにして、最大の相互運用性を得るために、BeanContextChild は常に、そのコンポーネントの親が BeanContext コンテナであるかどうかをチェックし、親でない場合には、適切であれば自らを追加します。このため、BeanContextChild はどんなシナリオのもとでも正しく機能します。BeanContextChild は、最初に show() の呼び出しを介して自らを表示可能にする役割を担当します。 BeanContextChild は、自らに対して hide() および show() を繰り返し実行可能です。
入れ子になった BeanContext、またはその関連するコンテナは、BeanContextChild のコンポーネントに対して hide() または show() を任意に実行できます。 ただし、イベント通知を取得するためにリスナーを登録する場合、または他のコンポーネント/コンテナ固有のプロトコルがコンテナに対しそのコンポーネントの内容の状態を変更することを許可または要求する場合を除き、コンポーネントをすべての面で不変として扱うことを強くお勧めします。この種の許可された相互作用の例として、background または foreground カラーなどのプロパティがコンテナからコンポーネントに伝達される場合を挙げることができます。
いったん BeanContextChild が BeanContext からの入れ子状態を解除されると、関連するコンポーネント (存在する場合) は、削除操作の副作用としてその BeanContext のコンテナから削除されます。 これは、BeanContext の役割です。 一般に、setBeanContext() メソッドの呼び出しを介して BeanContextChild を関連付けられたコンテナとともに別の BeanContext へ移動すると、そのコンポーネントには、その操作の副作用として、元の BeanContext が子からの PropertyChangeEvent を介して変更通知を受ける前に、再び親子関係が確立されます。 ただし、検査を行なって、それが発生していない場合にはコンポーネントを削除する必要があります。
無限回帰を避けるため、コンテナおよびコンポーネントの入れ子関係とも関連付けられた BeanContext および BeanContextChild の両方で、関係の相手によりコンポーネントに適用されたすべての変更を取り消さないようにする必要があります。一般に、BeanContext は、BeanContextChild のコンポーネントの外観、可視設定、相対位置を担当します。 BeanContextChild は、実装するアプリケーション機能に属するコンポーネントの状態および内容を担当します。
getContainer() メソッドから返される値は、実装する BeanContext の有効期間中は一定です。 つまり、BeanContext とコンテナ間の関係は両者の有効期間中は静的です。
public interface BeanContextChildComponentProxy { Component getComponent(); }
BeanContext または BeanContextChild は、このインタフェースを実装して、関連付けられた GUI コンポーネントを入れ子になった BeanContext に公開します。BeanContext は、このメソッドを使って、コンポーネントのインスタンスへの参照と、それが認識する BeanContextChild への参照間の関係を確立できます。 その場合、BeanContextChild およびコンポーネントは、同じオブジェクトインスタンスによって実装されることはありません。 つまり、BeanContextChild はそのコンポーネント実装を、コンポーネントから継承するのではなく、個別のオブジェクトに委譲します。BeanContext は、入れ子になった BeanContextChild から取得したコンポーネント参照を調査して、その状態を判別します。 その後、リスナーを特定のイベント用に登録します。 ただし、コンポーネントの状態を変更しないため、BeanContext が参照を一般に不変なものとして処理することを強くお勧めします。getComponent() メソッドから返される値は、BeanContextChild が有効である間、一定です。
BeanContext が関連するコンテナを保持するが、BeanContextContainerProxy インタフェースを実装してコンテナを公開したくない場合、かつ任意の BeanContextChild の関連するコンポーネント (BeanContextChildComponentProxy インタフェースを実装するか、コンポーネントの直接のサブクラスとして、BeanContextChild により公開された) の入れ子状態を処理したい場合、BeanContext にはそのコンポーネントを関連するコンテナに対して追加または削除を行う権限が与えられます。
クラスが BeanContextChildComponentProxy と BeanContextContainerProxy の両方を実装する場合、getComponent() と getContainer() の双方が返すオブジェクトは、同一のオブジェクトになります。