[HOME][JSFfollow-up]
Facelets入門(第二回)Faceletsの使い方
(つづき)
by Jacob Hookom
17 Aug 2005 01:00 EDT

本稿は、Faceletsに関する連載の第二回です。Faceletsは、JSFでアプリケーションを作るための新しい技術です。第一回はFaceletsの入門編でしたが、本稿ではJacobが、Faceletsを使って実際にJSFのアプリケーションを作るやり方の第一歩を説明します。


Faceletsのコンパイル

この連載の初回で述べたように、Faceletsは正しいXMLをコンパイルします。わずか数行のファイルでも、とにかくそれは正しいXML文書でなければなりません。

FaceletsはSAXを使ってドキュメントをコンパイルし、TagHandlerオブジェクトのステートのないツリー(ステートレスなツリー)作ってFaceletsオブジェクトの中に収めます。Faceletsはスレッドセーフですから、複数のリクエストから同時にアクセスされるような大規模な展開でも安心して使えます。Faceletsはコンパイル時に、警告メッセージや、ライブラリに関する情報、JSF内部のビュー処理に関する情報などをプログラマに提供します。

Faceletsのコンパイルの実行は、次のように簡単です:

// FaceletFactoryを取得してFaceletを作る
FaceletFactory factory = FaceletFactory.getInstance();
Facelet f = factory.getFacelet(viewToRender.getViewId());

// UIViewRootの中身を作る
f.apply(context, viewToRender);

Faceletsのアーキテクチャに関する詳しい説明は、今後の記事でいたします。

例外とデバッグ

Faceletsはエラーを綿密に扱います。たとえば属性の値を指定するELの式で、タイプミスをしたとしましょう。するとFaceletsは、コンパイル時に次のようなエラーメッセージを出力します:

greeting.xhtml @18,97 <input action="#{success[}"> Error Parsing: #{success[}

ご覧のようにFaceletsは、エラーが起きたファイル、行、そしてカラムまで表示します。それにもちろん、エラーを起こした成分と属性も表示します。

Faceletsはまた、デバッグメッセージの処理と出力のためにjava.util.loggingパッケージを使います。詳しくは、このパッケージのAPIドキュメンテーションを読んでください。

カスタムコンポーネント

Faceletsでは、XMLファイルやJavaのコードを使ってコンポーネントライブラリを定義できます。ただしここでは、今後よく使われると思われるXML方式について説明します。それは、次のような形になります:

<facelet-taglib>
  <namespace>http://www.mycompany.com/jsf</namespace>
  <tag>
    <tag-name>bar</tag-name>
    <component>
      <component-type>javax.faces.Data</component-type>
      <renderer-type>com.mycompany.Bar</renderer-type>
    </component>
  </tag>
</facelet-taglib>

たったこれだけで、あなたのコンポーネントをFaceletsの一員にすることができました。FaceletsはこのようなXMLファイルを、次の二つのうちどちらかの方法で参照します:

  1. web.xmlの中で、"facelets.LIBRARIES"というinit-paramの値として、";"で区切って羅列しておく。これらのファイルは、(web.xmlに書くのだから)Strutsのコンフィギュレーションファイルなどと同じく、アプリケーション固有のリソースです。
  2. アプリケーションをJARファイルにするときは、META-INFフォルダの中に拡張子が".taglib.xml"のファイルを収めます。Faceletsはこれらのファイルを、ちょうどJSPのtldファイルの場合のように、コンパイル時に拾い上げます。

facelet-taglibファイルの中で、コンバータやヴァリデータ、それにカスタムのTagHandlerも指定できますから、ドキュメントの処理をとても細かく制御できます。

カスタムヴァリデータとコンバータ

上と同じfacelet-taglibファイルによって、Faceletsの中で使うヴァリデータやコンバータを表現できます。たとえば:

<facelet-taglib>
  <namespace>http://www.jsfcentral.com/public</namespace>
  <tag>
    <tag-name>validateRegExp</tag-name>
    <validator>
      <validator-id>foo.bar.RegExp</validator-id>   
    </validator>
  </tag>
  <tag>
    <tag-name>convertUtilDate</tag-name>
    <converter>
      <converter-id>foo.bar.UtilDate</converter-id>   
    </converter>
  </tag>
</facelet-taglib>

この場合もやはりFaceletsは、JavaServer Facesの既存のAPIと密接に連動しますから、定義はご覧のように簡単です。Faceletsはあなたが定義したConverterValidatorに、必要な属性を自動的に結び付けます。

カスタムタグ

気の早いあなたは、Faceletsに自作のカスタムタグを加えたい、と思っていますね。それはたとえば、UIComponentValidator, Converterなどに独自のプロパティや属性を加えて独自の動作をさせたい場合です。

Faceletsには、あなたのその仕事を楽にするための基盤的なクラスがたくさんあります。ひとつの例として、<c:if>のソースを見てみましょう:

public final class IfHandler extends TagHandler {

    protected final TagAttribute test;
    protected final TagAttribute var;

    public IfHandler(TagConfig config) {
        super(config);
        this.test = this.getRequiredAttribute("test");
        this.var = this.getAttribute("var");
    }

    public void apply(FaceletContext ctx, UIComponent parent)
            throws IOException, FacesException, ELException {
        boolean b = this.test.getBoolean(ctx);
        if (this.var != null) {
            ctx.setAttribute(var.getValue(ctx), new Boolean(b));
        }
        if (b) {
            this.nextHandler.apply(ctx, parent);
        }
    }
}

たったのこれだけです!。ご覧のようにFaceletsは“善良な市民”のように自律的に振る舞い、コンストラクタ注入(*)を利用して依存性を受け取り、ドキュメントをコンパイルします(コンストラクタ引数でタグの属性値を取得する)。Faceletsとそのタグはすべてこのようにステートレス(ステートがない)ですから、タグハンドラオブジェクトをプールするJSPとは違います。技術的な詳しいお話は今後の記事で述べますから、ここでは上のコードを簡単に説明しましょう。

〔*:constructor injection, 依存性注入の3つの形式のうちのひとつ。依存性をコンストラクタ引数で受け取る。参考:Inversion of Control Containers and the Dependency Injection pattern(Martin Fowler)。コンストラクタ注入は、コンストラクト直後のオブジェクトが、それだけでそのまま完全に使える状態なので、別名、“善良な市民”デザインパターンとも呼ばれる。参考:A Brief Introduction to IoC(Sam Newman)。”他人--たとえばセッターメソッドなど--をあてにしない”という意味かなあ。〕

<c:if>がextendsするTagHandlerは、カスタムタグを作るための基盤的クラスの好例です。このTagHandlerは、JSPのTagSupportBodyTagSupportに相当します。

タグの構築時に、そのタグのTagオブジェクトを表すTagConfigが渡されます。TagConfigと、それから得られるTagオブジェクトは、 Faceletsドキュメントの中のタグの位置、子のタグ、属性など、ドキュメントの構造を伝えます。

TagAttributessはXMLドキュメントの中で指定されている属性の表現です。このクラスにはELの式を処理し、必要なタイプ変換をするためのメソッドがたくさんあります。これらもやはりステートレスですから、引数として現在のステートを表すFaceletContextを渡す必要があります。

もうひとつ注目していただきたいのは、子のタグをメンバ変数nextHandlerで表現していることです。子は必要なだけ何度でも適用できますし、またこの<c:if>の場合(test==falseの場合)のようにまったく適用されないこともあります。

カスタムタグを書いたら、それを次のようにしてfacelet-taglibファイルに書き加えます:

<facelet-taglib>
  <namespace>http://www.jsfcentral.com/public</namespace>
  <tag>
    <tag-name>if</tag-name>
    <handler-class>com.jsfcentral.IfHandler</handler-class>
  </tag>
</facelet-taglib>

まとめ

以上は、Faceletsフレームワークの使い方に関する簡単な入門記事です。今後の記事では、テンプレートの作成などFaceletsの重要な機能と、Faceletsのカスタマイズについて、説明します。


Jacob HookomはSunのJavaServer Faces参考実装とGlassfishプロジェクトのデベロッパであり、JavaServer Faces Expert Groupの現役メンバーです。彼は16歳のときにコンサルティングを始め、その後、情報技術やプロダクトマネージャなどの仕事を経験しました。そして最近Jacobは、JavaServer Facesを使った開発のための理想的な基盤として、Faceletsプロジェクトをスタートしました。彼はウィスコンシン州オークレアのウィスコンシン大学で総合コンピュータ科学の学士号を取得しています。

[HOME][JSFfollow-up]