2 * Created on 23.11.2004
4 * TODO To change the template for this generated file go to
5 * Window - Preferences - Java - Code Style - Code Templates
7 package net.sourceforge.phpeclipse.xdebug.php.model;
9 import java.util.Arrays;
10 import java.util.Collections;
11 import java.util.Vector;
13 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
14 import net.sourceforge.phpeclipse.xdebug.core.PHPDebugUtils;
15 import net.sourceforge.phpeclipse.xdebug.core.xdebug.XDebugResponse;
17 import org.eclipse.debug.core.DebugEvent;
18 import org.eclipse.debug.core.DebugException;
19 import org.eclipse.debug.core.DebugPlugin;
20 import org.eclipse.debug.core.IDebugEventSetListener;
21 import org.eclipse.debug.core.model.IBreakpoint;
22 import org.eclipse.debug.core.model.IStackFrame;
23 import org.eclipse.debug.core.model.IThread;
24 import org.eclipse.jface.resource.ImageDescriptor;
25 import org.eclipse.ui.model.IWorkbenchAdapter;
26 import org.w3c.dom.Node;
27 import org.w3c.dom.NodeList;
32 * TODO To change the template for this generated type comment go to
33 * Window - Preferences - Java - Code Style - Code Templates
35 public class XDebugThread extends XDebugElement implements IThread, IDebugEventSetListener {
36 private XDebugStackFrame[] fStackFrames;
37 private IBreakpoint[] fBreakpoints;
39 private boolean fStepping = false; // Whether this thread is stepping
40 private boolean fTerminated = false;
42 private int fStepCount = 0;
43 private int fCurrentStepCount = 0;
45 private Vector stackListOld = new Vector(); // The 'static' list of stack frames
48 * Constructs a new thread for the given target
52 public XDebugThread(XDebugTarget target) {
54 DebugPlugin.getDefault().addDebugEventListener(this);
61 public void setStackFrames (XDebugStackFrame[] frames) {
62 this.fStackFrames = frames;
65 public void incrementStepCounter() {
74 public Object getAdapter (Class arg0) {
75 if (IWorkbenchAdapter.class.equals (arg0)) {
76 return new IWorkbenchAdapter() {
77 public Object[] getChildren(Object o) {
79 return getStackFrames ();
80 } catch (DebugException x) {
81 PHPeclipsePlugin.log ("Unable to get stack frames.", x);
87 public ImageDescriptor getImageDescriptor(Object object) {
91 public String getLabel(Object o) {
92 throw new UnsupportedOperationException();
95 public Object getParent(Object o) {
96 return getDebugTarget();
100 return super.getAdapter(arg0);
104 * Reset the availability flag for all stackframes in the list.
106 * @param list The list of old stackframes
108 private void resetAvailability (Vector list) {
111 for (i = 0; i < list.size (); i++) {
112 ((XDebugStackFrame) list.get(i)).setAvailable (false); //
117 * Check whether the new stackframe is in the list of old stackframes.
118 * Test for identical stackframe (identical means same description and same line number).
120 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
121 * @param list The list of old stackframes
123 * - true if we have found the identical stackframe within the list
124 * - false if we did not find the identical stackframe within the list
126 private boolean isStackFrameInList (XDebugStackFrame stackFrameNew, Vector list) {
128 XDebugStackFrame stackFrameOld;
130 for (i = 0; i < list.size (); i++) {
131 stackFrameOld = (XDebugStackFrame) list.get (i); //
133 if (stackFrameNew.getFullName ().equals (stackFrameOld.getFullName ()) &&
134 stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ()) &&
135 stackFrameNew.getLineNumber () == stackFrameOld.getLineNumber ()) { // Did we find the sent stackframe within the list of old stackframes?
136 stackFrameOld.setAvailable (true); // We found the new stackframe in the list of old stack frames
137 stackFrameOld.setLevel (stackFrameNew.getLevel ());
138 stackFrameOld.setUpToDate (false); // Need to update the variables
140 return true; // The stackframe was found in the list
148 * Check whether the new stackframe is in the list of old stackframes.
149 * Test for exact stackframe (exact means same description and same line number).
151 * @param stackFrameNew The stackframe to check whether he is already within the old stackframe list
152 * @param list The list of old stackframes
154 * - true if we have exactly this stackframe within the list
155 * - false if we did not find the exact stackframe within the list
157 private void markIdenticalStackFrames (Vector oldList, Vector newList) {
159 XDebugStackFrame stackFrameNew;
161 resetAvailability (oldList); // Reset the availability flag of the old stack frames
162 resetAvailability (newList); // Reset the availability flag of the old stack frames
164 for (i = 0; i < newList.size (); i++) { // For all stackList entries
165 stackFrameNew = (XDebugStackFrame) newList.get (i);
167 if (isStackFrameInList (stackFrameNew, oldList)) { // Is this stackframe in the list
168 stackFrameNew.setAvailable (true); //
177 * The stackList contains the currently read stackframes which were sent
178 * from DBG. The DBG interface holds a list of the active stack frames.
179 * This method replicates the 'static' stackframe list with the DBG stackframe list
180 * Replication is done in the following way:
182 * <li> It looks for new stackframes within the DBG stackframe list and
183 * adds them to the 'static' list.
184 * <li> It looks for stackframes within the 'static' list, and removes them
185 * from the 'static' list in case they do not appear within the DBG list.
186 * <li> It looks for stackframes which are already existent and replicates the
187 * line number and the index number.
188 * <li> At the end, the 'static' stackframe list has to be sorted by the stackframes
192 * Removes the unused stackframes from the list, or adds stackframes which
193 * are not yet in the list.
198 private void updateStackFrameList (Vector stackList) {
201 XDebugStackFrame stackFrameNew;
202 XDebugStackFrame stackFrameOld;
203 XDebugStackFrame[] newStackList;
205 markIdenticalStackFrames (stackListOld, stackList); // Check whether the newly send stack frames can be found in the list
206 // of old stack frames
208 for (i = 0; i < stackList.size (); i++) { // For all stackList entries
209 stackFrameNew = (XDebugStackFrame) stackList.get(i);
211 for (n = 0; n < stackListOld.size (); n++) { // For all StackFrames in the StackFrame list
212 stackFrameOld = (XDebugStackFrame) stackListOld.get (n); //
214 if (stackFrameOld.isAvailable ()) { // If this stack frame was already found in the new list skip it
218 if (stackFrameNew.getFullName ().equals (stackFrameOld.getFullName ()) && // Did we find the sent stackframe within the list of old stackframes?
219 stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) {// Did we find the sent stackframe within the list of old stackframes?
220 stackFrameOld.setLineNumber (stackFrameNew.getLineNumber ());
221 stackFrameOld.setLevel (stackFrameNew.getLevel ());
222 stackFrameOld.setUpToDate (false); // Need to update the variables
224 stackFrameOld.setAvailable (true); // And mark this stack frame as available
225 stackFrameNew.setAvailable (true); // And mark this stack frame as available
227 break; // Yes, then break;
231 if (!stackFrameNew.isAvailable ()) { // Did not find the new stackframe within the list?
232 stackFrameNew.setAvailable (true); // Mark the stack frame as available and
233 stackListOld.add (stackFrameNew); // then add the new stackframe
237 // And now for removing unused stackframes from list
239 for (n = 0; n < stackListOld.size(); n++) {
240 stackFrameOld = (XDebugStackFrame) stackListOld.get(n);
242 if (!stackFrameOld.isAvailable()) {
243 stackListOld.remove(n--);
247 Collections.sort (stackListOld); // Sort the 'static' stackframe list by the stackframe index numbers.
249 newStackList = new XDebugStackFrame[stackListOld.size ()];
250 newStackList = (XDebugStackFrame[]) stackListOld.toArray (newStackList);
252 // DBGStackList = newStackList;
253 fStackFrames = newStackList;
257 public IStackFrame[] getStackFrames() throws DebugException {
258 if (!isSuspended()) {
259 return new IStackFrame[0];
262 if (fStepCount > fCurrentStepCount) { // Do we need to update the list of stackframes
263 XDebugResponse dr = ((XDebugTarget) getDebugTarget()).getStackFrames(); // Get the stackframes list from XDebug
264 XDebugStackFrame[] newStackFrames = _getStackFrames(dr); // Parse the stackframes list
266 updateStackFrameList (new Vector (Arrays.asList(newStackFrames))); // update the 'static' list of stackframes
268 fCurrentStepCount++; //
275 private XDebugStackFrame[] _getStackFrames(XDebugResponse lastResponse) {
276 if (lastResponse.isError()) {
277 return new XDebugStackFrame[0];
280 Node response = lastResponse.getParentNode();
281 NodeList frames = response.getChildNodes();
282 XDebugStackFrame[] theFrames = new XDebugStackFrame[frames.getLength()];
284 for (int i = 0; i < frames.getLength(); i++) {
285 Node stackNode = frames.item(i);
286 String fileName = PHPDebugUtils.unescapeString(PHPDebugUtils.getAttributeValue(stackNode,"filename"));
287 String lineNo = PHPDebugUtils.getAttributeValue(stackNode,"lineno");
289 XDebugStackFrame frame = new XDebugStackFrame (this,
291 PHPDebugUtils.getAttributeValue(stackNode,"type"),
292 Integer.parseInt(lineNo),
293 PHPDebugUtils.getAttributeValue(stackNode,"where"),
296 frame.incrementStepCounter();
298 theFrames[i] = frame;
305 * @see org.eclipse.debug.core.model.IThread#hasStackFrames()
307 public boolean hasStackFrames() throws DebugException {
308 if (fStackFrames == null) {
312 return fStackFrames.length > 0;
316 * @see org.eclipse.debug.core.model.IThread#getPriority()
318 public int getPriority() throws DebugException {
323 * @see org.eclipse.debug.core.model.IThread#getTopStackFrame()
325 public IStackFrame getTopStackFrame() throws DebugException {
326 IStackFrame[] frames = getStackFrames();
327 if (frames.length > 0) {
335 * @see org.eclipse.debug.core.model.IThread#getName()
337 public String getName() throws DebugException {
342 * @see org.eclipse.debug.core.model.IThread#getBreakpoints()
344 public IBreakpoint[] getBreakpoints() {
345 if (fBreakpoints == null) {
346 return new IBreakpoint[0];
352 * Sets the breakpoints this thread is suspended at, or <code>null</code>
355 * @param breakpoints the breakpoints this thread is suspended at, or <code>null</code>
358 protected void setBreakpoints(IBreakpoint[] breakpoints) {
359 fBreakpoints = breakpoints;
363 * @see org.eclipse.debug.core.model.ISuspendResume#canResume()
365 public boolean canResume() {
366 return isSuspended();
370 * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
372 public boolean canSuspend() {
373 return !isTerminated() && !isSuspended();
377 * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
379 public boolean isSuspended() {
380 return getDebugTarget().isSuspended();
384 * @see org.eclipse.debug.core.model.ISuspendResume#resume()
386 public void resume() throws DebugException {
388 getDebugTarget().resume();
392 * @see org.eclipse.debug.core.model.ISuspendResume#suspend()
394 public void suspend() throws DebugException {
395 getDebugTarget().suspend();
399 * @see org.eclipse.debug.core.model.IStep#canStepInto()
401 public boolean canStepInto() {
402 return isSuspended();
406 * @see org.eclipse.debug.core.model.IStep#canStepOver()
408 public boolean canStepOver() {
409 return isSuspended();
413 * @see org.eclipse.debug.core.model.IStep#canStepReturn()
415 public boolean canStepReturn() {
416 if (fStackFrames != null) {
417 return (fStackFrames.length > 1);
424 * @see org.eclipse.debug.core.model.IStep#isStepping()
426 public boolean isStepping() {
431 * @see org.eclipse.debug.core.model.IStep#stepInto()
433 public void stepInto() throws DebugException {
435 ((XDebugTarget) getDebugTarget()).step_into();
439 * @see org.eclipse.debug.core.model.IStep#stepOver()
441 public void stepOver() throws DebugException {
443 ((XDebugTarget) getDebugTarget()).step_over();
447 * @see org.eclipse.debug.core.model.IStep#stepReturn()
449 public void stepReturn() throws DebugException {
451 ((XDebugTarget) getDebugTarget()).step_out();
455 * @see org.eclipse.debug.core.model.ITerminate#canTerminate()
457 public boolean canTerminate() {
458 return !isTerminated();
462 * @see org.eclipse.debug.core.model.ITerminate#isTerminated()
464 public boolean isTerminated() {
469 * @see org.eclipse.debug.core.model.ITerminate#terminate()
471 public void terminate() throws DebugException {
472 ((XDebugTarget) getDebugTarget()).getDebugConnection().stop();
476 public void terminated() throws DebugException {
481 * Sets whether this thread is stepping
483 * @param stepping whether stepping
485 protected void setStepping(boolean stepping) {
486 fStepping = stepping;
489 public void handleDebugEvents(DebugEvent[] events) {
490 DebugEvent de = events[0];
491 System.out.println(de.toString());
494 public void removeEventListeners() {
495 DebugPlugin.getDefault().removeDebugEventListener(this);
499 * Fires a <code>RESUME</code> event for this element with
502 * @param detail event detail code
504 public void fireResumeEvent(int detail) {
505 fireEvent(new DebugEvent(this, DebugEvent.RESUME, detail));
509 * Fires a <code>SUSPEND</code> event for this element with
512 * @param detail event detail code
514 public void fireSuspendEvent (int detail) {
515 fireEvent (new DebugEvent (this, DebugEvent.SUSPEND, detail));