目次 JavaBeans の拡張可能ランタイム包含関係およびサーバプロトコル

JavaBeans バージョン 1.0 の拡張可能ランタイム包含関係およびサービスのプロトコル

コメントの送付先: java-beans@java.sun.com

1.0 はじめに

現在、JavaBeans 仕様 (バージョン 1.0) には、JavaBeans の階層や論理構造を説明した規則も、JavaBeans が、内部で JavaBean のインスタンスを生成したランタイムを認識したり、そのランタイムから任意のサービスや機能を取得したりする際の規則も含まれていません。

望ましい方法は、論理的でトラバーサルな JavaBeans の階層を提供すると同時に、任意の JavaBean のインスタンスを生成するオブジェクトが従来の方法で JavaBean に多様なサービスを提供したり、基本的なシステムサービスと JavaBean 間への割り込みを行うための一般的な機構を提供することです。

他のコンポーネントモデルでは、コンポーネントとその環境、またはコンテナ間の関係という概念が存在します。 そこでは、新たにインスタンスを生成されたコンポーネントが、そのコンテナまたは組み込みコンテキストへの参照とともに提供されます。

コンテナまたは組み込みコンテキストは、階層または論理構造を確立するだけではなく、コンテキストが提供するサービスを判別して利用するためにコンポーネントが調査するサービスプロバイダとしても機能します。

ここでは、次の拡張可能な機構をサポートするプロトコルを定義します。

以前のリストポイントのグラフィック表示

2.0 API の仕様

2.1 java.beans.beancontext.BeanContext インタフェース

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(); 
} 

2.1.1 入れ子構造に含まれる BeanContext

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() が必要です。

remove() メソッドは、既存の子 JavaBean または BeanContext をターゲットの BeanContext から削除する場合に呼び出されます。次のセマンティクスに従うためには、仕様に準拠して実装された remove() が必要です。

入れ子になった 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() メソッドによって定義されます。

一般に、これは目的の BeanContextClassLoader を使用して、適切な java.beans.Beans.instantiate() メソッドを呼び出すことにより実装されます。ただし、特定の BeanContext 実装は、このメソッドの実装内のインスタンス生成操作に対する副作用を引き起こす場合があります。

BeanContextEvent は、BeanContext の定義済みセマンティクスの状態変化に属するすべてのイベントに対する抽象ルートEventObject クラスです。この抽象ルートクラスは、通知元である BeanContexts を定義し、BeanContexts の階層を通じて BeanContextEvent サブクラスの伝播を可能にする機構を導入します。setPropagatedFrom() および getPropagatedFrom() メソッドを使用すると、BeanContext は伝播されるイベントのソースとして自らを識別するため、イベントは BeanContext に伝播されます。これは一般的な伝播機構であり、大規模な階層を経由して伝播が行われる場合、パフォーマンス面で重要な影響があるため、注意して使用する必要があります。

BeanContextMembershipEvent は、特定の BeanContext インスタンスのメンバシップ内で発生する変更を記述します。このイベントは、特定の BeanContext インスタンスのメンバシップ (すなわち、メンバシップセット内のデルタ) に対して、追加または削除された子のリストをカプセル化します。

特定の BeanContext インスタンスに対して呼び出された add()、remove()、addAll()、retainAll()、removeAll()、または clear() が成功する場合はいつでも、BeanContextMembershipEvent がトリガされてこの操作による影響を受ける子を記述します。

2.1.2 リソース

BeanContext は、getResourceAsStream() および getResource() という 2 つのメソッドを定義します。これらのメソッドは、java.lang.ClassLoader. BeanContextChild 上のメソッドに類似しています。BeanContext 内で入れ子になった BeanContext インスタンスは、入れ子構造の BeanContext に対するメソッドを、ClassLoader のメソッドに優先して呼び出します。 このため、子と基本的な ClassLoader セマンティクス間に動作を割り込ませることにより、BeanContext 実装からセマンティクスを拡張することができます。

2.1.3 サービスプロバイダとしての 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); 
} 
 
The BeanContextServiceRevokedListener is defined as follows: 
 
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 に登録されていることを示します。

いったん登録されたサービスは、取り消されるまで、BeanContextServicesgetService() メソッドを介して利用可能になります。

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 により、入れ子にされた BeanContextServicesreleaseService() メソッドの呼び出しを介して解放されるまで有効です。 ただし、BeanContextServicesBeanContextServiceRevokedEvent をトリガし、そのイベントの isCurrentServiceInvalidNow() メソッドが true を返す場合を除きます。この場合、BeanContextServices またはサービスを提供した BeanContextServiceProvider は、現在のサービス参照がただちに無効にされた、つまり「強制的に取り消された」(一般的には以下の状況で発生) と判断します。

BeanContextChild インスタンスが特定の BeanContextServices インスタンスから削除されると、BeanContextChild インスタンスは、適切な releaseService() を呼び出すことにより、BeanContextServices から取得したサービスへの参照をすべて破棄します。入れ子状態を解除する BeanContextChildBeanContextServices インスタンスである場合、およびこれらのサービス参照のすべてが、すでに定義されたように、委譲された getService() 要求の結果として、入れ子状態を解除する BeanContextServices 自身のメンバに公開されている場合には、BeanContextServiecs は、BeanContextServiceRevokedEvent をトリガして、入れ子にされた子に対して「サービスが強制的に取り消された」ことを通知します。入れ子状態の解除時に委譲されたサービスへの現在の参照をただちに無効化することにより、階層構造に依存するサービスの位置が変化した場合に、要求者によってそのサービスが使用されることを防ぐことができます。

サービスクラスの「強制的な取り消し」を受ける BeanContextChild インスタンスは、保持する可能性のあるその種の参照用の releaseService() を呼び出しません。 この場合、BeanContextServiceProvider または BeanContextChild へのサービス参照を提供した BeanContextServices は、そのサービスへの参照をすべて無効にしてしまっているからです。

BeanContextServiceProvider は、revokeService() メソッドを呼び出して BeanContextServices へ登録したあとであれば、いつでもサービスクラスを呼び出すことができます。BeanContextServicesBeanContextServiceRevokedEvent をトリガして、現在登録された BeanContextServiceRevokedListeners および現在サービスを利用できない BeanContextServicesListeners を通知すると、そのサービスクラスが再度登録されるまで、取り消されたサービスに対する新たなサービス要求には対応できなくなります。取り消される前に BeanContextChild の要求者により取得されたサービスへの参照は、有効のままになります。このため、サービスは、そのサービスへのすべての参照が解放されるまで有効のままになり、現存する参照を満たします。 ただし、例外的な状況で、サービスの取り消し時に BeanContextServiceProvider または BeanContextServices が現在の参照すべてへのサービスをただちに終了させる場合を除きます。即時取り消しは、BeanContextServices .revokeService() メソッドを、実パラメータ値 revokeNow == true で呼び出すことにより実行されます。現在のサービス参照の即時無効化の実行後に、サービス実装が、即時取り消し通知を無視してサービスへの参照を誤って保持しているサービスの要求者が呼び出すサービスを引き続き使用しようとする試みに応答して、サービス固有の検査されない例外をスローする場合があります。

(サービス要求の委譲時に) マルチスレッド環境で正しく動作するためには、BeanContextServices の実装は、addService()、hasService()、 getCurrentServiceClasses()、getCurrentServiceSelectors()、getService()、releaseService()、および revokeService() の実装を、BeanContext.globalHierarhyLock と同期させる必要があります。

BeanContextServicesProvider は、BeanContextServicesProviderBeanInfo を実装する BeanInfo クラスを提供することにより、実装を提供するサービスクラスに対して BeanInfo を公開します。このようにして、BeanInfo の配列を公開することにより、各サービスクラス用の BeanInfo がサポートされます。たとえば、開発用ツールは、この情報を利用してアプリケーション開発者に対し、アプリケーションに含まれるサービスクラスのパレットを提供できます。

2.1.4 持続性を持つ BeanContext の役割

BeanContext の主な役割の 1 つは、JavaBean コンポーネントの論理的な入れ子構造および BeanContext のインスタンス階層の表現です。このため、階層が持続的であるさまざまなシナリオを期待するのは当然のことです。階層が持続的であるとは、つまり、BeanContext が持続性機構、特に java.io.Serializable または java.io.Externalizable のいずれかに参加する場合のことを指します。後者の場合、BeanContext は、子のサブグラフ用の持続性コンテナ、クラス情報の符号化および復号化、および直列化解除後のサブグラフ相当機能の維持など、基本的に ObjectOutputStream および ObjectInputStream による直列化に対応した機能を提供します。

特に、BeanContext は、自身が持続性を付与されるか復元された場合、持続性を持ち、かつ適切な持続性インタフェースを実装する現在の子を復元します。

上記の要件の結果として、入れ子にされた BeanContext へのすべての参照、または入れ子にされた BeanContextServices 経由で取得された委譲者すべてへの参照を持続性のないものにするために、持続性を持つ BeanContextChild の実装が求められます。

BeanContexts は、持続状態からのインスタンスを復元する際に、新たにインスタンス生成された BeanContextChild への add() の呼び出しと等価な動作を実行する必要があります。 その結果、入れ子にされた BeanContext の新たに復元されたインスタンスが通知されるため、BeanContextChild はその環境への依存関係を十分に再確立できるようになります。

また、BeanContextjava.beans.beancontext.BeanContextChild を実装するため、このインタフェースの実装を扱う際には、以下に定義された持続性要件に準拠する必要があることにも留意してください。

2.1.5 関連付けられたプレゼンテーション階層での BeanContext

必須ではありませんが、多くの BeanContextjava.awt.Container および java.awt.Component の表示階層内で関連付けることができます。ContainerBeanContext を直接実装することはできません2 が、そこに記述された BeanContextProxy インタフェースを実装することにより BeanContext に関連付けることができます。

 
public interface BeanContextProxy { 
    BeanContext getBeanContext(); 
} 

BeanContext インタフェースを直接実装しない (そのコンポーネントやサブクラスの場合は、実装できない) クラスのインスタンスが、その実装のインスタンスに関連付けられている場合、(デリゲーションを介して) そのインスタンスは BeanContextProxy インタフェースを実装することにより、この関連付けを公開できます。このようにして、構築ツールなどの任意のサードパーティが、そのオブジェクトと関連付けられた BeanContext の問い合わせおよび検出を行い、関連付けられた BeanContext 内で入れ子にされたオブジェクトからメンバシップ変更を検出するか、またはそのサービスを取得することが可能になります。

これにより、複数の個別のオブジェクト (コンテナなど) が 1 つの BeanContext を共有することが可能になります。この場合、共有された BeanContextBeanContextContainerProxy を実装しないことに留意してください。 これは、単一の 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 つ存在します。

  1. 関連付けられたコンポーネントが、関連付けられたコンテナに、コンテナ API 経由で追加される場合、BeanContext 内の BeanContextChild の入れ子状態は、その副作用として生じるものであり、それ以上の操作は必要ありません。
  2. コンポーネントおよびコンテナが入れ子にされていない場合、入れ子状態の BeanContext は、副作用として、BeanContextChild に関連付けられたコンポーネントを、その関連付けられたコンテナに追加します。
  3. または

  4. コンポーネントおよびコンテナが入れ子にされていない場合、入れ子状態の BeanContextChild は、副作用として、そのコンポーネントを、入れ子にされた BeanContext に関連付けられたコンテナに関連付けます。

このようにして、最大の相互運用性を得るために、BeanContextChild は常に、そのコンポーネントの親が BeanContext コンテナであるかどうかをチェックし、親でない場合には、適切であれば自らを追加します。このため、BeanContextChild はどんなシナリオのもとでも正しく機能します。

BeanContextChild は、最初に show() の呼び出しを介して自らを表示可能にする役割を担当します。 BeanContextChild は、自らに対して hide() および show() を繰り返し実行可能です。

入れ子にされた BeanContext、またはその関連するコンテナは、BeanContextChild のコンポーネントに対して hide() または show() を任意に実行できます。 ただし、イベント通知を取得するためにリスナーを登録する場合、または他のコンポーネント/コンテナ固有のプロトコルがコンテナに対しそのコンポーネントの内容の状態を変更することを許可または要求する場合を除き、コンポーネントをすべての面で不変として扱うことを強くお勧めします。この種の許可された相互作用の例として、background または foreground カラーなどのプロパティがコンテナからコンポーネントに伝達される場合を挙げることができます。

いったん BeanContextChildBeanContext からの入れ子状態を解除されると、関連するコンポーネント (存在する場合) は、削除操作の副作用としてその 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 にはそのコンポーネントを関連するコンテナに対して追加または削除を行う権限が与えられます。この場合、BeanContextChild およびその関連するコンポーネント実装は、このアクションに干渉しません。

クラスが BeanContextChildComponentProxyBeanContextContainerProxy の両方を実装する場合、getComponent()getContainer() の双方が返すオブジェクトは、同一のオブジェクトになります。

2.2 java.beans.beancontext.BeanContextChild インタフェース3

環境のサポートまたは知識を必要としない単純な JavaBeans は、現在と同様将来も機能します。ただし、包含する BeanContext を利用する JavaBeans および入れ子にされた BeanContext の両方とも、認識している JavaBeans および入れ子にされた BeanContext を使って、内包する BeanContext への参照の伝搬を可能にする機構を実装する必要があります。 提案されているインタフェースは次のとおりです。

 
public interface java.beans.beancontext.BeanContextChild { 
	void        setBeanContext(BeanContext bc) 
				throws PropertyVetoException; 
 
	BeanContext getBeanContext(); 
 
	void addPropertyChangeListener 
		(String name, PropertyChangeListener pcl); 
  
     void removePropertyChangeListener 
		(String name, PropertyChangeListener pcl); 
  
	void addVetoableChangeListener 
		(String name, VetoableChangeListener pcl); 
  
     void removeVetoableChangeListener 
		(String name, VetoableChangeListener pcl); 
 
} 

予想される使用法としては、サードパーティが BeanContext 上で定義された適切なメソッドの 1 つを呼び出して (コレクションからの継承により)、ターゲットの BeanContext のメンバシップに BeanContextChild を追加する場合が挙げられます。その結果、BeanContext は、設定用メソッド setBeanContext() を呼び出して、BeanContextChild の「beanContext」プロパティを設定しようとします。BeanContextChildsetBeanContext() メソッドを呼び出すことができるのは、BeanContext だけです。 この機構は、新たな BeanContext 値を保持する子の通知に BeanContext が使用する機構であるためです。このプロパティは、アプリケーション構築用ツールを使ってユーザが直接設定したり、カスタマイズすることはできません。 このため、BeanContextChild 用の BeanInfo は、構築ツールがユーザにプロパティのカスタマイズを提示することのないように、このプロパティを隠された状態に設定する必要があります。

BeanContextChild オブジェクトは、PropertyVetoException をスローして、入れ子にされた BeanContext が、特定の BeanContext 内で機能しないこと、または入れ子にされていないことを通知することができます。そのような拒否通知は、BeanContext によって、BeanContextChild がその特定の BeanContext 内で機能しない、つまりファイナルであると解釈されます。

BeanContextChildBeanContext への入れ子状態から解除している間、その子または子の PropertyVetoEvents の「beanContext」プロパティに従うサードパーティが、PropertyVetoException をスローして、呼び出し側に入れ子解除状態ではないことを通知できます。このやり取りを抑制するために、BeanContextChild またはサードパーティは、初期入れ子解除通知を拒否できます。 ただし、その後の通知を拒否することはできません。 そして、通知を受け取った後、自らの状態を通知に合わせて修正して、その後に実行される入れ子解除に備える必要があります。

このインタフェースを実装するクラスは、java.beans.PropertyChangeListener の (サブ) インタフェースのイベントソースとしても動作します。 このため、その状態を適切に更新してから、適切な java.beans.PropertyChangeEvent をトリガする必要があります。 その際、propertyName には「beanContext」を、oldValue には以前に入れ子であった BeanContext への参照を、 newValue には新たに入れ子にされた BeanContext への参照を指定して、入れ子にされた BeanContext の値が変化したことをすべてのリスナーに通知します。

終了処理中の BeanContextChild インスタンス、または入れ子にされた BeanContext は、終了前に階層から自らを引き出すために、入れ子にされた BeanContext に対して remove() メソッドを呼び出します。

2.2.1 持続性に関する考慮事項

BeanContext 内で入れ子にされた BeanContextChild のインスタンスは、一般に、入れ子にされた BeanContext インスタンスへの参照を含むフィールドまたはインスタンス変数を、さらに可能であれば getService() メソッドを使って BeanContextServices インスタンスから取得したサービスを、定義します。

その種のインスタンスに持続性を持たせる作業の際、インスタンスが入れ子にされた環境で間違ってオブジェクトに持続性を持たせてしまうことがないよう、インスタンスがフィールドまたはインスタンス変数を一時的なものとして定義するか、そのような状態が持続することがないようカスタムの持続性メソッドを実装する必要があります。

ターゲットオブジェクトの直列化が、内部で入れ子にされたソース環境の大半も直列化する場合に、オブジェクトの直列化を介し、クリップボードを使用して行うオブジェクトインスタンスのカットおよびペーストなどの操作は正しく動作しないため、この要件は非常に重要です。

3.0 java.beans.instantiate() static メソッドのオーバーロード

java.beans.instantiate() は JavaBeans の (再) インスタンス生成を実行する現行の機構であるため、BeanContext の抽象化導入に対応するためには、このメソッドの構文およびセマンティクスを継承またはオーバーロードする必要があります。提案されている拡張は、次のとおりです。

public static Object instantiate(ClassLoader cl, 
						String	      beanName, 
						BeanContext beanContext); 

このメソッドの機能は、現在 JavaBeans 仕様で定義されていますが、これら既存のセマンティクスに加え、null 以外の BeanContext が指定された場合、メソッドは beanContext の実パラメータとして targetChild の実パラメータの値 (新たにインスタンス生成された JavaBean コンポーネントへの参照) を指定して add() メソッドを呼び出します。4

4.0 アプレットでもある Beans のサポート向上

java.beans.instantiate() の現行の実装には、アプレットでもある JavaBeans のインスタンスを生成するための最小限のサポートが含まれています。特に、このメソッドは、新たにインスタンス生成された JavaBean 用の AppletContext および AppletStub を構築し、まだ呼び出されていない場合には、新たにインスタンス生成されたアプレットにスタブを設定してから、アプレットに対して init() を実行します。

残念なことに、java.beans.instantiate() により作成された AppletContext および AppletStub を操作することはできないため、現行の実装では大半のアプレットが十分に機能するほどのサポートが提供されることはありません。これは、既存の Applet API に AppletContext および AppletStub 実装の構築方法を規定する仕様が不足しているために生じた結果です。また、そのような仕様が存在したとしても、あとで適切に初期化されたオブジェクトのインスタンスを生成するには、Codebase、Parameters、AppletContext、および Documentbase などの多数の Applet 属性を java.beans.instantiate() に伝搬する API が必要です。

完全に機能するアプレットをサポートする鍵は、アプレットに完全に機能する AppletContext および AppletStub のインスタンスを提供することであるため、設計上の目標は instantiate() を実行してこの状態を実現する機構を提供し、適切な初期化およびバインディング5を実行できるようにすることです。 このため、提案されるインタフェースは次のようになります。

public static Object  
			instantiate(ClassLoader 				cl, 
					  String      		beanName, 
					  BeanContext 		bCtxt, 
					  AppletInitializer															ai 
			); 
 
public interface AppletInitializer { 
	void initialize(Applet newApplet, BeanContext bCtxt); 
	void activate(Applet newApplet); 
} 

新たにインスタンス生成された JavaBean コンポーネントが java.applet.Applet のインスタンスである場合、新たに構築されたアプレット (Bean) が initialize() への呼び出しを介して AppletInitializer に渡されます。

仕様に準拠した AppletInitializer.initialize() の実装は、次のようになります。

  1. 新たにインスタンス生成したアプレットを、適切な AppletContext に関連付けます。
  2. AppletStub() のインスタンスを生成してから、setStub() の呼び出しを介して AppletStub をアプレットに関連付けます。
    1. an invocation of setStub().
    2. BeanContextパラメータが null の場合、add() の呼び出しを介してアプレットを適切なコンテナに追加することにより、アプレットをそのコンテナに関連付けます。BeanContext パラメータが null ではない場合、それに続く addChildren() メソッドの呼び出し時にアプレットをそのコンテナに関連付けるのは BeanContext の役割です。

    仕様に準拠した AppletInitializer.activate() の実装は、アプレットにアクティブであるとのマーク付けを行います。 またオプションで、アプレットの start() メソッドを呼び出すこともできます。

    新たにインスタンス生成された JavaBean が、アプレットのインスタンスではない場合は、AppletInitializer インタフェースは無視されることに留意してください。

    5.0 標準/提唱される BeanContext サービス規約

    5.0.1 InfoBus をサポートする BeanContext

    InfoBus 技術は、発行と署名の抽象化に基づき、単一の Java Virtual Machine 内の JavaBean コンポーネント間で、動的な自己記述型データの認識および交換を容易にする標準拡張パッケージです。

    InfoBus を入れ子にされた BeanContextChild に公開する BeanContext は、javax.infobus.InfoBus 型の hasService() および getService() メソッドを介してサービスを公開することにより、その機能を実行します。

    このため、BeanContextChild の実装は、この機構を使って InfoBus のインスタンスを認識することにより、現行の BeanContext に対応した一般的な InfoBus の実装を検出できます。

    Infobus 1.2 の仕様では、InfoBus クラスが提供する便利な機構が定義されています。 この機構を利用すると、特定の BeanContextServices のインスタンス内で入れ子にされた BeanContextChild インスタンスの検出機構が単純化されます。

    5.0.2 印刷をサポートする BeanContext

    印刷機能をその下位構造に公開する BeanContext は、java.awt.PrintJob (サブ) タイプの参照を委譲できます。

    Java Network Printing Interface が発展するにつれて、補足的な仕様が提供され、サービス機構を通じてその機能が公開されます。

    5.0.3 BeanContext 設計/実行時モードのサポート

    JavaBeans は、JavaBeans がアプリケーション開発ツールつまり IDE で開発者により操作および変換される際のモードである、「設計」モードをサポートします。 また、その結果 JavaBeans がアプレット、アプリケーションまたは抽象化された他の実行可能プログラムの一部として実行時にインスタンス生成される際のモードである、「実行」モードもサポートします。

    仕様の最初のバージョンでは、「モード」または状態 (つまり「設計」時または「実行」時) は、JVM のグローバルな属性でした。しかし、これでは不十分です。というのは、たとえばアプリケーション開発ツール環境では、「実行」モードで機能する JavaBeans がアプリケーション開発ツール環境の一部として存在します。 同様に、「設計」モードで機能する JavaBeans は、開発者がアプリケーション作成にアプリケーション開発ツールを使って構築します。

    このため、この「モード」を JVM グローバルよりさらに細分化してスコープする能力が必要になります。

    抽象化された BeanContext は、1 つ以上の JavaBeans の「コンテナ」または「コンテキスト」として、この「モード」をより細かくスコープするための適切な機構を提供します。

    このため、この「モード」を下位に公開および伝達する BeanContext は、次のようにして java.beans.DesignMode 型の参照を委譲できます。

    public interface java.beans.DesignMode { 
    	void    setDesignTime(boolean isDesignTime); 
    	boolean isDesignTime(); 
    } 
    

    また、参照を委譲する BeanContext は、propertyName = "designTime" と指定し、モードにより値が変更される際には oldValue および newValue に適切な値を設定して、適切な java.beans.propertyChangeEvent をトリガする必要があります。

    BeanContextChild のインスタンスが、内部で入れ子になった BeanContext のインスタンスに対して setDesignTime() を呼び出すのは、不正な動作であることに留意してください。

    5.0.4 BeanContext の可視性サポート

    関連付けられた表示機能、つまり GUI を保持する JavaBeans は、GUI が物理的に不可能である (ハードウェアが存在しない)、または現在の状況では適切ではない (クライアントではなくサーバコンテキストで実行中) ことを示す環境でインスタンス生成が可能です。

    JavaBeans 仕様の最初のバージョンでは、JavaBeans に「可視」状態、つまり GUI の描画用の機構を提供するために、java.beans.Visibility インタフェースが導入されました。

    子が持つ GUI の表示機能に関して、特定のポリシーを施行する BeanContext は、java.beans.Visibility インタフェースを使って、子を制御します。

    5.0.5 BeanContext からロケールを判定する

    BeanContext は、入れ子構造になった JavaBeans 間で重要な属性の関連付けおよび伝達を行うために、関連付けられたロケールを保持する場合があります。

    このため、BeanContext は、propertyName = "locale" とし、oldValue にロケール委譲の前の値への参照を設定し、newValue にはロケール委譲の新たな値への参照を指定して、適切な java.beans.PropertyChangeEvent をトリガする必要があります。

    BeanContext に対するロケール値の設定および取得は、実装に依存しています。

    6.0 サポートクラス

    この比較的複雑なプロトコルの実装を容易にするために、「ヘルパー」クラスである、java.beans.beancontext.BeanContextChildSupportjava.beans.beancontext.BeanContextSupport、および java.beans.beancontext.BeanContextServicesSupport が提供されますこれらのクラスは、別のオブジェクトにより暗黙的にサブクラス化または委譲されるように設計されています。 また、ここで統合するプロトコルの実装に完全に準拠 (拡張可能) しています。

    1サードパーティによる setBeanContext() の呼び出しの結果として、BeanContext が予期しない PropertyChangeEvent 通知を受け取り、その結果、remove() が呼び出された場合、削除実装は、remove() セマンティクスの一部として、子に対して setBeanContext(null) を呼び出すことはありません。 それは、呼び出すことにより、サードパーティにより設定された値を上書きしてしまうためです。
    2コンポーネントとコレクション間でメソッド名が衝突するため、コンポーネントは BeanContext またはコレクションを直接実装することはできません。 このため、機能を「〜である」という関係ではなく「〜を保持する」という関係でモデル化する必要があります。
    3この名前はあまり良くありません。 もっと良い別の名前を検討中です。
    4注: 単純な JavaBeans は、BeanContext を認識しません。 そのため、これら単純な JavaBeans が自らを階層から取り除き、ガベージコレクトされる機構は存在しないため、この種のインスタンスを階層内に導入することはお勧めできません。
    5AppletContext オブジェクトは、中に含むアプレットオブジェクトのリストを公開します。 残念ながら、現在のアプレットまたは AppletStub API の定義では、AppletContext が AppletStubs からアプレットを検出する機構、また AppletStub が AppletContext にアプレットに関する情報を提供する機構は提供されません。このため、この機構が java.beans.instantiate() 内で十分な意味を持つためには、このバインディング/検出が起こり得ると想定する必要があります。

     


    目次 JavaBeans バージョン 1.0 の拡張可能ランタイム包含関係およびサーバプロトコル