KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > debug > core > EventDispatcher


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.debug.core;
12
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.debug.core.DebugEvent;
21 import org.eclipse.debug.core.DebugException;
22 import org.eclipse.debug.core.DebugPlugin;
23 import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
24 import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
25
26 import com.sun.jdi.VMDisconnectedException;
27 import com.sun.jdi.VirtualMachine;
28 import com.sun.jdi.event.Event;
29 import com.sun.jdi.event.EventIterator;
30 import com.sun.jdi.event.EventQueue;
31 import com.sun.jdi.event.EventSet;
32 import com.sun.jdi.event.VMDeathEvent;
33 import com.sun.jdi.event.VMDisconnectEvent;
34 import com.sun.jdi.event.VMStartEvent;
35 import com.sun.jdi.request.EventRequest;
36
37 /**
38  * Dispatches events generated by an underlying VM.
39  * There is one event dispatcher per JDI debug target.
40  * <p>
41  * Event listeners register with a debug target to handle
42  * specific event requests. A debug target forwards event
43  * listeners and requests to its event dispatcher. As events
44  * are received from the underlying VM, those listeners that
45  * registered to handle the specific events are notified.
46  * </p>
47  * <p>
48  * Events are processed in event sets. It is possible that one
49  * event can trigger more than one event request to be processed.
50  * In such cases all event requests triggered by that one event are
51  * processed, and each event listener votes on whether the thread
52  * in which the event occurred should be resumed. A thread is only
53  * resumed in if all event handlers agree that the thread should be
54  * resumed.
55  * </p>
56  */

57
58 public class EventDispatcher implements Runnable JavaDoc {
59     /**
60      * The debug target this event dispatcher belongs to.
61      */

62     private JDIDebugTarget fTarget;
63     /**
64      * Whether this dispatcher is shutdown.
65      */

66     private boolean fShutdown;
67     /**
68      * Table of event listeners. Table is
69      * a mapping of <code>EventRequest</code>
70      * to <code>IJDIEventListener</code>.
71      */

72     private HashMap JavaDoc fEventHandlers;
73     
74     /**
75      * Queue of debug model events to fire, created
76      * when processing events on the target VM
77      */

78     private List JavaDoc fDebugEvents = new ArrayList JavaDoc(5);
79     
80     /**
81      * Collection of deferred events for conditional breakpoints.
82      * Conditional breakpoints are handled after all other events
83      * in an event set, such that we only evaluate conditions
84      * if required.
85      */

86     private List JavaDoc fDeferredEvents = new ArrayList JavaDoc(5);
87     
88     /**
89      * Constructs a new event dispatcher listening for events
90      * originating from the specified debug target's underlying
91      * VM.
92      *
93      * @param target the target this event dispatcher belongs to
94      */

95     public EventDispatcher(JDIDebugTarget target) {
96         fEventHandlers = new HashMap JavaDoc(10);
97         fTarget= target;
98         fShutdown = false;
99     }
100
101     /**
102      * Dispatch the given event set.
103      *
104      * @param eventSet events to dispatch
105      */

106     protected void dispatch(EventSet eventSet) {
107         if (isShutdown()) {
108             return;
109         }
110         EventIterator iter= eventSet.eventIterator();
111         boolean vote = false;
112         boolean resume = true;
113         int voters = 0;
114         Event winningEvent = null;
115         IJDIEventListener winner = null;
116         while (iter.hasNext()) {
117             if (isShutdown()) {
118                 return;
119             }
120             Event event= iter.nextEvent();
121             if (event == null) {
122                 continue;
123             }
124             // Dispatch events to registered listeners, if any
125
IJDIEventListener listener = (IJDIEventListener)fEventHandlers.get(event.request());
126             if (listener != null) {
127                 if (listener instanceof IJavaLineBreakpoint) {
128                     // Event dispatch to conditional breakpoints is deferred until after
129
// other listeners vote.
130
try {
131                         if (((IJavaLineBreakpoint)listener).isConditionEnabled()) {
132                             defer(event);
133                             continue;
134                         }
135                     } catch (CoreException exception) {
136                         JDIDebugPlugin.log(exception);
137                     }
138                 }
139                 vote = true;
140                 resume = listener.handleEvent(event, fTarget) && resume;
141                 voters++;
142                 if (!resume && winner == null) {
143                     winner = listener;
144                     winningEvent = event;
145                 }
146                 continue;
147             }
148             
149             // Dispatch VM start/end events
150
if (event instanceof VMDeathEvent) {
151                 fTarget.handleVMDeath((VMDeathEvent) event);
152                 shutdown(); // stop listening for events
153
} else if (event instanceof VMDisconnectEvent) {
154                 fTarget.handleVMDisconnect((VMDisconnectEvent) event);
155                 shutdown(); // stop listening for events
156
} else if (event instanceof VMStartEvent) {
157                 fTarget.handleVMStart((VMStartEvent)event);
158             } else {
159                 // Unhandled Event
160
}
161         }
162         
163         if (resume) {
164             // process deferred events if event handlers have voted
165
// to resume the thread
166
if (!getDeferredEvents().isEmpty()) {
167                 Iterator JavaDoc deferredIter= getDeferredEvents().iterator();
168                 while (deferredIter.hasNext()) {
169                     if (isShutdown()) {
170                         return;
171                     }
172                     Event event= (Event)deferredIter.next();
173                     if (event == null) {
174                         continue;
175                     }
176                     // Dispatch events to registered listeners, if any
177
IJDIEventListener listener = (IJDIEventListener)fEventHandlers.get(event.request());
178                     if (listener != null) {
179                         vote = true;
180                         resume = listener.handleEvent(event, fTarget) && resume;
181                         continue;
182                     }
183                 }
184             }
185         }
186         // clear any deferred events (processed or not)
187
getDeferredEvents().clear();
188         
189         // let the winner know they won
190
if (winner != null && voters > 1) {
191             winner.wonSuspendVote(winningEvent, fTarget);
192         }
193         
194         fireEvents();
195         
196         if (vote && resume) {
197             try {
198                 eventSet.resume();
199             } catch (VMDisconnectedException e) {
200             } catch (RuntimeException JavaDoc e) {
201                 try {
202                     fTarget.targetRequestFailed(JDIDebugMessages.EventDispatcher_0, e);
203                 } catch (DebugException de) {
204                     JDIDebugPlugin.log(de);
205                 }
206             }
207         }
208     }
209
210     /**
211      * Continuously reads events that are coming from the event queue,
212      * until this event dispatcher is shutdown. A debug target starts
213      * a thread on this method on startup.
214      *
215      * @see #shutdown()
216      */

217     public void run() {
218         VirtualMachine vm = fTarget.getVM();
219         if (vm != null) {
220             EventQueue q= vm.eventQueue();
221             EventSet eventSet= null;
222             while (!isShutdown()) {
223                 try {
224                     try {
225                         // Get the next event set.
226
eventSet= q.remove(1000);
227                     } catch (VMDisconnectedException e) {
228                         break;
229                     }
230                                     
231                     if(!isShutdown() && eventSet != null) {
232                         dispatch(eventSet);
233                     }
234                 } catch (InterruptedException JavaDoc e) {
235                     break;
236                 }
237             }
238         }
239     }
240
241     /**
242      * Shutdown this event dispatcher - i.e. causes this event
243      * dispatcher to stop reading and dispatching events from the
244      * event queue. The thread associated with this runnable
245      * will exit.
246      */

247     public void shutdown() {
248         fShutdown= true;
249     }
250     
251     /**
252      * Returns whether this event dispatcher has been
253      * shutdown.
254      *
255      * @return whether this event dispatcher has been
256      * shutdown
257      */

258     protected boolean isShutdown() {
259         return fShutdown;
260     }
261     
262     /**
263      * Registers the given listener for with the given event request.
264      * When an event is received from the underlying VM, that is
265      * assocaited with the given event request, the listener will
266      * be notified.
267      *
268      * @param listener the listener to register
269      * @param request the event request associated with events
270      * the listener is interested in
271      */

272     public void addJDIEventListener(IJDIEventListener listener, EventRequest request) {
273         fEventHandlers.put(request, listener);
274     }
275
276     /**
277      * Deregisters the given listener and event request. The listener
278      * will no longer be notified of events associated with the request.
279      * Listeners are responsible for deleting the assocaited event
280      * request if required.
281      *
282      * @param listener the listener to deregister
283      * @param request the event request to deregister
284      */

285     public void removeJDIEventListener(IJDIEventListener listener, EventRequest request) {
286         fEventHandlers.remove(request);
287     }
288     
289     /**
290      * Adds the given event to the queue of debug events to fire when done
291      * dispatching events from the current event set.
292      *
293      * @param event the event to queue
294      */

295     public void queue(DebugEvent event) {
296         fDebugEvents.add(event);
297     }
298     
299     /**
300      * Fires debug events in the event queue, and clears the queue
301      */

302     protected void fireEvents() {
303         DebugPlugin plugin= DebugPlugin.getDefault();
304         if (plugin != null) { //check that not in the process of shutting down
305
DebugEvent[] events = (DebugEvent[])fDebugEvents.toArray(new DebugEvent[fDebugEvents.size()]);
306             fDebugEvents.clear();
307             plugin.fireDebugEventSet(events);
308         }
309     }
310
311     /**
312      * Defer the given event, to be handled after all other events in
313      * an event set.
314      *
315      * @param event event to defer
316      */

317     protected void defer(Event event) {
318         fDeferredEvents.add(event);
319     }
320
321     /**
322      * Returns the events currently deferred.
323      *
324      * @return deferred events
325      */

326     protected List JavaDoc getDeferredEvents() {
327         return fDeferredEvents;
328     }
329         
330 }
331
332
Popular Tags