連載 役に立つXMLツール集(11)
XULとJSFでリッチクライアント 〜ロジック編2〜 Page 3

www.netpotlet.com
原田洋子
2004/10/13

検証/変換/ロジック実行の実装

検証の実装

 検証(バリデーション)とは取得したリクエストパラメータが適当な値になっているかどうかを調べることで、リクエスト処理ライフサイクルのProcess Validationsフェイズで行われます。検証を行うには、まず、ページ作成者が検証のメソッドをメソッドバインディングの書式でXULファイル内に指定します。サンプルではリスト3リスト4の23〜27行目のtextboxで入力されるパラメータを検証するために子要素となる25、26行目のconfigタグのvalidator属性で指定しました。

23   <textbox id="password" type="password"
24            maxlength="8" value="${userinfo.password}">
25     <jsf:config actionListener="#{userinfo.setPassword}"
26                 validator="#{userinfo.validate}"/>
27   </textbox>

 どのような検証を行うかを決めるのはアプリケーション開発者の作業です。ここではuserinfoという識別子で参照されるJavaBeansのvalidate()メソッドで検証を行うことにしましたので、アプリケーション開発者はリスト11のUserinfoBeanクラスを定義します。リスト11の67〜73行目がvalidate()メソッドです。validate()メソッドでは入力された文字数を検証対象としています。

 検証にはJSFが提供するjavax.faces.validator.LengthValidatorを使いました。JavaBeansのメソッドではなく、このクラスのvalidate()メソッドをXULファイル内で直接指定することもできますが、UIコンポーネントの実装を考慮するといい方法とはいえません。これは、UIコンポーネントではどのような検証でも同じ方法で対応するので、検証クラスはそのインターフェイスであるjavax.faces.validator.Validator型で参照するからです。

 このインターフェイスにはvalidate()メソッドしか定義されていないので、検証に必要なパラメータをいつどのようにセットするかを考えなければなりません。ある場合はe-mailアドレスのチェック、またある場合は数値の範囲のチェックというように検証の種類が変われば必要になるパラメータは数も型も違ってきます。このため、アプリケーション開発者が検証のためのクラスを作り、そのクラスのメソッドをメソッドバインディングで指定する方が使い勝手がよくなります。

 リスト11のJavaBeansはfaces-config.xmlでリスト12のように登録しておきます。これもアプリケーション開発者の作業です。

 なお、画面(図2、図3)には8文字以内としか表示していませんが、XULファイルで入力できる文字数を8文字までと指定したので、検証をパスしない8文字以上が入力されることはありません。このため、あえて正しくない結果を出せるように4文字以上も条件に加えてあります。

 また、アプリケーション開発者はリスト12のようにUserinfoBeanをfaces-config.xmlに登録し、識別名userinfoで参照できるようにします。4文字以上、8文字以内の数値もfaces-config.xmlで設定しました。

リスト11 UserinfoBean.java(別ウィンドウで表示します)

リスト12 UserinfoBeanの登録(faces-config.xml)(別ウィンドウで表示します)

 最後にコンポーネント作成者の作業です。コンポーネント作成者は指定された検証メソッドをUIコンポーネントにセットし、リクエスト処理ライフサイクルのProcess Validationsフェイズで実行されるメソッドを実装しておきます。リスト13が実装を行ったTextboxComponentです。検証メソッドは43〜50行目にあるように、UIコンポーネントツリーを作るときにUIコンポーネントにセットします。また、前回説明したようにProcess ValidationsフェイズではUIViewRoot以下、各UIComponentのprocessValidations()メソッドが実行されますが、実装するのはこのメソッドから呼ばれているvalidate()メソッドです(60〜70行目)。

リスト13 UserinfoBeanの登録(TextboxComponent.java)(別ウィンドウで表示します)

変換の実装

 変換では、java.lang.String型で取得するリクエストパラメータを、例えばjava.lang.Integerなどのある型に変換します。ページ作成者は変換を行うメソッドを識別子かクラス名で指定します。サンプルではリスト3リスト4の31〜34行目のtextboxで入力されるパラメータをjava.lang.Integer型に変換するために子要素configのconverter属性で指定しました(32、33行目)。

31    <textbox id="favorite" value="${userinfo.favorite}">
32      <jsf:config actionListener="#{userinfo.setFavorite}"
33                  converter="intConverter"/>
34    </textbox>

 アプリケーション開発者は識別子でコンバータを参照できるように、リスト14のようにfaces-config.xmlにconverter要素を追加します。

リスト14 コンバータの登録(faces-config.xml)(別ウィンドウで表示します)

 コンポーネント作成者はまず、指定されたコンバータidをUIコンポーネントにセットします(リスト15)。次に変換処理ですが、変換はリクエスト処理ライフサイクルのどのフェイズで実行されなければならないという明確な定義は仕様にありませんので、このサンプルではUpdate Model Valuesで変換することにしました。

 このフェイズはリクエストパラメータから取得した値を維持・管理しているオブジェクトにセットするところで、UIViewRoot以下、各UIComponentのprocessUpdates()メソッドが実行されます。 実装するのはこのメソッドから呼ばれているupdateModel()メソッドです。JSF仕様ではセットする先はUIコンポーネントのsetValueBinding()メソッドを使って指定しておくことになっていますが、このメソッドはJSFのEL(Expression Language)を利用しているのでプレゼンテーション層でJSPを使っていないこのサンプルでは使いにくいメソッドです。代わりに、リスト16にあるように、XULのconfig要素のactionListener属性で指定されたメソッドを実行してオブジェクトに値をセットするようにしました。

リスト15 コンバータidの登録(TextComponent.java)(別ウィンドウで表示します)

リスト16 値をオブジェクトにセット(TextComponent.java)(別ウィンドウで表示します)

ロジックの実装

 最後はロジックの実装です。ロジックについても、ページ作成者がどのボタンでどのメソッドを動かすかをXULファイル内に書きます。このサンプルではリスト3リスト4の47行目で

47       <jsf:config actionListener="#{userinfo.update}"
                     action="success"/>

のようにconfig要素のactionListener属性でメソッドバインディングの書式に従ってロジックのメソッドを指定しました。

 アプリケーション開発者はロジックを実装します。このサンプルではリスト11のUserinfoBeanクラスのupdate()メソッド(45〜49行目)が、ロジックを実行する一連の動作の入り口となるメソッドです。ここではロジックが動くことを確認するために、プロパティの値を出力しただけですが、データベースやファイルにアクセスしたり、計算したりといった操作はここで行います。

 コンポーネント作成者は指定されたロジックのメソッドをUIコンポーネントにセットしておきます。セットしたロジックはリクエスト処理ライフサイクルのInvoke Applicationフェイズで実行されます。Invoke ApplicationフェイズではUIViewRoot以下、各UIComponentのprocessApplications()メソッドが実行されます。ただし、前回説明したように、processApplications()メソッドを実装しません。イベントがブロードキャストされたときに、イベントを受け取ってロジックを実行するリスナをUIコンポーネントにセットしておきます。リスナはUICommand型のクラスsetActionListener()メソッドを使ってセットしておきます(リスト17)。

リスト17 リスナのセット(ButtonComponent.java)(別ウィンドウで表示します)

動作確認

 実装が終わりましたので動作を確認してみます。最初に、図10に示すように

メールアドレス abc@def.ghi
パスワード あいうえお(画面には*で表示される)
好きな数字 24680

の3つのフィールドとも正しい入力を行った場合です。了解ボタンを押すと、3つの入力値がサーバに送信され、JSFのリクエスト処理ライフサイクルが動いた結果、コンソールに図11のように表示されます。

 ここで、パスワードの文字数を4文字未満にすると、検証に失敗し、図12のように例外が発生します。検証に失敗したときに発生する例外が

javax.faces.convert.ConverterException: 
java.lang.NullPointerException

のようになっているのは、検証に失敗した場合のメッセージが適当な方法でセットされていないためです。JSFでは国際化に対応したメッセージを用意しておかなければなりません。つまり、ロケールに対応したリソースが必要です。今回のサンプルではリソースを用意していないのでこのような例外が発生しています。 次に、好きな数字のところに数字ではなく文字を入力したら変換に失敗するはずです。試してみると図13のように例外が発生しました。このように、検証/変換/ロジックが動いていることを確認できます。

図10 テキストボックスへの入力


図11 ロジック実行結果


図12 検証時に発生した例外


図13 変換時に発生した例外


まとめ&サンプルダウンロード

 今回はJSF仕様に従った実装はどのようにするのかを説明しました。実装時にはJSF仕様で定義されている利用者のカテゴリ、ページ作成者/アプリケーション開発者/コンポーネント作成者がそれぞれ何をするのかの違いが分かるように説明しましたが、いかがだったでしょうか。

 本連載ではJSF製品の使い方ではなく、JSF仕様がどうなっているのかを理解するところに焦点を当ててきました。あえてJSPではなくXULにしたのもUIコンポーネントから作る必要がある代わりに、仕様で決められている仕組みや動きが分かりやすくなるためです。JSFというとJSPで、JSFタグの使い方を解説する記事が多い中、異色だったかもしれません。

 クライアントをXULにした理由にはもう1つ、XMLで書くという点があります。本連載は第1〜4回までデータバインディングをテーマに取り上げてきました。この4回だけではデータバインディングの概念やツールの使い方が分かる程度で、実際にどのような場面で使えるのかまで話を進めることができませんでした。そこで、実例としてJSFのUIコンポーネント定義にデータバインディングツールを活用しました。この過程でスキーマ定義およびスキーマを拡張してJSF用の定義を追加する方法についても簡単に触れました。道具としてXMLを使うために選んだのがXULです。

 なお、本連載ではJSF関連の用語はあえて英語のまま使いましたが、これは本連載を執筆している時点で正式な邦訳がなかったためです。いずれhttp://java.sun.com/j2ee/ja/glossary.htmlに日本語の用語が追加されるでしょう。

 今回使用したプログラムやファイル類は以下からダウンロードできます。

 Windows環境で利用される場合、euc-jpをWindows-31Jなど適当なエンコーディングに変更してください。また、日本語を含むファイルはEUC-JPになっていますので、あらかじめ文字コードを変えてから利用するといいでしょう。JSF APIと参照実装のアーカイブは含まれていませんので、別途ダウンロードして本連載第8回の図1のlibディレクトリに置いてください。

ごあいさつ

 本連載「役に立つXMLツール集」は今回が最終回となります。長い間、お読みいただきありがとうございました。機会があれば、再度、役に立ちそうなXMLツールを紹介したいと思います。XMLを道具として使う、XMLを使って何かを作ることが選択肢の1つになることを願って本連載を終わります。(連載完)

3/3

 Index
連載 役に立つXMLツール集(11)
XULとJSFでリッチクライアント 〜ロジック編2〜
  Page 1
・はじめに
・サンプルの概要
  Page 2
・リクエストパラメータ取得/ナビゲーションの実装
Page 3
・検証/変換/ロジック実行の実装
・まとめ&サンプルダウンロード
・ごあいさつ


「連載 役に立つXMLツール集」


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間