History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/example/debug/gui/ThreadTreeTool.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/example/debug/gui/ThreadTreeTool.java+346−0
@@ -0,0 +1,346 @@
1/*
2 * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.example.debug.gui;
27
28import java.util.*;
29import java.util.List; // Must import explicitly due to conflict with javax.awt.List
30
31import javax.swing.*;
32import javax.swing.tree.*;
33import java.awt.*;
34import java.awt.event.*;
35
36import com.sun.jdi.*;
37import com.sun.tools.example.debug.event.*;
38import com.sun.tools.example.debug.bdi.*;
39
40//### Bug: If the name of a thread is changed via Thread.setName(), the
41//### thread tree view does not reflect this. The name of the thread at
42//### the time it is created is used throughout its lifetime.
43
44public class ThreadTreeTool extends JPanel {
45
46 private static final long serialVersionUID = 4168599992853038878L;
47
48 private Environment env;
49
50 private ExecutionManager runtime;
51 private SourceManager sourceManager;
52 private ClassManager classManager;
53
54 private JTree tree;
55 private DefaultTreeModel treeModel;
56 private ThreadTreeNode root;
57 private SearchPath sourcePath;
58
59 private CommandInterpreter interpreter;
60
61 private static String HEADING = "THREADS";
62
63 public ThreadTreeTool(Environment env) {
64
65 super(new BorderLayout());
66
67 this.env = env;
68 this.runtime = env.getExecutionManager();
69 this.sourceManager = env.getSourceManager();
70
71 this.interpreter = new CommandInterpreter(env);
72
73 root = createThreadTree(HEADING);
74 treeModel = new DefaultTreeModel(root);
75
76 // Create a tree that allows one selection at a time.
77
78 tree = new JTree(treeModel);
79 tree.setSelectionModel(new SingleLeafTreeSelectionModel());
80
81 MouseListener ml = new MouseAdapter() {
82 @Override
83 public void mouseClicked(MouseEvent e) {
84 int selRow = tree.getRowForLocation(e.getX(), e.getY());
85 TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
86 if(selRow != -1) {
87 if(e.getClickCount() == 1) {
88 ThreadTreeNode node =
89 (ThreadTreeNode)selPath.getLastPathComponent();
90 // If user clicks on leaf, select it, and issue 'thread' command.
91 if (node.isLeaf()) {
92 tree.setSelectionPath(selPath);
93 interpreter.executeCommand("thread " +
94 node.getThreadId() +
95 " (\"" +
96 node.getName() + "\")");
97 }
98 }
99 }
100 }
101 };
102
103 tree.addMouseListener(ml);
104
105 JScrollPane treeView = new JScrollPane(tree);
106 add(treeView);
107
108 // Create listener.
109 ThreadTreeToolListener listener = new ThreadTreeToolListener();
110 runtime.addJDIListener(listener);
111 runtime.addSessionListener(listener);
112
113 //### remove listeners on exit!
114 }
115
116 HashMap<ThreadReference, List<String>> threadTable = new HashMap<ThreadReference, List<String>>();
117
118 private List<String> threadPath(ThreadReference thread) {
119 // May exit abnormally if VM disconnects.
120 List<String> l = new ArrayList<String>();
121 l.add(0, thread.name());
122 ThreadGroupReference group = thread.threadGroup();
123 while (group != null) {
124 l.add(0, group.name());
125 group = group.parent();
126 }
127 return l;
128 }
129
130 private class ThreadTreeToolListener extends JDIAdapter
131 implements JDIListener, SessionListener {
132
133 // SessionListener
134
135 @Override
136 public void sessionStart(EventObject e) {
137 try {
138 for (ThreadReference thread : runtime.allThreads()) {
139 root.addThread(thread);
140 }
141 } catch (VMDisconnectedException ee) {
142 // VM went away unexpectedly.
143 } catch (NoSessionException ee) {
144 // Ignore. Should not happen.
145 }
146 }
147
148 @Override
149 public void sessionInterrupt(EventObject e) {}
150 @Override
151 public void sessionContinue(EventObject e) {}
152
153
154 // JDIListener
155
156 @Override
157 public void threadStart(ThreadStartEventSet e) {
158 root.addThread(e.getThread());
159 }
160
161 @Override
162 public void threadDeath(ThreadDeathEventSet e) {
163 root.removeThread(e.getThread());
164 }
165
166 @Override
167 public void vmDisconnect(VMDisconnectEventSet e) {
168 // Clear the contents of this view.
169 root = createThreadTree(HEADING);
170 treeModel = new DefaultTreeModel(root);
171 tree.setModel(treeModel);
172 threadTable = new HashMap<ThreadReference, List<String>>();
173 }
174
175 }
176
177 ThreadTreeNode createThreadTree(String label) {
178 return new ThreadTreeNode(label, null);
179 }
180
181 class ThreadTreeNode extends DefaultMutableTreeNode {
182
183 String name;
184 ThreadReference thread; // null if thread group
185 long uid;
186 String description;
187
188 ThreadTreeNode(String name, ThreadReference thread) {
189 if (name == null) {
190 name = "<unnamed>";
191 }
192 this.name = name;
193 this.thread = thread;
194 if (thread == null) {
195 this.uid = -1;
196 this.description = name;
197 } else {
198 this.uid = thread.uniqueID();
199 this.description = name + " (t@" + Long.toHexString(uid) + ")";
200 }
201 }
202
203 @Override
204 public String toString() {
205 return description;
206 }
207
208 public String getName() {
209 return name;
210 }
211
212 public ThreadReference getThread() {
213 return thread;
214 }
215
216 public String getThreadId() {
217 return "t@" + Long.toHexString(uid);
218 }
219
220 private boolean isThreadGroup() {
221 return (thread == null);
222 }
223
224 @Override
225 public boolean isLeaf() {
226 return !isThreadGroup();
227 }
228
229 public void addThread(ThreadReference thread) {
230 // This can fail if the VM disconnects.
231 // It is important to do all necessary JDI calls
232 // before modifying the tree, so we don't abort
233 // midway through!
234 if (threadTable.get(thread) == null) {
235 // Add thread only if not already present.
236 try {
237 List<String> path = threadPath(thread);
238 // May not get here due to exception.
239 // If we get here, we are committed.
240 // We must not leave the tree partially updated.
241 try {
242 threadTable.put(thread, path);
243 addThread(path, thread);
244 } catch (Throwable tt) {
245 //### Assertion failure.
246 throw new RuntimeException("ThreadTree corrupted");
247 }
248 } catch (VMDisconnectedException ee) {
249 // Ignore. Thread will not be added.
250 }
251 }
252 }
253
254 private void addThread(List<String> threadPath, ThreadReference thread) {
255 int size = threadPath.size();
256 if (size == 0) {
257 return;
258 } else if (size == 1) {
259 String name = threadPath.get(0);
260 insertNode(name, thread);
261 } else {
262 String head = threadPath.get(0);
263 List<String> tail = threadPath.subList(1, size);
264 ThreadTreeNode child = insertNode(head, null);
265 child.addThread(tail, thread);
266 }
267 }
268
269 private ThreadTreeNode insertNode(String name, ThreadReference thread) {
270 for (int i = 0; i < getChildCount(); i++) {
271 ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);
272 int cmp = name.compareTo(child.getName());
273 if (cmp == 0 && thread == null) {
274 // A like-named interior node already exists.
275 return child;
276 } else if (cmp < 0) {
277 // Insert new node before the child.
278 ThreadTreeNode newChild = new ThreadTreeNode(name, thread);
279 treeModel.insertNodeInto(newChild, this, i);
280 return newChild;
281 }
282 }
283 // Insert new node after last child.
284 ThreadTreeNode newChild = new ThreadTreeNode(name, thread);
285 treeModel.insertNodeInto(newChild, this, getChildCount());
286 return newChild;
287 }
288
289 public void removeThread(ThreadReference thread) {
290 List<String> threadPath = threadTable.get(thread);
291 // Only remove thread if we recorded it in table.
292 // Original add may have failed due to VM disconnect.
293 if (threadPath != null) {
294 removeThread(threadPath, thread);
295 }
296 }
297
298 private void removeThread(List<String> threadPath, ThreadReference thread) {
299 int size = threadPath.size();
300 if (size == 0) {
301 return;
302 } else if (size == 1) {
303 String name = threadPath.get(0);
304 ThreadTreeNode child = findLeafNode(thread, name);
305 treeModel.removeNodeFromParent(child);
306 } else {
307 String head = threadPath.get(0);
308 List<String> tail = threadPath.subList(1, size);
309 ThreadTreeNode child = findInternalNode(head);
310 child.removeThread(tail, thread);
311 if (child.isThreadGroup() && child.getChildCount() < 1) {
312 // Prune non-leaf nodes with no children.
313 treeModel.removeNodeFromParent(child);
314 }
315 }
316 }
317
318 private ThreadTreeNode findLeafNode(ThreadReference thread, String name) {
319 for (int i = 0; i < getChildCount(); i++) {
320 ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);
321 if (child.getThread() == thread) {
322 if (!name.equals(child.getName())) {
323 //### Assertion failure.
324 throw new RuntimeException("name mismatch");
325 }
326 return child;
327 }
328 }
329 //### Assertion failure.
330 throw new RuntimeException("not found");
331 }
332
333 private ThreadTreeNode findInternalNode(String name) {
334 for (int i = 0; i < getChildCount(); i++) {
335 ThreadTreeNode child = (ThreadTreeNode)getChildAt(i);
336 if (name.equals(child.getName())) {
337 return child;
338 }
339 }
340 //### Assertion failure.
341 throw new RuntimeException("not found");
342 }
343
344 }
345
346}