/*******************************************************************************
* Copyright (c) 2009 IBM Corporation 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:
* IBM Corporation - initial API and implementation
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.debug.core.zend.model;
import java.util.ArrayList;
import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.core.model.IVariable;
import org.eclipse.php.internal.debug.core.pathmapper.VirtualPath;
import org.eclipse.php.internal.debug.core.zend.debugger.*;
import org.eclipse.php.internal.debug.core.zend.model.ResolveBlackList.Type;
public class ContextManager {
private PHPDebugTarget fTarget;
private IRemoteDebugger fDebugger;
private IStackFrame[] fFrames;
private ILock fFramesInitLock = Job.getJobManager().newLock();
private int fSuspendCount;
private final static String DUMMY_PHP_FILE = "dummy.php"; //$NON-NLS-1$
public ContextManager(PHPDebugTarget target, IRemoteDebugger debugger) {
super();
fTarget = target;
fSuspendCount = target.getSuspendCount();
fDebugger = debugger;
}
public void addToResolveBlacklist(VirtualPath path, Type type) {
ResolveBlackList.getInstance().add(fDebugger.getDebugHandler().getDebugTarget().getLaunch(), path, type);
}
public boolean isResolveBlacklisted(String remoteFile) {
return ResolveBlackList.getInstance().containsEntry(fDebugger.getDebugHandler().getDebugTarget().getLaunch(),
remoteFile);
}
public IStackFrame[] getStackFrames() throws DebugException {
fFramesInitLock.acquire();
try {
if (fSuspendCount == fTarget.getSuspendCount()) {
return fFrames;
}
// check to see if eclipse is getting the same stack frames again.
PHPstack stack = fDebugger.getCallStack();
if (stack != null) {
StackLayer[] layers = stack.getLayers();
if (layers.length == 1 && layers[0].getCalledFileName().endsWith(DUMMY_PHP_FILE)) {
fDebugger.finish();// reached dummy file --> finish debug !
return fFrames;
}
IThread[] threads = fTarget.getThreads();
if (threads == null || threads.length == 0) {
// Connection was probably dumped
fFrames = new IStackFrame[0];
return fFrames;
}
PHPThread thread = (PHPThread) threads[0];
IStackFrame[] newFrames = applyDebugFilters(createNewFrames(layers, thread));
fFrames = newFrames;
} else {
// Connection was probably dumped
fFrames = new IStackFrame[0];
}
fSuspendCount = fTarget.getSuspendCount();
return fFrames;
} finally {
fFramesInitLock.release();
}
}
private IStackFrame[] applyDebugFilters(IStackFrame[] previousFrames) {
ArrayList<IStackFrame> tempStackFrames = new ArrayList<IStackFrame>();
for (int i = 0; i < previousFrames.length; i++) {
if (i == previousFrames.length - 1) {
String stackFrameName = ((PHPStackFrame) previousFrames[i]).getAbsoluteFileName();
if (stackFrameName.endsWith(DUMMY_PHP_FILE)) {
continue;// do not add it to stack view, filter it out.
}
}
tempStackFrames.add(previousFrames[i]);
}
IStackFrame[] result = new IStackFrame[tempStackFrames.size()];
tempStackFrames.toArray(result);
return result;
}
public IVariable[] getVariables(PHPStackFrame stackFrame) {
if (stackFrame == null) {
return createVariables();
}
IVariable[] variables = null;
try {
variables = stackFrame.getVariables();
} catch (DebugException e) {
}
return variables == null ? new IVariable[0] : variables;
}
private IStackFrame[] createNewFrames(StackLayer[] layers, PHPThread thread) throws DebugException {
RemoteDebugger remoteDebugger = (RemoteDebugger) fDebugger;
String cwd = null;
String currentScript = null;
IStackFrame[] frames = new IStackFrame[layers.length];
int frameCt = layers.length;
for (int i = 1; i < layers.length; i++) {
String sName = layers[i].getCallerFileName();
String rName = layers[i].getResolvedCallerFileName();
if (rName == null) {
rName = remoteDebugger.convertToLocalFilename(sName, cwd,
frameCt < frames.length ? ((PHPStackFrame) frames[frameCt]).getSourceName() : null);
if (rName == null) {
rName = sName;
}
layers[i].setResolvedCallerFileName(rName);
}
frames[frameCt - 1] = new PHPStackFrame(thread, sName, rName, layers[i].getCallerFunctionName(),
layers[i].getCallerLineNumber() + 1, layers[i].getDepth(), layers[i - 1].getVariables());
frameCt--;
if (!layers[i].getCalledFileName().equals(fTarget.getLastFileName())) {
currentScript = rName;
}
}
String resolvedFile = remoteDebugger.convertToLocalFilename(fTarget.getLastFileName(), cwd, currentScript);
if (resolvedFile == null) {
resolvedFile = fTarget.getLastFileName();
}
PHPStackFrame topFrame = new PHPStackFrame(thread, fTarget.getLastFileName(), resolvedFile,
(layers.length == 1) ? "" //$NON-NLS-1$
: layers[layers.length - 1].getCalledFunctionName(),
fTarget.getLastStop(), frameCt, getLocalVariables());
if (fFrames != null)
frames[0] = mergeFrame((PHPStackFrame) fFrames[0], topFrame);
else
frames[0] = topFrame;
return frames;
}
/**
* Merge existing top frame with the incoming one. If both frames have only
* different line number then existing is being updated with the use of data
* from incoming one.
*
* @param existingFrame
* @param incomingFrame
* @return merged frame
* @throws DebugException
*/
private IStackFrame mergeFrame(PHPStackFrame existingFrame, PHPStackFrame incomingFrame) throws DebugException {
if (existingFrame.getName().equals(incomingFrame.getName())
&& existingFrame.getAbsoluteFileName().equals(incomingFrame.getAbsoluteFileName())
&& existingFrame.getSourceName().equals(incomingFrame.getSourceName())
&& existingFrame.getThread() == incomingFrame.getThread()
&& existingFrame.getDepth() == incomingFrame.getDepth()) {
existingFrame.update(incomingFrame.getLineNumber(), incomingFrame.getStackVariables());
return existingFrame;
}
return incomingFrame;
}
private Expression[] getLocalVariables() {
DefaultExpressionsManager expressionsManager = fTarget.getExpressionManager();
if (expressionsManager == null) {
return new Expression[0];
}
return expressionsManager.getCurrentVariables(1);
}
private IVariable[] createVariables() {
Expression[] localVariables = getLocalVariables();
IVariable[] variables = new PHPVariable[localVariables.length];
for (int i = 0; i < localVariables.length; i++) {
variables[i] = new PHPVariable(fTarget, localVariables[i]);
}
return variables;
}
public IRemoteDebugger getRemoteDebugger() {
return fDebugger;
}
}