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 extends PHPDebugElement 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) {
77 if (null == launch && null == process)
78 throw new IllegalArgumentException();
80 this.process = process;
81 // TODO XXX remove breakpoint listener at termination to avoid live leak
82 IBreakpointManager manager = DebugPlugin.getDefault()
83 .getBreakpointManager();
84 manager.addBreakpointListener(this);
85 DebugPlugin.getDefault().addDebugEventListener(this);
89 protected synchronized void initialize() {
90 DebugEvent ev = new DebugEvent(this, DebugEvent.CREATE);
91 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
94 public void addThread(PHPThread phpThread) {
96 PHPThread[] updatedThreads = new PHPThread[threads.length + 1];
98 for (i = 0; i < threads.length; i++) {
99 updatedThreads[i] = threads[i];
101 updatedThreads[i] = phpThread;
102 threads = updatedThreads;
105 fireThreadCreateEvent(phpThread);
108 private void fireChangeEvent() {
109 DebugEvent ev = new DebugEvent(this, DebugEvent.CHANGE);
110 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
113 private void fireThreadCreateEvent(PHPThread phpThread) {
114 DebugEvent ev = new DebugEvent(phpThread, DebugEvent.CREATE);
115 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { ev });
118 protected PHPThread getThreadById(int id) {
119 for (int i = 0; i < threads.length; i++) {
120 if (threads[i].getId() == id) {
127 public IThread[] getThreads() {
131 public boolean hasThreads() throws DebugException {
132 return threads.length > 0;
135 public String getName() throws DebugException {
136 return "PHP Debugger at localhost:" + getPHPDBGProxy().getPort();
139 public boolean supportsBreakpoint(IBreakpoint arg0) {
140 if (arg0.getModelIdentifier().equals(PHPDebugCorePlugin.PLUGIN_ID)) {
146 public String getModelIdentifier() {
147 return PHPDebugCorePlugin.PLUGIN_ID;
150 public IDebugTarget getDebugTarget() {
154 public ILaunch getLaunch() {
158 public synchronized boolean canTerminate() {
159 return !isTerminated();
162 public synchronized boolean isTerminated() {
163 return state.isTerminated();
166 public synchronized void terminate() {
167 // This method is synchronized to control a race condition between the
168 // UI thread that terminates the debugging session, and the slave
169 // thread that executes PHPLoop.run
171 // Avoid terminating twice...
173 state.setTerminated(true);
175 this.threads = new PHPThread[0];
177 IBreakpointManager manager = DebugPlugin.getDefault()
178 .getBreakpointManager();
179 manager.removeBreakpointListener(this);
180 DebugPlugin.getDefault().removeDebugEventListener(this);
183 public synchronized boolean canResume() {
186 return isSuspended();
189 public synchronized boolean canSuspend() {
192 return !isSuspended();
195 public synchronized boolean isSuspended() {
196 return state.isSuspended();
199 public synchronized void resume() throws DebugException {
202 state.setSuspended(false);
203 this.getPHPDBGProxy().resume();
204 IThread[] threads = getThreads();
205 for (int i = 0; i < threads.length; ++i)
209 public synchronized void suspend() throws DebugException {
212 this.getPHPDBGProxy().pause();
213 state.setSuspended(true);
214 IThread[] threads = getThreads();
215 for (int i = 0; i < threads.length; ++i)
216 threads[i].suspend();
219 public void breakpointAdded(IBreakpoint breakpoint) {
220 this.getPHPDBGProxy().addBreakpoint(breakpoint);
223 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta arg1) {
224 this.getPHPDBGProxy().removeBreakpoint(breakpoint);
227 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta arg1) {
228 // This method is called whenever a source file has changed in which
230 // we terminate since the source will be out of sync with the debugger
231 // The method will also be called when the user enables/disables
233 // in this case we add or remove the breakpoint
235 // Check if breakpoint state changed from disabled to enabled
236 if (breakpoint.isEnabled()
237 && !arg1.getAttribute("org.eclipse.debug.core.enabled",
239 this.getPHPDBGProxy().addBreakpoint(breakpoint);
240 // Check if breakpoint state changed from enabled to disabled
241 } else if (!breakpoint.isEnabled()
243 .getAttribute("org.eclipse.debug.core.enabled",
245 this.getPHPDBGProxy().removeBreakpoint(breakpoint);
247 // All other cases will terminate the debugger
250 } catch (CoreException e) {
255 public boolean canDisconnect() {
259 public void disconnect() throws DebugException {
262 public boolean isDisconnected() {
266 public boolean supportsStorageRetrieval() {
270 public IMemoryBlock getMemoryBlock(long arg0, long arg1)
271 throws DebugException {
275 public Object getAdapter(Class arg0) {
276 if (IWorkbenchAdapter.class.equals(arg0)) {
277 return new IWorkbenchAdapter() {
278 public Object[] getChildren(Object o) {
279 Object[] children = null;
280 IThread[] threads = getThreads();
281 if (null != threads) {
282 children = new Object[threads.length];
283 for (int i = 0; i < threads.length; ++i)
284 children[i] = threads[i];
289 public ImageDescriptor getImageDescriptor(Object object) {
293 public String getLabel(Object o) {
294 String label = "(Unable to look up name... check error log)";
297 } catch (DebugException x) {
298 PHPeclipsePlugin.log(label, x);
303 public Object getParent(Object o) {
304 return PHPDebugTarget.this.getLaunch();
311 public IProcess getProcess() {
315 public void setProcess(IProcess process) {
316 this.process = process;
319 public PHPDBGProxy getPHPDBGProxy() {
323 public void setPHPDBGProxy(PHPDBGProxy phpDBGProxy) {
324 this.phpDBGProxy = phpDBGProxy;
328 * @see ILaunchListener#launchRemoved(ILaunch)
330 public void launchRemoved(ILaunch launch) {
331 if (!isTerminated()) {
334 if (launch.equals(getLaunch())) {
335 // This target has been deregistered, but it hasn't successfully
337 // Update internal state to reflect that it is disconnected
343 * @see ILaunchListener#launchAdded(ILaunch)
345 public void launchAdded(ILaunch launch) {
349 * @see ILaunchListener#launchChanged(ILaunch)
351 public void launchChanged(ILaunch launch) {
355 * When a debug target or process terminates, terminate DBG Proxy.
357 * @see IDebugEventSetListener#handleDebugEvents(DebugEvent[])
359 public void handleDebugEvents(DebugEvent[] events) {
360 for (int i = 0; i < events.length; i++) {
361 DebugEvent event = events[i];
362 if (event.getKind() == DebugEvent.TERMINATE) {
363 Object source = event.getSource();
364 if (source instanceof PHPDebugTarget
365 || source instanceof IDebugTarget) {
366 getPHPDBGProxy().stop();
367 } else if (source instanceof IProcess) {
368 if (getDebugTarget().getProcess() == (IProcess) source) {
369 getPHPDBGProxy().stop();
372 } else if (event.getKind() == DebugEvent.SUSPEND) {
373 getPHPDBGProxy().pause();