当前页面: 开发资料首页 → JSP 专题 → 开发一个调试JSP的Eclipse插件
摘要: 开发一个调试JSP的Eclipse插件
本文通过开发一个JSP 编辑器插件的示例,介绍了 Eclipse 中设置 JSP 断点的方法,以及如何远程调试 JSP。作为基础知识,本文的前两部分描述了 JAVA Debug 和 JSR-45 的基本原理。
环境要求: 本文的代码是在 Eclipse3.0.0,JDK1.4.2 和 Tomcat5.0.5 上测试过的。
JAVA 调试框架(JPDA)简介
JPDA 是一个多层的调试框架,包括 JVMDI、JDWP、JDI 三个层次。JAVA 虚拟机提供了 JPDA 的实现。其开发工具作为调试客户端,可以方便的与虚拟机通讯,进行调试。Eclipse 正是利用 JPDA 调试 JAVA 应用,事实上,所有 JAVA 开发工具都是这样做的。SUN JDK 还带了一个比较简单的调试工具以及示例。
-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n -Xrunjdwp JVM 加载 jdwp.dll transport=dt_socket 使用 Socket 传输 address 表示调试端口号 server=y 表示 JVM 作为服务器,建立 Socket suspend=n 表示启动过程中,JVM 不会挂起去等待调试客户端连接
Components Debugger Interface / |-----------------------| / | VM | debuggee ----( |-----------------------| <------- JVMDI - Java VM Debug Interface \ | back-end | \ |-----------------------| / | comm channel -( | <--------------- JDWP - Java Debug Wire Protocol \ | |---------------------| | front-end | |---------------------| <------- JDI - Java Debug Interface | UI | |---------------------|
com.sun.jdi com.sun.jdi.connect com.sun.jdi.event com.sun.jdi.request本文不对 JDI 进行深入阐述,这里重点介绍 JDI 中与断点相关的接口。
1 2 <head> 3Hello Example 4 </head> 5 <body> 6 <%@ include file="greeting.jsp" %> 7 </body> 8
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(" \r\n"); 46 out.write("<head> \r\n"); 47 out.write("Hello Example"); 48 out.write(" \r\n"); 49 out.write("</head> \r\n"); 50 out.write("<body> \r\n"); 51 out.write("Hello There!"); 52 out.write("\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(" \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 }
SourceDebugExtension_attribute { u2 attribute_name_index; u4 attribute_length; u1 debug_extension[attribute_length]; }
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); } }
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
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开发一个JSP编辑器
public class ManageBreakpointRulerActionDelegate extends AbstractRulerActionDelegate{ protected IAction createAction(ITextEditor editor, IVerticalRulerInfo rulerInfo) { return new ManageBreakpointRulerAction(rulerInfo, editor); } }
public class ManageBreakpointRulerAction extends Action implements IUpdate{ private IVerticalRulerInfo rulerInfo; private ITextEditor textEditor; private String BPmarkerType ; //当点Marker的类型 private List allMarkers; //当前鼠标点击行所有的Marker private String addBP; //Action 的显示名称 public ManageBreakpointRulerAction(IVerticalRulerInfo ruler, ITextEditor editor){ this.rulerInfo = ruler; this.textEditor = editor; BPmarkerType = IBreakpoint.BREAKPOINT_MARKER; addBP = "添加/删除断点"; //$NON-NLS-1$ setText(this.addBP); } public void update() { this.allMarkers = this.fetchBPMarkerList(); } public void run(){ if(this.allMarkers.isEmpty()) this.addMarker(); else this.removeMarkers(this.allMarkers); } }
ManageBreakpointRulerAction.update() line: 55 ManageBreakpointRulerActionDelegate(AbstractRulerActionDelegate).update() line: 114 ManageBreakpointRulerActionDelegate(AbstractRulerActionDelegate).mouseDown(MouseEvent) line: 139
protected void addMarker() { IEditorInput editorInput= this.getTextEditor().getEditorInput(); IDocument document= this.getDocument(); //the line number of the last mouse button activity int rulerLine= this.getRulerInfo().getLineOfLastMouseButtonActivity(); try{ int lineNum = rulerLine + 1; if(lineNum > 0){ //Returns a description of the specified line IRegion iregion = document.getLineInformation(lineNum - 1); int charStart = iregion.getOffset(); int charEnd = (charStart + iregion.getLength()) - 1; JSPDebugUtility.createJspLineBreakpoint(this.getResource(), lineNum, charStart, charEnd); } }catch(CoreException coreexception){ coreexception.printStackTrace(); } catch(BadLocationException badlocationexception){ badlocationexception.printStackTrace(); } }
public class JSPBreakpoint extends JavaStratumLineBreakpoint { public JSPBreakpoint(IResource resource, String stratum, String sourceName, String sourcePath, String classNamePattern, int lineNumber, int charStart, int charEnd, int hitCount, boolean register, Map attributes) throws DebugException { super(resource, stratum, sourceName, sourcePath, classNamePattern, lineNumber, charStart, charEnd, hitCount, register, attributes); } }
IWorkspaceRunnable wr= new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) throws CoreException { // create the marker setMarker(resource.createMarker(markerType)); // modify pattern String pattern = classNamePattern; if (pattern != null && pattern.length() == 0) { pattern = null; } // add attributes addLineBreakpointAttributes(attributes, getModelIdentifier(), true, lineNumber, charStart, charEnd); addStratumPatternAndHitCount(attributes, stratum, sourceName, sourcePath, pattern, hitCount); // set attributes ensureMarker().setAttributes(attributes); register(register); } }; run(null, wr); protected void register(boolean register) throws CoreException { if (register) { DebugPlugin.getDefault().getBreakpointManager().addBreakpoint(this); } else { setRegistered(false); } }
breakpointManager = DebugPlugin.getDefault().getBreakpointManager(); IBreakpoint breakpoint = breakpointManager.getBreakpoint(IMarker); breakpointManager.removeBreakpoint(breakpoint, true);
public void addToTarget(JDIDebugTarget target) throws CoreException { IMarker marker = this.getMarker(); IResource resource = marker.getResource(); String targetString = target.getLaunch().getLaunchConfiguration().getName(); IJSPNameUtil util = JSPDebugUtility.getJSPNameUtil(targetString); // pre-notification fireAdding(target); String referenceTypeName; try { referenceTypeName = getPattern(); //如果没有设置 Pattern, 根据 Server 的类型, 产生新的 Pattern if(referenceTypeName == null || "".equals(referenceTypeName.trim()) || "*".equals(referenceTypeName.trim())){ referenceTypeName = util.referenceTypeName(resource); } } catch (CoreException e) { JDIDebugPlugin.log(e); return; } this.ensureMarker().setAttribute(TYPE_NAME, referenceTypeName); String sourcePath = util.sourcePath(resource); this.ensureMarker().setAttribute(JSPBreakpoint.SOURCE_PATH, sourcePath); String classPrepareTypeName= referenceTypeName; //如果这时 class 还没有被加载, 注册一个 ClassPrepareRequest 请求 // //当 class 加载的时候, 首先会触发 JavaBreakpoint 的 handleClassPrepareEvent 方法 //调用 createRequest(target, event.referenceType()) newRequest() // createLineBreakpointRequest() 创建 enable或disable 断点的请求 // // 设置 enable/disable 动作在 configureRequest() updateEnabledState(request) 方法中 // 根据 getMarker().getAttribute(ENABLED, false) 确定断点是否有效 registerRequest(target.createClassPrepareRequest(classPrepareTypeName), target); // create breakpoint requests for each class currently loaded VirtualMachine vm = target.getVM(); if (vm == null) { target.requestFailed("Unable_to_add_breakpoint_-_VM_disconnected._1"), null); } List classes = null; try { classes= vm.allClasses(); } catch (RuntimeException e) { target.targetRequestFailed("JavaPatternBreakpoint.0"), e); } if (classes != null) { Iterator iter = classes.iterator(); while (iter.hasNext()) { ReferenceType type= (ReferenceType)iter.next(); if (installableReferenceType(type, target)) { createRequest(target, type); } } } }调试JSP
D:\j2sdk1.4.2\bin\java -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=8888,server=y,
suspend=n -Djava.endorsed.dirs="..\common\endorsed" -classpath "D:\j2sdk1.4.2\lib\tools.jar;..\bin\bootstrap.jar" -Dcatalina.base=".." -Dcatalina.home=".." -Djava.io.tmpdir="..\temp" org.apache.catalina.startup.Bootstrap start