2257e84323ba9f93048fc90535ec1dc0eb5b6c7b
[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                         fThread.fireTerminateEvent();
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 //              return (fDebugConnection==null);
363         }
364
365         /* (non-Javadoc)
366          * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval()
367          */
368         public boolean supportsStorageRetrieval() {
369                 return false;
370         }
371
372         /* (non-Javadoc)
373          * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long)
374          */
375         public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
376                 return null;
377         }
378
379         /**
380          * Notification we have connected to the PHP debugger and it has been started.
381          * Resume the the debugger.
382          */
383         public void started() throws DebugException {
384                 fThread.setBreakpoints(null);
385                 fThread.setStepping(false);
386
387                 int id = fDebugConnection.featureGet("detach");
388
389                 XDebugResponse response = getResponse(id);
390
391                 Integer.parseInt(response.getValue());
392                 System.out.println("in Target.started()");
393
394                 // Dirty hack
395                 // Need to refactory plugin to get variables in lazy mode.
396                 int id1 = fDebugConnection.featureSet("max_depth", "1024" );
397                 XDebugResponse response1 = getResponse(id1);
398                 if (response1.getAttributeValue("success").equals("1") ) {
399                         System.out.println("Set depth to 1024 (hack)");
400                 }
401                 int id2 = fDebugConnection.featureSet("max_children", "1024" );
402                 XDebugResponse response2 = getResponse(id2);
403                 if (response2.getAttributeValue("success").equals("1") ) {
404                         System.out.println("Set children to 1024 (hack)");
405                 }
406                 
407                 installDeferredBreakpoints();
408                 try {
409                         resume();
410                 } catch (DebugException e) {
411                         e.printStackTrace();
412                 }
413         }
414         
415         /**
416          * Install breakpoints that are already registered with the breakpoint
417          * manager.
418          */
419         private void installDeferredBreakpoints() {
420                 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
421                 for (int i = 0; i < breakpoints.length; i++) {
422                         breakpointAdded(breakpoints[i]);
423                 }
424         }
425         
426         /**
427          * Returns the current stack frames in the target.
428          * 
429          * @return the current stack frames in the target
430          * @throws DebugException if unable to perform the request
431          */
432         public XDebugResponse getStackFrames() throws DebugException {
433                 int id = fDebugConnection.stackGet();
434                 XDebugResponse lastResponse = getResponse(id);
435                 return lastResponse;
436         }
437         
438         /**
439          * Single step the interpreter.
440          * 
441          * @throws DebugException if the request fails
442          */
443         protected void step_over() throws DebugException {
444                 fThread.setStepping(true);
445                 resumed(DebugEvent.STEP_OVER);
446                 fDebugConnection.stepOver();
447         }
448         
449         /**
450          * Single step the interpreter.
451          * 
452          * @throws DebugException if the request fails
453          */
454         protected void step_into() throws DebugException {
455                 fThread.setStepping(true);
456                 resumed(DebugEvent.STEP_INTO);
457                 fDebugConnection.stepInto();
458         }
459         
460         /**
461          * Single step the interpreter.
462          * 
463          * @throws DebugException if the request fails
464          */
465         protected void step_out() throws DebugException {
466                 fThread.setStepping(true);
467                 resumed(DebugEvent.STEP_RETURN);
468                 fDebugConnection.stepOut();
469         }
470         
471         public boolean setVarValue(String name, String value) {
472                 int id = fDebugConnection.setVarValue(name,value);
473                 XDebugResponse response = getResponse(id);
474                 
475                 if ((response.getAttributeValue("success")).equals("1")) {
476                         return true;
477                 } else {
478                         return false;
479                 }
480         }
481         
482         public Node eval(String expression) {
483                 int id = fDebugConnection.eval(expression);
484                 XDebugResponse response = getResponse(id);
485
486                 Node evalResponse = response.getParentNode();
487                 Node evalProperty = evalResponse.getFirstChild();
488                 
489                 return evalProperty;
490         }
491         
492         public void handleDebugEvents(DebugEvent[] events) {
493                 for (int i = 0; i < events.length; i++) {
494                         DebugEvent event = events[i];
495                         
496                         if (fResponseListener != null) {
497                                 Object s = null;
498                                 s = event.getSource();
499                                 if (s instanceof ResponseListener) {
500                                         if (!fResponseListener.equals((ResponseListener) s)) {
501                                                 return;
502                                         }
503                                 }
504                         } else {
505                                 return;
506                         }
507                         
508                         if (event.getKind() == DebugEvent.MODEL_SPECIFIC) {
509                                 switch (event.getDetail()) {
510                                         case IPHPDebugEvent.BREAKPOINT_HIT:
511                                                 int id = fDebugConnection.stackGet();
512                                                 XDebugResponse lastResponse = getResponse(id);
513
514                                                 IBreakpoint breakpoint = breakpointHit(lastResponse.getParentNode());
515                                                 
516                                                 if (breakpoint != null) {
517                                                         fThread.setBreakpoints(new IBreakpoint[]{breakpoint});
518                                                         fThread.incrementStepCounter();
519                                                         suspended(DebugEvent.BREAKPOINT);
520                                                 } else {
521                                                         try {
522                                                                 resume();
523                                                         } catch (DebugException e ) {
524                                                                 ; //nothing to do
525                                                         }
526                                                 }
527                                                 break;
528                                         case IPHPDebugEvent.STEP_END:
529                                                 fThread.incrementStepCounter();
530                                                 suspended(DebugEvent.STEP_END);
531                                                 break;
532                                         case IPHPDebugEvent.STOPPED:
533                                                 stopped();
534                                                 break;
535                                 }
536                         }
537                 }
538         }
539         
540         public void stopped() {
541                 if(fDebugConnection == null) {
542                         return;
543                 }
544
545                 resumed(DebugEvent.TERMINATE);
546
547                 stopListener();
548                 fDebugConnection.close();
549
550                 fSuspended = false;
551
552                 // Dirty hack to check debugging mode (remote or local)
553                 if (fProcess != null) {
554                         try {
555                                 terminate();
556                         } catch (DebugException e) {
557                                 e.printStackTrace();
558                         }
559                 } else {
560                         fDebugConnection = null;
561                         fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
562                 }
563                 
564                 fThread.removeEventListeners();
565                 fThread = null;
566                 fThreads = new IThread[0];
567         }
568         
569         public void handleProxyEvent(/*String ideKey,*/ XDebugConnection connection) {
570                 setDebugConnection(connection);
571                 System.out.println("* New Connection - XDebug.Target: " + fDebugConnection.getSessionID());
572                 
573                 fThread = new XDebugThread(this);
574                 fThreads = new IThread[] {fThread};
575                 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CHANGE));
576                 try {
577                         started();
578                 } catch( DebugException e ){
579                         e.printStackTrace();            
580                 }               
581         }
582
583         private void setDebugConnection(XDebugConnection connection) {
584                 if (connection != null) {
585                         fDebugConnection = connection;
586                         fResponseListener = new ResponseListener(connection);
587                         startListener();
588                 }
589         }
590         
591         /**
592          * @return Returns the fDebugConnection.
593          */
594         public XDebugConnection getDebugConnection() {
595                 return fDebugConnection;
596         }       
597         
598         public void addProcess(IProcess p) {
599                 fProcess = p;
600
601         }
602         public Node getLocalVariables(int level) throws DebugException {
603                 int id = fDebugConnection.contextGet(level, 0);
604                 XDebugResponse response = getResponse(id);
605                 
606                 return response.getParentNode();
607         }
608         
609         public Node getGlobalVariables(int level) throws DebugException {
610                 int id = fDebugConnection.contextGet(level, 1);
611                 XDebugResponse response = getResponse(id);
612                 
613                 return response.getParentNode();
614         }
615         
616         public void stop() {
617                 fDebugConnection.stop();
618         }
619         
620         protected IBreakpoint breakpointHit(Node node) {
621                 Node child = node.getFirstChild();
622                 if (child.getNodeName().equals("stack")) {
623                         int lineNumber = Integer.parseInt(PHPDebugUtils.getAttributeValue(child, "lineno"));
624                         String filename = PHPDebugUtils.getAttributeValue(child, "filename");  
625                         IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
626                         for (int i = 0; i < breakpoints.length; i++) {
627                                 IBreakpoint breakpoint = breakpoints[i];
628                                 if (supportsBreakpoint(breakpoint)) {
629                                         if (breakpoint instanceof ILineBreakpoint) {
630                                                 ILineBreakpoint lineBreakpoint = (ILineBreakpoint) breakpoint;
631                                                 try {                                           
632                                                         if (breakpoint.isEnabled()) {
633                                                                 IMarker marker = breakpoint.getMarker();
634                                                                 if (marker != null) {
635                                                                         String endfilename;
636                                                                         
637                                                                         if (getProcess() == null) {
638                                                                                 endfilename = marker.getResource().getLocation().lastSegment(); 
639                                                                         } else {
640                                                                                 endfilename = marker.getResource().getLocation().toOSString();
641                                                                         }
642                                                                         
643                                                                         int id = fDebugConnection.breakpointGet(marker.getAttribute(XDebugLineBreakpoint.BREAKPOINT_ID,-1));
644                                                                         XDebugResponse dr = getResponse(id);
645                                                                         
646                                                                         Node hitCo = dr.getParentNode().getFirstChild();
647                                                                         int hitCount = 0;
648                                                                         if (hitCo.hasAttributes()) {
649                                                                                 NamedNodeMap listAttribute = hitCo.getAttributes();
650                                                                                 Node attribute = listAttribute.getNamedItem("hit_count");
651                                                                                 if (attribute !=null) {
652                                                                                         hitCount = Integer.parseInt(attribute.getNodeValue());
653                                                                                 }
654                                                                         }
655
656                                                                         if(PHPDebugUtils.unescapeString(filename).endsWith(endfilename)
657                                                                                         && (lineBreakpoint.getLineNumber() == lineNumber) ) {
658                                                                                 if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) > 0) {
659                                                                                         if (marker.getAttribute(XDebugLineBreakpoint.HIT_COUNT, 0) == hitCount) {
660                                                                                                 return (breakpoint);                                                                                            
661                                                                                         }
662                                                                                 } else {
663                                                                                         return (breakpoint);
664                                                                                 }
665                                                                         }
666                                                                 }
667                                                         }
668                                                 } catch (CoreException e) {
669                                                 }
670                                         }
671                                 }
672                         }
673                 }
674                 
675                 return null;
676         }
677         
678         public void startListener() {
679                 fResponseListener.schedule();
680         }
681         
682         public void stopListener() {
683                 fResponseListener.cancel();
684         }
685         public XDebugResponse getResponse(int id) {
686                 XDebugResponse response = fResponseListener.getResponse(id);
687
688                 return response;
689         }
690 }