blob: 27c83f21a547eb61dee79d99ab4f933504f01873 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}