さて、コンポーネントツリーから、DOMツリーが作成される様子、およびDOMSerializerによりレスポンスが出力される様子を、もう少し詳しく見てみよう。

図14は、コンポーネントツリーからDOMツリーが作成される際の、オブジェクトの関係を示したものである。

図14 DOMツリー作成時のオブジェクトの関係

コンポーネントツリーとDOMツリーの対応は、DOMコンテキストにより保持される。レンダラは、DOMコンテキストを用いながら、サーバサイドのDOMツリーを構築する。DOMコンテキストはDOMContextクラスのインスタンスであり、サーバサイドのDOMツリーへの参照、各コンポーネントに対応したノード(およびその親ノード)への参照などを保持する。

DOMResponseWriterオブジェクトは、DOMツリーへの参照、および各コンポーネントに対応するDOMContextオブジェクトのマップ(以下、DOMコンテキストマップと呼ぶ)を保持している。なお、DOMResponseWriterオブジェクトは、(スレッドローカル変数から参照される)BridgeFacesContextオブジェクトから取得される。

カスタムレンダラは、staticメソッドであるDOMContext#attachDOMContext()メソッドを呼び出すことにより、コンポーネントに対応するDOMContextインスタンスを生成し、DOMコンテキストマップに追加する。また、コンポーネントに対応するDOMサブツリー(テキストレンダラであれば、input要素)を生成し、DOMツリーに追加する。

このようにして、DOMコンテキストを介し、コンポーネントツリーとDOMツリーの対応付けがなされながら、DOMツリーが生成される。

DOMツリーが生成され、レスポンス用のDOMツリーが完成した後は、DOMSerializerによりレスポンスが生成される。この動作についても簡単に説明しておく。

初回のレンダリングフェーズでは、NormalModeSerializerオブジェクトがレスポンスの生成を担当する。このオブジェクトのserialize()メソッドが呼ばれ、DOMツリー全体が、HTMLの文字列へと書き出される。

パーシャルサブミットに対するレンダリングや、サーバ起動のレンダリングにおいては、PushModeSerializerオブジェクトがレスポンスの生成を担当する。serialize()メソッドでは、前回のDOMツリーと、今回のDOMツリーにおける差分が抽出される。この処理では、変更のあったノードの中の最も上位にある要素が差分要素として抽出される。抽出された差分要素は、UpdateElementsオブジェクトとしてキューに入れられる。

レンダリングが終了した後に、サーバサイドのAjaxブリッジにおいて、キューに存在するUpdateElementsインスタンスのserializeTo()メソッドが次々に実行され、(リスト3のような)部分更新のためのレスポンスが生成される。

なお、DOMに関する操作はDOMUtilsクラスに集約されており、DOMSerializerの実装クラスや、UpdateElementsクラスは、このDOMUtilsクラスを用いている。

D2Dレンダリングにおいては、このようにしてサーバサイドのDOMツリーを作成し、変更があった要素を抽出している。また、変更があった要素だけを更新するためのレスポンスを出力することで、インクリメンタルDOMアップデートを実現している。

カスタムレンダラクラスが、D2Dレンダリングにおいてどのように用いられており、どのようにしてDOMツリーを構築していくのかについて、おわかりいただけただろうか。