正 文

开发一个调试JSP的Eclipse插件


www.7dspace.com  更新日期:2006-2-7 19:45:17  七度空间


  JSR-45规范

  JSR-45(Debugging Support for Other Languages)为那些非 JAVA 语言写成,却需要编译成 JAVA 代码,运行在 JVM 中的程序,提供了一个进行调试的标准机制。也许字面的意思有点不好理解,什么算是非 JAVA 语言呢?其实 JSP 就是一个再好不过的例子,JSR-45 的样例就是一个 JSP。

  JSP的调试一直依赖于具体应用服务器的实现,没有一个统一的模式,JSR-45 针对这种情况,提供了一个标准的模式。我们知道,JAVA 的调试中,主要根据行号作为标志,进行定位。但是 JSP 被编译为 JAVA 代码之后,JAVA 行号与 JSP 行号无法一一对应,怎样解决呢?

  JSR-45 是这样规定的:JSP 被编译成 JAVA 代码时,同时生成一份 JSP 文件名和行号与 JAVA 行号之间的对应表(SMAP)。JVM 在接受到调试客户端请求后,可以根据这个对应表(SMAP),从 JSP 的行号转换到 JAVA 代码的行号;JVM 发出事件通知前, 也根据对应表(SMAP)进行转化,直接将 JSP 的文件名和行号通知调试客户端。

  我们用 Tomcat 5.0 做个测试,有两个 JSP,Hello.jsp 和 greeting.jsp,前者 include 后者。Tomcat会将他们编译成 JAVA 代码(Hello_jsp.java),JAVA Class(Hello_jsp.class) 以及 JSP 文件名/行号和 JAVA 行号之间的对应表(SMAP)。

  Hello.jsp:

          1    <HTML>
          2    <HEAD>
          3    <TITLE>Hello Example</TITLE>
          4    </HEAD>
          5    <BODY>
          6    <%@ include file="greeting.jsp" %>
          7    </BODY>
          8    </HTML>

  greeting.jsp:

1 Hello There!<P> 2 Goodbye on <%= new java.util.Date() %>

  JSP 编译后产生的Hello_jsp.java 如下:

Hello_jsp.java:
1      package org.apache.jsp;
2
3      import javax.servlet.*;
4      import javax.servlet.http.*;
5      import javax.servlet.jsp.*;
6
7      public final class Hello_jsp extends org.apache.jasper.runtime.HttpJspBase
8          implements org.apache.jasper.runtime.JspSourceDependent {
9
10        private static java.util.Vector _jspx_dependants;
11
12        static {
13          _jspx_dependants = new java.util.Vector(1);
14          _jspx_dependants.add("/greeting.jsp");
15        }
16
17        public java.util.List getDependants() {
18          return _jspx_dependants;
19        }
20
21  public void _jspService(HttpServletRequest request, HttpServletResponse response)
22              throws java.io.IOException, ServletException {
23
24          JspFactory _jspxFactory = null;
25          PageContext pageContext = null;
26          HttpSession session = null;
27          ServletContext application = null;
28          ServletConfig config = null;
29          JspWriter out = null;
30          Object page = this;
31          JspWriter _jspx_out = null;
32
33
34          try {
35            _jspxFactory = JspFactory.getDefaultFactory();
36            response.setContentType("text/html");
37            pageContext = _jspxFactory.getPageContext(this, request, response,
38               null, true, 8192, true);
39            application = pageContext.getServletContext();
40            config = pageContext.getServletConfig();
41            session = pageContext.getSession();
42            out = pageContext.getOut();
43            _jspx_out = out;
44
45            out.write("<HTML>    \r\n");
46            out.write("<HEAD>    \r\n");
47            out.write("<TITLE>Hello Example");
48            out.write("</TITLE>    \r\n");
49            out.write("</HEAD>    \r\n");
50            out.write("<BODY>    \r\n");
51            out.write("Hello There!");
52            out.write("<P>    \r\nGoodbye on ");
53            out.write(String.valueOf( new java.util.Date() ));
54            out.write("  \r\n");
55            out.write("    \r\n");
56            out.write("</BODY>    \r\n");
57            out.write("</HTML>  \r\n");
58          } catch (Throwable t) {
59            if (!(t instanceof javax.servlet.jsp.SkipPageException)){
60              out = _jspx_out;
61              if (out != null && out.getBufferSize() != 0)
62                out.clearBuffer();
63              if (pageContext != null) pageContext.handlePageException(t);
64            }
65          } finally {
66     if (_jspxFactory != null) _jspxFactory.releasePageContext ( pageContext);
67          }
68        }
69      }

  Tomcat 又将这个 JAVA 代码编译为 Hello_jsp.class,他们位于: $Tomcat_install_path$\work\Standalone\localhost\_ 目录下。但是 JSP 文件名/行号和 JAVA 行号的对应表(以下简称SMAP) 在哪里呢?答案是,它保存在 Class 中。如果用 UltraEdit 打开这个 Class 文件,就可以找到 SourceDebugExtension 属性,这个属性用来保存 SMAP。

  JVM 规范定义了 ClassFile 中可以包含 SourceDebugExtension 属性,保存 SMAP:

SourceDebugExtension_attribute {
  u2 attribute_name_index;
  u4 attribute_length;
  u1 debug_extension[attribute_length];
}

  我用 javassist 做了一个测试(javassist可是一个好东东,它可以动态改变Class的结构,JBOSS 的 AOP就利用了javassist,这里我们只使用它读取ClassFile的属性)

public static void main(String[] args) throws Exception{
   String[]files = {
   "E:\\Tomcat5_0_5\\work\\Catalina\\localhost\\_\\org\\apache\\jsp\\Hello_jsp.class",
   };

 for(int k = 0; k < files.length; k++){
    String file = files[k];
    System.out.println("Class : " + file);
    ClassFile classFile = new ClassFile(new DataInputStream(new FileInputStream(file))); 

    AttributeInfo attributeInfo = classFile.getAttribute("SourceDebugExtension");
    System.out.println("attribute name :" + attributeInfo.getName() + "]\n\n");
    byte[]bytes = attributeInfo.get();
    String str = new String(bytes);
    System.out.println(str);
   }
}

  这段代码显示了SourceDebugExtension 属性,你可以看到SMAP 的内容。编译JSP后,SMAP 就被写入 Class 中, 你也可以利用 javassist 修改 ClassFile 的属性。

  下面就是 Hello_jsp.class 中保存的 SMAP 内容:

SMAP
E:\Tomcat5_0_5\work\Catalina\localhost\_\org\apache\jsp\Hello_jsp.java
JSP
*S JSP
*F
+ 0 Hello.jsp
/Hello.jsp
+ 1 greeting.jsp
/greeting.jsp
*L
1:45
2:46
3:47
3:48
4:49
5:50
1#1:51
1:52
2:53
7#0:56
8:57
*E

  首先注明JAVA代码的名称:Hello_jsp.java,然后是 stratum 名称: JSP。随后是两个JSP文件的名称:Hello.jsp、greeting.jsp。两个JSP文件共10行,产生的Hello_jsp共69行代码。最后也是最重要的内容就是源文件文件名/行号和目标文件行号的对应关系(*L 与 *E之间的部分)

  在规范定义了这样的格式:

  源文件行号 # 源文件代号,重复次数 : 目标文件开始行号,目标文件行号每次增加的数量
(InputStartLine # LineFileID , RepeatCount : OutputStartLine , OutputLineIncrement)

  源文件行号(InputStartLine) 目标文件开始行号(OutputStartLine) 是必须的。下面是对这个SMAP具体的说明:

1:45  2:46  3:47  3:48  4:49  5:50(没有源文件代号,默认为Hello.jsp)
                   开始行号   结束行号
Hello.jsp:    1 ->  Hello_jsp.java:    45
              2 ->                     46
              3 ->                     47           48
              4 ->                     49
              5 ->                     50

1#1:51  1:52  2:53(1#1表示 greeting.jsp 的第1行)
greeting.jsp:    1 ->  Hello_jsp.java:       51           52
                 2 ->                     53  
        
7#0:56  8:57(7#0表示 Hello.jsp 的第7行)
Hello.jsp:     7 ->  Hello_jsp.java:       56
               8 ->                     57

5页,页码:[1] [2] [3] [4] [5] 

上一篇:Photoshop制作游戏角色像素图标
下一篇:VC中利用多线程技术实现线程之间的通信
标题:开发一个调试JSP的Eclipse插件 作者:焦烈焱 来源:ibm
收藏此页】【打印】【关闭
站 内 搜 索
 

热 点 导 读
特 别 推 荐