jpdadebugger.java

来自「JAVA Servlet2.3外文书籍源码」· Java 代码 · 共 244 行

JAVA
244
字号
package debugging;

import com.sun.jdi.Bootstrap;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.StackFrame;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.VirtualMachine;

import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.Connector;

import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventIterator;
import com.sun.jdi.event.EventQueue;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.event.MethodEntryEvent;

import com.sun.jdi.request.EventRequestManager;
import com.sun.jdi.request.MethodEntryRequest;

import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;

/**
 * A class to trace method invocations in a remote VM
 */
public class JPDADebugger {
  private static int SOCKET_ATTACH = 1;
  private VirtualMachine vm = null;
  private boolean running;
  
  /**
   * The main() method processes the command line arguments then calls
   * execute().
   */
  public static void main(String args[]) {
    // Stores the address of the remote VM
    String attachAddress = null;
    // Stores the classes to watch
    Vector includeClasses = new Vector();    

    // Handle the command line arguments
    for (int i=0; i<args.length; i++) {
      String thisArg = args[i];
      if ("-attach".equals(thisArg.toLowerCase())) { 
        attachAddress=args[++i];
      } 
      else if ("-include".equals(thisArg.toLowerCase())) {
        String incString = args[++i];
        StringTokenizer st = new StringTokenizer(incString, ":", false);
        while (st.hasMoreTokens()) {
          String thisOne = st.nextToken();
          System.out.println("including " + thisOne);
          includeClasses.addElement(thisOne);
        }
      }
    }
    
    // Create an instance of this class and try to execute it
    JPDADebugger thisDebugger = new JPDADebugger();
    try {
      thisDebugger.execute(attachAddress,includeClasses);
    } catch (Exception ex) { 
      ex.printStackTrace();
    }
  }
   
  /** 
   * In this method we attach to the remote VM and go into a loop
   * waiting for debug events.
   */
  public void execute(String attachAddress, Vector includeClasses) 
    throws Exception {
    if (includeClasses==null) {
      includeClasses=new Vector();
    }
    // Initialize these to dummy values
    String connectorName = null;
    int connectType = -1;
    String connectHost = null;
    String connectPort = null;

    // Get the host and port of the target VM
    if (attachAddress!=null) {
      connectorName = "com.sun.jdi.SocketAttach";
      connectType = SOCKET_ATTACH;
      int index = attachAddress.indexOf(":");
      connectHost = attachAddress.substring(0, index);
      connectPort = attachAddress.substring(index + 1);
    } else {
      throw new Exception ("ERROR: No attach address specified");
    }

    // Look for a suitable connector
    Connector connector = null;
    List connectors = Bootstrap.virtualMachineManager().allConnectors();
    Iterator iter=connectors.iterator();
    while (iter.hasNext()) {
      Connector thisConnector=(Connector)iter.next();
      if (thisConnector.name().equals(connectorName)) {
        connector=thisConnector;
      }
    }

    // If we didn't find one throw an exception
    if (connector==null) {
      throw new Exception ("ERROR: No connector with name " + connectorName);
    }

    // Set the host and port arguments of the connector
    Map arguments=connector.defaultArguments();
    Connector.Argument hostname = (Connector.Argument) arguments.get("hostname");
    Connector.Argument port = (Connector.Argument) arguments.get("port");
    hostname.setValue(connectHost);
    port.setValue(connectPort);
    
    // Cast the connector as AttachingConnector and try to attach
    // to the remote VM
    AttachingConnector attacher=(AttachingConnector) connector;
 
    vm = null;
    try {
      vm=attacher.attach(arguments);
    } catch (Exception e) {
      e.printStackTrace();
      throw new Exception ("ERROR: " + e + " @ attempting socket attach.");
    }

    // If we can't get hold of the remote VM throw an exception
    if (vm==null) {
      throw new Exception ("ERROR: No VM process connected.");
    }

    // Get the VM's EventRequestManager and add a MethodEntryRequest
    // with a filter for each included class
    EventRequestManager em = vm.eventRequestManager();
    for (Enumeration e=includeClasses.elements(); e.hasMoreElements(); ) {
      MethodEntryRequest meR=em.createMethodEntryRequest();
      String pattern=(String) e.nextElement();
      meR.addClassFilter(pattern);
      meR.enable();
    }

    // Get hold of the VM event queue
    EventQueue eventQ = vm.eventQueue();

    // Loop continually, waiting for events
    running = true;
    while (running) {
      // -- try to pop a set of events from the loop
      EventSet eventSet = null;
      try {
        eventSet = eventQ.remove();
      } catch (Exception e) {
        System.err.println("ERROR: Interrupted Event Loop");
        e.printStackTrace();
      }

      // Step through the events and proces each one
      EventIterator eventIterator = eventSet.eventIterator();
      while (eventIterator.hasNext()) {
        Event event=eventIterator.nextEvent();
        if (event instanceof MethodEntryEvent) {
          processMethodEntryEvent((MethodEntryEvent)event);
        }
      }

      // Tell the target VM to resume
      vm.resume();
    }
    System.out.close();
  }

  /**
   * This method is called for every MethodEntryEvent sent by the
   * target VM.
   */
   private void processMethodEntryEvent(MethodEntryEvent event)  {
    // What method was called?
    String methodString = event.method().toString();
    // What thread was it in ?
    ThreadReference thread = event.thread();
		
    // Get hold of the stack frames for this thread --
    List stackList=null;
    try {
      stackList=thread.frames();
    } catch (Exception e) {
      return;
    }

    // Initiallize the caller and callee information
    String calleeID = "?";
    String calleeClass = "?";
    String callerID = "?";
    String callerClass = "?";

    // Step through the stack frames
    int level = 0; 
    for (Iterator it=stackList.iterator(); it.hasNext();) {
      StackFrame stackFrame = (StackFrame) it.next();
      ObjectReference thisObject = stackFrame.thisObject();
      if (thisObject==null) {
        continue;
      }

      if (level==0) {
        calleeID=String.valueOf(thisObject.uniqueID());
        String classString = thisObject.referenceType().toString();
        StringTokenizer st = new StringTokenizer(classString, " ");
        calleeClass = st.nextToken();
        calleeClass = st.nextToken();
      } else if (level==1) {
        callerID = String.valueOf(thisObject.uniqueID());
        String classString = thisObject.referenceType().toString();
        StringTokenizer st = new StringTokenizer(classString, " ");
        callerClass = st.nextToken();
        callerClass = st.nextToken();
      }
      level++;
      if (level > 1) { 
        break;    
      }

    }

    // Print the result with tags
    System.out.println("<invocation><sender>" +
                       callerID+":"+callerClass +
                       "</sender><message>" +
                       methodString + 
                       "</message><receiver>" + 
                       calleeID + ":" + 
                       calleeClass + "</receiver><thread>" +
                       thread.name() + "</thread></invocation>");

  }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?