読者です 読者をやめる 読者になる 読者になる

この日記は私的なものであり、所属会社の見解ではありません。 GitHub: takahashikzn

TLDパス解決に見るTomcat7.0とTomcat6.0の違い

Java

Tomcat7.0.8(Stable)がリリースされていたので早速使ってみました。


とりあえず、いつも使っているサンプルアプリケーション
(Struts2, EclipseLink2, Spring3で構成)をデプロイして起動してみます。

2011-02-11 18:27:14,787 INFO  [spring.StrutsSpringObjectFactory] Thread-2 - Initializing Struts-Spring integration...
2011-02-11 18:27:14,787 INFO  [spring.SpringObjectFactory] Thread-2 - Setting autowire strategy to type
2011-02-11 18:27:14,787 INFO  [spring.StrutsSpringObjectFactory] Thread-2 - ... initialized Struts-Spring integration successfully
2011/02/11 18:27:26 org.apache.coyote.AbstractProtocolHandler start
情報: Starting ProtocolHandler ["http-bio-8080"]
2011/02/11 18:27:26 org.apache.coyote.AbstractProtocolHandler start
情報: Starting ProtocolHandler ["ajp-bio-8009"]
2011/02/11 18:27:26 org.apache.catalina.startup.Catalina start
情報: Server startup in 90049 ms

ふむ、何の問題もなく起動が完了したようです。
リクエストハンドラのスレッド名が変わった(http-bio-8080)んですね。へえ。

そうは上手く行く筈もなく

サンプルアプリのログイン画面を開こうとしたとき、それは起こりました。

2011/02/11 17:48:31 org.apache.catalina.core.ApplicationDispatcher invoke
致命的: サーブレット jsp のServlet.service()が例外を投げました
org.apache.jasper.JasperException: /WEB-INF/content/r42fw_auth/login/input.jsp(6,39) JSP ファイル "/r42fw-tags" が見つかりません
	at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:41)
	at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:407)
	at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:132)
	at org.apache.jasper.compiler.TagLibraryInfoImpl.<init>(TagLibraryInfoImpl.java:166)
	at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:410)
	at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:475)
	at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1425)
	at org.apache.jasper.compiler.Parser.parse(Parser.java:138)
	at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:239)
	at org.apache.jasper.compiler.ParserController.parse(ParserController.java:102)
	at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:197)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:365)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:345)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:332)
	at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:594)
        ...

r42fw-tagsとはTLDファイル(r42fw-tags.tld)のことで、
弊社独自フレームワークのタグライブラリのTLDです。


ちなみに、JSP内で同時に使用しているStruts2のTLDについては問題なく読めています。
jarの中に入っているTLDは、従来通りの仕様のままで問題ないようです。


Tomcat6では、/WEB-INF/classes/META-INFの中に配置すれば、何の問題もなく動作していました。
Tomcat7の標準であるJavaEE6の仕様が変わったのかも。


英語のお勉強タイムです

JavaEE6では、JSPは2.2にリビジョンアップしています。
とりあえず、JSP2.2の仕様書を眺めてみました。

http://jcp.org/aboutJava/communityprocess/mrel/jsr245/index.html


すると、§7.3.2にこんな記述が。

(抜粋)

JSP.7.3.2 TLD resource path


A URI in a taglib directive is mapped into a context relative path (as discussed in Section JSP.1.2.1, “Relative URL Specifications”). The context relative path is a URL without a protocol and host components that starts with / and is called the TLD resource path.


taglibのURI宣言は、コンテキスト相対パスにマップされる。コンテキスト相対パスはプロトコルとホスト名を省き、スラッシュから始まるURLである。コンテキスト相対パスはTLDリソースパスとも呼ばれる。



The TLD resource path is interpreted relative to the root of the web application and should resolve to a TLD file directly, or to a JAR file that has a TLD file at location META-INF/taglib.tld. If the TLD resource path is not one of these two cases, a fatal translation error will occur.


TLDリソースパスは、"WEBアプリのルート"または"JARファイルのMETA-INFディレクトリ"からの相対パスであり、TLDファイルが直接格納されているディレクトリの解決に使用される。
もしTLDリソースパスが前述のどちらにも該当しない場合は致命的エラーとなる。



The URI describing a tag library is mapped to a TLD resource path though a taglib map, and a fallback interpretation that is to be used if the map does not contain the URI. The taglib map is built from an explicit taglib map in web.xml (described in Section JSP.7.3.3) that is extended with implicit entries deduced from packaged tag libraries in the web application (described in Section JSP.7.3.4), and implicit entries known to the JSP container. The fallback interpretation is targetted to a casual use of the mechanism, as in the development cycle of the Web Application; in that case the URI is interpreted as a direct path to the TLD (see Section JSP.7.3.6.2).


タグライブラリを指すURIはTLDリソースパスへとマップされるが、もしマップ先が見つからない場合はフォールバック解釈される。
タグライブラリのマッピングはweb.xmlで明示的に指定するものである(詳しくはJSP.7.3.3を見よ)が、パッケージ化されたタグライブラリから自動的に設定を読み取り、暗黙的に拡張することもできる。
フォールバック解釈機能はWEBアプリの開発をラクちんにするために導入しているものである。そのようなケースでは、URIはTLDへの直接パスとして解釈される(詳しくはJSP.7.3.6.2を見よ)。



The following order of precedence applies (from highest to lowest) when building the taglib map (see the following sections for details):


フォールバック解釈では、以下の順でタグライブラリのマッピングが試みられる。


  1. If the container is Java EE platform compliant, the Map Entries for the tag libraries that are part of the Java EE platform. This currently includes the JavaServer Pages Standard Tag Library libraries and the JavaServer Faces libraries.
    もしコンテナがJavaEE準拠ならば、いくつかのタグライブラリのマッピングエントリが予めJavaEEプラットフォームに組み込まれている。(現在のところ、JSTLおよびJSFが組み込まれている)
  2. Taglib Map in web.xml
    web.xml内のタグライブラリマッピング
  3. Implicit Map Entries from TLDs
    暗黙的なタグライブラリマッピング
    • TLDs in JAR files in WEB-INF/lib
      WEB-INF/lib内のjarファイルに含まれるTLD
    • TLDs under WEB-INF
      WEB-INF直下のTLD
  4. Implicit Map Entries from the Container
    コンテナ独自の暗黙マッピング


ついでに、エラーメッセージをよく見てみると…

JSP ファイル "/r42fw-tags" が見つかりません

と言ってます。JSPファイル?

というわけで、

/WEB-INFの直下にTLDを配置して再起動してみました。するとエラーが出ずちゃんと動く。


jarにパッケージングすることも考慮に入れると、
TLDファイルは"src/META-INF"の直下に配置するのが普通だと思います。
"WEB-INF"の直下に置くのは不便です。


個人的には、Tomcat6までの仕様に戻してほしいなぁ。