正 文

开发一个调试JSP的Eclipse插件


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


  注册 JSP 断点为支持 JSR-45 规范,Eclipse 中提供了 JavaStratumLineBreakpoint。不过它目前是一个 internal 的实现,在以后的版本中不能保证不作修改。这里为了简单起见,直接从 JavaStratumLineBreakpoint 继承。

        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);
        }
    }

  查看 JavaStratumLineBreakpoint 的源代码可以知道,创建 JavaStratumLineBreakpoint 的时候做了两件事情:

  (1) 创建断点类型的 marker, 并且设置了marker的属性resource.createMarker(markerType);

  (2) 将断点注册到断点管理器

  DebugPlugin.getDefault().getBreakpointManager().addBreakpoint(this); 断点管理器负责产生一个 BreakpointRequest,通知正在运行的JVM Target 如果此时还没有启动 JVM,会在 JVM 启动的时候,将所有断点一起通知 JVM Target。

  下面是 JavaStratumLineBreakpoint 构造函数中的代码:

    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);
  }
 }

  移除断点的时候,根据 marker 找到相应的 IBreakpoint,从 BreakpointManager 中移除 BreakpointManager 会自动删除 marker,通知 JVM Target。

breakpointManager  = DebugPlugin.getDefault().getBreakpointManager();
IBreakpoint breakpoint = breakpointManager.getBreakpoint(IMarker);
breakpointManager.removeBreakpoint(breakpoint, true);

  JSPBreakpoint 重载了父类的addToTarget(JDIDebugTarget target) 方法。重载这个方法的目的是根据不同的应用服务器,设置不同的 referenceTypeName和sourcePath。我们知道,每种应用服务器编译 JSP 产生Java Class 名称的规则都不相同,例如Tomcat编译Hello.jsp 产生的Java 类名为 org.apache.jsp. Hello_jsp,而WebSphere6.0 却是 com.ibm._jsp._Hello。只有确定服务器类型,才能知道referenceTypeName 和souecePath应该是什么。目前通过启动 JVM 时target 名称来判断应用服务器类型: String targetString = target.getLaunch().getLaunchConfiguration().getName(); 如果targetString 包含 Tomcat ,就认为是 Tomcat。

  产生 referenceTypeName 后首先创建一个 ClassPrepareRequest 通知,然后从vm中取出所有的classes,如果是当前的 Class,再创建一个添加断点通知。之所以这样做,是因为有可能这个 Class 还没有被 JVM 加载,直接通知 JVM 没有任何意义。在 Class 被加载的时候,JVM 会通知 Eclipse,这个时候,才产生添加断点通知。需要指出的是,本文示例代码获取 referenceTypeName 的方法不是很完善:

  (1) 仅仅实现了Tomcat 读者有兴趣可以实现更多的Web容器,例如 JBoss3 以上,WebSphere6.0

  (2) 一些特殊情况没有处理例如 路径名为package的jsp,路径名或文件名带有数字的jsp

  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);
    }
   }
  }
 }

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

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

热 点 导 读
特 别 推 荐