blob: f6033bce95466f07cc84ce99c01e31b6d48dfa87 [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.rhino;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.e4.languages.javascript.debug.DebugRuntime;
import org.eclipse.e4.languages.javascript.debug.connect.DisconnectException;
import org.eclipse.e4.languages.javascript.debug.connect.EventPacket;
import org.eclipse.e4.languages.javascript.debug.connect.Request;
import org.eclipse.e4.languages.javascript.debug.connect.Response;
import org.eclipse.e4.languages.javascript.debug.connect.TimeoutException;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.debug.DebugFrame;
import org.mozilla.javascript.debug.DebuggableScript;
import org.mozilla.javascript.debug.Debugger;
public class RhinoDebugger implements Debugger, ContextFactory.Listener, Runnable {
private final DebugRuntime runtime;
private final RequestHandler requestHandler;
private final Thread requestHandlerThread;
private volatile boolean shutdown = false;
private final Map threadToThreadId = new HashMap();
private final Map threadIdToData = new HashMap();
private final Map scripts = new HashMap();
private final Map debuggableScripts = new HashMap();
private final Map breakpoints = new HashMap();
private long currentThreadId = 0L;
private long currentBreakpointId = 0L;
private long currentScriptId = 0L;
public RhinoDebugger(DebugRuntime runtime) {
this.runtime = runtime;
this.requestHandler = new RequestHandler(this);
this.requestHandlerThread = new Thread(this, "RhinoDebugger - Request Handler");
}
public void start() {
requestHandlerThread.start();
}
public void stop() {
shutdown = true;
try {
requestHandlerThread.interrupt();
requestHandlerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while (!shutdown) {
try {
Request request = runtime.receiveRequest(1000);
Response response = requestHandler.handleRequest(request);
runtime.sendResponse(response);
} catch (TimeoutException e) {
// ignore
} catch (DisconnectException e) {
break;
}
}
}
public DebugFrame getFrame(Context context, DebuggableScript debuggableScript) {
ScriptImpl script = getScript(debuggableScript);
ContextData contextData = (ContextData) context.getDebuggerContextData();
ThreadData thread = (ThreadData) threadIdToData.get(contextData.getThreadId());
return thread.getFrame(context, debuggableScript, script);
}
private ScriptImpl getScript(DebuggableScript debuggableScript) {
while (!debuggableScript.isTopLevel()) {
debuggableScript = debuggableScript.getParent();
}
return (ScriptImpl) debuggableScripts.get(debuggableScript);
}
public void handleCompilationDone(Context context, DebuggableScript debuggableScript, String source) {
if (!debuggableScript.isTopLevel())
return;
Long scriptId = nextScriptId();
ScriptImpl script = new ScriptImpl(scriptId, debuggableScript, source);
scripts.put(scriptId, script);
debuggableScripts.put(debuggableScript, script);
ContextData contextData = (ContextData) context.getDebuggerContextData();
contextData.scriptLoaded(script);
}
private synchronized Long nextScriptId() {
return new Long(currentScriptId++);
}
public synchronized void contextCreated(Context context) {
Thread thread = Thread.currentThread();
Long threadId = (Long) threadToThreadId.get(thread);
if (threadId == null) {
threadId = new Long(currentThreadId++);
threadToThreadId.put(thread, threadId);
}
ThreadData threadData = (ThreadData) threadIdToData.get(threadId);
if (threadData == null) {
threadData = new ThreadData(threadId, this);
threadIdToData.put(threadId, threadData);
}
threadData.contextCreated(context);
}
public synchronized void contextReleased(Context context) {
Thread thread = Thread.currentThread();
Long threadId = (Long) threadToThreadId.get(thread);
if (threadId == null)
return;
ThreadData threadData = (ThreadData) threadIdToData.get(threadId);
threadData.contextReleased(context);
if (!threadData.hasContext()) {
threadToThreadId.remove(thread);
threadIdToData.remove(threadId);
}
}
public synchronized void resume(Long threadId, String stepType) {
ThreadData threadData = (ThreadData) threadIdToData.get(threadId);
threadData.resume(stepType);
}
public synchronized void resumeAll() {
for (Iterator it = threadIdToData.keySet().iterator(); it.hasNext();) {
Long threadId = (Long) it.next();
resume(threadId, null);
}
}
public synchronized void suspend(Long threadId) {
ThreadData threadData = (ThreadData) threadIdToData.get(threadId);
threadData.suspend();
}
public synchronized void suspendAll() {
for (Iterator it = threadIdToData.keySet().iterator(); it.hasNext();) {
Long threadId = (Long) it.next();
suspend(threadId);
}
}
public void disconnect() {
}
public synchronized List getFrameIds(Long threadId) {
ThreadData threadData = (ThreadData) threadIdToData.get(threadId);
return threadData.getFrameIds();
}
public synchronized DebugFrameImpl getFrame(Long threadId, Long frameId) {
ThreadData threadData = (ThreadData) threadIdToData.get(threadId);
return threadData.getFrame(frameId);
}
public synchronized List getScriptIds() {
return new ArrayList(scripts.keySet());
}
public synchronized ScriptImpl getScript(Long scriptId) {
return (ScriptImpl) scripts.get(scriptId);
}
public synchronized Collection getBreakpoints() {
return new ArrayList(breakpoints.keySet());
}
public synchronized BreakpointImpl setBreakpoint(Long scriptId, Integer lineNumber, String functionName, String condition, Long threadId) {
ScriptImpl script = (ScriptImpl) scripts.get(scriptId);
if (!script.isValid(lineNumber, functionName))
return null;
BreakpointImpl breakpoint = new BreakpointImpl(nextBreakpointId(), script, lineNumber, functionName, condition, threadId);
breakpoints.put(breakpoint.getId(), breakpoint);
script.addBreakpoint(breakpoint);
return breakpoint;
}
private synchronized Long nextBreakpointId() {
return new Long(currentBreakpointId++);
}
public synchronized BreakpointImpl clearBreakpoint(Long breakpointId) {
BreakpointImpl breakpoint = (BreakpointImpl) breakpoints.remove(breakpointId);
if (breakpoint != null) {
ScriptImpl script = breakpoint.getScript();
script.removeBreakpoint(breakpoint);
}
return breakpoint;
}
public void sendEvent(EventPacket event) {
try {
runtime.sendEvent(event);
} catch (DisconnectException e) {
// ignore
e.printStackTrace(); // for now for debugging purposes
}
}
public BreakpointImpl getBreakpoint(Long breakpointId) {
return (BreakpointImpl) breakpoints.get(breakpointId);
}
public ThreadData getThreadData(Long threadId) {
return (ThreadData) threadIdToData.get(threadId);
}
public List getThreadIds() {
return new ArrayList(threadIdToData.keySet());
}
}