Coverage Report - th.co.edge.jseq.EventThread
 
Classes in this File Line Coverage Branch Coverage Complexity
EventThread
0%
0/185
0%
0/78
0
EventThread$ThreadTrace
0%
0/93
0%
0/32
0
 
 1  
 /*
 2  
  * Copyright (c) 2003-2008, by Henrik Arro and Contributors
 3  
  *
 4  
  * This file is part of JSeq, a tool to automatically create
 5  
  * sequence diagrams by tracing program execution.
 6  
  *
 7  
  * See <http://jseq.sourceforge.net> for more information.
 8  
  *
 9  
  * JSeq is free software: you can redistribute it and/or modify
 10  
  * it under the terms of the GNU Lesser General Public License as
 11  
  * published by the Free Software Foundation, either version 3 of
 12  
  * the License, or (at your option) any later version.
 13  
  *
 14  
  * JSeq is distributed in the hope that it will be useful,
 15  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 17  
  * GNU Lesser General Public License for more details.
 18  
  *
 19  
  * You should have received a copy of the GNU Lesser General Public License
 20  
  * along with JSeq. If not, see <http://www.gnu.org/licenses/>.
 21  
  */
 22  
 
 23  
 package th.co.edge.jseq;
 24  
 
 25  
 import java.util.HashMap;
 26  
 import java.util.List;
 27  
 import java.util.Map;
 28  
 
 29  
 import com.sun.jdi.AbsentInformationException;
 30  
 import com.sun.jdi.IncompatibleThreadStateException;
 31  
 import com.sun.jdi.Location;
 32  
 import com.sun.jdi.Method;
 33  
 import com.sun.jdi.ReferenceType;
 34  
 import com.sun.jdi.ThreadReference;
 35  
 import com.sun.jdi.VMDisconnectedException;
 36  
 import com.sun.jdi.VirtualMachine;
 37  
 import com.sun.jdi.event.BreakpointEvent;
 38  
 import com.sun.jdi.event.ClassPrepareEvent;
 39  
 import com.sun.jdi.event.Event;
 40  
 import com.sun.jdi.event.EventIterator;
 41  
 import com.sun.jdi.event.EventQueue;
 42  
 import com.sun.jdi.event.EventSet;
 43  
 import com.sun.jdi.event.ExceptionEvent;
 44  
 import com.sun.jdi.event.LocatableEvent;
 45  
 import com.sun.jdi.event.MethodEntryEvent;
 46  
 import com.sun.jdi.event.MethodExitEvent;
 47  
 import com.sun.jdi.event.StepEvent;
 48  
 import com.sun.jdi.event.ThreadDeathEvent;
 49  
 import com.sun.jdi.event.VMDeathEvent;
 50  
 import com.sun.jdi.event.VMDisconnectEvent;
 51  
 import com.sun.jdi.event.VMStartEvent;
 52  
 import com.sun.jdi.request.BreakpointRequest;
 53  
 import com.sun.jdi.request.ClassPrepareRequest;
 54  
 import com.sun.jdi.request.EventRequest;
 55  
 import com.sun.jdi.request.EventRequestManager;
 56  
 import com.sun.jdi.request.ExceptionRequest;
 57  
 import com.sun.jdi.request.MethodEntryRequest;
 58  
 import com.sun.jdi.request.MethodExitRequest;
 59  
 import com.sun.jdi.request.StepRequest;
 60  
 import com.sun.jdi.request.ThreadDeathRequest;
 61  
 
 62  
 /**
 63  
  * An <code>EventThred</code> traces the execution of a Java process, keeping
 64  
  * track of all method calls as <code>Activation</code>s in an
 65  
  * <code>ActivationList</code> containing all root activations, that is, all
 66  
  * method calls that occur "magically" from outside the traced methods, for
 67  
  * example from the main method. Each Java thread is traced as a separate root
 68  
  * activation.
 69  
  */
 70  0
 public class EventThread extends Thread {
 71  
 
 72  
     private final VirtualMachine vm;
 73  
     private final ActivationList rootActivations;
 74  
     private final List<String> includes;
 75  
     private final List<String> excludes;
 76  
     private final List<String> boundaryMethods;
 77  
     private final boolean trace;
 78  
 
 79  
     private String startClassName;
 80  
     private String startMethodName;
 81  
 
 82  0
     private boolean connected = true;
 83  0
     private boolean vmDied = true;
 84  
 
 85  0
     private Map<ThreadReference, ThreadTrace> traceMap =
 86  
             new HashMap<ThreadReference, ThreadTrace>();
 87  
 
 88  
     /**
 89  
      * Creates a new <code>EventThread</code> that traces a given JDI
 90  
      * <code>VirtualMachine</code>, filling in a list of root activations.
 91  
      *
 92  
      * <p>
 93  
      * A list of included and excluded method names determine which methods to
 94  
      * trace. If the list of included method names is empty, all methods except
 95  
      * the excluded ones are traced, and correspondingly if the list of excluded
 96  
      * method name is empty. If both lists are non-empty, only the methods in
 97  
      * the included list are traced, except the ones in the excluded list.
 98  
      * Method names in the included and excluded lists can either be a fully
 99  
      * qualified method name, or a simple wild-card expression starting or
 100  
      * ending with "*".
 101  
      *
 102  
      * <p>
 103  
      * For example, if the included list contains "foo.Bar.*", and the excluded
 104  
      * list is empty, all methods in the class <code>foo.Bar</code> will be
 105  
      * traced. If the included list is empty and the excluded list contains
 106  
      * "java.*", everything but methods in the <code>java</code> package will
 107  
      * be traced. Finally, if the included list contains "foo.Bar.*" and the
 108  
      * excluded list contains "foo.Bar.baz", all methods in the class
 109  
      * <code>foo.Bar</code> will be traced, except for the method
 110  
      * <code>baz</code>.
 111  
      *
 112  
      * <p>
 113  
      * It is also possible to specify a list of boundary methods. A <it>bounday
 114  
      * method</it> is a method where tracing stops at entry to the method and
 115  
      * is resumed when the method exits. This list should contain fully
 116  
      * qualified method names, no wild-cards are accepted.
 117  
      *
 118  
      * <p>
 119  
      * For example, if the list of boundary methods contains "foo.Bar.baz",
 120  
      * tracing will include the call to <code>baz</code>, but no methods
 121  
      * called by <code>baz</code>. Normal tracing is resumed after
 122  
      * <code>baz</code> returns.
 123  
      *
 124  
      * @param vm
 125  
      *            the JDI <code>VirtualMachine</code>, a representation of
 126  
      *            the Java process to trace
 127  
      * @param rootActivations
 128  
      *            the list of root activations that will be filled in during the
 129  
      *            program trace
 130  
      * @param includes
 131  
      *            a list of method name pattern that will be included in the
 132  
      *            program trace, where name patterns may start or end with the
 133  
      *            wild-card "*"
 134  
      * @param excludes
 135  
      *            a list of method name patterns that will be excluded in the
 136  
      *            program trace, where name patterns may start or end with the
 137  
      *            wild-card "*"
 138  
      * @param boundaryMethods
 139  
      *            a list of boundary methods, methods where tracing will stop
 140  
      *            during the execution of the method
 141  
      * @param trace
 142  
      *            if <code>true</code> the program trace (method entry and
 143  
      *            exit, for example) will be echoed to <code>System.out</code>
 144  
      */
 145  
     public EventThread(VirtualMachine vm, ActivationList rootActivations,
 146  
             List<String> includes, List<String> excludes,
 147  
             List<String> boundaryMethods, boolean trace) {
 148  0
         super("event-handler");
 149  0
         this.vm = vm;
 150  0
         this.rootActivations = rootActivations;
 151  0
         this.includes = includes;
 152  0
         this.excludes = excludes;
 153  0
         this.trace = trace;
 154  0
         this.boundaryMethods = boundaryMethods;
 155  0
     }
 156  
 
 157  
     /**
 158  
      * Handles all events generated by JDI, running for as long as the Java
 159  
      * process is active, or until an attached process disconnects the event
 160  
      * thread.
 161  
      */
 162  
     @Override
 163  
     public void run() {
 164  0
         EventQueue queue = vm.eventQueue();
 165  0
         while (connected) {
 166  
             try {
 167  0
                 EventSet eventSet = queue.remove();
 168  0
                 EventIterator it = eventSet.eventIterator();
 169  0
                 while (it.hasNext()) {
 170  0
                     Event event = it.nextEvent();
 171  0
                     handleEvent(event);
 172  0
                 }
 173  0
                 eventSet.resume();
 174  0
             } catch (InterruptedException exc) {
 175  0
                 System.err.println(exc);
 176  0
             } catch (VMDisconnectedException discExc) {
 177  0
                 handleDisconnectedException();
 178  0
                 break;
 179  0
             } catch (NoSuchMethodException e) {
 180  0
                 e.printStackTrace();
 181  0
             }
 182  
         }
 183  0
     }
 184  
 
 185  
     /**
 186  
      * Creates all JDI event requests, that is, defines the set of events that
 187  
      * will be handled by this <code>EventThread</code>.
 188  
      *
 189  
      * @param startMethod
 190  
      *            the fully qualified name of the method where tracing should
 191  
      *            start, or <code>null</code> if tracing should start
 192  
      *            immediately
 193  
      */
 194  
     public void setEventRequests(String startMethod) {
 195  0
         EventRequestManager mgr = vm.eventRequestManager();
 196  
 
 197  0
         if (startMethod != null) {
 198  0
             setStartMethodBreakpoints(startMethod);
 199  
         } else {
 200  
 
 201  
             // I really, really, want to refactor this clumsy implementation by
 202  
             // calling a helper method, but this is difficult since the
 203  
             // different request types do not implement a common interface
 204  
             // defining the addClassFilter and addClassExclusionFilter methods.
 205  
 
 206  0
             if (includes.isEmpty()) {
 207  0
                 MethodEntryRequest menr = mgr.createMethodEntryRequest();
 208  0
                 for (String excludePattern : excludes) {
 209  0
                     menr.addClassExclusionFilter(excludePattern);
 210  
                 }
 211  0
                 enableRequest(menr);
 212  0
             } else {
 213  0
                 for (String includePattern : includes) {
 214  0
                     MethodEntryRequest menr = mgr.createMethodEntryRequest();
 215  0
                     menr.addClassFilter(includePattern);
 216  0
                     for (String excludePattern : excludes) {
 217  0
                         menr.addClassExclusionFilter(excludePattern);
 218  
                     }
 219  0
                     enableRequest(menr);
 220  0
                 }
 221  
             }
 222  
 
 223  0
             if (includes.isEmpty()) {
 224  0
                 MethodExitRequest mexr = mgr.createMethodExitRequest();
 225  0
                 for (String excludePattern : excludes) {
 226  0
                     mexr.addClassExclusionFilter(excludePattern);
 227  
                 }
 228  0
                 enableRequest(mexr);
 229  0
             } else {
 230  0
                 for (String includePattern : includes) {
 231  0
                     MethodExitRequest mexr = mgr.createMethodExitRequest();
 232  0
                     mexr.addClassFilter(includePattern);
 233  0
                     for (String excludePattern : excludes) {
 234  0
                         mexr.addClassExclusionFilter(excludePattern);
 235  
                     }
 236  0
                     enableRequest(mexr);
 237  0
                 }
 238  
             }
 239  
 
 240  0
             if (includes.isEmpty()) {
 241  0
                 ExceptionRequest exr =
 242  
                         mgr.createExceptionRequest(null, true, true);
 243  0
                 for (String excludePattern : excludes) {
 244  0
                     exr.addClassExclusionFilter(excludePattern);
 245  
                 }
 246  0
                 enableRequest(exr);
 247  0
             } else {
 248  0
                 for (String includePattern : includes) {
 249  0
                     ExceptionRequest exr =
 250  
                             mgr.createExceptionRequest(null, true, true);
 251  0
                     exr.addClassFilter(includePattern);
 252  0
                     for (String excludePattern : excludes) {
 253  0
                         exr.addClassExclusionFilter(excludePattern);
 254  
                     }
 255  0
                     enableRequest(exr);
 256  0
                 }
 257  
             }
 258  
 
 259  0
             ThreadDeathRequest tdr = mgr.createThreadDeathRequest();
 260  0
             enableRequest(tdr);
 261  
         }
 262  0
     }
 263  
 
 264  
     private void enableRequest(EventRequest request) {
 265  0
         request.setSuspendPolicy(EventRequest.SUSPEND_ALL);
 266  0
         request.enable();
 267  0
     }
 268  
 
 269  
     private void setStartMethodBreakpoints(String qualifiedMethodName) {
 270  0
         int lastDot = qualifiedMethodName.lastIndexOf('.');
 271  0
         if (lastDot < 0) {
 272  0
             String message =
 273  
                     "Not a qualified method name: \"" + qualifiedMethodName +
 274  
                             "\"";
 275  0
             throw new IllegalArgumentException(message);
 276  
         }
 277  0
         startClassName = qualifiedMethodName.substring(0, lastDot);
 278  0
         startMethodName = qualifiedMethodName.substring(lastDot + 1);
 279  
 
 280  0
         List<ReferenceType> startClasses = vm.classesByName(startClassName);
 281  0
         boolean methodFound = false;
 282  0
         for (ReferenceType refType : startClasses) {
 283  0
             List<Method> methods = refType.methodsByName(startMethodName);
 284  0
             if (!methods.isEmpty()) {
 285  0
                 setMethodBreakpoints(methods);
 286  0
                 methodFound = true;
 287  
             }
 288  0
         }
 289  0
         if (!methodFound) {
 290  0
             System.err.println("Start method not found: " +
 291  
                     qualifiedMethodName +
 292  
                     ". Waiting to see if the class will be loaded.");
 293  0
             EventRequestManager mgr = vm.eventRequestManager();
 294  0
             ClassPrepareRequest cpr = mgr.createClassPrepareRequest();
 295  0
             enableRequest(cpr);
 296  
         }
 297  0
     }
 298  
 
 299  
     private void setMethodBreakpoints(List<Method> methods) {
 300  0
         EventRequestManager mgr = vm.eventRequestManager();
 301  0
         for (Method method : methods) {
 302  
             try {
 303  0
                 Location location = method.allLineLocations().get(0);
 304  0
                 BreakpointRequest bpr = mgr.createBreakpointRequest(location);
 305  0
                 enableRequest(bpr);
 306  0
             } catch (AbsentInformationException e) {
 307  0
                 e.printStackTrace();
 308  0
             }
 309  
         }
 310  0
     }
 311  
 
 312  
     private void deleteAllEventRequests() {
 313  0
         EventRequestManager mgr = vm.eventRequestManager();
 314  0
         mgr.deleteEventRequests(mgr.methodEntryRequests());
 315  0
         mgr.deleteEventRequests(mgr.methodExitRequests());
 316  0
         mgr.deleteEventRequests(mgr.exceptionRequests());
 317  0
     }
 318  
 
 319  0
     private class ThreadTrace {
 320  
         private final ThreadReference thread;
 321  
 
 322  0
         private Activation currentActivation = null;
 323  
 
 324  
         private String currentBoundaryMethod;
 325  
 
 326  0
         private boolean stopWhenActivationDone = false;
 327  
 
 328  0
         public ThreadTrace(ThreadReference thread) {
 329  0
             this.thread = thread;
 330  0
             trace("====== " + thread.name() + " ======");
 331  0
         }
 332  
 
 333  
         private void classPrepareEvent(ClassPrepareEvent event)
 334  
                 throws NoSuchMethodException {
 335  0
             if (event.referenceType().name().equals(startClassName)) {
 336  0
                 List<Method> methods =
 337  
                         event.referenceType().methodsByName(startMethodName);
 338  0
                 if (methods.isEmpty()) {
 339  0
                     throw new NoSuchMethodException(startClassName + "." +
 340  
                             startMethodName);
 341  
                 }
 342  0
                 setMethodBreakpoints(methods);
 343  
             }
 344  0
         }
 345  
 
 346  
         private void methodEntryEvent(MethodEntryEvent event) {
 347  0
             String className = getClassName(event);
 348  0
             Method method = event.method();
 349  0
             List<String> argumentTypeNames = event.method().argumentTypeNames();
 350  0
             if (isBoundaryMethod(event)) {
 351  0
                 deleteAllEventRequests();
 352  0
                 currentBoundaryMethod = className + "." + method.name();
 353  0
                 EventRequestManager mgr = vm.eventRequestManager();
 354  0
                 MethodExitRequest methodExitRequest =
 355  
                         mgr.createMethodExitRequest();
 356  0
                 enableRequest(methodExitRequest);
 357  
             }
 358  0
             methodEntry(className, method, argumentTypeNames);
 359  0
         }
 360  
 
 361  
         private boolean isBoundaryMethod(MethodEntryEvent event) {
 362  0
             String className = getClassName(event);
 363  0
             String methodName = event.method().name();
 364  0
             String qualifiedMethodName = className + "." + methodName;
 365  0
             for (String boundaryMethod : boundaryMethods) {
 366  0
                 if (qualifiedMethodName.equals(boundaryMethod)) {
 367  0
                     return true;
 368  
                 }
 369  
             }
 370  0
             return false;
 371  
         }
 372  
 
 373  
         private void methodEntry(String className, Method method,
 374  
                 List<String> argumentTypeNames) {
 375  0
             trace(className + "." + method.name() + " " + argumentTypeNames);
 376  0
             int frameCount = -1;
 377  
             try {
 378  0
                 frameCount = thread.frameCount();
 379  0
             } catch (IncompatibleThreadStateException e) {
 380  0
                 e.printStackTrace();
 381  
                 // Ignore -- I THINK this exception cannot occur here...
 382  0
             }
 383  0
             Activation activation =
 384  
                     new Activation(currentActivation, className, method,
 385  
                             frameCount);
 386  0
             if (currentActivation == null) {
 387  0
                 rootActivations.add(activation);
 388  
             }
 389  0
             currentActivation = activation;
 390  0
         }
 391  
 
 392  
         private void methodExitEvent(MethodExitEvent event) {
 393  0
             if (currentActivation == null) {
 394  0
                 return;
 395  
             }
 396  
 
 397  0
             String className = getClassName(event);
 398  0
             String methodName = event.method().name();
 399  0
             String qualifiedMethodName = className + "." + methodName;
 400  
 
 401  0
             if (className.equals(currentActivation.getClassName()) &&
 402  
                     methodName.equals(currentActivation.getMethod().name())) {
 403  0
                 currentActivation = currentActivation.getParent();
 404  
             }
 405  0
             if (currentActivation == null && stopWhenActivationDone) {
 406  0
                 deleteAllEventRequests();
 407  
             }
 408  0
             if (currentBoundaryMethod != null &&
 409  
                     currentBoundaryMethod.equals(qualifiedMethodName)) {
 410  0
                 setEventRequests(null);
 411  
             }
 412  0
         }
 413  
 
 414  
         private void exceptionEvent(ExceptionEvent event) {
 415  0
             EventRequestManager mgr = vm.eventRequestManager();
 416  0
             StepRequest request =
 417  
                     mgr.createStepRequest(thread, StepRequest.STEP_MIN,
 418  
                             StepRequest.STEP_INTO);
 419  0
             request.addCountFilter(1);
 420  0
             enableRequest(request);
 421  0
         }
 422  
 
 423  
         private void stepEvent(StepEvent event) {
 424  0
             EventRequestManager mgr = vm.eventRequestManager();
 425  0
             mgr.deleteEventRequest(event.request());
 426  
             // Find the activation that catches the exception.
 427  0
             int frameCount = -1;
 428  
             try {
 429  0
                 frameCount = thread.frameCount();
 430  0
             } catch (IncompatibleThreadStateException e) {
 431  0
                 System.err.println(e);
 432  0
             }
 433  0
             while (currentActivation.getParent() != null) {
 434  0
                 if (currentActivation.getFrameCount() == frameCount) {
 435  0
                     break;
 436  
                 }
 437  0
                 currentActivation = currentActivation.getParent();
 438  
             }
 439  0
         }
 440  
 
 441  
         private void breakpointEvent(BreakpointEvent event) {
 442  0
             String methodName = event.location().method().name();
 443  0
             if (!methodName.equals(startMethodName)) {
 444  0
                 String message =
 445  
                         "Unexpected breakpoint. Should be in method " +
 446  
                                 startMethodName + ", but was in method " +
 447  
                                 methodName + ". Event=" + event;
 448  0
                 throw new IllegalArgumentException(message);
 449  
             }
 450  0
             methodEntry(startClassName, event.location().method(), event
 451  
                     .location().method().argumentTypeNames());
 452  0
             EventRequestManager mgr = vm.eventRequestManager();
 453  0
             mgr.deleteEventRequest(event.request());
 454  0
             setEventRequests(null);
 455  0
             stopWhenActivationDone = true;
 456  0
         }
 457  
 
 458  
         private void threadDeathEvent(ThreadDeathEvent event) {
 459  0
             trace("====== " + thread.name() + " end ======");
 460  0
         }
 461  
 
 462  
         private String getClassName(LocatableEvent event) {
 463  0
             String className = getDeclaringType(event).name();
 464  
             try {
 465  0
                 className = getInstanceType(event).name();
 466  0
             } catch (IncompatibleThreadStateException itse) {
 467  0
                 System.err.println("cannot identify instance type for " +
 468  
                         "method call: " + event.location().method().name() +
 469  
                         "; using declaring type: " + className);
 470  0
             }
 471  0
             return className;
 472  
         }
 473  
 
 474  
         private ReferenceType getDeclaringType(LocatableEvent event) {
 475  0
             return event.location().method().declaringType();
 476  
         }
 477  
 
 478  
         private ReferenceType getInstanceType(LocatableEvent event)
 479  
                 throws IncompatibleThreadStateException {
 480  
             try {
 481  0
                 return event.thread().frame(0).thisObject().referenceType();
 482  0
             } catch (Exception e) {
 483  0
                 throw new IncompatibleThreadStateException(e.getMessage());
 484  
             }
 485  
         }
 486  
     }
 487  
 
 488  
     private ThreadTrace threadTrace(ThreadReference thread) {
 489  0
         ThreadTrace threadTrace = traceMap.get(thread);
 490  0
         if (threadTrace == null) {
 491  0
             threadTrace = new ThreadTrace(thread);
 492  0
             traceMap.put(thread, threadTrace);
 493  
         }
 494  0
         return threadTrace;
 495  
     }
 496  
 
 497  
     private void handleEvent(Event event) throws NoSuchMethodException {
 498  0
         if (event instanceof ClassPrepareEvent) {
 499  0
             classPrepareEvent((ClassPrepareEvent) event);
 500  0
         } else if (event instanceof MethodEntryEvent) {
 501  0
             methodEntryEvent((MethodEntryEvent) event);
 502  0
         } else if (event instanceof MethodExitEvent) {
 503  0
             methodExitEvent((MethodExitEvent) event);
 504  0
         } else if (event instanceof ExceptionEvent) {
 505  0
             exceptionEvent((ExceptionEvent) event);
 506  0
         } else if (event instanceof StepEvent) {
 507  0
             stepEvent((StepEvent) event);
 508  0
         } else if (event instanceof BreakpointEvent) {
 509  0
             breakpointEvent((BreakpointEvent) event);
 510  0
         } else if (event instanceof ThreadDeathEvent) {
 511  0
             threadDeathEvent((ThreadDeathEvent) event);
 512  0
         } else if (event instanceof VMStartEvent) {
 513  0
             vmStartEvent((VMStartEvent) event);
 514  0
         } else if (event instanceof VMDeathEvent) {
 515  0
             vmDeathEvent((VMDeathEvent) event);
 516  0
         } else if (event instanceof VMDisconnectEvent) {
 517  0
             vmDisconnectEvent((VMDisconnectEvent) event);
 518  
         } else {
 519  0
             throw new Error("Internal error: Unexpected event type");
 520  
         }
 521  0
     }
 522  
 
 523  
     private synchronized void handleDisconnectedException() {
 524  0
         EventQueue queue = vm.eventQueue();
 525  0
         while (connected) {
 526  
             try {
 527  0
                 EventSet eventSet = queue.remove();
 528  0
                 EventIterator iter = eventSet.eventIterator();
 529  0
                 while (iter.hasNext()) {
 530  0
                     Event event = iter.nextEvent();
 531  0
                     if (event instanceof VMDeathEvent) {
 532  0
                         vmDeathEvent((VMDeathEvent) event);
 533  0
                     } else if (event instanceof VMDisconnectEvent) {
 534  0
                         vmDisconnectEvent((VMDisconnectEvent) event);
 535  
                     }
 536  0
                 }
 537  0
                 eventSet.resume();
 538  0
             } catch (InterruptedException e) {
 539  0
                 System.err.println(e);
 540  0
             }
 541  
         }
 542  0
     }
 543  
 
 544  
     private void vmStartEvent(VMStartEvent event) {
 545  0
         trace("-- VM Started --");
 546  0
     }
 547  
 
 548  
     private void classPrepareEvent(ClassPrepareEvent event)
 549  
             throws NoSuchMethodException {
 550  0
         threadTrace(event.thread()).classPrepareEvent(event);
 551  0
     }
 552  
 
 553  
     private void methodEntryEvent(MethodEntryEvent event) {
 554  0
         threadTrace(event.thread()).methodEntryEvent(event);
 555  0
     }
 556  
 
 557  
     private void methodExitEvent(MethodExitEvent event) {
 558  0
         threadTrace(event.thread()).methodExitEvent(event);
 559  0
     }
 560  
 
 561  
     private void stepEvent(StepEvent event) {
 562  0
         threadTrace(event.thread()).stepEvent(event);
 563  0
     }
 564  
 
 565  
     private void breakpointEvent(BreakpointEvent event) {
 566  0
         threadTrace(event.thread()).breakpointEvent(event);
 567  0
     }
 568  
 
 569  
     private void threadDeathEvent(ThreadDeathEvent event) {
 570  0
         ThreadTrace threadTrace = traceMap.get(event.thread());
 571  0
         if (threadTrace != null) {
 572  0
             threadTrace.threadDeathEvent(event);
 573  
         }
 574  0
     }
 575  
 
 576  
     private void exceptionEvent(ExceptionEvent event) {
 577  0
         ThreadTrace threadTrace = traceMap.get(event.thread());
 578  0
         if (threadTrace != null) {
 579  0
             threadTrace.exceptionEvent(event);
 580  
         }
 581  0
     }
 582  
 
 583  
     private void vmDeathEvent(VMDeathEvent event) {
 584  0
         vmDied = true;
 585  0
         trace("-- The application exited --");
 586  0
     }
 587  
 
 588  
     private void vmDisconnectEvent(VMDisconnectEvent event) {
 589  0
         connected = false;
 590  0
         if (!vmDied) {
 591  0
             trace("-- The application has been disconnected --");
 592  
         }
 593  0
     }
 594  
 
 595  
     private void trace(String s) {
 596  0
         if (trace) {
 597  0
             System.err.println(s);
 598  
         }
 599  0
     }
 600  
 }