/** * 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.ui; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclim.plugin.jdt.command.debug.context.ThreadContext; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.jdt.debug.core.IJavaStackFrame; import org.eclipse.jdt.debug.core.IJavaThread; /** * UI model for displaying threads. * * <p> * The formatting code is borrowed from Eclipse JDT UI. * @see org.eclipse.jdt.internal.debug.ui.JDIModelPresentation */ public class ThreadView { // Thread status private static final String RUNNING = "Running"; private static final String SUSPENDED = "Suspended"; private static final String SUSPENDED_THREAD_PREFIX = ViewUtils.NON_LEAF_NODE_INDENT + ViewUtils.EXPANDED_NODE_SYMBOL; private static final String RUNNING_THREAD_PREFIX = ViewUtils.LEAF_NODE_INDENT + ViewUtils.LEAF_NODE_SYMBOL; private static final String STACK_FRAME_PREFIX = ViewUtils.LEAF_NODE_INDENT + ViewUtils.LEAF_NODE_INDENT + ViewUtils.LEAF_NODE_SYMBOL; private ThreadContext threadCtx; public ThreadView(ThreadContext threadCtx) { this.threadCtx = threadCtx; } public List<String> get() throws DebugException { List<String> results = new ArrayList<String>(); for (IJavaThread thread : threadCtx.getThreads()) { getThreadText(thread, results); } return results; } public List<String> get(IJavaThread thread) throws DebugException { List<String> results = new ArrayList<String>(); getThreadText(thread, results); return results; } private void getThreadText(IJavaThread thread, List<String> results) throws DebugException { long threadId = thread.getThreadObject().getUniqueId(); String threadName = thread.getName(); String prefix = null; String status = null; if (thread.isSuspended()) { prefix = SUSPENDED_THREAD_PREFIX; status = SUSPENDED; } else { prefix = RUNNING_THREAD_PREFIX; status = RUNNING; } results.add(prefix + "Thread-" + threadName + " (id=" + threadId + ") : " + " (" + status + ")"); IStackFrame[] stackFrames = thread.getStackFrames(); if (stackFrames != null) { // Protect against invalid stack frame. When debug session is resumed, // all threads are resumed first. Then notification is sent for each // thread. While processing for one thread, we might end up using old // stack frames for some other thread, that are no longer valid. // This should not happen normally since we have a handler for debug // target itself, but this is being defensive. try { for (IStackFrame stackFrame : stackFrames) { results.add(getStackFrameText(stackFrame)); } } catch (DebugException e) {} } } private String getStackFrameText(IStackFrame stackFrame) throws DebugException { StringBuilder result = new StringBuilder(); result.append(STACK_FRAME_PREFIX); IJavaStackFrame frame = (IJavaStackFrame) stackFrame.getAdapter( IJavaStackFrame.class); if (frame != null) { String dec = frame.getDeclaringTypeName(); if (frame.isObsolete()) { result.append(dec); result.append('>'); return result.toString(); } boolean javaStratum = true; javaStratum = frame.getReferenceType().getDefaultStratum().equals("Java"); if (javaStratum) { // receiver name String rec = frame.getReceivingTypeName(); result.append(ViewUtils.getQualifiedName(rec)); // append declaring type name if different if (!dec.equals(rec)) { result.append('('); result.append(ViewUtils.getQualifiedName(dec)); result.append(')'); } // append a dot separator and method name result.append('.'); result.append(frame.getMethodName()); List<String> args = frame.getArgumentTypeNames(); if (args.isEmpty()) { result.append("()"); } else { result.append('('); Iterator<String> iter = args.iterator(); while (iter.hasNext()) { result.append(ViewUtils.getQualifiedName(iter.next())); if (iter.hasNext()) { result.append(", "); } else if (frame.isVarArgs()) { result.replace(result.length() - 2, result.length(), "..."); } } result.append(')'); } } else { result.append(frame.getSourcePath()); } int lineNumber = frame.getLineNumber(); result.append(' '); result.append(' '); if (lineNumber >= 0) { result.append(lineNumber); } else { if (frame.isNative()) { result.append(' '); } } if (!frame.wereLocalsAvailable()) { result.append(' '); } return result.toString(); } return null; } }