9f318289e9a8e2b8d2f86812cfa34e5023c2da98
[phpeclipse.git] / net.sourceforge.phpeclipse.xdebug.core / src / net / sourceforge / phpeclipse / xdebug / php / model / XDebugTarget.java
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.AbstractDebugConnection;
9 import net.sourceforge.phpeclipse.xdebug.core.IDebugConnection;
10 import net.sourceforge.phpeclipse.xdebug.core.IPHPDebugEvent;
11 import net.sourceforge.phpeclipse.xdebug.core.IProxyEventListener;
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.ILaunchListener;
28
29 import org.eclipse.debug.core.model.IBreakpoint;
30 import org.eclipse.debug.core.model.IDebugTarget;
31 import org.eclipse.debug.core.model.IMemoryBlock;
32 import org.eclipse.debug.core.model.IProcess;
33 import org.eclipse.debug.core.model.IStackFrame;
34 import org.eclipse.debug.core.model.IThread;
35 import org.eclipse.debug.core.model.IValue;
36 import org.eclipse.debug.core.model.IVariable;
37
38 import net.sourceforge.phpeclipse.xdebug.core.xdebug.ResponseListener.DebugResponse;
39
40 /**
41  * @author Christian
42  *
43  */
44 public class XDebugTarget extends XDebugElement implements IDebugTarget, ILaunchListener, IDebugEventSetListener, IProxyEventListener{
45         // associated system process (VM)
46         private IProcess fProcess;
47         
48         // containing launch object
49         private ILaunch fLaunch;
50         
51         // debugPort
52         private int fDebugPort;
53         
54         // suspend state
55         private boolean fSuspended = false;
56         
57         // terminated state
58         private boolean fTerminated = false;
59         
60         // threads
61         private XDebugThread fThread;
62         private IThread[] fThreads;
63         
64         private AbstractDebugConnection fDebugConnection;
65
66         private String fIdeKey;
67
68
69         public XDebugTarget() {
70                 super(null);
71         }
72
73         /**
74          * Constructs a new debug target in the given launch and waits until
75          * someone with the ideKey connects to the Debugproxy
76          *  
77          * 
78          * @param launch containing launch
79          * @param process process of the interpreter
80          * @param ideKey 
81          * @exception CoreException if unable to connect to host
82          */
83         
84         public XDebugTarget(ILaunch launch, IProcess process, String ideKey) throws CoreException {
85                 init(launch, process, ideKey);
86         }
87
88         /**
89          * Constructs a new debug target in the given launch and waits until
90          * someone with the ideKey connects to the Debugproxy
91          *  
92          * 
93          * @param launch containing launch
94          * @param process process of the interpreter
95          * @param ideKey 
96          * @param pathMap Pathmap for the debug session
97          * @exception CoreException if unable to connect to host
98          */
99         
100         /*public XDebugTarget(ILaunch launch, IProcess process, String ideKey, List<String> pathMap) throws CoreException {
101                 super(null);
102                 init(launch, process, ideKey,pathMap);
103         }*/
104         
105         private void init(ILaunch launch, IProcess process, String ideKey/*,List<String> pathMap*/) {
106                 fLaunch = launch;
107                 fProcess = process;
108                 fTarget = this;
109                 fDebugConnection = null;
110                 fThread = null;
111                 fThreads = new IThread[0];
112                 fIdeKey = ideKey;
113                 
114                 XDebugProxy proxy = XDebugCorePlugin.getDefault().getXDebugProxy();
115                 proxy.addProxyEventListener(this,ideKey);
116                 if (!proxy.isRunning())
117                         proxy.start();
118                 
119                 proxy.setTarget(this);
120
121                 fDebugPort = proxy.getProxyPort();
122                 
123                 DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(this);
124                 DebugPlugin.getDefault().addDebugEventListener(this);
125         }
126
127         /* (non-Javadoc)
128          * @see org.eclipse.debug.core.model.IDebugTarget#getProcess()
129          */
130         public IProcess getProcess() {
131                 return fProcess;
132         }
133
134         /* (non-Javadoc)
135          * @see org.eclipse.debug.core.model.IDebugTarget#getThreads()
136          */
137         public IThread[] getThreads() throws DebugException {
138                 return fThreads;
139         }
140
141         /* (non-Javadoc)
142          * @see org.eclipse.debug.core.model.IDebugTarget#hasThreads()
143          */
144         public boolean hasThreads() throws DebugException {
145                 return (fThreads.length>0);
146         }
147
148         /* (non-Javadoc)
149          * @see org.eclipse.debug.core.model.IDebugTarget#getName()
150          */
151         public String getName() throws DebugException {
152                 return "PHP XDebug Client at localhost:" + fDebugPort;
153         }
154
155         /* (non-Javadoc)
156          * @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint)
157          */
158         public boolean supportsBreakpoint(IBreakpoint breakpoint) {
159                 if (breakpoint.getModelIdentifier().equals(IXDebugConstants.ID_PHP_DEBUG_MODEL)) {
160                         return true;
161                 }
162                 return false;
163         }
164
165         /* (non-Javadoc)
166          * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget()
167          */
168         public IDebugTarget getDebugTarget() {
169                 return this;
170         }
171
172         /* (non-Javadoc)
173          * @see org.eclipse.debug.core.model.IDebugElement#getLaunch()
174          */
175         public ILaunch getLaunch() {
176                 return fLaunch;
177         }
178
179         /* (non-Javadoc)
180          * @see org.eclipse.debug.core.model.ITerminate#canTerminate()
181          */
182         public boolean canTerminate() {
183                 if (getProcess()!=null)  // ther is no running Process in remote debugging
184                         return getProcess().canTerminate();
185                 return true;
186         }
187
188         /* (non-Javadoc)
189          * @see org.eclipse.debug.core.model.ITerminate#isTerminated()
190          */
191         public boolean isTerminated() {
192 //              return getProcess().isTerminated();
193                 return fTerminated;
194         }
195
196         /* (non-Javadoc)
197          * @see org.eclipse.debug.core.model.ITerminate#terminate()
198          */
199         public void terminate() throws DebugException {
200                 //IThread  t = fThreads.length();
201                 //fTerminated=true;
202                 XDebugProxy proxy=XDebugCorePlugin.getDefault().getXDebugProxy();
203                 proxy.stop();
204                 proxy.removeProxyEventListener(this,fIdeKey);
205                 System.out.println("XDebug.Target: ProxyEventlistener removed");
206                 fTerminated = true;
207                 //fDisconnected = true;
208                 fSuspended = false;
209                 XDebugCorePlugin.getBreakpointManager().removeBreakpointListener(this);
210                 fireTerminateEvent();
211                 DebugPlugin.getDefault().removeDebugEventListener(this);
212                 if (fThread!=null)
213                         fThread.removeEventListeners();
214         }
215
216         /* (non-Javadoc)
217          * @see org.eclipse.debug.core.model.ISuspendResume#canResume()
218          */
219         public boolean canResume() {
220 //              return !isTerminated() && isSuspended();
221                 return false;
222         }
223
224         /* (non-Javadoc)
225          * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
226          */
227         public boolean canSuspend() {
228 //              return !isTerminated() && !isSuspended();
229                 return false;
230         }
231
232         /* (non-Javadoc)
233          * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
234          */
235         public boolean isSuspended() {
236                 return fSuspended;
237         }
238
239         /* (non-Javadoc)
240          * @see org.eclipse.debug.core.model.ISuspendResume#resume()
241          */
242         public void resume() throws DebugException {
243                 if (fDebugConnection != null) {
244                         fThread.setBreakpoints(null);
245                         fDebugConnection.run();
246                 }                       
247         }
248         
249         /**
250          * Notification the target has resumed for the given reason
251          * 
252          * @param detail reason for the resume
253          */
254         private void resumed(int detail) {
255                 fSuspended = false;
256                 fThread.fireResumeEvent(detail);
257         }
258         
259         /**
260          * Notification the target has suspended for the given reason
261          * 
262          * @param detail reason for the suspend
263          */
264         public void suspended(int detail) {
265                 fSuspended = true;
266                 fThread.fireSuspendEvent(detail);
267         }       
268         
269         /* (non-Javadoc)
270          * @see org.eclipse.debug.core.model.ISuspendResume#suspend()
271          */
272         public void suspend() throws DebugException {
273         }
274
275         /* (non-Javadoc)
276          * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
277          */
278         public void breakpointAdded(IBreakpoint breakpoint) {
279                 IMarker marker = breakpoint.getMarker();
280                 IPath path = marker.getResource().getLocation();
281                 IPath cp = path.removeLastSegments(1);
282                 List pathMap = null;
283                 try {
284                         pathMap = fLaunch.getLaunchConfiguration().getAttribute(IXDebugConstants.ATTR_PHP_PATHMAP,(List)null);
285                 } catch (CoreException e2) {
286                         // TODO Auto-generated catch block
287                         e2.printStackTrace();
288                 }
289
290                 if (!fDebugConnection.isClosed()) {
291                         if (fProcess == null) {
292                                 PathMapItem pmi = null;
293                                 for (int i = 0; i < pathMap.size(); i++) {
294                                         pmi = new PathMapItem((String) pathMap.get(i));
295                                         IPath local = (IPath)pmi.getLocalPath().clone();
296                                         local = local./*removeFirstSegments(1).*/makeAbsolute();
297                                         int matchedSegments = local.segmentCount();
298                                         if (local.matchingFirstSegments(cp) == matchedSegments) {
299                                                 IPath newPath = pmi.getRemotePath();
300                                                 //newPath = newPath.removeFirstSegments(1);                                             
301                                                 newPath = newPath.append(path.removeFirstSegments(matchedSegments));
302                                                 newPath = newPath.makeAbsolute();
303                                                 if (supportsBreakpoint(breakpoint)) {
304                                                         try {
305                                                                 fDebugConnection.addBreakpoint(breakpoint, newPath);
306                                                         } catch (DebugException e) {
307                                                                 e.printStackTrace();
308                                                         }
309                                                 }
310                                         }
311                                 }                       
312                         } else {
313                                 if (supportsBreakpoint(breakpoint)) {
314                                         try {
315                                                 fDebugConnection.addBreakpoint(breakpoint, path);
316                                         } catch (DebugException e) {
317                                                 e.printStackTrace();
318                                         }
319                                 }
320                         }
321                 }
322         }
323         
324         /* (non-Javadoc)
325          * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
326          */
327         public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
328                 if (supportsBreakpoint(breakpoint)) {
329                         try {
330                                 fDebugConnection.removeBreakpoint(breakpoint);
331                         } catch (CoreException e) {
332                         }
333                 }
334         }
335
336         /* (non-Javadoc)
337          * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
338          */
339         public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
340 //              if (supportsBreakpoint(breakpoint)) {
341 //                      try {
342 //                              if (breakpoint.isEnabled()) {
343 //                                      breakpointAdded(breakpoint);
344 //                              } else {
345 //                                      breakpointRemoved(breakpoint, null);
346 //                              }
347 //                      } catch (CoreException e) {
348 //                      }
349 //              }
350         }
351
352         /* (non-Javadoc)
353          * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
354          */
355         public boolean canDisconnect() {
356                 return false;
357         }
358
359         /* (non-Javadoc)
360          * @see org.eclipse.debug.core.model.IDisconnect#disconnect()
361          */
362         public void disconnect() throws DebugException {
363         }
364
365         /* (non-Javadoc)
366          * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected()
367          */
368         public boolean isDisconnected() {
369                 return (fDebugConnection==null);
370         }
371
372         /* (non-Javadoc)
373          * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval()
374          */
375         public boolean supportsStorageRetrieval() {
376                 return false;
377         }
378
379         /* (non-Javadoc)
380          * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long)
381          */
382         public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
383                 return null;
384         }
385
386         /**
387          * Notification we have connected to the PHP debugger and it has been started.
388          * Resume the the debugger.
389          */
390         public void started() throws DebugException {
391                 fThread.setBreakpoints(null);
392                 fThread.setStepping(false);
393
394                 /*boolean CanDisconnect =*/ Integer.parseInt(fDebugConnection.featureGet("detach").getValue()) /*!= 0*/;
395
396                 System.out.println("in Target.started()");
397                 DebugResponse response = fDebugConnection.featureGet("max_children");
398                 String a1 = response.getValue();
399                 System.out.println("max children:"+a1);
400                 DebugResponse response1 = fDebugConnection.featureGet("max_children");
401                 String a2 = response1.getValue();
402                 System.out.println("max depth:"+a2);
403                 
404                 
405                 boolean res = fDebugConnection.featureSet("max_depth", "100" );
406                 if( res == true ) {
407                         System.out.println("Set depth to 100 (hack)");
408                 }
409                 
410                 installDeferredBreakpoints();
411                 try {
412                         resume();
413 //                      step();
414                 } catch (DebugException e) {
415                         e.printStackTrace();
416                 }
417         }
418         
419         /**
420          * Install breakpoints that are already registered with the breakpoint
421          * manager.
422          */
423         private void installDeferredBreakpoints() {
424                 IBreakpoint[] breakpoints = XDebugCorePlugin.getBreakpoints();
425                 for (int i = 0; i < breakpoints.length; i++) {
426                         breakpointAdded(breakpoints[i]);
427                 }
428         }
429         
430         /**
431          * Called when this debug target terminates.
432          */
433         public void terminated() {
434                 fTerminated = true;
435                 fSuspended = false;
436                 XDebugCorePlugin.getBreakpointManager().removeBreakpointListener(this);
437                 fireTerminateEvent();
438                 DebugPlugin.getDefault().removeDebugEventListener(this);
439                 fThread.removeEventListeners(); 
440         }
441         
442         /**
443          * Returns the current stack frames in the target.
444          * 
445          * @return the current stack frames in the target
446          * @throws DebugException if unable to perform the request
447          */
448         protected IStackFrame[] getStackFrames() throws DebugException {
449                 return fDebugConnection.getStackFrames(fThread);
450         }
451         
452         /**
453          * Single step the interpreter.
454          * 
455          * @throws DebugException if the request fails
456          */
457         protected void step_over() throws DebugException {
458                 fThread.setStepping(true);
459                 resumed(DebugEvent.STEP_OVER);
460                 fDebugConnection.stepOver();
461         }
462         
463         /**
464          * Single step the interpreter.
465          * 
466          * @throws DebugException if the request fails
467          */
468         protected void step_into() throws DebugException {
469                 fThread.setStepping(true);
470                 resumed(DebugEvent.STEP_INTO);
471                 fDebugConnection.stepInto();
472         }
473         
474         /**
475          * Single step the interpreter.
476          * 
477          * @throws DebugException if the request fails
478          */
479         protected void step_out() throws DebugException {
480                 fThread.setStepping(true);
481                 resumed(DebugEvent.STEP_RETURN);
482                 fDebugConnection.stepOut();
483         }
484         
485         /**
486          * Returns the current value of the given variable.
487          * 
488          * @param variable
489          * @return variable value
490          * @throws DebugException if the request fails
491          */
492         protected IValue getVariableValue(XDebugVariable variable) throws DebugException {
493                 return null;
494         }
495         
496         /**
497          * Returns the values on the data stack (top down)
498          * 
499          * @return the values on the data stack (top down)
500          */
501         public IValue[] getDataStack() throws DebugException {
502                 return new IValue[0];           
503         }
504         
505         public boolean setVarValue(String name, String value) {
506                 return fDebugConnection.setVarValue(name,value);
507         }
508         
509         public void handleDebugEvents(DebugEvent[] events) {
510                 for (int i=0;i<events.length;i++) {
511                         DebugEvent event=events[i];
512                         if(event.getKind()==DebugEvent.MODEL_SPECIFIC) {
513                                 if (event.getDetail()==IPHPDebugEvent.BREAKPOINT_HIT) {
514                                         IBreakpoint breakpoint = (IBreakpoint) event.getData();
515                                         fThread.setBreakpoints(new IBreakpoint[]{breakpoint});
516                                         fThread.incrementStepCounter();
517                                         suspended(DebugEvent.BREAKPOINT);
518                                 } else if (event.getDetail()==IPHPDebugEvent.STEP_END) {
519                                         fThread.incrementStepCounter();
520                                         suspended(DebugEvent.STEP_END);
521                                 } else if (event.getDetail()==IPHPDebugEvent.STOPPED) {
522                                         //fDebugConnection.removeBreakpoint(breakpoint);
523                                         fThread.removeEventListeners();
524                                         fThread=null;
525                                         fThreads= new IThread[0];
526                                         fSuspended=false;
527                                         // TODO Dirty hack to check debugging mode (remote or local)
528                                         if (fProcess!=null) {
529                                                 try {
530                                                         terminate();
531                                                 } catch (DebugException e) {
532                                                         e.printStackTrace();
533                                                 }
534                                         } else {
535                                                 fDebugConnection = null;
536                                                 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
537                                         }
538                                 } else {
539                                         int a = 20;
540                                         a *= 10;
541                                 }
542                         } else {
543                                 int b = 10;
544                                 b *= 1;
545                         }
546                 }
547                 
548         }
549         
550         public void handleProxyEvent(String ideKey, String initString, AbstractDebugConnection connection) {
551                 System.out.println("* New Connection - XDebug.Target: "+ideKey);
552                 setDebugConnection(connection);
553                 
554                 XDebugProxy proxy=XDebugCorePlugin.getDefault().getXDebugProxy();
555                 fDebugPort=proxy.getProxyPort();
556                 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CHANGE));
557
558                 
559 //              proxy.removeProxyEventListener(this,ideKey);
560 //              System.out.println("XDebug.Target: ProxyEventlistener removed");
561                 fThread = new XDebugThread(this);
562                 fThreads = new IThread[] {fThread};
563                 try {
564                         started();
565                 } catch( DebugException e ){
566                         e.printStackTrace();            
567                 }               
568         }
569
570         private void setDebugConnection(AbstractDebugConnection connection) {
571                 if (connection != null) {
572                         fDebugConnection = connection;
573                         fDebugConnection.startListener();
574                 }
575         }
576         
577         /**
578          * @return Returns the fDebugConnection.
579          */
580         public IDebugConnection getDebugConnection() {
581                 return fDebugConnection;
582         }       
583         
584         public void addProcess(IProcess p) {
585                 fProcess = p;
586
587         }
588
589         public void launchRemoved(ILaunch launch) {
590         }
591
592         /**
593          * Notifies this listener that the specified launch
594          * has been added.
595          * 
596          * @param launch the newly added launch
597          * @since 2.0
598          */
599         public void launchAdded(ILaunch launch){
600         }
601
602         /**
603          * Notifies this listener that the specified launch
604          * has changed. For example, a process or debug target
605          * has been added to the launch.
606          * 
607          * @param launch the changed launch
608          * @since 2.0
609          */
610         public void launchChanged(ILaunch launch) {
611         }
612         
613         public IVariable[] getVariables(XDebugStackFrame StackFrame, int Level) {
614                 return fDebugConnection.getVariables(StackFrame, Level);
615         }
616 }