home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

技術/Java/Tomcat上でJSPをJDBでデバッグとか。

技術/Java/Tomcat上でJSPをJDBでデバッグとか。

技術 / Java / Tomcat上でJSPをJDBでデバッグとか。
id: 105 所有者: msakamoto-sf    作成日: 2007-02-25 15:13:44
カテゴリ: Java 

お仕事のヘルプで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
<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>
    • TOMCAT_HOME/webapps/test/WEB-INF/web.xml
<?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>
  • 出力
    • 画面上には太字で「計算結果: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コンパイルディレクトリは<Context>タグの"workDir"属性で変更することができる。 その場合、workDirで指定されたディレクトリにJSPがコンパイルされ、出力される。*1

Tomcatをデバッグ用に起動

Tomcatといえども基本はJVMに他ならない。従ってJDBのリモートデバッグが可能である。javaコマンドのオプションとして、リモートデバッグオプションを追加し、リモートのJDB(およびその互換デバッグクライアント:Eclipse, NetBeansなど)からのデバッグ接続を受け付けるようにする。

参考HP

では、このデバッグオプションを追加して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によるコマンドラインデバッグ手順

  1. jdbでローカル又はリモートのJVMに接続する。
    1. ローカルの場合は、コマンドラインオプションから "-attach <portno>" のように、単純にローカルJVMがLISTENしているポート番号を指定する。
    2. リモートの場合は、コマンドラインオプションから "-connect com.sun.jdi.SocketAttach:hostname=<ipaddr>,port=<portno>" のように、<ipaddr>でリモートマシンのIPアドレスを指定し、<port>でデバッグソケットをLISTENしているポート番号を指定する。
  2. "use <directory>"か、JDB起動時に"-sourcepath <directory>"としてデバッグしたいクラスに対応するソースディレクトリの位置を指定する。
  3. "stop in <full-package-class-name>.<method>"や"stop at"をしてブレークポイントを仕掛ける。
  4. アプリを動かす。
  5. ブレークポイントで止まると、その旨JDBのコマンドラインに表示される。
  6. 以降、"list", "next", "continue", "dump", "where" などのコマンドを用いデバッグしていく。
  7. 終了は"quit"

なお、JDBはJVMへの接続に数種類の方法をサポートしている。この箇所だけ事情によりJDK1.5の説明になってしまうが、

$ jdb -listconnectors

でサポートされている接続方法(Connectorと呼ぶ)と、使用可能なパラメータの説明が表示される。共有メモリ経由の接続もあるようで、興味深い。

TomcatがコンパイルしたJSPのデバッグ

今回、TomcatがコンパイルしたJSPをデバッグするに辺り、トラブルになった箇所がある。この点もまとめると、以下のような手順でJSPをデバッグした。

  1. まず、非常に重要な注意点として、 TomcatはJSPを一括して"org.apache.jsp"パッケージ配下としてコンパイルする 点に注意する。
    1. しかしながら、Tomcat4( 付記参照 )はJSPファイルを TOMCAT_HOME/work/Standalone/localhost/(webappname)/ の直下にコンパイルする。
    2. →つまり、パッケージ名とディレクトリ構造がずれてしまっている。 *2
    3. 従って、以下の様に、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
  1. 上記のようなディレクトリ処理を行った後、以下の様にJDBを起動し、TomcatのJVMにアタッチする。
$ jdb -attach 9000 <<< 今回は9000でデバッグポートをLISTENしている。
> use /tmp
> stop in org.apache.jsp.index_jsp._jspService
  1. 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;
  1. 後はJDBのデバッグコマンドでデバッグし、デバッグを終了したいとき(プロセスからデタッチしたいとき)は"quit"コマンドを実行する。

付記:TomcatのJSPコンパイラについて

本文中でも挙げたが、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設定についての本家ドキュメントへのリンクを示す。


*1: デフォルトではTomcatは.javaファイルは削除しないようである。WebLogicの場合、デフォルトでは削除されてしまう為、web.xml/weblogic.xmlなどで固有の設定を行う必要があった。
*2: 先ほどの例だと、index.jspは org.apache.jsp.index_jsp クラスになるが、どこにも org/apache/jsp といったディレクトリ構造は作成されていない。
*3: もっとも、自分の経験上は少なくとも5.5.x以上を使用すればディレクトリの問題は解消されるようである。

プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2009-04-04 10:21:35
md5:956fe56444bd1a9945fb9abd67bc577e
sha1:1b3132e0016bbd51c5bc9a8fae146d9f817de76d
コメント
コメントを投稿するにはログインして下さい。