JSF2.0 Faceletsカスタムタグとjarファイル分割

1年ちょっと前にJSF2.0の記事を書いたのですが、JavaEE6のWebフレームワーク標準であるものの、やはりまだJSF2.0についての日本語情報は少ないですね。私がJSF2.0を導入したシステムも、ようやく第1弾のカットオーバーを数ヶ月前に迎えて、幸い安定稼働しています。

さて、今回はJSF2.0、特にFaceletsによるカスタムタグを、Webプロジェクト(war)に含めない場合の実装について記述したいと思います。前回の記事において、XHTMLによるコンポーネントが作れるようになったと書いたのですが、画面共通で利用する汎用的なコンポーネントを開発者向けに提供したいと考えた場合、Webプロジェクトではなく、別途jarを分けて提供したいというケースは多いのではないかと思います。

これまで大規模プロジェクトでアーキテクトとして携わってきた経験上、開発者が勝手に共通コンポーネントを改修してしまったり、誤って削除するなど、開発者が触れる場所にあるのは、全体最適化および標準化の観点からも好ましくありません。またバージョニングの観点からも、例えばMavenにてフレームワーク系のjarはバージョニングにしているケースも多いでしょうから、やはりシステム共通レベルの実装はおいそれと開発者が触れないようにしておくほうがベターです。

とはいえ、別のjarのresourcesフォルダにXHTMLを置くだけでは、warの中に含めた場合と違い、カスタムタグとして認識されないので、一工夫必要になるのですが、Webで調べてもほとんど言及されてないところなので、今回取り上げることにしました。


1.ResourceResolverの作成

まずは、jarの中に含まれているXHTMLリソースをFaceletsが認識できるようにしてやるために、デフォルトのResourceResolverではなく、カスタムのResourceResolverを作成します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.net.URL;
import com.sun.faces.facelets.impl.DefaultResourceResolver;

/**
* JAR内に含まれるFaceletsのリソースを見つけるためのResolverクラス<br/>
*/

public class JarResourceResolver extends DefaultResourceResolver {

@Override
public URL resolveUrl(String resource) {
String resourceVal = resource;
URL resourceUrl = super.resolveUrl(resourceVal);
if (resourceUrl == null) {
if (resourceVal.startsWith("/")) {
resourceVal = resourceVal.substring(1);
}
resourceUrl = Thread.currentThread().getContextClassLoader().getResource(resourceVal);
}
return resourceUrl;
}
}

2.web.xmlへのcontext-param要素追加

次に、web.xmlに下記のようにcontext-param要素を追加します。faces-config.xmlではないというのは、そもそもFaceletsがJSF1系時代からも利用されていた別プロダクトであるという背景によるものですね。

1
2
3
4
<context-param>
<param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
<param-value>com.sample.JarResourceResolver</param-value>
</context-param>

3.taglib.xmlへのtag要素追加

上記2までの手順により、ResourceResolverの差し替えはできているので、あとはカスタムタグの情報をtaglib.xmlに追加するだけです。

ちなみに、taglib.xmlは、ファイル名が重要で、xxx.taglib.xmlのように、ファイル名の最後が「taglib.xml」で終わっていないと、JSFが自動認識できないので注意が必要がです。なお、taglib.xml自体は、warの中に含める必要はなく、クラスパスが通っていれば別のjarに配置してもOKです。私の場合は、別のjarのsrc/main/resources/META-INFに配置していました。

さて、肝心のtaglib.xmlへのtag要素ですが、XHTMLにて作成したコンポーネントが、別のjarのsrc/main/resources/components/sample/Sample.xhtmlだとすると、下記のようにクラスパスからの相対パスをsource要素に記述します。

1
2
3
4
5
<tag>
<description>サンプル</description>
<tag-name>sample</tag-name>
<source>components/sample/Sample.xhtml</source>
</tag>

このjarがWebプロジェクトのWEB-INF/libに配置されていれば、上記のsampleタグが利用できるようになります。