package com.sap.runlet.expressionpad.launch;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.DebugElement;
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 com.sap.runlet.abstractinterpreter.AbstractObjectFormatter;
import com.sap.runlet.abstractinterpreter.AbstractRunletInterpreter;
import com.sap.runlet.abstractinterpreter.DebugListener;
import com.sap.runlet.abstractinterpreter.DebugSession;
import com.sap.runlet.expressionpad.Activator;
import com.sap.runlet.expressionpad.RunletEvaluator;
import com.sap.tc.moin.repository.mmi.reflect.RefObject;
public class RunletDebugTarget
extends DebugElement implements IDebugTarget, DebugListener {
private RunletEvaluator main;
private AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> topLevelInterpreter;
private AbstractObjectFormatter<?, ?, ?, ?> formatter;
private ILaunch launch;
private Date launchedAt;
private String name;
private IProcess process;
/**
* The connection to the interpreter
*/
private DebugSession debugSession;
public RunletDebugTarget(RunletEvaluator main, ILaunch launch, String name, AbstractObjectFormatter<?, ?, ?, ?> formatter) {
super(/*nested debug target*/ null);
this.main = main;
this.topLevelInterpreter = main.getInterpreter();
this.launch = launch;
this.formatter = formatter;
launchedAt = new Date();
this.name = name;
this.process = new RunletProcess(this);
this.debugSession = new DebugSession(this);
this.topLevelInterpreter.setDebugSession(getDebugSession());
fireCreationEvent();
}
public int hashCode() {
return getDebugSession().hashCode();
}
public boolean equals(Object o) {
boolean result = false;
if (o instanceof RunletDebugTarget) {
result = getDebugSession().equals(((RunletDebugTarget) o).getDebugSession());
}
return result;
}
@Override
public String getName() {
return Messages.RunletDebugTarget_0+name+Messages.RunletDebugTarget_1+launchedAt;
}
@Override
public IProcess getProcess() {
return process;
}
@Override
public RunletThread[] getThreads() {
List<IThread> result = new LinkedList<IThread>();
if (!isDisconnected()) {
result.addAll(getThreadsForInterpreter(getInterpreter()));
}
return result.toArray(new RunletThread[result.size()]);
}
private Collection<RunletThread> getThreadsForInterpreter(AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> interpreter) {
Collection<RunletThread> threads = new LinkedList<RunletThread>();
threads.add(new RunletThread(interpreter, getLaunch(), this, formatter));
for (AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> child : interpreter.getRunningChildren()) {
threads.addAll(getThreadsForInterpreter(child));
}
return threads;
}
@Override
public boolean hasThreads() {
return true;
}
@Override
public boolean supportsBreakpoint(IBreakpoint breakpoint) {
return true;
}
@Override
public ILaunch getLaunch() {
return launch;
}
@Override
public String getModelIdentifier() {
return Activator.PLUGIN_ID;
}
@Override
public boolean canTerminate() {
return !isDisconnected() && !isTerminated();
}
@Override
public boolean isTerminated() {
return getInterpreter() == null || getInterpreter().isTerminated();
}
@Override
public void terminate() throws DebugException {
for (IThread thread:getThreads()) {
thread.terminate();
}
}
@Override
public boolean canResume() {
return !isDisconnected() && isSuspended();
}
@Override
public boolean canSuspend() {
if (isTerminated() || isSuspended()) {
return false;
}
for (IThread thread : getThreads()) {
if (!thread.canSuspend()) {
return false;
}
}
return true;
}
@Override
public boolean isSuspended() {
for (IThread thread : getThreads()) {
if (!thread.isSuspended()) {
return false;
}
}
return true;
}
@Override
public void resume() throws DebugException {
for (IThread thread : getThreads()) {
thread.resume();
}
}
@Override
public void suspend() throws DebugException {
for (IThread thread:getThreads()) {
thread.suspend();
}
}
@Override
public void breakpointAdded(IBreakpoint breakpoint) {
// TODO Auto-generated method stub
}
@Override
public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
// TODO Auto-generated method stub
}
@Override
public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
// TODO Auto-generated method stub
}
@Override
public boolean canDisconnect() {
return !isDisconnected();
}
@Override
public void disconnect() {
topLevelInterpreter = null;
}
@Override
public boolean isDisconnected() {
return topLevelInterpreter == null;
}
@Override
public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
throw new DebugException(new Status(Status.ERROR, Activator.PLUGIN_ID, Messages.RunletDebugTarget_3));
}
@Override
public boolean supportsStorageRetrieval() {
return false;
}
public AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> getInterpreter() {
return topLevelInterpreter;
}
public RunletEvaluator getMain() {
return main;
}
protected DebugSession getDebugSession() {
return debugSession;
}
@Override
public void started(AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> interpreter) {
for (RunletThread thread : getThreadsForInterpreter(interpreter)) {
thread.fireCreationEvent();
}
}
@Override
public void hitBreakpoint(AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> interpreter, RefObject element) {
for (RunletThread thread : getThreadsForInterpreter(interpreter)) {
thread.fireSuspendEvent(DebugEvent.BREAKPOINT);
}
}
@Override
public void resumed(AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> interpreter, ResumeReason reason) {
for (RunletThread thread : getThreadsForInterpreter(interpreter)) {
int detail;
switch (reason) {
case STEP_INTO:
detail = DebugEvent.STEP_INTO; break;
case STEP_OVER:
detail = DebugEvent.STEP_OVER; break;
case STEP_RETURN:
detail = DebugEvent.STEP_RETURN; break;
case CLIENT_REQUEST:
detail = DebugEvent.CLIENT_REQUEST; break;
default:
detail = DebugEvent.UNSPECIFIED; break;
}
thread.fireResumeEvent(detail);
}
}
@Override
public void suspended(AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> interpreter, SuspendReason reason) {
for (RunletThread thread : getThreadsForInterpreter(interpreter)) {
int detail;
switch (reason) {
case BREAKPOINT:
detail = DebugEvent.BREAKPOINT; break;
case CLIENT_REQUEST:
detail = DebugEvent.CLIENT_REQUEST; break;
case STEP_END:
detail = DebugEvent.STEP_END; break;
default:
detail = DebugEvent.UNSPECIFIED; break;
}
thread.fireSuspendEvent(detail);
}
}
@Override
public void terminated(AbstractRunletInterpreter<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> interpreter) {
for (RunletThread thread : getThreadsForInterpreter(interpreter)) {
thread.fireTerminateEvent();
}
if (interpreter == getInterpreter()) { // the root died
fireTerminateEvent();
}
}
@Override
public IDebugTarget getDebugTarget() {
return this;
}
}