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

www.netpotlet.com
原田洋子
2004/6/24

サンプルプログラムの作成

 XULをレンダリングする簡単なアプリケーションを試してみます。プログラムがどうなっているかを説明する前に、JSF仕様で分類されている利用者という考え方に触れておきます。

 仕様では次の5つに利用者を分類しています。

  • ページ作成者
    HTMLなどのマークアップ言語を使ってページを作る人。オーサリングツールを使うデザイナーなどが含まれる
     
  • コンポーネント作成者
    UIコンポーネントやViewHandlerなど、JSF上で利用できるAPIやライブラリを作るプログラマ
     
  • アプリケーション開発者
    JSFのAPIやJSPのタグなどを使って、JSF上で動くアプリケーションを作るプログラマ
     
  • ツール提供者
    JSFで動くアプリケーションの開発環境やStrutsのようなフレームワークを作るベンダや開発者
     
  • JSF実装作成者
    JSF仕様の実装を作るベンダや開発者

 このように分類しているのは、仕様書のどの部分が誰に向けて書かれているのかをはっきりさせる意味もありますが、プログラミング時に参照しなければならないAPIの範囲の違いを明らかにする目的もあります。今回はXULのレンダリングを目的にしているので、コンポーネント作成者の作業が必要です。また、XULページも書く必要があるのでページ作成者の作業も行います。本来、アプリケーション開発者のプログラミングが最も必要になるところですが、今回はレンダリング中心なのでEL(Expression Language)に関係する部分でJavaBeansのクラスを1つ定義するだけです。

開発手順1 コンポーネント作成

 図5に示す手順でXUL用のUIコンポーネントとRenderKit/Rendererを作っていきます。最初にXULファイルをオブジェクトモデルにマッピングし、JSFのUIコンポーネントを作りやすくします。XULから直接UIコンポーネントを作らないのは、XULファイルの構造が変わるたびにUIコンポーネントツリーを作るプログラムを手直ししたくないからです。また、XULの構造をスキーマ言語で定義すればデータバインディングが使えるので、自動生成されたAPIを使って、楽にプログラミングできます。加えて、XULの構造が変わっても作り直しが必要なコードをなくせます。

図5 コンポーネント作成手順

 ここで、データバインディングツールに何を使うかですが、XULからマッピングされたオブジェクトモデルをさらにJSFのUIコンポーネントツリーへとマッピングしなければなりません。このような要求にはデザインパターンの1つであるビジターパターンが適しています。そこで、ビジターパターンのクラスも生成できるデータバインディングツールRelaxerを使うことにしました。Relaxerのビジターパターン生成機能については本連載「第5回 スキーマコンバータ/バリデータ/ビジターパターン」を参照してください。

 XMLモデルのXULをオブジェクトモデルにマッピングするには、XULのすべての要素、属性を含むスキーマ定義を作るのが正統派のやり方ですが、XULの要素数、属性数ともに相当な量があるので、今回はレンダリングしたいXULファイルから始めることにしました。

 手始めに前回紹介したリスト4(別ウィンドウで開きます)のbutton.xulをJSFでレンダリングすることにします。RelaxerはXMLインスタンスからオブジェクトモデルのクラス定義を作り出せますが、ここでは本連載第5回で紹介したTrangを使いました。この一連の処理を実行するのがAntのビルドファイル、リスト1のbuild.xmlです。button.xulは前回紹介した図1(別ウィンドウで開きます)のdocsディレクトリへコピーし、名前もlanguage.xulと変更しました。リスト1の21〜24行目で定義しているRelaxerタスクについては本連載「第7回 RelaxerでオブジェクトをRDBにマッピング」を参照してください。Relaxerタスクが使うプロパティはリスト2のRelaxer.propertiesで、前回紹介した図1(別ウィンドウで開きます)のschemasディレクトリに置いてあります。relaxerターゲットを実行すると、図6に示すクラスが生成されます。

図6 自動生成されたクラス、インターフェイス

リスト1 build.xml(別ウィンドウで表示します)

リスト2 Relaxer.properties(別ウィンドウで表示します)

 今度は図5の2つ目、UIコンポーネント群を作成します。ここでのポイントは、XUL要素をJSFで定義されているどのUIコンポーネントに対応させるかです。UIコンポーネントツリーは理想的にはマークアップ言語に依存せず、RenderKitを変えれば別のマークアップ言語でレンダリングできるような構成になっているべきです。しかし、例えば、HTMLのTABLEタグとXULのgridタグの違いを考えると、簡単には別のマークアップ言語でレンダリングできるものではありません。ある程度、マークアップ言語のタグをまとめてUIコンポーネントにマップするなどの工夫がいるところでしょう。

 今回のサンプルはXULからXULをレンダリングするにとどめたので、XULの要素ツリーがそのままUIコンポーネントツリーになるようにしてあります。UIコンポーネントツリーは例えば図7のようになっています。ルート要素は常にUIViewRootです。

図7 UIコンポーネントツリーの例

 UIコンポーネントの例を1つだけ挙げます。ほかのUIコンポーネントのソースコードはダウンロードできるアーカイブに入れてありますので、参照してください。

 リスト3がUIコンポーネントのルート要素に当たるWindowComponentで、XULのwindow要素に対応しています。このコンポーネントからRendererが十分な情報を得られるようにgetXXX()メソッドをいくつか定義しています。44〜46行目のgetFamily()メソッドはRendererとUIComponentとの対応を取るための情報ですので、delegated implementationを採用する場合は必ず定義します。

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

 次は図5の3番目に当たるRenderKit/Rendererを作ります。RendererはUIコンポーネントそれぞれをレンダリングできるだけの数を用意することになります。例えば、リスト3のWindowComponentのRendererはリスト4のWindowRendererのようになります。RendererにはUIコンポーネント同様、encodeXXX()メソッドが定義されているので、これを実装します。

 さて、リスト4の42行目を見てください。

     String title =
         CoveElResolver.getResolver().resolveExpression(mixed);

 これはEL(Expression Language)をXULファイルで使えるようにしたものです。ELというのはJakarta Taglibsが作ったもので、JSPのカスタムタグで使えるようにした変数参照の式言語です。その後、ELはJSP 2.0で仕様に取り込まれ、実装はJakarta Commons ELとしてリリースされるようになりました。JSFにもELの機能が定義され、JSPの暗黙オブジェクトやJavaBeansのプロパティを参照できるようになっています。ただし、ELはJSFではValueBindingと呼ばれ、ELが“${...}”で記述するのに対し、ValueBindingは“#{...}”と記述するという違いがあります。ELのソースコードはここでは紹介しませんが、ダウンロードできるアーカイブに入れてありますので、興味があれば参照してください。

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

 最後に図5に示した“ViewHandlerと関連するクラス”を作成します。HTMLを出力する場合はデフォルトのViewHandlerが使えますが、このサンプルはXULを出力するのでXUL用のViewHandlerを実装します。ViewHandlerのクラスCoveViewHandlerはリスト5に示すようにしました。デフォルトをCoveViewHandlerにするにはfaces-config.xml(リスト9)というJSFのコンフィグレーションファイルで次のように定義します。

5   <application>
6     <view-handler>
com.netpotlet.cove.application.CoveViewHandler</view-handler>
7   </application>

 CoveViewHandlerクラスでは図1(別ウィンドウで開きます)の“Restore View”と“Render Response”で実行されるメソッド、restoreView()(89〜118行目)とrenderView(49〜67行目)を定義しました。

 restoreViewではXUL用のRenderKitを

51         RenderKitFactory factory =
52             (RenderKitFactory) FactoryFinder.getFactory(
53                 FactoryFinder.RENDER_KIT_FACTORY);
54         RenderKit renderKit = factory.getRenderKit(context, "XUL_RENDER_KIT");

のようにして取得しています。これは、faces-config.xml(リスト9)というJSFのコンフィグレーションファイルにある次のような定義が関係しています。

15   <render-kit>
16     <render-kit-id>XUL_RENDER_KIT</render-kit-id>
17     <render-kit-class>
com.netpotlet.xul.renderkit.XulRenderKit</render-kit-class>
18     <renderer>
19       <component-family>Window</component-family>
20       <renderer-type>XulWindow</renderer-type>
21       <renderer-class>
com.netpotlet.xul.renderkit.WindowRenderer</renderer-class>
22     </renderer>

 また、レスポンスのためのストリームも

55         HttpServletResponse response =
56             (HttpServletResponse) context.getExternalContext().getResponse();
57         response.setContentType(CONTENT_TYPE + "; charset=" + CHAR_ENCODING);
58         ResponseWriter responseWriter =
59             renderKit.createResponseWriter(
60                 response.getWriter(),
61                 CONTENT_TYPE,
62                 CHAR_ENCODING);
63         context.setResponseWriter(responseWriter);

のようにして通常のサーブレット同様、文字エンコーディングを含むMIMEのタイプを設定した後に、取得したストリームを基にXUL出力用ストリームを作っています。

 restoreView()メソッドでは本連載第5回で紹介したサンプル同様、ビジターパターンを利用してUIコンポーネントツリーを作っています。

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

開発手順2 XULとJavaBeansの作成

 ここからはページ作成者とアプリケーション開発者の作業になります。ELを使うとlanguage.xulはリスト6のようになります。前回のリスト4(別ウィンドウで開きます)との違いは4、8、18、20、23、25行目でELを使っているところです。4、8、20、25行目ではJavaBeansのプロパティを参照し、18、23行目では暗黙オブジェクトを使っています。XULの国際化ではエンティティの参照を使うようになっていますが、サーバサイドの処理が加わるとELなど、もう少し分かりやすい方法で参照できます。

 ここで使ったJavaBeansはリスト7のLanguageBeanです。ValueBindingの機能を利用するにはfaces-config.xml(リスト9)に

 9   <managed-bean>
10     <managed-bean-name>language</managed-bean-name>
11     <managed-bean-class>
com.netpotlet.cove.bean.LanguageBean</managed-bean-class>
12     <managed-bean-scope>application</managed-bean-scope>
13   </managed-bean>

のように定義しておきます。

リスト6 language.xul(別ウィンドウで表示します)

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

 以上でプログラミングは終わりましたが、これだけではまだ動きません。JSFを動かすにはFacesServletのマッピングが必要です。そのためにリスト8に示すweb.xmlをcove/WEB-INFディレクトリに置きます。なお、faces-config.xmlはリスト9のようになっています。このファイルもcove/WEB-INFに置きます。

リスト8 web.xml(別ウィンドウで表示します)

リスト9 faces-config.xml(別ウィンドウで表示します)

 ようやくすべてそろいましたので、サンプルを動かしてみましょう。Tomcatを起動して

 http://localhost:8080/cove/faces/docs/language.xul

をMozillaなどXULを表示できるブラウザからリクエストしてください。図8のように表示されます。

図8 サンプルの実行結果

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

 XULの簡単な紹介とJSFを使ったレンダリングの説明をしましたがいかがだったでしょうか。大変だった割には、出来上がったものがインパクトのない結果になったと思われたかもしれませんが、これは今回、レンダリングしか取り上げていないためです。次回のアクション編では、ロジックを動かした結果をXULの表示に反映させられるようなプログラミングを試してみます。

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

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

参考サイト

2/2  

 Index
連載 役に立つXMLツール集(9)
XULとJSFでリッチクライアント 〜JSF編〜
  Page 1
・JavaServer Facesを使いこなす

・JSFのリクエスト処理ライフサイクル
・JSFのUIコンポーネントとレンダリング
Page 2
・サンプルプログラムの作成
・開発手順1 コンポーネント作成
・開発手順2 XULとJavaBeansの作成
・まとめ&サンプルダウンロード


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


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

注目のテーマ

HTML5+UX 記事ランキング

本日月間