#navi_header|技術|
お仕事のヘルプでJSPをデバッグしたい(但しEclipse抜き)とのこと。
ということで、取り急ぎTomcatの環境と、JSPのデバッグ?できるような基本的なサンプルを用意してみる。先方の環境として、JDK1.4(1.3?)、Tomcat4(多分、4)とのことなので、取り急ぎ合わせる。
| OS | TurboLinux 10 Server |
| Java | J2SDK 1.4.2_13 |
| Tomcat | 4.1.34 |
* Tomcat 環境
本筋と関係のないディレクトリは省いている。とりあえずで良いので、ユーザはrootで、いい加減でも動けば良いみたいなノリ。
/opt/in_vitro/apps/apache-tomcat-4.1.34/ ... 以降、TOMCAT_HOME
bin/ ... 起動・停止シェルスクリプト
conf/ ... XML設定ファイル
logs/
catalina.out ... System.out, System.err (標準出力・標準エラー出力)のダンプ
localhost_****.YYYY-MM-DD.txt
... TomcatのLoggerおよび各App毎のLoggerの出力するログファイル?
webapps/
... Tomcatが自動ロードしてくれるWebappのディレクトリ
work/
... JSPコンパイルディレクトリ他、Tomcatが汎用的に使用するテンポラリディレクトリ
Standalone/
localhost/
* JSPサンプル
動けば良いので、webapps/以下に直接rootユーザーで作ってしまう。
- 配置ディレクトリ
-- TOMCAT_HOME/webapps/test
- JSP
-- TOMCAT_HOME/webapps/test/index.jsp
test
<%-- 変数xを宣言 --%>
<%! int x = 0; %>
<%-- スクリプトレット内でforループ処理を実行 --%>
<%
for (int i = 0; i < 10; i++) {
x++;
System.out.println("i=[" + i + "]");
System.out.println("x=[" + x + "]");
}
%>
<%-- 式で実行結果を表示 --%>
計算結果:<%= x %>
-- TOMCAT_HOME/webapps/test/WEB-INF/web.xml
- 出力
-- 画面上には太字で「計算結果:10」と出力される。
-- TOMCAT_HOME/logs/catalina.out に、"i=..."と"x=..."が出力される。
* コンパイルされたJSPはどこか?
以下の様に、各WebApps毎にディレクトリが自動作成され、保存される。
TOMCAT_HOME/work/Standalone/localhost/
admin/...
manager/...
test/ ←今回作成したWebapp用
index_jsp.java
index_jsp.java
'' なお、JSPコンパイルディレクトリはタグの"workDir"属性で変更することができる。 '' その場合、workDirで指定されたディレクトリにJSPがコンパイルされ、出力される。((デフォルトではTomcatは.javaファイルは削除しないようである。WebLogicの場合、デフォルトでは削除されてしまう為、web.xml/weblogic.xmlなどで固有の設定を行う必要があった。))
* Tomcatをデバッグ用に起動
Tomcatといえども基本はJVMに他ならない。従ってJDBのリモートデバッグが可能である。javaコマンドのオプションとして、リモートデバッグオプションを追加し、リモートのJDB(およびその互換デバッグクライアント:Eclipse, NetBeansなど)からのデバッグ接続を受け付けるようにする。
参考HP
- http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/tooldocs/solaris/jdb.html (JDK1.4用)
- http://muimi.com/j/jboss/jdb/
- http://www.asahi-net.or.jp/~DP8T-ASM/java/tips2/jdb/HelloWorld_ja.html
では、このデバッグオプションを追加してTomcatを起動するにはどうすればよいか?まず、Tomcatの起動・停止のコアであるcatalina.sh(.bat)を参照する。
TOMCAT_HOME/bin/catalina.sh
- 冒頭で、JAVA_OPTSという環境変数を参照していることが分かる。
# JAVA_OPTS (Optional) Java runtime options used when the "start",
# "stop", or "run" command is executed.
- 実際に起動・停止している部分が下部にある。
elif [ "$1" = "start" ] ; then
shift
touch "$CATALINA_OUT"
if [ "$1" = "-security" ] ; then
echo "Using Security Manager"
shift
"$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
-Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
-Djava.security.manager \
-Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMPDIR" \
org.apache.catalina.startup.Bootstrap "$@" start \
>> "$CATALINA_OUT" 2>&1 &
以上より、予めJAVA_OPTSという環境変数を設定しておくことで、javaコマンドに任意のオプションを渡せることが分かった。
以下に示すとおり、実験してみる。
# JAVA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=9000,server=y,suspend=n"
←デバッグを有効にし(-Xdebug)、TCPソケットで、ポート番号9000で受け付ける(-Xrunjdwp:...)。
# export JAVA_OPTS
# echo $JAVA_OPTS
-Xdebug -Xrunjdwp:transport=dt_socket,address=9000,server=y,suspend=n
# cd ${TOMCAT_HOME}
# ./bin/startup.sh
Using CATALINA_BASE: /opt/in_vitro/apps/apache-tomcat-4.1.34
Using CATALINA_HOME: /opt/in_vitro/apps/apache-tomcat-4.1.34
Using CATALINA_TMPDIR: /opt/in_vitro/apps/apache-tomcat-4.1.34/temp
Using CATALINA_OUT: /opt/in_vitro/apps/apache-tomcat-4.1.34/logs/catalina.out
Using JAVA_HOME: /opt/in_vitro/apps/jdk1.4
psコマンドおよびnetstatコマンドで確認してみると、javaが上り、デバッグポートで指定した9000番をlistenしているのが分かる。
# ps a
...
2431 pts/0 S 0:06 /opt/in_vitro/apps/jdk1.4/bin/java -Xdebug -Xrunjdwp transport=dt_socket,address=9000,server=
# netstat -npl -t
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:8005 0.0.0.0:* LISTEN 2431/java
tcp 0 0 0.0.0.0:9000 0.0.0.0:* LISTEN 2431/java <<< デバッグポート
tcp 0 0 0.0.0.0:8009 0.0.0.0:* LISTEN 2431/java
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 2431/java
* JDBでJSPをデバッグ
以下、駆け足で上記までに整えた環境でJSPを、JDBでデバッグしてみる。
JDBはJavaSDKに付属するコマンドラインデバッガである。詳細は下記URL参照。
http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/tooldocs/solaris/jdb.html
** 簡易かつ一般的なJDBによるコマンドラインデバッグ手順
+ jdbでローカル又はリモートのJVMに接続する。
++ ローカルの場合は、コマンドラインオプションから "-attach " のように、単純にローカルJVMがLISTENしているポート番号を指定する。
++ リモートの場合は、コマンドラインオプションから "-connect com.sun.jdi.SocketAttach:hostname=,port=" のように、でリモートマシンのIPアドレスを指定し、でデバッグソケットをLISTENしているポート番号を指定する。
+ "use "か、JDB起動時に"-sourcepath "としてデバッグしたいクラスに対応するソースディレクトリの位置を指定する。
+ "stop in ."や"stop at"をしてブレークポイントを仕掛ける。
+ アプリを動かす。
+ ブレークポイントで止まると、その旨JDBのコマンドラインに表示される。
+ 以降、"list", "next", "continue", "dump", "where" などのコマンドを用いデバッグしていく。
+ 終了は"quit"
なお、JDBはJVMへの接続に数種類の方法をサポートしている。この箇所だけ事情によりJDK1.5の説明になってしまうが、
$ jdb -listconnectors
でサポートされている接続方法(Connectorと呼ぶ)と、使用可能なパラメータの説明が表示される。共有メモリ経由の接続もあるようで、興味深い。
** TomcatがコンパイルしたJSPのデバッグ
今回、TomcatがコンパイルしたJSPをデバッグするに辺り、トラブルになった箇所がある。この点もまとめると、以下のような手順でJSPをデバッグした。
+ まず、非常に重要な注意点として、 '' TomcatはJSPを一括して"org.apache.jsp"パッケージ配下としてコンパイルする '' 点に注意する。
++ しかしながら、Tomcat4( '' 付記参照 '' )はJSPファイルを TOMCAT_HOME/work/Standalone/localhost/(webappname)/ の直下にコンパイルする。
++ '' →つまり、パッケージ名とディレクトリ構造がずれてしまっている。 '' ((先ほどの例だと、index.jspは org.apache.jsp.index_jsp クラスになるが、どこにも org/apache/jsp といったディレクトリ構造は作成されていない。))
++ 従って、以下の様に、workディレクトリに対するシンボリックリンクを作成し、"org/apache/jsp"ディレクトリのように見せかける必要がある。
# cd /tmp
# mkdir -p org/apache
# ln -s /tmp/org/apache/jsp /opt/in_vitro/apps/apache-tomcat-4.1.34/work/Standalone/localhost/test
+ 上記のようなディレクトリ処理を行った後、以下の様にJDBを起動し、TomcatのJVMにアタッチする。
$ jdb -attach 9000 <<< 今回は9000でデバッグポートをLISTENしている。
> use /tmp
> stop in org.apache.jsp.index_jsp._jspService
+ Webからアクセスすると、途中で止まり以下のようになる。
Breakpoint hit: "thread=http-8080-Processor3", org.apache.jsp.index_jsp._jspService(), line=21 bci=0
http-8080-Processor3[1] list <<< "list"と入力しENTER
17
18 public void _jspService(HttpServletRequest request, HttpServletResponse response)
19 throws java.io.IOException, ServletException {
20
21 => JspFactory _jspxFactory = null;
22 javax.servlet.jsp.PageContext pageContext = null;
23 HttpSession session = null;
24 ServletContext application = null;
25 ServletConfig config = null;
26 JspWriter out = null;
+ 後はJDBのデバッグコマンドでデバッグし、デバッグを終了したいとき(プロセスからデタッチしたいとき)は"quit"コマンドを実行する。
** 付記:TomcatのJSPコンパイラについて
本文中でも挙げたが、Tomcat4.1.34の場合、コンパイルされたJSPがworkDirの直下にできてしまい、パッケージ名とのズレが発生した。 '' ところが、他で使用しているTomcat 5.5.17 の場合は問題なく org/apache/jsp ディレクトリが作成され、その中にできていた。 ''
実際のところはTomcatで使用されているJasper(JSPコンパイラ)周りのコードを紐解く必要がある。時間の都合上今はできないが、少なくともメジャーバージョン間ではいろいろ変わっているのかも知れない。((もっとも、自分の経験上は少なくとも5.5.x以上を使用すればディレクトリの問題は解消されるようである。))
また、JSPのデバッグを行う場合にはJSPのコンパイル自体をdebugモードONで行わせる必要がある。また、メソッド内のローカル変数を表示させたい場合、javacで"-g"オプション付きでコンパイルされている必要がある。
Tomcat4の場合はデフォルトでその辺りのデバッグオプションが有効化されているようである。また、TOMCAT_HOME/conf/web.xmlの設定によりデバッグオプションを無効化したり、JSPファイルのポーリング周りについても調整可能らしい。
以下に、Tomcat4.x/5.0.x/5.5.x/6.0.x でのJSP設定についての本家ドキュメントへのリンクを示す。
- Tomcat4.x : http://tomcat.apache.org/tomcat-4.1-doc/jasper-howto.html
- Tomcat5.0.x : http://tomcat.apache.org/tomcat-5.0-doc/jasper-howto.html
- Tomcat5.5.x : http://tomcat.apache.org/tomcat-5.5-doc/jasper-howto.html
- Tomcat6.0.x : http://tomcat.apache.org/tomcat-6.0-doc/jasper-howto.html
#navi_footer|技術|