KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > tools > example > trace > EventThread


1 /*
2  * @(#)EventThread.java 1.6 05/11/17
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 /*
8  * Copyright (c) 1997-2001 by Sun Microsystems, Inc. All Rights Reserved.
9  *
10  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
11  * modify and redistribute this software in source and binary code form,
12  * provided that i) this copyright notice and license appear on all copies of
13  * the software; and ii) Licensee does not utilize the software in a manner
14  * which is disparaging to Sun.
15  *
16  * This software is provided "AS IS," without a warranty of any kind. ALL
17  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
18  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
19  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
20  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
21  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
22  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
23  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
24  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
25  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGES.
27  *
28  * This software is not designed or intended for use in on-line control of
29  * aircraft, air traffic, aircraft navigation or aircraft communications; or in
30  * the design, construction, operation or maintenance of any nuclear
31  * facility. Licensee represents and warrants that it will not use or
32  * redistribute the Software for such purposes.
33  */

34
35 package com.sun.tools.example.trace;
36
37 import com.sun.jdi.*;
38 import com.sun.jdi.request.*;
39 import com.sun.jdi.event.*;
40
41 import java.util.*;
42 import java.io.PrintWriter JavaDoc;
43
44 /**
45  * This class processes incoming JDI events and displays them
46  *
47  * @version @(#) EventThread.java 1.6 05/11/17 00:25:20
48  * @author Robert Field
49  */

50 public class EventThread extends Thread JavaDoc {
51
52     private final VirtualMachine vm; // Running VM
53
private final String JavaDoc[] excludes; // Packages to exclude
54
private final PrintWriter JavaDoc writer; // Where output goes
55

56     static String JavaDoc nextBaseIndent = ""; // Starting indent for next thread
57

58     private boolean connected = true; // Connected to VM
59
private boolean vmDied = true; // VMDeath occurred
60

61     // Maps ThreadReference to ThreadTrace instances
62
private Map traceMap = new HashMap();
63
64     EventThread(VirtualMachine vm, String JavaDoc[] excludes, PrintWriter JavaDoc writer) {
65         super("event-handler");
66         this.vm = vm;
67         this.excludes = excludes;
68         this.writer = writer;
69     }
70
71     /**
72      * Run the event handling thread.
73      * As long as we are connected, get event sets off
74      * the queue and dispatch the events within them.
75      */

76     public void run() {
77         EventQueue queue = vm.eventQueue();
78         while (connected) {
79             try {
80                 EventSet eventSet = queue.remove();
81                 EventIterator it = eventSet.eventIterator();
82                 while (it.hasNext()) {
83                     handleEvent(it.nextEvent());
84                 }
85                 eventSet.resume();
86             } catch (InterruptedException JavaDoc exc) {
87                 // Ignore
88
} catch (VMDisconnectedException discExc) {
89                 handleDisconnectedException();
90                 break;
91             }
92         }
93     }
94
95     /**
96      * Create the desired event requests, and enable
97      * them so that we will get events.
98      * @param excludes Class patterns for which we don't want events
99      * @param watchFields Do we want to watch assignments to fields
100      */

101     void setEventRequests(boolean watchFields) {
102         EventRequestManager mgr = vm.eventRequestManager();
103
104         // want all exceptions
105
ExceptionRequest excReq = mgr.createExceptionRequest(null,
106                                                              true, true);
107         // suspend so we can step
108
excReq.setSuspendPolicy(EventRequest.SUSPEND_ALL);
109         excReq.enable();
110
111         MethodEntryRequest menr = mgr.createMethodEntryRequest();
112         for (int i=0; i<excludes.length; ++i) {
113             menr.addClassExclusionFilter(excludes[i]);
114         }
115         menr.setSuspendPolicy(EventRequest.SUSPEND_NONE);
116         menr.enable();
117
118         MethodExitRequest mexr = mgr.createMethodExitRequest();
119         for (int i=0; i<excludes.length; ++i) {
120             mexr.addClassExclusionFilter(excludes[i]);
121         }
122         mexr.setSuspendPolicy(EventRequest.SUSPEND_NONE);
123         mexr.enable();
124
125         ThreadDeathRequest tdr = mgr.createThreadDeathRequest();
126     // Make sure we sync on thread death
127
tdr.setSuspendPolicy(EventRequest.SUSPEND_ALL);
128         tdr.enable();
129
130     if (watchFields) {
131         ClassPrepareRequest cpr = mgr.createClassPrepareRequest();
132         for (int i=0; i<excludes.length; ++i) {
133         cpr.addClassExclusionFilter(excludes[i]);
134         }
135         cpr.setSuspendPolicy(EventRequest.SUSPEND_ALL);
136         cpr.enable();
137     }
138     }
139
140     /**
141      * This class keeps context on events in one thread.
142      * In this implementation, context is the indentation prefix.
143      */

144     class ThreadTrace {
145         final ThreadReference thread;
146         final String JavaDoc baseIndent;
147     static final String JavaDoc threadDelta = " ";
148     StringBuffer JavaDoc indent;
149
150     ThreadTrace(ThreadReference thread) {
151             this.thread = thread;
152             this.baseIndent = nextBaseIndent;
153         indent = new StringBuffer JavaDoc(baseIndent);
154         nextBaseIndent += threadDelta;
155         println("====== " + thread.name() + " ======");
156     }
157
158     private void println(String JavaDoc str) {
159         writer.print(indent);
160         writer.println(str);
161     }
162
163     void methodEntryEvent(MethodEntryEvent event) {
164         println(event.method().name() + " -- "
165                     + event.method().declaringType().name());
166         indent.append("| ");
167     }
168     
169     void methodExitEvent(MethodExitEvent event) {
170         indent.setLength(indent.length()-2);
171     }
172     
173     void fieldWatchEvent(ModificationWatchpointEvent event) {
174             Field field = event.field();
175             Value value = event.valueToBe();
176         println(" " + field.name() + " = " + value);
177     }
178     
179     void exceptionEvent(ExceptionEvent event) {
180         println("Exception: " + event.exception() +
181             " catch: " + event.catchLocation());
182
183             // Step to the catch
184
EventRequestManager mgr = vm.eventRequestManager();
185             StepRequest req = mgr.createStepRequest(thread,
186                                                     StepRequest.STEP_MIN,
187                                                     StepRequest.STEP_INTO);
188             req.addCountFilter(1); // next step only
189
req.setSuspendPolicy(EventRequest.SUSPEND_ALL);
190             req.enable();
191     }
192
193         // Step to exception catch
194
void stepEvent(StepEvent event) {
195             // Adjust call depth
196
int cnt = 0;
197             indent = new StringBuffer JavaDoc(baseIndent);
198             try {
199                 cnt = thread.frameCount();
200             } catch (IncompatibleThreadStateException exc) {
201             }
202             while (cnt-- > 0) {
203                 indent.append("| ");
204             }
205
206             EventRequestManager mgr = vm.eventRequestManager();
207             mgr.deleteEventRequest(event.request());
208         }
209
210     void threadDeathEvent(ThreadDeathEvent event) {
211             indent = new StringBuffer JavaDoc(baseIndent);
212         println("====== " + thread.name() + " end ======");
213         }
214     }
215
216     /**
217      * Returns the ThreadTrace instance for the specified thread,
218      * creating one if needed.
219      */

220     ThreadTrace threadTrace(ThreadReference thread) {
221     ThreadTrace trace = (ThreadTrace)traceMap.get(thread);
222     if (trace == null) {
223         trace = new ThreadTrace(thread);
224         traceMap.put(thread, trace);
225     }
226     return trace;
227     }
228
229     /**
230      * Dispatch incoming events
231      */

232     private void handleEvent(Event event) {
233         if (event instanceof ExceptionEvent) {
234             exceptionEvent((ExceptionEvent)event);
235         } else if (event instanceof ModificationWatchpointEvent) {
236             fieldWatchEvent((ModificationWatchpointEvent)event);
237         } else if (event instanceof MethodEntryEvent) {
238             methodEntryEvent((MethodEntryEvent)event);
239         } else if (event instanceof MethodExitEvent) {
240             methodExitEvent((MethodExitEvent)event);
241         } else if (event instanceof StepEvent) {
242             stepEvent((StepEvent)event);
243         } else if (event instanceof ThreadDeathEvent) {
244             threadDeathEvent((ThreadDeathEvent)event);
245         } else if (event instanceof ClassPrepareEvent) {
246             classPrepareEvent((ClassPrepareEvent)event);
247         } else if (event instanceof VMStartEvent) {
248             vmStartEvent((VMStartEvent)event);
249         } else if (event instanceof VMDeathEvent) {
250             vmDeathEvent((VMDeathEvent)event);
251         } else if (event instanceof VMDisconnectEvent) {
252             vmDisconnectEvent((VMDisconnectEvent)event);
253         } else {
254             throw new Error JavaDoc("Unexpected event type");
255         }
256     }
257
258     /***
259      * A VMDisconnectedException has happened while dealing with
260      * another event. We need to flush the event queue, dealing only
261      * with exit events (VMDeath, VMDisconnect) so that we terminate
262      * correctly.
263      */

264     synchronized void handleDisconnectedException() {
265         EventQueue queue = vm.eventQueue();
266         while (connected) {
267             try {
268                 EventSet eventSet = queue.remove();
269                 EventIterator iter = eventSet.eventIterator();
270                 while (iter.hasNext()) {
271                     Event event = iter.nextEvent();
272                     if (event instanceof VMDeathEvent) {
273                         vmDeathEvent((VMDeathEvent)event);
274                     } else if (event instanceof VMDisconnectEvent) {
275                         vmDisconnectEvent((VMDisconnectEvent)event);
276                     }
277                 }
278                 eventSet.resume(); // Resume the VM
279
} catch (InterruptedException JavaDoc exc) {
280                 // ignore
281
}
282         }
283     }
284
285     private void vmStartEvent(VMStartEvent event) {
286          writer.println("-- VM Started --");
287     }
288
289     // Forward event for thread specific processing
290
private void methodEntryEvent(MethodEntryEvent event) {
291          threadTrace(event.thread()).methodEntryEvent(event);
292     }
293
294     // Forward event for thread specific processing
295
private void methodExitEvent(MethodExitEvent event) {
296          threadTrace(event.thread()).methodExitEvent(event);
297     }
298
299     // Forward event for thread specific processing
300
private void stepEvent(StepEvent event) {
301          threadTrace(event.thread()).stepEvent(event);
302     }
303
304     // Forward event for thread specific processing
305
private void fieldWatchEvent(ModificationWatchpointEvent event) {
306          threadTrace(event.thread()).fieldWatchEvent(event);
307     }
308
309     void threadDeathEvent(ThreadDeathEvent event) {
310     ThreadTrace trace = (ThreadTrace)traceMap.get(event.thread());
311     if (trace != null) { // only want threads we care about
312
trace.threadDeathEvent(event); // Forward event
313
}
314     }
315
316     /**
317      * A new class has been loaded.
318      * Set watchpoints on each of its fields
319      */

320     private void classPrepareEvent(ClassPrepareEvent event) {
321         EventRequestManager mgr = vm.eventRequestManager();
322     List fields = event.referenceType().visibleFields();
323     for (Iterator it = fields.iterator(); it.hasNext(); ) {
324         Field field = (Field)it.next();
325         ModificationWatchpointRequest req =
326              mgr.createModificationWatchpointRequest(field);
327             for (int i=0; i<excludes.length; ++i) {
328                 req.addClassExclusionFilter(excludes[i]);
329             }
330         req.setSuspendPolicy(EventRequest.SUSPEND_NONE);
331         req.enable();
332     }
333     }
334
335     private void exceptionEvent(ExceptionEvent event) {
336     ThreadTrace trace = (ThreadTrace)traceMap.get(event.thread());
337     if (trace != null) { // only want threads we care about
338
trace.exceptionEvent(event); // Forward event
339
}
340     }
341
342     public void vmDeathEvent(VMDeathEvent event) {
343     vmDied = true;
344         writer.println("-- The application exited --");
345     }
346
347     public void vmDisconnectEvent(VMDisconnectEvent event) {
348         connected = false;
349         if (!vmDied) {
350         writer.println("-- The application has been disconnected --");
351     }
352     }
353 }
354
Popular Tags