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
9 IBM Corporation - Initial implementation
10 Vicente Fernando - www.alfersoft.com.ar
11 **********************************************************************/
12 package net.sourceforge.phpdt.internal.debug.core.model;
14 import net.sourceforge.phpdt.internal.debug.core.PHPDBGProxy;
15 import net.sourceforge.phpdt.internal.debug.core.PHPDebugCorePlugin;
16 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
18 import org.eclipse.core.resources.IMarkerDelta;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.debug.core.DebugEvent;
21 import org.eclipse.debug.core.DebugException;
22 import org.eclipse.debug.core.DebugPlugin;
23 import org.eclipse.debug.core.IBreakpointManager;
24 import org.eclipse.debug.core.IDebugEventSetListener;
25 import org.eclipse.debug.core.ILaunch;
26 import org.eclipse.debug.core.ILaunchListener;
27 import org.eclipse.debug.core.model.IBreakpoint;
28 import org.eclipse.debug.core.model.IDebugTarget;
29 import org.eclipse.debug.core.model.IMemoryBlock;
30 import org.eclipse.debug.core.model.IProcess;
31 import org.eclipse.debug.core.model.IThread;
32 import org.eclipse.jface.resource.ImageDescriptor;
33 import org.eclipse.ui.model.IWorkbenchAdapter;
36 * Debug target for PHP debug model.
38 public class PHPDebugTarget implements IPHPDebugTarget, ILaunchListener,
39 IDebugEventSetListener {
41 private IProcess process;
43 private ILaunch launch;
45 private PHPThread[] threads = new PHPThread[0];
47 private PHPDBGProxy phpDBGProxy;
50 private boolean isTerminated = false;
52 private boolean isSuspended = false;
54 boolean isTerminated() {
58 boolean isSuspended() {
62 void setTerminated(boolean terminated) {
63 this.isTerminated = terminated;
66 void setSuspended(boolean suspended) {
68 throw new IllegalStateException();
69 this.isSuspended = suspended;
73 private final State state = new State();
75 public PHPDebugTarget(ILaunch launch, IProcess process) {
76 if (null == launch && null == process)
77 throw new IllegalArgumentException();
79 this.process = process;
80 // TODO XXX remove breakpoint listener at termination to avoid live leak
81 IBreakpointManager manager = DebugPlugin.getDefault()
82 .getBreakpointManager();
83 manager.addBreakpointListener(this);
84 DebugPlugin.getDefault().addDebugEventListener(this);
88 protected synchronized void initialize() {
89 DebugEvent ev = new DebugEvent(this, DebugEvent.CREATE);
90 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
93 public void addThread(PHPThread phpThread) {
95 PHPThread[] updatedThreads = new PHPThread[threads.length + 1];
97 for (i = 0; i < threads.length; i++) {
98 updatedThreads[i] = threads[i];
100 updatedThreads[i] = phpThread;
101 threads = updatedThreads;
104 fireThreadCreateEvent(phpThread);
107 private void fireChangeEvent() {
108 DebugEvent ev = new DebugEvent(this, DebugEvent.CHANGE);
109 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
112 private void fireThreadCreateEvent(PHPThread phpThread) {
113 DebugEvent ev = new DebugEvent(phpThread, DebugEvent.CREATE);
114 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
117 protected PHPThread getThreadById(int id) {
118 for (int i = 0; i < threads.length; i++) {
119 if (threads[i].getId() == id) {
126 public IThread[] getThreads() {
130 public boolean hasThreads() throws DebugException {
131 return threads.length > 0;
134 public String getName() throws DebugException {
135 return "PHP Debugger at localhost:" + getPHPDBGProxy().getPort();
138 public boolean supportsBreakpoint(IBreakpoint arg0) {
139 if (arg0.getModelIdentifier().equals(PHPDebugCorePlugin.PLUGIN_ID)) {
145 public String getModelIdentifier() {
146 return PHPDebugCorePlugin.PLUGIN_ID;
149 public IDebugTarget getDebugTarget() {
153 public ILaunch getLaunch() {
157 public synchronized boolean canTerminate() {
158 return !isTerminated();
161 public synchronized boolean isTerminated() {
162 return state.isTerminated();
165 public synchronized void terminate() {
166 // This method is synchronized to control a race condition between the
167 // UI thread that terminates the debugging session, and the slave
168 // thread that executes PHPLoop.run
170 // Avoid terminating twice...
172 state.setTerminated(true);
174 this.threads = new PHPThread[0];
176 IBreakpointManager manager = DebugPlugin.getDefault()
177 .getBreakpointManager();
178 manager.removeBreakpointListener(this);
179 DebugPlugin.getDefault().removeDebugEventListener(this);
182 public synchronized boolean canResume() {
185 return isSuspended();
188 public synchronized boolean canSuspend() {
191 return !isSuspended();
194 public synchronized boolean isSuspended() {
195 return state.isSuspended();
198 public synchronized void resume() throws DebugException {
201 state.setSuspended(false);
202 this.getPHPDBGProxy().resume();
203 IThread[] threads = getThreads();
204 for (int i = 0; i < threads.length; ++i)
208 public synchronized void suspend() throws DebugException {
211 this.getPHPDBGProxy().pause();
212 state.setSuspended(true);
213 IThread[] threads = getThreads();
214 for (int i = 0; i < threads.length; ++i)
215 threads[i].suspend();
218 public void breakpointAdded(IBreakpoint breakpoint) {
219 this.getPHPDBGProxy().addBreakpoint(breakpoint);
222 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta arg1) {
223 this.getPHPDBGProxy().removeBreakpoint(breakpoint);
226 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta arg1) {
227 // This method is called whenever a source file has changed in which
229 // we terminate since the source will be out of sync with the debugger
230 // The method will also be called when the user enables/disables
232 // in this case we add or remove the breakpoint
234 // Check if breakpoint state changed from disabled to enabled
235 if (breakpoint.isEnabled()
236 && !arg1.getAttribute("org.eclipse.debug.core.enabled",
238 this.getPHPDBGProxy().addBreakpoint(breakpoint);
239 // Check if breakpoint state changed from enabled to disabled
240 } else if (!breakpoint.isEnabled()
242 .getAttribute("org.eclipse.debug.core.enabled",
244 this.getPHPDBGProxy().removeBreakpoint(breakpoint);
246 // All other cases will terminate the debugger
249 } catch (CoreException e) {
254 public boolean canDisconnect() {
258 public void disconnect() throws DebugException {
261 public boolean isDisconnected() {
265 public boolean supportsStorageRetrieval() {
269 public IMemoryBlock getMemoryBlock(long arg0, long arg1)
270 throws DebugException {
274 public Object getAdapter(Class arg0) {
275 if (IWorkbenchAdapter.class.equals(arg0)) {
276 return new IWorkbenchAdapter() {
277 public Object[] getChildren(Object o) {
278 Object[] children = null;
279 IThread[] threads = getThreads();
280 if (null != threads) {
281 children = new Object[threads.length];
282 for (int i = 0; i < threads.length; ++i)
283 children[i] = threads[i];
288 public ImageDescriptor getImageDescriptor(Object object) {
292 public String getLabel(Object o) {
293 String label = "(Unable to look up name... check error log)";
296 } catch (DebugException x) {
297 PHPeclipsePlugin.log(label, x);
302 public Object getParent(Object o) {
303 return PHPDebugTarget.this.getLaunch();
310 public IProcess getProcess() {
314 public void setProcess(IProcess process) {
315 this.process = process;
318 public PHPDBGProxy getPHPDBGProxy() {
322 public void setPHPDBGProxy(PHPDBGProxy phpDBGProxy) {
323 this.phpDBGProxy = phpDBGProxy;
327 * @see ILaunchListener#launchRemoved(ILaunch)
329 public void launchRemoved(ILaunch launch) {
330 if (!isTerminated()) {
333 if (launch.equals(getLaunch())) {
334 // This target has been deregistered, but it hasn't successfully
336 // Update internal state to reflect that it is disconnected
342 * @see ILaunchListener#launchAdded(ILaunch)
344 public void launchAdded(ILaunch launch) {
348 * @see ILaunchListener#launchChanged(ILaunch)
350 public void launchChanged(ILaunch launch) {
354 * When a debug target or process terminates, terminate DBG Proxy.
356 * @see IDebugEventSetListener#handleDebugEvents(DebugEvent[])
358 public void handleDebugEvents(DebugEvent[] events) {
359 for (int i = 0; i < events.length; i++) {
360 DebugEvent event = events[i];
361 if (event.getKind() == DebugEvent.TERMINATE) {
362 Object source = event.getSource();
363 if (source instanceof PHPDebugTarget
364 || source instanceof IDebugTarget) {
365 getPHPDBGProxy().stop();
366 } else if (source instanceof IProcess) {
367 if (getDebugTarget().getProcess() == (IProcess) source) {
368 getPHPDBGProxy().stop();
371 } else if (event.getKind() == DebugEvent.SUSPEND) {
372 getPHPDBGProxy().pause();