|
Java example source code file (ThreadTreeTool.java)
This example Java source code file (ThreadTreeTool.java) is included in the alvinalexander.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Learn more about this Java project at its project page.
The ThreadTreeTool.java Java example source code
/*
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
package com.sun.tools.example.debug.gui;
import java.util.*;
import java.util.List; // Must import explicitly due to conflict with javax.awt.List
import javax.swing.*;
import javax.swing.tree.*;
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 static final long serialVersionUID = 4168599992853038878L;
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() {
@Override
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<ThreadReference, List threadTable = new HashMap>();
private List<String> threadPath(ThreadReference thread) {
// May exit abnormally if VM disconnects.
List<String> 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
@Override
public void sessionStart(EventObject e) {
try {
for (ThreadReference thread : runtime.allThreads()) {
root.addThread(thread);
}
} catch (VMDisconnectedException ee) {
// VM went away unexpectedly.
} catch (NoSessionException ee) {
// Ignore. Should not happen.
}
}
@Override
public void sessionInterrupt(EventObject e) {}
@Override
public void sessionContinue(EventObject e) {}
// JDIListener
@Override
public void threadStart(ThreadStartEventSet e) {
root.addThread(e.getThread());
}
@Override
public void threadDeath(ThreadDeathEventSet e) {
root.removeThread(e.getThread());
}
@Override
public void vmDisconnect(VMDisconnectEventSet e) {
// Clear the contents of this view.
root = createThreadTree(HEADING);
treeModel = new DefaultTreeModel(root);
tree.setModel(treeModel);
threadTable = new HashMap<ThreadReference, List();
}
}
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) + ")";
}
}
@Override
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);
}
@Override
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<String> 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<String> threadPath, ThreadReference thread) {
int size = threadPath.size();
if (size == 0) {
return;
} else if (size == 1) {
String name = threadPath.get(0);
insertNode(name, thread);
} else {
String head = threadPath.get(0);
List<String> 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<String> threadPath = 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<String> threadPath, ThreadReference thread) {
int size = threadPath.size();
if (size == 0) {
return;
} else if (size == 1) {
String name = threadPath.get(0);
ThreadTreeNode child = findLeafNode(thread, name);
treeModel.removeNodeFromParent(child);
} else {
String head = threadPath.get(0);
List<String> 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");
}
}
}
Other Java examples (source code examples)
Here is a short list of links related to this Java ThreadTreeTool.java source code file:
|