/** * Copyright (C) 2014 Eric Van Dewoestine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.eclim.plugin.jdt.command.debug.event; import org.eclim.logging.Logger; import org.eclim.plugin.jdt.command.debug.context.DebuggerContext; import org.eclim.plugin.jdt.command.debug.context.DebuggerState; import org.eclim.plugin.jdt.command.debug.ui.ViewUtils; import org.eclipse.debug.core.DebugEvent; import org.eclipse.jdt.debug.core.IJavaStackFrame; import org.eclipse.jdt.internal.debug.core.model.JDIDebugElement; import org.eclipse.jdt.internal.debug.core.model.JDIThread; /** * Event handler for a thread. */ public class ThreadEventHandler extends DebugEventHandler { private static final Logger logger = Logger.getLogger(ThreadEventHandler.class); protected void handle( DebuggerContext ctx, JDIDebugElement element, int kind, int detail) throws Exception { JDIThread thread = (JDIThread) element; long threadId = thread.getThreadObject().getUniqueId(); if (logger.isDebugEnabled()) { logger.debug("Handling thread event : " + thread.getName() + " : " + threadId + " " + kind + " " + detail); } if (kind == DebugEvent.SUSPEND) { if ((detail == DebugEvent.STEP_END) || (detail == DebugEvent.BREAKPOINT)) { IJavaStackFrame topStackFrame = (IJavaStackFrame) thread.getTopStackFrame(); String fileName = getFileNameInFrame(ctx, topStackFrame); int lineNum = topStackFrame.getLineNumber(); if (logger.isDebugEnabled()) { if (detail == DebugEvent.BREAKPOINT) { logger.debug("Breakpoint hit: " + fileName + " at " + lineNum); } } ctx.getThreadContext().update(thread); // Do not update variables when suspended in a class file. // This causes the variable set to explode causing OOM. if (fileName != null) { ctx.jumpToFilePosition(fileName, lineNum); } // Call refresh after jumping to file. Otherwise, it causes the sign to // not get placed for some reason. ctx.updateThreadView(threadId, ViewUtils.MODIFY_NODE, ctx.getThreadView().get(thread)); ctx.updateVariableView(ctx.getVariableView().get()); } else if (detail == DebugEvent.CLIENT_REQUEST) { ctx.getThreadContext().update(thread); ctx.updateThreadView(threadId, ViewUtils.MODIFY_NODE, ctx.getThreadView().get(thread)); ctx.updateVariableView(ctx.getVariableView().get()); } } else if (kind == DebugEvent.CREATE) { ctx.getThreadContext().update(thread); // Refresh status only after debug target has been created. // This is to avoid refreshing for each and every thread that gets // created before the debug target has finished initialization. // Once its created, we do want to refresh for each thread creation. if (!ctx.getState().equals(DebuggerState.CONNECTING)) { ctx.updateThreadView(threadId, ViewUtils.ADD_NODE, ctx.getThreadView().get(thread)); } } else if (kind == DebugEvent.TERMINATE) { ctx.getThreadContext().remove(thread); ctx.updateThreadView(threadId, ViewUtils.REMOVE_NODE, null); } else if (kind == DebugEvent.RESUME) { ctx.getThreadContext().update(thread); ctx.updateThreadView(threadId, ViewUtils.MODIFY_NODE, ctx.getThreadView().get(thread)); if (ctx.getVariableView().isViewingThread(thread)) { ctx.getVariableView().clear(); // TODO If we send this remote command, then in some cases // it causes the next remote command to update variable window // to not get sent correctly. As a result, the variable window // becomes empty after a step over operation. ctx.updateVariableView(null); } } } }