blob: 04865f4e5e85f1c54a8385d6ef6f1573667e2d5e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 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
*
*******************************************************************************/
/**
*
*/
package org.eclipse.dltk.internal.debug.core.model;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IBreakpointManager;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
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.dltk.dbgp.exceptions.DbgpException;
import org.eclipse.dltk.debug.core.DLTKDebugPlugin;
import org.eclipse.dltk.debug.core.DebugPreferenceConstants;
import org.eclipse.dltk.debug.core.IDbgpService;
import org.eclipse.dltk.debug.core.model.IScriptDebugTarget;
import org.eclipse.dltk.debug.core.model.IScriptDebugTargetListener;
import org.eclipse.dltk.debug.core.model.IScriptThread;
import org.eclipse.dltk.debug.core.model.IScriptVariable;
import org.eclipse.dltk.debug.core.model.MethodEntryManager;
public class ScriptDebugTarget extends ScriptDebugElement implements
IScriptDebugTarget, IScriptThreadManagerListener {
private static final String ON_EXIT = "suspendOnExit";
private static final String SUSPEND_ON_ENTRY = "suspendOnEntry";
private static final int THREAD_TERMINATION_TIMEOUT = 5000; // 5 seconds
private static final String SUSPEND_ON_EXIT = ON_EXIT;
private final ListenerList listeners;
private IScriptDebugTargetStreamManager manager;
private final IProcess process;
private final ILaunch launch;
private String name;
private boolean suspendOnMethodEntry;
private boolean suspendOnMethodExit;
private boolean disconnected;
private final IScriptThreadManager threadManager;
private final ScriptBreakpointManager breakpointManager;
private final IDbgpService dbgpService;
private final String sessionId;
private final String mondelId;
private static int findFirstNonEmptyScriptLine(IFile file)
throws CoreException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(file
.getContents(), file.getCharset()));
int lineNumber = 1;
String line = null;
while ((line = reader.readLine()) != null) {
if (line.length() > 0) {
break;
}
++lineNumber;
}
return lineNumber;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
}
}
}
return -1;
}
private URI scriptUri;
private int scriptNonEmptyLine = -1;
private boolean isRemote;
private static final String ATTR_PROJECT = "project";
private static final String ATTR_SCRIPT = "mainScript";
private void setupScriptParameters(ILaunchConfiguration configuration)
throws CoreException {
final String projectName = configuration.getAttribute(ATTR_PROJECT,
(String) null);
final String scriptName = configuration.getAttribute(ATTR_SCRIPT,
(String) null);
if (projectName != null && scriptName != null) {
final IProject project = ResourcesPlugin.getWorkspace().getRoot()
.getProject(projectName);
if (project != null) {
final IResource resource = project.findMember(scriptName);
if (resource instanceof IFile) {
scriptUri = ScriptLineBreakpoint.makeUri((IFile) resource);
scriptNonEmptyLine = findFirstNonEmptyScriptLine((IFile) resource);
}
}
} else {
isRemote = true;
}
}
static WeakHashMap targets = new WeakHashMap();
public static List getAllTargets() {
return new ArrayList(targets.keySet());
}
public ScriptDebugTarget(String modelId, IDbgpService dbgpService,
String sessionId, ILaunch launch, IProcess process)
throws CoreException {
setupScriptParameters(launch.getLaunchConfiguration());
this.mondelId = modelId;
this.listeners = new ListenerList();
this.process = process;
this.launch = launch;
this.threadManager = new /* New */ScriptThreadManager(this);
this.sessionId = sessionId;
this.dbgpService = dbgpService;
this.dbgpService.registerAcceptor(this.sessionId, this.threadManager);
this.disconnected = false;
this.breakpointManager = new ScriptBreakpointManager(this);
this.threadManager.addListener(this);
DebugEventHelper.fireCreateEvent(this);
targets.put(this, "");
boolean suspendOnMethodEntry2 = MethodEntryManager
.isSuspendOnMethodEntry();
boolean suspendOnMethodExit2 = MethodEntryManager
.isSuspendOnMethodExit();
setSuspendOnMethodEntry(suspendOnMethodEntry2);
setSuspendOnMethodExit(suspendOnMethodExit2);
}
public String getSessionId() {
return sessionId;
}
public IDebugTarget getDebugTarget() {
return this;
}
public String getModelIdentifier() {
return mondelId;
}
public ILaunch getLaunch() {
return launch;
}
// IDebugTarget
public IProcess getProcess() {
return process;
}
public boolean hasThreads() throws DebugException {
return threadManager.hasThreads();
}
public IThread[] getThreads() throws DebugException {
return threadManager.getThreads();
}
public String getName() throws DebugException {
return name;
}
// ITerminate
public boolean canTerminate() {
return threadManager.canTerminate();
}
public boolean isTerminated() {
return threadManager.isTerminated();
}
protected boolean waitTermianted() {
final int WAIT_CHUNK = 400; // 200 ms
int all = 0;
while (all < THREAD_TERMINATION_TIMEOUT) {
try {
Thread.sleep(WAIT_CHUNK);
all += WAIT_CHUNK;
} catch (InterruptedException e) {
}
if (threadManager.isTerminated()) {
return true;
}
}
return false;
}
public void terminate() throws DebugException {
dbgpService.unregisterAcceptor(sessionId);
threadManager.terminate();
if (waitTermianted()) {
threadManager.removeListener(this);
IBreakpointManager manager = DebugPlugin.getDefault()
.getBreakpointManager();
manager.removeBreakpointListener(this);
manager.removeBreakpointManagerListener(breakpointManager);
DebugEventHelper.fireTerminateEvent(this);
}
}
// ISuspendResume
public boolean canSuspend() {
return threadManager.canSuspend();
}
public boolean isSuspended() {
return threadManager.isSuspended();
}
public void suspend() throws DebugException {
threadManager.suspend();
}
public boolean canResume() {
return threadManager.canResume();
}
public void resume() throws DebugException {
threadManager.resume();
}
// IDisconnect
public boolean canDisconnect() {
// Detach feature support!!!
return false;
}
public void disconnect() throws DebugException {
disconnected = true;
}
public boolean isDisconnected() {
return disconnected;
}
// IMemoryBlockRetrieval
public boolean supportsStorageRetrieval() {
return false;
}
public IMemoryBlock getMemoryBlock(long startAddress, long length)
throws DebugException {
return null;
}
public IScriptVariable findVariable(String variableName)
throws DebugException {
// TODO Auto-generated method stub
return null;
}
// Request timeout
public int getRequestTimeout() {
// TODO Auto-generated method stub
return 0;
}
public void setRequestTimeout(int timeout) {
// TODO Auto-generated method stub
}
// IBreakpointListener
public void breakpointAdded(IBreakpoint breakpoint) {
breakpointManager.breakpointAdded(breakpoint);
}
public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
breakpointManager.breakpointChanged(breakpoint, delta);
}
public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
breakpointManager.breakpointRemoved(breakpoint, delta);
}
// Streams
public IScriptDebugTargetStreamManager getStreamManager() {
return manager;
}
public void setStreamManager(IScriptDebugTargetStreamManager manager) {
this.manager = manager;
}
// IDbgpThreadManagerListener
public void threadAccepted(IScriptThread thread, boolean first) {
if (first) {
breakpointManager.setupDeferredBreakpoints();
IBreakpointManager manager = DebugPlugin.getDefault()
.getBreakpointManager();
manager.addBreakpointListener(this);
manager.addBreakpointManagerListener(breakpointManager);
// DebugEventHelper.fireCreateEvent(this);
fireTargetInitialized();
}
try {
initSuspends(thread);
} catch (DbgpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void initSuspends(IScriptThread thread) throws DbgpException {
thread.getDbgpSession().getCoreCommands().setProperty(SUSPEND_ON_ENTRY,
-1, Boolean.toString(suspendOnMethodEntry));
thread.getDbgpSession().getCoreCommands().setProperty(SUSPEND_ON_EXIT,
-1, Boolean.toString(suspendOnMethodExit));
}
public void allThreadsTerminated() {
try {
terminate();
} catch (DebugException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String toString() {
return "Debugging engine (id = " + this.sessionId + ")";
}
// IScriptDebugTarget
public void runToLine(URI uri, int lineNumber) throws DebugException {
breakpointManager.setBreakpointUntilFirstSuspend(uri, lineNumber);
resume();
}
public boolean isInitialized() {
return !threadManager.isWaitingForThreads();
}
protected void fireTargetInitialized() {
Object[] list = listeners.getListeners();
for (int i = 0; i < list.length; ++i) {
((IScriptDebugTargetListener) list[i]).targetInitialized();
}
}
public void addListener(IScriptDebugTargetListener listener) {
listeners.add(listener);
}
public void removeListener(IScriptDebugTargetListener listener) {
listeners.remove(listener);
}
public boolean supportsBreakpoint(IBreakpoint breakpoint) {
return breakpointManager.supportsBreakpoint(breakpoint);
}
public boolean isSuspendOnMethodEntry() {
return suspendOnMethodEntry;
}
public boolean isSuspendOnMethodExit() {
return suspendOnMethodExit;
}
public void setSuspendOnMethodEntry(boolean suspend) {
boolean ok = true;
if (!isDisconnected()) {
IThread[] threads;
try {
threads = this.getThreads();
l2: for (int a = 0; a < threads.length; a++) {
IScriptThread scr = (IScriptThread) threads[a];
try {
scr.getDbgpSession().getCoreCommands()
.setProperty(SUSPEND_ON_ENTRY, -1,
Boolean.toString(suspend));
} catch (DbgpException e) {
e.printStackTrace();
ok = false;
break l2;
}
}
} catch (DebugException e) {
e.printStackTrace();
}
}
if (ok)
this.suspendOnMethodEntry = suspend;
}
public void setSuspendOnMethodExit(boolean suspend) {
boolean ok = true;
if (!isDisconnected()) {
IThread[] threads;
try {
threads = this.getThreads();
l2: for (int a = 0; a < threads.length; a++) {
IScriptThread scr = (IScriptThread) threads[a];
try {
scr.getDbgpSession().getCoreCommands().setProperty(
ON_EXIT, -1, Boolean.toString(suspend));
} catch (DbgpException e) {
e.printStackTrace();
ok = false;
break l2;
}
}
} catch (DebugException e) {
e.printStackTrace();
}
}
if (ok)
this.suspendOnMethodExit = suspend;
}
}