-JSR252とTapestry4 (3)

JSF-RIのほうから行きましょう。JSF-RIのデコードの仕組みは、ViewHandlerおよびStateManagerを通して行われます。リクエストがあったとき、ViewHandler#restoreView()が呼び出されます。RIではStateManager#restoreView()にスルーします。StateManagerはsessionから既存のコンポーネントツリーを取得します。初回アクセス時は当然取得できないので、その場合はViewHandler#createView()でツリーのルートだけ作っておきます。
Tapestry(これは後に解説します)と比してJSF-RIの劣る点は、sessionを必ず使うことです。コンポーネントツリーをRIでは常にsession保存するので、サーバーサービス規模がスケールアップしていったときにはどうなるかというところが不安なところです(サーバに優しいStateManagerの実装は高価なアプリケーションサーバでは用意されるのかもしれませんね)。ま、JSF-RIではこのへんあまり力いれずに実装していて、ベンダーのビジネスチャンスを残しています。力いれていないといっても、そこんじょそこらのヘボミドルではないので、イントラで同時利用者が見える数のサービスなら問題ないですけどね。
描画は、ViewHandler#renderView()により行われます。ViewHandlerImplではJSPを実行すべくリクエストをdispatchするのが基本動作です。しかし、JSF1.1ではそれだけだったのですが、JSR252では違って、dispache後に、UIViewRoot#encodeAll() を実行しています。encodeAll()は新しいメソッドで、基本は以下の内容。

encodeBegin(facesContext);
if(getRendersChildren()) {
  encodeChildren(facesContext);
} else {
  for(...) {
    UIComponent child = ...;
    child.encodeAll();
  }
}
encodeEnd(facesContext);

これがJSR252の解決方法です。まずJSPの実行をしてツリーを構築し、JSP描画が終わった後に全コンポーネントツリーウォークでencodeBegin()、encodeChildren()、encodeEnd()を実行します。このとき、実際のアウトプットストリームに書き出されます。では、JSR252のJSP描画フェーズでは何が起こってるのでしょうか?それがUIComponentClassicTagBaseに実装された、力技な作業です。