お仕事のヘルプでJSPをデバッグしたい(但しEclipse抜き)とのこと。
ということで、取り急ぎTomcatの環境と、JSPのデバッグ?できるような基本的なサンプルを用意してみる。先方の環境として、JDK1.4(1.3?)、Tomcat4(多分、4)とのことなので、取り急ぎ合わせる。
| OS | TurboLinux 10 Server |
| Java | J2SDK 1.4.2_13 |
| Tomcat | 4.1.34 |
本筋と関係のないディレクトリは省いている。とりあえずで良いので、ユーザは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/
動けば良いので、webapps/以下に直接rootユーザーで作ってしまう。
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF8">
<title>test</title>
</head>
<body>
<%-- 変数xを宣言 --%>
<%! int x = 0; %>
<%-- スクリプトレット内でforループ処理を実行 --%>
<%
for (int i = 0; i < 10; i++) {
x++;
System.out.println("i=[" + i + "]");
System.out.println("x=[" + x + "]");
}
%>
<%-- 式で実行結果を表示 --%>
<H3>計算結果:<%= x %></H3>
</body>
</html>
<?xml version="1.0" ?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
</web-app>
以下の様に、各WebApps毎にディレクトリが自動作成され、保存される。
TOMCAT_HOME/work/Standalone/localhost/
admin/...
manager/...
test/ ←今回作成したWebapp用
index_jsp.java
index_jsp.java
なお、JSPコンパイルディレクトリは<Context>タグの"workDir"属性で変更することができる。 その場合、workDirで指定されたディレクトリにJSPがコンパイルされ、出力される。(*1)
Tomcatといえども基本はJVMに他ならない。従ってJDBのリモートデバッグが可能である。javaコマンドのオプションとして、リモートデバッグオプションを追加し、リモートのJDB(およびその互換デバッグクライアント:Eclipse, NetBeansなど)からのデバッグ接続を受け付けるようにする。
参考HP
では、このデバッグオプションを追加してTomcatを起動するにはどうすればよいか?まず、Tomcatの起動・停止のコアであるcatalina.sh(.bat)を参照する。
TOMCAT_HOME/bin/catalina.sh
# 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
以下、駆け足で上記までに整えた環境でJSPを、JDBでデバッグしてみる。
JDBはJavaSDKに付属するコマンドラインデバッガである。詳細は下記URL参照。
http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/tooldocs/solaris/jdb.html
なお、JDBはJVMへの接続に数種類の方法をサポートしている。この箇所だけ事情によりJDK1.5の説明になってしまうが、
$ jdb -listconnectors
でサポートされている接続方法(Connectorと呼ぶ)と、使用可能なパラメータの説明が表示される。共有メモリ経由の接続もあるようで、興味深い。
今回、TomcatがコンパイルしたJSPをデバッグするに辺り、トラブルになった箇所がある。この点もまとめると、以下のような手順で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 -attach 9000 <<< 今回は9000でデバッグポートをLISTENしている。 > use /tmp > stop in org.apache.jsp.index_jsp._jspService
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;
本文中でも挙げたが、Tomcat4.1.34の場合、コンパイルされたJSPがworkDirの直下にできてしまい、パッケージ名とのズレが発生した。 ところが、他で使用しているTomcat 5.5.17 の場合は問題なく org/apache/jsp ディレクトリが作成され、その中にできていた。
実際のところはTomcatで使用されているJasper(JSPコンパイラ)周りのコードを紐解く必要がある。時間の都合上今はできないが、少なくともメジャーバージョン間ではいろいろ変わっているのかも知れない。(*3)
また、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設定についての本家ドキュメントへのリンクを示す。