Tomcat(5.5対応)についての各種Tipsです。
新しく書いたものが上になるように並べてあります。
JSP2.0(Tomcat5以降) では、EL式というものが使えます。
例えば、今まで
<%= request.getAttribute("userName") %>
と記述していたものが、EL式を使うと
${userName}
こんなに簡単になります。
これはリクエスト属性だけでなくセッション属性(さらにはアプリケーション属性)もサポートしているので
今までのように「この属性ってリクエストだったかなぁ、セッションだったかなぁ」と悩む必要がありません。
ただし、リクエストパラメータを使うには多少手を加える必要があります。
<%= request.getParameter("userName") %>
これは、以下のように記述します。
${param.userName}
先頭に param.
のプレフィックスを付けるだけです。
<jsp:param>
で渡されるパラメータはリクエストパラメータに格納されるので
この表記を使う必要があります。
例を挙げます。
main.jsp
<jsp:include page="sub.jsp"> <jsp:param name="userName" value="jon" /> </jsp:include>
sub.jsp
userName : ${param.userName}
こんな感じになります。
JSPファイルがブラウザに表示するHTMLを生成する手順について説明します。
ブラウザからJSPファイルにアクセスすると、まずTomcatの共通クラスである JspServlet
に処理が移ります。
これは、Tomcat共通の web.xml に以下の記述がされているからです。
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> ... </servlet> <servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> </servlet-mapping>
ちなみに JBoss(3.2.1) with Tomcat(4.1.24) の場合、このファイルは$JBOSS_HOME/server/default/deploy/jbossweb-tomcat.sar/
ディレクトリ以下に存在します。
JspServlet
では、以下の処理を行います。
上記手順のうち、(1)と(2)の処理は省略される可能性があります。
例えば、既にJSPファイルからclassファイルが生成されている場合、
これらの処理は省略され即座にclassファイルを実行します。
よって、初めてJSPページにアクセスするときには時間が掛かりますが、その後は処理時間が大幅に短縮されます。
Java(class)ファイルが生成される場所は、サーブレットコンテナによって異なります。
デフォルトは $TOMCAT_HOME/work
以下になります。
ただし、コンテキスト毎のxmlファイルに workDir 要素が記述されている場合や
コンテキストのweb.xmlに scratchdir 要素が記述されている場合はそちらが優先されます。
$JBOSS_DIST/server/default/tmp/deploy/server/default/deploy/work/MainEngine/localhost
以下になります。
$JBOSS_DIST/server/default/work/MainEngine/localhost
以下になります。
先程説明したように、JSPファイルは一度コンパイルされたら
その後再びコンパイルされることはありません。
しかし、 web.xml のJspServlet要素内で
development もしくは reloading が true
に設定されている場合は若干動作が異なります。
この場合、サーブレットコンテナはJSPファイルとclassファイルのタイムスタンプを比較して
JSPファイルの方が新しければJava(class)ファイルを再生成します。
これにより、JSPファイルを修正すればclassファイルも自動的(次のアクセス時)に修正されます。
この設定が思わぬ事態を引き起こすことがあります。
具体的には、JSPファイルを修正していないのに
毎回Java(class)ファイルが生成されるといった現象です。
Java(class)ファイルの生成には時間が掛かるので、これではレスポンスが非常に悪くなります。
この事態を引き起こす原因となったのは、正しいシステム時刻を設定していなかった事です。
例を挙げてみます。
開発をしているクライアントマシンをPC-1、Tomcatを起動させているサーバマシンをPC-2とします。
PC-1のシステム時刻が 09:00 を指している同時刻、PC-2のシステム時刻は 08:00 を指していました。
PC-1でJSPファイルを修正します。このときの時刻はPC-1上で 10:00 でした。
このファイルを PC-2 にアップロードします。
そして、ブラウザからこのファイルにアクセスしてみました。
時刻はPC-1上で 10:05 です。初めてのアクセスなので、JSPファイルからJava(class)ファイルが生成されました。
しかし、Java(class)ファイルを生成するのは PC-2 なので、
生成されたJava(class)ファイルのタイムスタンプは 09:05 になってしまいます。
再びブラウザから同じ画面にアクセスします。時刻はPC-1上で 10:10 です。
サーブレットコンテナはJSPファイルとclassファイルのタイムスタンプを比較しました。
前者は 10:00、後者は 09:05 です。
コンテナは、JSPファイルがclassファイルより新しいと判断してしまいました。
そして、再度Java(class)ファイルを生成しました。このファイルのタイムスタンプは 09:10 です。
時刻がPC-1上で 11:00 を過ぎるまで、ブラウザにアクセスする度にJava(class)ファイルは生成され続けるでしょう。
こういった事態を引き起こさない為に、以下のいずれかの手段を取る必要があります。
development と reloading の要素を false
に設定する(デフォルトではどちらも true
)。
個人的には後者をお薦めします。
前者の方法では、時間が経つにつれてシステム時刻がずれていく可能性があるので若干不安が残ります。
後者の方法は確実な上、サーバに掛かる負荷も減らすことが出来ます。
ただし、この場合には気を付けなければいけない事があります。
JSPファイルに対応するclassファイルが存在しない場合にしかclassファイルの生成が行われないので
例え本当にJSPファイルが修正されてもclassファイルが再生成されなくなってしまいます。
そのため、JSPファイルを修正したらclassファイル(もしくはworkディレクトリ)を削除する必要があります。
JBoss利用時は、$JBOSS_DIST/server/default/deploy/jbossweb-tomcat.sar/META-INF/jboss-service.xml
に DeleteWorkDirs
要素値が false
で定義されていない限り
jarファイルの再デプロイ時にworkディレクトリが自動的に削除されます。
開発時などは false
に定義しておく方が開発効率が上がるので、
テスト用サーバ等では (1) の方法を取る方が無難かもしれません。
Tomcatには2つのセッション管理マネージャが存在します。
ここでは、PersistentManagerにおけるパラメータの役割を
セッションの生成から破棄に至るまでのプロセスと共に説明します。
サーブレットからの HttpServletRequest.getSession()
呼び出しによって、セッションが生成されます。
また、JSPファイルにアクセスした際にも
<%@ jsp:page session="false" %>
が記述されていないとセッションが生成されます。
このとき、メモリ上に maxActiveSessions(デフォルトは無制限) 以上の
セッションが存在していると、例外(IllegalStateException
)が発生します。
セッションは一度生成された後は、同じユーザーによって使い回されます。
そして、セッションが最後に使用されてから
maxIdleSwap (デフォルトは無制限)秒以上経つと、
それらのセッションは全て無条件でスワップアウトされます。
また、セッション数がmaxActiveSessions以上になると
minIdleSwap 秒以上使われていないセッションもスワップアウトの対象になります。
minIdleSwapを-1(デフォルト)にすると、全てのセッションが対象になります。
この場合、maxActiveSessions以下になるまで
これらのセッションがスワップアウトされます。
スワップアウト処理では、セッションオブジェクトを外部記憶装置もしくはデータベースに
格納して、そのオブジェクトをメモリ上から廃棄します。
このため、セッションオブジェクトはシリアライズ可能である必要があります。
具体的には、session.setAttribute(name, value) で格納した全てのvalueオブジェクトにSerializable
インターフェイスが実装されている必要があります。
これが守られていない場合、例外が発生します。
スワップアウト処理は、相当のパフォーマンスを必要とする「重い」処理です。
特に、大きなセッションオブジェクトを格納していると
この問題はもはや致命的になりかねません。
セッションオブジェクトにはなるべくコンパクトなデータの格納を心掛けましょう。
スワップアウトされたセッションが再び使用される場合、
外部記憶装置からセッションオブジェクトを構築してメモリ上に展開します。
そして外部記憶装置からは削除されます。
セッションが使用されないまま maxIdleBackup (デフォルトでは無制限)秒経つと、
そのセッションは外部記憶装置に書き込まれます。
ただし、このときメモリ上から廃棄されません。
セッションが使用されないまま session-timeout 分が経過すると、
そのセッションはメモリ上から「破棄」されます。
この場合、そのセッションは二度と再利用できなくなります。
この現象を「セッション・タイムアウト」と言います。
この値を0(デフォルト)にすると、セッションは永久に破棄されません。
この場合、明示的に session.invalidate() を呼び出すのが唯一のセッション破棄方法となります。
ただし、これではさすがにまずいので
普通は $TOMCAT_HOME/conf/web.xml にデフォルトの記述があるはずです。
この値を0にするような場面はまず無いでしょう。
0にしてしまうと、もしユーザがログアウトせずにブラウザを閉じてしまうだけで
このセッションは永久にメモリ上(もしくは外部記憶装置)に残ることになるのです。
maxActiveSessions に適切な値を設定することから始めましょう。
セッション数がこの値を超えるとスワップアウトが発生し、
スワップアウトが出来ない状況になると例外が発生してしまいます。
ただ、あまりこの値を大きくする事はメモリ消費量の増加に繋がるので
メモリ量に応じた設定が必要です。
まず、各画面(サーブレット)で使用しているセッションオブジェクトを把握しましょう。
一つのセッションには通常複数のオブジェクトを格納(put)しているはずです。
Javaのオブジェクトからメモリ使用量を予想するのは困難ですが、
少なくとも大容量オブジェクト(Listや可変長配列など)が無いかどうか確認します。
スワップアウトの媒体には、ファイルもしくはデータベースを利用できます。
データベース接続は最初の一度だけ、PreparedStatementもプールして使用しているので
おそらくファイルに格納するよりも速いはずです。
管理も簡単ですし、なるべくならデータベースを利用しましょう。
常にautoCommitモードを使用するので、MySQL等のトランザクションレスDBを使うのが良い選択肢でしょう。
通常、サーブレットは「マルチスレッドModel」という形式で動いています。
それに対して「シングルスレッドModel」のサーブレットも存在します。
これはOSのスレッド等で使われる「マルチ/シングル」の関係とは異なるので注意しましょう。
この形式のサーブレットは、リクエストが発生する度に
サーブレットのインスタンスを生成します。
つまり、リクエスト数(=スレッド数): インスタンス数 = 1 : 1 という関係が成立します。
SingleThreadModelインターフェイスを実装する事によって、
そのサーブレットはシングルスレッドModelになります。
この形式のサーブレットは、複数のリクエストが発生しても
一つのサーブレットインスタンスを使い回します。
つまり、リクエスト数(=スレッド数): インスタンス数 = n : 1 という関係が成立します。
SingleThreadModelインターフェイスを実装しない限り、
全てのサーブレット(HttpServletの派生クラス)はマルチスレッドModelです。
つまりこれがデフォルト形式という訳です。
ここで最大の注意点があります。
一つのインスタンスを使い回すという事は、
このインスタンスが持つフィールドも複数のリクエストによって共有されるのです。
簡単な例を示します。
public class TestServlet extends HttpServlet { private int count = 0; protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { for (int i = 0 ; i < 10 ; i++) { ++count; resp.getOutputStream().println(count); } } }
フィールド値を10回インクリメントして、その都度画面に出力するという単純なサーブレットです。
では、次にリクエストを発生させたときの動きを追ってみます。
まず、一つリクエストを発生させてみましょう。
クライアント側で、ブラウザから目的のURLにアクセスします。
このとき、ブラウザには1から10までの数字が出力されます。
まぁこれは判りますね。では、次にいきましょう。
最初のリクエストを発生させて画面に「10」が出力されるのを確認した上で、
もう一回リクエストを発生させてみます。具体的には、ブラウザでリロードします。
このとき、画面には11から20までの数字が出力されます。
そう、マルチスレッドModelでは一つのインスタンスを共有するので
countフィールドは先程リクエストを処理した状態のまま残っているのです。
このサンプルでは、画面に表示される値はクライアント側から予測できません。
そのリクエストが何回目に発生されたかどうかは、サーバ側からしか判断できないからです。
しかし、例えばdoGetメソッドの先頭に
count = 0;
と書けば、クライアント側には常に1から10までの値が出力されそうです。
とりあえず、上の方法で確認してみれば一応画面には二回とも1から10の値が表示されるはずです。
これで一件落着・・・という訳には当然いきません。
仮に、同時刻に2つのリクエストを一斉に発生させたらどうなるでしょうか。
クライアント側でブラウザを2つ開き、同時に同じURLにアクセスします。
詳しくはスレッド関連の文書に譲りますが、このとき画面に表示される値は予測不可能になります。
例えば、片方のブラウザにはには
1 2 3 4 5 6 7 13 14 17
と表示されて、もう片方のブラウザには
8 9 10 11 12 15 16 18 19 20
と表示されることもあり得ます。
これを解決する為には、例えば
synchronized (lock) { count = 0; for (int i = 0 ; i < 10 ; i++) { ++count; System.out.println(count); } }
のようにロジック全体を同期化する等の方法を取る必要がありますが、
これはパフォーマンスの点から言って考えれば良策ではありません。
いっそのことシングルスレッドModelにしてしまう方が良いでしょう。
以上のことを踏まえると、マルチスレッドModelのサーブレットには
リクエストの度に代入されるようなフィールドを基本的に使ってはいけません。
シングルスレッドModelの実装方法は、コンテナに依存されます。
Tomcatが使用するcatalinaコンテナでは、シングルスレッドModelのサーブレットは
必ずしもリクエストの度に生成(new)されません。
処理を終えたサーブレットのインスタンスはプールされ、
次のリクエスト時にはそのインスタンスを使い回します。
リクエストが発生したときに、「未使用のインスタンスが存在しない」場合にのみ
catalinaコンテナはサーブレットのインスタンスを生成(new)します。
リクエストの度にインスタンスを生成していては非常にコストが高く付いてしまうからです。
ここでも少し注意が必要です。
例えば、マルチスレッドModelの項で紹介したTestSevletを
シングルスレッドModelにした場合を考えてみます。
この場合、その動作はコンテナによって異なってしまいます。
2回目のリクエストを発生させたとき、
もしコンテナがサーブレットのインスタンスをnewすれば
画面には1から10までの値が表示されます。
しかし、Tomcatのようにインスタンスをプールするコンテナの場合は
マルチスレッドModelと同じように画面には11から20までの値が表示されます。
これを解決する方法は、先程も紹介しましたがdoGetメソッドの先頭に
count = 0;
を入れることです。
こうすれば、常に画面には1から10までの値が表示されます。
同時に複数のリクエストを発生させた場合にも、
コンテナがサーブレットのインスタンスを新たに生成するので
常に1から10までの値が正しく表示されることが保証されます。
しかし、このシングルスレッドModelという概念は
今後無くなってしまう可能性があります。
jakartaによれば、SingleThreadModelインターフェイスは
Servlet API 2.4において deprecated(非推奨) であると説明されています。
Tomcat5ではServlet API 2.4を採用しています。
もちろんすぐに使えなくなるという訳では無いですが、
先程説明したシングルスレッドModelサーブレットの動作はTomcat5以降では
保証されないという事ですので、使い続けるのはあまり好ましい事では無いのかもしれません。
ただ、個人的にはSingleThreadModelを使うことは悪い事だとは思いません。
前述したように、Tomcat(catalina)はインスタンスプールを使っているので
これによるコストパフォーマンスの低下はほとんどありません。
jakartaは、このインターフェイスを非推奨にする理由として
「このインターフェイスは完全なスレッドセーフを実現するものではないから」としています。
確かに、リクエストの度にstaticフィールドに代入するような作りにしてしまうと
そのサーブレットはスレッドセーフでは無くなってしまいます。
しかし、僕はもともとSingleThreadModelをそのような目的で使っていません。
全てのリクエストでインスタンスを共有するというマルチスレッドModelの挙動よりも、
リクエスト毎に異なるインスタンスを使うシングルスレッドModelの挙動の方が
プログラムを組みやすいという理由で、僕はシングルスレッドModelを使用しています。
代入可能なフィールドを一切使えないプログラミングというのはどう考えても不便だからです。
その代わりに、全てのオブジェクトを引数で渡さなければなりません。
これは余りにスマートでない方法だと思うのですが、皆さんはどうでしょうか。
商用APサーバであるWebSphereのテクニカル情報を見てみました。
http://www-6.ibm.com/jp/software/websphere/developer/performance/v5/
これを読むと、WebSphereにおいてSingleThreadModelを用いると
「サーブレットの全処理が同期化されるのでパフォーマンスが極端に悪化する」とあります。
何ということでしょうか。
先程も書いたように、SingleThreadModelの実装方法はコンテナに依存されるのですが
こんな作りがあって良いのでしょうか?
つまり、WebSphereでSingleThreadModelを用いると
同一Servletへの処理は同時に実行されないと言っているのです。
イメージとしては、リクエストが単一のキューに保管されて
それを一つずつServletが処理をしていくような感じでしょうか。
確かにこれではパフォーマンスは劇的に低下します。
こんな実装を用意するくらいなら、いっそのことSingleThreadModelを使用不可にでも
すれば良いのに、と思ってしまいます。
とにかく、今のところWebSphere(V5)でSingleThreadModelを使うのは絶対に止めましょう。
StrutsではServletの代わりにActionクラスを用いますが、
Actionは完全にマルチスレッド専用の作りになっています。
一旦ロードされたActionクラスのインスタンスは内部的に保持されてそれを使い回す仕組みになっているので、
StrutsでSingleThreadModelの概念を導入することは残念ながら不可能のようです。
JBoss等でActionクラスのリロードが行われない事があるのもこれが原因です。
最後になりますが、SingleThreadModelインターフェイスを実装したサーブレットの
デバッグ方法について一つ。
Tomcatではサーブレットのデバッグをスムーズに行う為に
サーブレットのリロード機能が使えます。
詳しくはserver.xmlのreloadable要素を参照して下さい。
しかし、SingleThreadModelインターフェイスを実装したサーブレットでは
このリロード機能がうまく働きません。
環境やTomcatのバージョンにも依存するかとは思いますが。
とりあえず、僕が試した限りでは確実にリロードが成功する方法を紹介します。
Webアプリケーション・マネージャを使用します。
ここでは画面上からコンテキストの再ロード等が行えますが、
「再ロード」のリンクをクリックせずに「停止」「起動」と2回に分けてリンクをクリックします。
こうすると、何故かサーブレットのリロードが確実に成功します。
ただし、それでもリロード不能になってしまう状況もあるので
その場合は諦めてTomcatを再起動しましょう。
Tomcatアプリケーションで使用するサーブレットファイルは
通常、$APP_HOME
/WEB-INF/classes 以下に置かれています。
アプリケーション実行時、Tomcatは自動的にこの場所にクラスパスを設定します。
一方、strutsを利用するとき等に使用するjarファイルは$APP_HOME
/WEB-INF/lib 以下に置きます。
これ以外にも、Tomcatアプリケーションで利用できる
クラスファイルの置き場所はいくつかあります。
そして、これらのクラスファイルの読み込みには決まった順番があります。
jakartaの公式サイトによると以下の通りです。
クラスファイルは上から順に検索されます。
つまり、同名のファイルが複数存在した場合には
その中で一番最初に見つかったものが使用されるという事になります。
例えば、Tomcatで提供されているクラス(org.apache.*やjavax.servlet.*)を
自分でカスタマイズしたい場合を考えます。
元々これらのファイルは $TOMCAT_HOME/common/lib/*.jar に置かれているので
$TOMCAT_HOME/common/classes 以下にカスタマイズしたクラスファイルを置けば
このクラスファイルが上書きされて使用されることになります。
全アプリケーションで共通に利用するjarファイルは
各アプリの WEB-INF/lib に置いても良いですが
$TOMCAT_HOME/common 以下に置くことも可能です。
後者の利点は、
共有ライブラリが修正された場合に1つのファイルを更新するだけで済むことや
メモリ使用量が抑えられることが考えられます。
一方、欠点としては
jarファイルを修正したときにTomcatを再起動しなければならない点が挙げられます。
どちらが望ましいかは状況に応じて変わると思いますので
各自工夫してみて下さい。
Tomcatアプリケーションからデータベースに接続する場合、
最も簡単な方法は通常のJavaアプリと同様に
java.sql以下のクラスを利用する事です。
ここは一歩踏み込んで、接続プールを使う方法を紹介します。
接続プールとは、DB接続を予めいくつか確保しておいて
アプリケーションから接続が要求されたときに
この確保された接続(これを接続プールと言う)を利用するというものです。
これによって、DBへの接続/切断に掛かるタイムロスを大幅に軽減させる事ができます。
DBを利用したいアプリケーションのContext要素内にResource要素を記述します。
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"/>
次に、Resourceと同じ階層にResourceParams要素を記述します。
<ResourceParams name="jdbc/TestDB"> <parameter> <name>factory</name> <value>org.apache.commons.dbcp.BasicDataSourceFactory</value> </parameter> ... </ResourceParams>
ResourceParams要素内に複数のparameter要素を記述します。
parameter要素はnameとvalueの対になっています。
全DB共通でfactoryを記述し、後は各ファクトリに応じた値を必要なだけ記述して下さい。
ファクトリはDBで提供されている場合もあるかもしれませんが
Tomcat付属のBasicDataSourceFactoryを使った方が確実でしょう。
通常のjdbcドライバならば、接続URLにクエリーを指定することで
接続情報をカスタマイズできます。
その際に注意する事が一つ。「&」はXMLでは特殊文字になるので
「&」にエスケープして記述しなければなりません。
MySQLでの記述例が <ここ> にあるので参考にして下さい。
これだけではまだアプリケーションからDBにアクセスできないので
最後に各アプリケーションの WEB-INF/web.xml に記述します。
<web-app> <description>MySQL Test App</description> <resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/TestDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app>
res-ref-name要素の値は、server.xmlのResource要素に記述した名前に合わせます。
使用するDBのJDBCドライバを配置します。
配置場所は $TOMCAT_HOME/common/lib です。
配置したらTomcatを再起動する必要があります。
あとはプログラムを書くだけです。
Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/TestDB"); Connection conn = ds.getConnection();
この3行のうち、最初の2行は毎回行う必要はありません。
Webアプリケーションの場合、リクエストがある度に実行しなければならないのは
最後の1行だけです。
DataSourceクラスのインスタンスを何らかの共有メモリに保管しておけば、
そのインスタンスを使ってDB接続を得ることが出来ます。
取得したConnectionはロジックを抜ける前に必ずcloseして下さい。
そうしないとこの接続は接続プールに返されません。
Connectionのインスタンスをローカル変数で定義しても、
この変数はスコープを抜けた後も「生きて」います。
Tomcatは複数プロセスで稼働しているので、
メソッドのローカル変数が削除されるタイミングは
そのプロセスが消滅した時もしくは
そのプロセスに新たなリクエストが発生した場合に限られるからです。
conn = null;
と明示的に記述しても、状況はほとんど変わりません。
インスタンスにnullを代入しても、「そのインスタンスを消滅させる」訳ではなく
単に「そのインスタンスへの参照を解除する」に過ぎません。
つまり、このインスタンスが消滅するのは
次に発生するGC(ガーベッジ・コレクト)のタイミングになります。
GCはいつ発生するか判らないので、これに頼るべきではありません。
一番良いのは、サーブレットの基底クラスを作成して
基底クラス内のロジックでDB接続の制御をする事です。
こうすれば閉じ忘れもなくコードもすっきりします。
Tomcatに標準で付属しているWebアプリケーション・マネージャの使い方を紹介します。
名前が長いので、以下管理マネージャと略します。
管理マネージャはWebアプリケーションとして提供されています。
格納場所は $TOMCAT_HOME/server/webapp/manager
です。
Tomcatをインストールしてから特に設定をいじっていなければ、
この管理マネージャはコンテキストパス /manager
に結び付けられているはずです。
ブラウザから次のアドレスを直接入力してみて下さい。
http://localhost:8080/manager
「/ のディレクトリ一覧」という画面になっていれば成功です。
さてここで、管理マネージャを利用する為には設定ファイルを修正する必要があります。
上で指定したアドレスは、ファイアウォール等を敷いていなければ
外部からも直接参照できてしまう事を考えてみて下さい。
管理マネージャを利用する為にはユーザ認証を行う必要があるのです。
$TOMCAT_HOME/webapps/manager.xml
を見ると、
<ResourceLink name="users" global="UserDatabase" type="org.apache.catalina.UserDatabase"/>
という記述があります。
これは、このアプリケーションがユーザ認証を必要とすることを意味します。
さらに $TOMCAT_HOME/server/webapp/manager/WEB-INF/web.xml
を見れば
このアプリケーションを利用できるロール名が manager
という事がわかります。
ロールとは「権限」に似た概念のことです。
$TOMCAT_HOME/conf/tomcat-users.xml
というファイルをエディタで開いて下さい。
そしてその中に、
<user username="username" password="password" roles="manager"/>
という行を追加します。
イタリック体の部分には、あなたが実際に利用するユーザ名とパスワードを入れて下さい。roles="manager"
とすることで、
このユーザがmanagerロール(権限)を持つことを意味します。
編集が終わったら、このファイルを保存しましょう。
そしたら、Tocmatを再起動した後で次のアドレスをブラウザから打ち込んで下さい。
http://localhost:8080/manager/html
ユーザ名とパスワードを求めるウィンドウが現れたでしょうか。
ここに先程設定ファイルに記述したユーザ名とパスワードを入力します。
無事認証が成功すれば、「Tomcat Webアプリケーションマネージャ」という画面に移ります。
ここまでくれば、もはや説明の必要は無いでしょう。
各アプリケーションの起動、停止、再ロード、削除は
対応するリンクをクリックするだけでOKです。
開発中に重宝するのは再ロードでしょう。これでもう
サーブレットを追加したり、Strutsの設定ファイルを修正しただけで
Tomcatを再起動するような必要は無くなります。
ただし、この再起動の機能もまだ不十分な点が多いようです。
例えばアプリケーション毎のContext設定をserver.xmlから分離させている場合、
それを修正してアプリケーション再起動を行っても
その内容を再読込してくれません。
こういった状況では結局Tomcatの再起動が必要となってしまうのです。
この管理マネージャを使うと、Tomcatを起動した状態で
アプーケーションの追加と削除が行えます。
削除は画面上にリンクがあるのでそれをクリックするだけですので説明は要らないでしょう。
ここでは、任意のwarファイルを追加する方法を紹介します。
管理ページの下の方に「WARファイルのインストールアップロード」という項目があると思います。
そこの「アップロードするWARファイルの選択」から「参照」をクリックして
追加したいWARファイルを選択して下さい。
あとは「インストール」をクリックすればOKです。
このWARファイルは、ディレクトリ上のどこに存在しても構いません。
「インストール」する事によって、このファイルは $TOMCAT_HOME/webapps
ディレクトリ上にコピーされます。
さらに、設定ファイルserver.xmlのHost要素unpackWars属性がtrueになっていれば
このWARファイルがwebappsディレクトリ上に展開されるでしょう。