Fixed the debugger client to work in Eclipse 3.1.
[phpeclipse.git] / net.sourceforge.phpeclipse.debug.core / src / net / sourceforge / phpdt / internal / debug / core / model / PHPDebugTarget.java
1 /**********************************************************************
2 Copyright (c) 2000, 2002 IBM Corp. and others.
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
7
8 Contributors:
9     IBM Corporation - Initial implementation
10     Vicente Fernando - www.alfersoft.com.ar
11 **********************************************************************/
12 package net.sourceforge.phpdt.internal.debug.core.model;
13
14 import net.sourceforge.phpdt.internal.debug.core.PHPDBGProxy;
15 import net.sourceforge.phpdt.internal.debug.core.PHPDebugCorePlugin;
16 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
17
18 import org.eclipse.core.resources.IMarkerDelta;
19 import org.eclipse.debug.core.DebugEvent;
20 import org.eclipse.debug.core.DebugException;
21 import org.eclipse.debug.core.DebugPlugin;
22 import org.eclipse.debug.core.IBreakpointManager;
23 import org.eclipse.debug.core.IDebugEventSetListener;
24 import org.eclipse.debug.core.ILaunch;
25 import org.eclipse.debug.core.ILaunchListener;
26 import org.eclipse.debug.core.model.IBreakpoint;
27 import org.eclipse.debug.core.model.IDebugTarget;
28 import org.eclipse.debug.core.model.IMemoryBlock;
29 import org.eclipse.debug.core.model.IProcess;
30 import org.eclipse.debug.core.model.IStackFrame;
31 import org.eclipse.debug.core.model.IThread;
32 import org.eclipse.jface.resource.ImageDescriptor;
33 import org.eclipse.ui.model.IWorkbenchAdapter;
34
35 /**
36  * Debug target for PHP debug model.
37  */
38 public class PHPDebugTarget implements IPHPDebugTarget, ILaunchListener, IDebugEventSetListener {
39                 
40         private IProcess process;
41         private boolean isTerminated;
42         private boolean isSuspended;
43         private ILaunch launch;
44         private PHPThread[] threads;
45         private PHPDBGProxy phpDBGProxy;
46
47         public PHPDebugTarget(ILaunch launch, IProcess process) {
48                 this.isSuspended = false;
49                 this.launch = launch;
50                 this.process = process;
51                 this.threads = new PHPThread[0];
52                 // TODO XXX remove breakpoint listener at termination to avoid live leak
53                 IBreakpointManager manager= DebugPlugin.getDefault().getBreakpointManager();
54                 manager.addBreakpointListener(this);
55                 DebugPlugin.getDefault().addDebugEventListener(this);
56                 initialize();
57         }
58
59         protected synchronized void initialize() {
60                 DebugEvent ev = new DebugEvent(this, DebugEvent.CREATE);
61                 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });    
62         }
63
64         public void addThread(PHPThread phpThread) {
65                 int i;
66                 PHPThread[] updatedThreads = new PHPThread[threads.length + 1];
67                 
68                 for(i=0; i < threads.length; i++) {
69                         updatedThreads[i] = threads[i];
70                 }
71                 updatedThreads[i] = phpThread;
72                 threads = updatedThreads;
73
74                 fireChangeEvent();
75                 fireThreadCreateEvent(phpThread);
76         }
77
78         private void fireChangeEvent() {
79                 DebugEvent ev = new DebugEvent(this, DebugEvent.CHANGE);
80                 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
81         }
82
83         private void fireThreadCreateEvent(PHPThread phpThread) {
84                 DebugEvent ev = new DebugEvent(phpThread, DebugEvent.CREATE);
85                 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
86         }
87
88         protected PHPThread getThreadById(int id) {
89                 for (int i = 0; i < threads.length; i++) {
90                         if (threads[i].getId() == id) {
91                                 return threads[i];
92                         }
93                 }
94                 return null;
95         }
96
97         public IThread[] getThreads() {
98                 return threads;
99         }
100
101         public boolean hasThreads() throws DebugException {
102                 return threads.length > 0;
103         }
104
105         public String getName() throws DebugException {
106                 return "PHP Debugger at localhost:" + getPHPDBGProxy().getPort();
107         }
108
109         public boolean supportsBreakpoint(IBreakpoint arg0) {
110             if(arg0.getModelIdentifier().equals(PHPDebugCorePlugin.PLUGIN_ID)) {
111             return true;
112             }
113                 return false;
114         }
115
116         public String getModelIdentifier() {
117                 return PHPDebugCorePlugin.PLUGIN_ID;
118         }
119
120         public IDebugTarget getDebugTarget() {
121                 return this;
122         }
123
124         public ILaunch getLaunch() {
125                 return launch;
126         }
127
128         public boolean canTerminate() {
129                 return !isTerminated;
130         }
131
132         public boolean isTerminated() {
133                 return isTerminated;
134         }
135
136         public synchronized void terminate() {
137                 // This method is synchronized to control a race condition between the 
138                 // UI thread that terminates the debugging session, and the slave 
139                 // thread that executes PHPLoop.run
140                 if (isTerminated)
141                         // Avoid terminating twice...
142                         return;
143                 phpDBGProxy.stop();
144                 this.threads = new PHPThread[0];
145                 isTerminated = true;
146                 fireChangeEvent();
147                 IBreakpointManager manager= DebugPlugin.getDefault().getBreakpointManager();
148                 manager.removeBreakpointListener(this);
149                 DebugPlugin.getDefault().removeDebugEventListener(this);
150         }
151
152         public boolean canResume() {
153                 if(isTerminated) return false;
154                 return isSuspended;
155         }
156
157         public boolean canSuspend() {
158                 if(isTerminated) return false;
159                 return !isSuspended;
160         }
161
162         public boolean isSuspended() {
163                 return isSuspended;
164         }
165
166         public void resume() throws DebugException {
167                 this.getPHPDBGProxy().resume();
168                 isSuspended= false;
169         }
170
171         public void suspend() throws DebugException {
172                 this.getPHPDBGProxy().pause();
173                 isSuspended= true;
174         }
175
176         public void breakpointAdded(IBreakpoint breakpoint) {
177                 this.getPHPDBGProxy().addBreakpoint(breakpoint) ;
178         }
179
180         public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta arg1) {
181                 this.getPHPDBGProxy().removeBreakpoint(breakpoint) ;            
182         }
183
184         public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta arg1) {
185                 // is called e.g. after a line has been inserted before a breakpoint
186                 // but then the debugger is out of sync with the file anyway, so debugging
187                 // should be stopped here.
188         }
189
190         public boolean canDisconnect() {
191                 return false;
192         }
193
194         public void disconnect() throws DebugException {
195         }
196
197         public boolean isDisconnected() {
198                 return false;
199         }
200
201         public boolean supportsStorageRetrieval() {
202                 return false;
203         }
204
205         public IMemoryBlock getMemoryBlock(long arg0, long arg1) throws DebugException {
206                 return null;
207         }
208
209         public Object getAdapter(Class arg0) {
210                 if (IWorkbenchAdapter.class.equals(arg0)) {
211                         return new IWorkbenchAdapter() {
212                                 public Object[] getChildren(Object o) {
213                                         Object[] children = null;
214                                         IThread[] threads = getThreads();
215                                         if (null != threads) {
216                                                 children = new Object[threads.length];
217                                                 for (int i = 0; i < threads.length; ++i) 
218                                                         children[i] = threads[i];
219                                         }
220                                         return children;
221                                 }
222                                 public ImageDescriptor getImageDescriptor(Object object) {
223                                         return null;
224                                 }
225                                 public String getLabel(Object o) {
226                                         String label = "(Unable to look up name... check error log)";
227                                         try {
228                                                 label = getName();
229                                         } catch (DebugException x) {
230                                                 PHPeclipsePlugin.log(label, x);
231                                         }
232                                         return label;
233                                 }
234                                 public Object getParent(Object o) {
235                                         return PHPDebugTarget.this.getLaunch();
236                                 }
237                         };
238                 }
239                 return null;
240         }
241
242         public IProcess getProcess() {
243                 return process;
244         }
245
246         public void setProcess(IProcess process) {
247                 this.process = process;
248         }
249
250         public PHPDBGProxy getPHPDBGProxy() {
251                 return phpDBGProxy;
252         }
253
254         public void setPHPDBGProxy(PHPDBGProxy phpDBGProxy) {
255                 this.phpDBGProxy = phpDBGProxy;
256         }
257         
258         /**
259          * @see ILaunchListener#launchRemoved(ILaunch)
260          */
261         public void launchRemoved(ILaunch launch) {
262                 if (!isTerminated()) {
263                         return;
264                 }
265                 if (launch.equals(getLaunch())) {
266                         // This target has been deregistered, but it hasn't successfully terminated.
267                         // Update internal state to reflect that it is disconnected
268                         terminate();
269                 }
270         }
271         
272         /**
273          * @see ILaunchListener#launchAdded(ILaunch)
274          */
275         public void launchAdded(ILaunch launch) {
276         }
277         
278         /**
279          * @see ILaunchListener#launchChanged(ILaunch)
280          */
281         public void launchChanged(ILaunch launch) {
282         }
283         
284         /**
285          * When a debug target or process terminates, terminate DBG Proxy.
286          * 
287          * @see IDebugEventSetListener#handleDebugEvents(DebugEvent[])
288          */
289         public void handleDebugEvents(DebugEvent[] events) {
290                 for (int i = 0; i < events.length; i++) {
291                         DebugEvent event = events[i];
292                         if (event.getKind() == DebugEvent.TERMINATE) {
293                                 Object source = event.getSource();
294                                 if (source instanceof PHPDebugTarget || source instanceof IDebugTarget) {
295                                         getPHPDBGProxy().stop();
296                                 } else if(source instanceof IProcess) {
297                                         if(getDebugTarget().getProcess() == (IProcess)source) {
298                                                 getPHPDBGProxy().stop();
299                                         }
300                                 }
301                         } else if (event.getKind() == DebugEvent.SUSPEND) {
302                                 getPHPDBGProxy().pause();
303                         }
304                 }
305         }
306 }
307