0c9f1d3377d1d1e2abb95d136ae8728833500a4a
[phpeclipse.git] /
1 /**
2  * 
3  */
4 package net.sourceforge.phpeclipse.xdebug.php.model;
5
6 import java.util.List;
7
8 import net.sourceforge.phpeclipse.xdebug.core.IPHPDebugEvent;
9 import net.sourceforge.phpeclipse.xdebug.core.IProxyEventListener;
10 import net.sourceforge.phpeclipse.xdebug.core.IXDebugPreferenceConstants;
11 import net.sourceforge.phpeclipse.xdebug.core.PHPDebugUtils;
12 import net.sourceforge.phpeclipse.xdebug.core.PathMapItem;
13 import net.sourceforge.phpeclipse.xdebug.core.XDebugCorePlugin;
14 import net.sourceforge.phpeclipse.xdebug.core.XDebugProxy;
15 import net.sourceforge.phpeclipse.xdebug.php.launching.IXDebugConstants;
16
17 import org.eclipse.core.resources.IMarker;
18 import org.eclipse.core.resources.IMarkerDelta;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.core.runtime.IPath;
21 import org.eclipse.debug.core.DebugEvent;
22 import org.eclipse.debug.core.DebugException;
23 import org.eclipse.debug.core.DebugPlugin;
24 import org.eclipse.debug.core.IDebugEventSetListener;
25 import org.eclipse.debug.core.ILaunch;
26
27 import org.eclipse.debug.core.model.IBreakpoint;
28 import org.eclipse.debug.core.model.IDebugTarget;
29 import org.eclipse.debug.core.model.ILineBreakpoint;
30 import org.eclipse.debug.core.model.IMemoryBlock;
31 import org.eclipse.debug.core.model.IProcess;
32 import org.eclipse.debug.core.model.IThread;
33 import org.w3c.dom.NamedNodeMap;
34 import org.w3c.dom.Node;
35
36 import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener;
37 import net.sourceforge.phpeclipse.xdebug.core.xdebug.XDebugConnection;
38 import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener.XDebugResponse;
39
40 /**
41  * @author Christian
42  *
43  */
44 public class XDebugTarget extends XDebugElement implements IDebugTarget, IDebugEventSetListener, IProxyEventListener {
45         private IProcess fProcess;
46         
47         private ILaunch fLaunch;
48         
49         private int fDebugPort;
50         
51         private boolean fSuspended = false;
52         
53         private boolean fTerminated = false;
54         
55         private XDebugThread fThread;
56         private IThread[] fThreads;
57         
58         private XDebugConnection fDebugConnection;
59
60         private ResponseListener fResponseListener;
61
62         private String fIdeKey;
63
64
65         /**
66          * Constructs a new debug target in the given launch and waits until
67          * someone with the ideKey connects to the Debugproxy
68          *  
69          * 
70          * @param launch containing launch
71          * @param process process of the interpreter
72          * @param ideKey 
73          * @exception CoreException if unable to connect to host
74          */     
75         public XDebugTarget(ILaunch launch, IProcess process, String ideKey) throws CoreException {
76                 fLaunch = launch;
77                 fProcess = process;
78                 fDebugConnection = null;
79                 fThread = null;
80                 fThreads = new IThread[0];
81                 fIdeKey = ideKey;
82                 
83                 fDebugPort = XDebugCorePlugin.getDefault().getPreferenceStore().getInt(IXDebugPreferenceConstants.DEBUGPORT_PREFERENCE);                
84                 if (fDebugPort == 0) {
85                         fDebugPort = IXDebugPreferenceConstants.DEFAULT_DEBUGPORT;
86                 }
87                 
88                 DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(this);
89                 DebugPlugin.getDefault().addDebugEventListener(this);
90         }
91
92         /* (non-Javadoc)
93          * @see org.eclipse.debug.core.model.IDebugTarget#getProcess()
94          */
95         public IProcess getProcess() {
96                 return fProcess;
97         }
98
99         /* (non-Javadoc)
100          * @see org.eclipse.debug.core.model.IDebugTarget#getThreads()
101          */
102         public IThread[] getThreads() throws DebugException {
103                 return fThreads;
104         }
105
106         /* (non-Javadoc)
107          * @see org.eclipse.debug.core.model.IDebugTarget#hasThreads()
108          */
109         public boolean hasThreads() throws DebugException {
110                 return (fThreads.length > 0);
111         }
112
113         /* (non-Javadoc)
114          * @see org.eclipse.debug.core.model.IDebugTarget#getName()
115          */
116         public String getName() throws DebugException {
117                 return "PHP XDebug Client at localhost:" + fDebugPort;
118         }
119
120         /* (non-Javadoc)
121          * @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint)
122          */
123         public boolean supportsBreakpoint(IBreakpoint breakpoint) {
124                 if (breakpoint.getModelIdentifier().equals(IXDebugConstants.ID_PHP_DEBUG_MODEL)) {
125                         return true;
126                 }
127                 return false;
128         }
129
130         /* (non-Javadoc)
131          * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget()
132          */
133         public IDebugTarget getDebugTarget() {
134                 return this;
135         }
136
137         /* (non-Javadoc)
138          * @see org.eclipse.debug.core.model.IDebugElement#getLaunch()
139          */
140         public ILaunch getLaunch() {
141                 return fLaunch;
142         }
143
144         /* (non-Javadoc)
145          * @see org.eclipse.debug.core.model.ITerminate#canTerminate()
146          */
147         public boolean canTerminate() {
148                 if (getProcess()!=null)  // ther is no running Process in remote debugging
149                         return getProcess().canTerminate();
150                 return true;
151         }
152
153         /* (non-Javadoc)
154          * @see org.eclipse.debug.core.model.ITerminate#isTerminated()
155          */
156         public boolean isTerminated() {
157 //              return getProcess().isTerminated();
158                 return fTerminated;
159         }
160
161         /* (non-Javadoc)
162          * @see org.eclipse.debug.core.model.ITerminate#terminate()
163          */
164         public void terminate() throws DebugException {
165                 if(fTerminated) {
166                         return;
167                 }
168                 
169                 if (XDebugCorePlugin.getDefault() != null) {
170                         XDebugProxy proxy = XDebugCorePlugin.getDefault().getXDebugProxy();
171                         proxy.removeProxyEventListener(this, fIdeKey);
172                         
173                         System.out.println("XDebug.Target: ProxyEventlistener removed");
174                         
175                         fTerminated = true;
176                         fSuspended = false;
177                         
178                         XDebugCorePlugin.getBreakpointManager().removeBreakpointListener(this);
179                         fireEvent(new DebugEvent(this, DebugEvent.TERMINATE));
180                         DebugPlugin.getDefault().removeDebugEventListener(this);
181                 }
182         }
183
184         /* (non-Javadoc)
185          * @see org.eclipse.debug.core.model.ISuspendResume#canResume()
186          */
187         public boolean canResume() {
188                 return false;
189         }
190
191         /* (non-Javadoc)
192          * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
193          */
194         public boolean canSuspend() {
195                 return false;
196         }
197
198         /* (non-Javadoc)
199          * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
200          */
201         public boolean isSuspended() {
202                 return fSuspended;
203         }
204
205         /* (non-Javadoc)
206          * @see org.eclipse.debug.core.model.ISuspendResume#resume()
207          */
208         public void resume() throws DebugException {
209                 if (fDebugConnection != null) {
210                         fThread.setBreakpoints(null);
211                         resumed(DebugEvent.RESUME);
212                         fDebugConnection.run();
213                 }               
214         }
215         
216         /**
217          * Notification the target has resumed for the given reason
218          * 
219          * @param detail reason for the resume
220          */
221         private void resumed(int detail) {
222                 fSuspended = false;
223                 fThread.fireResumeEvent(detail);
224         }
225         
226         /**
227          * Notification the target has suspended for the given reason
228          * 
229          * @param detail reason for the suspend
230          */
231         public void suspended(int detail) {
232                 fSuspended = true;
233                 fThread.fireSuspendEvent(detail);
234         }       
235         
236         /* (non-Javadoc)
237          * @see org.eclipse.debug.core.model.ISuspendResume#suspend()
238          */
239         public void suspend() throws DebugException {
240         }
241
242         /* (non-Javadoc)
243          * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
244          */
245         public void breakpointAdded(IBreakpoint breakpoint) {
246                 IMarker marker = breakpoint.getMarker();
247                 IPath path = marker.getResource().getLocation();
248                 IPath cp = path.removeLastSegments(1);
249                 List pathMap = null;
250                 try {
251                         pathMap = fLaunch.getLaunchConfiguration().getAttribute(IXDebugConstants.ATTR_PHP_PATHMAP,(List)null);
252                 } catch (CoreException e2) {
253                         // TODO Auto-generated catch block
254                         e2.printStackTrace();
255                 }
256
257                 if (fDebugConnection != null)
258                 if (!fDebugConnection.isClosed()) {
259                         if (fProcess == null) {
260                                 PathMapItem pmi = null;
261                                 for (int i = 0; i < pathMap.size(); i++) {
262                                         pmi = new PathMapItem((String) pathMap.get(i));
263                                         IPath local = (IPath)pmi.getLocalPath().clone();
264                                         local = local.makeAbsolute();
265                                         int matchedSegments = local.segmentCount();
266                                         if (local.matchingFirstSegments(cp) == matchedSegments) {
267                                                 IPath newPath = pmi.getRemotePath();
268                                                 newPath = newPath.append(path.removeFirstSegments(matchedSegments));
269                                                 newPath = newPath.makeAbsolute();
270                                                 if (supportsBreakpoint(breakpoint)) {
271                                                         try {
272                                                                 if (breakpoint.isEnabled()) {
273                                                                         if (marker != null) {
274                                                                                 int id = fDebugConnection.breakpointSet(newPath.toString(), ((ILineBreakpoint)breakpoint).getLineNumber(), marker.getAttribute(XDebugBreakpoint.HIT_COUNT,-1));
275                                                                                 XDebugResponse dr = getResponse(id);
276                                                                                 
277                                                                                 String bpid = dr.getAttributeValue("id");
278                                                                                 
279                                                                                 if (!"".equals(bpid))
280                                                                                         marker.setAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,Integer.parseInt(bpid));
281                                                                         }
282                                                                 }
283                                                         } catch (DebugException e) {
284                                                                 e.printStackTrace();
285                                                         } catch (CoreException e) {
286                                                                 e.printStackTrace();
287                                                         }
288                                                 }
289                                         }
290                                 }                       
291                         } else {
292                                 if (supportsBreakpoint(breakpoint)) {
293                                         try {
294                                                 if (breakpoint.isEnabled()) {
295                                                         if (marker != null) {
296                                                                 int id = fDebugConnection.breakpointSet(path.toString(), ((ILineBreakpoint)breakpoint).getLineNumber(), marker.getAttribute(XDebugBreakpoint.HIT_COUNT,-1));
297                                                                 XDebugResponse dr = getResponse(id);
298                                                                 String bpid = dr.getAttributeValue("id");
299                                                                 
300                                                                 if (!"".equals(bpid))
301                                                                         marker.setAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,Integer.parseInt(bpid));
302                                                         }
303                                                 }
304                                         } catch (DebugException e) {
305                                                 e.printStackTrace();
306                                         } catch (CoreException e) {
307                                                 e.printStackTrace();
308                                         }
309                                 }
310                         }
311                 }
312         }
313         
314         /* (non-Javadoc)
315          * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
316          */
317         public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
318                 if (supportsBreakpoint(breakpoint)) {
319                         try {
320                                 int id =((XDebugLineBreakpoint)breakpoint).getID();
321                                 if (id >0)
322                                         fDebugConnection.breakpointRemove(id);
323                         } catch (CoreException e) {
324                         }
325                 }
326         }
327
328         /* (non-Javadoc)
329          * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
330          */
331         public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
332 //              if (supportsBreakpoint(breakpoint)) {
333 //                      try {
334 //                              if (breakpoint.isEnabled()) {
335 //                                      breakpointAdded(breakpoint);
336 //                              } else {
337 //                                      breakpointRemoved(breakpoint, null);
338 //                              }
339 //                      } catch (CoreException e) {
340 //                      }
341 //              }
342         }
343
344         /* (non-Javadoc)
345          * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
346          */
347         public boolean canDisconnect() {
348                 return false;
349         }
350
351         /* (non-Javadoc)
352          * @see org.eclipse.debug.core.model.IDisconnect#disconnect()
353          */
354         public void disconnect() throws DebugException {
355         }
356
357         /* (non-Javadoc)
358          * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected()
359          */
360         public boolean isDisconnected() {
361                 return (false);
362         }
363
364         /* (non-Javadoc)
365          * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval()
366          */
367         public boolean supportsStorageRetrieval() {
368                 return false;
369         }
370
371         /* (non-Javadoc)
372          * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long)
373          */
374         public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
375                 return null;
376         }
377
378         /**
379          * Notification we have connected to the PHP debugger and it has been started.
380          * Resume the the debugger.
381          */
382         public void started() throws DebugException {
383                 fThread.setBreakpoints(null);
384                 fThread.setStepping(false);
385
386                 int id = fDebugConnection.featureGet("detach");
387
388                 XDebugResponse response = getResponse(id);
389
390                 Integer.parseInt(response.getValue());
391                 System.out.println("in Target.started()");
392
393                 // Dirty hack
394                 // Need to refactory plugin to get variables in lazy mode.
395                 int id1 = fDebugConnection.featureSet("max_depth", "1024" );
396                 XDebugResponse response1 = getResponse(id1);
397                 if (response1.getAttributeValue("success").equals("1") ) {
398                         System.out.println("Set depth to 1024 (hack)");
399                 }
400                 int id2 = fDebugConnection.featureSet("max_children", "1024" );
401                 XDebugResponse response2 = getResponse(id2);
402                 if (response2.getAttributeValue("success").equals("1") ) {
403                         System.out.println("Set children to 1024 (hack)");
404                 }
405                 
406                 installDeferredBreakpoints();
407                 try {
408                         resume();
409                 } catch (DebugException e) {
410                         e.printStackTrace();
411                 }
412         }
413         
414         /**
415          * Install breakpoints that are already registered with the breakpoint
416          * manager.
417          */
418         private void installDeferredBreakpoints() {
419                 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
420                 for (int i = 0; i < breakpoints.length; i++) {
421                         breakpointAdded(breakpoints[i]);
422                 }
423         }
424         
425         /**
426          * Returns the current stack frames in the target.
427          * 
428          * @return the current stack frames in the target
429          * @throws DebugException if unable to perform the request
430          */
431         public XDebugResponse getStackFrames() throws DebugException {
432                 int id = fDebugConnection.stackGet();
433                 XDebugResponse lastResponse = getResponse(id);
434                 return lastResponse;
435         }
436         
437         /**
438          * Single step the interpreter.
439          * 
440          * @throws DebugException if the request fails
441          */
442         protected void step_over() throws DebugException {
443                 fThread.setStepping(true);
444                 resumed(DebugEvent.STEP_OVER);
445                 fDebugConnection.stepOver();
446         }
447         
448         /**
449          * Single step the interpreter.
450          * 
451          * @throws DebugException if the request fails
452          */
453         protected void step_into() throws DebugException {
454                 fThread.setStepping(true);
455                 resumed(DebugEvent.STEP_INTO);
456                 fDebugConnection.stepInto();
457         }
458         
459         /**
460          * Single step the interpreter.
461          * 
462          * @throws DebugException if the request fails
463          */
464         protected void step_out() throws DebugException {
465                 fThread.setStepping(true);
466                 resumed(DebugEvent.STEP_RETURN);
467                 fDebugConnection.stepOut();
468         }
469         
470         public boolean setVarValue(String name, String value) {
471                 int id = fDebugConnection.setVarValue(name,value);
472                 XDebugResponse response = getResponse(id);
473                 
474                 if ((response.getAttributeValue("success")).equals("1")) {
475                         return true;
476                 } else {
477                         return false;
478                 }
479         }
480         
481         public Node eval(String expression) {
482                 int id = fDebugConnection.eval(expression);
483                 XDebugResponse response = getResponse(id);
484
485                 Node evalResponse = response.getParentNode();
486                 Node evalProperty = evalResponse.getFirstChild();
487                 
488                 return evalProperty;
489         }
490         
491         public void handleDebugEvents(DebugEvent[] events) {
492                 for (int i = 0; i < events.length; i++) {
493                         DebugEvent event = events[i];
494                         
495                         if (fResponseListener != null) {
496                                 Object s = null;
497                                 s = event.getSource();
498                                 if (s instanceof ResponseListener) {
499                                         if (!fResponseListener.equals((ResponseListener) s)) {
500                                                 return;
501                                         }
502                                 }
503                         } else {
504                                 return;
505                         }
506                         
507                         if (event.getKind() == DebugEvent.MODEL_SPECIFIC) {
508                                 switch (event.getDetail()) {
509                                         case IPHPDebugEvent.BREAKPOINT_HIT:
510                                                 int id = fDebugConnection.stackGet();
511                                                 XDebugResponse lastResponse = getResponse(id);
512
513                                                 IBreakpoint breakpoint = breakpointHit(lastResponse.getParentNode());
514                                                 
515                                                 if (breakpoint != null) {
516                                                         fThread.setBreakpoints(new IBreakpoint[]{breakpoint});
517                                                         fThread.incrementStepCounter();
518                                                         suspended(DebugEvent.BREAKPOINT);
519                                                 } else {
520                                                         try {
521                                                                 resume();
522                                                         } catch (DebugException e ) {
523                                                                 ; //nothing to do
524                                                         }
525                                                 }
526                                                 break;
527                                         case IPHPDebugEvent.STEP_END:
528                                                 fThread.incrementStepCounter();
529                                                 suspended(DebugEvent.STEP_END);
530                                                 break;
531                                         case IPHPDebugEvent.STOPPED:
532                                                 stopped();
533                                                 break;
534                                 }
535                         }
536                 }
537         }
538         
539         public void stopped() {
540                 if(fDebugConnection == null) {
541                         return;
542                 }
543
544                 resumed(DebugEvent.TERMINATE);
545
546                 stopListener();
547                 fDebugConnection.close();
548
549                 fSuspended = false;
550
551                 // Dirty hack to check debugging mode (remote or local)
552                 if (fProcess != null) {
553                         try {
554                                 terminate();
555                         } catch (DebugException e) {
556                                 e.printStackTrace();
557                         }
558                 } else {
559                         fDebugConnection = null;
560                         fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
561                 }
562                 
563                 fThread.removeEventListeners();
564                 fThread = null;
565                 fThreads = new IThread[0];
566         }
567         
568         public void handleProxyEvent(XDebugConnection connection) {
569                 setDebugConnection(connection);
570                 //System.out.println("* New Connection - XDebug.Target: " + fDebugConnection.getSessionID());
571                 
572                 fThread = new XDebugThread(this);
573                 fThreads = new IThread[] {fThread};
574                 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CHANGE));
575                 try {
576                         started();
577                 } catch( DebugException e ){
578                         e.printStackTrace();            
579                 }               
580         }
581
582         private void setDebugConnection(XDebugConnection connection) {
583                 if (connection != null) {
584                         fDebugConnection = connection;
585                         fResponseListener = new ResponseListener(connection);
586                         startListener();
587                 }
588         }
589         
590         /**
591          * @return Returns the fDebugConnection.
592          */
593         public XDebugConnection getDebugConnection() {
594                 return fDebugConnection;
595         }       
596         
597         public void addProcess(IProcess p) {
598                 fProcess = p;
599
600         }
601         public Node getLocalVariables(int level) throws DebugException {
602                 int id = fDebugConnection.contextGet(level, 0);
603                 XDebugResponse response = getResponse(id);
604                 
605                 return response.getParentNode();
606         }
607         
608         public Node getGlobalVariables(int level) throws DebugException {
609                 int id = fDebugConnection.contextGet(level, 1);
610                 XDebugResponse response = getResponse(id);
611                 
612                 return response.getParentNode();
613         }
614         
615         public void stop() {
616                 fDebugConnection.stop();
617         }
618         
619         protected IBreakpoint breakpointHit(Node node) {
620                 Node child = node.getFirstChild();
621                 if (child.getNodeName().equals("stack")) {
622                         int lineNumber = Integer.parseInt(PHPDebugUtils.getAttributeValue(child, "lineno"));
623                         String filename = PHPDebugUtils.getAttributeValue(child, "filename");  
624                         IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
625                         for (int i = 0; i < breakpoints.length; i++) {
626                                 IBreakpoint breakpoint = breakpoints[i];
627                                 if (supportsBreakpoint(breakpoint)) {
628                                         if (breakpoint instanceof ILineBreakpoint) {
629                                                 ILineBreakpoint lineBreakpoint = (ILineBreakpoint) breakpoint;
630                                                 try {                                           
631                                                         if (breakpoint.isEnabled()) {
632                                                                 IMarker marker = breakpoint.getMarker();
633                                                                 if (marker != null) {
634                                                                         String endfilename;
635                                                                         
636                                                                         if (getProcess() == null) {
637                                                                                 endfilename = marker.getResource().getLocation().lastSegment(); 
638                                                                         } else {
639                                                                                 endfilename = marker.getResource().getLocation().toOSString();
640                                                                         }
641                                                                         
642                                                                         int id = fDebugConnection.breakpointGet(marker.getAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,-1));
643                                                                         XDebugResponse dr = getResponse(id);
644                                                                         
645                                                                         Node hitCo = dr.getParentNode().getFirstChild();
646                                                                         int hitCount = 0;
647                                                                         if (hitCo.hasAttributes()) {
648                                                                                 NamedNodeMap listAttribute = hitCo.getAttributes();
649                                                                                 Node attribute = listAttribute.getNamedItem("hit_count");
650                                                                                 if (attribute !=null) {
651                                                                                         hitCount = Integer.parseInt(attribute.getNodeValue());
652                                                                                 }
653                                                                         }
654
655                                                                         if(PHPDebugUtils.unescapeString(filename).endsWith(endfilename)
656                                                                                         && (lineBreakpoint.getLineNumber() == lineNumber) ) {
657                                                                                 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) > 0) {
658                                                                                         if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) == hitCount) {
659                                                                                                 return (breakpoint);                                                                                            
660                                                                                         }
661                                                                                 } else {
662                                                                                         return (breakpoint);
663                                                                                 }
664                                                                         }
665                                                                 }
666                                                         }
667                                                 } catch (CoreException e) {
668                                                 }
669                                         }
670                                 }
671                         }
672                 }
673                 
674                 return null;
675         }
676         
677         public void startListener() {
678                 fResponseListener.schedule();
679         }
680         
681         public void stopListener() {
682                 fResponseListener.cancel();
683         }
684         public XDebugResponse getResponse(int id) {
685                 XDebugResponse response = fResponseListener.getResponse(id);
686
687                 return response;
688         }
689 }