| /******************************************************************************* |
| * 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 |
| *******************************************************************************/ |
| package org.eclipse.e4.languages.javascript.debug.model; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.debug.core.DebugEvent; |
| import org.eclipse.debug.core.DebugException; |
| import org.eclipse.debug.core.model.IBreakpoint; |
| import org.eclipse.debug.core.model.IStackFrame; |
| import org.eclipse.debug.core.model.IThread; |
| import org.eclipse.e4.languages.javascript.jsdi.StackFrame; |
| import org.eclipse.e4.languages.javascript.jsdi.ThreadReference; |
| import org.eclipse.e4.languages.javascript.jsdi.event.Event; |
| import org.eclipse.e4.languages.javascript.jsdi.event.EventSet; |
| import org.eclipse.e4.languages.javascript.jsdi.event.StepEvent; |
| import org.eclipse.e4.languages.javascript.jsdi.request.EventRequestManager; |
| import org.eclipse.e4.languages.javascript.jsdi.request.StepRequest; |
| |
| /** |
| * A JSDI thread |
| * |
| * @since 1.0 |
| */ |
| public class JSDIThread extends JSDIDebugElement implements IThread, IJSDIEventListener { |
| |
| // states |
| private static final int UNKNOWN = 0; |
| private static final int SUSPENDED = 1; |
| private static final int RUNNING = 2; |
| private static final int STEPPING = 3; |
| private static final int TERMINATED = 4; |
| |
| /** |
| * Stack frames, or <code>null</code> if none. |
| */ |
| private List frames = null; |
| |
| /** |
| * The name for the thread. |
| */ |
| private final String name; |
| |
| /** |
| * Current state |
| */ |
| private int state = UNKNOWN; |
| |
| /** |
| * The underlying {@link ThreadReference} for this thread |
| */ |
| private final ThreadReference thread; |
| |
| /** |
| * Constructor |
| * |
| * @param target |
| * the target the thread belongs to |
| * @param thread |
| * the underlying {@link ThreadReference} |
| */ |
| public JSDIThread(JSDIDebugTarget target, ThreadReference thread) { |
| super(target); |
| this.thread = thread; |
| this.name = thread.name(); |
| this.state = thread.isSuspended() ? SUSPENDED : RUNNING; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IThread#getBreakpoints() |
| */ |
| public IBreakpoint[] getBreakpoints() { |
| return new IBreakpoint[0]; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IThread#getName() |
| */ |
| public String getName() throws DebugException { |
| return name; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IThread#getPriority() |
| */ |
| public int getPriority() throws DebugException { |
| return 0; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IThread#getStackFrames() |
| */ |
| public IStackFrame[] getStackFrames() throws DebugException { |
| if (frames == null) { |
| frames = new ArrayList(); |
| |
| List threadFrames = thread.frames(); |
| for (Iterator iterator = threadFrames.iterator(); iterator.hasNext();) { |
| StackFrame stackFrame = (StackFrame) iterator.next(); |
| JSDIStackFrame jsdiStackFrame = createJSDIStackFrame(stackFrame); |
| frames.add(jsdiStackFrame); |
| } |
| } |
| return (IStackFrame[]) frames.toArray(new IStackFrame[this.frames.size()]); |
| } |
| |
| private JSDIStackFrame createJSDIStackFrame(StackFrame stackFrame) { |
| return new JSDIStackFrame(this, stackFrame); |
| } |
| |
| /** |
| * Clears out old stack frames after resuming. |
| */ |
| private synchronized void clearFrames() { |
| if (frames != null) { |
| frames.clear(); |
| frames = null; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IThread#getTopStackFrame() |
| */ |
| public IStackFrame getTopStackFrame() throws DebugException { |
| IStackFrame[] stackFrames = getStackFrames(); |
| if (stackFrames != null && stackFrames.length > 0) { |
| return stackFrames[0]; |
| } |
| return null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IThread#hasStackFrames() |
| */ |
| public boolean hasStackFrames() throws DebugException { |
| return isSuspended(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.ISuspendResume#canResume() |
| */ |
| public synchronized boolean canResume() { |
| return state == SUSPENDED; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend() |
| */ |
| public synchronized boolean canSuspend() { |
| return state == RUNNING; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended() |
| */ |
| public synchronized boolean isSuspended() { |
| return state == SUSPENDED; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.ISuspendResume#resume() |
| */ |
| public synchronized void resume() throws DebugException { |
| if (canResume()) { |
| thread.resume(); |
| state = RUNNING; |
| clearFrames(); |
| fireResumeEvent(DebugEvent.CLIENT_REQUEST); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.ISuspendResume#suspend() |
| */ |
| public synchronized void suspend() throws DebugException { |
| if (canSuspend()) { |
| thread.suspend(); |
| state = SUSPENDED; |
| clearFrames(); |
| fireSuspendEvent(DebugEvent.CLIENT_REQUEST); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IStep#canStepInto() |
| */ |
| public boolean canStepInto() { |
| return isSuspended(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IStep#canStepOver() |
| */ |
| public boolean canStepOver() { |
| return isSuspended(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IStep#canStepReturn() |
| */ |
| public boolean canStepReturn() { |
| return isSuspended(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IStep#isStepping() |
| */ |
| public synchronized boolean isStepping() { |
| return this.state == STEPPING; |
| } |
| |
| /** |
| * Sends a step request and fires a step event if successful. |
| * |
| * @param stepAction |
| * step command to send |
| * @param eventDetail |
| * debug event detail to fire |
| * @throws DebugException |
| * if request is not successful |
| */ |
| private synchronized void step(int step) throws DebugException { |
| if (canResume()) { |
| EventRequestManager requestManager = thread.virtualMachine().eventRequestManager(); |
| StepRequest stepRequest = requestManager.createStepRequest(thread, step); |
| stepRequest.setEnabled(true); |
| getJSDITarget().addJSDIEventListener(this, stepRequest); |
| thread.resume(); |
| this.state = STEPPING; |
| clearFrames(); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IStep#stepInto() |
| */ |
| public void stepInto() throws DebugException { |
| step(StepRequest.STEP_INTO); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IStep#stepOver() |
| */ |
| public void stepOver() throws DebugException { |
| step(StepRequest.STEP_OVER); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.IStep#stepReturn() |
| */ |
| public void stepReturn() throws DebugException { |
| step(StepRequest.STEP_OUT); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.ITerminate#canTerminate() |
| */ |
| public boolean canTerminate() { |
| return false; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.ITerminate#isTerminated() |
| */ |
| public synchronized boolean isTerminated() { |
| return state == TERMINATED; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.core.model.ITerminate#terminate() |
| */ |
| public void terminate() throws DebugException { |
| notSupported("Unsupported Operation", null); |
| } |
| |
| public boolean matches(ThreadReference thread) { |
| return this.thread == thread; |
| } |
| |
| public void eventSetComplete(Event event, JSDIDebugTarget target, boolean suspend, EventSet eventSet) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public synchronized boolean handleEvent(Event event, JSDIDebugTarget target, boolean suspendVote, EventSet eventSet) { |
| if (event instanceof StepEvent) { |
| return false; |
| } |
| |
| return false; |
| } |
| } |