blob: f1ade3170d1b8dd2259f86af5a92deb0168e96c6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 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.wst.jsdt.debug.internal.core.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IBreakpointManager;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchListener;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptBreakpoint;
import org.eclipse.wst.jsdt.debug.core.jsdi.ScriptReference;
import org.eclipse.wst.jsdt.debug.core.jsdi.ThreadReference;
import org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine;
import org.eclipse.wst.jsdt.debug.core.jsdi.event.DebuggerStatementEvent;
import org.eclipse.wst.jsdt.debug.core.jsdi.event.Event;
import org.eclipse.wst.jsdt.debug.core.jsdi.event.EventSet;
import org.eclipse.wst.jsdt.debug.core.jsdi.event.ScriptLoadEvent;
import org.eclipse.wst.jsdt.debug.core.jsdi.event.ThreadEnterEvent;
import org.eclipse.wst.jsdt.debug.core.jsdi.event.ThreadExitEvent;
import org.eclipse.wst.jsdt.debug.core.jsdi.event.VMDeathEvent;
import org.eclipse.wst.jsdt.debug.core.jsdi.event.VMDisconnectEvent;
import org.eclipse.wst.jsdt.debug.core.jsdi.request.DebuggerStatementRequest;
import org.eclipse.wst.jsdt.debug.core.jsdi.request.ScriptLoadRequest;
import org.eclipse.wst.jsdt.debug.core.jsdi.request.ThreadEnterRequest;
import org.eclipse.wst.jsdt.debug.core.jsdi.request.ThreadExitRequest;
import org.eclipse.wst.jsdt.debug.core.model.IJavaScriptDebugTarget;
import org.eclipse.wst.jsdt.debug.core.model.IScript;
import org.eclipse.wst.jsdt.debug.core.model.IScriptGroup;
import org.eclipse.wst.jsdt.debug.core.model.JavaScriptDebugModel;
import org.eclipse.wst.jsdt.debug.internal.core.JavaScriptDebugPlugin;
import org.eclipse.wst.jsdt.debug.internal.core.JavaScriptPreferencesManager;
import org.eclipse.wst.jsdt.debug.internal.core.breakpoints.JavaScriptBreakpoint;
/**
* JavaScript debug target
*
* @since 1.0
*/
public class JavaScriptDebugTarget extends JavaScriptDebugElement implements IJavaScriptDebugTarget, IDebugEventSetListener, ILaunchListener, IJavaScriptEventListener {
static final String DEFAULT_NAME = ModelMessages.JSDIDebugTarget_jsdi_debug_target;
/**
* The cached collection of scripts, sorted by name
*/
private ArrayList iScriptCache = null;
private final IProcess process;
private final VirtualMachine vm;
private final ILaunch launch;
private final boolean supportsTerminate;
private final boolean supportsDisconnect;
private final String name;
private final EventDispatcher eventDispatcher;
private ArrayList threads = new ArrayList();
private ArrayList breakpoints = new ArrayList();
private IScriptGroup scriptgroup = null;
private boolean disconnected = false;
private boolean terminating = false;
private boolean terminated = false;
private boolean suspended = false;
private ThreadEnterRequest threadEnterRequest;
private ThreadExitRequest threadExitRequest;
private ScriptLoadRequest scriptLoadrequest;
private DebuggerStatementRequest debuggerStatementRequest;
/**
* Constructor
*
* @param vm
* @param process
* @param launch
* @param name
* @param supportsTerminate
* @param supportsDisconnect
*/
public JavaScriptDebugTarget(VirtualMachine vm, IProcess process, ILaunch launch,
String name, boolean supportsTerminate, boolean supportsDisconnect) {
super(null);
this.vm = vm;
this.process = process;
this.launch = launch;
this.supportsTerminate = supportsTerminate;
this.supportsDisconnect = supportsDisconnect;
if (name != null) {
this.name = name;
} else if (vm.name() != null) {
this.name = vm.name();
} else {
this.name = DEFAULT_NAME;
}
this.eventDispatcher = new EventDispatcher(this);
this.scriptgroup = new ScriptGroup(this);
// TODO: consider calling this outside of constructor
initialize();
}
/**
* Initialize any threads and breakpoints existing at the time this target
* has been created
*/
public synchronized void initialize() {
// perform initializations
initializeThreads();
initializeBreakpoints();
//register listening for script load request
scriptLoadrequest = getEventRequestManager().createScriptLoadRequest();
scriptLoadrequest.setEnabled(true);
addJSDIEventListener(this, scriptLoadrequest);
getLaunch().addDebugTarget(this);
DebugPlugin plugin = DebugPlugin.getDefault();
plugin.addDebugEventListener(this);
plugin.getLaunchManager().addLaunchListener(this);
fireCreationEvent();
// begin handling/dispatching events after the creation event is handled
// by all listeners
plugin.asyncExec(new Runnable() {
public void run() {
Thread t = new Thread(eventDispatcher, "JavaScriptDebugModel.EventDispatcher"); //$NON-NLS-1$
t.setDaemon(true);
t.start();
}
});
}
/**
* Shuts down the target
*/
public synchronized void shutdown() {
try {
if (supportsTerminate) {
terminate();
} else if (supportsDisconnect) {
disconnect();
}
} catch (DebugException e) {
JavaScriptDebugPlugin.log(e);
} finally {
cleanup();
fireTerminateEvent();
}
}
/**
* Cleans up the state of the target
*/
void cleanup() {
DebugPlugin plugin = DebugPlugin.getDefault();
plugin.getLaunchManager().removeLaunchListener(this);
plugin.removeDebugEventListener(this);
getEventDispatcher().shutdown();
removeAllThreads();
removeAllBreakpoints();
removeJSDIEventListener(this, scriptLoadrequest);
this.scriptgroup = null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.DebugElement#getDebugTarget()
*/
public IDebugTarget getDebugTarget() {
return this;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.DebugElement#getLaunch()
*/
public ILaunch getLaunch() {
return launch;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#getName()
*/
public String getName() throws DebugException {
return name;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#getProcess()
*/
public IProcess getProcess() {
return process;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ITerminate#canTerminate()
*/
public boolean canTerminate() {
return supportsTerminate && isAvailable();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ITerminate#isTerminated()
*/
public boolean isTerminated() {
return terminated;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
*/
public boolean canDisconnect() {
return supportsDisconnect && isAvailable();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDisconnect#isDisconnected()
*/
public boolean isDisconnected() {
return disconnected;
}
/**
* Returns the collection of underlying {@link ScriptReference}s
* whose name matches the given name
* @param name
* @return the complete list of {@link ScriptReference}s matching the given name
* or an empty collection, never <code>null</code>
*/
public synchronized List underlyingScripts(String name) {
List scripts = getVM().allScripts();
if(!scripts.isEmpty()) {
List byname = new ArrayList();
ScriptReference script = null;
for (Iterator iter = scripts.iterator(); iter.hasNext();) {
script = (ScriptReference) iter.next();
if (Script.resolveName(script.sourceURI()).equals(name)) {
byname.add(script);
}
}
return byname;
}
return Collections.EMPTY_LIST;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.model.IJavaScriptDebugTarget#allScriptsByName(java.lang.String)
*/
public synchronized List allScriptsByName(String name) {
List scripts = allScripts();
if(scripts.size() > 0) {
List byname = new ArrayList();
IScript script = null;
for (Iterator iter = scripts.iterator(); iter.hasNext();) {
script = (IScript) iter.next();
if (Script.resolveName(script.sourceURI()).equals(name)) {
byname.add(script);
}
}
return byname;
}
return Collections.EMPTY_LIST;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.model.IJavaScriptDebugTarget#allScripts()
*/
public synchronized List allScripts() {
if(iScriptCache == null) {
ArrayList all = (ArrayList) getVM().allScripts();
if(all.size() > 0) {
iScriptCache = new ArrayList(all.size());
for (int i = 0; i < all.size(); i++) {
iScriptCache.add(new Script(this, (ScriptReference) all.get(i)));
}
Collections.sort(iScriptCache);
}
}
if(iScriptCache == null) {
return Collections.EMPTY_LIST;
}
return iScriptCache;
}
/**
* Collects all of the current threads from the {@link VirtualMachine} and
* adds them to the cached list
*/
private synchronized void initializeThreads() {
threadEnterRequest = vm.eventRequestManager().createThreadEnterRequest();
threadEnterRequest.setEnabled(true);
eventDispatcher.addEventListener(this, threadEnterRequest);
threadExitRequest = vm.eventRequestManager().createThreadExitRequest();
threadExitRequest.setEnabled(true);
eventDispatcher.addEventListener(this, threadExitRequest);
List allThreads = vm.allThreads();
ThreadReference threadReference = null;
for (Iterator iterator = allThreads.iterator(); iterator.hasNext();) {
threadReference = (ThreadReference) iterator.next();
createThread(threadReference, false);
}
}
/**
* Removes all threads from the target
*/
private synchronized void removeAllThreads() {
Iterator iter = getThreadIterator();
while (iter.hasNext()) {
JavaScriptThread thread = (JavaScriptThread) iter.next();
thread.terminated();
}
threads.clear();
removeJSDIEventListener(this, threadEnterRequest);
removeJSDIEventListener(this, threadExitRequest);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#getThreads()
*/
public synchronized IThread[] getThreads() throws DebugException {
return (IThread[]) threads.toArray(new IThread[this.threads.size()]);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#hasThreads()
*/
public synchronized boolean hasThreads() throws DebugException {
return !threads.isEmpty();
}
/**
* Installs all JavaScript breakpoints that currently exist in the
* breakpoint manager
*/
synchronized void initializeBreakpoints() {
debuggerStatementRequest = getEventRequestManager().createDebuggerStatementRequest();
debuggerStatementRequest.setEnabled(true);
addJSDIEventListener(this, debuggerStatementRequest);
IBreakpointManager manager = DebugPlugin.getDefault().getBreakpointManager();
manager.addBreakpointListener(this);
IBreakpoint[] managerBreakpoints = manager.getBreakpoints(JavaScriptDebugModel.MODEL_ID);
for (int i = 0; i < managerBreakpoints.length; i++) {
breakpointAdded(managerBreakpoints[i]);
}
//add the managed breakpoints
IJavaScriptBreakpoint[] breakpoints = JavaScriptPreferencesManager.getAllManagedBreakpoints();
for (int i = 0; i < breakpoints.length; i++) {
breakpointAdded(breakpoints[i]);
}
}
/**
* Removes all breakpoints from this target
*/
private synchronized void removeAllBreakpoints() {
Iterator iter = ((ArrayList)this.breakpoints.clone()).iterator();
JavaScriptBreakpoint breakpoint = null;
while (iter.hasNext()) {
breakpoint = (JavaScriptBreakpoint) iter.next();
breakpoint.removeFromTarget(this);
}
this.breakpoints.clear();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint)
*/
public boolean supportsBreakpoint(IBreakpoint breakpoint) {
return JavaScriptDebugModel.MODEL_ID.equals(breakpoint.getModelIdentifier());
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#canResume()
*/
public boolean canResume() {
if ((isSuspended() || canResumeThreads()) && isAvailable()) {
if (threads.size() == 0) {
return true;
}
Iterator iter = getThreadIterator();
while (iter.hasNext()) {
IThread thread = (IThread) iter.next();
if (thread.canResume()) {
// if at least 1 thread can resume the target can be resumed
return true;
}
}
}
return false;
}
/**
* @return true if any one of the threads in the target can be resumed,
* false otherwise
*/
private boolean canResumeThreads() {
Iterator iter = getThreadIterator();
IThread thread = null;
while (iter.hasNext()) {
thread = (IThread) iter.next();
if (thread.canResume()) {
return true;
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
*/
public boolean canSuspend() {
if (!isSuspended() && isAvailable()) {
Iterator iter = getThreadIterator();
while (iter.hasNext()) {
IThread thread = (IThread) iter.next();
if (thread.isSuspended()) {
// do not allow the target to suspend if there is already a
// suspended thread
return false;
}
}
return true;
}
return false;
}
/**
* Returns an iterator over the collection of threads. The returned iterator
* is made on a copy of the thread list so that it is thread safe. This
* method should always be used instead of getThreadList().iterator()
*
* @return an iterator over the collection of threads
*/
private Iterator getThreadIterator() {
List threadList;
synchronized (this.threads) {
threadList = (List) this.threads.clone();
}
return threadList.iterator();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
*/
public boolean isSuspended() {
return this.suspended;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#resume()
*/
public void resume() throws DebugException {
if (!isAvailable()) {
// no-op if the target is not ready
return;
}
// if we are resuming the target resume all of the threads before
// resuming the target
// this gives the threads a chance to save state, etc before the VM is
// resumed
Iterator iter = getThreadIterator();
JavaScriptThread thread = null;
while (iter.hasNext()) {
thread = (JavaScriptThread) iter.next();
if (thread.isSuspended()) {
thread.targetResume();
}
}
this.suspended = false;
resumeVM(false);
fireResumeEvent(DebugEvent.CLIENT_REQUEST);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#suspend()
*/
public void suspend() throws DebugException {
if (isSuspended() || !isAvailable()) {
// no-op if the target is suspended or not ready
return;
}
try {
suspended = true;
if (this.vm != null) {
this.vm.suspend();
}
// set all owned, unsuspended threads as suspended if we suspend the
// target
Iterator iter = getThreadIterator();
while (iter.hasNext()) {
JavaScriptThread thread = (JavaScriptThread) iter.next();
if (!thread.isSuspended()) {
thread.markSuspended();
}
}
} finally {
fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
}
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.model.IJavaScriptDebugTarget#getScriptGroup()
*/
public IScriptGroup getScriptGroup() {
return scriptgroup;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDisconnect#disconnect()
*/
public void disconnect() throws DebugException {
if (!isAvailable()) {
// already done
return;
}
if (!this.supportsDisconnect) {
notSupported(NLS.bind(
ModelMessages.JSDIDebugTarget_not_support_disconnect,
getName()), null);
}
try {
// first resume the VM, do not leave it in a suspended state
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=304574
resumeVM(true);
}
catch(RuntimeException rte) {}
finally {
cleanup();
disposeVM(true);
this.disconnected = true;
fireTerminateEvent();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ITerminate#terminate()
*/
public void terminate() throws DebugException {
if (!isAvailable()) {
// already done
return;
}
if (!this.supportsTerminate) {
notSupported(NLS.bind(
ModelMessages.JSDIDebugTarget_not_support_terminate,
getName()), null);
}
this.terminating = true;
try {
// first resume the VM, do not leave it in a suspended state
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=304574
resumeVM(true);
// next terminate the underlying process
if (this.process != null) {
this.process.terminate();
}
this.terminated = true;
} finally {
disposeVM(true);
cleanup();
this.terminating = false;
fireTerminateEvent();
}
}
/**
* disposes the underlying {@link VirtualMachine}
*
* @param shutdown
* @throws DebugException
*/
void disposeVM(boolean shutdown) throws DebugException {
if(this.vm != null) {
try {
this.vm.dispose();
}
catch(RuntimeException rte) {
if(!shutdown) {
disconnect();
}
}
}
}
/**
* resumes the underlying {@link VirtualMachine}
*
* @param shutdown if the method is being called during a terminating call
* @throws DebugException
*/
void resumeVM(boolean shutdown) throws DebugException {
if(this.vm != null) {
try {
this.vm.resume();
}
catch(RuntimeException rte) {
if(!shutdown) {
disconnect();
}
}
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long,
* long)
*/
public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
notSupported(ModelMessages.JSDIDebugTarget_unsupported_operation, null);
return null;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval
* ()
*/
public boolean supportsStorageRetrieval() {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.internal.core.model.JavaScriptDebugElement#getVM()
*/
public VirtualMachine getVM() {
return this.vm;
}
/**
* @return if the target is available to be disconnected or terminated
*/
public boolean isAvailable() {
return !(this.terminated || this.terminating || this.disconnected);
}
/**
* @return the event dispatcher
*/
EventDispatcher getEventDispatcher() {
return this.eventDispatcher;
}
/**
* Delegate method to create a new {@link JavaScriptThread} and add it to the list
* of threads
*
* @param thread the underlying {@link ThreadReference}
* @return a new {@link JavaScriptThread}
*/
private synchronized JavaScriptThread createThread(ThreadReference thread, boolean fireEvent) {
if (isDisconnected()) {
return null;
}
JavaScriptThread jsdiThread = findThread(thread);
if (jsdiThread != null) {
return jsdiThread;
}
jsdiThread = new JavaScriptThread(this, thread);
this.threads.add(jsdiThread);
if (fireEvent) {
jsdiThread.fireCreationEvent();
}
return jsdiThread;
}
/**
* Terminates the given {@link ThreadReference} if the target is not
* disconnected
*
* @param thread
*/
private synchronized void terminateThread(ThreadReference thread) {
if (isDisconnected()) {
return;
}
JavaScriptThread jsdiThread = findThread(thread);
if (jsdiThread == null) {
return;
}
threads.remove(jsdiThread);
jsdiThread.markTerminated();
jsdiThread.fireTerminateEvent();
}
/**
* Finds the {@link JavaScriptThread} mapped to the given {@link ThreadReference}
*
* @param thread
* @return the mapped {@link JavaScriptThread} or <code>null</code>
*/
public synchronized JavaScriptThread findThread(ThreadReference thread) {
for (Iterator iterator = threads.iterator(); iterator.hasNext();) {
JavaScriptThread jsdiThread = (JavaScriptThread) iterator.next();
if (jsdiThread.matches(thread)) {
return jsdiThread;
}
}
return null;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.model.DebugElement#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if (adapter == JavaScriptDebugTarget.class) {
return this;
}
return super.getAdapter(adapter);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
*/
public synchronized void breakpointAdded(IBreakpoint breakpoint) {
if (!isAvailable() || !supportsBreakpoint(breakpoint)) {
// no-op either not ready or we don't care about the given
// breakpoint
return;
}
try {
((JavaScriptBreakpoint) breakpoint).addToTarget(this);
synchronized (this.breakpoints) {
this.breakpoints.add(breakpoint);
}
} catch (CoreException ce) {
JavaScriptDebugPlugin.log(ce);
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
*/
public synchronized void breakpointChanged(IBreakpoint breakpoint,IMarkerDelta delta) {
breakpointRemoved(breakpoint, delta);
breakpointAdded(breakpoint);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
*/
public synchronized void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
if (!isAvailable() || !supportsBreakpoint(breakpoint)) {
// no-op either not ready or we don't care about the breakpoint
return;
}
((JavaScriptBreakpoint) breakpoint).removeFromTarget(this);
synchronized (this.breakpoints) {
this.breakpoints.remove(breakpoint);
}
// remove cached breakpoints from threads
if (this.threads != null) {
for (Iterator iter = this.threads.iterator(); iter.hasNext();) {
((JavaScriptThread) iter.next()).removeBreakpoint((JavaScriptBreakpoint) breakpoint);
}
}
}
/**
* Returns the live list of breakpoints currently set in this target
*
* @return the live list of breakpoints
*/
public List getBreakpoints() {
return this.breakpoints;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse
* .debug.core.DebugEvent[])
*/
public void handleDebugEvents(DebugEvent[] events) {
if (events.length == 1) {
DebugEvent event = events[0];
switch(event.getKind()) {
case DebugEvent.TERMINATE: {
if(event.getSource().equals(getProcess())) {
shutdown();
}
break;
}
}
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchListener#launchRemoved(org.eclipse.debug.core.ILaunch)
*/
public void launchRemoved(ILaunch launch) {
if (!isAvailable()) {
return;
}
if (launch.equals(getLaunch())) {
// This target has been unregistered, but it hasn't successfully
// terminated.
// Update internal state to reflect that it is disconnected
disconnected();
}
}
/**
* delegate to clean up if the target has been disconnected and a framework
* method has been called
*/
protected void disconnected() {
if (!isDisconnected()) {
this.disconnected = true;
shutdown();
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchListener#launchAdded(org.eclipse.debug.core.ILaunch)
*/
public void launchAdded(ILaunch launch) {
// ignore
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.ILaunchListener#launchChanged(org.eclipse.debug.core.ILaunch)
*/
public void launchChanged(ILaunch launch) {
// ignore
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.model.IJSDIEventListener#eventSetComplete(org.eclipse.wst.jsdt.debug.core.jsdi.event.Event, org.eclipse.wst.jsdt.debug.core.model.JSDIDebugTarget, boolean, org.eclipse.wst.jsdt.debug.core.jsdi.event.EventSet)
*/
public void eventSetComplete(Event event, JavaScriptDebugTarget target, boolean suspend, EventSet eventSet) {
// thread enter
// thread exit
// script?
if (event instanceof DebuggerStatementEvent) {
DebuggerStatementEvent debuggerStatementEvent = (DebuggerStatementEvent) event;
ThreadReference threadReference = debuggerStatementEvent.thread();
JavaScriptThread thread = findThread(threadReference);
thread.fireSuspendEvent(DebugEvent.BREAKPOINT);
}
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.core.model.IJSDIEventListener#handleEvent(org.eclipse.wst.jsdt.debug.core.jsdi.event.Event, org.eclipse.wst.jsdt.debug.core.model.JSDIDebugTarget, boolean, org.eclipse.wst.jsdt.debug.core.jsdi.event.EventSet)
*/
public synchronized boolean handleEvent(Event event, JavaScriptDebugTarget target, boolean suspendVote, EventSet eventSet) {
if (event instanceof ThreadEnterEvent) {
ThreadEnterEvent threadEnterEvent = (ThreadEnterEvent) event;
createThread(threadEnterEvent.thread(), true);
return false;
}
if (event instanceof ThreadExitEvent) {
ThreadExitEvent threadExitEvent = (ThreadExitEvent) event;
terminateThread(threadExitEvent.thread());
return false;
}
if (event instanceof ScriptLoadEvent) {
if(iScriptCache != null) {
iScriptCache.clear();
iScriptCache = null;
}
fireEvent(new DebugEvent(this.scriptgroup, DebugEvent.MODEL_SPECIFIC, EventDispatcher.EVENT_SCRIPT_LOADED));
return true;
}
if (event instanceof DebuggerStatementEvent) {
DebuggerStatementEvent debuggerStatementEvent = (DebuggerStatementEvent) event;
ThreadReference threadReference = debuggerStatementEvent.thread();
JavaScriptThread thread = findThread(threadReference);
if(!thread.isSuspended()) {
thread.markSuspended();
}
return false;
}
// handle VM events i.e. death / disconnect
if (event instanceof VMDeathEvent) {
try {
if (!this.terminated) {
eventCleanup();
}
} finally {
shutdown();
}
return false;
}
if (event instanceof VMDisconnectEvent) {
try {
if (!this.disconnected) {
eventCleanup();
}
} finally {
shutdown();
}
return false;
}
throw new IllegalArgumentException(NLS.bind(
ModelMessages.JSDIDebugTarget_recieved_unknown_event, event
.toString()));
}
/**
* Cleans up the target
*/
void eventCleanup() {
try {
cleanup();
} finally {
this.disconnected = true;
this.terminated = true;
fireTerminateEvent();
}
}
}