threadtreetool.java

来自「jpda例子文件」· Java 代码 · 共 349 行

JAVA
349
字号
/* * @(#)ThreadTreeTool.java	1.10 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. *//* * Copyright (c) 1997-1999 by Sun Microsystems, Inc. All Rights Reserved. *  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use, * modify and redistribute this software in source and binary code form, * provided that i) this copyright notice and license appear on all copies of * the software; and ii) Licensee does not utilize the software in a manner * which is disparaging to Sun. *  * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. *  * This software is not designed or intended for use in on-line control of * aircraft, air traffic, aircraft navigation or aircraft communications; or in * the design, construction, operation or maintenance of any nuclear * facility. Licensee represents and warrants that it will not use or * redistribute the Software for such purposes. */package com.sun.tools.example.debug.gui;import java.io.*;import java.util.*;import java.util.List;  // Must import explicitly due to conflict with javax.awt.Listimport javax.swing.*;import javax.swing.tree.*;import javax.swing.event.*;import java.awt.*;import java.awt.event.*;import com.sun.jdi.*;import com.sun.tools.example.debug.event.*;import com.sun.tools.example.debug.bdi.*;//### Bug: If the name of a thread is changed via Thread.setName(), the//### thread tree view does not reflect this.  The name of the thread at//### the time it is created is used throughout its lifetime.public class ThreadTreeTool extends JPanel {    private Environment env;    private ExecutionManager runtime;    private SourceManager sourceManager;    private ClassManager classManager;    private JTree tree;    private DefaultTreeModel treeModel;    private ThreadTreeNode root;    private SearchPath sourcePath;    private CommandInterpreter interpreter;    private static String HEADING = "THREADS";    public ThreadTreeTool(Environment env) {	super(new BorderLayout());	this.env = env;	this.runtime = env.getExecutionManager();	this.sourceManager = env.getSourceManager();	this.interpreter = new CommandInterpreter(env);	root = createThreadTree(HEADING);	treeModel = new DefaultTreeModel(root);	        // Create a tree that allows one selection at a time.	        tree = new JTree(treeModel);	tree.setSelectionModel(new SingleLeafTreeSelectionModel());	MouseListener ml = new MouseAdapter() {	    public void mouseClicked(MouseEvent e) {		int selRow = tree.getRowForLocation(e.getX(), e.getY());		TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());		if(selRow != -1) {		    if(e.getClickCount() == 1) {			ThreadTreeNode node =			    (ThreadTreeNode)selPath.getLastPathComponent();			// If user clicks on leaf, select it, and issue 'thread' command.			if (node.isLeaf()) {			    tree.setSelectionPath(selPath);			    interpreter.executeCommand("thread " +						       node.getThreadId() +						       "  (\"" +						       node.getName() + "\")");			}		    }		}	    }	};	tree.addMouseListener(ml);	JScrollPane treeView = new JScrollPane(tree);	add(treeView);	// Create listener.	ThreadTreeToolListener listener = new ThreadTreeToolListener();	runtime.addJDIListener(listener);	runtime.addSessionListener(listener);        //### remove listeners on exit!    }    HashMap threadTable = new HashMap();    private List threadPath(ThreadReference thread) {	// May exit abnormally if VM disconnects.	List l = new ArrayList();	l.add(0, thread.name());	ThreadGroupReference group = thread.threadGroup();	while (group != null) {	    l.add(0, group.name());	    group = group.parent();	}	return l;    }    private class ThreadTreeToolListener extends JDIAdapter                               implements JDIListener, SessionListener {	// SessionListener	public void sessionStart(EventObject e) {	    try {		Iterator iter = runtime.allThreads().iterator();		while (iter.hasNext()) {		    ThreadReference thread = ((ThreadReference)iter.next());		    root.addThread(thread);		}	    } catch (VMDisconnectedException ee) {		// VM went away unexpectedly.	    } catch (NoSessionException ee) {		// Ignore.  Should not happen.	    }	}	public void sessionInterrupt(EventObject e) {}	public void sessionContinue(EventObject e) {}	// JDIListener        public void threadStart(ThreadStartEventSet e) {	    root.addThread(e.getThread());	}	public void threadDeath(ThreadDeathEventSet e) {	    root.removeThread(e.getThread());	}        public void vmDisconnect(VMDisconnectEventSet e) {	    // Clear the contents of this view.	    root = createThreadTree(HEADING);	    treeModel = new DefaultTreeModel(root);	    tree.setModel(treeModel);	    threadTable = new HashMap();	}    }    ThreadTreeNode createThreadTree(String label) {	return new ThreadTreeNode(label, null);    }    class ThreadTreeNode extends DefaultMutableTreeNode {	String name;	ThreadReference thread;	// null if thread group	long uid;	String description;	ThreadTreeNode(String name, ThreadReference thread) {	    if (name == null) {		name = "<unnamed>";	    }	    this.name = name;	    this.thread = thread;	    if (thread == null) {		this.uid = -1;		this.description = name;	    } else {		this.uid = thread.uniqueID();		this.description = name + " (t@" + Long.toHexString(uid) + ")";	    }	}	public String toString() {	    return description;	}	public String getName() {	    return name;	}	public ThreadReference getThread() {	    return thread;	}	public String getThreadId() {	    return "t@" + Long.toHexString(uid);	}	private boolean isThreadGroup() {	    return (thread == null);	}	public boolean isLeaf() {	    return !isThreadGroup();	}	public void addThread(ThreadReference thread) {	    // This can fail if the VM disconnects.	    // It is important to do all necessary JDI calls	    // before modifying the tree, so we don't abort	    // midway through!	    if (threadTable.get(thread) == null) {		// Add thread only if not already present.		try {		    List path = threadPath(thread);		    // May not get here due to exception.		    // If we get here, we are committed.		    // We must not leave the tree partially updated.		    try {			threadTable.put(thread, path);			addThread(path, thread);		    } catch (Throwable tt) {			//### Assertion failure.			throw new RuntimeException("ThreadTree corrupted");		    }		} catch (VMDisconnectedException ee) {		    // Ignore.  Thread will not be added.		}	    }	}	private void addThread(List threadPath, ThreadReference thread) {	    int size = threadPath.size();	    if (size == 0) {		return;	    } else if (size == 1) {		String name = (String)threadPath.get(0);		insertNode(name, thread);	    } else {		String head = (String)threadPath.get(0);		List tail = threadPath.subList(1, size);		ThreadTreeNode child = insertNode(head, null);		child.addThread(tail, thread);	    }	}	private ThreadTreeNode insertNode(String name, ThreadReference thread) {	    for (int i = 0; i < getChildCount(); i++) {		ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);		int cmp = name.compareTo(child.getName());		if (cmp == 0 && thread == null) {		    // A like-named interior node already exists.		    return child;		} else if (cmp < 0) {		    // Insert new node before the child.		    ThreadTreeNode newChild = new ThreadTreeNode(name, thread);		    treeModel.insertNodeInto(newChild, this, i);		    return newChild;		}	    }	    // Insert new node after last child.	    ThreadTreeNode newChild = new ThreadTreeNode(name, thread);	    treeModel.insertNodeInto(newChild, this, getChildCount());	    return newChild;	}	public void removeThread(ThreadReference thread) {	    List threadPath = (List)threadTable.get(thread);	    // Only remove thread if we recorded it in table.	    // Original add may have failed due to VM disconnect.	    if (threadPath != null) {		removeThread(threadPath, thread);	    }	}	private void removeThread(List threadPath, ThreadReference thread) {	    int size = threadPath.size();	    if (size == 0) {		return;	    } else if (size == 1) {		String name = (String)threadPath.get(0);		ThreadTreeNode child = findLeafNode(thread, name);                treeModel.removeNodeFromParent(child);	    } else {		String head = (String)threadPath.get(0);		List tail = threadPath.subList(1, size);		ThreadTreeNode child = findInternalNode(head);		child.removeThread(tail, thread);		if (child.isThreadGroup() && child.getChildCount() < 1) {		    // Prune non-leaf nodes with no children.		    treeModel.removeNodeFromParent(child);		}	    }	}		private ThreadTreeNode findLeafNode(ThreadReference thread, String name) {	    for (int i = 0; i < getChildCount(); i++) {		ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);		if (child.getThread() == thread) {		    if (!name.equals(child.getName())) {			//### Assertion failure.			throw new RuntimeException("name mismatch");		    }		    return child;		}	    }	    //### Assertion failure.	    throw new RuntimeException("not found");	}		private ThreadTreeNode findInternalNode(String name) {	    for (int i = 0; i < getChildCount(); i++) {		ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);		if (name.equals(child.getName())) {		    return child;		}	    }	    //### Assertion failure.	    throw new RuntimeException("not found");	}    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?