KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > tools > example > debug > gui > ThreadTreeTool


1 /*
2  * @(#)ThreadTreeTool.java 1.12 05/11/17
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 /*
8  * Copyright (c) 1997-1999 by Sun Microsystems, Inc. All Rights Reserved.
9  *
10  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
11  * modify and redistribute this software in source and binary code form,
12  * provided that i) this copyright notice and license appear on all copies of
13  * the software; and ii) Licensee does not utilize the software in a manner
14  * which is disparaging to Sun.
15  *
16  * This software is provided "AS IS," without a warranty of any kind. ALL
17  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
18  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
19  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
20  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
21  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
22  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
23  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
24  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
25  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGES.
27  *
28  * This software is not designed or intended for use in on-line control of
29  * aircraft, air traffic, aircraft navigation or aircraft communications; or in
30  * the design, construction, operation or maintenance of any nuclear
31  * facility. Licensee represents and warrants that it will not use or
32  * redistribute the Software for such purposes.
33  */

34
35 package com.sun.tools.example.debug.gui;
36
37 import java.io.*;
38 import java.util.*;
39 import java.util.List JavaDoc; // Must import explicitly due to conflict with javax.awt.List
40

41 import javax.swing.*;
42 import javax.swing.tree.*;
43 import javax.swing.event.*;
44 import java.awt.*;
45 import java.awt.event.*;
46
47 import com.sun.jdi.*;
48 import com.sun.tools.example.debug.event.*;
49 import com.sun.tools.example.debug.bdi.*;
50
51 //### Bug: If the name of a thread is changed via Thread.setName(), the
52
//### thread tree view does not reflect this. The name of the thread at
53
//### the time it is created is used throughout its lifetime.
54

55 public class ThreadTreeTool extends JPanel {
56
57     private Environment env;
58
59     private ExecutionManager runtime;
60     private SourceManager sourceManager;
61     private ClassManager classManager;
62
63     private JTree tree;
64     private DefaultTreeModel treeModel;
65     private ThreadTreeNode root;
66     private SearchPath sourcePath;
67
68     private CommandInterpreter interpreter;
69
70     private static String JavaDoc HEADING = "THREADS";
71
72     public ThreadTreeTool(Environment env) {
73
74     super(new BorderLayout());
75
76     this.env = env;
77     this.runtime = env.getExecutionManager();
78     this.sourceManager = env.getSourceManager();
79
80     this.interpreter = new CommandInterpreter(env);
81
82     root = createThreadTree(HEADING);
83     treeModel = new DefaultTreeModel(root);
84     
85         // Create a tree that allows one selection at a time.
86

87         tree = new JTree(treeModel);
88     tree.setSelectionModel(new SingleLeafTreeSelectionModel());
89
90     MouseListener ml = new MouseAdapter() {
91         public void mouseClicked(MouseEvent e) {
92         int selRow = tree.getRowForLocation(e.getX(), e.getY());
93         TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
94         if(selRow != -1) {
95             if(e.getClickCount() == 1) {
96             ThreadTreeNode node =
97                 (ThreadTreeNode)selPath.getLastPathComponent();
98             // If user clicks on leaf, select it, and issue 'thread' command.
99
if (node.isLeaf()) {
100                 tree.setSelectionPath(selPath);
101                 interpreter.executeCommand("thread " +
102                                node.getThreadId() +
103                                " (\"" +
104                                node.getName() + "\")");
105             }
106             }
107         }
108         }
109     };
110
111     tree.addMouseListener(ml);
112
113     JScrollPane treeView = new JScrollPane(tree);
114     add(treeView);
115
116     // Create listener.
117
ThreadTreeToolListener listener = new ThreadTreeToolListener();
118     runtime.addJDIListener(listener);
119     runtime.addSessionListener(listener);
120
121         //### remove listeners on exit!
122
}
123
124     HashMap threadTable = new HashMap();
125
126     private List JavaDoc threadPath(ThreadReference thread) {
127     // May exit abnormally if VM disconnects.
128
List JavaDoc l = new ArrayList();
129     l.add(0, thread.name());
130     ThreadGroupReference group = thread.threadGroup();
131     while (group != null) {
132         l.add(0, group.name());
133         group = group.parent();
134     }
135     return l;
136     }
137
138     private class ThreadTreeToolListener extends JDIAdapter
139                               implements JDIListener, SessionListener {
140
141     // SessionListener
142

143     public void sessionStart(EventObject e) {
144         try {
145         Iterator iter = runtime.allThreads().iterator();
146         while (iter.hasNext()) {
147             ThreadReference thread = ((ThreadReference)iter.next());
148             root.addThread(thread);
149         }
150         } catch (VMDisconnectedException ee) {
151         // VM went away unexpectedly.
152
} catch (NoSessionException ee) {
153         // Ignore. Should not happen.
154
}
155     }
156
157     public void sessionInterrupt(EventObject e) {}
158     public void sessionContinue(EventObject e) {}
159
160
161     // JDIListener
162

163         public void threadStart(ThreadStartEventSet e) {
164         root.addThread(e.getThread());
165     }
166
167     public void threadDeath(ThreadDeathEventSet e) {
168         root.removeThread(e.getThread());
169     }
170
171         public void vmDisconnect(VMDisconnectEventSet e) {
172         // Clear the contents of this view.
173
root = createThreadTree(HEADING);
174         treeModel = new DefaultTreeModel(root);
175         tree.setModel(treeModel);
176         threadTable = new HashMap();
177     }
178
179     }
180
181     ThreadTreeNode createThreadTree(String JavaDoc label) {
182     return new ThreadTreeNode(label, null);
183     }
184
185     class ThreadTreeNode extends DefaultMutableTreeNode {
186
187     String JavaDoc name;
188     ThreadReference thread; // null if thread group
189
long uid;
190     String JavaDoc description;
191
192     ThreadTreeNode(String JavaDoc name, ThreadReference thread) {
193         if (name == null) {
194         name = "<unnamed>";
195         }
196         this.name = name;
197         this.thread = thread;
198         if (thread == null) {
199         this.uid = -1;
200         this.description = name;
201         } else {
202         this.uid = thread.uniqueID();
203         this.description = name + " (t@" + Long.toHexString(uid) + ")";
204         }
205     }
206
207     public String JavaDoc toString() {
208         return description;
209     }
210
211     public String JavaDoc getName() {
212         return name;
213     }
214
215     public ThreadReference getThread() {
216         return thread;
217     }
218
219     public String JavaDoc getThreadId() {
220         return "t@" + Long.toHexString(uid);
221     }
222
223     private boolean isThreadGroup() {
224         return (thread == null);
225     }
226
227     public boolean isLeaf() {
228         return !isThreadGroup();
229     }
230
231     public void addThread(ThreadReference thread) {
232         // This can fail if the VM disconnects.
233
// It is important to do all necessary JDI calls
234
// before modifying the tree, so we don't abort
235
// midway through!
236
if (threadTable.get(thread) == null) {
237         // Add thread only if not already present.
238
try {
239             List JavaDoc path = threadPath(thread);
240             // May not get here due to exception.
241
// If we get here, we are committed.
242
// We must not leave the tree partially updated.
243
try {
244             threadTable.put(thread, path);
245             addThread(path, thread);
246             } catch (Throwable JavaDoc tt) {
247             //### Assertion failure.
248
throw new RuntimeException JavaDoc("ThreadTree corrupted");
249             }
250         } catch (VMDisconnectedException ee) {
251             // Ignore. Thread will not be added.
252
}
253         }
254     }
255
256     private void addThread(List JavaDoc threadPath, ThreadReference thread) {
257         int size = threadPath.size();
258         if (size == 0) {
259         return;
260         } else if (size == 1) {
261         String JavaDoc name = (String JavaDoc)threadPath.get(0);
262         insertNode(name, thread);
263         } else {
264         String JavaDoc head = (String JavaDoc)threadPath.get(0);
265         List JavaDoc tail = threadPath.subList(1, size);
266         ThreadTreeNode child = insertNode(head, null);
267         child.addThread(tail, thread);
268         }
269     }
270
271     private ThreadTreeNode insertNode(String JavaDoc name, ThreadReference thread) {
272         for (int i = 0; i < getChildCount(); i++) {
273         ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);
274         int cmp = name.compareTo(child.getName());
275         if (cmp == 0 && thread == null) {
276             // A like-named interior node already exists.
277
return child;
278         } else if (cmp < 0) {
279             // Insert new node before the child.
280
ThreadTreeNode newChild = new ThreadTreeNode(name, thread);
281             treeModel.insertNodeInto(newChild, this, i);
282             return newChild;
283         }
284         }
285         // Insert new node after last child.
286
ThreadTreeNode newChild = new ThreadTreeNode(name, thread);
287         treeModel.insertNodeInto(newChild, this, getChildCount());
288         return newChild;
289     }
290
291     public void removeThread(ThreadReference thread) {
292         List JavaDoc threadPath = (List JavaDoc)threadTable.get(thread);
293         // Only remove thread if we recorded it in table.
294
// Original add may have failed due to VM disconnect.
295
if (threadPath != null) {
296         removeThread(threadPath, thread);
297         }
298     }
299
300     private void removeThread(List JavaDoc threadPath, ThreadReference thread) {
301         int size = threadPath.size();
302         if (size == 0) {
303         return;
304         } else if (size == 1) {
305         String JavaDoc name = (String JavaDoc)threadPath.get(0);
306         ThreadTreeNode child = findLeafNode(thread, name);
307                 treeModel.removeNodeFromParent(child);
308         } else {
309         String JavaDoc head = (String JavaDoc)threadPath.get(0);
310         List JavaDoc tail = threadPath.subList(1, size);
311         ThreadTreeNode child = findInternalNode(head);
312         child.removeThread(tail, thread);
313         if (child.isThreadGroup() && child.getChildCount() < 1) {
314             // Prune non-leaf nodes with no children.
315
treeModel.removeNodeFromParent(child);
316         }
317         }
318     }
319     
320     private ThreadTreeNode findLeafNode(ThreadReference thread, String JavaDoc name) {
321         for (int i = 0; i < getChildCount(); i++) {
322         ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);
323         if (child.getThread() == thread) {
324             if (!name.equals(child.getName())) {
325             //### Assertion failure.
326
throw new RuntimeException JavaDoc("name mismatch");
327             }
328             return child;
329         }
330         }
331         //### Assertion failure.
332
throw new RuntimeException JavaDoc("not found");
333     }
334     
335     private ThreadTreeNode findInternalNode(String JavaDoc name) {
336         for (int i = 0; i < getChildCount(); i++) {
337         ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);
338         if (name.equals(child.getName())) {
339             return child;
340         }
341         }
342         //### Assertion failure.
343
throw new RuntimeException JavaDoc("not found");
344     }
345
346     }
347
348 }
349
Popular Tags