JSFは今後期待されるWebアプリケーションフレームワークの一つです。標準規格ということで、普及してくるのではないかと思います。

JSFはユーザインターフェース周りの処理を簡単に実装できるということを目標に開発されたフレームワークで、WebでGUIアプリケーションを作っているような感覚でコーディングが出来ます。

アクションやイベントといった概念を扱っていて、非常に直感的に流れが分かるようなフレームワークになっています。ということで、今回はJSFフレームワークの流れについての覚書きです。

参考

覚書き

JSFのライフサイクルの覚書きです。JSFには6つのフェーズがあり、それぞれ役割分担がきっちりされています。

参考

JSFライフサイクルの図 (@IT)

JSFはJavaのWebアプリケーションフレームワークですので、サーブレットとして動作します。javax.faces.webapp.FacesServlet というのがそうです。クライアントのリクエストをサーブレットが受け取ってレスポンスを返すという処理は、通常のWebアプリケーションと一緒です。(当たり前ですが・・・)

JSFはリクエストを受け取って、レスポンスを返すまでのサイクルが6つに分かれています。

  1. レスポンスのレンダリング(Render Response)

Viewの復元(Reconstitute Request Tree)

レスポンス時に保存してあったコンポーネントツリーを復元するフェーズです。

初めてのリクエストや、JSF以外のページからのリクエストの場合は、コンポーネントツリーが存在しないので、新しくコンポーネントツリーを生成し、[レスポンスのレンダリング]フェーズに移行する。

このように途中のフェーズを省略して[レスポンスのレンダリング]フェーズに移行するためには、FacesContext#renderResponse メソッドを呼び出す。

JSFフレームワークは、UIコンポーネントという単位で画面を作っています。UIコンポーネントとは情報を持った塊のことで、下記のようなコンポーネントがある。

開発者はUIコンポーネントに対して処理を行っていく。サーバー側ではUIコンポーネントは親子関係を持ったツリーの形で保持される。

リクエスト値の適用(Apply Request Values)

クライアントが入力した値を、対応するUIコンポーネントに保存する。

入力フィールド(UIInput)であれば値をコンポーネントに保存し、ボタン(UICommand)であればイベントをキューに追加する。この段階ではモデルには値は反映されない。

編集可能なUIコンポーネント(EditableValueHolderインターフェースを実装したコンポーネント、例えばUIInputクラス)はこのフェーズで2種類の処理に分岐される。

immediate属性が true の場合

バリデータを呼び出して入力検証を行う。成功した場合UIコンポーネントに値を保存して、ValueChangeEventをキューにつめる。通常この処理は[入力値の検証]フェーズで行われる。その後、ValueChangeEventのリスナーや、対応するアクションが呼ばれる。

immediate属性が false の場合(属性がない場合)

UIコンポーネントに値を保存して、次のフェーズ[入力値の検証]に移行する。

イベントキューにイベントが追加された場合、次のProcess Eventsが処理される。(レスポンスのレンダリング]フェーズに移行する(Render Response)。

つまり、この後のフェーズが実行されない。これは、例えば「キャンセル」ボタンや「戻る」ボタンを実装したい場合に使う。[入力値の検証]が行われては困る場合には immediate属性をコントロールするべし。

入力値の検証(Process Validations)

[リクエスト値の適用]フェーズでUIコンポーネントに適用された値を、バリデータによって検証する。ここでは、画面に表示されるUIコンポーネントのみがチェックされる(rendered属性がtrueのもの)。

1. UIコンポーネントに保持されている値を型変換する。型変換エラーが出た場合には ConverterException例外をスローする。
2. 型変換された値に対してバリデータを使って検証する。検証エラーが出た場合には ValidatorException例外をスローする。
3. 例外が発生した場合には、FacesContextにエラーメッセージを追加して、Render Response処理に移行する。

このフェーズでバリデーションエラーが出た場合には、モデルの値は更新されずに下の画面に戻る。

通常であれば、[アプリケーションロジックの呼び出し]フェーズで次の画面のコンポーネントルート(UIViewRoot)が設定されて次の画面に遷移する。

しかし、途中でエラーがでて、次の画面のコンポーネントルート(UIViewRoot)が設定されない場合には、元の画面のコンポーネントルート(UIViewRoot)が残っているために、元の画面に戻ってしまうのである。

モデルの更新(Update Model Values)

UIコンポーネントに設定された値を、対応するモデル(JavaBean)にセットする。UIコンポーネントの型からモデルの型に変換できずにエラー(ConvertException)が発生した場合には、Response Renderが呼ばれてレスポンス処理に入る。

アプリケーションロジックの呼び出し(Invoke Application)

ボタンを押したなどのアクションに対してロジックを呼び出します。このロジックの結果によって次の画面遷移先を決定します。

イベントが発生するとイベントのリスナーが呼ばれます。リスナーはaddActionListenerメソッドで追加する方法(アクションリスナー)とsetActionメソッドでセットする方法(アクションハンドラ)がある。フレームワークはアクションリスナーを先に呼び出します。

リスナーの設定は基本的にはJSP内でタグを使って設定する。
・アクションリスナーを設定するには、UIInputやUICommandコンポーネントに 〜Listener という属性があるので、そこにメソッド・バインディングという方法を用いて指定する。
 
・アクションハンドラを設定するにはUICommandコンポーネントの action という属性にメソッド・バインディングを使って指定する。

レスポンスのレンダリング(Render Response)

次の画面を構築します。FacesContextに設定されているUIViewRootを使って、次の画面を決定します。

参考

JSFのタグ一覧

@IT:特別企画 JavaServer Facesを理解する(前編)

  • オライリーから発売中のJSFに関する書籍です。

  • リファレンス的な使い方も出来る結構情報量の多い本です。