/******************************************************************************* * Copyright (c) 2013 S.Boyko 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: * S.Boyko - initial API and implementation *******************************************************************************/ package org.eclipse.m2m.internal.tests.qvt.oml.debugger; import java.text.MessageFormat; import java.util.ArrayList; 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.IWatchExpression; import org.eclipse.m2m.qvt.oml.debug.core.QVTOThread; import org.eclipse.m2m.qvt.oml.debug.core.vm.VMLocation; /** * A listener for <code>DebugPlugin</code> events * Writes a <code>log</code> - a list of (@link <code>LogRecord</code>) * @see <code>DebugPlugin</code> */ class DebugEventLogger implements IDebugEventSetListener { /** * Creates a new event listener object that will resume a thread containing a <code>lock</code> * object after obtaining <code>TERMINATE</code> event * @param lock - a thread lock to be sent a <code>notify()</code> call on <code>TERMINATE</code> event * @see <code>DebugEvent</code> */ public DebugEventLogger(Object lock, Script script) { myLog = new ArrayList<LogRecord>(); myLock = lock; myScript = script; } /** * @see <code>IDebugEventSetListener#handleDebugEvents</code> */ public void handleDebugEvents(DebugEvent[] events) { for (int i = 0; i < events.length; i++) { switch (events[i].getKind()) { case DebugEvent.SUSPEND: // The program has been interrupted if (false == events[i].getSource() instanceof QVTOThread) { return; } QVTOThread thread = (QVTOThread) events[i].getSource(); Script.Command command = null; if (myScript.hasNextCommand()) { command = myScript.nextCommand(); } try { try { if (events[i].getData() instanceof VMLocation) { // location information provided // @see QVTOThread.handleEvent() implementation VMLocation location = (VMLocation) events[i].getData(); int detail = events[i].getDetail(); int line = location.getLineNum(); myLog.add(new LogRecord(detail, line, command)); } } finally { if (command != null) { IWatchExpression expr = DebugPlugin.getDefault().getExpressionManager().newWatchExpression("100 = 1"); expr.setExpressionContext(thread); switch (command.code) { case Script.RESUME_CODE: thread.resume(); break; case Script.STEP_INTO_CODE: thread.stepInto(); break; case Script.STEP_OVER_CODE: thread.stepOver(); break; case Script.STEP_RETURN_CODE: thread.stepReturn(); break; } } else { thread.resume(); } } } catch (DebugException e) { System.err.println(e); } break; case DebugEvent.TERMINATE: // Debugger has terminated // Resume the main thread synchronized(myLock) { myLock.notifyAll(); } break; } } } /** * @return Log - a list of <code>LogRecord</code> objects */ public ArrayList<LogRecord> getLog() { return myLog; } /** * Stores a record from debugger's event log. */ static class LogRecord { /** * Creates a log record consisting of an eventDetail (cause of program interruption, * see {@link <code>DebugEvent</code>}) and a line in sorce file where the interruption * occured * @param eventDetail - event detail (see {@<code>DebugEvent.getDetail()</code>}) * @param line - line number */ public LogRecord(int eventDetail, int line, Script.Command command) { this.eventDetail = eventDetail; this.lineNumber = line; this.command = command; } public static String eventDetailToString(int eventDetail) { String message; switch (eventDetail) { case DebugEvent.BREAKPOINT: message = BREAKPOINT_MESSAGE; break; case DebugEvent.STEP_INTO: message = STEP_INTO_MESSAGE; break; case DebugEvent.STEP_OVER: message = STEP_OVER_MESSAGE; break; case DebugEvent.STEP_RETURN: message = RETURN_MESSAGE; break; default: message = String.valueOf(eventDetail); } return message; } public String toString(MarkedTransformation markedTrans) { MarkedTransformation.LineMarker marker = markedTrans.getLineMarker(lineNumber); String name = (marker != null)?marker.name:NAME_NONE; return eventDetailToString(eventDetail) + MessageFormat.format(LINE_PATTERN, new Object[] {name, new Integer(lineNumber)}); } public Script.Command getCommand() { return command; } public int getLineNumber() { return lineNumber; } public int getEventDetail() { return eventDetail; } private final int eventDetail; private final int lineNumber; private final Script.Command command; private static final String BREAKPOINT_MESSAGE = "Breakpoint"; //$NON-NLS-1$ private static final String STEP_INTO_MESSAGE = "Step into"; //$NON-NLS-1$ private static final String STEP_OVER_MESSAGE = "Step over"; //$NON-NLS-1$ private static final String RETURN_MESSAGE = "Return"; //$NON-NLS-1$ private static final String LINE_PATTERN = " (name {0}, line {1})"; //$NON-NLS-1$ private static final String NAME_NONE = "<unknown>"; //$NON-NLS-1$ } private final Script myScript; private final Object myLock; private final ArrayList<LogRecord> myLog; }