转自 http://www.sk-jp.com/java/servlet/webxml.html
ご参考まで
web_app_2_3.dtdに基づいたweb.xmlの各要素に関するリファレンスです。 JavaPress誌Vol22/23に掲載された「ピンポイントJSP&サーブレット」 という記事の原稿をもとにして、 コラムなどを末尾に移動して見通しをよくしたものを公開します。 校正前の原稿(プレインテキスト)を元にしていますので、 見栄えなどはあまり考慮していません。 また、雑誌記事口調の部分と、適当に省略して不自然になっている文が 混じってます_o_。
間違いのご指摘はshin@sk-jp.comまでお願いします。
-
Webアプリケーションとは
-
web.xml詳細
-
各要素の説明
-
開発者のサポートのための要素
-
<distributable>?
-
<context-param>*
-
<param-name>
-
<param-value>
-
<description>?
-
<filter>*
-
<icon>?
-
<filter-name>
-
<display-name>?
-
<description>?
-
<filter-class>
-
<init-param>*
-
<param-name>
-
<param-value>
-
<description>?
-
<filter-mapping>*
-
<filter-name>
-
(<url-pattern> | <servlet-name>)
-
<listener>*
-
<listener-class>
-
<servlet>*
-
<icon>?
-
<servlet-name>
-
<display-name>?
-
<description>?
-
(<servlet-class> | <jsp-file>)
-
<init-param>*
-
<param-name>
-
<param-value>
-
<description>?
-
<load-on-startup>?
-
<run-as>?
-
<description>?
-
<role-name>
-
<security-role-ref>*
-
<description>?
-
<role-name>
-
<role-link>?
-
<servlet-mapping>*
-
<servlet-name>
-
<url-pattern>
-
<session-config>?
-
<session-timeout?>
-
<mime-mapping>*
-
<extension>
-
<mime-type>
-
<welcome-file-list>?
-
<welcome-file>+
-
<error-page>*
-
(<error-code> | <exception-type>)
-
<location>
-
<taglib>*
-
<taglib-uri>
-
<taglib-location>
-
<resource-env-ref>*
-
<description>?
-
<resource-env-ref-name>
-
<resource-env-ref-type>
-
<resource-ref>*
-
<description>?
-
<res-ref-name>
-
<res-type>
-
<res-auth>
-
<res-sharing-scope>?
-
<security-constraint>*
-
<description>?
-
<display-name>?
-
<web-resource-collection>+
-
<web-resource-name>
-
<description>?
-
<url-pattern>*
-
<http-method>*
-
<auth-constraint>?
-
<description>?
-
<role-name>*
-
<user-data-constraint>?
-
<description>?
-
<transport-guarantee>
-
<login-config>?
-
<auth-method>?
-
<realm-name>?
-
<form-login-config>?
-
<form-login-page>
-
<form-error-page>
-
<security-role>*
-
<description>?
-
<role-name>
-
<env-entry>*
-
<description>?
-
<env-entry-name>
-
<env-entry-value>?
-
<env-entry-type>
-
<ejb-ref>*
-
<description>?
-
<ejb-ref-name>
-
<ejb-ref-type>
-
<home>
-
<remote>
-
<ejb-link>?
-
<ejb-local-ref>*
-
<description>?
-
<ejb-ref-name>
-
<ejb-ref-type>
-
<local-home>
-
<local>
-
<ejb-link>?
-
付録(コラム)
WebアプリケーションというのはWebベースのユーザインターフェイスを 持つアプリケーションのことです。Servlet API 2.2以降で、 Servlet/JSPだけでなく、それらを利用する/それらから利用される HTMLファイルやイメージなどのリソースもひとまとめにして、 一つのWebアプリケーションという括りで扱う為の 標準形式が決まっています。
一つのWebアプリケーションは、以下のようなディレクトリ構成で構築します。
図1.Webアプリケーションのディレクトリ構成
MyApp
+- 任意の静的なファイル及びJSPファイル(及びディレクトリ)
+- WEB-INF
+- web.xml このWebアプリケーションで使用するServletに関する定義情報ファイル
+- classes .classファイル置き場
+- lib .jarファイル置き場
特徴としては、Webアプリケーションに関する設定を、 このディレクトリ構成の内部であるWEB-INF/web.xmlというファイルに 記述するようになっていることです。 このファイルに、そのWebアプリケーションがどのようなものであるかを Servletコンテナに伝える情報を記述します。 ウェブブラウザからアクセスする時はWEB-INFディレクトリ配下は 暗黙の内にアクセス禁止になります(*)。 また、classesとlibディレクトリは配置すべきものが class ファイルであるかjarファイルであるかの違いだけで、 Servletコンテナからは同じようにクラスを参照できます(*2)。
*:これを利用して直接アクセスされたくないファイルを WEB-INF配下に配置するというテクニックもあります。 web.xmlのアクセス制御でも似たような仕組みは実現可能です。
*2:一般的にはWebアプリケーションが使用する外部ライブラリの jarファイルをlibに置くことが多いですが、 そうしなければならないというわけではありません。
MyAppというWebアプリケーションは基本的にMyApp 配下のファイル以外を直接参照することがないようにしますので、MyApp ディレクトリを所定の場所に配置するだけでインストール完了 ということになります。
Webアプリケーションとは、いわば一つのWebサイトを詰め込んだようなもの と考えられるかと思います。 実際には一つのWebサイトで、辞書検索サービスとスケジュール管理 といったように複数の独立したサービスを提供する場合がありますが、 これらをそれぞれ一つのWebアプリケーションとしてまとめることで 独立性を高めることができますね。
WARフォーマット
図1のようなディレクトリ構成で作成されたWebアプリケーションをjar 形式でアーカイブした物が、WAR形式と呼ばれるものです。 WAR形式は、Webアプリケーションの配布単位として適当なもの という事になっていますが、実際のところは私たちが作成するWeb アプリケーションをWARファイルとしてまとめる意義は あまりないでしょう。
(なぜなら、ほとんどの場合は配布先の環境や要件の変更に合わせて、 初期パラメタやページデザインの変更をたびたび行う必要がある為です)
J2EEの規則に則ってアプリケーションの配備を行う場合は、 複数のWAR形式を内包したEAR形式のファイルを用意する必要があるのですが (これをJ2EEアプリケーションと呼びます)、 こちらについては現状は述べないことにします。
web.xmlはDD(Deployment Descriptor)と呼ばれるものの一つで、 Webアプリケーションのインストール先の環境において、 どのようなURLに対するリクエストがあったらServlet を呼び出すかを定義したり、各Servletに関する初期設定情報を記述します。 また、Webアプリケーション内のコンテンツの認証の制御なども このファイルの設定によって可能になります。
ここでweb.xml中の各設定項目と、その項目の意義について 筆者の解釈ではありますが説明していきたいと思います。
※Servlet 2.3仕様ではweb.xmlと似たような書式であるTLDファイル(Tag Library Descriptor)の要素名について、 単語の区切りにハイフンを使うように命名方針が変わっています。 つまり、下位互換性が無くなってしまっています。 両方で動作するタグライブラリを含むWebアプリケーションは ほぼ書けないということですねT_T。 XMLのバリデーションを行わないパーサなら両方の要素を 書くということで何とかなるんですが…。
要素の配置順
web.xmlに限らず、DTDで規定されたXML書式には、 要素の記述順についての定義があり、妥当性を検証するXML parserでは 要素の配置が間違っているとparseエラーになります。 図2に、ルート要素(web-app)の直接の子階層についてServlet 2.3仕様(DTD)に記載された出現順序を記します。 <filter>/<listener>/<servlet>要素などは 記述位置に迷うことがありますが、この順番で記述しなければならない ということです。いちいち覚えてられませんねぇ。 ただ、XMLはもともと要素の出現順序を意識する言語であり、 web.xmlでも一部の要素(複数記述できるもの)はその記述順自体に 意味を持っているものもあります。 XMLを設定ファイルに用いることの利点であり欠点でもありますね。 例えばdescriptionタグなどはいろいろな個所に記述できますが、 一貫性のある配置とは言いがたく、 どの位置に記述するかでとまどいそうです。 これは、そもそもweb.xmlは人間が編集するのではなく、 ツールによって自動生成されるようになることを 目指しているためと言えます。 そういったツールであれば記述順序に関する意識はほぼ無くなるわけですが、 現状はまだ直接記述するケースもあるでしょうね。
図2.web.xmlの第一層の要素の記述順
- <icon>
- <display-name>
- <description>
- <distributable>
- <context-param>
- <filter>
- <filter-mapping>
- <listener>
- <servlet>
- <servlet-mapping>
- <session-config>
- <mime-mapping>
- <welcome-file-list>
- <error-page>
- <taglib>
- <resource-env-ref>
- <resource-ref>
- <security-constraint>
- <login-config>
- <security-role>
- <env-entry>
- <ejb-ref>
- <ejb-local-ref>
この記事における記法について
この記事ではweb.xmlの要素が省略可能であることや、 複数指定が可能であることを以下のように表現します。
表記 |
意味 |
<icon>? |
<icon>要素は省略可能 |
<context-param>* |
<context-param>要素は省略可能で、複数記述も可能 |
(<url-pattern> | <servlet-name>) |
<url-pattern>要素か<servlet-name>要素 の何れかを必ず指定 |
'?'や'*'、及び'|'の意味はDTDにおける同記号と同じです(*1)。
また、DTD で定義された要素の出現順序に従って説明文を記述しています。
DTDの記述そのものは宣言的(*2)ですので、 それをぱっと見ても要素の記述順序をイメージしづらいですので このようにしています。 複数の場所に現れ得る要素についてもいちいち並べていますが 説明は簡略化します。
*1:他にDTDでは'+'(必須で、複数記述も可能)というのもあります。 正規表現でも同じ意味でこれらの記号が使われますね。
*2:XSLTも宣言的な文法ですね。他にRFCやParserGeneratorで用いられる BNF等も同様です。これらの表記にも慣れておく必要があるでしょうね。
以下の要素は、統合開発環境やServletコンテナの管理画面などで Webアプリケーションそのものを取り扱う際に使用されることが 想定されているものです。 これらの要素は他のいくつかの要素の子として記述することができます。 Webアプリケーションの実行には直接関係ないものと考えて良いでしょう。
要素 |
意味 |
<icon>? |
親要素が表す情報を表すアイコン(gif/jpeg)のファイル名を記述します。 |
<small-icon>? |
16×16ピクセルのアイコンを表すURL |
<large-icon>? |
32×32ピクセルのアイコンを表すURL |
<display-name>? |
親要素が表す情報の名前です。 |
<description>? |
親要素についての説明文を記述します。 |
内容は記述できません(空要素です)。 サーブレットコンテナはこの要素が存在するか否かを判断します。
この要素が記述されているWebアプリケーションは、 クラスタリング(分散化)されたサーブレットコンテナ上で 問題無く実行されることを宣言したことになります。 この要素を付加できないケースは、HttpSessionオブジェクトに Serializableでないオブジェクトを格納するようなプログラムが 含まれる場合です。
サーブレットコンテナが分散化されている場合、 同じユーザからのリクエストで毎回同じサーブレットコンテナ上の Servletが起動されるとは限らなくなります。 HttpSessionオブジェクトはサーブレットコンテナ毎に独立ですので、 別のサーブレットコンテナでリクエストが処理される場合は、 直前のアクセス時に確立したセッションが使えなくなるということです。 Servlet API仕様ではこのような状況も考慮して、 HttpSessionオブジェクトのサーブレットコンテナ間の移送/同期 についても触れられています。 HttpSessionオブジェクトに格納する全てのオブジェクトが Serializableであれば、これらのオブジェクトを転送することで 別のサーブレットコンテナにセッションの引き継ぎが出来るというものです。 そのルールを守っているWebアプリケーションは、 自分が分散配置されてもよいとここで宣言することができるわけです。
例:
<distributable />
<!-- 空要素の記述方法に注意 -->
このWebアプリケーション全体で共通の初期パラメタを記述できます。 ここで指定されたパラメタは、ServletContext#getInitParameter() で取得出来ます。 Servlet#getInitParameter()及びServletConfig#getInitParameter() では取得できないことに注意が必要です。 初期パラメタですので、実行時に値を変更することはできません。
パラメタ名
パラメタ名
説明文
フィルタオブジェクトの定義です。フィルタそのものについてはJavaPress Vol21の記事で紹介していますね。 子要素の書式や設定上のコツは<servlet>要素と同じです。 特に、<filter-name>要素で指定する名前はインスタンスに 対して付けるものであること、すなわち、同じクラスの別々の インスタンスに対して定義が可能であることは覚えておいてください。 <init-param>要素の設定によって、 同じクラスで振る舞いの異なるフィルタを複数定義できるということです。
アイコン
フィルタインスタンスに付ける名前です。
web.xmlの他の個所(<filter-mapping>要素)で、 使用するフィルタを特定するために使われます。
要素につける名前
説明文
フィルタクラス名
Filter#init(FilterConfig)メソッドに渡されるFilterConfig オブジェクトから取得可能な初期パラメタの定義です。
設定方法は<context-param>要素と同様です。
ちなみに、FilterからもFilterConfig#getServletContext() を使って<context-param>要素の情報を取得することも出来ます。
パラメタ名
パラメタ値
説明文
特定のフィルタオブジェクト(<filter>要素で定義されたもの) を適用する対象を指定します。
複数のマッピングを記述でき、その記述順に適用されることに注意が必要です。
<filter>要素で定義したフィルタ名
フィルタを適用する(呼び出されるようにする)リクエストURL、 またはServlet名。
一般には、特定ディレクトリ配下の全てのコンテンツに対して フィルタリングを行うための、 <url-pattern>/dir/*</url-pattern>といった設定が 良く使われるでしょう。
Webアプリケーション中で発生したイベントに応じて何らかの処理を 行いたい場合に、ここに以下の何れかのinterface を実装したクラスの名前を記述します。 Servletでのイベント処理におけるリスナの登録は、ここでのみ行えます。 プログラム中でaddXxxxListener() のようなメソッドを使うわけではありません。 したがって、リスナオブジェクトはWebアプリケーションそのものと 同じ寿命を持つといえます。言い方を変えると、Servlet API の Listener はイベントをハンドリングしたいコンテキストを指定することができず、 どのServlet上で起こったイベントも同じようにリスナに通知されるので、 リスナ側でイベントの発生元の判断が必要になるということになります。 何が変わったかという情報については、 登録するリスナクラスの型とパラメタであるイベントオブジェクト から判断出来ます。
ここに以下のinterfaceの何れかを実装したクラス名(FQCN)を指定します。
- javax.servlet.ServletContextListener
- javax.servlet.ServletContextAttributeListener
- javax.servlet.http.HttpSessionActivationListener
- javax.servlet.http.HttpSessionAttributeListener
- javax.servlet.http.HttpSessionBindingListener
- javax.servlet.http.HttpSessionListener
おなじみの Servlet のインスタンスに関する定義です。この設定がなくても Servlet や JSP にアクセスすることが可能ですが、 初期パラメタを与えたい場合のほか、 予めロードしたい/アクセス制限を行いたいといった場合は、 この要素で、個々の Servlet インスタンスに対して属性を設定できます。
JSPファイルも結局は Servlet ですので、この設定項目によって Servlet と同様の設定を行うことが可能です。
アイコン
ここで定義するServletインスタンスに付ける名前です。 <servlet-name>要素はあくまで<servlet-mapping>要素でURL にマッピングする際に使用する名前でしかないということを 忘れないようにしましょう。つまり、web.xmlファイル中でのみ参照される 名前です。これは<filter-name>要素にもいえます。
要素につける名前
説明文
Servletクラス名(FQCN)、またはJSPファイルのWebアプリケーション内の相対URI です。
例えば、/{webapp-root}/jsp/foo.jspに対する初期値の定義を行いたい場合は /jsp/foo.jspを指定します。
Servlet#getInitParameter()または、ServletConfig#getInitParameter() で取得できる初期パラメタです。
パラメタ名
パラメタ値
説明文
Webアプリケーションのスタートと同時にこのServlet/JSP をインスタンス化/初期化したい場合に指定します。
内容には起動する順番を表す0以上の整数値を記述します。
数値が小さいほど、より早く初期化が行われます。 負の値を指定した場合は無指定と等価で、Servlet のロードタイミングはコンテナに任されます (初回リクエストのときもあれば起動時の場合もあるでしょう)。
初めてリクエストがあった時ではなく、daemonのようにServlet コンテナの起動/終了に合わせて何かを監視するバックグラウンドスレッド を使いたい場合などに利用出来ます。
このServlet/JSPが、どの役割のユーザとして実行されるかを指定します。 この要素を使うことで、このServlet/JSPへ未認証状態でアクセスした時に HttpServletRequest#isUserInRole(roleName)の呼び出しが適切に true を返すようになる、ということと思うのですが、Tomcat4.0.1 で実行/ソースを見た限りでは、まだ実装されていないようです…。
説明文
<security-role>要素で宣言した役割名の何れか。
このServlet/JSPのソースコード内で指定する役割名(の別名)を定義し、 それを実際の役割名(<security-role>要素で宣言されるもの) とマップします。Realmに格納された役割名が変わった場合に、 ソースコード上の役割名文字列を書き替えずにすむようにするためのものです。 この要素が存在しなくても、<security-role> 要素で宣言された役割名をソースコード上で指定すれば動作しますが、 その場合は役割名の変更があった場合にソースコードの 書き替えが必要になります。
HttpServletRequest#isUserInRole(roleName) または EJBContext#isCallerInRole(roleName) により、この Servlet にアクセスしたユーザがどの役割であるかを調べることが出来ます。
説明文
Servletコード中で指定する役割名を定義します。 別名と捉えればよいでしょう。
<security-role>要素で使用を宣言した役割名を参照します。 <role-link> 要素が省略された場合は、 配備アプリケーションがマップすべき適切な役割名を 選択することとされています。 Tomcat では特に何もしてくれないので、<role-link> 要素をちゃんと指定しましょう。
特定のServlet/JSPオブジェクト(<servlet>要素で定義されたもの) を呼び出すためのURLを指定します。
複数のマッピングを記述でき、コンテナはリクエストがあった時にその URL がここで定義されたパターンにマッチするか順に調べていき、最初にマッチした Servlet/JSP オブジェクトを呼び出します。 したがって、複数のマッピングを定義する時は 記述の順序に注意が必要です。
Filterと同様に/*のように任意のURLへのリクエスト時に Servlet を呼び出させることができます。例えば JSP を実現するために、デフォルトで以下のようなマッピングを定義している サーブレットコンテナも多いです。
<servlet-mapping>
<servlet-name>JSPProcessingServlet</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
これは、URLの末尾が".jsp"となっているリクエストがあると、全て JSPProcessingServlet の呼び出しとなるというものです。
特定のディレクトリ配下のファイルや特定の拡張子のファイルへの リクエストに対して Servlet にレスポンスを返させるといった用途ですね。 このような場合は、HttpServletRequest#getRequestURI() を用いて実際にリクエストされたファイル名を取り出して処理を行います。
<servlet>要素で定義したサーブレットの名前
Servlet を呼び出すリクエストURL。 特定ディレクトリ配下を示す時は"/*"で終わるパターンを、 特定のサフィックスのファイルへのリクエストを Servlet で処理したい場合は、"/*.xxx"のようなパターンを記述します。
Webアプリケーション中の HttpSession オブジェクトの扱いに関する設定項目です。 現在はタイムアウト時間の設定のみです。
HttpSessionのデフォルトの有効期限を分単位で指定します。 0以下を指定すると、HttpSession オブジェクトは自動的に破棄されることはなくなります。 この要素自体を指定しなかった場合は、 コンテナのデフォルト値が用いられます。
タイムアウトとは、そのセッションの相手からの新たなHTTP リクエストが一定時間なかった場合に、サーバ側のHttpSession オブジェクトを破棄して、以降の同じクライアントからの接続を新たな セッションとすることです。 どのクライアントとのセッションであるかを識別するセッションID が盗まれると、なりすましされることになりますので、 セッションタイムアウトはユーザの利便を損なわない範囲で 出来る限り短い時間を設定します。 コンテナでのデフォルト値は一般に30分です。
静的コンテンツがリクエストされたときに、ファイルの拡張子に応じて返送する Content-Typeを決定したい場合に指定します。
ここで定義されていない拡張子のファイルがリクエストされた場合は、 (Tomcatでは)レスポンスのContent-Typeが指定されません。 これは望ましくありませんので、Web アプリケーション内で公開するファイルの拡張子に応じた <mime-mapping>要素はきちんと定義すべきでしょう(*)。
なお、いくつかの拡張子については Servlet コンテナのデフォルトマッピングとして定義されており、Tomcatであれば conf/web.xml に記述されている内容がそれに相当します。
ファイルの拡張子
Content-Type:ヘッダに記述されるMIMEタイプ(例:text/html)
例:Webアプリケーション内にPDFを配置したい場合
<mime-mapping>
<extension>pdf</extension>
<mime-type>application/pdf</mime-type>
</mime-mapping>
<mime-type>要素に指定できるMIMEタイプは、 http://www.isi.edu/in-notes/iana/assignments/media-types/ に定義されています。
# IEはレスポンスのContent-Typeに関らず、 返された文書をスキャンして適当に処理してしまう場合があって 困ったりするんですが。
URL末尾が/で終わる(ディレクトリを表す)ようなリクエストがあった時に、 返送するファイル名を指定します。
デフォルトで index.html, index.htm, index.jsp になっており(Tomcat 4.0の場合)、通常は指定する必要はありません。
<welcome-file>要素を複数並べることで、ディレクトリを表すURL がリクエストされたときに、指定された順番にファイルを検索して、 最初に見つかったファイルを返すようになります。
ファイル名
例:index.jspを優先的に表示したい場合
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
特定のHTTPステータスコード(404 File Not Foundなど)を クライアントに返送しようとした時、または、リクエスト処理中にServlet コンテナが特定の例外を catch した場合に、クライアントに返送するページを指定できます。
返送するページは<location>要素に相対URLで指定します。このページは Servlet/JSP の URL でも構いません。Servlet/JSP だった場合は、呼び出された側で、 ハンドリングしたステータスコードまたは例外オブジェクトを参照して表示を カスタマイズすることができます。 参照するには、ServletRequest#getAttribute() で以下のような属性名を指定します。
返されるオブジェクトの型は属性によって異なります。getAttribute() の戻り値をキャストして利用することになります。
属性名 |
格納オブジェクトの型 |
意味 |
"javax.servlet.jsp.jspException" |
Throwable |
例外オブジェクトです。JSP中で発生した例外が格納されます。 JSPにおける組み込み変数 exception の内容と等価です。 |
"javax.servlet.error.request_uri" |
String |
例外の発生したURIです。 ユーザのリクエストと一致するとは限りません (リダイレクトを伴う場合など)。 |
"javax.servlet.error.status_code" |
Integer |
HTTPステータスコードを表す整数です。 <error-code> 要素にマッチしてジャンプしてきた場合にセットされます。 |
"javax.servlet.error.exception" |
Throwable |
例外オブジェクトです。 この属性は例外が発生していれば常にセットされますので、 発生した例外を検査する場合は"javax.servlet.jsp.jspException" ではなくこちらを用いたほうがよいでしょう。 |
"javax.servlet.error.exception_type" |
Class |
例外クラスを表すClassオブジェクトです。 |
"javax.servlet.error.message" |
String |
発生した例外のgetMessage()の結果 |
<error-page>要素は複数記述可能ですが、Tomcat では記述順に関らず適切に発生した例外にマッチする エラーページにジャンプしてくれるようです。 この点は try ~ catch の場合とは違いますね( try ~ catch の catch 節は狭い型から順に記述しなければならない)。
ただ、以下の例のように RuntimeException を<error-page> 要素で捕捉するといったことは、運用の段階ではあってはならないことですし、 基本は各 Servlet が適切に例外処理を行っておくべきということになるでしょう。 それでも、ステータスコードでハンドリングするより詳細な情報を エラーページ側で取得できるという利点もありますし、 あくまで保険的な意味あいでこの要素を利用するという用途はありそうです。 万が一にも 500 Internal Server Error が返送されてしまうよりは、 何か原因をユーザに伝えるようにした方がよいですしね。
HTTPレスポンスステータスコードである3桁の数字か、Java の例外クラス名(FQCN)を指定します。
<error-code>要素または<exception-type> 要素の指定にマッチした場合に飛ばす先のURLを指定します。
例:アクセス禁止ページをカスタマイズ
<error-page>
<error-code>403</error-code>
<location>/errors/forbidden.html</location>
</error-page>
注意:ステータスコード403はServletが ServletResponse#sendError(SC_FORBIDDEN) で出力しないとハンドリング出来ません。
標準的なサーブレットコンテナはステータスコード403 を返送する設定にできない為、それを行うServletを作成することになります。
例:デバッグ用に RuntimeException のサブクラスが throw された時に debug.jspを呼び出す
<error-page>
<exception-type>java.lang.RuntimeException</exception-type>
<location>/errors/debug.jsp</location>
</error-page>
Webアプリケーション中でタグライブラリを使用したいときに、 JSPからタグライブラリを参照するためのURIを定義する要素です。
JSP中で指定するURIと、タグライブラリの定義ファイルである .tld ファイルのマッピングを指定します。
JSP中で指定するURIです。
タグライブラリを公開しているURLを元に、 他とぶつからない名前を付けるのが一般的です。
TLDファイルのパス(Webアプリケーションルートからの相対パス)
例:web.xmlと同じディレクトリに置いた sample.tld で定義されるタグライブラリにURIを関連付ける
<taglib>
<taglib-uri>http://example.com/tld/sample</taglib-uri>
<taglib-location>/WEB-INF/sample.tld</taglib-location>
</taglib>
一つのJavaオブジェクトを表します。 この次の<resource-ref>要素と同じく、 ソースコード外のリソースを参照するための定義です。 詳細は<resource-ref>の説明を参照してください。 <resource-ref>要素と異なるのは、 字面的には<auth>要素が不要であることです。 ただ、<resource-ref>要素は JDBC の DataSource のように、実際にアクセスしたいリソースに対する 間接的なアクセス手段をあらわすオブジェクトを取得することを 目的としていましたが、<resource-env-ref> 要素は任意の情報を自身が保持するような Java オブジェクトを取得できます。
もともとこの要素が Servlet 2.3 仕様で追加されたのは、J2EE 1.3 で追加された Message Driven Bean (EJBの形態のひとつ) にアクセスするために必要となる、JMS(Java Message Service)(*) の Queue(または Topic)オブジェクトを参照するためのようです (同時に必要となる QueueConnectionFactory / TopicConnectionFactory は<resource-ref>要素のほうで定義します)。
ただ、それ専用というわけではなく、プログラマが作成したクラスの オブジェクトもこの要素によって参照することができます。 方法についてはTomcatのドキュメントの、 JNDI Resources HOW-TO 等を参考にすればよいでしょう。
*: JMS/Message Driven Bean の概要についてはJavaPress誌Vol19/20号の「J2EEの世界」がわかりやすいです。
説明文
リソースをソースコードから参照するための名前を定義します。 詳細は<resource-ref>要素中の<res-ref-name> 要素を参照してください。
リソースの型をJavaクラス名(FQCN)で指定します。
WebアプリケーションをJ2EEアプリケーションにおける Webコンポーネントとしての位置づけで使用する際に、 J2EEプラットフォームが提供するネーミングサービスから 情報を参照できるようにするために定義します。
一つのJavaオブジェクトを表します。 主にリソースへのアクセス手段を提供するオブジェクト(データソース) を取得するために使用します。 データソースの仕組みを利用することで、接続先などを Java ソースにハードコードせずに、 JNDI の名前を使って間接参照することができます。 ここで宣言されたリソースにアクセスするには、 JNDI の API である javax.naming.InitialContext クラスの lookup() メソッドを用いて、"java:comp/env/"に<res-ref-name> 要素で宣言した名称を繋げたものを指定します。
Servlet中では、以下のように記述することでどこからでも このリソースにアクセスできます(*)。
InitialContext ic = new InitialContext();
dataSource = (javax.sql.DataSource)ic.lookup("java:comp/env/jdbc/MyDataSource");
データソースそのものの定義は、Tomcat なら server.xml 上に記述、通常のJ2EEコンテナであればアプリケーションの deploy 時に決定するというように、Webアプリケーションの外側で行います。 これによって運用段階での柔軟性/メンテナンス性が上がるわけですね。
*:通常は、InitialContextオブジェクトは使いまわすように実装します。
説明文
データソースオブジェクトをソースコードから 参照するための名前を定義します。 ここで定義する名前はあくまでWebアプリケーションのソースコードから 参照するための名前(Coded Name)です。 ソースコードからは、ここで指定された名前に"java:comp/env/" というプレフィックスを付加した名前でlookupを行います(上記例参照)。
実際のネーミングサーバ上に登録される名前は JNDI Name といわれ、deploy 時に Coded Name との対応付けの設定を行います。Tomcat 単体の場合は JNDI Name という概念が存在しませんので、server.xml 上の定義により、ここで定義した名前に直接 DataSource 等のオブジェクトをマッピングします。
データソースの型をJavaのクラス名で指定します。 javax.sql.DataSource や javax.mail.Session の他に java.net.URL や javax.jms.QueueConnectionFactory 等も指定できます。 いずれもリソースの実体が別にあってそれに対する獲得手段を あらわすオブジェクトです。
このリソースに対するアクセス認証をアプリケーションプログラム上で行う ("Application")か、コンテナに任せる("Container")かを指定します。
Application Servlet のプログラム中で認証のチェックを行う。(Servlet API 2.2 以前はこの値名は"SERVLET"でした)
Container Servletコンテナに認証制御を任せる。
このデータソースへの接続を共有出来るようにするか否かを指定します。
Shareable/Unshareableの何れかを指定でき、デフォルトではShareable となっています。Shareable の場合はそのデータソースに対するアクセスは他のコンポーネント (Webコンポーネント/他のJ2EEアプリケーション)と共有されていると考えて、 アプリケーションによるトランザクション制御が必要になります。 Unshareable を指定すると、そのデータソースへのアクセスが、 ある時点でこのコンポーネントのみからであることが保証されます。
特定条件にマッチしたリクエストに対するアクセス制限を定義します。
子要素でリソースの集合を定義し、 それらのリソースに対してアクセス可能な役割を指定することで、 その役割を持つユーザのみリソース群へのアクセスを可能にするといった 設定を行います。 定義したリソースの集合に誰にもアクセスさせないといった設定も可能です。
説明文
要素につける名前
アクセス制限対象のリソースの集合を定義する部分です。 リソースの集合は、URL-Pattern と HTTP method により指定します。特定のURLパターン(ワイルドカード指定可能) に加え特定のアクセス方法(HTTP method)の場合のみに 制限を加えることが可能です。
ここで定義するリソースの集合に付ける名前です。 この名前は<display-name>要素と同様に、web.xml 中の他の箇所からは参照されない、開発(またはdeploy)ツール向けの 情報といえます。 開発ツール上では一つの<security-constraint>に対して それを識別する名前を与えないと、 それぞれのリソース集合の定義をユーザが特定しづらいですもんね。
説明文
リソースのURL群を指定します。 ワイルドカードによって複数のリソースをひとくくりにしたり、複数の <url-pattern>要素で記述することができます。 指定しない場合のアクセス対象は未定義ですが、Tomcat 4.0.1 においては<http-method>要素の有無に関係なく全ての URLが対象になります。
アクセス制限を行う HTTP method を限定したい場合に指定します。指定しない場合は全ての method が該当します(こちらは仕様で規定されています)。
特定の HTTP method の場合以外を弾くという指定ができず、そういったことを実現するには、 制限したいすべての HTTP method を列挙しなければなりません。 逆に言えば、<http-method>要素を用いた場合は、 そこで指定されなかった他の HTTP method でのアクセスはなんら制限されないということです。注意しましょう。
親要素である<security-constraint> 要素で定義されるリソースのセットに対してアクセスを許す役割を定義します。
このWebアプリケーション中で使用を宣言した (<security-role>要素中に記述した)役割名を指定します。
<role-name>要素をひとつも記述しないことで、 誰にもアクセス(ログイン)できないリソース集合を定義することもできます。 注意が必要なのは、<auth-constraint>要素自体も省略可能なのですが、 この要素を省略した場合は、Tomcat 4.0.1 ではアクセス制限自体がかからないということです。 アクセスを禁止するには<auth-constraint> 要素のみを記述するようにします。
説明文
このリソースにアクセス可能な役割を列挙します。
内容に"*"を指定した場合 ("*"指定の<role-name>要素が一つでもある場合)、 アクセス可能なユーザは<security-role>要素で宣言した役割のうち、 いずれか一つでも持っているユーザとなります。 この要素を指定しないと誰にもアクセスできなくなります。
指定されているリソースに対する通信の保護を行うかを指定する要素です。
ここで指定するのは抽象的なもので、 具体的にどうやって通信の保護を実現するかは サーブレットコンテナに依存します。
説明文
保護の方針を指定します。指定可能な値は、"NONE" / "INTEGRAL" / "CONFIDENTIAL" のいずれかです。
- "NONE" では何も要求しません。
- "INTEGRAL" では通信データが改竄できないことを保証する通信方法を要求します。
- "CONFIDENTIAL" を指定すると、通信の改竄に対する保護に加え、 傍受からも保護されることを要求します。
保護を要求した場合、例えばSSL上でのリクエストでなければ、 エラーが返されるようになります。
逆に言うと、SSL通信が期待されるコンテンツなのに、 ここが未設定またはNONEであると、http URLでアクセスされかねないといえます。 この設定以外の個所(ソース上でのチェックなど)でブロックしていれば よいわけではありますが。
図3にこの要素で定義されるリソース集合とアクセス制限の関係を示します。
図3.<security-constraint>要素とアクセス制御の関係
このWebアプリケーションで用いる認証方式を定義します。 認証の仕組みは、前前回のServletFilterの記事のように独自に作り込む 場合もありますが、Servletコンテナ自体が認証を補佐することが できるように仕様が定められています(*)。
ここでは認証方式(ユーザインターフェイス)を指定するわけですが、 認証そのもの(ユーザ/パスワードの照合)については<login-config>や <security-constraint>を用いた時点でサーブレット (またはJ2EE)コンテナに任せたことになります。 Tomcatでは認証自体に用いるユーザ/パスワードのデータベースをserver.xml の<Realm>要素で切り替えることができますが、J2EE 1.3.1 に含まれる deploytool では、J2EE サーバに組み込まれたユーザデータベース以外を用いる方法が わかりませんでした。 商用アプリケーションサーバではおそらく可能だろうと思いますけれど。
*:ただし、この設定はWebアプリケーション全体で一つですので、同じ Webアプリケーションで別の認証方法を混在させたいようなケースでは この機能だけでは駄目です(そんな人はあまりいないと思いますが)。
認証方法を指定します。設定できる値は "BASIC" / "DIGEST" / "FORM" / "CLIENT-CERT" のいずれかです。省略可能とされていますが、少なくとも Tomcat 4.0.1 では省略するとエラーとなります。
"CLIENT-CERT" を指定した場合は、SSLクライアント認証を要求します。
BASIC認証のダイアログボックスに表示される realm (領域)名を指定します(*)。
<web-resource-collection>要素内の<web-resource-name> 要素の内容が使われればよいと思うのですが、そうはならないようですね…。 この要素を省略すると、Servlet コンテナに応じて固定の文字列が表示されます。 一つのWebアプリケーション中で(URLに応じて)異なる realm 名を用いるといったことはできないようです。
*:ここで指定する realm とは、Tomcatでの server.xml 内に現れる <Realm> 要素で言うところの realm とは関係ありません。server.xml 内で定義するのは Tomcat におけるユーザデータベースの格納/参照方法 の設定です。J2EEではさらに別の意味で realm という用語が用いられていますが…。
フォームベース認証方式を用いる場合の、 ログインページと認証失敗ページを指定します。
auth-methodが"FORM"以外の場合は意味をなしません。
ログインページ(を返すServletなど)へのURLを記述します。 '/'から始まる場合はWebアプリケーションルートからの相対パスとなります。
ログインページには以下のような<form>要素を含める必要があります。
- ・action="j_security_check"である
- ・name="j_username"である<input>要素を含む
- ・name="j_password"である<input>要素を含む
ログイン認証に失敗した場合に表示されるページへの相対URLを記述します。
このWebアプリケーション中でアクセス制限を利用するページがある場合に、 使用する全ての役割を宣言します。
<role-name>要素に役割名を記述します。 ここで宣言した役割は<servlet>要素中の <run-as>/<security-role-ref>要素、及び、 <security-constraint>要素中の<auth-constraint> 要素で参照されます。 Tomcatにおいては実はあまり意味のない要素です。 J2EEのdeploytool等のGUI設定ツールでは、 まず使用する役割名を宣言してから、 他の項目の設定画面で宣言した役割のなかから選択するという ユーザインターフェイスをとっています。 そのためにはWebコンポーネント中で用いる役割名のリストが先に現れる 必要があるために、この要素があるということになりますが、 本来はこの要素が無くても、Webアプリケーション中で使用する 役割名の一覧は、他の要素に記述された役割名をかき集めればすむことです。 そのようなわけで、Tomcatではこの要素をまったく記述しなくても 問題なく動作します。
説明文
web.xml内で使用する役割名です。 その役割がどのユーザやグループに対応するかはdeploy時に決定します。 Tomcatの場合はユーザデータベースに直接役割が関連付けられます。
Webアプリケーション単位で参照する環境エントリ情報を宣言できます。
ここで宣言する環境エントリとは、<resource-ref>要素と同じように JNDI を用いて情報を取得する方法の一つです。 実際にはネーミングサービスに値が格納されるわけではなく、 コンテナ自身が保持する値をJNDI経由で参照できるようにしている、 といった感じです。
<context-param>要素で指定する初期パラメタと似たような 位置づけにあると言えますが、J2EEアプリケーションを作成するならば、 その作法としてこちらを用いる方がよいということになると思われます。
この要素はスカラー値をJNDI経由で参照するためにあるわけですが、J2EE サンプルアプリケーションであるpetstore等を見てみると、 <env-entry-type>要素にStringクラスを指定して、 <env-entry-value>要素にクラス名を記述し、 ソースコード中でインスタンス化するといった使い方もされています。 そういった目的ならオブジェクト自身を登録しておいて <resource-env-ref> 要素で参照するほうが適切ではないかと思えますが…。
説明文
環境エントリをソースコードから参照するための名前を定義します。 <resource-ref>要素の項で説明したCoded Name ですね。環境エントリはその値を直接マッピングしますのでJNDI Name という概念は存在しません(*)。
*:ただ、なぜかServlet仕様書中ではこの要素に記述する名前をJNDI Name と呼んでいるのですが…。
環境エントリの値を指定します。指定する値は次の<env-entry-type> 要素に記述するようなスカラー型(*)になります。 <env-entry-type> 要素で指定するクラスが認識可能な書式で無ければなりません。
*:この言い方は語弊があるかもしれませんね。single value parameter という言い方もされているようです。
<env-entry-value>要素の内容の型をJavaの型で定義します。
記述できるのは以下の何れかです。
- java.lang.Boolean
- java.lang.Byte
- java.lang.Character
- java.lang.String
- java.lang.Short
- java.lang.Integer
- java.lang.Long
- java.lang.Float
- java.lang.Double
Webアプリケーション(Webコンポーネント)がEJB オブジェクトを参照することを宣言します。
EJBは、まずネーミングサーバから特定の名前でHome インターフェイスのオブジェクトを取得し、そのHomeインターフェイスからEJB そのものを表すRemoteインターフェイスのオブジェクトを獲得して使用します。 ちょっと冗長に感じますがこれらのEJB に関する情報を全て記述することになります。
説明文
EJBをソースコードから参照するための名前を定義します。 ここに記述するのは<resource-ref>要素で説明したCoded Name です。この名前を、deploy時に JNDI Name とマッピングするか、あるいは <ejb-link>要素によって直接EJBにマッピングすることになります。
名前は"ejb/"で始まるようにすることが推奨されています。
EJBがEntity Beanであるか、Session Beanであるかを指定します。
"Entity"または"Session"のいずれかを記述します。
EJBのHomeインターフェイスの型をFQDNで指定します。
EJBのRemoteインターフェイスの型をFQDNで指定します。
ejb.xml中の<ejb-name>要素で定義されたEJB オブジェクト名を指定します。 性能などの要因により、<ejb-ref-name>要素で指定する Coded Name と JNDI Name の対応付けを行わずに、Coded Name を直接EJBに関連付けたい場合に指定します。この要素がない場合は、deploy 時に Coded Name に対応する JNDI Name の指定が必要になります。
EJBの含まれるjarファイルを明示して、その中のejb.xml中の<ejb-name> 要素を指し示す場合は、以下のようにwarファイルからの相対パスを記述して #の後に<ejb-name>要素の内容を記述することができます。
例:web-app_2_3.dtdに書かれている記述例
:
<ejb-link>EmployeeRecord</ejb-link>
:
<ejb-link>../products/product.jar#ProductEJB</ejb-link>
:
Webアプリケーション(Webコンポーネント)がローカルホストに存在するEJB オブジェクトを参照することを宣言します。
子要素の内容は<ejb-ref>要素とほぼ同じです。 ただ、ここで定義するものはRMIを用いずにアクセスするEJBですので、 Home/Remote インターフェイスの変わりに LocalHome/Local インターフェイスを記述します。これらの要素で指定するクラスはそれぞれ EJBLocalHome/EJBLocalObject を継承した interface になります。そもそも EJB はデフォルトでリモート呼び出しが前提になっており、 ローカルホスト上での呼び出しもRMIを使って行うようになっていました。 これでは、EJBを同じマシン上に置くことが決まっている場合には、 無駄な呼び出しコストがかかってしまいます。 これを回避するために、LocalHome/Local インターフェイスが EJB 2.0 で定義され、それらを参照するための要素が Servlet 2.3 仕様に追加されたというものです。
説明文
EJBをソースコードから参照するための名前を定義します。 ここに記述するのは<resource-ref>要素で説明したCoded Nameです。
名前は"ejb/"で始まるようにすることが推奨されています。
EJBがEntity Beanであるか、Session Beanであるかを指定します。
EJBのLocalHomeインターフェイスの型をFQCNで指定します。
EJBのLocalインターフェイスの型をFQCNで指定します。
ejb.xml中の<ejb-name>要素で定義された EJB オブジェクト名を指定します。
<env-entry>/<resource-env-ref>/<resource-ref>
これらの要素はいずれも特定のリソースに名前を付けてJNDI 経由で情報を参照できるようにするものです。
<env-entry>要素はスカラー値、<resource-env-ref> はスカラー値を格納した任意のオブジェクト、<resource-ref> は特定の情報に基づいて情報を取得するためのオブジェクト (リソースファクトリと呼ばれます)を参照するためのもの、 と分けることができます。
セキュリティ/role/realmについて
web.xmlのセキュリティ関連の設定項目は、 これらの項目リストや仕様書の記述をざっと見ただけでは 把握しづらいのではないかと思います。J2EE のセキュリティモデルは柔軟である分だけ複雑なのですが、 Webアプリケーション単体で運用する場合はそこまで複雑ではありません。 しかし、web.xmlの設定やTomcatの設定は、J2EEのモデルを 踏襲しているだけあってやはりすぐには飲み込みづらい のではないかと思います。
用語を見ておきましょう。
user |
アクセスを許すユーザ名です。ユーザ毎にパスワードが必要です。 ユーザは複数のgroupに属することができ、 複数のroleを持つことができます。 |
group |
ユーザの属するグループです。Tomcatではグループの概念はありません (なのでここでは詳細は割愛します)。 J2EEでは複数のユーザをグループに属させることができ、 各groupが複数のroleを持つことができます。 |
role |
ユーザまたはグループの持つ役割です。 ユーザ/グループ毎に複数の役割を持つことができます。 アクセス制御はユーザやグループではなくroleに対して行われます。 ちなみにOSのユーザ管理ではユーザやグループに対して アクセス制御が行われる場合が多いですが、 J2EEのモデルではさらに一段アクセス制御のための 割り当ての自由度を増していることになります。 |
realm |
Tomcatにおいてはuser/role定義の集合(ユーザデータベース)を realm と呼んでいます。 どこにuser/password/roleの定義が格納されているかは サーブレットコンテナに対して宣言する「使用realm」によります。 TomcatのデフォルトはMemoryRealmであり、tomcat-users.xml に記述されたユーザ群の定義を用いますが、 実運用ではJDBCRealm などを用いてアカウント管理に柔軟性を持たせるでしょう。 |
ややこしいのはRealmという用語です。 <login-config>要素に<realm-name>という要素がありますが、 これは上記のrealmの定義とは無関係です。 また、J2EEの立場ではまた別の意味でrealmという用語が使われています (が、やはりここでは割愛します)。
謝辞
この記事の元原稿は、つ∞たん佐藤さん、前橋和弥さん、安藤 利和さんに 記事をチェックしていただき、いくつかのご意見をいただきました_o_。
変更履歴
- 2003/04/18 付録にあった「<servlet>要素の定義無しでServletを起動」は、現在意味がなくなったためコメントアウトしました。