KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > debug > internal > ui > views > launch > LaunchViewEventHandler


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.debug.internal.ui.views.launch;
12
13
14 import java.util.HashMap JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Map JavaDoc;
17 import java.util.Set JavaDoc;
18
19 import org.eclipse.debug.core.DebugEvent;
20 import org.eclipse.debug.core.DebugException;
21 import org.eclipse.debug.core.DebugPlugin;
22 import org.eclipse.debug.core.ILaunch;
23 import org.eclipse.debug.core.ILaunchManager;
24 import org.eclipse.debug.core.ILaunchesListener2;
25 import org.eclipse.debug.core.model.IDebugElement;
26 import org.eclipse.debug.core.model.IDebugTarget;
27 import org.eclipse.debug.core.model.IProcess;
28 import org.eclipse.debug.core.model.IStackFrame;
29 import org.eclipse.debug.core.model.IThread;
30 import org.eclipse.debug.internal.ui.DebugUIPlugin;
31 import org.eclipse.debug.internal.ui.views.AbstractDebugEventHandler;
32 import org.eclipse.jface.viewers.IStructuredSelection;
33 import org.eclipse.jface.viewers.ITreeContentProvider;
34 import org.eclipse.jface.viewers.StructuredSelection;
35
36 /**
37  * Handles debug events, updating the launch view and viewer.
38  */

39 public class LaunchViewEventHandler extends AbstractDebugEventHandler implements ILaunchesListener2 {
40     /**
41      * The timer used to time step and evaluation events. The timer allows
42      * the UI to not refresh during fast evaluations and steps.
43      */

44     private ThreadTimer fThreadTimer= new ThreadTimer();
45     
46     /**
47      * Cache of the last top stack frame
48      */

49     private IStackFrame fLastStackFrame = null;
50     
51     /**
52      * Constructs an event handler for the given launch view.
53      *
54      * @param view launch view
55      */

56     public LaunchViewEventHandler(LaunchView view) {
57         super(view);
58         DebugPlugin plugin= DebugPlugin.getDefault();
59         plugin.getLaunchManager().addLaunchListener(this);
60     }
61     
62
63     /* (non-Javadoc)
64      * @see org.eclipse.debug.internal.ui.views.AbstractDebugEventHandler#filterEvents(org.eclipse.debug.core.DebugEvent[])
65      */

66     protected DebugEvent[] filterEvents(DebugEvent[] events) {
67         if (events.length > 0) {
68             DebugEvent event = events[0];
69             Object JavaDoc source = event.getSource();
70             ILaunch launch = null;
71             if (source instanceof IDebugElement) {
72                 launch = ((IDebugElement)source).getLaunch();
73             } else if (source instanceof IProcess) {
74                 launch = ((IProcess)source).getLaunch();
75             }
76             // we only need to consider the first event, as all events in an event set come
77
// from the same program
78
if (launch != null && DebugPlugin.getDefault().getLaunchManager().isRegistered(launch)) {
79                 return events;
80             }
81             return EMPTY_EVENT_SET;
82         }
83         return events;
84     }
85     
86     /**
87      * Returns the parent for the given element.
88      *
89      * @param element
90      * @return parent
91      */

92     private Object JavaDoc getParent(Object JavaDoc element) {
93         return ((ITreeContentProvider)getTreeViewer().getContentProvider()).getParent(element);
94     }
95     
96     /**
97      * @see AbstractDebugEventHandler#doHandleDebugEvents(DebugEvent[])
98      */

99     protected void doHandleDebugEvents(DebugEvent[] events, Object JavaDoc data) {
100         fThreadTimer.handleDebugEvents(events);
101         Object JavaDoc suspendee = null;
102         for (int i = 0; i < events.length; i++) {
103             DebugEvent event = events[i];
104             Object JavaDoc source= event.getSource();
105             switch (event.getKind()) {
106                 case DebugEvent.CREATE :
107                     if (source instanceof IThread) {
108                         insert(source);
109                     } else {
110                         Object JavaDoc parent = getParent(source);
111                         if (parent != null) {
112                             refresh(parent);
113                         }
114                         if (source instanceof IDebugTarget | source instanceof IProcess) {
115                             getLaunchView().autoExpand(source, true);
116                         }
117                     }
118                     break;
119                 case DebugEvent.TERMINATE :
120                     clearSourceSelection(source);
121                     if (source instanceof IThread) {
122                         fThreadTimer.getTimedOutThreads().remove(source);
123                         remove(source);
124                     } else {
125                         Object JavaDoc parent = getParent(source);
126                         if (parent != null) {
127                             refresh(parent);
128                         }
129                     }
130                     break;
131                 case DebugEvent.RESUME :
132                     doHandleResumeEvent(event, source, data);
133                     break;
134                 case DebugEvent.SUSPEND :
135                     if (suspendee == null || !suspendee.equals(source)) {
136                         doHandleSuspendEvent(source, event, data);
137                         suspendee = source;
138                     }
139                     break;
140                 case DebugEvent.CHANGE :
141                     Object JavaDoc element = null;
142                     IStructuredSelection selection = getLaunchViewer().getDeferredSelection();
143                     if (selection == null) {
144                         selection = (IStructuredSelection) getLaunchViewer().getSelection();
145                     }
146                     
147                     element = selection.getFirstElement();
148                     IStackFrame lastFrame = null;
149                     if (element instanceof IStackFrame) {
150                         lastFrame = (IStackFrame) element;
151                     }
152                     if (source instanceof IStackFrame) {
153                         if (source.equals(lastFrame)) {
154                             getLaunchView().setStackFrame(null);
155                             getLaunchView().autoExpand(lastFrame, true);
156                         }
157                     }
158                     if (event.getDetail() == DebugEvent.STATE) {
159                         labelChanged(source);
160                     } else {
161                         //structural change
162
refresh(source);
163                     }
164                     if (lastFrame != null && source instanceof IThread) {
165                         if (lastFrame.getThread().equals(source)) {
166                             getLaunchView().autoExpand(lastFrame, true);
167                         }
168                     }
169                     break;
170             }
171         }
172     }
173     
174     /**
175      * Handles the given resume event with the given source.
176      */

177     protected void doHandleResumeEvent(DebugEvent event, Object JavaDoc source, Object JavaDoc data) {
178         if (!event.isEvaluation()) {
179             clearSourceSelection(source);
180         }
181         if (event.isEvaluation() || event.isStepStart()) {
182             // Do not update for step starts and evaluation
183
// starts immediately. Instead, start the timer.
184
IThread thread= getThread(source);
185             if (thread != null) {
186                 fThreadTimer.startTimer(thread);
187             }
188             return;
189         }
190         refresh(source);
191         if (source instanceof IThread) {
192             if (data instanceof IStackFrame) {
193                 selectAndReveal(data);
194                 return;
195             }
196             selectAndReveal(source);
197         }
198     }
199     
200     /**
201      * Updates the stack frame icons for a running thread.
202      * This is useful for the case where a thread is resumed
203      * temporarily but the view should keep the stack frame
204      * visible (for example, step start or evaluation start).
205      */

206     protected void updateRunningThread(IThread thread) {
207         labelChanged(thread);
208         getLaunchViewer().updateStackFrameImages(thread);
209         clearSourceSelection(thread);
210     }
211
212     protected void doHandleSuspendEvent(Object JavaDoc element, DebugEvent event, Object JavaDoc data) {
213         IThread thread= getThread(element);
214         if (thread != null) {
215             fThreadTimer.stopTimer(thread);
216         }
217         
218         boolean wasTimedOut= fThreadTimer.getTimedOutThreads().remove(thread);
219         if (event.isEvaluation() && ((event.getDetail() & DebugEvent.EVALUATION_IMPLICIT) != 0)) {
220             if (thread != null && !wasTimedOut) {
221                 // No refresh required for implicit evaluations that complete on time
222
return;
223             }
224         }
225         if (element instanceof IThread) {
226             doHandleSuspendThreadEvent((IThread)element, event, wasTimedOut, data);
227             return;
228         }
229         refresh(element);
230     }
231     
232     /**
233      * Updates the given thread for the given suspend event.
234      */

235     protected void doHandleSuspendThreadEvent(IThread thread, DebugEvent event, boolean wasTimedOut, Object JavaDoc data) {
236         // if the thread has already resumed, do nothing
237
if (!thread.isSuspended() || !isAvailable()) {
238             return;
239         }
240
241         // do not update source selection for evaluation events
242
boolean evaluationEvent = event.isEvaluation();
243         
244         // get the top frame
245
IStackFrame frame = null;
246         if (data instanceof IStackFrame) {
247             frame = (IStackFrame) data;
248         }
249         
250         // if the top frame is the same, only update labels and images, and re-select
251
// the frame to display source
252
if (frame != null && frame.equals(fLastStackFrame)) {
253             if (wasTimedOut) {
254                 getLaunchViewer().updateStackFrameImages(thread);
255             }
256             getLaunchViewer().update(new Object JavaDoc[] {thread, frame}, null);
257             if (!evaluationEvent) {
258                 getLaunchViewer().deferExpansion(thread);
259                 getLaunchViewer().deferSelection(new StructuredSelection(frame));
260             } else if (wasTimedOut) {
261                 getLaunchView().showEditorForCurrentSelection();
262             }
263             return;
264         }
265         
266         if (frame == null) {
267             // suspend event, but no frames in the thead
268
fLastStackFrame = null;
269             refresh(thread);
270             getLaunchView().autoExpand(thread, !evaluationEvent);
271         } else {
272             fLastStackFrame = frame;
273             // Auto-expand the thread. Only select the thread if this wasn't the end
274
// of an evaluation
275
refresh(thread);
276             getLaunchView().autoExpand(frame, !evaluationEvent);
277         }
278     }
279     
280     /**
281      * @see AbstractDebugEventHandler#updateForDebugEvents(DebugEvent[])
282      */

283     protected void updateForDebugEvents(DebugEvent[] events, Object JavaDoc data) {
284         super.updateForDebugEvents(events, data);
285         if (isViewVisible()) {
286             return;
287         }
288         doHandleDebugEvents(events, data);
289     }
290     
291     /**
292      * De-registers this event handler from the debug model.
293      */

294     public void dispose() {
295         super.dispose();
296         fThreadTimer.stop();
297         DebugPlugin plugin= DebugPlugin.getDefault();
298         plugin.getLaunchManager().removeLaunchListener(this);
299     }
300
301     /**
302      * Clear the selection in the editor - must be called in UI thread
303      */

304     private void clearSourceSelection(Object JavaDoc source) {
305         if (getViewer() != null) {
306             getLaunchView().clearSourceSelection(source);
307         }
308     }
309
310     /**
311      * Returns this event handler's launch viewer
312      *
313      * @return launch viewer
314      */

315     protected LaunchViewer getLaunchViewer() {
316         return (LaunchViewer)getViewer();
317     }
318     
319     /**
320      * Returns this event handler's launch view
321      *
322      * @return launch view
323      */

324     protected LaunchView getLaunchView() {
325         return (LaunchView)getView();
326     }
327     
328     private IThread getThread(Object JavaDoc element) {
329         IThread thread = null;
330         if (element instanceof IThread) {
331             thread = (IThread) element;
332         } else if (element instanceof IStackFrame) {
333             thread = ((IStackFrame)element).getThread();
334         }
335         return thread;
336     }
337     
338     class ThreadTimer {
339         
340         private Thread JavaDoc fThread;
341         /**
342          * The time allotted before a thread will be updated
343          */

344         private long TIMEOUT= 500;
345         /**
346          * Time in milliseconds that the thread timer started
347          * running with no timers.
348          */

349         private long timeEmpty= 0;
350         /**
351          * The maximum time in milliseconds that the thread
352          * will continue running with no timers.
353          */

354         private long MAX_TIME_EMPTY= 3000;
355         private boolean fStopped= false;
356         private Object JavaDoc fLock= new Object JavaDoc();
357         
358         /**
359          * Maps threads that are currently performing being timed
360          * to the allowed time by which they must finish. If this
361          * limit expires before the timer is stopped, the thread will
362          * be refreshed.
363          */

364         HashMap JavaDoc fStopTimes= new HashMap JavaDoc();
365         /**
366          * Collection of threads whose timers have expired.
367          */

368         HashSet JavaDoc fTimedOutThreads= new HashSet JavaDoc();
369         
370         public Set JavaDoc getTimedOutThreads() {
371             return fTimedOutThreads;
372         }
373         
374         /**
375          * Handle debug events dispatched from launch view event handler.
376          * If there are no running targets, stop this timer.
377          */

378         public void handleDebugEvents(DebugEvent[] events) {
379             if (fStopped) {
380                 return;
381             }
382             DebugEvent event;
383             for (int i= 0, numEvents= events.length; i < numEvents; i++) {
384                 event= events[i];
385                 if (event.getKind() == DebugEvent.TERMINATE && event.getSource() instanceof IDebugTarget) {
386                     ILaunch[] launches= DebugPlugin.getDefault().getLaunchManager().getLaunches();
387                     // If there are no more active DebugTargets, stop the thread.
388
for (int j= 0; j < launches.length; j++) {
389                         IDebugTarget[] targets= launches[j].getDebugTargets();
390                         for (int k = 0; k < targets.length; k++) {
391                             IDebugTarget target = targets[k];
392                             if (target != null && !target.isDisconnected() && !target.isTerminated()) {
393                                 return;
394                             }
395                         }
396                     }
397                     // To get here, there must be no running DebugTargets
398
stop();
399                     return;
400                 }
401             }
402         }
403             
404         public void startTimer(IThread thread) {
405             synchronized (fLock) {
406                 fStopTimes.put(thread, new Long JavaDoc(System.currentTimeMillis() + TIMEOUT));
407                 if (fThread == null) {
408                     startThread();
409                 }
410             }
411         }
412         
413         public void stop() {
414             synchronized (fLock) {
415                 fStopped= true;
416                 fThread= null;
417                 fStopTimes.clear();
418             }
419         }
420         
421         public void stopTimer(IThread thread) {
422             synchronized (fLock) {
423                 fStopTimes.remove(thread);
424             }
425         }
426         
427         private void startThread() {
428             fThread= new Thread JavaDoc(new Runnable JavaDoc() {
429                 public void run() {
430                     fStopped= false;
431                     while (!fStopped) {
432                         checkTimers();
433                     }
434                     
435                 }
436             }, "Thread timer"); //$NON-NLS-1$
437
fThread.setDaemon(true);
438             fThread.start();
439         }
440         
441         private void checkTimers() {
442             long timeToWait= TIMEOUT;
443             Map.Entry JavaDoc[] entries;
444             synchronized (fLock) {
445                 if (fStopTimes.size() == 0) {
446                     if (timeEmpty == 0) {
447                         timeEmpty= System.currentTimeMillis();
448                     } else if (System.currentTimeMillis() - timeEmpty > MAX_TIME_EMPTY) {
449                         stop();
450                         return;
451                     }
452                 } else {
453                     timeEmpty= 0;
454                 }
455                 entries= (Map.Entry JavaDoc[])fStopTimes.entrySet().toArray(new Map.Entry JavaDoc[0]);
456             }
457             long stopTime, currentTime= System.currentTimeMillis();
458             Long JavaDoc entryValue;
459             Map.Entry JavaDoc entry= null;
460             for (int i= 0, numEntries= entries.length; i < numEntries; i++) {
461                 entry= entries[i];
462                 entryValue= (Long JavaDoc)entry.getValue();
463                 if (entryValue == null) {
464                     continue;
465                 }
466                 stopTime= entryValue.longValue();
467                 if (stopTime <= currentTime) {
468                     // The timer has expired for this thread.
469
// Refresh the UI to show that the thread
470
// is performing a long evaluation
471
final IThread thread= (IThread)entry.getKey();
472                     fStopTimes.remove(thread);
473                     getView().asyncExec(new Runnable JavaDoc() {
474                         public void run() {
475                             fTimedOutThreads.add(thread);
476                             updateRunningThread(thread);
477                         }
478                     });
479                 } else {
480                     timeToWait= Math.min(timeToWait, stopTime - currentTime);
481                 }
482             }
483             try {
484                 Thread.sleep(timeToWait);
485             } catch (InterruptedException JavaDoc e) {
486             }
487         }
488     }
489     
490     /**
491      * @see org.eclipse.debug.core.ILaunchesListener#launchesAdded(org.eclipse.debug.core.ILaunch)
492      */

493     public void launchesAdded(final ILaunch[] launches) {
494         Runnable JavaDoc r= new Runnable JavaDoc() {
495             public void run() {
496                 if (isAvailable()) {
497                     if (launches.length == 1) {
498                         insert(launches[0]);
499                     } else {
500                         refresh();
501                     }
502                     for (int i = 0; i < launches.length; i++) {
503                         if (launches[i].hasChildren()) {
504                             getLaunchView().autoExpand(launches[i], false);
505                         }
506                     }
507
508                 }
509             }
510         };
511
512         getView().syncExec(r);
513     }
514
515     /**
516      * @see org.eclipse.debug.core.ILaunchesListener#launchesChanged(org.eclipse.debug.core.ILaunch)
517      */

518     public void launchesChanged(final ILaunch[] launches) {
519         Runnable JavaDoc r= new Runnable JavaDoc() {
520             public void run() {
521                 if (isAvailable()) {
522                     if (launches.length == 1) {
523                         refresh(launches[0]);
524                     } else {
525                         refresh();
526                     }
527                     for (int i = 0; i < launches.length; i++) {
528                         if (launches[i].hasChildren()) {
529                             getLaunchView().autoExpand(launches[i], false);
530                         }
531                     }
532                 }
533             }
534         };
535         
536         getView().asyncExec(r);
537     }
538
539     /**
540      * @see org.eclipse.debug.core.ILaunchesListener#launchesRemoved(org.eclipse.debug.core.ILaunch)
541      */

542     public void launchesRemoved(final ILaunch[] launches) {
543         Runnable JavaDoc r= new Runnable JavaDoc() {
544             public void run() {
545                 if (isAvailable()) {
546                     if (launches.length == 1) {
547                         remove(launches[0]);
548                     } else {
549                         refresh();
550                     }
551                     
552                     getLaunchView().cleanupLaunches(launches);
553                     
554                     ILaunchManager lm= DebugPlugin.getDefault().getLaunchManager();
555                     IDebugTarget[] targets= lm.getDebugTargets();
556                     if (targets.length > 0) {
557                         IDebugTarget target= targets[targets.length - 1];
558                         try {
559                             IThread[] threads= target.getThreads();
560                             for (int i=0; i < threads.length; i++) {
561                                 if (threads[i].isSuspended()) {
562                                     IStackFrame topStackFrame = threads[i].getTopStackFrame();
563                                     if (topStackFrame != null) {
564                                         getLaunchView().autoExpand(topStackFrame, true);
565                                     }
566                                     return;
567                                 }
568                             }
569                         } catch (DebugException de) {
570                             DebugUIPlugin.log(de);
571                         }
572                         
573                         getLaunchView().autoExpand(target.getLaunch(), true);
574                     }
575                 }
576             }
577         };
578
579         getView().asyncExec(r);
580     }
581
582
583     /* (non-Javadoc)
584      * @see org.eclipse.debug.core.ILaunchesListener2#launchesTerminated(org.eclipse.debug.core.ILaunch[])
585      */

586     public void launchesTerminated(final ILaunch[] launches) {
587         if (fLastStackFrame != null) {
588             ILaunch launch= fLastStackFrame.getLaunch();
589             for (int i = 0; i < launches.length; i++) {
590                 ILaunch terminatedLaunch = launches[i];
591                 if (terminatedLaunch.equals(launch)) {
592                     fLastStackFrame= null;
593                 }
594             }
595         }
596         Runnable JavaDoc r= new Runnable JavaDoc() {
597             public void run() {
598                 getLaunchView().cleanupLaunches(launches);
599             }
600         };
601         getView().asyncExec(r);
602     }
603
604     /* (non-Javadoc)
605      * @see org.eclipse.debug.internal.ui.views.AbstractDebugEventHandler#doPreprocessEvents(org.eclipse.debug.core.DebugEvent[])
606      */

607     protected DebugEvent[] doPreprocessEvents(DebugEvent[] events) {
608         for (int i = 0; i < events.length; i++) {
609             DebugEvent event = events[i];
610             Object JavaDoc source = event.getSource();
611             switch (event.getKind()) {
612                 case DebugEvent.SUSPEND:
613                     if (source instanceof IThread) {
614                         IThread thread = (IThread)source;
615                         try {
616                             IStackFrame frame = thread.getTopStackFrame();
617                             queueData(frame);
618                         } catch (DebugException e) {
619                         }
620                     }
621                     break;
622                 case DebugEvent.RESUME:
623                     if (source instanceof IThread && event.getDetail() == DebugEvent.CLIENT_REQUEST) {
624                         // When a thread resumes, try to select another suspended thread
625
// in the same target.
626
try {
627                             IDebugTarget target = ((IThread) source).getDebugTarget();
628                             IThread[] threads= target.getThreads();
629                             for (int j = 0; j < threads.length; j++) {
630                                 IStackFrame frame = threads[j].getTopStackFrame();
631                                 if (frame != null) {
632                                     queueData(frame);
633                                     break;
634                                 }
635                             }
636                         } catch (DebugException e) {
637                         }
638                     }
639                     break;
640             }
641         }
642         return events;
643     }
644 }
645
Popular Tags