/*******************************************************************************
* Copyright (c) 2014 Zend Technologies and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Zend Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.php.internal.debug.core.zend.model;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.*;
import org.eclipse.debug.core.model.*;
import org.eclipse.php.internal.debug.core.IPHPDebugConstants;
import org.eclipse.php.internal.debug.core.Logger;
import org.eclipse.php.internal.debug.core.launching.PHPProcess;
import org.eclipse.php.internal.debug.core.model.DebugOutput;
import org.eclipse.php.internal.debug.core.model.IPHPDebugTarget;
import org.eclipse.php.internal.debug.core.model.PHPDebugElement;
/**
* This class is a wrapper for multiple debug targets that might be considered
* as running in parallel in context of a particular debug session. This wrapper
* pretends to be a multi-threaded element in debug model.
*
* @author Bartlomiej Laczkowski
*/
public class PHPMultiDebugTarget extends PHPDebugElement implements IPHPDebugTarget, IDebugEventSetListener {
private ILaunch fLaunch;
private IProcess fProcess;
private boolean fTerminated = false;
protected DebugOutput fDebugOutput = new DebugOutput();
protected CopyOnWriteArrayList<IPHPDebugTarget> fDebugTargets = new CopyOnWriteArrayList<IPHPDebugTarget>();
/**
* Creates new multiple debug targets wrapper.
*
* @param launch
* @param process
* @throws CoreException
*/
public PHPMultiDebugTarget(ILaunch launch, IProcess process) throws CoreException {
super(null);
fLaunch = launch;
fProcess = process;
fProcess.setAttribute(IProcess.ATTR_PROCESS_TYPE, IPHPDebugConstants.PHPProcessType);
if (fProcess instanceof PHPProcess) {
((PHPProcess) fProcess).setDebugTarget(this);
}
fireCreationEvent();
DebugPlugin.getDefault().addDebugEventListener(this);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.DebugElement#getDebugTarget()
*/
public IDebugTarget getDebugTarget() {
return this;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.debug.core.model.PHPDebugElement#getLaunch()
*/
@Override
public ILaunch getLaunch() {
return fLaunch;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#getProcess()
*/
@Override
public IProcess getProcess() {
return fProcess;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#getThreads()
*/
@Override
public IThread[] getThreads() throws DebugException {
// Collect threads from all sub-targets
List<IThread> threads = new ArrayList<IThread>();
for (IPHPDebugTarget target : fDebugTargets)
if (target.hasThreads())
for (IThread thread : target.getThreads())
threads.add(thread);
return threads.toArray(new IThread[threads.size()]);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#hasThreads()
*/
@Override
public boolean hasThreads() throws DebugException {
// Check if any sub-target has at least one thread
for (IPHPDebugTarget target : fDebugTargets)
if (target.hasThreads())
return true;
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#getName()
*/
@Override
public String getName() throws DebugException {
return null;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse
* .debug.core.model.IBreakpoint)
*/
@Override
public boolean supportsBreakpoint(IBreakpoint breakpoint) {
boolean supports = false;
// Supports if any of sub-targets supports
if (breakpoint.getModelIdentifier().equals(IPHPDebugConstants.ID_PHP_DEBUG_CORE)) {
for (IPHPDebugTarget target : fDebugTargets)
if (target.supportsBreakpoint(breakpoint))
supports = true;
}
return supports;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ITerminate#canTerminate()
*/
@Override
public boolean canTerminate() {
return !isTerminated();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ITerminate#isTerminated()
*/
@Override
public boolean isTerminated() {
return fTerminated;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ITerminate#terminate()
*/
@Override
public synchronized void terminate() throws DebugException {
if (!fTerminated)
for (IPHPDebugTarget target : fDebugTargets)
target.terminate();
DebugPlugin.getDefault().removeDebugEventListener(this);
fireTerminateEvent();
fTerminated = true;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#canResume()
*/
@Override
public boolean canResume() {
for (IPHPDebugTarget target : fDebugTargets)
if (target.canResume())
return true;
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
*/
@Override
public boolean canSuspend() {
for (IPHPDebugTarget target : fDebugTargets)
if (target.canSuspend())
return true;
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
*/
@Override
public boolean isSuspended() {
for (IPHPDebugTarget target : fDebugTargets)
if (target.isSuspended())
return true;
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#resume()
*/
@Override
public void resume() throws DebugException {
for (IPHPDebugTarget target : fDebugTargets)
if (target.canResume())
target.resume();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#suspend()
*/
@Override
public void suspend() throws DebugException {
for (IPHPDebugTarget target : fDebugTargets)
if (target.canSuspend())
target.suspend();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse
* .debug.core.model.IBreakpoint)
*/
@Override
public void breakpointAdded(IBreakpoint breakpoint) {
for (IPHPDebugTarget target : fDebugTargets)
target.breakpointAdded(breakpoint);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse
* .debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
*/
@Override
public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
for (IPHPDebugTarget target : fDebugTargets)
target.breakpointRemoved(breakpoint, delta);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse
* .debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
*/
@Override
public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
for (IPHPDebugTarget target : fDebugTargets)
target.breakpointChanged(breakpoint, delta);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
*/
@Override
public boolean canDisconnect() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDisconnect#disconnect()
*/
@Override
public void disconnect() throws DebugException {
// ignore
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDisconnect#isDisconnected()
*/
@Override
public boolean isDisconnected() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#
* supportsStorageRetrieval ()
*/
@Override
public boolean supportsStorageRetrieval() {
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long,
* long)
*/
@Override
public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
return null;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.debug.core.model.IPHPDebugTarget#getOutputBuffer
* ()
*/
@Override
public DebugOutput getOutputBuffer() {
return fDebugOutput;
}
/**
* always return false, this concept is xdebug specific.
*/
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.debug.core.model.IPHPDebugTarget#isWaiting()
*/
@Override
public boolean isWaiting() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.
* eclipse .debug.core.DebugEvent[])
*/
@Override
public void handleDebugEvents(DebugEvent[] events) {
for (int i = 0; i < events.length; i++) {
DebugEvent event = events[i];
Object source = event.getSource();
if (event.getKind() == DebugEvent.TERMINATE) {
if (source instanceof PHPDebugTarget) {
PHPDebugTarget target = (PHPDebugTarget) source;
if (fDebugTargets.contains(target))
shutdown();
}
}
}
}
/**
* Adds sub-target to this debug target.
*
* @param target
*/
public void addSubTarget(IPHPDebugTarget target) {
fDebugTargets.add(target);
}
private void shutdown() {
// Check if all sub-targets are terminated
for (IPHPDebugTarget target : fDebugTargets)
if (!target.isTerminated())
return;
try {
terminate();
} catch (DebugException e) {
Logger.logException(e);
}
}
}