| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
/*  | 
 | 
 * This source code is provided to illustrate the usage of a given feature  | 
 | 
 * or technique and has been deliberately simplified. Additional steps  | 
 | 
 * required for a production-quality application, such as security checks,  | 
 | 
 * input validation and proper error handling, might not be present in  | 
 | 
 * this sample code.  | 
 | 
 */  | 
 | 
 | 
 | 
 | 
 | 
package com.sun.tools.example.trace;  | 
 | 
 | 
 | 
import com.sun.jdi.*;  | 
 | 
import com.sun.jdi.request.*;  | 
 | 
import com.sun.jdi.event.*;  | 
 | 
 | 
 | 
import java.util.*;  | 
 | 
import java.io.PrintWriter;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public class EventThread extends Thread { | 
 | 
 | 
 | 
    private final VirtualMachine vm;     | 
 | 
    private final String[] excludes;     | 
 | 
    private final PrintWriter writer;    | 
 | 
 | 
 | 
    static String nextBaseIndent = "";   | 
 | 
 | 
 | 
    private boolean connected = true;    | 
 | 
    private boolean vmDied = true;       | 
 | 
 | 
 | 
      | 
 | 
    private Map<ThreadReference, ThreadTrace> traceMap =  | 
 | 
       new HashMap<>();  | 
 | 
 | 
 | 
    EventThread(VirtualMachine vm, String[] excludes, PrintWriter writer) { | 
 | 
        super("event-handler"); | 
 | 
        this.vm = vm;  | 
 | 
        this.excludes = excludes;  | 
 | 
        this.writer = writer;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public void run() { | 
 | 
        EventQueue queue = vm.eventQueue();  | 
 | 
        while (connected) { | 
 | 
            try { | 
 | 
                EventSet eventSet = queue.remove();  | 
 | 
                EventIterator it = eventSet.eventIterator();  | 
 | 
                while (it.hasNext()) { | 
 | 
                    handleEvent(it.nextEvent());  | 
 | 
                }  | 
 | 
                eventSet.resume();  | 
 | 
            } catch (InterruptedException exc) { | 
 | 
                // Ignore  | 
 | 
            } catch (VMDisconnectedException discExc) { | 
 | 
                handleDisconnectedException();  | 
 | 
                break;  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    void setEventRequests(boolean watchFields) { | 
 | 
        EventRequestManager mgr = vm.eventRequestManager();  | 
 | 
 | 
 | 
          | 
 | 
        ExceptionRequest excReq = mgr.createExceptionRequest(null,  | 
 | 
                                                             true, true);  | 
 | 
          | 
 | 
        excReq.setSuspendPolicy(EventRequest.SUSPEND_ALL);  | 
 | 
        excReq.enable();  | 
 | 
 | 
 | 
        MethodEntryRequest menr = mgr.createMethodEntryRequest();  | 
 | 
        for (int i=0; i<excludes.length; ++i) { | 
 | 
            menr.addClassExclusionFilter(excludes[i]);  | 
 | 
        }  | 
 | 
        menr.setSuspendPolicy(EventRequest.SUSPEND_NONE);  | 
 | 
        menr.enable();  | 
 | 
 | 
 | 
        MethodExitRequest mexr = mgr.createMethodExitRequest();  | 
 | 
        for (int i=0; i<excludes.length; ++i) { | 
 | 
            mexr.addClassExclusionFilter(excludes[i]);  | 
 | 
        }  | 
 | 
        mexr.setSuspendPolicy(EventRequest.SUSPEND_NONE);  | 
 | 
        mexr.enable();  | 
 | 
 | 
 | 
        ThreadDeathRequest tdr = mgr.createThreadDeathRequest();  | 
 | 
          | 
 | 
        tdr.setSuspendPolicy(EventRequest.SUSPEND_ALL);  | 
 | 
        tdr.enable();  | 
 | 
 | 
 | 
        if (watchFields) { | 
 | 
            ClassPrepareRequest cpr = mgr.createClassPrepareRequest();  | 
 | 
            for (int i=0; i<excludes.length; ++i) { | 
 | 
                cpr.addClassExclusionFilter(excludes[i]);  | 
 | 
            }  | 
 | 
            cpr.setSuspendPolicy(EventRequest.SUSPEND_ALL);  | 
 | 
            cpr.enable();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    class ThreadTrace { | 
 | 
        final ThreadReference thread;  | 
 | 
        final String baseIndent;  | 
 | 
        static final String threadDelta = "                     ";  | 
 | 
        StringBuffer indent;  | 
 | 
 | 
 | 
        ThreadTrace(ThreadReference thread) { | 
 | 
            this.thread = thread;  | 
 | 
            this.baseIndent = nextBaseIndent;  | 
 | 
            indent = new StringBuffer(baseIndent);  | 
 | 
            nextBaseIndent += threadDelta;  | 
 | 
            println("====== " + thread.name() + " ======"); | 
 | 
        }  | 
 | 
 | 
 | 
        private void println(String str) { | 
 | 
            writer.print(indent);  | 
 | 
            writer.println(str);  | 
 | 
        }  | 
 | 
 | 
 | 
        void methodEntryEvent(MethodEntryEvent event)  { | 
 | 
            println(event.method().name() + "  --  "  | 
 | 
                    + event.method().declaringType().name());  | 
 | 
            indent.append("| "); | 
 | 
        }  | 
 | 
 | 
 | 
        void methodExitEvent(MethodExitEvent event)  { | 
 | 
            indent.setLength(indent.length()-2);  | 
 | 
        }  | 
 | 
 | 
 | 
        void fieldWatchEvent(ModificationWatchpointEvent event)  { | 
 | 
            Field field = event.field();  | 
 | 
            Value value = event.valueToBe();  | 
 | 
            println("    " + field.name() + " = " + value); | 
 | 
        }  | 
 | 
 | 
 | 
        void exceptionEvent(ExceptionEvent event) { | 
 | 
            println("Exception: " + event.exception() + | 
 | 
                    " catch: " + event.catchLocation());  | 
 | 
 | 
 | 
              | 
 | 
            EventRequestManager mgr = vm.eventRequestManager();  | 
 | 
            StepRequest req = mgr.createStepRequest(thread,  | 
 | 
                                                    StepRequest.STEP_MIN,  | 
 | 
                                                    StepRequest.STEP_INTO);  | 
 | 
            req.addCountFilter(1);    | 
 | 
            req.setSuspendPolicy(EventRequest.SUSPEND_ALL);  | 
 | 
            req.enable();  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        void stepEvent(StepEvent event)  { | 
 | 
              | 
 | 
            int cnt = 0;  | 
 | 
            indent = new StringBuffer(baseIndent);  | 
 | 
            try { | 
 | 
                cnt = thread.frameCount();  | 
 | 
            } catch (IncompatibleThreadStateException exc) { | 
 | 
            }  | 
 | 
            while (cnt-- > 0) { | 
 | 
                indent.append("| "); | 
 | 
            }  | 
 | 
 | 
 | 
            EventRequestManager mgr = vm.eventRequestManager();  | 
 | 
            mgr.deleteEventRequest(event.request());  | 
 | 
        }  | 
 | 
 | 
 | 
        void threadDeathEvent(ThreadDeathEvent event)  { | 
 | 
            indent = new StringBuffer(baseIndent);  | 
 | 
            println("====== " + thread.name() + " end ======"); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    ThreadTrace threadTrace(ThreadReference thread) { | 
 | 
        ThreadTrace trace = traceMap.get(thread);  | 
 | 
        if (trace == null) { | 
 | 
            trace = new ThreadTrace(thread);  | 
 | 
            traceMap.put(thread, trace);  | 
 | 
        }  | 
 | 
        return trace;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void handleEvent(Event event) { | 
 | 
        if (event instanceof ExceptionEvent) { | 
 | 
            exceptionEvent((ExceptionEvent)event);  | 
 | 
        } else if (event instanceof ModificationWatchpointEvent) { | 
 | 
            fieldWatchEvent((ModificationWatchpointEvent)event);  | 
 | 
        } else if (event instanceof MethodEntryEvent) { | 
 | 
            methodEntryEvent((MethodEntryEvent)event);  | 
 | 
        } else if (event instanceof MethodExitEvent) { | 
 | 
            methodExitEvent((MethodExitEvent)event);  | 
 | 
        } else if (event instanceof StepEvent) { | 
 | 
            stepEvent((StepEvent)event);  | 
 | 
        } else if (event instanceof ThreadDeathEvent) { | 
 | 
            threadDeathEvent((ThreadDeathEvent)event);  | 
 | 
        } else if (event instanceof ClassPrepareEvent) { | 
 | 
            classPrepareEvent((ClassPrepareEvent)event);  | 
 | 
        } else if (event instanceof VMStartEvent) { | 
 | 
            vmStartEvent((VMStartEvent)event);  | 
 | 
        } else if (event instanceof VMDeathEvent) { | 
 | 
            vmDeathEvent((VMDeathEvent)event);  | 
 | 
        } else if (event instanceof VMDisconnectEvent) { | 
 | 
            vmDisconnectEvent((VMDisconnectEvent)event);  | 
 | 
        } else { | 
 | 
            throw new Error("Unexpected event type"); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    synchronized void handleDisconnectedException() { | 
 | 
        EventQueue queue = vm.eventQueue();  | 
 | 
        while (connected) { | 
 | 
            try { | 
 | 
                EventSet eventSet = queue.remove();  | 
 | 
                EventIterator iter = eventSet.eventIterator();  | 
 | 
                while (iter.hasNext()) { | 
 | 
                    Event event = iter.nextEvent();  | 
 | 
                    if (event instanceof VMDeathEvent) { | 
 | 
                        vmDeathEvent((VMDeathEvent)event);  | 
 | 
                    } else if (event instanceof VMDisconnectEvent) { | 
 | 
                        vmDisconnectEvent((VMDisconnectEvent)event);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                eventSet.resume();   | 
 | 
            } catch (InterruptedException exc) { | 
 | 
                // ignore  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void vmStartEvent(VMStartEvent event)  { | 
 | 
         writer.println("-- VM Started --"); | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private void methodEntryEvent(MethodEntryEvent event)  { | 
 | 
         threadTrace(event.thread()).methodEntryEvent(event);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private void methodExitEvent(MethodExitEvent event)  { | 
 | 
         threadTrace(event.thread()).methodExitEvent(event);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private void stepEvent(StepEvent event)  { | 
 | 
         threadTrace(event.thread()).stepEvent(event);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private void fieldWatchEvent(ModificationWatchpointEvent event)  { | 
 | 
         threadTrace(event.thread()).fieldWatchEvent(event);  | 
 | 
    }  | 
 | 
 | 
 | 
    void threadDeathEvent(ThreadDeathEvent event)  { | 
 | 
        ThreadTrace trace = traceMap.get(event.thread());  | 
 | 
        if (trace != null) {  // only want threads we care about | 
 | 
            trace.threadDeathEvent(event);     | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void classPrepareEvent(ClassPrepareEvent event)  { | 
 | 
        EventRequestManager mgr = vm.eventRequestManager();  | 
 | 
        List<Field> fields = event.referenceType().visibleFields();  | 
 | 
        for (Field field : fields) { | 
 | 
            ModificationWatchpointRequest req =  | 
 | 
                     mgr.createModificationWatchpointRequest(field);  | 
 | 
            for (int i=0; i<excludes.length; ++i) { | 
 | 
                req.addClassExclusionFilter(excludes[i]);  | 
 | 
            }  | 
 | 
            req.setSuspendPolicy(EventRequest.SUSPEND_NONE);  | 
 | 
            req.enable();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void exceptionEvent(ExceptionEvent event) { | 
 | 
        ThreadTrace trace = traceMap.get(event.thread());  | 
 | 
        if (trace != null) {  // only want threads we care about | 
 | 
            trace.exceptionEvent(event);        | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public void vmDeathEvent(VMDeathEvent event) { | 
 | 
        vmDied = true;  | 
 | 
        writer.println("-- The application exited --"); | 
 | 
    }  | 
 | 
 | 
 | 
    public void vmDisconnectEvent(VMDisconnectEvent event) { | 
 | 
        connected = false;  | 
 | 
        if (!vmDied) { | 
 | 
            writer.println("-- The application has been disconnected --"); | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |