KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > debug > core > model > JDIThread


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  * BEA - Daniel R Somerfield - Bug 89643
11  *******************************************************************************/

12 package org.eclipse.jdt.internal.debug.core.model;
13
14
15 import java.util.ArrayList JavaDoc;
16 import java.util.Collections JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Vector JavaDoc;
20
21 import org.eclipse.core.runtime.CoreException;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.MultiStatus;
25 import org.eclipse.core.runtime.Status;
26 import org.eclipse.core.runtime.jobs.ISchedulingRule;
27 import org.eclipse.core.runtime.jobs.Job;
28 import org.eclipse.debug.core.DebugEvent;
29 import org.eclipse.debug.core.DebugException;
30 import org.eclipse.debug.core.DebugPlugin;
31 import org.eclipse.debug.core.IStatusHandler;
32 import org.eclipse.debug.core.model.IBreakpoint;
33 import org.eclipse.debug.core.model.IStackFrame;
34 import org.eclipse.debug.core.model.ITerminate;
35 import org.eclipse.jdt.core.Signature;
36 import org.eclipse.jdt.debug.core.IEvaluationRunnable;
37 import org.eclipse.jdt.debug.core.IJavaBreakpoint;
38 import org.eclipse.jdt.debug.core.IJavaObject;
39 import org.eclipse.jdt.debug.core.IJavaStackFrame;
40 import org.eclipse.jdt.debug.core.IJavaThread;
41 import org.eclipse.jdt.debug.core.IJavaThreadGroup;
42 import org.eclipse.jdt.debug.core.IJavaValue;
43 import org.eclipse.jdt.debug.core.IJavaVariable;
44 import org.eclipse.jdt.debug.core.JDIDebugModel;
45 import org.eclipse.jdt.internal.debug.core.IJDIEventListener;
46 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
47 import org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint;
48
49 import com.ibm.icu.text.MessageFormat;
50 import com.sun.jdi.BooleanValue;
51 import com.sun.jdi.ClassNotLoadedException;
52 import com.sun.jdi.ClassType;
53 import com.sun.jdi.Field;
54 import com.sun.jdi.IncompatibleThreadStateException;
55 import com.sun.jdi.IntegerValue;
56 import com.sun.jdi.InvalidStackFrameException;
57 import com.sun.jdi.InvalidTypeException;
58 import com.sun.jdi.InvocationException;
59 import com.sun.jdi.Location;
60 import com.sun.jdi.Method;
61 import com.sun.jdi.ObjectCollectedException;
62 import com.sun.jdi.ObjectReference;
63 import com.sun.jdi.ReferenceType;
64 import com.sun.jdi.StackFrame;
65 import com.sun.jdi.ThreadGroupReference;
66 import com.sun.jdi.ThreadReference;
67 import com.sun.jdi.VMDisconnectedException;
68 import com.sun.jdi.Value;
69 import com.sun.jdi.event.Event;
70 import com.sun.jdi.event.StepEvent;
71 import com.sun.jdi.request.EventRequest;
72 import com.sun.jdi.request.EventRequestManager;
73 import com.sun.jdi.request.StepRequest;
74
75 /**
76  * Model thread implementation for an underlying
77  * thread on a VM.
78  */

79 public class JDIThread extends JDIDebugElement implements IJavaThread {
80     
81     /**
82      * Constant for the name of the default Java stratum
83      */

84     private static final String JavaDoc JAVA_STRATUM_CONSTANT = "Java"; //$NON-NLS-1$
85

86     /**
87      * Constant for the name of the main thread group.
88      */

89     private static final String JavaDoc MAIN_THREAD_GROUP = "main"; //$NON-NLS-1$
90
/**
91      * Status code indicating that a request to suspend this thread has timed out
92      */

93     public static final int SUSPEND_TIMEOUT= 161;
94     /**
95      * Underlying thread.
96      */

97     private ThreadReference fThread;
98     /**
99      * Cache of previous name, used in case thread is garbage collected.
100      */

101     private String JavaDoc fPreviousName;
102     /**
103      * Collection of stack frames
104      */

105     private List JavaDoc fStackFrames;
106     /**
107      * Underlying thread group, cached on first access.
108      */

109     private ThreadGroupReference fThreadGroup;
110     /**
111      * Name of underlying thread group, cached on first access.
112      */

113     private String JavaDoc fThreadGroupName;
114     /**
115      * Whether children need to be refreshed. Set to
116      * <code>true</code> when stack frames are re-used
117      * on the next suspend.
118      */

119     private boolean fRefreshChildren = true;
120     /**
121      * Currently pending step handler, <code>null</code>
122      * when not performing a step.
123      */

124     private StepHandler fStepHandler= null;
125     /**
126      * Whether running.
127      */

128     private boolean fRunning;
129     /**
130      * Whether terminated.
131      */

132     private boolean fTerminated;
133     /**
134      * whether suspended but without firing the equivalent events.
135      */

136     private boolean fSuspendedQuiet;
137     /**
138      * Whether this thread is a system thread.
139      */

140     private boolean fIsSystemThread;
141     
142     /**
143      * Whether this thread is a daemon thread
144      * @since 3.3
145      */

146     private boolean fIsDaemon = false;
147     
148     /**
149      * The collection of breakpoints that caused the last suspend, or
150      * an empty collection if the thread is not suspended or was not
151      * suspended by any breakpoint(s).
152      */

153     private List JavaDoc fCurrentBreakpoints = new ArrayList JavaDoc(2);
154     /**
155      * Whether this thread is currently performing
156      * an evaluation. An evaluation may involve a series
157      * of method invocations.
158      */

159     private boolean fIsPerformingEvaluation= false;
160     private IEvaluationRunnable fEvaluationRunnable;
161     
162     /**
163      * Whether this thread was manually suspended during an
164      * evaluation.
165      */

166     private boolean fEvaluationInterrupted = false;
167     
168     /**
169      * Whether this thread is currently invoking a method.
170      * Nested method invocations cannot be performed.
171      */

172     private boolean fIsInvokingMethod = false;
173     /**
174      * Whether or not this thread is currently honoring
175      * breakpoints. This flag allows breakpoints to be
176      * disabled during evaluations.
177      */

178     private boolean fHonorBreakpoints= true;
179     /**
180      * The kind of step that was originally requested. Zero or
181      * more 'secondary steps' may be performed programmatically after
182      * the original user-requested step, and this field tracks the
183      * type (step into, over, return) of the original step.
184      */

185     private int fOriginalStepKind;
186     /**
187      * The JDI Location from which an original user-requested step began.
188      */

189     private Location fOriginalStepLocation;
190     /**
191      * The total stack depth at the time an original (user-requested) step
192      * is initiated. This is used along with the original step Location
193      * to determine if a step into comes back to the starting location and
194      * needs to be 'nudged' forward. Checking the stack depth eliminates
195      * undesired 'nudging' in recursive methods.
196      */

197     private int fOriginalStepStackDepth;
198     
199     /**
200      * Whether or not this thread is currently suspending (user-requested).
201      */

202     private boolean fIsSuspending= false;
203     /**
204      * Whether or not this thread is currently evaluating an expression for a conditional breakpoint
205      */

206     private boolean fIsEvaluatingConditionalBreakpoint= false;
207
208     private ThreadJob fAsyncJob;
209     
210     private ThreadJob fRunningAsyncJob;
211     
212     /**
213      * Creates a new thread on the underlying thread reference
214      * in the given debug target.
215      *
216      * @param target the debug target in which this thread is contained
217      * @param thread the underlying thread on the VM
218      * @exception ObjectCollectedException if the underlying thread has been
219      * garbage collected and cannot be properly initialized
220      */

221     public JDIThread(JDIDebugTarget target, ThreadReference thread) throws ObjectCollectedException {
222         super(target);
223         setUnderlyingThread(thread);
224         initialize();
225     }
226
227     /**
228      * Thread initialization:<ul>
229      * <li>Determines if this thread is a system thread</li>
230      * <li>Sets terminated state to <code>false</code></li>
231      * <li>Determines suspended state from underlying thread</li>
232      * <li>Sets this threads stack frames to an empty collection</li>
233      * </ul>
234      * @exception ObjectCollectedException if the thread has been garbage
235      * collected and cannot be initialized
236      */

237     protected void initialize() throws ObjectCollectedException {
238         fStackFrames= new ArrayList JavaDoc();
239         // system thread
240
try {
241             determineIfSystemThread();
242         } catch (DebugException e) {
243             Throwable JavaDoc underlyingException= e.getStatus().getException();
244             if (underlyingException instanceof VMDisconnectedException) {
245                 // Threads may be created by the VM at shutdown
246
// as finalizers. The VM may be disconnected by
247
// the time we hear about the thread creation.
248
disconnected();
249                 return;
250             }
251             if (underlyingException instanceof ObjectCollectedException) {
252                 throw (ObjectCollectedException)underlyingException;
253             }
254             logError(e);
255         }
256         
257         try {
258             determineIfDaemonThread();
259         } catch (DebugException e) {
260             Throwable JavaDoc underlyingException= e.getStatus().getException();
261             if (underlyingException instanceof VMDisconnectedException) {
262                 // Threads may be created by the VM at shutdown
263
// as finalizers. The VM may be disconnected by
264
// the time we hear about the thread creation.
265
disconnected();
266                 return;
267             }
268             logError(e);
269         }
270         
271         try {
272             ThreadGroupReference group = getUnderlyingThreadGroup();
273             // might already be terminated
274
if (group != null) {
275                 getJavaDebugTarget().addThreadGroup(group);
276             }
277         } catch (DebugException e1) {
278         }
279
280         // state
281
setTerminated(false);
282         setRunning(false);
283         try {
284             // see bug 30816
285
if (fThread.status() == ThreadReference.THREAD_STATUS_UNKNOWN) {
286                 setRunning(true);
287                 return;
288             }
289         } catch (VMDisconnectedException e) {
290             disconnected();
291             return;
292         } catch (ObjectCollectedException e){
293             throw e;
294         } catch (RuntimeException JavaDoc e) {
295             logError(e);
296         }
297         
298         try {
299             boolean suspended = fThread.isSuspended();
300             if (suspended) {
301                 // Unless we're at a breakpoint, set status to running. The thread state
302
// will be properly updated to suspended in the case that a breakpoint
303
// is hit. Otherwise this is likely just a transient suspend state (for
304
// example, a breakpoint is handling a class prepare event quietly).
305
// See bug 120385
306
suspended = getBreakpoints().length > 0;
307             }
308             setRunning(!suspended);
309         } catch (VMDisconnectedException e) {
310             disconnected();
311             return;
312         } catch (ObjectCollectedException e){
313             throw e;
314         } catch (RuntimeException JavaDoc e) {
315             logError(e);
316         }
317     }
318
319     /**
320      * Adds the given breakpoint to the list of breakpoints
321      * this thread is suspended at
322      */

323     protected void addCurrentBreakpoint(IBreakpoint bp) {
324         fCurrentBreakpoints.add(bp);
325     }
326     
327     /**
328      * Removes the given breakpoint from the list of breakpoints
329      * this thread is suspended at (called when a breakpoint is
330      * deleted, in case we are suspended at that breakpoint)
331      */

332     protected void removeCurrentBreakpoint(IBreakpoint bp) {
333         fCurrentBreakpoints.remove(bp);
334     }
335     
336     /**
337      * @see org.eclipse.debug.core.model.IThread#getBreakpoints()
338      */

339     public synchronized IBreakpoint[] getBreakpoints() {
340         return (IBreakpoint[])fCurrentBreakpoints.toArray(new IBreakpoint[fCurrentBreakpoints.size()]);
341     }
342
343     /**
344      * @see ISuspendResume#canResume()
345      */

346     public boolean canResume() {
347         return isSuspended() && !isSuspendedQuiet() && (!isPerformingEvaluation() || isInvokingMethod());
348     }
349
350     /**
351      * @see ISuspendResume#canSuspend()
352      */

353     public boolean canSuspend() {
354         return !isSuspended() || isSuspendedQuiet() || (isPerformingEvaluation() && !isInvokingMethod());
355     }
356
357     /**
358      * @see ITerminate#canTerminate()
359      */

360     public boolean canTerminate() {
361         return getDebugTarget().canTerminate();
362     }
363
364     /**
365      * @see IStep#canStepInto()
366      */

367     public boolean canStepInto() {
368         return canStep();
369     }
370
371     /**
372      * @see IStep#canStepOver()
373      */

374     public boolean canStepOver() {
375         return canStep();
376     }
377
378     /**
379      * @see IStep#canStepReturn()
380      */

381     public boolean canStepReturn() {
382         return canStep();
383     }
384
385     /**
386      * Returns whether this thread is in a valid state to
387      * step.
388      *
389      * @return whether this thread is in a valid state to
390      * step
391      */

392     protected boolean canStep() {
393         try {
394             return isSuspended()
395                 && !isSuspendedQuiet()
396                 && (!isPerformingEvaluation() || isInvokingMethod())
397                 && !isStepping()
398                 && getTopStackFrame() != null
399                 && !getJavaDebugTarget().isPerformingHotCodeReplace();
400         } catch (DebugException e) {
401             return false;
402         }
403     }
404
405     /**
406      * Determines and sets whether this thread represents a system thread.
407      *
408      * @exception DebugException if this method fails. Reasons include:
409      * <ul>
410      * <li>Failure communicating with the VM. The DebugException's
411      * status code contains the underlying exception responsible for
412      * the failure.</li>
413      * </ul>
414      */

415     protected void determineIfSystemThread() throws DebugException {
416         fIsSystemThread= false;
417         ThreadGroupReference tgr= getUnderlyingThreadGroup();
418         fIsSystemThread = tgr != null;
419         while (tgr != null) {
420             String JavaDoc tgn= null;
421             try {
422                 tgn= tgr.name();
423                 tgr= tgr.parent();
424             } catch (UnsupportedOperationException JavaDoc e) {
425                 fIsSystemThread = false;
426                 break;
427             } catch (RuntimeException JavaDoc e) {
428                 targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_determining_if_system_thread, new String JavaDoc[] {e.toString()}), e);
429                 // execution will not reach this line, as
430
// #targetRequestFailed will throw an exception
431
return;
432             }
433             if (tgn != null && tgn.equals(MAIN_THREAD_GROUP)) {
434                 fIsSystemThread= false;
435                 break;
436             }
437         }
438     }
439     
440     /**
441      * Determines whether this is a daemon thread.
442      *
443      * @throws DebugException on failure
444      */

445     protected void determineIfDaemonThread() throws DebugException {
446         fIsDaemon = false;
447         try {
448             ReferenceType referenceType = getUnderlyingThread().referenceType();
449             Field field = referenceType.fieldByName("daemon"); //$NON-NLS-1$
450
if (field == null) {
451                 field = referenceType.fieldByName("isDaemon"); //$NON-NLS-1$
452
}
453             if (field != null) {
454                 if (field.signature().equals(Signature.SIG_BOOLEAN)) {
455                     Value value = getUnderlyingThread().getValue(field);
456                     if (value instanceof BooleanValue) {
457                         fIsDaemon = ((BooleanValue)value).booleanValue();
458                     }
459                 }
460             }
461         }
462         catch(ObjectCollectedException oce) {/*do nothing thread does not exist*/}
463         catch (RuntimeException JavaDoc e) {
464             targetRequestFailed(JDIDebugModelMessages.JDIThread_47, e);
465         }
466     }
467
468     /**
469      * NOTE: this method returns a copy of this thread's stack frames.
470      *
471      * @see IThread#getStackFrames()
472      */

473     public synchronized IStackFrame[] getStackFrames() throws DebugException {
474         if (isSuspendedQuiet()) {
475             return new IStackFrame[0];
476         }
477         List JavaDoc list = computeStackFrames();
478         return (IStackFrame[])list.toArray(new IStackFrame[list.size()]);
479     }
480     
481     /**
482      * @see computeStackFrames()
483      *
484      * @param refreshChildren whether or not this method should request new stack
485      * frames from the VM
486      */

487     protected synchronized List JavaDoc computeStackFrames(boolean refreshChildren) throws DebugException {
488         if (isSuspended()) {
489             if (isTerminated()) {
490                 fStackFrames.clear();
491             } else if (refreshChildren) {
492                 List JavaDoc frames = getUnderlyingFrames();
493                 int oldSize = fStackFrames.size();
494                 int newSize = frames.size();
495                 int discard = oldSize - newSize; // number of old frames to discard, if any
496
for (int i = 0; i < discard; i++) {
497                     JDIStackFrame invalid = (JDIStackFrame) fStackFrames.remove(0);
498                     invalid.bind(null, -1);
499                 }
500                 int newFrames = newSize - oldSize; // number of frames to create, if any
501
int depth = oldSize;
502                 for (int i = newFrames - 1; i >= 0; i--) {
503                     fStackFrames.add(0, new JDIStackFrame(this, (StackFrame) frames.get(i), depth));
504                     depth++;
505                 }
506                 int numToRebind = Math.min(newSize, oldSize); // number of frames to attempt to rebind
507
int offset = newSize - 1;
508                 for (depth = 0; depth < numToRebind; depth++) {
509                     JDIStackFrame oldFrame = (JDIStackFrame) fStackFrames.get(offset);
510                     StackFrame frame = (StackFrame) frames.get(offset);
511                     JDIStackFrame newFrame = oldFrame.bind(frame, depth);
512                     if (newFrame != oldFrame) {
513                         fStackFrames.set(offset, newFrame);
514                     }
515                     offset--;
516                 }
517                 
518
519             }
520             fRefreshChildren = false;
521         } else {
522             return Collections.EMPTY_LIST;
523         }
524         return fStackFrames;
525     }
526     
527     /**
528      * Returns this thread's current stack frames as a list, computing
529      * them if required. Returns an empty collection if this thread is
530      * not currently suspended, or this thread is terminated. This
531      * method should be used internally to get the current stack frames,
532      * instead of calling <code>#getStackFrames()</code>, which makes a
533      * copy of the current list.
534      * <p>
535      * Before a thread is resumed a call must be made to one of:<ul>
536      * <li><code>preserveStackFrames()</code></li>
537      * <li><code>disposeStackFrames()</code></li>
538      * </ul>
539      * If stack frames are disposed before a thread is resumed, stack frames
540      * are completely re-computed on the next call to this method. If stack
541      * frames are to be preserved, this method will attempt to re-use any stack
542      * frame objects which represent the same stack frame as on the previous
543      * suspend. Stack frames are cached until a subsequent call to preserve
544      * or dispose stack frames.
545      * </p>
546      *
547      * @return list of <code>IJavaStackFrame</code>
548      * @exception DebugException if this method fails. Reasons include:
549      * <ul>
550      * <li>Failure communicating with the VM. The DebugException's
551      * status code contains the underlying exception responsible for
552      * the failure.</li>
553      * </ul>
554      */

555     public synchronized List JavaDoc computeStackFrames() throws DebugException {
556         return computeStackFrames(fRefreshChildren);
557     }
558     
559     /**
560      * @see JDIThread#computeStackFrames()
561      *
562      * This method differs from computeStackFrames() in that it
563      * always requests new stack frames from the VM. As this is
564      * an expensive operation, this method should only be used
565      * by clients who know for certain that the stack frames
566      * on the VM have changed.
567      */

568     public List JavaDoc computeNewStackFrames() throws DebugException {
569         return computeStackFrames(true);
570     }
571
572     private List JavaDoc getUnderlyingFrames() throws DebugException {
573         if (!isSuspended()) {
574             // Checking isSuspended here eliminates a race condition in resume
575
// between the time stack frames are preserved and the time the
576
// underlying thread is actually resumed.
577
requestFailed(JDIDebugModelMessages.JDIThread_Unable_to_retrieve_stack_frame___thread_not_suspended__1, null, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
578         }
579         try {
580             return fThread.frames();
581         } catch (IncompatibleThreadStateException e) {
582             requestFailed(JDIDebugModelMessages.JDIThread_Unable_to_retrieve_stack_frame___thread_not_suspended__1, e, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
583         } catch (RuntimeException JavaDoc e) {
584             targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_stack_frames_2, new String JavaDoc[] {e.toString()}), e);
585         } catch (InternalError JavaDoc e) {
586             targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_stack_frames_2, new String JavaDoc[] {e.toString()}), e);
587         }
588         // execution will not reach this line, as
589
// #targetRequestFailed will thrown an exception
590
return null;
591     }
592
593     /**
594      * Returns the number of frames on the stack from the
595      * underlying thread.
596      *
597      * @return number of frames on the stack
598      * @exception DebugException if this method fails. Reasons include:
599      * <ul>
600      * <li>Failure communicating with the VM. The DebugException's
601      * status code contains the underlying exception responsible for
602      * the failure.</li>
603      * <li>This thread is not suspended</li>
604      * </ul>
605      */

606     protected int getUnderlyingFrameCount() throws DebugException {
607         try {
608             return fThread.frameCount();
609         } catch (RuntimeException JavaDoc e) {
610             targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_frame_count, new String JavaDoc[] {e.toString()}), e);
611         } catch (IncompatibleThreadStateException e) {
612             requestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_frame_count, new String JavaDoc[] {e.toString()}), e, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
613         }
614         // execution will not reach here - try block will either
615
// return or exception will be thrown
616
return -1;
617     }
618     
619     /**
620      * @see IJavaThread#runEvaluation(IEvaluationRunnable, IProgressMonitor, int, boolean)
621      */

622     public void runEvaluation(IEvaluationRunnable evaluation, IProgressMonitor monitor, int evaluationDetail, boolean hitBreakpoints) throws DebugException {
623         if (isPerformingEvaluation()) {
624             requestFailed(JDIDebugModelMessages.JDIThread_Cannot_perform_nested_evaluations, null, IJavaThread.ERR_NESTED_METHOD_INVOCATION); //
625
}
626         
627         if (!canRunEvaluation()) {
628             requestFailed(JDIDebugModelMessages.JDIThread_Evaluation_failed___thread_not_suspended, null, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
629         }
630         
631         fIsPerformingEvaluation = true;
632         fEvaluationRunnable= evaluation;
633         fHonorBreakpoints= hitBreakpoints;
634         fireResumeEvent(evaluationDetail);
635         //save and restore current breakpoint information - bug 30837
636
IBreakpoint[] breakpoints = getBreakpoints();
637         ISchedulingRule rule = null;
638         if (evaluationDetail == DebugEvent.EVALUATION_IMPLICIT) {
639             rule = getThreadRule();
640         }
641         try {
642             if (rule != null) {
643                 Job.getJobManager().beginRule(rule, monitor);
644             }
645             if (monitor == null || !monitor.isCanceled()) {
646                 evaluation.run(this, monitor);
647             }
648         } catch (DebugException e) {
649             throw e;
650         } finally {
651             if (rule != null) {
652                 Job.getJobManager().endRule(rule);
653             }
654             fIsPerformingEvaluation = false;
655             fEvaluationRunnable= null;
656             fHonorBreakpoints= true;
657             if (getBreakpoints().length == 0 && breakpoints.length > 0) {
658                 for (int i = 0; i < breakpoints.length; i++) {
659                     addCurrentBreakpoint(breakpoints[i]);
660                 }
661             }
662             fireSuspendEvent(evaluationDetail);
663             if (fEvaluationInterrupted && (fAsyncJob == null || fAsyncJob.isEmpty()) && (fRunningAsyncJob == null || fRunningAsyncJob.isEmpty())) {
664                 // @see bug 31585:
665
// When an evaluation was interrupted & resumed, the launch view does
666
// not update properly. It cannot know when it is safe to display frames
667
// since it does not know about queued evaluations. Thus, when the queue
668
// is empty, we fire a change event to force the view to update.
669
fEvaluationInterrupted = false;
670                 fireChangeEvent(DebugEvent.CONTENT);
671             }
672         }
673     }
674     
675     /**
676      * Returns whether this thread is in a valid state to
677      * run an evaluation.
678      *
679      * @return whether this thread is in a valid state to
680      * run an evaluation
681      */

682     protected boolean canRunEvaluation() {
683         // NOTE similar to #canStep, except a quiet suspend state is OK
684
try {
685             return isSuspendedQuiet() || (isSuspended()
686                 && !(isPerformingEvaluation() || isInvokingMethod())
687                 && !isStepping()
688                 && getTopStackFrame() != null
689                 && !getJavaDebugTarget().isPerformingHotCodeReplace());
690         } catch (DebugException e) {
691             return false;
692         }
693     }
694     
695     /**
696      * @see org.eclipse.jdt.debug.core.IJavaThread#queueRunnable(Runnable)
697      */

698     public void queueRunnable(Runnable JavaDoc evaluation) {
699         if (fAsyncJob == null) {
700             fAsyncJob= new ThreadJob(this);
701         }
702         fAsyncJob.addRunnable(evaluation);
703     }
704     
705     /**
706      * @see IJavaThread#terminateEvaluation()
707      */

708     public void terminateEvaluation() throws DebugException {
709         if (canTerminateEvaluation()) {
710             ((ITerminate) fEvaluationRunnable).terminate();
711         }
712     }
713     
714     /**
715      * @see IJavaThread#canTerminateEvaluation()
716      */

717     public boolean canTerminateEvaluation() {
718         return fEvaluationRunnable instanceof ITerminate;
719     }
720
721     /**
722      * Invokes a method on the target, in this thread, and returns the result. Only
723      * one receiver may be specified - either a class or an object, the other must
724      * be <code>null</code>. This thread is left suspended after the invocation
725      * is complete, unless a call is made to <code>abortEvaluation<code> while
726      * performing a method invocation. In that case, this thread is automatically
727      * resumed when/if this invocation (eventually) completes.
728      * <p>
729      * Method invocations cannot be nested. That is, this method must
730      * return before another call to this method can be made. This
731      * method does not return until the invocation is complete.
732      * Breakpoints can suspend a method invocation, and it is possible
733      * that an invocation will not complete due to an infinite loop
734      * or deadlock.
735      * </p>
736      * <p>
737      * Stack frames are preserved during method invocations, unless
738      * a timeout occurs. Although this thread's state is updated to
739      * running while performing an evaluation, no debug events are
740      * fired unless this invocation is interrupted by a breakpoint,
741      * or the invocation times out.
742      * </p>
743      * <p>
744      * When performing an invocation, the communication timeout with
745      * the target VM is set to infinite, as the invocation may not
746      * complete in a timely fashion, if at all. The timeout value
747      * is reset to its original value when the invocation completes.
748      * </p>
749      *
750      * @param receiverClass the class in the target representing the receiver
751      * of a static message send, or <code>null</code>
752      * @param receiverObject the object in the target to be the receiver of
753      * the message send, or <code>null</code>
754      * @param method the underlying method to be invoked
755      * @param args the arguments to invoke the method with (an empty list
756      * if none)
757      * @return the result of the method, as an underlying value
758      * @exception DebugException if this method fails. Reasons include:
759      * <ul>
760      * <li>Failure communicating with the VM. The DebugException's
761      * status code contains the underlying exception responsible for
762      * the failure.</li>
763      * <li>This thread is not suspended
764      * (status code <code>IJavaThread.ERR_THREAD_NOT_SUSPENDED</code>)</li>
765      * <li>This thread is already invoking a method
766      * (status code <code>IJavaThread.ERR_NESTED_METHOD_INVOCATION</code>)</li>
767      * <li>This thread is not suspended by a JDI request
768      * (status code <code>IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE</code>)</li>
769      * </ul>
770      */

771     protected Value invokeMethod(ClassType receiverClass, ObjectReference receiverObject, Method method, List JavaDoc args, boolean invokeNonvirtual) throws DebugException {
772         if (receiverClass != null && receiverObject != null) {
773             throw new IllegalArgumentException JavaDoc(JDIDebugModelMessages.JDIThread_can_only_specify_one_receiver_for_a_method_invocation);
774         }
775         Value result= null;
776         int timeout= getRequestTimeout();
777         try {
778             // this is synchronized such that any other operation that
779
// might be resuming this thread has a chance to complete before
780
// we determine if it is safe to continue with a method invocation.
781
// See bugs 6518, 14069
782
synchronized (this) {
783                 if (!isSuspended()) {
784                     requestFailed(JDIDebugModelMessages.JDIThread_Evaluation_failed___thread_not_suspended, null, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
785                 }
786                 if (isInvokingMethod()) {
787                     requestFailed(JDIDebugModelMessages.JDIThread_Cannot_perform_nested_evaluations, null, IJavaThread.ERR_NESTED_METHOD_INVOCATION);
788                 }
789                 // set the request timeout to be infinite
790
setRequestTimeout(Integer.MAX_VALUE);
791                 setRunning(true);
792                 setInvokingMethod(true);
793             }
794             preserveStackFrames();
795             int flags= ClassType.INVOKE_SINGLE_THREADED;
796             if (invokeNonvirtual) {
797                 // Superclass method invocation must be performed nonvirtual.
798
flags |= ObjectReference.INVOKE_NONVIRTUAL;
799             }
800             if (receiverClass == null) {
801                 result= receiverObject.invokeMethod(fThread, method, args, flags);
802             } else {
803                 result= receiverClass.invokeMethod(fThread, method, args, flags);
804             }
805         } catch (InvalidTypeException e) {
806             invokeFailed(e, timeout);
807         } catch (ClassNotLoadedException e) {
808             invokeFailed(e, timeout);
809         } catch (IncompatibleThreadStateException e) {
810             invokeFailed(JDIDebugModelMessages.JDIThread_Thread_must_be_suspended_by_step_or_breakpoint_to_perform_method_invocation_1, IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE, e, timeout);
811         } catch (InvocationException e) {
812             invokeFailed(e, timeout);
813         } catch (RuntimeException JavaDoc e) {
814             invokeFailed(e, timeout);
815         }
816
817         invokeComplete(timeout);
818         return result;
819     }
820     
821     /**
822      * Invokes a constructor in this thread, creating a new instance of the given
823      * class, and returns the result as an object reference.
824      * This thread is left suspended after the invocation
825      * is complete.
826      * <p>
827      * Method invocations cannot be nested. That is, this method must
828      * return before another call to this method can be made. This
829      * method does not return until the invocation is complete.
830      * Breakpoints can suspend a method invocation, and it is possible
831      * that an invocation will not complete due to an infinite loop
832      * or deadlock.
833      * </p>
834      * <p>
835      * Stack frames are preserved during method invocations, unless
836      * a timeout occurs. Although this thread's state is updated to
837      * running while performing an evaluation, no debug events are
838      * fired unless this invocation is interrupted by a breakpoint,
839      * or the invocation times out.
840      * </p>
841      * <p>
842      * When performing an invocation, the communication timeout with
843      * the target VM is set to infinite, as the invocation may not
844      * complete in a timely fashion, if at all. The timeout value
845      * is reset to its original value when the invocation completes.
846      * </p>
847      *
848      * @param receiverClass the class in the target representing the receiver
849      * of the 'new' message send
850      * @param constructor the underlying constructor to be invoked
851      * @param args the arguments to invoke the constructor with (an empty list
852      * if none)
853      * @return a new object reference
854      * @exception DebugException if this method fails. Reasons include:
855      * <ul>
856      * <li>Failure communicating with the VM. The DebugException's
857      * status code contains the underlying exception responsible for
858      * the failure.</li>
859      * </ul>
860      */

861     protected ObjectReference newInstance(ClassType receiverClass, Method constructor, List JavaDoc args) throws DebugException {
862         if (isInvokingMethod()) {
863             requestFailed(JDIDebugModelMessages.JDIThread_Cannot_perform_nested_evaluations_2, null);
864         }
865         ObjectReference result= null;
866         int timeout= getRequestTimeout();
867         try {
868             // set the request timeout to be infinite
869
setRequestTimeout(Integer.MAX_VALUE);
870             setRunning(true);
871             setInvokingMethod(true);
872             preserveStackFrames();
873             result= receiverClass.newInstance(fThread, constructor, args, ClassType.INVOKE_SINGLE_THREADED);
874         } catch (InvalidTypeException e) {
875             invokeFailed(e, timeout);
876         } catch (ClassNotLoadedException e) {
877             invokeFailed(e, timeout);
878         } catch (IncompatibleThreadStateException e) {
879             invokeFailed(e, timeout);
880         } catch (InvocationException e) {
881             invokeFailed(e, timeout);
882         } catch (RuntimeException JavaDoc e) {
883             invokeFailed(e, timeout);
884         }
885
886         invokeComplete(timeout);
887         return result;
888     }
889     
890     /**
891      * Called when an invocation fails. Performs cleanup
892      * and throws an exception.
893      *
894      * @param e the exception that caused the failure
895      * @param restoreTimeout the communication timeout value,
896      * in milliseconds, that should be reset
897      * @see #invokeComplete(int)
898      * @exception DebugException. Reasons include:
899      * <ul>
900      * <li>Failure communicating with the VM. The DebugException's
901      * status code contains the underlying exception responsible for
902      * the failure.</li>
903      * </ul>
904      */

905     protected void invokeFailed(Throwable JavaDoc e, int restoreTimeout) throws DebugException {
906         invokeFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_invoking_method, new String JavaDoc[] {e.toString()}), DebugException.TARGET_REQUEST_FAILED, e, restoreTimeout);
907     }
908     
909     /**
910      * Called when an invocation fails. Performs cleanup
911      * and throws an exception.
912      *
913      * @param message error message
914      * @param code status code
915      * @param e the exception that caused the failure
916      * @param restoreTimeout the communication timeout value,
917      * in milliseconds, that should be reset
918      * @see #invokeComplete(int)
919      * @exception DebugException. Reasons include:
920      * <ul>
921      * <li>Failure communicating with the VM. The DebugException's
922      * status code contains the underlying exception responsible for
923      * the failure.</li>
924      * </ul>
925      */

926     protected void invokeFailed(String JavaDoc message, int code, Throwable JavaDoc e, int restoreTimeout) throws DebugException {
927         invokeComplete(restoreTimeout);
928         requestFailed(message, e, code);
929     }
930     
931     /**
932      * Called when a method invocation has returned, successfully
933      * or not. This method performs cleanup:<ul>
934      * <li>Resets the state of this thread to suspended</li>
935      * <li>Restores the communication timeout value</li>
936      * <li>Computes the new set of stack frames for this thread</code>
937      * </ul>
938      *
939      * @param restoreTimeout the communication timeout value,
940      * in milliseconds, that should be reset
941      * @see #invokeMethod(ClassType, ObjectReference, Method, List)
942      * @see #newInstance(ClassType, Method, List)
943      */

944     protected synchronized void invokeComplete(int restoreTimeout) {
945         if (!fIsEvaluatingConditionalBreakpoint) {
946             abortStep();
947         }
948         setInvokingMethod(false);
949         setRunning(false);
950         setRequestTimeout(restoreTimeout);
951         // update preserved stack frames
952
try {
953             computeStackFrames();
954         } catch (DebugException e) {
955             logError(e);
956         }
957     }
958     
959     /**
960      * Sets whether or not this thread is currently evaluating a conditional
961      * breakpoint expression. This state is maintained as a workaround to problems
962      * that can occur related to the interaction of stepping and expression
963      * evaluation. See bug 81658 for more details.
964      * @param evaluating
965      */

966     public void setEvaluatingConditionalBreakpoint(boolean evaluating) {
967         fIsEvaluatingConditionalBreakpoint= evaluating;
968     }
969     
970     /**
971      * @see IThread#getName()
972      */

973     public String JavaDoc getName() throws DebugException {
974         try {
975             fPreviousName = fThread.name();
976         } catch (RuntimeException JavaDoc e) {
977             // Don't bother reporting the exception when retrieving the name (bug 30785 & bug 33276)
978
if (e instanceof ObjectCollectedException) {
979                 if (fPreviousName == null) {
980                     fPreviousName= JDIDebugModelMessages.JDIThread_garbage_collected_1;
981                 }
982             } else if (e instanceof VMDisconnectedException) {
983                 if (fPreviousName == null) {
984                     fPreviousName= JDIDebugModelMessages.JDIThread_42;
985                 }
986             } else {
987                 targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_thread_name, new String JavaDoc[] {e.toString()}), e);
988             }
989         }
990         return fPreviousName;
991     }
992
993     /**
994      * @see IThread#getPriority
995      */

996     public int getPriority() throws DebugException {
997         // to get the priority, we must get the value from the "priority" field
998
Field p= null;
999         try {
1000            p= fThread.referenceType().fieldByName("priority"); //$NON-NLS-1$
1001
if (p == null) {
1002                requestFailed(JDIDebugModelMessages.JDIThread_no_priority_field, null);
1003            }
1004            Value v= fThread.getValue(p);
1005            if (v instanceof IntegerValue) {
1006                return ((IntegerValue)v).value();
1007            }
1008            requestFailed(JDIDebugModelMessages.JDIThread_priority_not_an_integer, null);
1009        } catch (RuntimeException JavaDoc e) {
1010            targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_thread_priority, new String JavaDoc[] {e.toString()}), e);
1011        }
1012        // execution will not fall through to this line, as
1013
// #targetRequestFailed or #requestFailed will throw
1014
// an exception
1015
return -1;
1016    }
1017
1018    /**
1019     * @see IThread#getTopStackFrame()
1020     */

1021    public synchronized IStackFrame getTopStackFrame() throws DebugException {
1022        List JavaDoc c= computeStackFrames();
1023        if (c.isEmpty()) {
1024            return null;
1025        }
1026        return (IStackFrame) c.get(0);
1027    }
1028
1029    /**
1030     * A breakpoint has suspended execution of this thread.
1031     * Aborts any step currently in process and fires a
1032     * suspend event.
1033     *
1034     * @param breakpoint the breakpoint that caused the suspend
1035     * @return whether this thread suspended
1036     */

1037    public synchronized boolean handleSuspendForBreakpoint(JavaBreakpoint breakpoint, boolean queueEvent) {
1038        addCurrentBreakpoint(breakpoint);
1039        setSuspendedQuiet(false);
1040        try {
1041            // update state to suspended but don't actually
1042
// suspend unless a registered listener agrees
1043
if (breakpoint.getSuspendPolicy() == IJavaBreakpoint.SUSPEND_VM) {
1044                ((JDIDebugTarget)getDebugTarget()).prepareToSuspendByBreakpoint(breakpoint);
1045            } else {
1046                setRunning(false);
1047            }
1048            
1049            // poll listeners
1050
boolean suspend = JDIDebugPlugin.getDefault().fireBreakpointHit(this, breakpoint);
1051            
1052            // suspend or resume
1053
if (suspend) {
1054                if (breakpoint.getSuspendPolicy() == IJavaBreakpoint.SUSPEND_VM) {
1055                    ((JDIDebugTarget)getDebugTarget()).suspendedByBreakpoint(breakpoint, queueEvent);
1056                }
1057                abortStep();
1058                if (queueEvent) {
1059                    queueSuspendEvent(DebugEvent.BREAKPOINT);
1060                } else {
1061                    fireSuspendEvent(DebugEvent.BREAKPOINT);
1062                }
1063            } else {
1064                if (breakpoint.getSuspendPolicy() == IJavaBreakpoint.SUSPEND_VM) {
1065                    ((JDIDebugTarget)getDebugTarget()).cancelSuspendByBreakpoint(breakpoint);
1066                } else {
1067                    setRunning(true);
1068                    // dispose cached stack frames so we re-retrieve on the next breakpoint
1069
preserveStackFrames();
1070                }
1071            }
1072            return suspend;
1073        } catch (CoreException e) {
1074            logError(e);
1075            setRunning(true);
1076            return false;
1077        }
1078    }
1079    
1080    public void wonSuspendVote(JavaBreakpoint breakpoint) {
1081        setSuspendedQuiet(false);
1082        try {
1083            setRunning(false);
1084            if (breakpoint.getSuspendPolicy() == IJavaBreakpoint.SUSPEND_VM) {
1085                ((JDIDebugTarget)getDebugTarget()).suspendedByBreakpoint(breakpoint, false);
1086            }
1087        } catch (CoreException e) {
1088            logError(e);
1089        }
1090    }
1091    
1092    /**
1093     * Updates the state of this thread to suspend for
1094     * the given breakpoint but does not fire notification
1095     * of the suspend. Do no abort the current step as the program
1096     * may be resumed quietly and the step may still finish.
1097     */

1098    public synchronized boolean handleSuspendForBreakpointQuiet(JavaBreakpoint breakpoint) {
1099        addCurrentBreakpoint(breakpoint);
1100        setSuspendedQuiet(true);
1101        setRunning(false);
1102        return true;
1103    }
1104
1105    /**
1106     * @see IStep#isStepping()
1107     */

1108    public boolean isStepping() {
1109        return getPendingStepHandler() != null;
1110    }
1111
1112    /**
1113     * @see ISuspendResume#isSuspended()
1114     */

1115    public boolean isSuspended() {
1116        return !fRunning && !fTerminated;
1117    }
1118
1119    /**
1120     * @see ISuspendResume#isSuspended()
1121     */

1122    public boolean isSuspendedQuiet() {
1123        return fSuspendedQuiet;
1124    }
1125
1126    /**
1127     * @see IJavaThread#isSystemThread()
1128     */

1129    public boolean isSystemThread() {
1130        return fIsSystemThread;
1131    }
1132
1133    /* (non-Javadoc)
1134     * @see org.eclipse.jdt.debug.core.IJavaThread#isDaemon()
1135     */

1136    public boolean isDaemon() throws DebugException {
1137        return fIsDaemon;
1138    }
1139
1140    /**
1141     * @see IJavaThread#getThreadGroupName()
1142     */

1143    public String JavaDoc getThreadGroupName() throws DebugException {
1144        if (fThreadGroupName == null) {
1145            ThreadGroupReference tgr= getUnderlyingThreadGroup();
1146            
1147            // bug# 20370
1148
if (tgr == null) {
1149                return null;
1150            }
1151            
1152            try {
1153                fThreadGroupName = tgr.name();
1154            } catch (RuntimeException JavaDoc e) {
1155                targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_thread_group_name, new String JavaDoc[] {e.toString()}), e);
1156                // execution will not reach this line, as
1157
// #targetRequestFailed will thrown an exception
1158
return null;
1159            }
1160        }
1161        return fThreadGroupName;
1162    }
1163
1164    /**
1165     * @see ITerminate#isTerminated()
1166     */

1167    public boolean isTerminated() {
1168        return fTerminated;
1169    }
1170    
1171    public synchronized boolean isOutOfSynch() throws DebugException {
1172        if (isSuspended() && ((JDIDebugTarget)getDebugTarget()).hasHCRFailed()) {
1173            List JavaDoc frames= computeStackFrames();
1174            Iterator JavaDoc iter= frames.iterator();
1175            while (iter.hasNext()) {
1176                if (((JDIStackFrame) iter.next()).isOutOfSynch()) {
1177                    return true;
1178                }
1179            }
1180            return false;
1181        }
1182        // If the thread is not suspended, there's no way to
1183
// say for certain that it is running out of synch code
1184
return false;
1185    }
1186    
1187    public boolean mayBeOutOfSynch() {
1188        if (!isSuspended()) {
1189            return ((JDIDebugTarget)getDebugTarget()).hasHCRFailed();
1190        }
1191        return false;
1192    }
1193    
1194    /**
1195     * Sets whether this thread is terminated
1196     *
1197     * @param terminated whether this thread is terminated
1198     */

1199    protected void setTerminated(boolean terminated) {
1200        fTerminated= terminated;
1201    }
1202
1203    /**
1204     * @see ISuspendResume#resume()
1205     */

1206    public synchronized void resume() throws DebugException {
1207        if (getDebugTarget().isSuspended()) {
1208            getDebugTarget().resume();
1209        } else {
1210            resumeThread(true);
1211        }
1212    }
1213    
1214    /**
1215     * @see ISuspendResume#resume()
1216     *
1217     * Updates the state of this thread to resumed,
1218     * but does not fire notification of the resumption.
1219     */

1220    public synchronized void resumeQuiet() throws DebugException {
1221        if (isSuspendedQuiet()) {
1222            resumeThread(false);
1223        }
1224    }
1225    
1226    /**
1227     * @see ISuspendResume#resume()
1228     *
1229     * Updates the state of this thread, but only fires
1230     * notification to listeners if <code>fireNotification</code>
1231     * is <code>true</code>.
1232     */

1233    private synchronized void resumeThread(boolean fireNotification) throws DebugException {
1234        if (!isSuspended() || (isPerformingEvaluation() && !isInvokingMethod())) {
1235            return;
1236        }
1237        try {
1238            setRunning(true);
1239            setSuspendedQuiet(false);
1240            if (fireNotification) {
1241                fireResumeEvent(DebugEvent.CLIENT_REQUEST);
1242            }
1243            preserveStackFrames();
1244            fThread.resume();
1245        } catch (VMDisconnectedException e) {
1246            disconnected();
1247        } catch (RuntimeException JavaDoc e) {
1248            setRunning(false);
1249            fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
1250            targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_resuming, new String JavaDoc[] {e.toString()}), e);
1251        }
1252    }
1253        
1254    /**
1255     * Sets whether this thread is currently executing.
1256     * When set to <code>true</code>, this thread's current
1257     * breakpoints are cleared.
1258     *
1259     * @param running whether this thread is executing
1260     */

1261    protected void setRunning(boolean running) {
1262        fRunning = running;
1263        if (running) {
1264            fCurrentBreakpoints.clear();
1265        }
1266    }
1267    
1268    protected void setSuspendedQuiet(boolean suspendedQuiet) {
1269        fSuspendedQuiet= suspendedQuiet;
1270    }
1271
1272    /**
1273     * Preserves stack frames to be used on the next suspend event.
1274     * Iterates through all current stack frames, setting their
1275     * state as invalid. This method should be called before this thread
1276     * is resumed, when stack frames are to be re-used when it later
1277     * suspends.
1278     *
1279     * @see computeStackFrames()
1280     */

1281    protected synchronized void preserveStackFrames() {
1282        fRefreshChildren = true;
1283        Iterator JavaDoc frames = fStackFrames.iterator();
1284        while (frames.hasNext()) {
1285            ((JDIStackFrame)frames.next()).setUnderlyingStackFrame(null);
1286        }
1287    }
1288
1289    /**
1290     * Disposes stack frames, to be completely re-computed on
1291     * the next suspend event. This method should be called before
1292     * this thread is resumed when stack frames are not to be re-used
1293     * on the next suspend.
1294     *
1295     * @see computeStackFrames()
1296     */

1297    protected synchronized void disposeStackFrames() {
1298        fStackFrames.clear();
1299        fRefreshChildren = true;
1300    }
1301    
1302    /**
1303     * This method is synchronized, such that the step request
1304     * begins before a background evaluation can be performed.
1305     *
1306     * @see IStep#stepInto()
1307     */

1308    public synchronized void stepInto() throws DebugException {
1309        if (!canStepInto()) {
1310            return;
1311        }
1312        StepHandler handler = new StepIntoHandler();
1313        handler.step();
1314    }
1315
1316    /**
1317     * This method is synchronized, such that the step request
1318     * begins before a background evaluation can be performed.
1319     *
1320     * @see IStep#stepOver()
1321     */

1322    public synchronized void stepOver() throws DebugException {
1323        if (!canStepOver()) {
1324            return;
1325        }
1326        StepHandler handler = new StepOverHandler();
1327        handler.step();
1328    }
1329
1330    /**
1331     * This method is synchronized, such that the step request
1332     * begins before a background evaluation can be performed.
1333     *
1334     * @see IStep#stepReturn()
1335     */

1336    public synchronized void stepReturn() throws DebugException {
1337        if (!canStepReturn()) {
1338            return;
1339        }
1340        StepHandler handler = new StepReturnHandler();
1341        handler.step();
1342    }
1343    
1344    protected void setOriginalStepKind(int stepKind) {
1345        fOriginalStepKind = stepKind;
1346    }
1347    
1348    protected int getOriginalStepKind() {
1349        return fOriginalStepKind;
1350    }
1351    
1352    protected void setOriginalStepLocation(Location location) {
1353        fOriginalStepLocation = location;
1354    }
1355    
1356    protected Location getOriginalStepLocation() {
1357        return fOriginalStepLocation;
1358    }
1359    
1360    protected void setOriginalStepStackDepth(int depth) {
1361        fOriginalStepStackDepth = depth;
1362    }
1363    
1364    protected int getOriginalStepStackDepth() {
1365        return fOriginalStepStackDepth;
1366    }
1367    
1368    /**
1369     * In cases where a user-requested step into encounters nothing but filtered code
1370     * (static initializers, synthetic methods, etc.), the default JDI behavior is to
1371     * put the instruction pointer back where it was before the step into. This requires
1372     * a second step to move forward. Since this is confusing to the user, we do an
1373     * extra step into in such situations. This method determines when such an extra
1374     * step into is necessary. It compares the current Location to the original
1375     * Location when the user step into was initiated. It also makes sure the stack depth
1376     * now is the same as when the step was initiated.
1377     */

1378    protected boolean shouldDoExtraStepInto(Location location) throws DebugException {
1379        if (getOriginalStepKind() != StepRequest.STEP_INTO) {
1380            return false;
1381        }
1382        if (getOriginalStepStackDepth() != getUnderlyingFrameCount()) {
1383            return false;
1384        }
1385        Location origLocation = getOriginalStepLocation();
1386        if (origLocation == null) {
1387            return false;
1388        }
1389        // We cannot simply check if the two Locations are equal using the equals()
1390
// method, since this checks the code index within the method. Even if the
1391
// code indices are different, the line numbers may be the same, in which case
1392
// we need to do the extra step into.
1393
Method origMethod = origLocation.method();
1394        Method currMethod = location.method();
1395        if (!origMethod.equals(currMethod)) {
1396            return false;
1397        }
1398        if (origLocation.lineNumber() != location.lineNumber()) {
1399            return false;
1400        }
1401        return true;
1402    }
1403    
1404    /**
1405     * Determines if a user did a step into and stepped through filtered code.
1406     * In this case, do a step return if the user has requested not to
1407     * step thru to an un-filtered location.
1408     */

1409    protected boolean shouldDoStepReturn() throws DebugException {
1410        if (getOriginalStepKind() == StepRequest.STEP_INTO) {
1411            if ((getOriginalStepStackDepth() + 1) < getUnderlyingFrameCount()) {
1412                return true;
1413            }
1414        }
1415        return false;
1416    }
1417    
1418    /**
1419     * @see ISuspendResume#suspend()
1420     */

1421    public synchronized void suspend() throws DebugException {
1422        try {
1423            // Abort any pending step request
1424
abortStep();
1425            setSuspendedQuiet(false);
1426            fEvaluationInterrupted = isPerformingEvaluation();
1427            suspendUnderlyingThread();
1428        } catch (RuntimeException JavaDoc e) {
1429            setRunning(true);
1430            targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_suspending, new String JavaDoc[] {e.toString()}), e);
1431        }
1432    }
1433    
1434    /**
1435     * Suspends the underlying thread asynchronously and fires notification when
1436     * the underlying thread is suspended.
1437     */

1438    protected synchronized void suspendUnderlyingThread() {
1439        if (fIsSuspending) {
1440            return;
1441        }
1442        if (isSuspended()) {
1443            fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
1444            return;
1445        }
1446        fIsSuspending= true;
1447        Thread JavaDoc thread= new Thread JavaDoc(new Runnable JavaDoc() {
1448            public void run() {
1449                try {
1450                    fThread.suspend();
1451                    int timeout= JDIDebugModel.getPreferences().getInt(JDIDebugModel.PREF_REQUEST_TIMEOUT);
1452                    long stop= System.currentTimeMillis() + timeout;
1453                    boolean suspended= isUnderlyingThreadSuspended();
1454                    while (System.currentTimeMillis() < stop && !suspended) {
1455                        try {
1456                            Thread.sleep(50);
1457                        } catch (InterruptedException JavaDoc e) {
1458                        }
1459                        suspended= isUnderlyingThreadSuspended();
1460                        if (suspended) {
1461                            break;
1462                        }
1463                    }
1464                    if (!suspended) {
1465                        IStatus status= new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), SUSPEND_TIMEOUT, MessageFormat.format(JDIDebugModelMessages.JDIThread_suspend_timeout, new String JavaDoc[] {new Integer JavaDoc(timeout).toString()}), null);
1466                        IStatusHandler handler= DebugPlugin.getDefault().getStatusHandler(status);
1467                        if (handler != null) {
1468                            try {
1469                                handler.handleStatus(status, JDIThread.this);
1470                            } catch (CoreException e) {
1471                            }
1472                        }
1473                    }
1474                    setRunning(false);
1475                    fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
1476                } catch (RuntimeException JavaDoc exception) {
1477                } finally {
1478                    fIsSuspending= false;
1479                }
1480            }
1481        });
1482        thread.setDaemon(true);
1483        thread.start();
1484    }
1485    
1486    public boolean isUnderlyingThreadSuspended() {
1487        return fThread.isSuspended();
1488    }
1489
1490    /**
1491     * Notifies this thread that it has been suspended due
1492     * to a VM suspend.
1493     */

1494    protected synchronized void suspendedByVM() {
1495        setRunning(false);
1496        setSuspendedQuiet(false);
1497    }
1498
1499    /**
1500     * Notifies this thread that is about to be resumed due
1501     * to a VM resume.
1502     */

1503    protected synchronized void resumedByVM() throws DebugException {
1504        setRunning(true);
1505        preserveStackFrames();
1506        // This method is called *before* the VM is actually resumed.
1507
// To ensure that all threads will fully resume when the VM
1508
// is resumed, make sure the suspend count of each thread
1509
// is no greater than 1. @see Bugs 23328 and 27622
1510
ThreadReference thread= fThread;
1511        while (thread.suspendCount() > 1) {
1512            try {
1513                thread.resume();
1514            } catch (ObjectCollectedException e) {
1515            } catch (VMDisconnectedException e) {
1516                disconnected();
1517            }catch (RuntimeException JavaDoc e) {
1518                setRunning(false);
1519                fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
1520                targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_resuming, new String JavaDoc[] {e.toString()}), e); //
1521
}
1522        }
1523    }
1524
1525    /**
1526     * @see ITerminate#terminate()
1527     */

1528    public void terminate() throws DebugException {
1529        terminateEvaluation();
1530        getDebugTarget().terminate();
1531    }
1532
1533    /**
1534     * Drops to the given stack frame
1535     *
1536     * @exception DebugException if this method fails. Reasons include:
1537     * <ul>
1538     * <li>Failure communicating with the VM. The DebugException's
1539     * status code contains the underlying exception responsible for
1540     * the failure.</li>
1541     * </ul>
1542     */

1543    protected void dropToFrame(IStackFrame frame) throws DebugException {
1544        JDIDebugTarget target= (JDIDebugTarget) getDebugTarget();
1545        if (target.canPopFrames()) {
1546            // JDK 1.4 support
1547
try {
1548                // Pop the drop frame and all frames above it
1549
popFrame(frame);
1550                stepInto();
1551            } catch (RuntimeException JavaDoc exception) {
1552                targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_dropping_to_frame, new String JavaDoc[] {exception.toString()}),exception);
1553            }
1554        } else {
1555            // J9 support
1556
// This block is synchronized, such that the step request
1557
// begins before a background evaluation can be performed.
1558
synchronized (this) {
1559                StepHandler handler = new DropToFrameHandler(frame);
1560                handler.step();
1561            }
1562        }
1563    }
1564    
1565    protected void popFrame(IStackFrame frame) throws DebugException {
1566        JDIDebugTarget target= (JDIDebugTarget)getDebugTarget();
1567        if (target.canPopFrames()) {
1568            // JDK 1.4 support
1569
try {
1570                // Pop the frame and all frames above it
1571
StackFrame jdiFrame= null;
1572                int desiredSize= fStackFrames.size() - fStackFrames.indexOf(frame) - 1;
1573                int lastSize= fStackFrames.size() + 1; // Set up to pass the first test
1574
int size= fStackFrames.size();
1575                while (size < lastSize && size > desiredSize) {
1576                    // Keep popping frames until the stack stops getting smaller
1577
// or popFrame is gone.
1578
// see Bug 8054
1579
jdiFrame = ((JDIStackFrame) frame).getUnderlyingStackFrame();
1580                    preserveStackFrames();
1581                    fThread.popFrames(jdiFrame);
1582                    lastSize= size;
1583                    size= computeStackFrames().size();
1584                }
1585            } catch (IncompatibleThreadStateException exception) {
1586                targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_popping, new String JavaDoc[] {exception.toString()}),exception);
1587            } catch (InvalidStackFrameException exception) {
1588                // InvalidStackFrameException can be thrown when all but the
1589
// deepest frame were popped. Fire a changed notification
1590
// in case this has occured.
1591
fireChangeEvent(DebugEvent.CONTENT);
1592                targetRequestFailed(exception.toString(),exception);
1593            } catch (RuntimeException JavaDoc exception) {
1594                targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_popping, new String JavaDoc[] {exception.toString()}),exception);
1595            }
1596        }
1597    }
1598    
1599    /**
1600     * Steps until the specified stack frame is the top frame. Provides
1601     * ability to step over/return in the non-top stack frame.
1602     * This method is synchronized, such that the step request
1603     * begins before a background evaluation can be performed.
1604     *
1605     * @exception DebugException if this method fails. Reasons include:
1606     * <ul>
1607     * <li>Failure communicating with the VM. The DebugException's
1608     * status code contains the underlying exception responsible for
1609     * the failure.</li>
1610     * </ul>
1611     */

1612    protected synchronized void stepToFrame(IStackFrame frame) throws DebugException {
1613        if (!canStepReturn()) {
1614            return;
1615        }
1616        StepHandler handler = new StepToFrameHandler(frame);
1617        handler.step();
1618    }
1619        
1620    /**
1621     * Aborts the current step, if any.
1622     */

1623    protected void abortStep() {
1624        StepHandler handler = getPendingStepHandler();
1625        if (handler != null) {
1626            handler.abort();
1627        }
1628    }
1629
1630    /**
1631     * @see IJavaThread#findVariable(String)
1632     */

1633    public IJavaVariable findVariable(String JavaDoc varName) throws DebugException {
1634        if (isSuspended()) {
1635            try {
1636                IStackFrame[] stackFrames= getStackFrames();
1637                for (int i = 0; i < stackFrames.length; i++) {
1638                    IJavaStackFrame sf= (IJavaStackFrame)stackFrames[i];
1639                    IJavaVariable var= sf.findVariable(varName);
1640                    if (var != null) {
1641                        return var;
1642                    }
1643                }
1644            } catch (DebugException e) {
1645                // if the thread has since reusmed, return null (no need to report error)
1646
if (e.getStatus().getCode() != IJavaThread.ERR_THREAD_NOT_SUSPENDED) {
1647                    throw e;
1648                }
1649            }
1650        }
1651        return null;
1652    }
1653        
1654    /**
1655     * Notification this thread has terminated - update state
1656     * and fire a terminate event.
1657     */

1658    protected void terminated() {
1659        setTerminated(true);
1660        setRunning(false);
1661        fireTerminateEvent();
1662    }
1663    
1664    /**
1665     * Returns this thread on the underlying VM which this
1666     * model thread is a proxy to.
1667     *
1668     * @return underlying thread
1669     */

1670    public ThreadReference getUnderlyingThread() {
1671        return fThread;
1672    }
1673    
1674    /**
1675     * Sets the underlying thread that this model object
1676     * is a proxy to.
1677     *
1678     * @param thread underlying thread on target VM
1679     */

1680    protected void setUnderlyingThread(ThreadReference thread) {
1681        fThread = thread;
1682    }
1683    
1684    /**
1685     * Returns this thread's underlying thread group.
1686     *
1687     * @return thread group
1688     * @exception DebugException if this method fails. Reasons include:
1689     * <ul>
1690     * <li>Failure communicating with the VM. The DebugException's
1691     * status code contains the underlying exception responsible for
1692     * the failure.</li>
1693     * <li>Retrieving the underlying thread group is not supported
1694     * on the underlying VM</li>
1695     * </ul>
1696     */

1697    protected ThreadGroupReference getUnderlyingThreadGroup() throws DebugException {
1698        if (fThreadGroup == null) {
1699            try {
1700                fThreadGroup = fThread.threadGroup();
1701            } catch (UnsupportedOperationException JavaDoc e) {
1702                requestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_thread_group, new String JavaDoc[] {e.toString()}), e);
1703                // execution will not reach this line, as
1704
// #requestFailed will throw an exception
1705
return null;
1706            } catch (VMDisconnectedException e) {
1707                // ignore disconnect
1708
return null;
1709            } catch (ObjectCollectedException e) {
1710                // ignore object collected
1711
return null;
1712            } catch (RuntimeException JavaDoc e) {
1713                targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_thread_group, new String JavaDoc[] {e.toString()}), e);
1714                // execution will not reach this line, as
1715
// #targetRequestFailed will throw an exception
1716
return null;
1717            }
1718        }
1719        return fThreadGroup;
1720    }
1721            
1722    /**
1723     * @see IJavaThread#isPerformingEvaluation()
1724     */

1725    public boolean isPerformingEvaluation() {
1726        return fIsPerformingEvaluation;
1727    }
1728    
1729    /**
1730     * Returns whether this thread is currently performing
1731     * a method invokation
1732     */

1733    public boolean isInvokingMethod() {
1734        return fIsInvokingMethod;
1735    }
1736    
1737    /**
1738     * Returns whether this thread is currently ignoring
1739     * breakpoints.
1740     */

1741    public boolean isIgnoringBreakpoints() {
1742        return !fHonorBreakpoints;
1743    }
1744    
1745    /**
1746     * Sets whether this thread is currently invoking a method
1747     *
1748     * @param evaluating whether this thread is currently
1749     * invoking a method
1750     */

1751    protected void setInvokingMethod(boolean invoking) {
1752        fIsInvokingMethod= invoking;
1753    }
1754    
1755    /**
1756     * Sets the step handler currently handling a step
1757     * request.
1758     *
1759     * @param handler the current step handler, or <code>null</code>
1760     * if none
1761     */

1762    protected void setPendingStepHandler(StepHandler handler) {
1763        fStepHandler = handler;
1764    }
1765    
1766    /**
1767     * Returns the step handler currently handling a step
1768     * request, or <code>null</code> if none.
1769     *
1770     * @return step handler, or <code>null</code> if none
1771     */

1772    protected StepHandler getPendingStepHandler() {
1773        return fStepHandler;
1774    }
1775    
1776    
1777    /**
1778     * Helper class to perform stepping an a thread.
1779     */

1780    abstract class StepHandler implements IJDIEventListener {
1781        /**
1782         * Request for stepping in the underlying VM
1783         */

1784        private StepRequest fStepRequest;
1785        
1786        /**
1787         * Initiates a step in the underlying VM by creating a step
1788         * request of the appropriate kind (over, into, return),
1789         * and resuming this thread. When a step is initiated it
1790         * is registered with its thread as a pending step. A pending
1791         * step could be cancelled if a breakpoint suspends execution
1792         * during the step.
1793         * <p>
1794         * This thread's state is set to running and stepping, and
1795         * stack frames are invalidated (but preserved to be re-used
1796         * when the step completes). A resume event with a step detail
1797         * is fired for this thread.
1798         * </p>
1799         * Note this method does nothing if this thread has no stack frames.
1800         *
1801         * @exception DebugException if this method fails. Reasons include:
1802         * <ul>
1803         * <li>Failure communicating with the VM. The DebugException's
1804         * status code contains the underlying exception responsible for
1805         * the failure.</li>
1806         * </ul>
1807         */

1808        protected void step() throws DebugException {
1809            JDIStackFrame top = (JDIStackFrame)getTopStackFrame();
1810            if (top == null) {
1811                return;
1812            }
1813            setOriginalStepKind(getStepKind());
1814            Location location = top.getUnderlyingStackFrame().location();
1815            setOriginalStepLocation(location);
1816            setOriginalStepStackDepth(computeStackFrames().size());
1817            setStepRequest(createStepRequest());
1818            setPendingStepHandler(this);
1819            addJDIEventListener(this, getStepRequest());
1820            setRunning(true);
1821            preserveStackFrames();
1822            fireResumeEvent(getStepDetail());
1823            invokeThread();
1824        }
1825        
1826        /**
1827         * Resumes the underlying thread to initiate the step.
1828         * By default the thread is resumed. Step handlers that
1829         * require other actions can override this method.
1830         *
1831         * @exception DebugException if this method fails. Reasons include:
1832         * <ul>
1833         * <li>Failure communicating with the VM. The DebugException's
1834         * status code contains the underlying exception responsible for
1835         * the failure.</li>
1836         * </ul>
1837         */

1838        protected void invokeThread() throws DebugException {
1839            try {
1840                fThread.resume();
1841            } catch (RuntimeException JavaDoc e) {
1842                stepEnd();
1843                targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_stepping, new String JavaDoc[] {e.toString()}), e);
1844            }
1845        }
1846        
1847        /**
1848         * Creates and returns a step request specific to this step
1849         * handler. Subclasses must override <code>getStepKind()</code>
1850         * to return the kind of step it implements.
1851         *
1852         * @return step request
1853         * @exception DebugException if this method fails. Reasons include:
1854         * <ul>
1855         * <li>Failure communicating with the VM. The DebugException's
1856         * status code contains the underlying exception responsible for
1857         * the failure.</li>
1858         * </ul>
1859         */

1860        protected StepRequest createStepRequest() throws DebugException {
1861            return createStepRequest(getStepKind());
1862        }
1863        
1864        /**
1865         * Creates and returns a step request of the specified kind.
1866         *
1867         * @param one of <code>StepRequest.STEP_INTO</code>,
1868         * <code>StepRequest.STEP_OVER</code>, <code>StepRequest.STEP_OUT</code>
1869         * @return step request
1870         * @exception DebugException if this method fails. Reasons include:
1871         * <ul>
1872         * <li>Failure communicating with the VM. The DebugException's
1873         * status code contains the underlying exception responsible for
1874         * the failure.</li>
1875         * </ul>
1876         */

1877        protected StepRequest createStepRequest(int kind) throws DebugException {
1878            EventRequestManager manager = getEventRequestManager();
1879            if (manager == null) {
1880                requestFailed(JDIDebugModelMessages.JDIThread_Unable_to_create_step_request___VM_disconnected__1, null);
1881            }
1882            try {
1883                StepRequest request = manager.createStepRequest(fThread, StepRequest.STEP_LINE, kind);
1884                request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
1885                request.addCountFilter(1);
1886                attachFiltersToStepRequest(request);
1887                request.enable();
1888                return request;
1889            } catch (RuntimeException JavaDoc e) {
1890                targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_creating_step_request, new String JavaDoc[] {e.toString()}), e);
1891            }
1892            // this line will never be executed, as the try block
1893
// will either return, or the catch block will throw
1894
// an exception
1895
return null;
1896            
1897        }
1898        
1899        /**
1900         * Returns the kind of step this handler implements.
1901         *
1902         * @return one of <code>StepRequest.STEP_INTO</code>,
1903         * <code>StepRequest.STEP_OVER</code>, <code>StepRequest.STEP_OUT</code>
1904         */

1905        protected abstract int getStepKind();
1906        
1907        /**
1908         * Returns the detail for this step event.
1909         *
1910         * @return one of <code>DebugEvent.STEP_INTO</code>,
1911         * <code>DebugEvent.STEP_OVER</code>, <code>DebugEvent.STEP_RETURN</code>
1912         */

1913        protected abstract int getStepDetail();
1914        
1915        /**
1916         * Sets the step request created by this handler in
1917         * the underlying VM. Set to <code>null<code> when
1918         * this handler deletes its request.
1919         *
1920         * @param request step request
1921         */

1922        protected void setStepRequest(StepRequest request) {
1923            fStepRequest = request;
1924        }
1925        
1926        /**
1927         * Returns the step request created by this handler in
1928         * the underlying VM.
1929         *
1930         * @return step request
1931         */

1932        protected StepRequest getStepRequest() {
1933            return fStepRequest;
1934        }
1935        
1936        /**
1937         * Deletes this handler's step request from the underlying VM
1938         * and removes this handler as an event listener.
1939         */

1940        protected void deleteStepRequest() {
1941            removeJDIEventListener(this, getStepRequest());
1942            try {
1943                EventRequestManager manager = getEventRequestManager();
1944                if (manager != null) {
1945                    manager.deleteEventRequest(getStepRequest());
1946                }
1947                setStepRequest(null);
1948            } catch (RuntimeException JavaDoc e) {
1949                logError(e);
1950            }
1951        }
1952        
1953        /**
1954         * If step filters are currently switched on and the current location is not a filtered
1955         * location, set all active filters on the step request.
1956         */

1957        protected void attachFiltersToStepRequest(StepRequest request) {
1958            
1959            if (applyStepFilters() && isStepFiltersEnabled()) {
1960                Location currentLocation= getOriginalStepLocation();
1961                if (currentLocation == null || !JAVA_STRATUM_CONSTANT.equals(currentLocation.declaringType().defaultStratum())) {
1962                    return;
1963                }
1964// Removed the fix for bug 5587, to address bug 41510
1965
// //check if the user has already stopped in a filtered location
1966
// //is so do not filter @see bug 5587
1967
// ReferenceType type= currentLocation.declaringType();
1968
// String typeName= type.name();
1969
String JavaDoc[] activeFilters = getJavaDebugTarget().getStepFilters();
1970// for (int i = 0; i < activeFilters.length; i++) {
1971
// StringMatcher matcher = new StringMatcher(activeFilters[i], false, false);
1972
// if (matcher.match(typeName)) {
1973
// return;
1974
// }
1975
// }
1976
if (activeFilters != null) {
1977                    for (int i = 0; i < activeFilters.length; i++) {
1978                        request.addClassExclusionFilter(activeFilters[i]);
1979                    }
1980                }
1981            }
1982        }
1983        
1984        /**
1985         * Returns whether this step handler should use step
1986         * filters when creating its step request. By default,
1987         * step filters can be used by any step request.
1988         * Subclasses must override if/when required.
1989         *
1990         * @return whether this step handler should use step
1991         * filters when creating its step request
1992         */

1993        protected boolean applyStepFilters() {
1994            return true;
1995        }
1996        
1997        /**
1998         * Notification the step request has completed.
1999         * If the current location matches one of the user-specified
2000         * step filter criteria (e.g., synthetic methods, static initializers),
2001         * then continue stepping.
2002         *
2003         * @see IJDIEventListener#handleEvent(Event, JDIDebugTarget)
2004         */

2005        public boolean handleEvent(Event event, JDIDebugTarget target) {
2006            try {
2007                StepEvent stepEvent = (StepEvent) event;
2008                Location currentLocation = stepEvent.location();
2009
2010                
2011                if (!getJavaDebugTarget().isStepThruFilters()) {
2012                    if (shouldDoStepReturn()) {
2013                        deleteStepRequest();
2014                        createSecondaryStepRequest(StepRequest.STEP_OUT);
2015                        return true;
2016                    }
2017                }
2018                // if the ending step location is filtered and we did not start from
2019
// a filtered location, or if we're back where
2020
// we started on a step into, do another step of the same kind
2021
if (locationShouldBeFiltered(currentLocation) || shouldDoExtraStepInto(currentLocation)) {
2022                    setRunning(true);
2023                    deleteStepRequest();
2024                    createSecondaryStepRequest();
2025                    return true;
2026                // otherwise, we're done stepping
2027
}
2028                stepEnd();
2029                return false;
2030            } catch (DebugException e) {
2031                logError(e);
2032                stepEnd();
2033                return false;
2034            }
2035        }
2036        
2037        
2038        
2039        /* (non-Javadoc)
2040         * @see org.eclipse.jdt.internal.debug.core.IJDIEventListener#wonSuspendVote(com.sun.jdi.event.Event, org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget)
2041         */

2042        public void wonSuspendVote(Event event, JDIDebugTarget target) {
2043            // do nothing
2044
}
2045
2046        /**
2047         * Returns <code>true</code> if the StepEvent's Location is a Method that the
2048         * user has indicated (via the step filter preferences) should be
2049         * filtered and the step was not initiated from a filtered location.
2050         * Returns <code>false</code> otherwise.
2051         */

2052        protected boolean locationShouldBeFiltered(Location location) throws DebugException {
2053            if (applyStepFilters()) {
2054                Location origLocation= getOriginalStepLocation();
2055                if (origLocation != null) {
2056                    return !locationIsFiltered(origLocation.method()) && locationIsFiltered(location.method());
2057                }
2058            }
2059            return false;
2060        }
2061        /**
2062         * Returns <code>true</code> if the StepEvent's Location is a Method that the
2063         * user has indicated (via the step filter preferences) should be
2064         * filtered. Returns <code>false</code> otherwise.
2065         */

2066        protected boolean locationIsFiltered(Method method) {
2067            if (isStepFiltersEnabled()) {
2068                boolean filterStatics = getJavaDebugTarget().isFilterStaticInitializers();
2069                boolean filterSynthetics = getJavaDebugTarget().isFilterSynthetics();
2070                boolean filterConstructors = getJavaDebugTarget().isFilterConstructors();
2071                if (!(filterStatics || filterSynthetics || filterConstructors)) {
2072                    return false;
2073                }
2074                
2075                if ((filterStatics && method.isStaticInitializer()) ||
2076                    (filterSynthetics && method.isSynthetic()) ||
2077                    (filterConstructors && method.isConstructor()) ) {
2078                    return true;
2079                }
2080            }
2081            
2082            return false;
2083        }
2084
2085        /**
2086         * Cleans up when a step completes.<ul>
2087         * <li>Thread state is set to suspended.</li>
2088         * <li>Stepping state is set to false</li>
2089         * <li>Stack frames and variables are incrementally updated</li>
2090         * <li>The step request is deleted and removed as
2091         * and event listener</li>
2092         * <li>A suspend event is fired</li>
2093         * </ul>
2094         */

2095        protected void stepEnd() {
2096            setRunning(false);
2097            deleteStepRequest();
2098            setPendingStepHandler(null);
2099            queueSuspendEvent(DebugEvent.STEP_END);
2100        }
2101        
2102        /**
2103         * Creates another step request in the underlying thread of the
2104         * appropriate kind (over, into, return). This thread will
2105         * be resumed by the event dispatcher as this event handler
2106         * will vote to resume suspended threads. When a step is
2107         * initiated it is registered with its thread as a pending
2108         * step. A pending step could be cancelled if a breakpoint
2109         * suspends execution during the step.
2110         *
2111         * @exception DebugException if this method fails. Reasons include:
2112         * <ul>
2113         * <li>Failure communicating with the VM. The DebugException's
2114         * status code contains the underlying exception responsible for
2115         * the failure.</li>
2116         * </ul>
2117         */

2118        protected void createSecondaryStepRequest() throws DebugException {
2119            createSecondaryStepRequest(getStepKind());
2120        }
2121        
2122        /**
2123         * Creates another step request in the underlying thread of the
2124         * specified kind (over, into, return). This thread will
2125         * be resumed by the event dispatcher as this event handler
2126         * will vote to resume suspended threads. When a step is
2127         * initiated it is registered with its thread as a pending
2128         * step. A pending step could be cancelled if a breakpoint
2129         * suspends execution during the step.
2130         *
2131         * @param one of <code>StepRequest.STEP_INTO</code>,
2132         * <code>StepRequest.STEP_OVER</code>, <code>StepRequest.STEP_OUT</code>
2133         * @exception DebugException if this method fails. Reasons include:
2134         * <ul>
2135         * <li>Failure communicating with the VM. The DebugException's
2136         * status code contains the underlying exception responsible for
2137         * the failure.</li>
2138         * </ul>
2139         */

2140        protected void createSecondaryStepRequest(int kind) throws DebugException {
2141            setStepRequest(createStepRequest(kind));
2142            setPendingStepHandler(this);
2143            addJDIEventListener(this, getStepRequest());
2144        }
2145        
2146        /**
2147         * Aborts this step request if active. The step event
2148         * request is deleted from the underlying VM.
2149         */

2150        protected void abort() {
2151            if (getStepRequest() != null) {
2152                deleteStepRequest();
2153                setPendingStepHandler(null);
2154            }
2155        }
2156}
2157    
2158    /**
2159     * Handler for step over requests.
2160     */

2161    class StepOverHandler extends StepHandler {
2162        /**
2163         * @see StepHandler#getStepKind()
2164         */

2165        protected int getStepKind() {
2166            return StepRequest.STEP_OVER;
2167        }
2168        
2169        /**
2170         * @see StepHandler#getStepDetail()
2171         */

2172        protected int getStepDetail() {
2173            return DebugEvent.STEP_OVER;
2174        }
2175    }
2176    
2177    /**
2178     * Handler for step into requests.
2179     */

2180    class StepIntoHandler extends StepHandler {
2181        /**
2182         * @see StepHandler#getStepKind()
2183         */

2184        protected int getStepKind() {
2185            return StepRequest.STEP_INTO;
2186        }
2187        
2188        /**
2189         * @see StepHandler#getStepDetail()
2190         */

2191        protected int getStepDetail() {
2192            return DebugEvent.STEP_INTO;
2193        }
2194        
2195    }
2196    
2197    /**
2198     * Handler for step return requests.
2199     */

2200    class StepReturnHandler extends StepHandler {
2201        /* (non-Javadoc)
2202         * @see org.eclipse.jdt.internal.debug.core.model.JDIThread.StepHandler#locationShouldBeFiltered(com.sun.jdi.Location)
2203         */

2204        protected boolean locationShouldBeFiltered(Location location) throws DebugException {
2205            // if still at the same depth, do another step return (see bug 38744)
2206
if (getOriginalStepStackDepth() == getUnderlyingFrameCount()) {
2207                return true;
2208            }
2209            return super.locationShouldBeFiltered(location);
2210        }
2211
2212        /**
2213         * @see StepHandler#getStepKind()
2214         */

2215        protected int getStepKind() {
2216            return StepRequest.STEP_OUT;
2217        }
2218        
2219        /**
2220         * @see StepHandler#getStepDetail()
2221         */

2222        protected int getStepDetail() {
2223            return DebugEvent.STEP_RETURN;
2224        }
2225    }
2226    
2227    /**
2228     * Handler for stepping to a specific stack frame
2229     * (stepping in the non-top stack frame). Step returns
2230     * are performed until a specified stack frame is reached
2231     * or the thread is suspended (explicitly, or by a
2232     * breakpoint).
2233     */

2234    class StepToFrameHandler extends StepReturnHandler {
2235        
2236        /**
2237         * The number of frames that should be left on the stack
2238         */

2239        private int fRemainingFrames;
2240        
2241        /**
2242         * Constructs a step handler to step until the specified
2243         * stack frame is reached.
2244         *
2245         * @param frame the stack frame to step to
2246         * @exception DebugException if this method fails. Reasons include:
2247         * <ul>
2248         * <li>Failure communicating with the VM. The DebugException's
2249         * status code contains the underlying exception responsible for
2250         * the failure.</li>
2251         * </ul>
2252         */

2253        protected StepToFrameHandler(IStackFrame frame) throws DebugException {
2254            List JavaDoc frames = computeStackFrames();
2255            setRemainingFrames(frames.size() - frames.indexOf(frame));
2256        }
2257        
2258        /**
2259         * Sets the number of frames that should be
2260         * remaining on the stack when done.
2261         *
2262         * @param num number of remaining frames
2263         */

2264        protected void setRemainingFrames(int num) {
2265            fRemainingFrames = num;
2266        }
2267        
2268        /**
2269         * Returns number of frames that should be
2270         * remaining on the stack when done
2271         *
2272         * @return number of frames that should be left
2273         */

2274        protected int getRemainingFrames() {
2275            return fRemainingFrames;
2276        }
2277        
2278        /**
2279         * Notification the step request has completed.
2280         * If in the desired frame, complete the step
2281         * request normally. If not in the desired frame,
2282         * another step request is created and this thread
2283         * is resumed.
2284         *
2285         * @see IJDIEventListener#handleEvent(Event, JDIDebugTarget)
2286         */

2287        public boolean handleEvent(Event event, JDIDebugTarget target) {
2288            try {
2289                int numFrames = getUnderlyingFrameCount();
2290                // tos should not be null
2291
if (numFrames <= getRemainingFrames()) {
2292                    stepEnd();
2293                    return false;
2294                }
2295                // reset running state and keep going
2296
setRunning(true);
2297                deleteStepRequest();
2298                createSecondaryStepRequest();
2299                return true;
2300            } catch (DebugException e) {
2301                logError(e);
2302                stepEnd();
2303                return false;
2304            }
2305        }
2306    }
2307    
2308    /**
2309     * Handles dropping to a specified frame.
2310     */

2311    class DropToFrameHandler extends StepReturnHandler {
2312        
2313        /**
2314         * The number of frames to drop off the
2315         * stack.
2316         */

2317        private int fFramesToDrop;
2318        
2319        /**
2320         * Constructs a handler to drop to the specified
2321         * stack frame.
2322         *
2323         * @param frame the stack frame to drop to
2324         * @exception DebugException if this method fails. Reasons include:
2325         * <ul>
2326         * <li>Failure communicating with the VM. The DebugException's
2327         * status code contains the underlying exception responsible for
2328         * the failure.</li>
2329         * </ul>
2330         */

2331        protected DropToFrameHandler(IStackFrame frame) throws DebugException {
2332            List JavaDoc frames = computeStackFrames();
2333            setFramesToDrop(frames.indexOf(frame));
2334        }
2335        
2336        /**
2337         * Sets the number of frames to pop off the stack.
2338         *
2339         * @param num number of frames to pop
2340         */

2341        protected void setFramesToDrop(int num) {
2342            fFramesToDrop = num;
2343        }
2344        
2345        /**
2346         * Returns the number of frames to pop off the stack.
2347         *
2348         * @return remaining number of frames to pop
2349         */

2350        protected int getFramesToDrop() {
2351            return fFramesToDrop;
2352        }
2353        
2354        /**
2355         * To drop a frame or re-enter, the underlying thread is instructed
2356         * to do a return. When the frame count is less than zero, the
2357         * step being performed is a "step return", so a regular invocation
2358         * is performed.
2359         *
2360         * @see StepHandler#invokeThread()
2361         */

2362        protected void invokeThread() throws DebugException {
2363            if (getFramesToDrop() < 0) {
2364                super.invokeThread();
2365            } else {
2366                try {
2367                    org.eclipse.jdi.hcr.ThreadReference hcrThread= (org.eclipse.jdi.hcr.ThreadReference) fThread;
2368                    hcrThread.doReturn(null, true);
2369                } catch (RuntimeException JavaDoc e) {
2370                    stepEnd();
2371                    targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_while_popping_stack_frame, new String JavaDoc[] {e.toString()}), e);
2372                }
2373            }
2374        }
2375        
2376        /**
2377         * Notification that the pop has completed. If there are
2378         * more frames to pop, keep going, otherwise re-enter the
2379         * top frame. Returns false, as this handler will resume this
2380         * thread with a special invocation (<code>doReturn</code>).
2381         *
2382         * @see IJDIEventListener#handleEvent(Event, JDIDebugTarget)
2383         * @see #invokeThread()
2384         */

2385        public boolean handleEvent(Event event, JDIDebugTarget target) {
2386            // pop is complete, update number of frames to drop
2387
setFramesToDrop(getFramesToDrop() - 1);
2388            try {
2389                if (getFramesToDrop() >= -1) {
2390                    deleteStepRequest();
2391                    doSecondaryStep();
2392                } else {
2393                    stepEnd();
2394                }
2395            } catch (DebugException e) {
2396                stepEnd();
2397                logError(e);
2398            }
2399            return false;
2400        }
2401        
2402        /**
2403         * Pops a secondary frame off the stack, does a re-enter,
2404         * or a step-into.
2405         *
2406         * @exception DebugException if this method fails. Reasons include:
2407         * <ul>
2408         * <li>Failure communicating with the VM. The DebugException's
2409         * status code contains the underlying exception responsible for
2410         * the failure.</li>
2411         * </ul>
2412         */

2413        protected void doSecondaryStep() throws DebugException {
2414            setStepRequest(createStepRequest());
2415            setPendingStepHandler(this);
2416            addJDIEventListener(this, getStepRequest());
2417            invokeThread();
2418        }
2419
2420        /**
2421         * Creates and returns a step request. If there
2422         * are no more frames to drop, a re-enter request
2423         * is made. If the re-enter is complete, a step-into
2424         * request is created.
2425         *
2426         * @return step request
2427         * @exception DebugException if this method fails. Reasons include:
2428         * <ul>
2429         * <li>Failure communicating with the VM. The DebugException's
2430         * status code contains the underlying exception responsible for
2431         * the failure.</li>
2432         * </ul>
2433         */

2434        protected StepRequest createStepRequest() throws DebugException {
2435            EventRequestManager manager = getEventRequestManager();
2436            if (manager == null) {
2437                requestFailed(JDIDebugModelMessages.JDIThread_Unable_to_create_step_request___VM_disconnected__2, null);
2438            }
2439            int num = getFramesToDrop();
2440            if (num > 0) {
2441                return super.createStepRequest();
2442            } else if (num == 0) {
2443                try {
2444                    StepRequest request = ((org.eclipse.jdi.hcr.EventRequestManager) manager).createReenterStepRequest(fThread);
2445                    request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
2446                    request.addCountFilter(1);
2447                    request.enable();
2448                    return request;
2449                } catch (RuntimeException JavaDoc e) {
2450                    targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_creating_step_request, new String JavaDoc[] {e.toString()}), e);
2451                }
2452            } else if (num == -1) {
2453                try {
2454                    StepRequest request = manager.createStepRequest(fThread, StepRequest.STEP_LINE, StepRequest.STEP_INTO);
2455                    request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
2456                    request.addCountFilter(1);
2457                    request.enable();
2458                    return request;
2459                } catch (RuntimeException JavaDoc e) {
2460                    targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_creating_step_request, new String JavaDoc[] {e.toString()}), e);
2461                }
2462            }
2463            // this line will never be executed, as the try block
2464
// will either return, or the catch block with throw
2465
// an exception
2466
return null;
2467        }
2468    }
2469    
2470
2471    /**
2472     * @see IThread#hasStackFrames()
2473     */

2474    public boolean hasStackFrames() throws DebugException {
2475        return isSuspended();
2476    }
2477        
2478    /**
2479     * @see IAdaptable#getAdapter(Class)
2480     */

2481    public Object JavaDoc getAdapter(Class JavaDoc adapter) {
2482        if (adapter == IJavaThread.class) {
2483            return this;
2484        }
2485        if (adapter == IJavaStackFrame.class) {
2486            try {
2487                return getTopStackFrame();
2488            } catch (DebugException e) {
2489                // do nothing if not able to get frame
2490
}
2491        }
2492        return super.getAdapter(adapter);
2493    }
2494    
2495    /**
2496     * @see org.eclipse.jdt.debug.core.IJavaThread#hasOwnedMonitors()
2497     */

2498    public boolean hasOwnedMonitors() throws DebugException {
2499        return isSuspended() && getOwnedMonitors().length > 0;
2500    }
2501    
2502    
2503    /**
2504     * @see org.eclipse.jdt.debug.core.IJavaThread#getOwnedMonitors()
2505     */

2506    public IJavaObject[] getOwnedMonitors() throws DebugException {
2507        try {
2508            JDIDebugTarget target= (JDIDebugTarget)getDebugTarget();
2509            List JavaDoc ownedMonitors= fThread.ownedMonitors();
2510            IJavaObject[] javaOwnedMonitors= new IJavaObject[ownedMonitors.size()];
2511            Iterator JavaDoc itr= ownedMonitors.iterator();
2512            int i= 0;
2513            while (itr.hasNext()) {
2514                ObjectReference element = (ObjectReference) itr.next();
2515                javaOwnedMonitors[i]= new JDIObjectValue(target, element);
2516                i++;
2517            }
2518            return javaOwnedMonitors;
2519        } catch (IncompatibleThreadStateException e) {
2520            targetRequestFailed(JDIDebugModelMessages.JDIThread_43, e);
2521        } catch (RuntimeException JavaDoc e) {
2522            targetRequestFailed(JDIDebugModelMessages.JDIThread_44, e);
2523        }
2524        return null;
2525    }
2526
2527    /**
2528     * @see org.eclipse.jdt.debug.core.IJavaThread#getContendedMonitor()
2529     */

2530    public IJavaObject getContendedMonitor() throws DebugException {
2531        try {
2532            ObjectReference monitor= fThread.currentContendedMonitor();
2533            if (monitor != null) {
2534                return new JDIObjectValue((JDIDebugTarget)getDebugTarget(), monitor);
2535            }
2536        } catch (IncompatibleThreadStateException e) {
2537            targetRequestFailed(JDIDebugModelMessages.JDIThread_45, e);
2538        } catch (RuntimeException JavaDoc e) {
2539            targetRequestFailed(JDIDebugModelMessages.JDIThread_46, e);
2540        }
2541        
2542        return null;
2543    }
2544    /**
2545     * @see org.eclipse.debug.core.model.IFilteredStep#canStepWithFilters()
2546     */

2547    public boolean canStepWithFilters() {
2548        if (canStepInto()) {
2549            String JavaDoc[] filters = getJavaDebugTarget().getStepFilters();
2550            return filters != null && filters.length > 0;
2551        }
2552        return false;
2553    }
2554
2555    /**
2556     * @see org.eclipse.debug.core.model.IFilteredStep#stepWithFilters()
2557     */

2558    public void stepWithFilters() throws DebugException {
2559        if (!canStepWithFilters()) {
2560            return;
2561        }
2562        stepInto();
2563    }
2564    
2565    /**
2566     * Class which managed the queue of runnable associated with this thread.
2567     */

2568    static class ThreadJob extends Job {
2569        
2570        private Vector JavaDoc fRunnables;
2571        
2572        private JDIThread fJDIThread;
2573        
2574        public ThreadJob(JDIThread thread) {
2575            super(JDIDebugModelMessages.JDIThread_39);
2576            fJDIThread= thread;
2577            fRunnables= new Vector JavaDoc(5);
2578            setSystem(true);
2579        }
2580        
2581        public void addRunnable(Runnable JavaDoc runnable) {
2582            synchronized (fRunnables) {
2583                fRunnables.add(runnable);
2584            }
2585            schedule();
2586        }
2587        
2588        public boolean isEmpty() {
2589            return fRunnables.isEmpty();
2590        }
2591
2592        /*
2593         * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
2594         */

2595        public IStatus run(IProgressMonitor monitor) {
2596            fJDIThread.fRunningAsyncJob= this;
2597            Object JavaDoc[] runnables;
2598            synchronized (fRunnables) {
2599                runnables= fRunnables.toArray();
2600                fRunnables.clear();
2601            }
2602            
2603            MultiStatus failed = null;
2604            monitor.beginTask(this.getName(), runnables.length);
2605            int i = 0;
2606            while (i < runnables.length && !fJDIThread.isTerminated() && !monitor.isCanceled()) {
2607                try {
2608                    ((Runnable JavaDoc) runnables[i]).run();
2609                } catch (Exception JavaDoc e) {
2610                    if (failed == null) {
2611                        failed = new MultiStatus(JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.INTERNAL_ERROR, JDIDebugModelMessages.JDIThread_0, null);
2612                    }
2613                    failed.add(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.INTERNAL_ERROR, JDIDebugModelMessages.JDIThread_0, e));
2614                }
2615                i++;
2616                monitor.worked(1);
2617            }
2618            fJDIThread.fRunningAsyncJob= null;
2619            monitor.done();
2620            if (failed == null) {
2621                return Status.OK_STATUS;
2622            }
2623            return failed;
2624        }
2625
2626        /*
2627         * @see org.eclipse.core.runtime.jobs.Job#shouldRun()
2628         */

2629        public boolean shouldRun() {
2630            return !fJDIThread.isTerminated() && !fRunnables.isEmpty();
2631        }
2632
2633    }
2634
2635
2636    /**
2637     * @see org.eclipse.jdt.debug.core.IJavaThread#stop(org.eclipse.jdt.debug.core.IJavaValue)
2638     */

2639    public void stop(IJavaObject exception) throws DebugException {
2640        try {
2641            fThread.stop(((JDIObjectValue)exception).getUnderlyingObject());
2642        } catch (InvalidTypeException e) {
2643            targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_stoping_thread, new String JavaDoc[] {e.toString()}), e);
2644        }
2645    }
2646
2647    /* (non-Javadoc)
2648     * @see org.eclipse.jdt.debug.core.IJavaThread#getThreadGroup()
2649     */

2650    public IJavaThreadGroup getThreadGroup() throws DebugException {
2651        ThreadGroupReference group = getUnderlyingThreadGroup();
2652        if (group != null) {
2653            return getJavaDebugTarget().findThreadGroup(group);
2654        }
2655        return null;
2656    }
2657
2658    /* (non-Javadoc)
2659     * @see org.eclipse.jdt.debug.core.IJavaThread#getFrameCount()
2660     */

2661    public int getFrameCount() throws DebugException {
2662        return getUnderlyingFrameCount();
2663    }
2664
2665    protected void forceReturn(IJavaValue value) throws DebugException {
2666        if (!isSuspended()) {
2667            return;
2668        }
2669        try {
2670            fThread.forceEarlyReturn(((JDIValue)value).getUnderlyingValue());
2671            stepReturn();
2672        } catch (VMDisconnectedException e) {
2673            disconnected();
2674        } catch (InvalidTypeException e) {
2675            targetRequestFailed(JDIDebugModelMessages.JDIThread_48, e);
2676        } catch (ClassNotLoadedException e) {
2677            targetRequestFailed(JDIDebugModelMessages.JDIThread_48, e);
2678        } catch (IncompatibleThreadStateException e) {
2679            targetRequestFailed(JDIDebugModelMessages.JDIThread_48, e);
2680        } catch (UnsupportedOperationException JavaDoc e) {
2681            requestFailed(JDIDebugModelMessages.JDIThread_48, e);
2682        } catch (RuntimeException JavaDoc e) {
2683            targetRequestFailed(JDIDebugModelMessages.JDIThread_48, e);
2684        }
2685    }
2686    
2687   
2688    /**
2689     * Implementation of a scheduling rule for this thread, which defines how it should behave
2690     * when a request for content job tries to run while the thread is evaluating
2691     *
2692     * @since 3.3.0
2693     */

2694    class SerialPerObjectRule implements ISchedulingRule {
2695        
2696        private Object JavaDoc fObject = null;
2697        
2698        public SerialPerObjectRule(Object JavaDoc lock) {
2699            fObject = lock;
2700        }
2701
2702        /* (non-Javadoc)
2703         * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule)
2704         */

2705        public boolean contains(ISchedulingRule rule) {
2706            return rule == this;
2707        }
2708
2709        /* (non-Javadoc)
2710         * @see org.eclipse.core.runtime.jobs.ISchedulingRule#isConflicting(org.eclipse.core.runtime.jobs.ISchedulingRule)
2711         */

2712        public boolean isConflicting(ISchedulingRule rule) {
2713            if (rule instanceof SerialPerObjectRule) {
2714                SerialPerObjectRule vup = (SerialPerObjectRule) rule;
2715                return fObject == vup.fObject;
2716            }
2717            return false;
2718        }
2719        
2720    }
2721  
2722    /**
2723     * returns the scheduling rule for getting content while evaluations are running
2724     * @return the <code>ISchedulingRule</code> for this thread
2725     *
2726     * @since 3.3.0
2727     */

2728    public ISchedulingRule getThreadRule() {
2729           return new SerialPerObjectRule(this);
2730   }
2731}
2732
Popular Tags