/** * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ /* * Author: atotic * Created on Apr 22, 2004 */ package org.python.pydev.debug.model; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.PlatformObject; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IRegisterGroup; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; import org.eclipse.debug.core.model.IVariable; import org.eclipse.ui.views.properties.IPropertySource; import org.eclipse.ui.views.tasklist.ITaskListResourceAdapter; import org.python.pydev.core.IPyStackFrame; import org.python.pydev.debug.model.remote.AbstractDebuggerCommand; import org.python.pydev.debug.model.remote.AbstractRemoteDebugger; import org.python.pydev.debug.model.remote.GetFileContentsCommand; import org.python.pydev.debug.model.remote.GetFrameCommand; import org.python.pydev.debug.model.remote.GetVariableCommand; import org.python.pydev.debug.model.remote.ICommandResponseListener; import org.python.pydev.editorinput.PySourceLocatorPrefs; import org.python.pydev.shared_core.string.StringUtils; /** * Represents a stack entry. * * Needs to integrate with the source locator */ public class PyStackFrame extends PlatformObject implements IStackFrame, IVariableLocator, IPyStackFrame, IVariablesContainerParent { private String name; private PyThread thread; private String id; private IPath path; private int line; private final ContainerOfVariables variableContainer = new ContainerOfVariables(this, true); private IVariableLocator localsLocator; private IVariableLocator globalsLocator; private IVariableLocator frameLocator; private IVariableLocator expressionLocator; private AbstractDebugTarget target; public PyStackFrame(PyThread in_thread, String in_id, String name, IPath file, int line, AbstractDebugTarget target) { this.id = in_id; this.name = name; this.path = file; this.line = line; this.thread = in_thread; localsLocator = new IVariableLocator() { @Override public String getPyDBLocation() { return thread.getId() + "\t" + id + "\tLOCAL"; } @Override public String getThreadId() { return thread.getId(); } }; frameLocator = new IVariableLocator() { @Override public String getPyDBLocation() { return thread.getId() + "\t" + id + "\tFRAME"; } @Override public String getThreadId() { return thread.getId(); } }; globalsLocator = new IVariableLocator() { @Override public String getPyDBLocation() { return thread.getId() + "\t" + id + "\tGLOBAL"; } @Override public String getThreadId() { return thread.getId(); } }; expressionLocator = new IVariableLocator() { @Override public String getPyDBLocation() { return thread.getId() + "\t" + id + "\tEXPRESSION"; } @Override public String getThreadId() { return thread.getId(); } }; this.target = target; } @Override public AbstractDebugTarget getTarget() { return target; } public String getId() { return id; } @Override public String getThreadId() { return this.thread.getId(); } public IVariableLocator getLocalsLocator() { return localsLocator; } public IVariableLocator getFrameLocator() { return frameLocator; } @Override public IVariableLocator getGlobalLocator() { return globalsLocator; } public IVariableLocator getExpressionLocator() { return expressionLocator; } public void setName(String name) { this.name = name; } public void setPath(IPath path) { this.path = path; } public void setLine(int line) { this.line = line; } public IPath getPath() { return path; } @Override public IThread getThread() { return thread; } @Override public IVariable[] getVariables() throws DebugException { return variableContainer.getVariables(); } public void forceGetNewVariables() { variableContainer.forceGetNewVariables(); } @Override public boolean hasVariables() throws DebugException { return true; } /** * Note: line 1-based. */ @Override public int getLineNumber() throws DebugException { return line; } @Override public int getCharStart() throws DebugException { return -1; } @Override public int getCharEnd() throws DebugException { return -1; } private boolean currentStackFrame = false; public void setCurrentStackFrame() { this.currentStackFrame = true; } @Override public String getName() throws DebugException { String ret = StringUtils.join("", name, " [", path.lastSegment(), ":", Integer.toString(line), "]"); if (currentStackFrame) { ret += " <-- Current frame"; } return ret; } @Override public IRegisterGroup[] getRegisterGroups() throws DebugException { return new IRegisterGroup[0]; } @Override public boolean hasRegisterGroups() throws DebugException { return false; } @Override public String getModelIdentifier() { return thread.getModelIdentifier(); } @Override public IDebugTarget getDebugTarget() { return thread.getDebugTarget(); } @Override public ILaunch getLaunch() { return thread.getLaunch(); } @Override public boolean canStepInto() { return thread.canStepInto(); } @Override public boolean canStepOver() { return thread.canStepOver(); } @Override public boolean canStepReturn() { return thread.canStepReturn(); } @Override public boolean isStepping() { return thread.isStepping(); } @Override public void stepInto() throws DebugException { thread.stepInto(); } @Override public void stepOver() throws DebugException { thread.stepOver(); } @Override public void stepReturn() throws DebugException { thread.stepReturn(); } @Override public boolean canResume() { return thread.canResume(); } @Override public boolean canSuspend() { return thread.canSuspend(); } @Override public boolean isSuspended() { return thread.isSuspended(); } @Override public void resume() throws DebugException { thread.resume(); } @Override public void suspend() throws DebugException { thread.suspend(); } @Override public boolean canTerminate() { return thread.canTerminate(); } @Override public boolean isTerminated() { return thread.isTerminated(); } @Override public void terminate() throws DebugException { thread.terminate(); } @SuppressWarnings("unchecked") @Override public <T> T getAdapter(Class<T> adapter) { AdapterDebug.print(this, adapter); if (adapter.equals(ILaunch.class) || adapter.equals(IResource.class)) { return thread.getAdapter(adapter); } if (adapter.equals(ITaskListResourceAdapter.class)) { return null; } if (adapter.equals(IDebugTarget.class)) { return (T) thread.getDebugTarget(); } if (adapter.equals(org.eclipse.debug.ui.actions.IRunToLineTarget.class)) { return (T) this.target.getRunToLineTarget(); } if (adapter.equals(IPropertySource.class) || adapter.equals(ITaskListResourceAdapter.class) || adapter.equals(org.eclipse.debug.ui.actions.IToggleBreakpointsTarget.class)) { return super.getAdapter(adapter); } AdapterDebug.printDontKnow(this, adapter); // ongoing, I do not fully understand all the interfaces they'd like me to support return super.getAdapter(adapter); } /** * fixed - this was bug http://sourceforge.net/tracker/index.php?func=detail&aid=1174821&group_id=85796&atid=577329 * in the forum (unable to get stack correctly when recursing) */ @Override public int hashCode() { return id.hashCode(); } /** * fixed - this was bug http://sourceforge.net/tracker/index.php?func=detail&aid=1174821&group_id=85796&atid=577329 * in the forum (unable to get stack correctly when recursing) */ @Override public boolean equals(Object obj) { if (obj instanceof PyStackFrame) { PyStackFrame sf = (PyStackFrame) obj; return this.id.equals(sf.id) && this.path.toString().equals(sf.path.toString()) && this.line == sf.line && this.getThreadId().equals(sf.getThreadId()); } return false; } public GetVariableCommand getFrameCommand(AbstractDebugTarget dbg) { return new GetFrameCommand(dbg, frameLocator.getPyDBLocation()); } @Override public GetVariableCommand getVariableCommand(AbstractDebugTarget target) { return getFrameCommand(target); } @Override public String getPyDBLocation() { return this.frameLocator.getPyDBLocation(); } public AbstractRemoteDebugger getDebugger() { return target.getDebugger(); } @Override public String toString() { return "PyStackFrame: " + this.id; } private String fileContents = null; @Override public String getFileContents() { if (fileContents == null) { // send the command, and then busy-wait GetFileContentsCommand cmd = new GetFileContentsCommand(target, this.path.toOSString()); final Object lock = new Object(); final String[] response = new String[1]; cmd.setCompletionListener(new ICommandResponseListener() { @Override public void commandComplete(AbstractDebuggerCommand cmd) { try { response[0] = ((GetFileContentsCommand) cmd).getResponse(); } catch (CoreException e) { response[0] = ""; } try { synchronized (lock) { lock.notify(); } } catch (Exception e) { //ignore } } }); target.postCommand(cmd); int timeout = PySourceLocatorPrefs.getFileContentsTimeout(); long initialTimeMillis = System.currentTimeMillis(); while (response[0] == null) { synchronized (lock) { try { lock.wait(50); } catch (Exception e) { //ignore } } if (System.currentTimeMillis() - initialTimeMillis > timeout) { break; } } fileContents = response[0]; } return fileContents; } }