/******************************************************************************* * Copyright (c) 2007 committers of openArchitectureWare 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: * committers of openArchitectureWare - initial API and implementation *******************************************************************************/ package org.eclipse.emf.mwe.internal.ui.debug.processing; import java.io.IOException; import java.util.List; 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.IDebugEventSetListener; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.emf.mwe.core.debug.model.SyntaxElement; import org.eclipse.emf.mwe.internal.core.debug.communication.Connection; import org.eclipse.emf.mwe.internal.core.debug.model.VarValueTO; import org.eclipse.emf.mwe.internal.ui.debug.model.DebugStackFrame; import org.eclipse.emf.mwe.internal.ui.debug.model.DebugTarget; import org.eclipse.emf.mwe.internal.ui.debug.model.DebugThread; import org.eclipse.emf.mwe.internal.ui.debug.processing.handlers.BreakpointPluginHandler; import org.eclipse.emf.mwe.internal.ui.debug.processing.handlers.CommandPluginHandler; import org.eclipse.emf.mwe.internal.ui.debug.processing.handlers.VariablesPluginHandler; import org.eclipse.emf.mwe.internal.ui.workflow.Activator; import org.eclipse.emf.mwe.ui.debug.model.MWEBreakpoint; import org.eclipse.emf.mwe.ui.debug.processing.PluginExtensionManager; import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; public class DebugModelManager implements IDebugEventSetListener { private final DebugTarget target; private PluginExtensionManager extensionManager; private CommandPluginHandler cmdHandler; private VariablesPluginHandler varHandler; private BreakpointPluginHandler bpHandler; public static DebugModelManager newDebugModelManager(final DebugTarget target, final Connection connection) throws DebugException { final DebugModelManager dmm = new DebugModelManager(target); dmm.extensionManager = PluginExtensionManager.getDefault(); dmm.extensionManager.init(dmm, connection); return dmm; } private DebugModelManager(final DebugTarget target) { this.target = target; DebugPlugin.getDefault().addDebugEventListener(this); } // ------------------------------------------------------------------------- public void setCmdHandler(final CommandPluginHandler cmdHandler) { this.cmdHandler = cmdHandler; } public void setVariablesHandler(final VariablesPluginHandler varHandler) { this.varHandler = varHandler; } public void setBreakpointHandler(final BreakpointPluginHandler bpHandler) { this.bpHandler = bpHandler; } public boolean hasRequiredHandlers() { return cmdHandler != null && varHandler != null && bpHandler != null; } // ------------------------------------------------------------------------- public DebugTarget getTarget() { return target; } public DebugThread getThread() { return target.getThread(); } // ********************************************************** event handling public void debuggerStarted() throws DebugException { if (shallStopInMain()) { cmdHandler.sendSuspendCommand(); } target.setSuspended(false); target.installDeferredBreakpoints(); fireCreationEvent(); } public void adaptStackFrames(final int cleanStackLevel, final List<SyntaxElement> frames) { getThread().clearStack(cleanStackLevel); getThread().pushStackFrames(frames); target.setVariablesDirty(); getThread().setVariablesDirty(); } public void debuggerSuspended() { target.setSuspended(true); // Hint: we don't set DebugEvent.STEP_END by intention // only CLIENT_REQUEST or BREAKPOINT detail will expand the launch tree final int detail = checkBreakPoint() ? DebugEvent.BREAKPOINT : DebugEvent.CLIENT_REQUEST; fireSuspendEvent(detail); } public void debuggerResumed() { target.setSuspended(false); // Hint: we don't set STEP_IN, STEP_OVER or STEP_RETURN by intention // because the ThreadEventHandler would only update CONTENT, but not // STATE fireResumeEvent(DebugEvent.CLIENT_REQUEST); } public void debuggerTerminated() { target.setSuspended(true); getThread().setStepping(false); fireSuspendEvent(DebugEvent.CLIENT_REQUEST); // wait until the delayed event handling is finished (>500ms) before // returning and sending confirmation // afterwards // this is to make sure that the source view update event will be really // thrown // see // org.eclipse.debug.internal.ui.viewers.update.EventHandlerModelProxy.dispatchResume(...) try { Thread.sleep(700); } catch (final InterruptedException e) { } } /** * This class is registered as IDebugEventSetListener to get TERMINATE * information during an unnormal end of the runtime process (when no * terminate communication-event is thrown)<br> * In this case a DebugEvent.TERMINATE is fired with an IProcess source.<br> * Another terminate event must be fired here with the DebugTarget source. * This is necessary because some listeners don't cleanup completely if * there is only a terminate event with source = IProcess * * @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse.debug.core.DebugEvent[]) */ public void handleDebugEvents(final DebugEvent[] events) { for (final DebugEvent event : events) { if (event.getKind() == DebugEvent.TERMINATE) { DebugPlugin.getDefault().removeDebugEventListener(this); DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(target); getThread().clearStack(0); target.removeThread(); fireTerminateEvent(); } } } private boolean shallStopInMain() { try { return target.getLaunch().getLaunchConfiguration().getAttribute( IJavaLaunchConfigurationConstants.ATTR_STOP_IN_MAIN, true); } catch (final CoreException e) { return true; } } private boolean checkBreakPoint() { final IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints( MWEBreakpoint.DEBUG_MODEL_ID); final DebugStackFrame frame = getThread().getStackFramePeek(); for (final IBreakpoint bp : breakpoints) { if (((MWEBreakpoint) bp).equals(frame.getCharStart(), frame.getResource())) { getThread().setBreakpoint((MWEBreakpoint) bp); return true; } } return false; } // ********************************************************* type sending public void requireStepInto() throws DebugException { getThread().setStepping(true); cmdHandler.sendStepIntoCommand(); } public void requireStepOver() throws DebugException { getThread().setStepping(true); cmdHandler.sendStepOverCommand(); } public void requireStepReturn() throws DebugException { getThread().setStepping(true); cmdHandler.sendStepReturnCommand(); } public void requireResume() throws DebugException { getThread().setStepping(false); cmdHandler.sendResumeCommand(); } public void requireSuspend() throws DebugException { cmdHandler.sendSuspendCommand(); } public void requireTerminate() throws DebugException { cmdHandler.sendTerminateCommand(); } // ------------------------------------------------------------------------- public List<VarValueTO> requireVariables(final int frameId) throws DebugException { try { final List<VarValueTO> vars = varHandler.sendRequireVariables(frameId); target.updateDebugValues(vars); return vars; } catch (final IOException e) { handleIOProblem(e); return null; // does not occur, because handleIOProblem throws // always an exception } } // we send the frame id and the var id; the frame id is used to get the // correct adapter // example: an object could occur in a workflow slot (which is handled by // the workflow adapter // later in the execution context the string representation may be rendered // differently by another adapter public List<VarValueTO> requireSubVariables(final int varId) throws DebugException { final int frameId = target.getThread().getVarFrameId(); try { final List<VarValueTO> vars = varHandler.sendRequireSubVariables(frameId, varId); target.updateDebugValues(vars); return vars; } catch (final IOException e) { handleIOProblem(e); return null; // does not occur, because handleIOProblem throws // always an exception } } public void requireSetBreakpoint(final MWEBreakpoint bp) throws DebugException { try { bpHandler.sendSetBreakpoint(bp); } catch (final IOException e) { handleIOProblem(e); } } public void requireRemoveBreakpoint(final MWEBreakpoint bp) throws DebugException { try { bpHandler.sendRemoveBreakpoint(bp); } catch (final IOException e) { handleIOProblem(e); } } public void handleIOProblem(final Exception e) throws DebugException { throw new DebugException(Activator.createErrorStatus( "lost connection to debugger runtime process --> aborting", e)); } // *************************************** forward events to the DebugPlugin private void fireCreationEvent() { fireEvent(new DebugEvent(target, DebugEvent.CREATE)); } private void fireResumeEvent(final int detail) { fireEvent(new DebugEvent(getThread(), DebugEvent.RESUME, detail)); } private void fireSuspendEvent(final int detail) { fireEvent(new DebugEvent(getThread(), DebugEvent.SUSPEND, detail)); } private void fireTerminateEvent() { fireEvent(new DebugEvent(target, DebugEvent.TERMINATE)); } private void fireEvent(final DebugEvent event) { DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { event }); } }