KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > drjava > model > debug > EventHandlerThread


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  *END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.drjava.model.debug;
35
36 import edu.rice.cs.util.Log;
37
38 import com.sun.jdi.*;
39 import com.sun.jdi.event.*;
40 import com.sun.jdi.request.*;
41 import java.util.*;
42 import java.io.*;
43
44 /** A thread that listens and responds to events from JPDA when the debugger has attached to another JVM.
45  * @version $Id: EventHandlerThread.java 4067 2007-01-18 16:40:38Z dlsmith $
46  */

47 public class EventHandlerThread extends Thread JavaDoc {
48
49   /** Debugger to which this class reports events. */
50   private final JPDADebugger _debugger;
51
52   /** JPDA reference to the VirtualMachine generating the events. */
53   private final VirtualMachine _vm;
54
55   /** Whether this event handler is currently connected to the JPDA VirtualMachine. */
56   private volatile boolean _connected;
57
58   /** A log for recording messages in a file. */
59   private static final Log _log = new Log("EventTest", false);
60
61   /** Creates a new EventHandlerThread to listen to events from the given debugger and virtual machine. Calling
62    * this Thread's start() method causes it to begin listenting.
63    * @param debugger Debugger to which to report events
64    * @param vm JPDA reference to the VirtualMachine generating the events
65    */

66   EventHandlerThread(JPDADebugger debugger, VirtualMachine vm) {
67     super("DrJava Debug Event Handler");
68     _debugger = debugger;
69     _vm = vm;
70     _connected = true;
71   }
72
73   /** Logs any unexpected behavior that occurs (but which should not cause DrJava to abort).
74    * @param message message to print to the log
75    */

76   private void _log(String JavaDoc message) { _log.log(message); }
77
78   /** Logs any unexpected behavior that occurs (but which should not cause DrJava to abort).
79    * @param message message to print to the log
80    * @param t Exception or Error being logged
81    */

82   private void _log(String JavaDoc message, Throwable JavaDoc t) { _log.log(message, t); }
83
84   /** Continually consumes events from the VM's event queue until it is disconnected.*/
85   public void run() {
86     _debugger.notifyDebuggerStarted();
87
88     EventQueue queue = _vm.eventQueue();
89     while (_connected) {
90       try {
91         try {
92           // Remove and consume a set of events from the queue (blocks for an event)
93
EventSet eventSet = queue.remove();
94           EventIterator it = eventSet.eventIterator();
95           
96           while (it.hasNext()) handleEvent(it.nextEvent());
97         }
98         catch (InterruptedException JavaDoc ie) {
99           // Don't need to do anything. If the VM was disconnected,
100
// the loop will terminate.
101
_log("InterruptedException in main loop: " + ie);
102         }
103         catch (VMDisconnectedException de) {
104           // We expect this to happen if the other JVM is reset
105
handleDisconnectedException();
106           break;
107         }
108       }
109       catch (Exception JavaDoc e) {
110         // Log and report to the debugger
111
_log("Exception in main event handler loop.", e);
112         _debugger.eventHandlerError(e);
113         _debugger.printMessage("An exception occurred in the event handler:\n" + e);
114         _debugger.printMessage("The debugger may have become unstable as a result.");
115         ByteArrayOutputStream baos = new ByteArrayOutputStream();
116         e.printStackTrace(new PrintWriter(baos, true));
117         _debugger.printMessage("Stack trace: "+baos.toString());
118       }
119     }
120
121     _debugger.notifyDebuggerShutdown();
122   }
123
124   /** Processes a given event from JPDA. A visitor approach would be much better for this, but Sun's Event class
125    * doesn't have an appropriate visit() method.
126    */

127   private void handleEvent(Event e) throws DebugException {
128 // Utilities.showDebug("EventHandler.handleEvent(" + e + ") called");
129
_log("handling event: " + e);
130
131     if (e instanceof BreakpointEvent) _handleBreakpointEvent((BreakpointEvent) e);
132     else if (e instanceof StepEvent) _handleStepEvent((StepEvent) e);
133     //else if (e instanceof ModificationWatchpointEvent) {
134
// _handleModificationWatchpointEvent((ModificationWatchpointEvent) e);
135
//}
136
else if (e instanceof ClassPrepareEvent) _handleClassPrepareEvent((ClassPrepareEvent) e);
137     else if (e instanceof ThreadStartEvent) _handleThreadStartEvent((ThreadStartEvent) e);
138     else if (e instanceof ThreadDeathEvent) _handleThreadDeathEvent((ThreadDeathEvent) e);
139     else if (e instanceof VMDeathEvent) _handleVMDeathEvent((VMDeathEvent) e);
140     else if (e instanceof VMDisconnectEvent) _handleVMDisconnectEvent((VMDisconnectEvent) e);
141     else
142       throw new DebugException("Unexpected event type: " + e);
143   }
144
145   /** Returns whether the given thread is both suspended and has stack frames. */
146   private boolean _isSuspendedWithFrames(ThreadReference thread) throws DebugException {
147     
148     try { return thread.isSuspended() && thread.frameCount() > 0; }
149     catch (IncompatibleThreadStateException itse) {
150       throw new DebugException("Could not count frames on a suspended thread: " + itse);
151     }
152   }
153
154   /** Responds to a breakpoint event.
155    * @param e breakpoint event from JPDA
156    */

157   private void _handleBreakpointEvent(BreakpointEvent e) throws DebugException {
158     synchronized(_debugger) {
159       if (_isSuspendedWithFrames(e.thread()) && _debugger.setCurrentThread(e.thread())) {
160 // Utilities.showDebug("EventHandlerThread._handleBreakpointEvent(" + e + ") called");
161
_debugger.currThreadSuspended();
162 // _debugger.scrollToSource(e);
163
_debugger.reachedBreakpoint((BreakpointRequest) e.request());
164       }
165     }
166   }
167
168   /** Responds to a step event.
169    * @param e step event from JPDA
170    */

171   private void _handleStepEvent(StepEvent e) throws DebugException {
172     synchronized(_debugger) {
173       if (_isSuspendedWithFrames(e.thread()) && _debugger.setCurrentThread(e.thread())) {
174         _debugger.printMessage("Stepped to " + e.location().declaringType().name() + "." + e.location().method().name()
175                                  + "(...) [line " + e.location().lineNumber() + "]");
176         _debugger.currThreadSuspended();
177 // _debugger.scrollToSource(e);
178
}
179       // Delete the step request so it doesn't happen again
180
_debugger.getEventRequestManager().deleteEventRequest(e.request());
181     }
182   }
183
184 // /** Responds to an event for a modified watchpoint.
185
// * This event is not currently expected in DrJava.
186
// * @param e modification watchpoint event from JPDA
187
// */
188
// private void _handleModificationWatchpointEvent(ModificationWatchpointEvent e) {
189
// _debugger.printMessage("ModificationWatchpointEvent occured ");
190
// _debugger.printMessage("Field: " + e.field() + " Value: " +
191
// e.valueToBe() +"]");
192
// }
193

194   /** Responds when a class of interest has been prepared. Allows the debugger to set a pending breakpoint before any
195    * code in the class is executed.
196    * @param e class prepare event from JPDA
197    * @throws DebugException if actions performed on the prepared class fail
198    */

199   private void _handleClassPrepareEvent(ClassPrepareEvent e) throws DebugException {
200     synchronized(_debugger) {
201       _debugger.getPendingRequestManager().classPrepared(e);
202       // resume this thread which was suspended because its
203
// suspend policy was SUSPEND_EVENT_THREAD
204
e.thread().resume();
205     }
206   }
207
208   /** Responds to a thread start event.
209    * @param e thread start event from JPDA
210    */

211   private void _handleThreadStartEvent(ThreadStartEvent e) { synchronized(_debugger) { _debugger.threadStarted(); } }
212
213   /** Reponds to a thread death event.
214    * @param e thread death event from JPDA
215    */

216   private void _handleThreadDeathEvent(ThreadDeathEvent e) throws DebugException {
217     // no need to check if there are suspended threads on the stack
218
// because all that logic should be in the debugger
219
synchronized(_debugger) {
220       ThreadReference running = _debugger.getCurrentRunningThread();
221       if (e.thread().equals(running)) {
222         // Delete any step requests pending on this thread
223
EventRequestManager erm = _vm.eventRequestManager();
224         List steps = erm.stepRequests();
225         for (int i = 0; i < steps.size(); i++) {
226           StepRequest step = (StepRequest)steps.get(i);
227           if (step.thread().equals(e.thread())) {
228             erm.deleteEventRequest(step);
229
230             // There can only be one step request per thread,
231
// so we can stop looking
232
break;
233           }
234         }
235         _debugger.currThreadDied();
236       }
237       else _debugger.nonCurrThreadDied();
238     }
239
240     // Thread is suspended on death, so resume it now.
241
e.thread().resume();
242   }
243
244   /** Responds if the virtual machine being debugged dies.
245    * @param e virtual machine death event from JPDA
246    */

247   private void _handleVMDeathEvent(VMDeathEvent e) throws DebugException { _cleanUp(e); }
248
249   /**
250    * Responds if the virtual machine being debugged disconnects.
251    * @param e virtual machine disconnect event from JPDA
252    */

253   private void _handleVMDisconnectEvent(VMDisconnectEvent e) throws DebugException { _cleanUp(e); }
254
255   /** Cleans up the state after the virtual machine being debugged dies or disconnects.
256    * @param e JPDA event indicating the debugging session has ended
257    */

258   private void _cleanUp(Event e) throws DebugException {
259     synchronized(_debugger) {
260       _connected = false;
261       if (_debugger.isReady()) {
262         // caused crash if "Run Document's Main Method" was invoked while debugging
263
// if (_debugger.hasSuspendedThreads()) _debugger.currThreadDied();
264
_debugger.shutdown();
265       }
266     }
267   }
268
269   /** Responds when a VMDisconnectedException occurs while dealing with another event. We need to flush the event
270    * queue, dealing only with exit events (VMDeath, VMDisconnect) so that we terminate correctly. */

271   private void handleDisconnectedException() throws DebugException {
272     EventQueue queue = _vm.eventQueue();
273     while (_connected) {
274       try {
275         EventSet eventSet = queue.remove();
276         EventIterator iter = eventSet.eventIterator();
277         while (iter.hasNext()) {
278           Event event = iter.nextEvent();
279           if (event instanceof VMDeathEvent) _handleVMDeathEvent((VMDeathEvent)event);
280           else if (event instanceof VMDisconnectEvent) _handleVMDisconnectEvent((VMDisconnectEvent)event);
281           // else ignore the event
282
}
283         eventSet.resume(); // Resume the VM
284
}
285       catch (InterruptedException JavaDoc ie) {
286         // ignore
287
_log("InterruptedException after a disconnected exception.", ie);
288       }
289       catch (VMDisconnectedException de) {
290         // try to continue flushing the event queue anyway
291
_log("A second VMDisconnectedException.", de);
292       }
293     }
294   }
295 }
296
Popular Tags