Showing the changes to java/pkg/com/sun/tools/example/debug/gui (32 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,74 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import javax.swing.*; | |
| 29 | +import java.awt.*; | |
| 30 | +import java.awt.event.*; | |
| 31 | + | |
| 32 | +import com.sun.tools.example.debug.bdi.*; | |
| 33 | + | |
| 34 | +public class ApplicationTool extends JPanel { | |
| 35 | + | |
| 36 | + private static final long serialVersionUID = 310966063293205714L; | |
| 37 | + | |
| 38 | + private ExecutionManager runtime; | |
| 39 | + | |
| 40 | + private TypeScript script; | |
| 41 | + | |
| 42 | + private static final String PROMPT = "Input:"; | |
| 43 | + | |
| 44 | + public ApplicationTool(Environment env) { | |
| 45 | + | |
| 46 | + super(new BorderLayout()); | |
| 47 | + | |
| 48 | + this.runtime = env.getExecutionManager(); | |
| 49 | + | |
| 50 | + this.script = new TypeScript(PROMPT, false); // No implicit echo. | |
| 51 | + this.add(script); | |
| 52 | + | |
| 53 | + script.addActionListener(new ActionListener() { | |
| 54 | + @Override | |
| 55 | + public void actionPerformed(ActionEvent e) { | |
| 56 | + runtime.sendLineToApplication(script.readln()); | |
| 57 | + } | |
| 58 | + }); | |
| 59 | + | |
| 60 | + runtime.addApplicationEchoListener(new TypeScriptOutputListener(script)); | |
| 61 | + runtime.addApplicationOutputListener(new TypeScriptOutputListener(script)); | |
| 62 | + runtime.addApplicationErrorListener(new TypeScriptOutputListener(script)); | |
| 63 | + | |
| 64 | + //### should clean up on exit! | |
| 65 | + | |
| 66 | + } | |
| 67 | + | |
| 68 | + /****** | |
| 69 | + public void setFont(Font f) { | |
| 70 | + script.setFont(f); | |
| 71 | + } | |
| 72 | + ******/ | |
| 73 | + | |
| 74 | +} | |
| @@ -0,0 +1,64 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +public class ClassManager { | |
| 29 | + | |
| 30 | + // This class is provided primarily for symmetry with | |
| 31 | + // SourceManager. Currently, it does very little. | |
| 32 | + // If we add facilities in the future that require that | |
| 33 | + // class files be read outside of the VM, for example, to | |
| 34 | + // provide a disassembled view of a class for bytecode-level | |
| 35 | + // debugging, the required class file management will be done | |
| 36 | + // here. | |
| 37 | + | |
| 38 | + private SearchPath classPath; | |
| 39 | + | |
| 40 | + public ClassManager(Environment env) { | |
| 41 | + this.classPath = new SearchPath(""); | |
| 42 | + } | |
| 43 | + | |
| 44 | + public ClassManager(SearchPath classPath) { | |
| 45 | + this.classPath = classPath; | |
| 46 | + } | |
| 47 | + | |
| 48 | + /* | |
| 49 | + * Set path for access to class files. | |
| 50 | + */ | |
| 51 | + | |
| 52 | + public void setClassPath(SearchPath sp) { | |
| 53 | + classPath = sp; | |
| 54 | + } | |
| 55 | + | |
| 56 | + /* | |
| 57 | + * Get path for access to class files. | |
| 58 | + */ | |
| 59 | + | |
| 60 | + public SearchPath getClassPath() { | |
| 61 | + return classPath; | |
| 62 | + } | |
| 63 | + | |
| 64 | +} | |
| @@ -0,0 +1,278 @@ | ||
| 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.util.*; | |
| 29 | + | |
| 30 | +import javax.swing.*; | |
| 31 | +import javax.swing.tree.*; | |
| 32 | +import java.awt.*; | |
| 33 | +import java.awt.event.*; | |
| 34 | + | |
| 35 | +import com.sun.jdi.*; | |
| 36 | +import com.sun.tools.example.debug.event.*; | |
| 37 | +import com.sun.tools.example.debug.bdi.*; | |
| 38 | + | |
| 39 | +public class ClassTreeTool extends JPanel { | |
| 40 | + | |
| 41 | + private static final long serialVersionUID = 526178912591739259L; | |
| 42 | + | |
| 43 | + private Environment env; | |
| 44 | + | |
| 45 | + private ExecutionManager runtime; | |
| 46 | + private SourceManager sourceManager; | |
| 47 | + private ClassManager classManager; | |
| 48 | + | |
| 49 | + private JTree tree; | |
| 50 | + private DefaultTreeModel treeModel; | |
| 51 | + private ClassTreeNode root; | |
| 52 | +// private SearchPath sourcePath; | |
| 53 | + | |
| 54 | + private CommandInterpreter interpreter; | |
| 55 | + | |
| 56 | + private static String HEADING = "CLASSES"; | |
| 57 | + | |
| 58 | + public ClassTreeTool(Environment env) { | |
| 59 | + | |
| 60 | + super(new BorderLayout()); | |
| 61 | + | |
| 62 | + this.env = env; | |
| 63 | + this.runtime = env.getExecutionManager(); | |
| 64 | + this.sourceManager = env.getSourceManager(); | |
| 65 | + | |
| 66 | + this.interpreter = new CommandInterpreter(env); | |
| 67 | + | |
| 68 | + root = createClassTree(HEADING); | |
| 69 | + treeModel = new DefaultTreeModel(root); | |
| 70 | + | |
| 71 | + // Create a tree that allows one selection at a time. | |
| 72 | + | |
| 73 | + tree = new JTree(treeModel); | |
| 74 | + tree.setSelectionModel(new SingleLeafTreeSelectionModel()); | |
| 75 | + | |
| 76 | + /****** | |
| 77 | + // Listen for when the selection changes. | |
| 78 | + tree.addTreeSelectionListener(new TreeSelectionListener() { | |
| 79 | + public void valueChanged(TreeSelectionEvent e) { | |
| 80 | + ClassTreeNode node = (ClassTreeNode) | |
| 81 | + (e.getPath().getLastPathComponent()); | |
| 82 | + if (node != null) { | |
| 83 | + interpreter.executeCommand("view " + node.getReferenceTypeName()); | |
| 84 | + } | |
| 85 | + } | |
| 86 | + }); | |
| 87 | + ******/ | |
| 88 | + | |
| 89 | + MouseListener ml = new MouseAdapter() { | |
| 90 | + @Override | |
| 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 | + ClassTreeNode node = | |
| 97 | + (ClassTreeNode)selPath.getLastPathComponent(); | |
| 98 | + // If user clicks on leaf, select it, and issue 'view' command. | |
| 99 | + if (node.isLeaf()) { | |
| 100 | + tree.setSelectionPath(selPath); | |
| 101 | + interpreter.executeCommand("view " + node.getReferenceTypeName()); | |
| 102 | + } | |
| 103 | + } | |
| 104 | + } | |
| 105 | + } | |
| 106 | + }; | |
| 107 | + tree.addMouseListener(ml); | |
| 108 | + | |
| 109 | + JScrollPane treeView = new JScrollPane(tree); | |
| 110 | + add(treeView); | |
| 111 | + | |
| 112 | + // Create listener. | |
| 113 | + ClassTreeToolListener listener = new ClassTreeToolListener(); | |
| 114 | + runtime.addJDIListener(listener); | |
| 115 | + runtime.addSessionListener(listener); | |
| 116 | + | |
| 117 | + //### remove listeners on exit! | |
| 118 | + } | |
| 119 | + | |
| 120 | + private class ClassTreeToolListener extends JDIAdapter | |
| 121 | + implements JDIListener, SessionListener { | |
| 122 | + | |
| 123 | + // SessionListener | |
| 124 | + | |
| 125 | + @Override | |
| 126 | + public void sessionStart(EventObject e) { | |
| 127 | + // Get system classes and any others loaded before attaching. | |
| 128 | + try { | |
| 129 | + for (ReferenceType type : runtime.allClasses()) { | |
| 130 | + root.addClass(type); | |
| 131 | + } | |
| 132 | + } catch (VMDisconnectedException ee) { | |
| 133 | + // VM terminated unexpectedly. | |
| 134 | + } catch (NoSessionException ee) { | |
| 135 | + // Ignore. Should not happen. | |
| 136 | + } | |
| 137 | + } | |
| 138 | + | |
| 139 | + @Override | |
| 140 | + public void sessionInterrupt(EventObject e) {} | |
| 141 | + @Override | |
| 142 | + public void sessionContinue(EventObject e) {} | |
| 143 | + | |
| 144 | + // JDIListener | |
| 145 | + | |
| 146 | + @Override | |
| 147 | + public void classPrepare(ClassPrepareEventSet e) { | |
| 148 | + root.addClass(e.getReferenceType()); | |
| 149 | + } | |
| 150 | + | |
| 151 | + @Override | |
| 152 | + public void classUnload(ClassUnloadEventSet e) { | |
| 153 | + root.removeClass(e.getClassName()); | |
| 154 | + } | |
| 155 | + | |
| 156 | + @Override | |
| 157 | + public void vmDisconnect(VMDisconnectEventSet e) { | |
| 158 | + // Clear contents of this view. | |
| 159 | + root = createClassTree(HEADING); | |
| 160 | + treeModel = new DefaultTreeModel(root); | |
| 161 | + tree.setModel(treeModel); | |
| 162 | + } | |
| 163 | + } | |
| 164 | + | |
| 165 | + ClassTreeNode createClassTree(String label) { | |
| 166 | + return new ClassTreeNode(label, null); | |
| 167 | + } | |
| 168 | + | |
| 169 | + class ClassTreeNode extends DefaultMutableTreeNode { | |
| 170 | + | |
| 171 | + private String name; | |
| 172 | + private ReferenceType refTy; // null for package | |
| 173 | + | |
| 174 | + ClassTreeNode(String name, ReferenceType refTy) { | |
| 175 | + this.name = name; | |
| 176 | + this.refTy = refTy; | |
| 177 | + } | |
| 178 | + | |
| 179 | + @Override | |
| 180 | + public String toString() { | |
| 181 | + return name; | |
| 182 | + } | |
| 183 | + | |
| 184 | + public ReferenceType getReferenceType() { | |
| 185 | + return refTy; | |
| 186 | + } | |
| 187 | + | |
| 188 | + public String getReferenceTypeName() { | |
| 189 | + return refTy.name(); | |
| 190 | + } | |
| 191 | + | |
| 192 | + private boolean isPackage() { | |
| 193 | + return (refTy == null); | |
| 194 | + } | |
| 195 | + | |
| 196 | + @Override | |
| 197 | + public boolean isLeaf() { | |
| 198 | + return !isPackage(); | |
| 199 | + } | |
| 200 | + | |
| 201 | + public void addClass(ReferenceType refTy) { | |
| 202 | + addClass(refTy.name(), refTy); | |
| 203 | + } | |
| 204 | + | |
| 205 | + private void addClass(String className, ReferenceType refTy) { | |
| 206 | + if (className.equals("")) { | |
| 207 | + return; | |
| 208 | + } | |
| 209 | + int pos = className.indexOf('.'); | |
| 210 | + if (pos < 0) { | |
| 211 | + insertNode(className, refTy); | |
| 212 | + } else { | |
| 213 | + String head = className.substring(0, pos); | |
| 214 | + String tail = className.substring(pos + 1); | |
| 215 | + ClassTreeNode child = insertNode(head, null); | |
| 216 | + child.addClass(tail, refTy); | |
| 217 | + } | |
| 218 | + } | |
| 219 | + | |
| 220 | + private ClassTreeNode insertNode(String name, ReferenceType refTy) { | |
| 221 | + for (int i = 0; i < getChildCount(); i++) { | |
| 222 | + ClassTreeNode child = (ClassTreeNode)getChildAt(i); | |
| 223 | + int cmp = name.compareTo(child.toString()); | |
| 224 | + if (cmp == 0) { | |
| 225 | + // like-named node already exists | |
| 226 | + return child; | |
| 227 | + } else if (cmp < 0) { | |
| 228 | + // insert new node before the child | |
| 229 | + ClassTreeNode newChild = new ClassTreeNode(name, refTy); | |
| 230 | + treeModel.insertNodeInto(newChild, this, i); | |
| 231 | + return newChild; | |
| 232 | + } | |
| 233 | + } | |
| 234 | + // insert new node after last child | |
| 235 | + ClassTreeNode newChild = new ClassTreeNode(name, refTy); | |
| 236 | + treeModel.insertNodeInto(newChild, this, getChildCount()); | |
| 237 | + return newChild; | |
| 238 | + } | |
| 239 | + | |
| 240 | + public void removeClass(String className) { | |
| 241 | + if (className.equals("")) { | |
| 242 | + return; | |
| 243 | + } | |
| 244 | + int pos = className.indexOf('.'); | |
| 245 | + if (pos < 0) { | |
| 246 | + ClassTreeNode child = findNode(className); | |
| 247 | + if (!isPackage()) { | |
| 248 | + treeModel.removeNodeFromParent(child); | |
| 249 | + } | |
| 250 | + } else { | |
| 251 | + String head = className.substring(0, pos); | |
| 252 | + String tail = className.substring(pos + 1); | |
| 253 | + ClassTreeNode child = findNode(head); | |
| 254 | + child.removeClass(tail); | |
| 255 | + if (isPackage() && child.getChildCount() < 1) { | |
| 256 | + // Prune non-leaf nodes with no children. | |
| 257 | + treeModel.removeNodeFromParent(child); | |
| 258 | + } | |
| 259 | + } | |
| 260 | + } | |
| 261 | + | |
| 262 | + private ClassTreeNode findNode(String name) { | |
| 263 | + for (int i = 0; i < getChildCount(); i++) { | |
| 264 | + ClassTreeNode child = (ClassTreeNode)getChildAt(i); | |
| 265 | + int cmp = name.compareTo(child.toString()); | |
| 266 | + if (cmp == 0) { | |
| 267 | + return child; | |
| 268 | + } else if (cmp > 0) { | |
| 269 | + // not found, since children are sorted | |
| 270 | + return null; | |
| 271 | + } | |
| 272 | + } | |
| 273 | + return null; | |
| 274 | + } | |
| 275 | + | |
| 276 | + } | |
| 277 | + | |
| 278 | +} | |
| @@ -0,0 +1,1459 @@ | ||
| 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | +import java.util.*; | |
| 30 | + | |
| 31 | +import com.sun.jdi.*; | |
| 32 | +import com.sun.tools.example.debug.bdi.*; | |
| 33 | + | |
| 34 | +public class CommandInterpreter { | |
| 35 | + | |
| 36 | + boolean echo; | |
| 37 | + | |
| 38 | + Environment env; | |
| 39 | + | |
| 40 | + private ContextManager context; | |
| 41 | + private ExecutionManager runtime; | |
| 42 | + private ClassManager classManager; | |
| 43 | + private SourceManager sourceManager; | |
| 44 | + | |
| 45 | + private OutputSink out; //### Hack! Should be local in each method used. | |
| 46 | + private String lastCommand = "help"; | |
| 47 | + | |
| 48 | + public CommandInterpreter(Environment env) { | |
| 49 | + this(env, true); | |
| 50 | + } | |
| 51 | + | |
| 52 | + public CommandInterpreter(Environment env, boolean echo) { | |
| 53 | + this.env = env; | |
| 54 | + this.echo = echo; | |
| 55 | + this.runtime = env.getExecutionManager(); | |
| 56 | + this.context = env.getContextManager(); | |
| 57 | + this.classManager = env.getClassManager(); | |
| 58 | + this.sourceManager = env.getSourceManager(); | |
| 59 | + } | |
| 60 | + | |
| 61 | + private ThreadReference[] threads = null; | |
| 62 | + | |
| 63 | + /* | |
| 64 | + * The numbering of threads is relative to the current set of threads, | |
| 65 | + * and may be affected by the creation and termination of new threads. | |
| 66 | + * Commands issued using such thread ids will only give reliable behavior | |
| 67 | + * relative to what was shown earlier in 'list' commands if the VM is interrupted. | |
| 68 | + * We need a better scheme. | |
| 69 | + */ | |
| 70 | + | |
| 71 | + private ThreadReference[] threads() throws NoSessionException { | |
| 72 | + if (threads == null) { | |
| 73 | + ThreadIterator ti = new ThreadIterator(getDefaultThreadGroup()); | |
| 74 | + List<ThreadReference> tlist = new ArrayList<ThreadReference>(); | |
| 75 | + while (ti.hasNext()) { | |
| 76 | + tlist.add(ti.nextThread()); | |
| 77 | + } | |
| 78 | + threads = tlist.toArray(new ThreadReference[tlist.size()]); | |
| 79 | + } | |
| 80 | + return threads; | |
| 81 | + } | |
| 82 | + | |
| 83 | + private ThreadReference findThread(String idToken) throws NoSessionException { | |
| 84 | + String id; | |
| 85 | + ThreadReference thread = null; | |
| 86 | + if (idToken.startsWith("t@")) { | |
| 87 | + id = idToken.substring(2); | |
| 88 | + } else { | |
| 89 | + id = idToken; | |
| 90 | + } | |
| 91 | + try { | |
| 92 | + ThreadReference[] threads = threads(); | |
| 93 | + long threadID = Long.parseLong(id, 16); | |
| 94 | + for (ThreadReference thread2 : threads) { | |
| 95 | + if (thread2.uniqueID() == threadID) { | |
| 96 | + thread = thread2; | |
| 97 | + break; | |
| 98 | + } | |
| 99 | + } | |
| 100 | + if (thread == null) { | |
| 101 | + //env.failure("No thread for id \"" + idToken + "\""); | |
| 102 | + env.failure("\"" + idToken + "\" is not a valid thread id."); | |
| 103 | + } | |
| 104 | + } catch (NumberFormatException e) { | |
| 105 | + env.error("Thread id \"" + idToken + "\" is ill-formed."); | |
| 106 | + thread = null; | |
| 107 | + } | |
| 108 | + return thread; | |
| 109 | + } | |
| 110 | + | |
| 111 | + private ThreadIterator allThreads() throws NoSessionException { | |
| 112 | + threads = null; | |
| 113 | + //### Why not use runtime.allThreads().iterator() ? | |
| 114 | + return new ThreadIterator(runtime.topLevelThreadGroups()); | |
| 115 | + } | |
| 116 | + | |
| 117 | + private ThreadIterator currentThreadGroupThreads() throws NoSessionException { | |
| 118 | + threads = null; | |
| 119 | + return new ThreadIterator(getDefaultThreadGroup()); | |
| 120 | + } | |
| 121 | + | |
| 122 | + private ThreadGroupIterator allThreadGroups() throws NoSessionException { | |
| 123 | + threads = null; | |
| 124 | + return new ThreadGroupIterator(runtime.topLevelThreadGroups()); | |
| 125 | + } | |
| 126 | + | |
| 127 | + private ThreadGroupReference defaultThreadGroup; | |
| 128 | + | |
| 129 | + private ThreadGroupReference getDefaultThreadGroup() throws NoSessionException { | |
| 130 | + if (defaultThreadGroup == null) { | |
| 131 | + defaultThreadGroup = runtime.systemThreadGroup(); | |
| 132 | + } | |
| 133 | + return defaultThreadGroup; | |
| 134 | + } | |
| 135 | + | |
| 136 | + private void setDefaultThreadGroup(ThreadGroupReference tg) { | |
| 137 | + defaultThreadGroup = tg; | |
| 138 | + } | |
| 139 | + | |
| 140 | + /* | |
| 141 | + * Command handlers. | |
| 142 | + */ | |
| 143 | + | |
| 144 | + // Command: classes | |
| 145 | + | |
| 146 | + private void commandClasses() throws NoSessionException { | |
| 147 | + OutputSink out = env.getOutputSink(); | |
| 148 | + //out.println("** classes list **"); | |
| 149 | + for (ReferenceType refType : runtime.allClasses()) { | |
| 150 | + out.println(refType.name()); | |
| 151 | + } | |
| 152 | + out.show(); | |
| 153 | + } | |
| 154 | + | |
| 155 | + | |
| 156 | + // Command: methods | |
| 157 | + | |
| 158 | + private void commandMethods(StringTokenizer t) throws NoSessionException { | |
| 159 | + if (!t.hasMoreTokens()) { | |
| 160 | + env.error("No class specified."); | |
| 161 | + return; | |
| 162 | + } | |
| 163 | + String idClass = t.nextToken(); | |
| 164 | + ReferenceType cls = findClass(idClass); | |
| 165 | + if (cls != null) { | |
| 166 | + List<Method> methods = cls.allMethods(); | |
| 167 | + OutputSink out = env.getOutputSink(); | |
| 168 | + for (int i = 0; i < methods.size(); i++) { | |
| 169 | + Method method = methods.get(i); | |
| 170 | + out.print(method.declaringType().name() + " " + | |
| 171 | + method.name() + "("); | |
| 172 | + Iterator<String> it = method.argumentTypeNames().iterator(); | |
| 173 | + if (it.hasNext()) { | |
| 174 | + while (true) { | |
| 175 | + out.print(it.next()); | |
| 176 | + if (!it.hasNext()) { | |
| 177 | + break; | |
| 178 | + } | |
| 179 | + out.print(", "); | |
| 180 | + } | |
| 181 | + } | |
| 182 | + out.println(")"); | |
| 183 | + } | |
| 184 | + out.show(); | |
| 185 | + } else { | |
| 186 | + //### Should validate class name syntax. | |
| 187 | + env.failure("\"" + idClass + "\" is not a valid id or class name."); | |
| 188 | + } | |
| 189 | + } | |
| 190 | + | |
| 191 | + private ReferenceType findClass(String pattern) throws NoSessionException { | |
| 192 | + List<ReferenceType> results = runtime.findClassesMatchingPattern(pattern); | |
| 193 | + if (results.size() > 0) { | |
| 194 | + //### Should handle multiple results sensibly. | |
| 195 | + return results.get(0); | |
| 196 | + } | |
| 197 | + return null; | |
| 198 | + } | |
| 199 | + | |
| 200 | + // Command: threads | |
| 201 | + | |
| 202 | + private void commandThreads(StringTokenizer t) throws NoSessionException { | |
| 203 | + if (!t.hasMoreTokens()) { | |
| 204 | + OutputSink out = env.getOutputSink(); | |
| 205 | + printThreadGroup(out, getDefaultThreadGroup(), 0); | |
| 206 | + out.show(); | |
| 207 | + return; | |
| 208 | + } | |
| 209 | + String name = t.nextToken(); | |
| 210 | + ThreadGroupReference tg = findThreadGroup(name); | |
| 211 | + if (tg == null) { | |
| 212 | + env.failure(name + " is not a valid threadgroup name."); | |
| 213 | + } else { | |
| 214 | + OutputSink out = env.getOutputSink(); | |
| 215 | + printThreadGroup(out, tg, 0); | |
| 216 | + out.show(); | |
| 217 | + } | |
| 218 | + } | |
| 219 | + | |
| 220 | + private ThreadGroupReference findThreadGroup(String name) throws NoSessionException { | |
| 221 | + //### Issue: Uniqueness of thread group names is not enforced. | |
| 222 | + ThreadGroupIterator tgi = allThreadGroups(); | |
| 223 | + while (tgi.hasNext()) { | |
| 224 | + ThreadGroupReference tg = tgi.nextThreadGroup(); | |
| 225 | + if (tg.name().equals(name)) { | |
| 226 | + return tg; | |
| 227 | + } | |
| 228 | + } | |
| 229 | + return null; | |
| 230 | + } | |
| 231 | + | |
| 232 | + private int printThreadGroup(OutputSink out, ThreadGroupReference tg, int iThread) { | |
| 233 | + out.println("Group " + tg.name() + ":"); | |
| 234 | + List<ThreadReference> tlist = tg.threads(); | |
| 235 | + int maxId = 0; | |
| 236 | + int maxName = 0; | |
| 237 | + for (int i = 0 ; i < tlist.size() ; i++) { | |
| 238 | + ThreadReference thr = tlist.get(i); | |
| 239 | + int len = Utils.description(thr).length(); | |
| 240 | + if (len > maxId) { | |
| 241 | + maxId = len; | |
| 242 | + } | |
| 243 | + String name = thr.name(); | |
| 244 | + int iDot = name.lastIndexOf('.'); | |
| 245 | + if (iDot >= 0 && name.length() > iDot) { | |
| 246 | + name = name.substring(iDot + 1); | |
| 247 | + } | |
| 248 | + if (name.length() > maxName) { | |
| 249 | + maxName = name.length(); | |
| 250 | + } | |
| 251 | + } | |
| 252 | + String maxNumString = String.valueOf(iThread + tlist.size()); | |
| 253 | + int maxNumDigits = maxNumString.length(); | |
| 254 | + for (int i = 0 ; i < tlist.size() ; i++) { | |
| 255 | + ThreadReference thr = tlist.get(i); | |
| 256 | + char buf[] = new char[80]; | |
| 257 | + for (int j = 0; j < 79; j++) { | |
| 258 | + buf[j] = ' '; | |
| 259 | + } | |
| 260 | + buf[79] = '\0'; | |
| 261 | + StringBuffer sbOut = new StringBuffer(); | |
| 262 | + sbOut.append(buf); | |
| 263 | + | |
| 264 | + // Right-justify the thread number at start of output string | |
| 265 | + String numString = String.valueOf(iThread + i + 1); | |
| 266 | + sbOut.insert(maxNumDigits - numString.length(), | |
| 267 | + numString); | |
| 268 | + sbOut.insert(maxNumDigits, "."); | |
| 269 | + | |
| 270 | + int iBuf = maxNumDigits + 2; | |
| 271 | + sbOut.insert(iBuf, Utils.description(thr)); | |
| 272 | + iBuf += maxId + 1; | |
| 273 | + String name = thr.name(); | |
| 274 | + int iDot = name.lastIndexOf('.'); | |
| 275 | + if (iDot >= 0 && name.length() > iDot) { | |
| 276 | + name = name.substring(iDot + 1); | |
| 277 | + } | |
| 278 | + sbOut.insert(iBuf, name); | |
| 279 | + iBuf += maxName + 1; | |
| 280 | + sbOut.insert(iBuf, Utils.getStatus(thr)); | |
| 281 | + sbOut.setLength(79); | |
| 282 | + out.println(sbOut.toString()); | |
| 283 | + } | |
| 284 | + for (ThreadGroupReference tg0 : tg.threadGroups()) { | |
| 285 | + if (!tg.equals(tg0)) { // TODO ref mgt | |
| 286 | + iThread += printThreadGroup(out, tg0, iThread + tlist.size()); | |
| 287 | + } | |
| 288 | + } | |
| 289 | + return tlist.size(); | |
| 290 | + } | |
| 291 | + | |
| 292 | + // Command: threadgroups | |
| 293 | + | |
| 294 | + private void commandThreadGroups() throws NoSessionException { | |
| 295 | + ThreadGroupIterator it = allThreadGroups(); | |
| 296 | + int cnt = 0; | |
| 297 | + OutputSink out = env.getOutputSink(); | |
| 298 | + while (it.hasNext()) { | |
| 299 | + ThreadGroupReference tg = it.nextThreadGroup(); | |
| 300 | + ++cnt; | |
| 301 | + out.println("" + cnt + ". " + Utils.description(tg) + " " + tg.name()); | |
| 302 | + } | |
| 303 | + out.show(); | |
| 304 | + } | |
| 305 | + | |
| 306 | + // Command: thread | |
| 307 | + | |
| 308 | + private void commandThread(StringTokenizer t) throws NoSessionException { | |
| 309 | + if (!t.hasMoreTokens()) { | |
| 310 | + env.error("Thread number not specified."); | |
| 311 | + return; | |
| 312 | + } | |
| 313 | + ThreadReference thread = findThread(t.nextToken()); | |
| 314 | + if (thread != null) { | |
| 315 | + //### Should notify user. | |
| 316 | + context.setCurrentThread(thread); | |
| 317 | + } | |
| 318 | + } | |
| 319 | + | |
| 320 | + // Command: threadgroup | |
| 321 | + | |
| 322 | + private void commandThreadGroup(StringTokenizer t) throws NoSessionException { | |
| 323 | + if (!t.hasMoreTokens()) { | |
| 324 | + env.error("Threadgroup name not specified."); | |
| 325 | + return; | |
| 326 | + } | |
| 327 | + String name = t.nextToken(); | |
| 328 | + ThreadGroupReference tg = findThreadGroup(name); | |
| 329 | + if (tg == null) { | |
| 330 | + env.failure(name + " is not a valid threadgroup name."); | |
| 331 | + } else { | |
| 332 | + //### Should notify user. | |
| 333 | + setDefaultThreadGroup(tg); | |
| 334 | + } | |
| 335 | + } | |
| 336 | + | |
| 337 | + // Command: run | |
| 338 | + | |
| 339 | + private void commandRun(StringTokenizer t) throws NoSessionException { | |
| 340 | + if (doLoad(false, t)) { | |
| 341 | + env.notice("Running ..."); | |
| 342 | + } | |
| 343 | + } | |
| 344 | + | |
| 345 | + // Command: load | |
| 346 | + | |
| 347 | + private void commandLoad(StringTokenizer t) throws NoSessionException { | |
| 348 | + if (doLoad(true, t)) {} | |
| 349 | + } | |
| 350 | + | |
| 351 | + private boolean doLoad(boolean suspended, | |
| 352 | + StringTokenizer t) throws NoSessionException { | |
| 353 | + | |
| 354 | + String clname; | |
| 355 | + | |
| 356 | + if (!t.hasMoreTokens()) { | |
| 357 | + clname = context.getMainClassName(); | |
| 358 | + if (!clname.equals("")) { | |
| 359 | + // Run from prevously-set class name. | |
| 360 | + try { | |
| 361 | + String vmArgs = context.getVmArguments(); | |
| 362 | + runtime.run(suspended, | |
| 363 | + vmArgs, | |
| 364 | + clname, | |
| 365 | + context.getProgramArguments()); | |
| 366 | + return true; | |
| 367 | + } catch (VMLaunchFailureException e) { | |
| 368 | + env.failure("Attempt to launch main class \"" + clname + "\" failed."); | |
| 369 | + } | |
| 370 | + } else { | |
| 371 | + env.failure("No main class specifed and no current default defined."); | |
| 372 | + } | |
| 373 | + } else { | |
| 374 | + clname = t.nextToken(); | |
| 375 | + StringBuffer sbuf = new StringBuffer(); | |
| 376 | + // Allow VM arguments to be specified here? | |
| 377 | + while (t.hasMoreTokens()) { | |
| 378 | + String tok = t.nextToken(); | |
| 379 | + sbuf.append(tok); | |
| 380 | + if (t.hasMoreTokens()) { | |
| 381 | + sbuf.append(' '); | |
| 382 | + } | |
| 383 | + } | |
| 384 | + String args = sbuf.toString(); | |
| 385 | + try { | |
| 386 | + String vmArgs = context.getVmArguments(); | |
| 387 | + runtime.run(suspended, vmArgs, clname, args); | |
| 388 | + context.setMainClassName(clname); | |
| 389 | + //context.setVmArguments(vmArgs); | |
| 390 | + context.setProgramArguments(args); | |
| 391 | + return true; | |
| 392 | + } catch (VMLaunchFailureException e) { | |
| 393 | + env.failure("Attempt to launch main class \"" + clname + "\" failed."); | |
| 394 | + } | |
| 395 | + } | |
| 396 | + return false; | |
| 397 | + } | |
| 398 | + | |
| 399 | + // Command: connect | |
| 400 | + | |
| 401 | + private void commandConnect(StringTokenizer t) { | |
| 402 | + try { | |
| 403 | + LaunchTool.queryAndLaunchVM(runtime); | |
| 404 | + } catch (VMLaunchFailureException e) { | |
| 405 | + env.failure("Attempt to connect failed."); | |
| 406 | + } | |
| 407 | + } | |
| 408 | + | |
| 409 | + // Command: attach | |
| 410 | + | |
| 411 | + private void commandAttach(StringTokenizer t) { | |
| 412 | + String portName; | |
| 413 | + if (!t.hasMoreTokens()) { | |
| 414 | + portName = context.getRemotePort(); | |
| 415 | + if (!portName.equals("")) { | |
| 416 | + try { | |
| 417 | + runtime.attach(portName); | |
| 418 | + } catch (VMLaunchFailureException e) { | |
| 419 | + env.failure("Attempt to attach to port \"" + portName + "\" failed."); | |
| 420 | + } | |
| 421 | + } else { | |
| 422 | + env.failure("No port specifed and no current default defined."); | |
| 423 | + } | |
| 424 | + } else { | |
| 425 | + portName = t.nextToken(); | |
| 426 | + try { | |
| 427 | + runtime.attach(portName); | |
| 428 | + } catch (VMLaunchFailureException e) { | |
| 429 | + env.failure("Attempt to attach to port \"" + portName + "\" failed."); | |
| 430 | + } | |
| 431 | + context.setRemotePort(portName); | |
| 432 | + } | |
| 433 | + } | |
| 434 | + | |
| 435 | + // Command: detach | |
| 436 | + | |
| 437 | + private void commandDetach(StringTokenizer t) throws NoSessionException { | |
| 438 | + runtime.detach(); | |
| 439 | + } | |
| 440 | + | |
| 441 | + // Command: interrupt | |
| 442 | + | |
| 443 | + private void commandInterrupt(StringTokenizer t) throws NoSessionException { | |
| 444 | + runtime.interrupt(); | |
| 445 | + } | |
| 446 | + | |
| 447 | + // Command: suspend | |
| 448 | + | |
| 449 | + private void commandSuspend(StringTokenizer t) throws NoSessionException { | |
| 450 | + if (!t.hasMoreTokens()) { | |
| 451 | + // Suspend all threads in the current thread group. | |
| 452 | + //### Issue: help message says default is all threads. | |
| 453 | + //### Behavior here agrees with 'jdb', however. | |
| 454 | + ThreadIterator ti = currentThreadGroupThreads(); | |
| 455 | + while (ti.hasNext()) { | |
| 456 | + // TODO - don't suspend debugger threads | |
| 457 | + ti.nextThread().suspend(); | |
| 458 | + } | |
| 459 | + env.notice("All (non-system) threads suspended."); | |
| 460 | + } else { | |
| 461 | + while (t.hasMoreTokens()) { | |
| 462 | + ThreadReference thread = findThread(t.nextToken()); | |
| 463 | + if (thread != null) { | |
| 464 | + //thread.suspend(); | |
| 465 | + runtime.suspendThread(thread); | |
| 466 | + } | |
| 467 | + } | |
| 468 | + } | |
| 469 | + } | |
| 470 | + | |
| 471 | + // Command: resume | |
| 472 | + | |
| 473 | + private void commandResume(StringTokenizer t) throws NoSessionException { | |
| 474 | + if (!t.hasMoreTokens()) { | |
| 475 | + // Suspend all threads in the current thread group. | |
| 476 | + //### Issue: help message says default is all threads. | |
| 477 | + //### Behavior here agrees with 'jdb', however. | |
| 478 | + ThreadIterator ti = currentThreadGroupThreads(); | |
| 479 | + while (ti.hasNext()) { | |
| 480 | + // TODO - don't suspend debugger threads | |
| 481 | + ti.nextThread().resume(); | |
| 482 | + } | |
| 483 | + env.notice("All threads resumed."); | |
| 484 | + } else { | |
| 485 | + while (t.hasMoreTokens()) { | |
| 486 | + ThreadReference thread = findThread(t.nextToken()); | |
| 487 | + if (thread != null) { | |
| 488 | + //thread.resume(); | |
| 489 | + runtime.resumeThread(thread); | |
| 490 | + } | |
| 491 | + } | |
| 492 | + } | |
| 493 | + } | |
| 494 | + | |
| 495 | + // Command: cont | |
| 496 | + | |
| 497 | + private void commandCont() throws NoSessionException { | |
| 498 | + try { | |
| 499 | + runtime.go(); | |
| 500 | + } catch (VMNotInterruptedException e) { | |
| 501 | + //### failure? | |
| 502 | + env.notice("Target VM is already running."); | |
| 503 | + } | |
| 504 | + } | |
| 505 | + | |
| 506 | + // Command: step | |
| 507 | + | |
| 508 | + private void commandStep(StringTokenizer t) throws NoSessionException{ | |
| 509 | + ThreadReference current = context.getCurrentThread(); | |
| 510 | + if (current == null) { | |
| 511 | + env.failure("No current thread."); | |
| 512 | + return; | |
| 513 | + } | |
| 514 | + try { | |
| 515 | + if (t.hasMoreTokens() && | |
| 516 | + t.nextToken().toLowerCase().equals("up")) { | |
| 517 | + runtime.stepOut(current); | |
| 518 | + } else { | |
| 519 | + runtime.stepIntoLine(current); | |
| 520 | + } | |
| 521 | + } catch (AbsentInformationException e) { | |
| 522 | + env.failure("No linenumber information available -- " + | |
| 523 | + "Try \"stepi\" to step by instructions."); | |
| 524 | + } | |
| 525 | + } | |
| 526 | + | |
| 527 | + // Command: stepi | |
| 528 | + | |
| 529 | + private void commandStepi() throws NoSessionException { | |
| 530 | + ThreadReference current = context.getCurrentThread(); | |
| 531 | + if (current == null) { | |
| 532 | + env.failure("No current thread."); | |
| 533 | + return; | |
| 534 | + } | |
| 535 | + runtime.stepIntoInstruction(current); | |
| 536 | + } | |
| 537 | + | |
| 538 | + // Command: next | |
| 539 | + | |
| 540 | + private void commandNext() throws NoSessionException { | |
| 541 | + ThreadReference current = context.getCurrentThread(); | |
| 542 | + if (current == null) { | |
| 543 | + env.failure("No current thread."); | |
| 544 | + return; | |
| 545 | + } | |
| 546 | + try { | |
| 547 | + runtime.stepOverLine(current); | |
| 548 | + } catch (AbsentInformationException e) { | |
| 549 | + env.failure("No linenumber information available -- " + | |
| 550 | + "Try \"nexti\" to step by instructions."); | |
| 551 | + } | |
| 552 | + } | |
| 553 | + | |
| 554 | + // Command: nexti (NEW) | |
| 555 | + | |
| 556 | + private void commandNexti() throws NoSessionException { | |
| 557 | + ThreadReference current = context.getCurrentThread(); | |
| 558 | + if (current == null) { | |
| 559 | + env.failure("No current thread."); | |
| 560 | + return; | |
| 561 | + } | |
| 562 | + runtime.stepOverInstruction(current); | |
| 563 | + } | |
| 564 | + | |
| 565 | + // Command: kill | |
| 566 | + | |
| 567 | + private void commandKill(StringTokenizer t) throws NoSessionException { | |
| 568 | + //### Should change the way in which thread ids and threadgroup names | |
| 569 | + //### are distinguished. | |
| 570 | + if (!t.hasMoreTokens()) { | |
| 571 | + env.error("Usage: kill <threadgroup name> or <thread id>"); | |
| 572 | + return; | |
| 573 | + } | |
| 574 | + while (t.hasMoreTokens()) { | |
| 575 | + String idToken = t.nextToken(); | |
| 576 | + ThreadReference thread = findThread(idToken); | |
| 577 | + if (thread != null) { | |
| 578 | + runtime.stopThread(thread); | |
| 579 | + env.notice("Thread " + thread.name() + " killed."); | |
| 580 | + return; | |
| 581 | + } else { | |
| 582 | + /* Check for threadgroup name, NOT skipping "system". */ | |
| 583 | + //### Should skip "system"? Classic 'jdb' does this. | |
| 584 | + //### Should deal with possible non-uniqueness of threadgroup names. | |
| 585 | + ThreadGroupIterator itg = allThreadGroups(); | |
| 586 | + while (itg.hasNext()) { | |
| 587 | + ThreadGroupReference tg = itg.nextThreadGroup(); | |
| 588 | + if (tg.name().equals(idToken)) { | |
| 589 | + ThreadIterator it = new ThreadIterator(tg); | |
| 590 | + while (it.hasNext()) { | |
| 591 | + runtime.stopThread(it.nextThread()); | |
| 592 | + } | |
| 593 | + env.notice("Threadgroup " + tg.name() + "killed."); | |
| 594 | + return; | |
| 595 | + } | |
| 596 | + } | |
| 597 | + env.failure("\"" + idToken + | |
| 598 | + "\" is not a valid threadgroup or id."); | |
| 599 | + } | |
| 600 | + } | |
| 601 | + } | |
| 602 | + | |
| 603 | + | |
| 604 | + /************* | |
| 605 | + // TODO | |
| 606 | + private void commandCatchException(StringTokenizer t) throws NoSessionException {} | |
| 607 | + // TODO | |
| 608 | + private void commandIgnoreException(StringTokenizer t) throws NoSessionException {} | |
| 609 | + *************/ | |
| 610 | + | |
| 611 | + // Command: up | |
| 612 | + | |
| 613 | + //### Print current frame after command? | |
| 614 | + | |
| 615 | + int readCount(StringTokenizer t) { | |
| 616 | + int cnt = 1; | |
| 617 | + if (t.hasMoreTokens()) { | |
| 618 | + String idToken = t.nextToken(); | |
| 619 | + try { | |
| 620 | + cnt = Integer.valueOf(idToken).intValue(); | |
| 621 | + } catch (NumberFormatException e) { | |
| 622 | + cnt = -1; | |
| 623 | + } | |
| 624 | + } | |
| 625 | + return cnt; | |
| 626 | + } | |
| 627 | + | |
| 628 | + void commandUp(StringTokenizer t) throws NoSessionException { | |
| 629 | + ThreadReference current = context.getCurrentThread(); | |
| 630 | + if (current == null) { | |
| 631 | + env.failure("No current thread."); | |
| 632 | + return; | |
| 633 | + } | |
| 634 | + int nLevels = readCount(t); | |
| 635 | + if (nLevels <= 0) { | |
| 636 | + env.error("usage: up [n frames]"); | |
| 637 | + return; | |
| 638 | + } | |
| 639 | + try { | |
| 640 | + int delta = context.moveCurrentFrameIndex(current, -nLevels); | |
| 641 | + if (delta == 0) { | |
| 642 | + env.notice("Already at top of stack."); | |
| 643 | + } else if (-delta < nLevels) { | |
| 644 | + env.notice("Moved up " + delta + " frames to top of stack."); | |
| 645 | + } | |
| 646 | + } catch (VMNotInterruptedException e) { | |
| 647 | + env.failure("Target VM must be in interrupted state."); | |
| 648 | + } | |
| 649 | + } | |
| 650 | + | |
| 651 | + private void commandDown(StringTokenizer t) throws NoSessionException { | |
| 652 | + ThreadReference current = context.getCurrentThread(); | |
| 653 | + if (current == null) { | |
| 654 | + env.failure("No current thread."); | |
| 655 | + return; | |
| 656 | + } | |
| 657 | + int nLevels = readCount(t); | |
| 658 | + if (nLevels <= 0) { | |
| 659 | + env.error("usage: down [n frames]"); | |
| 660 | + return; | |
| 661 | + } | |
| 662 | + try { | |
| 663 | + int delta = context.moveCurrentFrameIndex(current, nLevels); | |
| 664 | + if (delta == 0) { | |
| 665 | + env.notice("Already at bottom of stack."); | |
| 666 | + } else if (delta < nLevels) { | |
| 667 | + env.notice("Moved down " + delta + " frames to bottom of stack."); | |
| 668 | + } | |
| 669 | + } catch (VMNotInterruptedException e) { | |
| 670 | + env.failure("Target VM must be in interrupted state."); | |
| 671 | + } | |
| 672 | + } | |
| 673 | + | |
| 674 | + // Command: frame | |
| 675 | + | |
| 676 | + private void commandFrame(StringTokenizer t) throws NoSessionException { | |
| 677 | + ThreadReference current = context.getCurrentThread(); | |
| 678 | + if (current == null) { | |
| 679 | + env.failure("No current thread."); | |
| 680 | + return; | |
| 681 | + } | |
| 682 | + if (!t.hasMoreTokens()) { | |
| 683 | + env.error("usage: frame <frame-index>"); | |
| 684 | + return; | |
| 685 | + } | |
| 686 | + String idToken = t.nextToken(); | |
| 687 | + int n; | |
| 688 | + try { | |
| 689 | + n = Integer.valueOf(idToken).intValue(); | |
| 690 | + } catch (NumberFormatException e) { | |
| 691 | + n = 0; | |
| 692 | + } | |
| 693 | + if (n <= 0) { | |
| 694 | + env.error("use positive frame index"); | |
| 695 | + return; | |
| 696 | + } | |
| 697 | + try { | |
| 698 | + int delta = context.setCurrentFrameIndex(current, n); | |
| 699 | + if (delta == 0) { | |
| 700 | + env.notice("Frame unchanged."); | |
| 701 | + } else if (delta < 0) { | |
| 702 | + env.notice("Moved up " + -delta + " frames."); | |
| 703 | + } else { | |
| 704 | + env.notice("Moved down " + delta + " frames."); | |
| 705 | + } | |
| 706 | + } catch (VMNotInterruptedException e) { | |
| 707 | + env.failure("Target VM must be in interrupted state."); | |
| 708 | + } | |
| 709 | + } | |
| 710 | + | |
| 711 | + // Command: where | |
| 712 | + | |
| 713 | + //### Should we insist that VM be interrupted here? | |
| 714 | + //### There is an inconsistency between the 'where' command | |
| 715 | + //### and 'up' and 'down' in this respect. | |
| 716 | + | |
| 717 | + private void commandWhere(StringTokenizer t, boolean showPC) | |
| 718 | + throws NoSessionException { | |
| 719 | + ThreadReference current = context.getCurrentThread(); | |
| 720 | + if (!t.hasMoreTokens()) { | |
| 721 | + if (current == null) { | |
| 722 | + env.error("No thread specified."); | |
| 723 | + return; | |
| 724 | + } | |
| 725 | + dumpStack(current, showPC); | |
| 726 | + } else { | |
| 727 | + String token = t.nextToken(); | |
| 728 | + if (token.toLowerCase().equals("all")) { | |
| 729 | + ThreadIterator it = allThreads(); | |
| 730 | + while (it.hasNext()) { | |
| 731 | + ThreadReference thread = it.next(); | |
| 732 | + out.println(thread.name() + ": "); | |
| 733 | + dumpStack(thread, showPC); | |
| 734 | + } | |
| 735 | + } else { | |
| 736 | + ThreadReference thread = findThread(t.nextToken()); | |
| 737 | + //### Do we want to set current thread here? | |
| 738 | + //### Should notify user of change. | |
| 739 | + if (thread != null) { | |
| 740 | + context.setCurrentThread(thread); | |
| 741 | + } | |
| 742 | + dumpStack(thread, showPC); | |
| 743 | + } | |
| 744 | + } | |
| 745 | + } | |
| 746 | + | |
| 747 | + private void dumpStack(ThreadReference thread, boolean showPC) { | |
| 748 | + //### Check for these. | |
| 749 | + //env.failure("Thread no longer exists."); | |
| 750 | + //env.failure("Target VM must be in interrupted state."); | |
| 751 | + //env.failure("Current thread isn't suspended."); | |
| 752 | + //### Should handle extremely long stack traces sensibly for user. | |
| 753 | + List<StackFrame> stack = null; | |
| 754 | + try { | |
| 755 | + stack = thread.frames(); | |
| 756 | + } catch (IncompatibleThreadStateException e) { | |
| 757 | + env.failure("Thread is not suspended."); | |
| 758 | + } | |
| 759 | + //### Fix this! | |
| 760 | + //### Previously mishandled cases where thread was not current. | |
| 761 | + //### Now, prints all of the stack regardless of current frame. | |
| 762 | + int frameIndex = 0; | |
| 763 | + //int frameIndex = context.getCurrentFrameIndex(); | |
| 764 | + if (stack == null) { | |
| 765 | + env.failure("Thread is not running (no stack)."); | |
| 766 | + } else { | |
| 767 | + OutputSink out = env.getOutputSink(); | |
| 768 | + int nFrames = stack.size(); | |
| 769 | + for (int i = frameIndex; i < nFrames; i++) { | |
| 770 | + StackFrame frame = stack.get(i); | |
| 771 | + Location loc = frame.location(); | |
| 772 | + Method meth = loc.method(); | |
| 773 | + out.print(" [" + (i + 1) + "] "); | |
| 774 | + out.print(meth.declaringType().name()); | |
| 775 | + out.print('.'); | |
| 776 | + out.print(meth.name()); | |
| 777 | + out.print(" ("); | |
| 778 | + if (meth.isNative()) { | |
| 779 | + out.print("native method"); | |
| 780 | + } else if (loc.lineNumber() != -1) { | |
| 781 | + try { | |
| 782 | + out.print(loc.sourceName()); | |
| 783 | + } catch (AbsentInformationException e) { | |
| 784 | + out.print("<unknown>"); | |
| 785 | + } | |
| 786 | + out.print(':'); | |
| 787 | + out.print(loc.lineNumber()); | |
| 788 | + } | |
| 789 | + out.print(')'); | |
| 790 | + if (showPC) { | |
| 791 | + long pc = loc.codeIndex(); | |
| 792 | + if (pc != -1) { | |
| 793 | + out.print(", pc = " + pc); | |
| 794 | + } | |
| 795 | + } | |
| 796 | + out.println(); | |
| 797 | + } | |
| 798 | + out.show(); | |
| 799 | + } | |
| 800 | + } | |
| 801 | + | |
| 802 | + private void listEventRequests() throws NoSessionException { | |
| 803 | + // Print set breakpoints | |
| 804 | + List<EventRequestSpec> specs = runtime.eventRequestSpecs(); | |
| 805 | + if (specs.isEmpty()) { | |
| 806 | + env.notice("No breakpoints/watchpoints/exceptions set."); | |
| 807 | + } else { | |
| 808 | + OutputSink out = env.getOutputSink(); | |
| 809 | + out.println("Current breakpoints/watchpoints/exceptions set:"); | |
| 810 | + for (EventRequestSpec bp : specs) { | |
| 811 | + out.println("\t" + bp); | |
| 812 | + } | |
| 813 | + out.show(); | |
| 814 | + } | |
| 815 | + } | |
| 816 | + | |
| 817 | + private BreakpointSpec parseBreakpointSpec(String bptSpec) { | |
| 818 | + StringTokenizer t = new StringTokenizer(bptSpec); | |
| 819 | + BreakpointSpec bpSpec = null; | |
| 820 | +// try { | |
| 821 | + String token = t.nextToken("@:( \t\n\r"); | |
| 822 | + // We can't use hasMoreTokens here because it will cause any leading | |
| 823 | + // paren to be lost. | |
| 824 | + String rest; | |
| 825 | + try { | |
| 826 | + rest = t.nextToken("").trim(); | |
| 827 | + } catch (NoSuchElementException e) { | |
| 828 | + rest = null; | |
| 829 | + } | |
| 830 | + if ((rest != null) && rest.startsWith("@")) { | |
| 831 | + t = new StringTokenizer(rest.substring(1)); | |
| 832 | + String sourceName = token; | |
| 833 | + String lineToken = t.nextToken(); | |
| 834 | + int lineNumber = Integer.valueOf(lineToken).intValue(); | |
| 835 | + if (t.hasMoreTokens()) { | |
| 836 | + return null; | |
| 837 | + } | |
| 838 | + bpSpec = runtime.createSourceLineBreakpoint(sourceName, | |
| 839 | + lineNumber); | |
| 840 | + } else if ((rest != null) && rest.startsWith(":")) { | |
| 841 | + t = new StringTokenizer(rest.substring(1)); | |
| 842 | + String classId = token; | |
| 843 | + String lineToken = t.nextToken(); | |
| 844 | + int lineNumber = Integer.valueOf(lineToken).intValue(); | |
| 845 | + if (t.hasMoreTokens()) { | |
| 846 | + return null; | |
| 847 | + } | |
| 848 | + bpSpec = runtime.createClassLineBreakpoint(classId, lineNumber); | |
| 849 | + } else { | |
| 850 | + // Try stripping method from class.method token. | |
| 851 | + int idot = token.lastIndexOf("."); | |
| 852 | + if ( (idot <= 0) || /* No dot or dot in first char */ | |
| 853 | + (idot >= token.length() - 1) ) { /* dot in last char */ | |
| 854 | + return null; | |
| 855 | + } | |
| 856 | + String methodName = token.substring(idot + 1); | |
| 857 | + String classId = token.substring(0, idot); | |
| 858 | + List<String> argumentList = null; | |
| 859 | + if (rest != null) { | |
| 860 | + if (!rest.startsWith("(") || !rest.endsWith(")")) { | |
| 861 | + //### Should throw exception with error message | |
| 862 | + //out.println("Invalid method specification: " | |
| 863 | + // + methodName + rest); | |
| 864 | + return null; | |
| 865 | + } | |
| 866 | + // Trim the parens | |
| 867 | + //### What about spaces in arglist? | |
| 868 | + rest = rest.substring(1, rest.length() - 1); | |
| 869 | + argumentList = new ArrayList<String>(); | |
| 870 | + t = new StringTokenizer(rest, ","); | |
| 871 | + while (t.hasMoreTokens()) { | |
| 872 | + argumentList.add(t.nextToken()); | |
| 873 | + } | |
| 874 | + } | |
| 875 | + bpSpec = runtime.createMethodBreakpoint(classId, | |
| 876 | + methodName, | |
| 877 | + argumentList); | |
| 878 | + } | |
| 879 | +// } catch (Exception e) { | |
| 880 | +// env.error("Exception attempting to create breakpoint: " + e); | |
| 881 | +// return null; | |
| 882 | +// } | |
| 883 | + return bpSpec; | |
| 884 | + } | |
| 885 | + | |
| 886 | + private void commandStop(StringTokenizer t) throws NoSessionException { | |
| 887 | + String token; | |
| 888 | + | |
| 889 | + if (!t.hasMoreTokens()) { | |
| 890 | + listEventRequests(); | |
| 891 | + } else { | |
| 892 | + token = t.nextToken(); | |
| 893 | + // Ignore optional "at" or "in" token. | |
| 894 | + // Allowed for backward compatibility. | |
| 895 | + if (token.equals("at") || token.equals("in")) { | |
| 896 | + if (t.hasMoreTokens()) { | |
| 897 | + token = t.nextToken(); | |
| 898 | + } else { | |
| 899 | + env.error("Missing breakpoint specification."); | |
| 900 | + return; | |
| 901 | + } | |
| 902 | + } | |
| 903 | + BreakpointSpec bpSpec = parseBreakpointSpec(token); | |
| 904 | + if (bpSpec != null) { | |
| 905 | + //### Add sanity-checks for deferred breakpoint. | |
| 906 | + runtime.install(bpSpec); | |
| 907 | + } else { | |
| 908 | + env.error("Ill-formed breakpoint specification."); | |
| 909 | + } | |
| 910 | + } | |
| 911 | + } | |
| 912 | + | |
| 913 | + private void commandClear(StringTokenizer t) throws NoSessionException { | |
| 914 | + if (!t.hasMoreTokens()) { | |
| 915 | + // Print set breakpoints | |
| 916 | + listEventRequests(); | |
| 917 | + return; | |
| 918 | + } | |
| 919 | + //### need 'clear all' | |
| 920 | + BreakpointSpec bpSpec = parseBreakpointSpec(t.nextToken()); | |
| 921 | + if (bpSpec != null) { | |
| 922 | + List<EventRequestSpec> specs = runtime.eventRequestSpecs(); | |
| 923 | + | |
| 924 | + if (specs.isEmpty()) { | |
| 925 | + env.notice("No breakpoints set."); | |
| 926 | + } else { | |
| 927 | + List<EventRequestSpec> toDelete = new ArrayList<EventRequestSpec>(); | |
| 928 | + for (EventRequestSpec spec : specs) { | |
| 929 | + if (spec.equals(bpSpec)) { | |
| 930 | + toDelete.add(spec); | |
| 931 | + } | |
| 932 | + } | |
| 933 | + // The request used for matching should be found | |
| 934 | + if (toDelete.size() <= 1) { | |
| 935 | + env.notice("No matching breakpoint set."); | |
| 936 | + } | |
| 937 | + for (EventRequestSpec spec : toDelete) { | |
| 938 | + runtime.delete(spec); | |
| 939 | + } | |
| 940 | + } | |
| 941 | + } else { | |
| 942 | + env.error("Ill-formed breakpoint specification."); | |
| 943 | + } | |
| 944 | + } | |
| 945 | + | |
| 946 | + // Command: list | |
| 947 | + | |
| 948 | + private void commandList(StringTokenizer t) throws NoSessionException { | |
| 949 | + ThreadReference current = context.getCurrentThread(); | |
| 950 | + if (current == null) { | |
| 951 | + env.error("No thread specified."); | |
| 952 | + return; | |
| 953 | + } | |
| 954 | + Location loc; | |
| 955 | + try { | |
| 956 | + StackFrame frame = context.getCurrentFrame(current); | |
| 957 | + if (frame == null) { | |
| 958 | + env.failure("Thread has not yet begun execution."); | |
| 959 | + return; | |
| 960 | + } | |
| 961 | + loc = frame.location(); | |
| 962 | + } catch (VMNotInterruptedException e) { | |
| 963 | + env.failure("Target VM must be in interrupted state."); | |
| 964 | + return; | |
| 965 | + } | |
| 966 | + SourceModel source = sourceManager.sourceForLocation(loc); | |
| 967 | + if (source == null) { | |
| 968 | + if (loc.method().isNative()) { | |
| 969 | + env.failure("Current method is native."); | |
| 970 | + return; | |
| 971 | + } | |
| 972 | + env.failure("No source available for " + Utils.locationString(loc) + "."); | |
| 973 | + return; | |
| 974 | + } | |
| 975 | + ReferenceType refType = loc.declaringType(); | |
| 976 | + int lineno = loc.lineNumber(); | |
| 977 | + if (t.hasMoreTokens()) { | |
| 978 | + String id = t.nextToken(); | |
| 979 | + // See if token is a line number. | |
| 980 | + try { | |
| 981 | + lineno = Integer.valueOf(id).intValue(); | |
| 982 | + } catch (NumberFormatException nfe) { | |
| 983 | + // It isn't -- see if it's a method name. | |
| 984 | + List<Method> meths = refType.methodsByName(id); | |
| 985 | + if (meths == null || meths.size() == 0) { | |
| 986 | + env.failure(id + | |
| 987 | + " is not a valid line number or " + | |
| 988 | + "method name for class " + | |
| 989 | + refType.name()); | |
| 990 | + return; | |
| 991 | + } else if (meths.size() > 1) { | |
| 992 | + env.failure(id + | |
| 993 | + " is an ambiguous method name in" + | |
| 994 | + refType.name()); | |
| 995 | + return; | |
| 996 | + } | |
| 997 | + loc = meths.get(0).location(); | |
| 998 | + lineno = loc.lineNumber(); | |
| 999 | + } | |
| 1000 | + } | |
| 1001 | + int startLine = (lineno > 4) ? lineno - 4 : 1; | |
| 1002 | + int endLine = startLine + 9; | |
| 1003 | + String sourceLine = source.sourceLine(lineno); | |
| 1004 | + if (sourceLine == null) { | |
| 1005 | + env.failure("" + | |
| 1006 | + lineno + | |
| 1007 | + " is an invalid line number for " + | |
| 1008 | + refType.name()); | |
| 1009 | + } else { | |
| 1010 | + OutputSink out = env.getOutputSink(); | |
| 1011 | + for (int i = startLine; i <= endLine; i++) { | |
| 1012 | + sourceLine = source.sourceLine(i); | |
| 1013 | + if (sourceLine == null) { | |
| 1014 | + break; | |
| 1015 | + } | |
| 1016 | + out.print(i); | |
| 1017 | + out.print("\t"); | |
| 1018 | + if (i == lineno) { | |
| 1019 | + out.print("=> "); | |
| 1020 | + } else { | |
| 1021 | + out.print(" "); | |
| 1022 | + } | |
| 1023 | + out.println(sourceLine); | |
| 1024 | + } | |
| 1025 | + out.show(); | |
| 1026 | + } | |
| 1027 | + } | |
| 1028 | + | |
| 1029 | + // Command: use | |
| 1030 | + // Get or set the source file path list. | |
| 1031 | + | |
| 1032 | + private void commandUse(StringTokenizer t) { | |
| 1033 | + if (!t.hasMoreTokens()) { | |
| 1034 | + out.println(sourceManager.getSourcePath().asString()); | |
| 1035 | + } else { | |
| 1036 | + //### Should throw exception for invalid path. | |
| 1037 | + //### E.g., vetoable property change. | |
| 1038 | + sourceManager.setSourcePath(new SearchPath(t.nextToken())); | |
| 1039 | + } | |
| 1040 | + } | |
| 1041 | + | |
| 1042 | + // Command: sourcepath | |
| 1043 | + // Get or set the source file path list. (Alternate to 'use'.) | |
| 1044 | + | |
| 1045 | + private void commandSourcepath(StringTokenizer t) { | |
| 1046 | + if (!t.hasMoreTokens()) { | |
| 1047 | + out.println(sourceManager.getSourcePath().asString()); | |
| 1048 | + } else { | |
| 1049 | + //### Should throw exception for invalid path. | |
| 1050 | + //### E.g., vetoable property change. | |
| 1051 | + sourceManager.setSourcePath(new SearchPath(t.nextToken())); | |
| 1052 | + } | |
| 1053 | + } | |
| 1054 | + | |
| 1055 | + // Command: classpath | |
| 1056 | + // Get or set the class file path list. | |
| 1057 | + | |
| 1058 | + private void commandClasspath(StringTokenizer t) { | |
| 1059 | + if (!t.hasMoreTokens()) { | |
| 1060 | + out.println(classManager.getClassPath().asString()); | |
| 1061 | + } else { | |
| 1062 | + //### Should throw exception for invalid path. | |
| 1063 | + //### E.g., vetoable property change. | |
| 1064 | + classManager.setClassPath(new SearchPath(t.nextToken())); | |
| 1065 | + } | |
| 1066 | + } | |
| 1067 | + | |
| 1068 | + // Command: view | |
| 1069 | + // Display source for source file or class. | |
| 1070 | + | |
| 1071 | + private void commandView(StringTokenizer t) throws NoSessionException { | |
| 1072 | + if (!t.hasMoreTokens()) { | |
| 1073 | + env.error("Argument required"); | |
| 1074 | + } else { | |
| 1075 | + String name = t.nextToken(); | |
| 1076 | + if (name.endsWith(".java") || | |
| 1077 | + name.indexOf(File.separatorChar) >= 0) { | |
| 1078 | + env.viewSource(name); | |
| 1079 | + } else { | |
| 1080 | + //### JDI crashes taking line number for class. | |
| 1081 | + /***** | |
| 1082 | + ReferenceType cls = findClass(name); | |
| 1083 | + if (cls != null) { | |
| 1084 | + env.viewLocation(cls.location()); | |
| 1085 | + } else { | |
| 1086 | + env.failure("No such class"); | |
| 1087 | + } | |
| 1088 | + *****/ | |
| 1089 | + String fileName = name.replace('.', File.separatorChar) + ".java"; | |
| 1090 | + env.viewSource(fileName); | |
| 1091 | + } | |
| 1092 | + } | |
| 1093 | + } | |
| 1094 | + | |
| 1095 | + // Command: locals | |
| 1096 | + // Print all local variables in current stack frame. | |
| 1097 | + | |
| 1098 | + private void commandLocals() throws NoSessionException { | |
| 1099 | + ThreadReference current = context.getCurrentThread(); | |
| 1100 | + if (current == null) { | |
| 1101 | + env.failure("No default thread specified: " + | |
| 1102 | + "use the \"thread\" command first."); | |
| 1103 | + return; | |
| 1104 | + } | |
| 1105 | + StackFrame frame; | |
| 1106 | + try { | |
| 1107 | + frame = context.getCurrentFrame(current); | |
| 1108 | + if (frame == null) { | |
| 1109 | + env.failure("Thread has not yet created any stack frames."); | |
| 1110 | + return; | |
| 1111 | + } | |
| 1112 | + } catch (VMNotInterruptedException e) { | |
| 1113 | + env.failure("Target VM must be in interrupted state."); | |
| 1114 | + return; | |
| 1115 | + } | |
| 1116 | + | |
| 1117 | + List<LocalVariable> vars; | |
| 1118 | + try { | |
| 1119 | + vars = frame.visibleVariables(); | |
| 1120 | + if (vars == null || vars.size() == 0) { | |
| 1121 | + env.failure("No local variables"); | |
| 1122 | + return; | |
| 1123 | + } | |
| 1124 | + } catch (AbsentInformationException e) { | |
| 1125 | + env.failure("Local variable information not available." + | |
| 1126 | + " Compile with -g to generate variable information"); | |
| 1127 | + return; | |
| 1128 | + } | |
| 1129 | + | |
| 1130 | + OutputSink out = env.getOutputSink(); | |
| 1131 | + out.println("Method arguments:"); | |
| 1132 | + for (LocalVariable var : vars) { | |
| 1133 | + if (var.isArgument()) { | |
| 1134 | + printVar(out, var, frame); | |
| 1135 | + } | |
| 1136 | + } | |
| 1137 | + out.println("Local variables:"); | |
| 1138 | + for (LocalVariable var : vars) { | |
| 1139 | + if (!var.isArgument()) { | |
| 1140 | + printVar(out, var, frame); | |
| 1141 | + } | |
| 1142 | + } | |
| 1143 | + out.show(); | |
| 1144 | + return; | |
| 1145 | + } | |
| 1146 | + | |
| 1147 | + /** | |
| 1148 | + * Command: monitor | |
| 1149 | + * Monitor an expression | |
| 1150 | + */ | |
| 1151 | + private void commandMonitor(StringTokenizer t) throws NoSessionException { | |
| 1152 | + if (!t.hasMoreTokens()) { | |
| 1153 | + env.error("Argument required"); | |
| 1154 | + } else { | |
| 1155 | + env.getMonitorListModel().add(t.nextToken("")); | |
| 1156 | + } | |
| 1157 | + } | |
| 1158 | + | |
| 1159 | + /** | |
| 1160 | + * Command: unmonitor | |
| 1161 | + * Unmonitor an expression | |
| 1162 | + */ | |
| 1163 | + private void commandUnmonitor(StringTokenizer t) throws NoSessionException { | |
| 1164 | + if (!t.hasMoreTokens()) { | |
| 1165 | + env.error("Argument required"); | |
| 1166 | + } else { | |
| 1167 | + env.getMonitorListModel().remove(t.nextToken("")); | |
| 1168 | + } | |
| 1169 | + } | |
| 1170 | + | |
| 1171 | + // Print a stack variable. | |
| 1172 | + | |
| 1173 | + private void printVar(OutputSink out, LocalVariable var, StackFrame frame) { | |
| 1174 | + out.print(" " + var.name()); | |
| 1175 | + if (var.isVisible(frame)) { | |
| 1176 | + Value val = frame.getValue(var); | |
| 1177 | + out.println(" = " + val.toString()); | |
| 1178 | + } else { | |
| 1179 | + out.println(" is not in scope"); | |
| 1180 | + } | |
| 1181 | + } | |
| 1182 | + | |
| 1183 | + // Command: print | |
| 1184 | + // Evaluate an expression. | |
| 1185 | + | |
| 1186 | + private void commandPrint(StringTokenizer t, boolean dumpObject) throws NoSessionException { | |
| 1187 | + if (!t.hasMoreTokens()) { | |
| 1188 | + //### Probably confused if expresion contains whitespace. | |
| 1189 | + env.error("No expression specified."); | |
| 1190 | + return; | |
| 1191 | + } | |
| 1192 | + ThreadReference current = context.getCurrentThread(); | |
| 1193 | + if (current == null) { | |
| 1194 | + env.failure("No default thread specified: " + | |
| 1195 | + "use the \"thread\" command first."); | |
| 1196 | + return; | |
| 1197 | + } | |
| 1198 | + StackFrame frame; | |
| 1199 | + try { | |
| 1200 | + frame = context.getCurrentFrame(current); | |
| 1201 | + if (frame == null) { | |
| 1202 | + env.failure("Thread has not yet created any stack frames."); | |
| 1203 | + return; | |
| 1204 | + } | |
| 1205 | + } catch (VMNotInterruptedException e) { | |
| 1206 | + env.failure("Target VM must be in interrupted state."); | |
| 1207 | + return; | |
| 1208 | + } | |
| 1209 | + while (t.hasMoreTokens()) { | |
| 1210 | + String expr = t.nextToken(""); | |
| 1211 | + Value val = null; | |
| 1212 | + try { | |
| 1213 | + val = runtime.evaluate(frame, expr); | |
| 1214 | + } catch(Exception e) { | |
| 1215 | + env.error("Exception: " + e); | |
| 1216 | + //### Fix this! | |
| 1217 | + } | |
| 1218 | + if (val == null) { | |
| 1219 | + return; // Error message already printed | |
| 1220 | + } | |
| 1221 | + OutputSink out = env.getOutputSink(); | |
| 1222 | + if (dumpObject && (val instanceof ObjectReference) && | |
| 1223 | + !(val instanceof StringReference)) { | |
| 1224 | + ObjectReference obj = (ObjectReference)val; | |
| 1225 | + ReferenceType refType = obj.referenceType(); | |
| 1226 | + out.println(expr + " = " + val.toString() + " {"); | |
| 1227 | + dump(out, obj, refType, refType); | |
| 1228 | + out.println("}"); | |
| 1229 | + } else { | |
| 1230 | + out.println(expr + " = " + val.toString()); | |
| 1231 | + } | |
| 1232 | + out.show(); | |
| 1233 | + } | |
| 1234 | + } | |
| 1235 | + | |
| 1236 | + private void dump(OutputSink out, | |
| 1237 | + ObjectReference obj, ReferenceType refType, | |
| 1238 | + ReferenceType refTypeBase) { | |
| 1239 | + for (Field field : refType.fields()) { | |
| 1240 | + out.print(" "); | |
| 1241 | + if (!refType.equals(refTypeBase)) { | |
| 1242 | + out.print(refType.name() + "."); | |
| 1243 | + } | |
| 1244 | + out.print(field.name() + ": "); | |
| 1245 | + Object o = obj.getValue(field); | |
| 1246 | + out.println((o == null) ? "null" : o.toString()); // Bug ID 4374471 | |
| 1247 | + } | |
| 1248 | + if (refType instanceof ClassType) { | |
| 1249 | + ClassType sup = ((ClassType)refType).superclass(); | |
| 1250 | + if (sup != null) { | |
| 1251 | + dump(out, obj, sup, refTypeBase); | |
| 1252 | + } | |
| 1253 | + } else if (refType instanceof InterfaceType) { | |
| 1254 | + for (InterfaceType sup : ((InterfaceType)refType).superinterfaces()) { | |
| 1255 | + dump(out, obj, sup, refTypeBase); | |
| 1256 | + } | |
| 1257 | + } | |
| 1258 | + } | |
| 1259 | + | |
| 1260 | + /* | |
| 1261 | + * Display help message. | |
| 1262 | + */ | |
| 1263 | + | |
| 1264 | + private void help() { | |
| 1265 | + out.println("** command list **"); | |
| 1266 | + out.println("threads [threadgroup] -- list threads"); | |
| 1267 | + out.println("thread <thread id> -- set default thread"); | |
| 1268 | + out.println("suspend [thread id(s)] -- suspend threads (default: all)"); | |
| 1269 | + out.println("resume [thread id(s)] -- resume threads (default: all)"); | |
| 1270 | + out.println("where [thread id] | all -- dump a thread's stack"); | |
| 1271 | + out.println("wherei [thread id] | all -- dump a thread's stack, with pc info"); | |
| 1272 | + out.println("threadgroups -- list threadgroups"); | |
| 1273 | + out.println("threadgroup <name> -- set current threadgroup\n"); | |
| 1274 | +// out.println("print <expression> -- print value of expression"); | |
| 1275 | + out.println("dump <expression> -- print all object information\n"); | |
| 1276 | +// out.println("eval <expression> -- evaluate expression (same as print)"); | |
| 1277 | + out.println("locals -- print all local variables in current stack frame\n"); | |
| 1278 | + out.println("classes -- list currently known classes"); | |
| 1279 | + out.println("methods <class id> -- list a class's methods\n"); | |
| 1280 | + out.println("stop [in] <class id>.<method>[(argument_type,...)] -- set a breakpoint in a method"); | |
| 1281 | + out.println("stop [at] <class id>:<line> -- set a breakpoint at a line"); | |
| 1282 | + out.println("up [n frames] -- move up a thread's stack"); | |
| 1283 | + out.println("down [n frames] -- move down a thread's stack"); | |
| 1284 | + out.println("frame <frame-id> -- to a frame"); | |
| 1285 | + out.println("clear <class id>.<method>[(argument_type,...)] -- clear a breakpoint in a method"); | |
| 1286 | + out.println("clear <class id>:<line> -- clear a breakpoint at a line"); | |
| 1287 | + out.println("clear -- list breakpoints"); | |
| 1288 | + out.println("step -- execute current line"); | |
| 1289 | + out.println("step up -- execute until the current method returns to its caller"); | |
| 1290 | + out.println("stepi -- execute current instruction"); | |
| 1291 | + out.println("next -- step one line (step OVER calls)"); | |
| 1292 | + out.println("nexti -- step one instruction (step OVER calls)"); | |
| 1293 | + out.println("cont -- continue execution from breakpoint\n"); | |
| 1294 | +// out.println("catch <class id> -- break for the specified exception"); | |
| 1295 | +// out.println("ignore <class id> -- ignore when the specified exception\n"); | |
| 1296 | + out.println("view classname|filename -- display source file"); | |
| 1297 | + out.println("list [line number|method] -- print source code context at line or method"); | |
| 1298 | + out.println("use <source file path> -- display or change the source path\n"); | |
| 1299 | +//### new | |
| 1300 | + out.println("sourcepath <source file path> -- display or change the source path\n"); | |
| 1301 | +//### new | |
| 1302 | + out.println("classpath <class file path> -- display or change the class path\n"); | |
| 1303 | + out.println("monitor <expression> -- evaluate an expression each time the program stops\n"); | |
| 1304 | + out.println("unmonitor <monitor#> -- delete a monitor\n"); | |
| 1305 | + out.println("read <filename> -- read and execute a command file\n"); | |
| 1306 | +// out.println("memory -- report memory usage"); | |
| 1307 | +// out.println("gc -- free unused objects\n"); | |
| 1308 | + out.println("run <class> [args] -- start execution of a Java class"); | |
| 1309 | + out.println("run -- re-execute last class run"); | |
| 1310 | + out.println("load <class> [args] -- start execution of a Java class, initially suspended"); | |
| 1311 | + out.println("load -- re-execute last class run, initially suspended"); | |
| 1312 | + out.println("attach <portname> -- debug existing process\n"); | |
| 1313 | + out.println("detach -- detach from debuggee process\n"); | |
| 1314 | + out.println("kill <thread(group)> -- kill a thread or threadgroup\n"); | |
| 1315 | + out.println("!! -- repeat last command"); | |
| 1316 | + out.println("help (or ?) -- list commands"); | |
| 1317 | + out.println("exit (or quit) -- exit debugger"); | |
| 1318 | + } | |
| 1319 | + | |
| 1320 | + /* | |
| 1321 | + * Execute a command. | |
| 1322 | + */ | |
| 1323 | + | |
| 1324 | + public void executeCommand(String command) { | |
| 1325 | + //### Treatment of 'out' here is dirty... | |
| 1326 | + out = env.getOutputSink(); | |
| 1327 | + if (echo) { | |
| 1328 | + out.println(">>> " + command); | |
| 1329 | + } | |
| 1330 | + StringTokenizer t = new StringTokenizer(command); | |
| 1331 | + try { | |
| 1332 | + String cmd; | |
| 1333 | + if (t.hasMoreTokens()) { | |
| 1334 | + cmd = t.nextToken().toLowerCase(); | |
| 1335 | + lastCommand = cmd; | |
| 1336 | + } else { | |
| 1337 | + cmd = lastCommand; | |
| 1338 | + } | |
| 1339 | + if (cmd.equals("print")) { | |
| 1340 | + commandPrint(t, false); | |
| 1341 | + } else if (cmd.equals("eval")) { | |
| 1342 | + commandPrint(t, false); | |
| 1343 | + } else if (cmd.equals("dump")) { | |
| 1344 | + commandPrint(t, true); | |
| 1345 | + } else if (cmd.equals("locals")) { | |
| 1346 | + commandLocals(); | |
| 1347 | + } else if (cmd.equals("classes")) { | |
| 1348 | + commandClasses(); | |
| 1349 | + } else if (cmd.equals("methods")) { | |
| 1350 | + commandMethods(t); | |
| 1351 | + } else if (cmd.equals("threads")) { | |
| 1352 | + commandThreads(t); | |
| 1353 | + } else if (cmd.equals("thread")) { | |
| 1354 | + commandThread(t); | |
| 1355 | + } else if (cmd.equals("suspend")) { | |
| 1356 | + commandSuspend(t); | |
| 1357 | + } else if (cmd.equals("resume")) { | |
| 1358 | + commandResume(t); | |
| 1359 | + } else if (cmd.equals("cont")) { | |
| 1360 | + commandCont(); | |
| 1361 | + } else if (cmd.equals("threadgroups")) { | |
| 1362 | + commandThreadGroups(); | |
| 1363 | + } else if (cmd.equals("threadgroup")) { | |
| 1364 | + commandThreadGroup(t); | |
| 1365 | + } else if (cmd.equals("run")) { | |
| 1366 | + commandRun(t); | |
| 1367 | + } else if (cmd.equals("load")) { | |
| 1368 | + commandLoad(t); | |
| 1369 | + } else if (cmd.equals("connect")) { | |
| 1370 | + commandConnect(t); | |
| 1371 | + } else if (cmd.equals("attach")) { | |
| 1372 | + commandAttach(t); | |
| 1373 | + } else if (cmd.equals("detach")) { | |
| 1374 | + commandDetach(t); | |
| 1375 | + } else if (cmd.equals("interrupt")) { | |
| 1376 | + commandInterrupt(t); | |
| 1377 | +//### Not implemented. | |
| 1378 | +// } else if (cmd.equals("catch")) { | |
| 1379 | +// commandCatchException(t); | |
| 1380 | +//### Not implemented. | |
| 1381 | +// } else if (cmd.equals("ignore")) { | |
| 1382 | +// commandIgnoreException(t); | |
| 1383 | + } else if (cmd.equals("step")) { | |
| 1384 | + commandStep(t); | |
| 1385 | + } else if (cmd.equals("stepi")) { | |
| 1386 | + commandStepi(); | |
| 1387 | + } else if (cmd.equals("next")) { | |
| 1388 | + commandNext(); | |
| 1389 | + } else if (cmd.equals("nexti")) { | |
| 1390 | + commandNexti(); | |
| 1391 | + } else if (cmd.equals("kill")) { | |
| 1392 | + commandKill(t); | |
| 1393 | + } else if (cmd.equals("where")) { | |
| 1394 | + commandWhere(t, false); | |
| 1395 | + } else if (cmd.equals("wherei")) { | |
| 1396 | + commandWhere(t, true); | |
| 1397 | + } else if (cmd.equals("up")) { | |
| 1398 | + commandUp(t); | |
| 1399 | + } else if (cmd.equals("down")) { | |
| 1400 | + commandDown(t); | |
| 1401 | + } else if (cmd.equals("frame")) { | |
| 1402 | + commandFrame(t); | |
| 1403 | + } else if (cmd.equals("stop")) { | |
| 1404 | + commandStop(t); | |
| 1405 | + } else if (cmd.equals("clear")) { | |
| 1406 | + commandClear(t); | |
| 1407 | + } else if (cmd.equals("list")) { | |
| 1408 | + commandList(t); | |
| 1409 | + } else if (cmd.equals("use")) { | |
| 1410 | + commandUse(t); | |
| 1411 | + } else if (cmd.equals("sourcepath")) { | |
| 1412 | + commandSourcepath(t); | |
| 1413 | + } else if (cmd.equals("classpath")) { | |
| 1414 | + commandClasspath(t); | |
| 1415 | + } else if (cmd.equals("monitor")) { | |
| 1416 | + commandMonitor(t); | |
| 1417 | + } else if (cmd.equals("unmonitor")) { | |
| 1418 | + commandUnmonitor(t); | |
| 1419 | + } else if (cmd.equals("view")) { | |
| 1420 | + commandView(t); | |
| 1421 | +// } else if (cmd.equals("read")) { | |
| 1422 | +// readCommand(t); | |
| 1423 | + } else if (cmd.equals("help") || cmd.equals("?")) { | |
| 1424 | + help(); | |
| 1425 | + } else if (cmd.equals("quit") || cmd.equals("exit")) { | |
| 1426 | + try { | |
| 1427 | + runtime.detach(); | |
| 1428 | + } catch (NoSessionException e) { | |
| 1429 | + // ignore | |
| 1430 | + } | |
| 1431 | + env.terminate(); | |
| 1432 | + } else { | |
| 1433 | + //### Dubious repeat-count feature inherited from 'jdb' | |
| 1434 | + if (t.hasMoreTokens()) { | |
| 1435 | + try { | |
| 1436 | + int repeat = Integer.parseInt(cmd); | |
| 1437 | + String subcom = t.nextToken(""); | |
| 1438 | + while (repeat-- > 0) { | |
| 1439 | + executeCommand(subcom); | |
| 1440 | + } | |
| 1441 | + return; | |
| 1442 | + } catch (NumberFormatException exc) { | |
| 1443 | + } | |
| 1444 | + } | |
| 1445 | + out.println("huh? Try help..."); | |
| 1446 | + out.flush(); | |
| 1447 | + } | |
| 1448 | + } catch (NoSessionException e) { | |
| 1449 | + out.println("There is no currently attached VM session."); | |
| 1450 | + out.flush(); | |
| 1451 | + } catch (Exception e) { | |
| 1452 | + out.println("Internal exception: " + e.toString()); | |
| 1453 | + out.flush(); | |
| 1454 | + System.out.println("JDB internal exception: " + e.toString()); | |
| 1455 | + e.printStackTrace(); | |
| 1456 | + } | |
| 1457 | + out.show(); | |
| 1458 | + } | |
| 1459 | +} | |
| @@ -0,0 +1,333 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | +import java.util.*; | |
| 30 | + | |
| 31 | +import javax.swing.*; | |
| 32 | +import java.awt.BorderLayout; | |
| 33 | +import java.awt.event.*; | |
| 34 | + | |
| 35 | +import com.sun.jdi.*; | |
| 36 | +import com.sun.jdi.event.*; | |
| 37 | + | |
| 38 | +import com.sun.tools.example.debug.bdi.*; | |
| 39 | +import com.sun.tools.example.debug.event.*; | |
| 40 | + | |
| 41 | +public class CommandTool extends JPanel { | |
| 42 | + | |
| 43 | + private static final long serialVersionUID = 8613516856378346415L; | |
| 44 | + | |
| 45 | + private Environment env; | |
| 46 | + | |
| 47 | + private ContextManager context; | |
| 48 | + private ExecutionManager runtime; | |
| 49 | + private SourceManager sourceManager; | |
| 50 | + | |
| 51 | + private TypeScript script; | |
| 52 | + | |
| 53 | + private static final String DEFAULT_CMD_PROMPT = "Command:"; | |
| 54 | + | |
| 55 | + public CommandTool(Environment env) { | |
| 56 | + | |
| 57 | + super(new BorderLayout()); | |
| 58 | + | |
| 59 | + this.env = env; | |
| 60 | + this.context = env.getContextManager(); | |
| 61 | + this.runtime = env.getExecutionManager(); | |
| 62 | + this.sourceManager = env.getSourceManager(); | |
| 63 | + | |
| 64 | + script = new TypeScript(DEFAULT_CMD_PROMPT, false); //no echo | |
| 65 | + this.add(script); | |
| 66 | + | |
| 67 | + final CommandInterpreter interpreter = | |
| 68 | + new CommandInterpreter(env); | |
| 69 | + | |
| 70 | + // Establish handler for incoming commands. | |
| 71 | + | |
| 72 | + script.addActionListener(new ActionListener() { | |
| 73 | + @Override | |
| 74 | + public void actionPerformed(ActionEvent e) { | |
| 75 | + interpreter.executeCommand(script.readln()); | |
| 76 | + } | |
| 77 | + }); | |
| 78 | + | |
| 79 | + // Establish ourselves as the listener for VM diagnostics. | |
| 80 | + | |
| 81 | + OutputListener diagnosticsListener = | |
| 82 | + new TypeScriptOutputListener(script, true); | |
| 83 | + runtime.addDiagnosticsListener(diagnosticsListener); | |
| 84 | + | |
| 85 | + // Establish ourselves as the shared debugger typescript. | |
| 86 | + | |
| 87 | + env.setTypeScript(new PrintWriter(new TypeScriptWriter(script))); | |
| 88 | + | |
| 89 | + // Handle VM events. | |
| 90 | + | |
| 91 | + TTYDebugListener listener = new TTYDebugListener(diagnosticsListener); | |
| 92 | + | |
| 93 | + runtime.addJDIListener(listener); | |
| 94 | + runtime.addSessionListener(listener); | |
| 95 | + runtime.addSpecListener(listener); | |
| 96 | + context.addContextListener(listener); | |
| 97 | + | |
| 98 | + //### remove listeners on exit! | |
| 99 | + | |
| 100 | + } | |
| 101 | + | |
| 102 | + private class TTYDebugListener implements | |
| 103 | + JDIListener, SessionListener, SpecListener, ContextListener { | |
| 104 | + | |
| 105 | + private OutputListener diagnostics; | |
| 106 | + | |
| 107 | + TTYDebugListener(OutputListener diagnostics) { | |
| 108 | + this.diagnostics = diagnostics; | |
| 109 | + } | |
| 110 | + | |
| 111 | + // JDIListener | |
| 112 | + | |
| 113 | + @Override | |
| 114 | + public void accessWatchpoint(AccessWatchpointEventSet e) { | |
| 115 | + setThread(e); | |
| 116 | + for (EventIterator it = e.eventIterator(); it.hasNext(); ) { | |
| 117 | + it.nextEvent(); | |
| 118 | + diagnostics.putString("Watchpoint hit: " + | |
| 119 | + locationString(e)); | |
| 120 | + } | |
| 121 | + } | |
| 122 | + | |
| 123 | + @Override | |
| 124 | + public void classPrepare(ClassPrepareEventSet e) { | |
| 125 | + if (context.getVerboseFlag()) { | |
| 126 | + String name = e.getReferenceType().name(); | |
| 127 | + diagnostics.putString("Class " + name + " loaded"); | |
| 128 | + } | |
| 129 | + } | |
| 130 | + | |
| 131 | + @Override | |
| 132 | + public void classUnload(ClassUnloadEventSet e) { | |
| 133 | + if (context.getVerboseFlag()) { | |
| 134 | + diagnostics.putString("Class " + e.getClassName() + | |
| 135 | + " unloaded."); | |
| 136 | + } | |
| 137 | + } | |
| 138 | + | |
| 139 | + @Override | |
| 140 | + public void exception(ExceptionEventSet e) { | |
| 141 | + setThread(e); | |
| 142 | + String name = e.getException().referenceType().name(); | |
| 143 | + diagnostics.putString("Exception: " + name); | |
| 144 | + } | |
| 145 | + | |
| 146 | + @Override | |
| 147 | + public void locationTrigger(LocationTriggerEventSet e) { | |
| 148 | + String locString = locationString(e); | |
| 149 | + setThread(e); | |
| 150 | + for (EventIterator it = e.eventIterator(); it.hasNext(); ) { | |
| 151 | + Event evt = it.nextEvent(); | |
| 152 | + if (evt instanceof BreakpointEvent) { | |
| 153 | + diagnostics.putString("Breakpoint hit: " + locString); | |
| 154 | + } else if (evt instanceof StepEvent) { | |
| 155 | + diagnostics.putString("Step completed: " + locString); | |
| 156 | + } else if (evt instanceof MethodEntryEvent) { | |
| 157 | + diagnostics.putString("Method entered: " + locString); | |
| 158 | + } else if (evt instanceof MethodExitEvent) { | |
| 159 | + diagnostics.putString("Method exited: " + locString); | |
| 160 | + } else { | |
| 161 | + diagnostics.putString("UNKNOWN event: " + e); | |
| 162 | + } | |
| 163 | + } | |
| 164 | + } | |
| 165 | + | |
| 166 | + @Override | |
| 167 | + public void modificationWatchpoint(ModificationWatchpointEventSet e) { | |
| 168 | + setThread(e); | |
| 169 | + for (EventIterator it = e.eventIterator(); it.hasNext(); ) { | |
| 170 | + it.nextEvent(); | |
| 171 | + diagnostics.putString("Watchpoint hit: " + | |
| 172 | + locationString(e)); | |
| 173 | + } | |
| 174 | + } | |
| 175 | + | |
| 176 | + @Override | |
| 177 | + public void threadDeath(ThreadDeathEventSet e) { | |
| 178 | + if (context.getVerboseFlag()) { | |
| 179 | + diagnostics.putString("Thread " + e.getThread() + | |
| 180 | + " ended."); | |
| 181 | + } | |
| 182 | + } | |
| 183 | + | |
| 184 | + @Override | |
| 185 | + public void threadStart(ThreadStartEventSet e) { | |
| 186 | + if (context.getVerboseFlag()) { | |
| 187 | + diagnostics.putString("Thread " + e.getThread() + | |
| 188 | + " started."); | |
| 189 | + } | |
| 190 | + } | |
| 191 | + | |
| 192 | + @Override | |
| 193 | + public void vmDeath(VMDeathEventSet e) { | |
| 194 | + script.setPrompt(DEFAULT_CMD_PROMPT); | |
| 195 | + diagnostics.putString("VM exited"); | |
| 196 | + } | |
| 197 | + | |
| 198 | + @Override | |
| 199 | + public void vmDisconnect(VMDisconnectEventSet e) { | |
| 200 | + script.setPrompt(DEFAULT_CMD_PROMPT); | |
| 201 | + diagnostics.putString("Disconnected from VM"); | |
| 202 | + } | |
| 203 | + | |
| 204 | + @Override | |
| 205 | + public void vmStart(VMStartEventSet e) { | |
| 206 | + script.setPrompt(DEFAULT_CMD_PROMPT); | |
| 207 | + diagnostics.putString("VM started"); | |
| 208 | + } | |
| 209 | + | |
| 210 | + // SessionListener | |
| 211 | + | |
| 212 | + @Override | |
| 213 | + public void sessionStart(EventObject e) {} | |
| 214 | + | |
| 215 | + @Override | |
| 216 | + public void sessionInterrupt(EventObject e) { | |
| 217 | + Thread.yield(); // fetch output | |
| 218 | + diagnostics.putString("VM interrupted by user."); | |
| 219 | + script.setPrompt(DEFAULT_CMD_PROMPT); | |
| 220 | + } | |
| 221 | + | |
| 222 | + @Override | |
| 223 | + public void sessionContinue(EventObject e) { | |
| 224 | + diagnostics.putString("Execution resumed."); | |
| 225 | + script.setPrompt(DEFAULT_CMD_PROMPT); | |
| 226 | + } | |
| 227 | + | |
| 228 | + // SpecListener | |
| 229 | + | |
| 230 | + @Override | |
| 231 | + public void breakpointSet(SpecEvent e) { | |
| 232 | + EventRequestSpec spec = e.getEventRequestSpec(); | |
| 233 | + diagnostics.putString("Breakpoint set at " + spec + "."); | |
| 234 | + } | |
| 235 | + @Override | |
| 236 | + public void breakpointDeferred(SpecEvent e) { | |
| 237 | + EventRequestSpec spec = e.getEventRequestSpec(); | |
| 238 | + diagnostics.putString("Breakpoint will be set at " + | |
| 239 | + spec + " when its class is loaded."); | |
| 240 | + } | |
| 241 | + @Override | |
| 242 | + public void breakpointDeleted(SpecEvent e) { | |
| 243 | + EventRequestSpec spec = e.getEventRequestSpec(); | |
| 244 | + diagnostics.putString("Breakpoint at " + spec.toString() + " deleted."); | |
| 245 | + } | |
| 246 | + @Override | |
| 247 | + public void breakpointResolved(SpecEvent e) { | |
| 248 | + EventRequestSpec spec = e.getEventRequestSpec(); | |
| 249 | + diagnostics.putString("Breakpoint resolved to " + spec.toString() + "."); | |
| 250 | + } | |
| 251 | + @Override | |
| 252 | + public void breakpointError(SpecErrorEvent e) { | |
| 253 | + EventRequestSpec spec = e.getEventRequestSpec(); | |
| 254 | + diagnostics.putString("Deferred breakpoint at " + | |
| 255 | + spec + " could not be resolved:" + | |
| 256 | + e.getReason()); | |
| 257 | + } | |
| 258 | + | |
| 259 | +//### Add info for watchpoints and exceptions | |
| 260 | + | |
| 261 | + @Override | |
| 262 | + public void watchpointSet(SpecEvent e) { | |
| 263 | + } | |
| 264 | + @Override | |
| 265 | + public void watchpointDeferred(SpecEvent e) { | |
| 266 | + } | |
| 267 | + @Override | |
| 268 | + public void watchpointDeleted(SpecEvent e) { | |
| 269 | + } | |
| 270 | + @Override | |
| 271 | + public void watchpointResolved(SpecEvent e) { | |
| 272 | + } | |
| 273 | + @Override | |
| 274 | + public void watchpointError(SpecErrorEvent e) { | |
| 275 | + } | |
| 276 | + | |
| 277 | + @Override | |
| 278 | + public void exceptionInterceptSet(SpecEvent e) { | |
| 279 | + } | |
| 280 | + @Override | |
| 281 | + public void exceptionInterceptDeferred(SpecEvent e) { | |
| 282 | + } | |
| 283 | + @Override | |
| 284 | + public void exceptionInterceptDeleted(SpecEvent e) { | |
| 285 | + } | |
| 286 | + @Override | |
| 287 | + public void exceptionInterceptResolved(SpecEvent e) { | |
| 288 | + } | |
| 289 | + @Override | |
| 290 | + public void exceptionInterceptError(SpecErrorEvent e) { | |
| 291 | + } | |
| 292 | + | |
| 293 | + | |
| 294 | + // ContextListener. | |
| 295 | + | |
| 296 | + // If the user selects a new current thread or frame, update prompt. | |
| 297 | + | |
| 298 | + @Override | |
| 299 | + public void currentFrameChanged(CurrentFrameChangedEvent e) { | |
| 300 | + // Update prompt only if affect thread is current. | |
| 301 | + ThreadReference thread = e.getThread(); | |
| 302 | + if (thread == context.getCurrentThread()) { | |
| 303 | + script.setPrompt(promptString(thread, e.getIndex())); | |
| 304 | + } | |
| 305 | + } | |
| 306 | + | |
| 307 | + } | |
| 308 | + | |
| 309 | + private String locationString(LocatableEventSet e) { | |
| 310 | + Location loc = e.getLocation(); | |
| 311 | + return "thread=\"" + e.getThread().name() + | |
| 312 | + "\", " + Utils.locationString(loc); | |
| 313 | + } | |
| 314 | + | |
| 315 | + private void setThread(LocatableEventSet e) { | |
| 316 | + if (!e.suspendedNone()) { | |
| 317 | + Thread.yield(); // fetch output | |
| 318 | + script.setPrompt(promptString(e.getThread(), 0)); | |
| 319 | + //### Current thread should be set elsewhere, e.g., | |
| 320 | + //### in ContextManager | |
| 321 | + //### context.setCurrentThread(thread); | |
| 322 | + } | |
| 323 | + } | |
| 324 | + | |
| 325 | + private String promptString(ThreadReference thread, int frameIndex) { | |
| 326 | + if (thread == null) { | |
| 327 | + return DEFAULT_CMD_PROMPT; | |
| 328 | + } else { | |
| 329 | + // Frame indices are presented to user as indexed from 1. | |
| 330 | + return (thread.name() + "[" + (frameIndex + 1) + "]:"); | |
| 331 | + } | |
| 332 | + } | |
| 333 | +} | |
| @@ -0,0 +1,30 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +public interface ContextListener { | |
| 29 | + void currentFrameChanged(CurrentFrameChangedEvent e); | |
| 30 | +} | |
| @@ -0,0 +1,353 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | +import java.util.*; | |
| 30 | + | |
| 31 | +import com.sun.jdi.*; | |
| 32 | +import com.sun.tools.example.debug.event.*; | |
| 33 | +import com.sun.tools.example.debug.bdi.*; | |
| 34 | + | |
| 35 | +public class ContextManager { | |
| 36 | + | |
| 37 | + private ClassManager classManager; | |
| 38 | + private ExecutionManager runtime; | |
| 39 | + | |
| 40 | + private String mainClassName; | |
| 41 | + private String vmArguments; | |
| 42 | + private String commandArguments; | |
| 43 | + private String remotePort; | |
| 44 | + | |
| 45 | + private ThreadReference currentThread; | |
| 46 | + | |
| 47 | + private boolean verbose; | |
| 48 | + | |
| 49 | + private ArrayList<ContextListener> contextListeners = new ArrayList<ContextListener>(); | |
| 50 | + | |
| 51 | + public ContextManager(Environment env) { | |
| 52 | + classManager = env.getClassManager(); | |
| 53 | + runtime = env.getExecutionManager(); | |
| 54 | + mainClassName = ""; | |
| 55 | + vmArguments = ""; | |
| 56 | + commandArguments = ""; | |
| 57 | + currentThread = null; | |
| 58 | + | |
| 59 | + ContextManagerListener listener = new ContextManagerListener(); | |
| 60 | + runtime.addJDIListener(listener); | |
| 61 | + runtime.addSessionListener(listener); | |
| 62 | + } | |
| 63 | + | |
| 64 | + // Program execution defaults. | |
| 65 | + | |
| 66 | + //### Should there be change listeners for these? | |
| 67 | + //### They would be needed if we expected a dialog to be | |
| 68 | + //### synchronized with command input while it was open. | |
| 69 | + | |
| 70 | + public String getMainClassName() { | |
| 71 | + return mainClassName; | |
| 72 | + } | |
| 73 | + | |
| 74 | + public void setMainClassName(String mainClassName) { | |
| 75 | + this.mainClassName = mainClassName; | |
| 76 | + } | |
| 77 | + | |
| 78 | + public String getVmArguments() { | |
| 79 | + return processClasspathDefaults(vmArguments); | |
| 80 | + } | |
| 81 | + | |
| 82 | + public void setVmArguments(String vmArguments) { | |
| 83 | + this.vmArguments = vmArguments; | |
| 84 | + } | |
| 85 | + | |
| 86 | + public String getProgramArguments() { | |
| 87 | + return commandArguments; | |
| 88 | + } | |
| 89 | + | |
| 90 | + public void setProgramArguments(String commandArguments) { | |
| 91 | + this.commandArguments = commandArguments; | |
| 92 | + } | |
| 93 | + | |
| 94 | + public String getRemotePort() { | |
| 95 | + return remotePort; | |
| 96 | + } | |
| 97 | + | |
| 98 | + public void setRemotePort(String remotePort) { | |
| 99 | + this.remotePort = remotePort; | |
| 100 | + | |
| 101 | + } | |
| 102 | + | |
| 103 | + | |
| 104 | + // Miscellaneous debugger session preferences. | |
| 105 | + | |
| 106 | + public boolean getVerboseFlag() { | |
| 107 | + return verbose; | |
| 108 | + } | |
| 109 | + | |
| 110 | + public void setVerboseFlag(boolean verbose) { | |
| 111 | + this.verbose = verbose; | |
| 112 | + } | |
| 113 | + | |
| 114 | + | |
| 115 | + // Thread focus. | |
| 116 | + | |
| 117 | + public ThreadReference getCurrentThread() { | |
| 118 | + return currentThread; | |
| 119 | + } | |
| 120 | + | |
| 121 | + public void setCurrentThread(ThreadReference t) { | |
| 122 | + if (t != currentThread) { | |
| 123 | + currentThread = t; | |
| 124 | + notifyCurrentThreadChanged(t); | |
| 125 | + } | |
| 126 | + } | |
| 127 | + | |
| 128 | + public void setCurrentThreadInvalidate(ThreadReference t) { | |
| 129 | + currentThread = t; | |
| 130 | + notifyCurrentFrameChanged(runtime.threadInfo(t), | |
| 131 | + 0, true); | |
| 132 | + } | |
| 133 | + | |
| 134 | + public void invalidateCurrentThread() { | |
| 135 | + notifyCurrentFrameChanged(null, 0, true); | |
| 136 | + } | |
| 137 | + | |
| 138 | + | |
| 139 | + // If a view is displaying the current thread, it may | |
| 140 | + // choose to indicate which frame is current in the | |
| 141 | + // sense of the command-line UI. It may also "warp" the | |
| 142 | + // selection to that frame when changed by an 'up' or 'down' | |
| 143 | + // command. Hence, a notifier is provided. | |
| 144 | + | |
| 145 | + /****** | |
| 146 | + public int getCurrentFrameIndex() { | |
| 147 | + return getCurrentFrameIndex(currentThreadInfo); | |
| 148 | + } | |
| 149 | + ******/ | |
| 150 | + | |
| 151 | + public int getCurrentFrameIndex(ThreadReference t) { | |
| 152 | + return getCurrentFrameIndex(runtime.threadInfo(t)); | |
| 153 | + } | |
| 154 | + | |
| 155 | + //### Used in StackTraceTool. | |
| 156 | + public int getCurrentFrameIndex(ThreadInfo tinfo) { | |
| 157 | + if (tinfo == null) { | |
| 158 | + return 0; | |
| 159 | + } | |
| 160 | + Integer currentFrame = (Integer)tinfo.getUserObject(); | |
| 161 | + if (currentFrame == null) { | |
| 162 | + return 0; | |
| 163 | + } else { | |
| 164 | + return currentFrame.intValue(); | |
| 165 | + } | |
| 166 | + } | |
| 167 | + | |
| 168 | + public int moveCurrentFrameIndex(ThreadReference t, int count) throws VMNotInterruptedException { | |
| 169 | + return setCurrentFrameIndex(t,count, true); | |
| 170 | + } | |
| 171 | + | |
| 172 | + public int setCurrentFrameIndex(ThreadReference t, int newIndex) throws VMNotInterruptedException { | |
| 173 | + return setCurrentFrameIndex(t, newIndex, false); | |
| 174 | + } | |
| 175 | + | |
| 176 | + public int setCurrentFrameIndex(int newIndex) throws VMNotInterruptedException { | |
| 177 | + if (currentThread == null) { | |
| 178 | + return 0; | |
| 179 | + } else { | |
| 180 | + return setCurrentFrameIndex(currentThread, newIndex, false); | |
| 181 | + } | |
| 182 | + } | |
| 183 | + | |
| 184 | + private int setCurrentFrameIndex(ThreadReference t, int x, boolean relative) throws VMNotInterruptedException { | |
| 185 | + boolean sameThread = t.equals(currentThread); | |
| 186 | + ThreadInfo tinfo = runtime.threadInfo(t); | |
| 187 | + if (tinfo == null) { | |
| 188 | + return 0; | |
| 189 | + } | |
| 190 | + int maxIndex = tinfo.getFrameCount()-1; | |
| 191 | + int oldIndex = getCurrentFrameIndex(tinfo); | |
| 192 | + int newIndex = relative? oldIndex + x : x; | |
| 193 | + if (newIndex > maxIndex) { | |
| 194 | + newIndex = maxIndex; | |
| 195 | + } else if (newIndex < 0) { | |
| 196 | + newIndex = 0; | |
| 197 | + } | |
| 198 | + if (!sameThread || newIndex != oldIndex) { // don't recurse | |
| 199 | + setCurrentFrameIndex(tinfo, newIndex); | |
| 200 | + } | |
| 201 | + return newIndex - oldIndex; | |
| 202 | + } | |
| 203 | + | |
| 204 | + private void setCurrentFrameIndex(ThreadInfo tinfo, int index) { | |
| 205 | + tinfo.setUserObject(new Integer(index)); | |
| 206 | + //### In fact, the value may not have changed at this point. | |
| 207 | + //### We need to signal that the user attempted to change it, | |
| 208 | + //### however, so that the selection can be "warped" to the | |
| 209 | + //### current location. | |
| 210 | + notifyCurrentFrameChanged(tinfo.thread(), index); | |
| 211 | + } | |
| 212 | + | |
| 213 | + public StackFrame getCurrentFrame() throws VMNotInterruptedException { | |
| 214 | + return getCurrentFrame(runtime.threadInfo(currentThread)); | |
| 215 | + } | |
| 216 | + | |
| 217 | + public StackFrame getCurrentFrame(ThreadReference t) throws VMNotInterruptedException { | |
| 218 | + return getCurrentFrame(runtime.threadInfo(t)); | |
| 219 | + } | |
| 220 | + | |
| 221 | + public StackFrame getCurrentFrame(ThreadInfo tinfo) throws VMNotInterruptedException { | |
| 222 | + int index = getCurrentFrameIndex(tinfo); | |
| 223 | + try { | |
| 224 | + // It is possible, though unlikely, that the VM was interrupted | |
| 225 | + // before the thread created its Java stack. | |
| 226 | + return tinfo.getFrame(index); | |
| 227 | + } catch (FrameIndexOutOfBoundsException e) { | |
| 228 | + return null; | |
| 229 | + } | |
| 230 | + } | |
| 231 | + | |
| 232 | + public void addContextListener(ContextListener cl) { | |
| 233 | + contextListeners.add(cl); | |
| 234 | + } | |
| 235 | + | |
| 236 | + public void removeContextListener(ContextListener cl) { | |
| 237 | + contextListeners.remove(cl); | |
| 238 | + } | |
| 239 | + | |
| 240 | + //### These notifiers are fired only in response to USER-INITIATED changes | |
| 241 | + //### to the current thread and current frame. When the current thread is set automatically | |
| 242 | + //### after a breakpoint hit or step completion, no event is generated. Instead, | |
| 243 | + //### interested parties are expected to listen for the BreakpointHit and StepCompleted | |
| 244 | + //### events. This convention is unclean, and I believe that it reflects a defect in | |
| 245 | + //### in the current architecture. Unfortunately, however, we cannot guarantee the | |
| 246 | + //### order in which various listeners receive a given event, and the handlers for | |
| 247 | + //### the very same events that cause automatic changes to the current thread may also | |
| 248 | + //### need to know the current thread. | |
| 249 | + | |
| 250 | + private void notifyCurrentThreadChanged(ThreadReference t) { | |
| 251 | + ThreadInfo tinfo = null; | |
| 252 | + int index = 0; | |
| 253 | + if (t != null) { | |
| 254 | + tinfo = runtime.threadInfo(t); | |
| 255 | + index = getCurrentFrameIndex(tinfo); | |
| 256 | + } | |
| 257 | + notifyCurrentFrameChanged(tinfo, index, false); | |
| 258 | + } | |
| 259 | + | |
| 260 | + private void notifyCurrentFrameChanged(ThreadReference t, int index) { | |
| 261 | + notifyCurrentFrameChanged(runtime.threadInfo(t), | |
| 262 | + index, false); | |
| 263 | + } | |
| 264 | + | |
| 265 | + private void notifyCurrentFrameChanged(ThreadInfo tinfo, int index, | |
| 266 | + boolean invalidate) { | |
| 267 | + ArrayList<ContextListener> l = new ArrayList<ContextListener>(contextListeners); | |
| 268 | + CurrentFrameChangedEvent evt = | |
| 269 | + new CurrentFrameChangedEvent(this, tinfo, index, invalidate); | |
| 270 | + for (int i = 0; i < l.size(); i++) { | |
| 271 | + l.get(i).currentFrameChanged(evt); | |
| 272 | + } | |
| 273 | + } | |
| 274 | + | |
| 275 | + private class ContextManagerListener extends JDIAdapter | |
| 276 | + implements SessionListener, JDIListener { | |
| 277 | + | |
| 278 | + // SessionListener | |
| 279 | + | |
| 280 | + @Override | |
| 281 | + public void sessionStart(EventObject e) { | |
| 282 | + invalidateCurrentThread(); | |
| 283 | + } | |
| 284 | + | |
| 285 | + @Override | |
| 286 | + public void sessionInterrupt(EventObject e) { | |
| 287 | + setCurrentThreadInvalidate(currentThread); | |
| 288 | + } | |
| 289 | + | |
| 290 | + @Override | |
| 291 | + public void sessionContinue(EventObject e) { | |
| 292 | + invalidateCurrentThread(); | |
| 293 | + } | |
| 294 | + | |
| 295 | + // JDIListener | |
| 296 | + | |
| 297 | + @Override | |
| 298 | + public void locationTrigger(LocationTriggerEventSet e) { | |
| 299 | + setCurrentThreadInvalidate(e.getThread()); | |
| 300 | + } | |
| 301 | + | |
| 302 | + @Override | |
| 303 | + public void exception(ExceptionEventSet e) { | |
| 304 | + setCurrentThreadInvalidate(e.getThread()); | |
| 305 | + } | |
| 306 | + | |
| 307 | + @Override | |
| 308 | + public void vmDisconnect(VMDisconnectEventSet e) { | |
| 309 | + invalidateCurrentThread(); | |
| 310 | + } | |
| 311 | + | |
| 312 | + } | |
| 313 | + | |
| 314 | + | |
| 315 | + /** | |
| 316 | + * Add a -classpath argument to the arguments passed to the exec'ed | |
| 317 | + * VM with the contents of CLASSPATH environment variable, | |
| 318 | + * if -classpath was not already specified. | |
| 319 | + * | |
| 320 | + * @param javaArgs the arguments to the VM being exec'd that | |
| 321 | + * potentially has a user specified -classpath argument. | |
| 322 | + * @return a javaArgs whose -classpath option has been added | |
| 323 | + */ | |
| 324 | + | |
| 325 | + private String processClasspathDefaults(String javaArgs) { | |
| 326 | + if (javaArgs.indexOf("-classpath ") == -1) { | |
| 327 | + StringBuffer munged = new StringBuffer(javaArgs); | |
| 328 | + SearchPath classpath = classManager.getClassPath(); | |
| 329 | + if (classpath.isEmpty()) { | |
| 330 | + String envcp = System.getProperty("env.class.path"); | |
| 331 | + if ((envcp != null) && (envcp.length() > 0)) { | |
| 332 | + munged.append(" -classpath " + envcp); | |
| 333 | + } | |
| 334 | + } else { | |
| 335 | + munged.append(" -classpath " + classpath.asString()); | |
| 336 | + } | |
| 337 | + return munged.toString(); | |
| 338 | + } else { | |
| 339 | + return javaArgs; | |
| 340 | + } | |
| 341 | + } | |
| 342 | + | |
| 343 | + private String appendPath(String path1, String path2) { | |
| 344 | + if (path1 == null || path1.length() == 0) { | |
| 345 | + return path2 == null ? "." : path2; | |
| 346 | + } else if (path2 == null || path2.length() == 0) { | |
| 347 | + return path1; | |
| 348 | + } else { | |
| 349 | + return path1 + File.pathSeparator + path2; | |
| 350 | + } | |
| 351 | + } | |
| 352 | + | |
| 353 | +} | |
| @@ -0,0 +1,62 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import com.sun.jdi.*; | |
| 29 | +import com.sun.tools.example.debug.bdi.*; | |
| 30 | +import java.util.EventObject; | |
| 31 | + | |
| 32 | +public class CurrentFrameChangedEvent extends EventObject { | |
| 33 | + | |
| 34 | + private static final long serialVersionUID = 4214479486546762179L; | |
| 35 | + private ThreadInfo tinfo; | |
| 36 | + private int index; | |
| 37 | + private boolean invalidate; | |
| 38 | + | |
| 39 | + public CurrentFrameChangedEvent(Object source, ThreadInfo tinfo, | |
| 40 | + int index, boolean invalidate) { | |
| 41 | + super(source); | |
| 42 | + this.tinfo = tinfo; | |
| 43 | + this.index = index; | |
| 44 | + this.invalidate = invalidate; | |
| 45 | + } | |
| 46 | + | |
| 47 | + public ThreadReference getThread() { | |
| 48 | + return tinfo == null? null : tinfo.thread(); | |
| 49 | + } | |
| 50 | + | |
| 51 | + public ThreadInfo getThreadInfo() { | |
| 52 | + return tinfo; | |
| 53 | + } | |
| 54 | + | |
| 55 | + public int getIndex() { | |
| 56 | + return index; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public boolean getInvalidate() { | |
| 60 | + return invalidate; | |
| 61 | + } | |
| 62 | +} | |
| @@ -0,0 +1,156 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | +import com.sun.jdi.*; | |
| 30 | +import com.sun.tools.example.debug.bdi.*; | |
| 31 | + | |
| 32 | +public class Environment { | |
| 33 | + | |
| 34 | + private SourceManager sourceManager; | |
| 35 | + private ClassManager classManager; | |
| 36 | + private ContextManager contextManager; | |
| 37 | + private MonitorListModel monitorListModel; | |
| 38 | + private ExecutionManager runtime; | |
| 39 | + | |
| 40 | + private PrintWriter typeScript; | |
| 41 | + | |
| 42 | + private boolean verbose; | |
| 43 | + | |
| 44 | + public Environment() { | |
| 45 | + this.classManager = new ClassManager(this); | |
| 46 | + //### Order of the next three lines is important! (FIX THIS) | |
| 47 | + this.runtime = new ExecutionManager(); | |
| 48 | + this.sourceManager = new SourceManager(this); | |
| 49 | + this.contextManager = new ContextManager(this); | |
| 50 | + this.monitorListModel = new MonitorListModel(this); | |
| 51 | + } | |
| 52 | + | |
| 53 | + // Services used by debugging tools. | |
| 54 | + | |
| 55 | + public SourceManager getSourceManager() { | |
| 56 | + return sourceManager; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public ClassManager getClassManager() { | |
| 60 | + return classManager; | |
| 61 | + } | |
| 62 | + | |
| 63 | + public ContextManager getContextManager() { | |
| 64 | + return contextManager; | |
| 65 | + } | |
| 66 | + | |
| 67 | + public MonitorListModel getMonitorListModel() { | |
| 68 | + return monitorListModel; | |
| 69 | + } | |
| 70 | + | |
| 71 | + public ExecutionManager getExecutionManager() { | |
| 72 | + return runtime; | |
| 73 | + } | |
| 74 | + | |
| 75 | + //### TODO: | |
| 76 | + //### Tools should attach/detach from environment | |
| 77 | + //### via a property, which should call an 'addTool' | |
| 78 | + //### method when set to maintain a registry of | |
| 79 | + //### tools for exit-time cleanup, etc. Tool | |
| 80 | + //### class constructors should be argument-free, so | |
| 81 | + //### that they may be instantiated by bean builders. | |
| 82 | + //### Will also need 'removeTool' in case property | |
| 83 | + //### value is changed. | |
| 84 | + // | |
| 85 | + // public void addTool(Tool t); | |
| 86 | + // public void removeTool(Tool t); | |
| 87 | + | |
| 88 | + public void terminate() { | |
| 89 | + System.exit(0); | |
| 90 | + } | |
| 91 | + | |
| 92 | + // public void refresh(); // notify all tools to refresh their views | |
| 93 | + | |
| 94 | + | |
| 95 | + // public void addStatusListener(StatusListener l); | |
| 96 | + // public void removeStatusListener(StatusListener l); | |
| 97 | + | |
| 98 | + // public void addOutputListener(OutputListener l); | |
| 99 | + // public void removeOutputListener(OutputListener l); | |
| 100 | + | |
| 101 | + public void setTypeScript(PrintWriter writer) { | |
| 102 | + typeScript = writer; | |
| 103 | + } | |
| 104 | + | |
| 105 | + public void error(String message) { | |
| 106 | + if (typeScript != null) { | |
| 107 | + typeScript.println(message); | |
| 108 | + } else { | |
| 109 | + System.out.println(message); | |
| 110 | + } | |
| 111 | + } | |
| 112 | + | |
| 113 | + public void failure(String message) { | |
| 114 | + if (typeScript != null) { | |
| 115 | + typeScript.println(message); | |
| 116 | + } else { | |
| 117 | + System.out.println(message); | |
| 118 | + } | |
| 119 | + } | |
| 120 | + | |
| 121 | + public void notice(String message) { | |
| 122 | + if (typeScript != null) { | |
| 123 | + typeScript.println(message); | |
| 124 | + } else { | |
| 125 | + System.out.println(message); | |
| 126 | + } | |
| 127 | + } | |
| 128 | + | |
| 129 | + public OutputSink getOutputSink() { | |
| 130 | + return new OutputSink(typeScript); | |
| 131 | + } | |
| 132 | + | |
| 133 | + public void viewSource(String fileName) { | |
| 134 | + //### HACK ### | |
| 135 | + //### Should use listener here. | |
| 136 | + com.sun.tools.example.debug.gui.GUI.srcTool.showSourceFile(fileName); | |
| 137 | + } | |
| 138 | + | |
| 139 | + public void viewLocation(Location locn) { | |
| 140 | + //### HACK ### | |
| 141 | + //### Should use listener here. | |
| 142 | + //### Should we use sourceForLocation here? | |
| 143 | + com.sun.tools.example.debug.gui.GUI.srcTool.showSourceForLocation(locn); | |
| 144 | + } | |
| 145 | + | |
| 146 | + //### Also in 'ContextManager'. Do we need both? | |
| 147 | + | |
| 148 | + public boolean getVerboseFlag() { | |
| 149 | + return verbose; | |
| 150 | + } | |
| 151 | + | |
| 152 | + public void setVerboseFlag(boolean verbose) { | |
| 153 | + this.verbose = verbose; | |
| 154 | + } | |
| 155 | + | |
| 156 | +} | |
| @@ -0,0 +1,256 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | +import javax.swing.*; | |
| 30 | +import javax.swing.border.*; | |
| 31 | +import java.awt.*; | |
| 32 | +import java.awt.event.*; | |
| 33 | + | |
| 34 | +import com.sun.jdi.*; | |
| 35 | +import com.sun.tools.example.debug.bdi.*; | |
| 36 | + | |
| 37 | +public class GUI extends JPanel { | |
| 38 | + | |
| 39 | + private static final long serialVersionUID = 3292463234530679091L; | |
| 40 | + private CommandTool cmdTool; | |
| 41 | + private ApplicationTool appTool; | |
| 42 | + //###HACK## | |
| 43 | + //### There is currently dirty code in Environment that | |
| 44 | + //### accesses this directly. | |
| 45 | + //private SourceTool srcTool; | |
| 46 | + public static SourceTool srcTool; | |
| 47 | + | |
| 48 | + private SourceTreeTool sourceTreeTool; | |
| 49 | + private ClassTreeTool classTreeTool; | |
| 50 | + private ThreadTreeTool threadTreeTool; | |
| 51 | + private StackTraceTool stackTool; | |
| 52 | + private MonitorTool monitorTool; | |
| 53 | + | |
| 54 | + public static final String progname = "javadt"; | |
| 55 | + public static final String version = "1.0Beta"; //### FIX ME. | |
| 56 | + public static final String windowBanner = "Java(tm) platform Debug Tool"; | |
| 57 | + | |
| 58 | + private Font fixedFont = new Font("monospaced", Font.PLAIN, 10); | |
| 59 | + | |
| 60 | + private GUI(Environment env) { | |
| 61 | + setLayout(new BorderLayout()); | |
| 62 | + | |
| 63 | + setBorder(new EmptyBorder(5, 5, 5, 5)); | |
| 64 | + | |
| 65 | + add(new JDBToolBar(env), BorderLayout.NORTH); | |
| 66 | + | |
| 67 | + srcTool = new SourceTool(env); | |
| 68 | + srcTool.setPreferredSize(new java.awt.Dimension(500, 300)); | |
| 69 | + srcTool.setTextFont(fixedFont); | |
| 70 | + | |
| 71 | + stackTool = new StackTraceTool(env); | |
| 72 | + stackTool.setPreferredSize(new java.awt.Dimension(500, 100)); | |
| 73 | + | |
| 74 | + monitorTool = new MonitorTool(env); | |
| 75 | + monitorTool.setPreferredSize(new java.awt.Dimension(500, 50)); | |
| 76 | + | |
| 77 | + JSplitPane right = new JSplitPane(JSplitPane.VERTICAL_SPLIT, srcTool, | |
| 78 | + new JSplitPane(JSplitPane.VERTICAL_SPLIT, stackTool, monitorTool)); | |
| 79 | + | |
| 80 | + sourceTreeTool = new SourceTreeTool(env); | |
| 81 | + sourceTreeTool.setPreferredSize(new java.awt.Dimension(200, 450)); | |
| 82 | + | |
| 83 | + classTreeTool = new ClassTreeTool(env); | |
| 84 | + classTreeTool.setPreferredSize(new java.awt.Dimension(200, 450)); | |
| 85 | + | |
| 86 | + threadTreeTool = new ThreadTreeTool(env); | |
| 87 | + threadTreeTool.setPreferredSize(new java.awt.Dimension(200, 450)); | |
| 88 | + | |
| 89 | + JTabbedPane treePane = new JTabbedPane(SwingConstants.BOTTOM); | |
| 90 | + treePane.addTab("Source", null, sourceTreeTool); | |
| 91 | + treePane.addTab("Classes", null, classTreeTool); | |
| 92 | + treePane.addTab("Threads", null, threadTreeTool); | |
| 93 | + | |
| 94 | + JSplitPane centerTop = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treePane, right); | |
| 95 | + | |
| 96 | + cmdTool = new CommandTool(env); | |
| 97 | + cmdTool.setPreferredSize(new java.awt.Dimension(700, 150)); | |
| 98 | + | |
| 99 | + appTool = new ApplicationTool(env); | |
| 100 | + appTool.setPreferredSize(new java.awt.Dimension(700, 200)); | |
| 101 | + | |
| 102 | + JSplitPane centerBottom = new JSplitPane(JSplitPane.VERTICAL_SPLIT, cmdTool, appTool); | |
| 103 | + // centerBottom.setPreferredSize(new java.awt.Dimension(700, 350)); | |
| 104 | + | |
| 105 | + JSplitPane center = new JSplitPane(JSplitPane.VERTICAL_SPLIT, centerTop, centerBottom); | |
| 106 | + | |
| 107 | + add(center, BorderLayout.CENTER); | |
| 108 | + | |
| 109 | + | |
| 110 | + } | |
| 111 | + | |
| 112 | + private static void usage() { | |
| 113 | + String separator = File.pathSeparator; | |
| 114 | + System.out.println("Usage: " + progname + " <options> <class> <arguments>"); | |
| 115 | + System.out.println(); | |
| 116 | + System.out.println("where options include:"); | |
| 117 | + System.out.println(" -help print out this message and exit"); | |
| 118 | + System.out.println(" -sourcepath <directories separated by \"" + | |
| 119 | + separator + "\">"); | |
| 120 | + System.out.println(" list directories in which to look for source files"); | |
| 121 | + System.out.println(" -remote <hostname>:<port-number>"); | |
| 122 | + System.out.println(" host machine and port number of interpreter to attach to"); | |
| 123 | + System.out.println(" -dbgtrace [flags] print info for debugging " + progname); | |
| 124 | + System.out.println(); | |
| 125 | + System.out.println("options forwarded to debuggee process:"); | |
| 126 | + System.out.println(" -v -verbose[:class|gc|jni]"); | |
| 127 | + System.out.println(" turn on verbose mode"); | |
| 128 | + System.out.println(" -D<name>=<value> set a system property"); | |
| 129 | + System.out.println(" -classpath <directories separated by \"" + | |
| 130 | + separator + "\">"); | |
| 131 | + System.out.println(" list directories in which to look for classes"); | |
| 132 | + System.out.println(" -X<option> non-standard debuggee VM option"); | |
| 133 | + System.out.println(); | |
| 134 | + System.out.println("<class> is the name of the class to begin debugging"); | |
| 135 | + System.out.println("<arguments> are the arguments passed to the main() method of <class>"); | |
| 136 | + System.out.println(); | |
| 137 | + System.out.println("For command help type 'help' at " + progname + " prompt"); | |
| 138 | + } | |
| 139 | + | |
| 140 | + public static void main(String argv[]) { | |
| 141 | + String clsName = ""; | |
| 142 | + String progArgs = ""; | |
| 143 | + String javaArgs = ""; | |
| 144 | + final Environment env = new Environment(); | |
| 145 | + | |
| 146 | + JPanel mainPanel = new GUI(env); | |
| 147 | + | |
| 148 | + ContextManager context = env.getContextManager(); | |
| 149 | + ExecutionManager runtime = env.getExecutionManager(); | |
| 150 | + | |
| 151 | + for (int i = 0; i < argv.length; i++) { | |
| 152 | + String token = argv[i]; | |
| 153 | + if (token.equals("-dbgtrace")) { | |
| 154 | + if ((i == argv.length - 1) || | |
| 155 | + ! Character.isDigit(argv[i+1].charAt(0))) { | |
| 156 | + runtime.setTraceMode(VirtualMachine.TRACE_ALL); | |
| 157 | + } else { | |
| 158 | + String flagStr = argv[++i]; | |
| 159 | + runtime.setTraceMode(Integer.decode(flagStr).intValue()); | |
| 160 | + } | |
| 161 | + } else if (token.equals("-X")) { | |
| 162 | + System.out.println( | |
| 163 | + "Use 'java -X' to see the available non-standard options"); | |
| 164 | + System.out.println(); | |
| 165 | + usage(); | |
| 166 | + System.exit(1); | |
| 167 | + } else if ( | |
| 168 | + // Standard VM options passed on | |
| 169 | + token.equals("-v") || token.startsWith("-v:") || // -v[:...] | |
| 170 | + token.startsWith("-verbose") || // -verbose[:...] | |
| 171 | + token.startsWith("-D") || | |
| 172 | + // NonStandard options passed on | |
| 173 | + token.startsWith("-X") || | |
| 174 | + // Old-style options | |
| 175 | + // (These should remain in place as long as the standard VM accepts them) | |
| 176 | + token.equals("-noasyncgc") || token.equals("-prof") || | |
| 177 | + token.equals("-verify") || token.equals("-noverify") || | |
| 178 | + token.equals("-verifyremote") || | |
| 179 | + token.equals("-verbosegc") || | |
| 180 | + token.startsWith("-ms") || token.startsWith("-mx") || | |
| 181 | + token.startsWith("-ss") || token.startsWith("-oss") ) { | |
| 182 | + javaArgs += token + " "; | |
| 183 | + } else if (token.equals("-sourcepath")) { | |
| 184 | + if (i == (argv.length - 1)) { | |
| 185 | + System.out.println("No sourcepath specified."); | |
| 186 | + usage(); | |
| 187 | + System.exit(1); | |
| 188 | + } | |
| 189 | + env.getSourceManager().setSourcePath(new SearchPath(argv[++i])); | |
| 190 | + } else if (token.equals("-classpath")) { | |
| 191 | + if (i == (argv.length - 1)) { | |
| 192 | + System.out.println("No classpath specified."); | |
| 193 | + usage(); | |
| 194 | + System.exit(1); | |
| 195 | + } | |
| 196 | + env.getClassManager().setClassPath(new SearchPath(argv[++i])); | |
| 197 | + } else if (token.equals("-remote")) { | |
| 198 | + if (i == (argv.length - 1)) { | |
| 199 | + System.out.println("No remote specified."); | |
| 200 | + usage(); | |
| 201 | + System.exit(1); | |
| 202 | + } | |
| 203 | + env.getContextManager().setRemotePort(argv[++i]); | |
| 204 | + } else if (token.equals("-help")) { | |
| 205 | + usage(); | |
| 206 | + System.exit(0); | |
| 207 | + } else if (token.equals("-version")) { | |
| 208 | + System.out.println(progname + " version " + version); | |
| 209 | + System.exit(0); | |
| 210 | + } else if (token.startsWith("-")) { | |
| 211 | + System.out.println("invalid option: " + token); | |
| 212 | + usage(); | |
| 213 | + System.exit(1); | |
| 214 | + } else { | |
| 215 | + // Everything from here is part of the command line | |
| 216 | + clsName = token; | |
| 217 | + for (i++; i < argv.length; i++) { | |
| 218 | + progArgs += argv[i] + " "; | |
| 219 | + } | |
| 220 | + break; | |
| 221 | + } | |
| 222 | + } | |
| 223 | + | |
| 224 | + context.setMainClassName(clsName); | |
| 225 | + context.setProgramArguments(progArgs); | |
| 226 | + context.setVmArguments(javaArgs); | |
| 227 | + | |
| 228 | + // Force Cross Platform L&F | |
| 229 | + try { | |
| 230 | + UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); | |
| 231 | + // If you want the System L&F instead, comment out the above line and | |
| 232 | + // uncomment the following: | |
| 233 | + // UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); | |
| 234 | + } catch (Exception exc) { | |
| 235 | + System.err.println("Error loading L&F: " + exc); | |
| 236 | + } | |
| 237 | + | |
| 238 | + JFrame frame = new JFrame(); | |
| 239 | + frame.setBackground(Color.lightGray); | |
| 240 | + frame.setTitle(windowBanner); | |
| 241 | + frame.setJMenuBar(new JDBMenuBar(env)); | |
| 242 | + frame.setContentPane(mainPanel); | |
| 243 | + | |
| 244 | + frame.addWindowListener(new WindowAdapter() { | |
| 245 | + @Override | |
| 246 | + public void windowClosing(WindowEvent e) { | |
| 247 | + env.terminate(); | |
| 248 | + } | |
| 249 | + }); | |
| 250 | + | |
| 251 | + frame.pack(); | |
| 252 | + frame.setVisible(true); | |
| 253 | + | |
| 254 | + } | |
| 255 | + | |
| 256 | +} | |
| @@ -0,0 +1,209 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import javax.swing.Icon; | |
| 29 | +import javax.swing.ImageIcon; | |
| 30 | + | |
| 31 | +class Icons { | |
| 32 | + | |
| 33 | + private static int[] exec = { | |
| 34 | + 0xffd8ffe0, 0x00104a46, 0x49460001, 0x01020000 | |
| 35 | +, 0x00000000, 0xffdb0043, 0x00020101, 0x01010102 | |
| 36 | +, 0x01010102, 0x02020202, 0x04030202, 0x02020504 | |
| 37 | +, 0x04030406, 0x05060606, 0x05060606, 0x07090806 | |
| 38 | +, 0x07090706, 0x06080b08, 0x090a0a0a, 0x0a0a0608 | |
| 39 | +, 0x0b0c0b0a, 0x0c090a0a, 0x0affdb00, 0x43010202 | |
| 40 | +, 0x02020202, 0x05030305, 0x0a070607, 0x0a0a0a0a | |
| 41 | +, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a | |
| 42 | +, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a | |
| 43 | +, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0affc0 | |
| 44 | +, 0x00110800, 0x0c000c03, 0x01220002, 0x11010311 | |
| 45 | +, 0x01ffc400, 0x1f000001, 0x05010101, 0x01010100 | |
| 46 | +, 0x00000000, 0x00000001, 0x02030405, 0x06070809 | |
| 47 | +, 0x0a0bffc4, 0x00b51000, 0x02010303, 0x02040305 | |
| 48 | +, 0x05040400, 0x00017d01, 0x02030004, 0x11051221 | |
| 49 | +, 0x31410613, 0x51610722, 0x71143281, 0x91a10823 | |
| 50 | +, 0x42b1c115, 0x52d1f024, 0x33627282, 0x090a1617 | |
| 51 | +, 0x18191a25, 0x26272829, 0x2a343536, 0x3738393a | |
| 52 | +, 0x43444546, 0x4748494a, 0x53545556, 0x5758595a | |
| 53 | +, 0x63646566, 0x6768696a, 0x73747576, 0x7778797a | |
| 54 | +, 0x83848586, 0x8788898a, 0x92939495, 0x96979899 | |
| 55 | +, 0x9aa2a3a4, 0xa5a6a7a8, 0xa9aab2b3, 0xb4b5b6b7 | |
| 56 | +, 0xb8b9bac2, 0xc3c4c5c6, 0xc7c8c9ca, 0xd2d3d4d5 | |
| 57 | +, 0xd6d7d8d9, 0xdae1e2e3, 0xe4e5e6e7, 0xe8e9eaf1 | |
| 58 | +, 0xf2f3f4f5, 0xf6f7f8f9, 0xfaffc400, 0x1f010003 | |
| 59 | +, 0x01010101, 0x01010101, 0x01000000, 0x00000001 | |
| 60 | +, 0x02030405, 0x06070809, 0x0a0bffc4, 0x00b51100 | |
| 61 | +, 0x02010204, 0x04030407, 0x05040400, 0x01027700 | |
| 62 | +, 0x01020311, 0x04052131, 0x06124151, 0x07617113 | |
| 63 | +, 0x22328108, 0x144291a1, 0xb1c10923, 0x3352f015 | |
| 64 | +, 0x6272d10a, 0x162434e1, 0x25f11718, 0x191a2627 | |
| 65 | +, 0x28292a35, 0x36373839, 0x3a434445, 0x46474849 | |
| 66 | +, 0x4a535455, 0x56575859, 0x5a636465, 0x66676869 | |
| 67 | +, 0x6a737475, 0x76777879, 0x7a828384, 0x85868788 | |
| 68 | +, 0x898a9293, 0x94959697, 0x98999aa2, 0xa3a4a5a6 | |
| 69 | +, 0xa7a8a9aa, 0xb2b3b4b5, 0xb6b7b8b9, 0xbac2c3c4 | |
| 70 | +, 0xc5c6c7c8, 0xc9cad2d3, 0xd4d5d6d7, 0xd8d9dae2 | |
| 71 | +, 0xe3e4e5e6, 0xe7e8e9ea, 0xf2f3f4f5, 0xf6f7f8f9 | |
| 72 | +, 0xfaffda00, 0x0c030100, 0x02110311, 0x003f00fd | |
| 73 | +, 0xbafda27e, 0x35ea1f03, 0x346f0ef8, 0x86cfc2d3 | |
| 74 | +, 0x6b31ea9e, 0x2ab7d2ee, 0xf4fb38cb, 0x5cc91cb0 | |
| 75 | +, 0xce4790a0, 0xfcd2ef44, 0xc29e1f95, 0xf94b065f | |
| 76 | +, 0x42a86eb4, 0xed3ef67b, 0x7b9bcb18, 0x6692ce63 | |
| 77 | +, 0x35a492c4, 0x19a090a3, 0x465d09fb, 0xadb1dd72 | |
| 78 | +, 0x39daec3a, 0x13535706, 0x1f0f8ca7, 0x8dad56a5 | |
| 79 | +, 0x5e6a72e5, 0xe485be0b, 0x2b49df77, 0xcceda6ca | |
| 80 | +, 0xda6ece3a, 0x147150c5, 0xd5a93a97, 0x84b97963 | |
| 81 | +, 0x6f86cbde, 0x77ddf33b, 0x69b2b69b, 0xb3ffd900 | |
| 82 | + | |
| 83 | + }; | |
| 84 | + private static int[] blank = { | |
| 85 | + 0xffd8ffe0, 0x00104a46, 0x49460001, 0x01020000 | |
| 86 | +, 0x00000000, 0xffdb0043, 0x00020101, 0x01010102 | |
| 87 | +, 0x01010102, 0x02020202, 0x04030202, 0x02020504 | |
| 88 | +, 0x04030406, 0x05060606, 0x05060606, 0x07090806 | |
| 89 | +, 0x07090706, 0x06080b08, 0x090a0a0a, 0x0a0a0608 | |
| 90 | +, 0x0b0c0b0a, 0x0c090a0a, 0x0affdb00, 0x43010202 | |
| 91 | +, 0x02020202, 0x05030305, 0x0a070607, 0x0a0a0a0a | |
| 92 | +, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a | |
| 93 | +, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a | |
| 94 | +, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0affc0 | |
| 95 | +, 0x00110800, 0x0c000c03, 0x01220002, 0x11010311 | |
| 96 | +, 0x01ffc400, 0x1f000001, 0x05010101, 0x01010100 | |
| 97 | +, 0x00000000, 0x00000001, 0x02030405, 0x06070809 | |
| 98 | +, 0x0a0bffc4, 0x00b51000, 0x02010303, 0x02040305 | |
| 99 | +, 0x05040400, 0x00017d01, 0x02030004, 0x11051221 | |
| 100 | +, 0x31410613, 0x51610722, 0x71143281, 0x91a10823 | |
| 101 | +, 0x42b1c115, 0x52d1f024, 0x33627282, 0x090a1617 | |
| 102 | +, 0x18191a25, 0x26272829, 0x2a343536, 0x3738393a | |
| 103 | +, 0x43444546, 0x4748494a, 0x53545556, 0x5758595a | |
| 104 | +, 0x63646566, 0x6768696a, 0x73747576, 0x7778797a | |
| 105 | +, 0x83848586, 0x8788898a, 0x92939495, 0x96979899 | |
| 106 | +, 0x9aa2a3a4, 0xa5a6a7a8, 0xa9aab2b3, 0xb4b5b6b7 | |
| 107 | +, 0xb8b9bac2, 0xc3c4c5c6, 0xc7c8c9ca, 0xd2d3d4d5 | |
| 108 | +, 0xd6d7d8d9, 0xdae1e2e3, 0xe4e5e6e7, 0xe8e9eaf1 | |
| 109 | +, 0xf2f3f4f5, 0xf6f7f8f9, 0xfaffc400, 0x1f010003 | |
| 110 | +, 0x01010101, 0x01010101, 0x01000000, 0x00000001 | |
| 111 | +, 0x02030405, 0x06070809, 0x0a0bffc4, 0x00b51100 | |
| 112 | +, 0x02010204, 0x04030407, 0x05040400, 0x01027700 | |
| 113 | +, 0x01020311, 0x04052131, 0x06124151, 0x07617113 | |
| 114 | +, 0x22328108, 0x144291a1, 0xb1c10923, 0x3352f015 | |
| 115 | +, 0x6272d10a, 0x162434e1, 0x25f11718, 0x191a2627 | |
| 116 | +, 0x28292a35, 0x36373839, 0x3a434445, 0x46474849 | |
| 117 | +, 0x4a535455, 0x56575859, 0x5a636465, 0x66676869 | |
| 118 | +, 0x6a737475, 0x76777879, 0x7a828384, 0x85868788 | |
| 119 | +, 0x898a9293, 0x94959697, 0x98999aa2, 0xa3a4a5a6 | |
| 120 | +, 0xa7a8a9aa, 0xb2b3b4b5, 0xb6b7b8b9, 0xbac2c3c4 | |
| 121 | +, 0xc5c6c7c8, 0xc9cad2d3, 0xd4d5d6d7, 0xd8d9dae2 | |
| 122 | +, 0xe3e4e5e6, 0xe7e8e9ea, 0xf2f3f4f5, 0xf6f7f8f9 | |
| 123 | +, 0xfaffda00, 0x0c030100, 0x02110311, 0x003f00fd | |
| 124 | +, 0xfca28a28, 0x03ffd900 | |
| 125 | + | |
| 126 | + }; | |
| 127 | + | |
| 128 | + private static int[] stopSignWords = { | |
| 129 | + 0xffd8ffe0, 0x00104a46, 0x49460001, 0x01020000 | |
| 130 | +, 0x00000000, 0xffdb0043, 0x00020101, 0x01010102 | |
| 131 | +, 0x01010102, 0x02020202, 0x04030202, 0x02020504 | |
| 132 | +, 0x04030406, 0x05060606, 0x05060606, 0x07090806 | |
| 133 | +, 0x07090706, 0x06080b08, 0x090a0a0a, 0x0a0a0608 | |
| 134 | +, 0x0b0c0b0a, 0x0c090a0a, 0x0affdb00, 0x43010202 | |
| 135 | +, 0x02020202, 0x05030305, 0x0a070607, 0x0a0a0a0a | |
| 136 | +, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a | |
| 137 | +, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a | |
| 138 | +, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0affc0 | |
| 139 | +, 0x00110800, 0x0c000c03, 0x01220002, 0x11010311 | |
| 140 | +, 0x01ffc400, 0x1f000001, 0x05010101, 0x01010100 | |
| 141 | +, 0x00000000, 0x00000001, 0x02030405, 0x06070809 | |
| 142 | +, 0x0a0bffc4, 0x00b51000, 0x02010303, 0x02040305 | |
| 143 | +, 0x05040400, 0x00017d01, 0x02030004, 0x11051221 | |
| 144 | +, 0x31410613, 0x51610722, 0x71143281, 0x91a10823 | |
| 145 | +, 0x42b1c115, 0x52d1f024, 0x33627282, 0x090a1617 | |
| 146 | +, 0x18191a25, 0x26272829, 0x2a343536, 0x3738393a | |
| 147 | +, 0x43444546, 0x4748494a, 0x53545556, 0x5758595a | |
| 148 | +, 0x63646566, 0x6768696a, 0x73747576, 0x7778797a | |
| 149 | +, 0x83848586, 0x8788898a, 0x92939495, 0x96979899 | |
| 150 | +, 0x9aa2a3a4, 0xa5a6a7a8, 0xa9aab2b3, 0xb4b5b6b7 | |
| 151 | +, 0xb8b9bac2, 0xc3c4c5c6, 0xc7c8c9ca, 0xd2d3d4d5 | |
| 152 | +, 0xd6d7d8d9, 0xdae1e2e3, 0xe4e5e6e7, 0xe8e9eaf1 | |
| 153 | +, 0xf2f3f4f5, 0xf6f7f8f9, 0xfaffc400, 0x1f010003 | |
| 154 | +, 0x01010101, 0x01010101, 0x01000000, 0x00000001 | |
| 155 | +, 0x02030405, 0x06070809, 0x0a0bffc4, 0x00b51100 | |
| 156 | +, 0x02010204, 0x04030407, 0x05040400, 0x01027700 | |
| 157 | +, 0x01020311, 0x04052131, 0x06124151, 0x07617113 | |
| 158 | +, 0x22328108, 0x144291a1, 0xb1c10923, 0x3352f015 | |
| 159 | +, 0x6272d10a, 0x162434e1, 0x25f11718, 0x191a2627 | |
| 160 | +, 0x28292a35, 0x36373839, 0x3a434445, 0x46474849 | |
| 161 | +, 0x4a535455, 0x56575859, 0x5a636465, 0x66676869 | |
| 162 | +, 0x6a737475, 0x76777879, 0x7a828384, 0x85868788 | |
| 163 | +, 0x898a9293, 0x94959697, 0x98999aa2, 0xa3a4a5a6 | |
| 164 | +, 0xa7a8a9aa, 0xb2b3b4b5, 0xb6b7b8b9, 0xbac2c3c4 | |
| 165 | +, 0xc5c6c7c8, 0xc9cad2d3, 0xd4d5d6d7, 0xd8d9dae2 | |
| 166 | +, 0xe3e4e5e6, 0xe7e8e9ea, 0xf2f3f4f5, 0xf6f7f8f9 | |
| 167 | +, 0xfaffda00, 0x0c030100, 0x02110311, 0x003f00f8 | |
| 168 | +, 0xe7e37fc6, 0xff00197f, 0xc142fc65, 0x17ed5bfb | |
| 169 | +, 0x56db699e, 0x27f14f89, 0xf4cb7b85, 0x5bcd3924 | |
| 170 | +, 0xb5d1ed5d, 0x3cc8b4db, 0x08a4ddf6, 0x6b387cc6 | |
| 171 | +, 0x09182599, 0x99e595e5, 0x9e69a693, 0xbaf0dffc | |
| 172 | +, 0x1c9dff00, 0x050aff00, 0x82637837, 0x44fd94be | |
| 173 | +, 0x11e89f0f, 0xfc61e16d, 0x334c5b8f, 0x0f37c45d | |
| 174 | +, 0x26fef2eb, 0x46b56778, 0xd34db796, 0xd6fadbfd | |
| 175 | +, 0x0e2f2898, 0xa3903b42, 0xb21891d6, 0x08e08623 | |
| 176 | +, 0xfe0e4ef0, 0xdf837fe0, 0x98dff050, 0xbb2f847f | |
| 177 | +, 0xb2978274, 0xcd33c2de, 0x30f87f69, 0xe2e6f0f5 | |
| 178 | +, 0xe44ef6ba, 0x35d5c5fe, 0xa16b2dad, 0x8246d1f9 | |
| 179 | +, 0x167fe84b, 0x2a40772c, 0x2d33c717, 0x9702c304 | |
| 180 | +, 0x5fb0dff0, 0x4abff825, 0x5ffc13d7, 0xc55ff04f | |
| 181 | +, 0x5f845f17, 0x3e2e7ec8, 0xbf0ffe21, 0xf8a7e21f | |
| 182 | +, 0xc3fd1fc5, 0xde21f10f, 0xc45f0758, 0x6b774b75 | |
| 183 | +, 0xa9584174, 0xf6b6ef75, 0x0b7d9ace, 0x1f304514 | |
| 184 | +, 0x11ed50a8, 0x647f3279, 0x679e5fcf, 0x720cbb37 | |
| 185 | +, 0xc3f1257a, 0x95eb7343, 0xdebabc9d, 0xeef4d1ab | |
| 186 | +, 0x2b7e1b2d, 0x0fec0f16, 0xb8c7c3cc, 0xdbc15caf | |
| 187 | +, 0x0795e59e, 0xc710fd97, 0x2cfd9d38, 0xf2f241aa | |
| 188 | +, 0x9efc64e5, 0x2e67dd7b, 0xdf14acd1, 0xffd90000 | |
| 189 | + | |
| 190 | +}; | |
| 191 | + | |
| 192 | + static private byte[] wordsToBytes(int[] wordArray) { | |
| 193 | + byte[] bytes = new byte[wordArray.length * 4]; | |
| 194 | + int inx = bytes.length; | |
| 195 | + for (int i = wordArray.length-1; i >= 0; --i) { | |
| 196 | + int word = wordArray[i]; | |
| 197 | + for (int j = 0; j < 4; ++j) { | |
| 198 | + bytes[--inx] = (byte)(word & 0xff); | |
| 199 | + word = word >>> 8; | |
| 200 | + } | |
| 201 | + } | |
| 202 | + return bytes; | |
| 203 | + } | |
| 204 | + | |
| 205 | + static Icon stopSignIcon = new ImageIcon(wordsToBytes(stopSignWords)); | |
| 206 | + static Icon blankIcon = new ImageIcon(wordsToBytes(blank)); | |
| 207 | + | |
| 208 | + static Icon execIcon = new ImageIcon(wordsToBytes(exec)); | |
| 209 | +} | |
| @@ -0,0 +1,269 @@ | ||
| 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.File; | |
| 29 | +import java.util.Hashtable; | |
| 30 | +import java.util.Enumeration; | |
| 31 | +import javax.swing.filechooser.*; | |
| 32 | + | |
| 33 | +//### Renamed from 'ExampleFileFilter.java' provided with Swing demos. | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * A convenience implementation of FileFilter that filters out | |
| 37 | + * all files except for those type extensions that it knows about. | |
| 38 | + * | |
| 39 | + * Extensions are of the type ".foo", which is typically found on | |
| 40 | + * Windows and Unix boxes, but not on Macinthosh. Case is ignored. | |
| 41 | + * | |
| 42 | + * Example - create a new filter that filerts out all files | |
| 43 | + * but gif and jpg image files: | |
| 44 | + * | |
| 45 | + * JFileChooser chooser = new JFileChooser(); | |
| 46 | + * ExampleFileFilter filter = new ExampleFileFilter( | |
| 47 | + * new String{"gif", "jpg"}, "JPEG & GIF Images") | |
| 48 | + * chooser.addChoosableFileFilter(filter); | |
| 49 | + * chooser.showOpenDialog(this); | |
| 50 | + * | |
| 51 | + * @author Jeff Dinkins | |
| 52 | + */ | |
| 53 | + | |
| 54 | +public class JDBFileFilter extends FileFilter { | |
| 55 | + | |
| 56 | + private static String TYPE_UNKNOWN = "Type Unknown"; | |
| 57 | + private static String HIDDEN_FILE = "Hidden File"; | |
| 58 | + | |
| 59 | + private Hashtable<String, JDBFileFilter> filters = null; | |
| 60 | + private String description = null; | |
| 61 | + private String fullDescription = null; | |
| 62 | + private boolean useExtensionsInDescription = true; | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * Creates a file filter. If no filters are added, then all | |
| 66 | + * files are accepted. | |
| 67 | + * | |
| 68 | + * @see #addExtension | |
| 69 | + */ | |
| 70 | + public JDBFileFilter() { | |
| 71 | + this.filters = new Hashtable<String, JDBFileFilter>(); | |
| 72 | + } | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * Creates a file filter that accepts files with the given extension. | |
| 76 | + * Example: new JDBFileFilter("jpg"); | |
| 77 | + * | |
| 78 | + * @see #addExtension | |
| 79 | + */ | |
| 80 | + public JDBFileFilter(String extension) { | |
| 81 | + this(extension,null); | |
| 82 | + } | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * Creates a file filter that accepts the given file type. | |
| 86 | + * Example: new JDBFileFilter("jpg", "JPEG Image Images"); | |
| 87 | + * | |
| 88 | + * Note that the "." before the extension is not needed. If | |
| 89 | + * provided, it will be ignored. | |
| 90 | + * | |
| 91 | + * @see #addExtension | |
| 92 | + */ | |
| 93 | + public JDBFileFilter(String extension, String description) { | |
| 94 | + this(); | |
| 95 | + if(extension!=null) { | |
| 96 | + addExtension(extension); | |
| 97 | + } | |
| 98 | + if(description!=null) { | |
| 99 | + setDescription(description); | |
| 100 | + } | |
| 101 | + } | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Creates a file filter from the given string array. | |
| 105 | + * Example: new JDBFileFilter(String {"gif", "jpg"}); | |
| 106 | + * | |
| 107 | + * Note that the "." before the extension is not needed adn | |
| 108 | + * will be ignored. | |
| 109 | + * | |
| 110 | + * @see #addExtension | |
| 111 | + */ | |
| 112 | + public JDBFileFilter(String[] filters) { | |
| 113 | + this(filters, null); | |
| 114 | + } | |
| 115 | + | |
| 116 | + /** | |
| 117 | + * Creates a file filter from the given string array and description. | |
| 118 | + * Example: new JDBFileFilter(String {"gif", "jpg"}, "Gif and JPG Images"); | |
| 119 | + * | |
| 120 | + * Note that the "." before the extension is not needed and will be ignored. | |
| 121 | + * | |
| 122 | + * @see #addExtension | |
| 123 | + */ | |
| 124 | + public JDBFileFilter(String[] filters, String description) { | |
| 125 | + this(); | |
| 126 | + for (String filter : filters) { | |
| 127 | + // add filters one by one | |
| 128 | + addExtension(filter); | |
| 129 | + } | |
| 130 | + if(description!=null) { | |
| 131 | + setDescription(description); | |
| 132 | + } | |
| 133 | + } | |
| 134 | + | |
| 135 | + /** | |
| 136 | + * Return true if this file should be shown in the directory pane, | |
| 137 | + * false if it shouldn't. | |
| 138 | + * | |
| 139 | + * Files that begin with "." are ignored. | |
| 140 | + * | |
| 141 | + * @see #getExtension | |
| 142 | + * @see FileFilter#accepts | |
| 143 | + */ | |
| 144 | + @Override | |
| 145 | + public boolean accept(File f) { | |
| 146 | + if(f != null) { | |
| 147 | + if(f.isDirectory()) { | |
| 148 | + return true; | |
| 149 | + } | |
| 150 | + String extension = getExtension(f); | |
| 151 | + if(extension != null && filters.get(getExtension(f)) != null) { | |
| 152 | + return true; | |
| 153 | + }; | |
| 154 | + } | |
| 155 | + return false; | |
| 156 | + } | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * Return the extension portion of the file's name . | |
| 160 | + * | |
| 161 | + * @see #getExtension | |
| 162 | + * @see FileFilter#accept | |
| 163 | + */ | |
| 164 | + public String getExtension(File f) { | |
| 165 | + if(f != null) { | |
| 166 | + String filename = f.getName(); | |
| 167 | + int i = filename.lastIndexOf('.'); | |
| 168 | + if(i>0 && i<filename.length()-1) { | |
| 169 | + return filename.substring(i+1).toLowerCase(); | |
| 170 | + }; | |
| 171 | + } | |
| 172 | + return null; | |
| 173 | + } | |
| 174 | + | |
| 175 | + /** | |
| 176 | + * Adds a filetype "dot" extension to filter against. | |
| 177 | + * | |
| 178 | + * For example: the following code will create a filter that filters | |
| 179 | + * out all files except those that end in ".jpg" and ".tif": | |
| 180 | + * | |
| 181 | + * JDBFileFilter filter = new JDBFileFilter(); | |
| 182 | + * filter.addExtension("jpg"); | |
| 183 | + * filter.addExtension("tif"); | |
| 184 | + * | |
| 185 | + * Note that the "." before the extension is not needed and will be ignored. | |
| 186 | + */ | |
| 187 | + public void addExtension(String extension) { | |
| 188 | + if(filters == null) { | |
| 189 | + filters = new Hashtable<String, JDBFileFilter>(5); | |
| 190 | + } | |
| 191 | + filters.put(extension.toLowerCase(), this); | |
| 192 | + fullDescription = null; | |
| 193 | + } | |
| 194 | + | |
| 195 | + | |
| 196 | + /** | |
| 197 | + * Returns the human readable description of this filter. For | |
| 198 | + * example: "JPEG and GIF Image Files (*.jpg, *.gif)" | |
| 199 | + * | |
| 200 | + * @see setDescription | |
| 201 | + * @see setExtensionListInDescription | |
| 202 | + * @see isExtensionListInDescription | |
| 203 | + * @see FileFilter#getDescription | |
| 204 | + */ | |
| 205 | + @Override | |
| 206 | + public String getDescription() { | |
| 207 | + if(fullDescription == null) { | |
| 208 | + if(description == null || isExtensionListInDescription()) { | |
| 209 | + fullDescription = description==null ? "(" : description + " ("; | |
| 210 | + // build the description from the extension list | |
| 211 | + Enumeration<String> extensions = filters.keys(); | |
| 212 | + if(extensions != null) { | |
| 213 | + fullDescription += "." + extensions.nextElement(); | |
| 214 | + while (extensions.hasMoreElements()) { | |
| 215 | + fullDescription += ", " + extensions.nextElement(); | |
| 216 | + } | |
| 217 | + } | |
| 218 | + fullDescription += ")"; | |
| 219 | + } else { | |
| 220 | + fullDescription = description; | |
| 221 | + } | |
| 222 | + } | |
| 223 | + return fullDescription; | |
| 224 | + } | |
| 225 | + | |
| 226 | + /** | |
| 227 | + * Sets the human readable description of this filter. For | |
| 228 | + * example: filter.setDescription("Gif and JPG Images"); | |
| 229 | + * | |
| 230 | + * @see setDescription | |
| 231 | + * @see setExtensionListInDescription | |
| 232 | + * @see isExtensionListInDescription | |
| 233 | + */ | |
| 234 | + public void setDescription(String description) { | |
| 235 | + this.description = description; | |
| 236 | + fullDescription = null; | |
| 237 | + } | |
| 238 | + | |
| 239 | + /** | |
| 240 | + * Determines whether the extension list (.jpg, .gif, etc) should | |
| 241 | + * show up in the human readable description. | |
| 242 | + * | |
| 243 | + * Only relevent if a description was provided in the constructor | |
| 244 | + * or using setDescription(); | |
| 245 | + * | |
| 246 | + * @see getDescription | |
| 247 | + * @see setDescription | |
| 248 | + * @see isExtensionListInDescription | |
| 249 | + */ | |
| 250 | + public void setExtensionListInDescription(boolean b) { | |
| 251 | + useExtensionsInDescription = b; | |
| 252 | + fullDescription = null; | |
| 253 | + } | |
| 254 | + | |
| 255 | + /** | |
| 256 | + * Returns whether the extension list (.jpg, .gif, etc) should | |
| 257 | + * show up in the human readable description. | |
| 258 | + * | |
| 259 | + * Only relevent if a description was provided in the constructor | |
| 260 | + * or using setDescription(); | |
| 261 | + * | |
| 262 | + * @see getDescription | |
| 263 | + * @see setDescription | |
| 264 | + * @see setExtensionListInDescription | |
| 265 | + */ | |
| 266 | + public boolean isExtensionListInDescription() { | |
| 267 | + return useExtensionsInDescription; | |
| 268 | + } | |
| 269 | +} | |
| @@ -0,0 +1,190 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import javax.swing.*; | |
| 29 | +import java.awt.*; | |
| 30 | +import java.awt.event.*; | |
| 31 | +import java.util.Vector; | |
| 32 | +import java.util.List; | |
| 33 | + | |
| 34 | +import com.sun.tools.example.debug.bdi.*; | |
| 35 | + | |
| 36 | +//### This is currently just a placeholder! | |
| 37 | + | |
| 38 | +class JDBMenuBar extends JMenuBar { | |
| 39 | + | |
| 40 | + Environment env; | |
| 41 | + | |
| 42 | + ExecutionManager runtime; | |
| 43 | + ClassManager classManager; | |
| 44 | + SourceManager sourceManager; | |
| 45 | + | |
| 46 | + CommandInterpreter interpreter; | |
| 47 | + | |
| 48 | + JDBMenuBar(Environment env) { | |
| 49 | + this.env = env; | |
| 50 | + this.runtime = env.getExecutionManager(); | |
| 51 | + this.classManager = env.getClassManager(); | |
| 52 | + this.sourceManager = env.getSourceManager(); | |
| 53 | + this.interpreter = new CommandInterpreter(env, true); | |
| 54 | + | |
| 55 | + JMenu fileMenu = new JMenu("File"); | |
| 56 | + | |
| 57 | + JMenuItem openItem = new JMenuItem("Open...", 'O'); | |
| 58 | + openItem.addActionListener(new ActionListener() { | |
| 59 | + @Override | |
| 60 | + public void actionPerformed(ActionEvent e) { | |
| 61 | + openCommand(); | |
| 62 | + } | |
| 63 | + }); | |
| 64 | + fileMenu.add(openItem); | |
| 65 | + addTool(fileMenu, "Exit debugger", "Exit", "exit"); | |
| 66 | + | |
| 67 | + JMenu cmdMenu = new JMenu("Commands"); | |
| 68 | + | |
| 69 | + addTool(cmdMenu, "Step into next line", "Step", "step"); | |
| 70 | + addTool(cmdMenu, "Step over next line", "Next", "next"); | |
| 71 | + cmdMenu.addSeparator(); | |
| 72 | + | |
| 73 | + addTool(cmdMenu, "Step into next instruction", | |
| 74 | + "Step Instruction", "stepi"); | |
| 75 | + addTool(cmdMenu, "Step over next instruction", | |
| 76 | + "Next Instruction", "nexti"); | |
| 77 | + cmdMenu.addSeparator(); | |
| 78 | + | |
| 79 | + addTool(cmdMenu, "Step out of current method call", | |
| 80 | + "Step Up", "step up"); | |
| 81 | + cmdMenu.addSeparator(); | |
| 82 | + | |
| 83 | + addTool(cmdMenu, "Suspend execution", "Interrupt", "interrupt"); | |
| 84 | + addTool(cmdMenu, "Continue execution", "Continue", "cont"); | |
| 85 | + cmdMenu.addSeparator(); | |
| 86 | + | |
| 87 | + addTool(cmdMenu, "Display current stack", "Where", "where"); | |
| 88 | + cmdMenu.addSeparator(); | |
| 89 | + | |
| 90 | + addTool(cmdMenu, "Move up one stack frame", "Up", "up"); | |
| 91 | + addTool(cmdMenu, "Move down one stack frame", "Down", "down"); | |
| 92 | + cmdMenu.addSeparator(); | |
| 93 | + | |
| 94 | + JMenuItem monitorItem = new JMenuItem("Monitor Expression...", 'M'); | |
| 95 | + monitorItem.addActionListener(new ActionListener() { | |
| 96 | + @Override | |
| 97 | + public void actionPerformed(ActionEvent e) { | |
| 98 | + monitorCommand(); | |
| 99 | + } | |
| 100 | + }); | |
| 101 | + cmdMenu.add(monitorItem); | |
| 102 | + | |
| 103 | + JMenuItem unmonitorItem = new JMenuItem("Unmonitor Expression..."); | |
| 104 | + unmonitorItem.addActionListener(new ActionListener() { | |
| 105 | + @Override | |
| 106 | + public void actionPerformed(ActionEvent e) { | |
| 107 | + unmonitorCommand(); | |
| 108 | + } | |
| 109 | + }); | |
| 110 | + cmdMenu.add(unmonitorItem); | |
| 111 | + | |
| 112 | + JMenu breakpointMenu = new JMenu("Breakpoint"); | |
| 113 | + JMenuItem stopItem = new JMenuItem("Stop in...", 'S'); | |
| 114 | + stopItem.addActionListener(new ActionListener() { | |
| 115 | + @Override | |
| 116 | + public void actionPerformed(ActionEvent e) { | |
| 117 | + buildBreakpoint(); | |
| 118 | + } | |
| 119 | + }); | |
| 120 | + breakpointMenu.add(stopItem); | |
| 121 | + | |
| 122 | + JMenu helpMenu = new JMenu("Help"); | |
| 123 | + addTool(helpMenu, "Display command list", "Help", "help"); | |
| 124 | + | |
| 125 | + this.add(fileMenu); | |
| 126 | + this.add(cmdMenu); | |
| 127 | +// this.add(breakpointMenu); | |
| 128 | + this.add(helpMenu); | |
| 129 | + } | |
| 130 | + | |
| 131 | + private void buildBreakpoint() { | |
| 132 | + Frame frame = JOptionPane.getRootFrame(); | |
| 133 | + JDialog dialog = new JDialog(frame, "Specify Breakpoint"); | |
| 134 | + Container contents = dialog.getContentPane(); | |
| 135 | + Vector<String> classes = new Vector<String>(); | |
| 136 | + classes.add("Foo"); | |
| 137 | + classes.add("Bar"); | |
| 138 | + JList list = new JList(classes); | |
| 139 | + JScrollPane scrollPane = new JScrollPane(list); | |
| 140 | + contents.add(scrollPane); | |
| 141 | + dialog.show(); | |
| 142 | + | |
| 143 | + } | |
| 144 | + | |
| 145 | + private void monitorCommand() { | |
| 146 | + String expr = (String)JOptionPane.showInputDialog(null, | |
| 147 | + "Expression to monitor:", "Add Monitor", | |
| 148 | + JOptionPane.QUESTION_MESSAGE, null, null, null); | |
| 149 | + if (expr != null) { | |
| 150 | + interpreter.executeCommand("monitor " + expr); | |
| 151 | + } | |
| 152 | + } | |
| 153 | + | |
| 154 | + private void unmonitorCommand() { | |
| 155 | + List monitors = env.getMonitorListModel().monitors(); | |
| 156 | + String expr = (String)JOptionPane.showInputDialog(null, | |
| 157 | + "Expression to unmonitor:", "Remove Monitor", | |
| 158 | + JOptionPane.QUESTION_MESSAGE, null, | |
| 159 | + monitors.toArray(), | |
| 160 | + monitors.get(monitors.size()-1)); | |
| 161 | + if (expr != null) { | |
| 162 | + interpreter.executeCommand("unmonitor " + expr); | |
| 163 | + } | |
| 164 | + } | |
| 165 | + | |
| 166 | + private void openCommand() { | |
| 167 | + JFileChooser chooser = new JFileChooser(); | |
| 168 | + JDBFileFilter filter = new JDBFileFilter("java", "Java source code"); | |
| 169 | + chooser.setFileFilter(filter); | |
| 170 | + int result = chooser.showOpenDialog(this); | |
| 171 | + if (result == JFileChooser.APPROVE_OPTION) { | |
| 172 | + System.out.println("Chose file: " + chooser.getSelectedFile().getName()); | |
| 173 | + } | |
| 174 | + } | |
| 175 | + | |
| 176 | + private void addTool(JMenu menu, String toolTip, String labelText, | |
| 177 | + String command) { | |
| 178 | + JMenuItem mi = new JMenuItem(labelText); | |
| 179 | + mi.setToolTipText(toolTip); | |
| 180 | + final String cmd = command; | |
| 181 | + mi.addActionListener(new ActionListener() { | |
| 182 | + @Override | |
| 183 | + public void actionPerformed(ActionEvent e) { | |
| 184 | + interpreter.executeCommand(cmd); | |
| 185 | + } | |
| 186 | + }); | |
| 187 | + menu.add(mi); | |
| 188 | + } | |
| 189 | + | |
| 190 | +} | |
| @@ -0,0 +1,101 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import javax.swing.*; | |
| 29 | +import java.awt.event.*; | |
| 30 | + | |
| 31 | +import com.sun.tools.example.debug.bdi.*; | |
| 32 | + | |
| 33 | +class JDBToolBar extends JToolBar { | |
| 34 | + | |
| 35 | + Environment env; | |
| 36 | + | |
| 37 | + ExecutionManager runtime; | |
| 38 | + ClassManager classManager; | |
| 39 | + SourceManager sourceManager; | |
| 40 | + | |
| 41 | + CommandInterpreter interpreter; | |
| 42 | + | |
| 43 | + JDBToolBar(Environment env) { | |
| 44 | + | |
| 45 | + this.env = env; | |
| 46 | + this.runtime = env.getExecutionManager(); | |
| 47 | + this.classManager = env.getClassManager(); | |
| 48 | + this.sourceManager = env.getSourceManager(); | |
| 49 | + this.interpreter = new CommandInterpreter(env, true); | |
| 50 | + | |
| 51 | + //===== Configure toolbar here ===== | |
| 52 | + | |
| 53 | + addTool("Run application", "run", "run"); | |
| 54 | + addTool("Connect to application", "connect", "connect"); | |
| 55 | + addSeparator(); | |
| 56 | + | |
| 57 | + addTool("Step into next line", "step", "step"); | |
| 58 | + addTool("Step over next line", "next", "next"); | |
| 59 | +// addSeparator(); | |
| 60 | + | |
| 61 | +// addTool("Step into next instruction", "stepi", "stepi"); | |
| 62 | +// addTool("Step over next instruction", "nexti", "nexti"); | |
| 63 | +// addSeparator(); | |
| 64 | + | |
| 65 | + addTool("Step out of current method call", "step up", "step up"); | |
| 66 | + addSeparator(); | |
| 67 | + | |
| 68 | + addTool("Suspend execution", "interrupt", "interrupt"); | |
| 69 | + addTool("Continue execution", "cont", "cont"); | |
| 70 | + addSeparator(); | |
| 71 | + | |
| 72 | +// addTool("Display current stack", "where", "where"); | |
| 73 | +// addSeparator(); | |
| 74 | + | |
| 75 | + addTool("Move up one stack frame", "up", "up"); | |
| 76 | + addTool("Move down one stack frame", "down", "down"); | |
| 77 | +// addSeparator(); | |
| 78 | + | |
| 79 | +// addTool("Display command list", "help", "help"); | |
| 80 | +// addSeparator(); | |
| 81 | + | |
| 82 | +// addTool("Exit debugger", "exit", "exit"); | |
| 83 | + | |
| 84 | + //================================== | |
| 85 | + | |
| 86 | + } | |
| 87 | + | |
| 88 | + private void addTool(String toolTip, String labelText, String command) { | |
| 89 | + JButton button = new JButton(labelText); | |
| 90 | + button.setToolTipText(toolTip); | |
| 91 | + final String cmd = command; | |
| 92 | + button.addActionListener(new ActionListener() { | |
| 93 | + @Override | |
| 94 | + public void actionPerformed(ActionEvent e) { | |
| 95 | + interpreter.executeCommand(cmd); | |
| 96 | + } | |
| 97 | + }); | |
| 98 | + this.add(button); | |
| 99 | + } | |
| 100 | + | |
| 101 | +} | |
| @@ -0,0 +1,263 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.util.List; | |
| 29 | +import java.util.ArrayList; | |
| 30 | +import java.util.Map; | |
| 31 | +import java.util.HashMap; | |
| 32 | +import java.awt.BorderLayout; | |
| 33 | +import java.awt.Container; | |
| 34 | +import java.awt.event.ActionEvent; | |
| 35 | +import java.awt.event.ActionListener; | |
| 36 | +import javax.swing.*; | |
| 37 | +import javax.swing.border.Border; | |
| 38 | +import javax.swing.border.TitledBorder; | |
| 39 | + | |
| 40 | +import com.sun.jdi.*; | |
| 41 | +import com.sun.jdi.connect.*; | |
| 42 | + | |
| 43 | +import com.sun.tools.example.debug.bdi.*; | |
| 44 | + | |
| 45 | +class LaunchTool { | |
| 46 | + | |
| 47 | + private final ExecutionManager runtime; | |
| 48 | + | |
| 49 | + private abstract class ArgRep { | |
| 50 | + final Connector.Argument arg; | |
| 51 | + final JPanel panel; | |
| 52 | + | |
| 53 | + ArgRep(Connector.Argument arg) { | |
| 54 | + this.arg = arg; | |
| 55 | + panel = new JPanel(); | |
| 56 | + Border etched = BorderFactory.createEtchedBorder(); | |
| 57 | + Border titled = BorderFactory.createTitledBorder(etched, | |
| 58 | + arg.description(), | |
| 59 | + TitledBorder.LEFT, TitledBorder.TOP); | |
| 60 | + panel.setBorder(titled); | |
| 61 | + } | |
| 62 | + | |
| 63 | + abstract String getText(); | |
| 64 | + | |
| 65 | + boolean isValid() { | |
| 66 | + return arg.isValid(getText()); | |
| 67 | + } | |
| 68 | + | |
| 69 | + boolean isSpecified() { | |
| 70 | + String value = getText(); | |
| 71 | + return (value != null && value.length() > 0) || | |
| 72 | + !arg.mustSpecify(); | |
| 73 | + } | |
| 74 | + | |
| 75 | + void install() { | |
| 76 | + arg.setValue(getText()); | |
| 77 | + } | |
| 78 | + } | |
| 79 | + | |
| 80 | + private class StringArgRep extends ArgRep { | |
| 81 | + final JTextField textField; | |
| 82 | + | |
| 83 | + StringArgRep(Connector.Argument arg, JPanel comp) { | |
| 84 | + super(arg); | |
| 85 | + textField = new JTextField(arg.value(), 50 ); | |
| 86 | + textField.setBorder(BorderFactory.createLoweredBevelBorder()); | |
| 87 | + | |
| 88 | + panel.add(new JLabel(arg.label(), SwingConstants.RIGHT)); | |
| 89 | + panel.add(textField); // , BorderLayout.CENTER); | |
| 90 | + comp.add(panel); | |
| 91 | + } | |
| 92 | + | |
| 93 | + @Override | |
| 94 | + String getText() { | |
| 95 | + return textField.getText(); | |
| 96 | + } | |
| 97 | + } | |
| 98 | + | |
| 99 | + private class BooleanArgRep extends ArgRep { | |
| 100 | + final JCheckBox check; | |
| 101 | + | |
| 102 | + BooleanArgRep(Connector.BooleanArgument barg, JPanel comp) { | |
| 103 | + super(barg); | |
| 104 | + check = new JCheckBox(barg.label()); | |
| 105 | + check.setSelected(barg.booleanValue()); | |
| 106 | + panel.add(check); | |
| 107 | + comp.add(panel); | |
| 108 | + } | |
| 109 | + | |
| 110 | + @Override | |
| 111 | + String getText() { | |
| 112 | + return ((Connector.BooleanArgument)arg) | |
| 113 | + .stringValueOf(check.getModel().isSelected()); | |
| 114 | + } | |
| 115 | + } | |
| 116 | + | |
| 117 | + | |
| 118 | + private LaunchTool(ExecutionManager runtime) { | |
| 119 | + this.runtime = runtime; | |
| 120 | + } | |
| 121 | + | |
| 122 | + private Connector selectConnector() { | |
| 123 | + final JDialog dialog = new JDialog(); | |
| 124 | + Container content = dialog.getContentPane(); | |
| 125 | + final JPanel radioPanel = new JPanel(); | |
| 126 | + final ButtonGroup radioGroup = new ButtonGroup(); | |
| 127 | + VirtualMachineManager manager = Bootstrap.virtualMachineManager(); | |
| 128 | + List<Connector> all = manager.allConnectors(); | |
| 129 | + Map<ButtonModel, Connector> modelToConnector = new HashMap<ButtonModel, Connector>(all.size(), 0.5f); | |
| 130 | + | |
| 131 | + dialog.setModal(true); | |
| 132 | + dialog.setTitle("Select Connector Type"); | |
| 133 | + radioPanel.setLayout(new BoxLayout(radioPanel, BoxLayout.Y_AXIS)); | |
| 134 | + for (Connector connector : all) { | |
| 135 | + JRadioButton radio = new JRadioButton(connector.description()); | |
| 136 | + modelToConnector.put(radio.getModel(), connector); | |
| 137 | + radioPanel.add(radio); | |
| 138 | + radioGroup.add(radio); | |
| 139 | + } | |
| 140 | + content.add(radioPanel); | |
| 141 | + | |
| 142 | + final boolean[] oked = {false}; | |
| 143 | + JPanel buttonPanel = okCancel( dialog, new ActionListener() { | |
| 144 | + @Override | |
| 145 | + public void actionPerformed(ActionEvent event) { | |
| 146 | + if (radioGroup.getSelection() == null) { | |
| 147 | + JOptionPane.showMessageDialog(dialog, | |
| 148 | + "Please select a connector type", | |
| 149 | + "No Selection", | |
| 150 | + JOptionPane.ERROR_MESSAGE); | |
| 151 | + } else { | |
| 152 | + oked[0] = true; | |
| 153 | + dialog.setVisible(false); | |
| 154 | + dialog.dispose(); | |
| 155 | + } | |
| 156 | + } | |
| 157 | + } ); | |
| 158 | + content.add(BorderLayout.SOUTH, buttonPanel); | |
| 159 | + dialog.pack(); | |
| 160 | + dialog.setVisible(true); | |
| 161 | + | |
| 162 | + return oked[0] ? | |
| 163 | + modelToConnector.get(radioGroup.getSelection()) : | |
| 164 | + null; | |
| 165 | + } | |
| 166 | + | |
| 167 | + private void configureAndConnect(final Connector connector) { | |
| 168 | + final JDialog dialog = new JDialog(); | |
| 169 | + final Map<String, Connector.Argument> args = connector.defaultArguments(); | |
| 170 | + | |
| 171 | + dialog.setModal(true); | |
| 172 | + dialog.setTitle("Connector Arguments"); | |
| 173 | + Container content = dialog.getContentPane(); | |
| 174 | + JPanel guts = new JPanel(); | |
| 175 | + Border etched = BorderFactory.createEtchedBorder(); | |
| 176 | + BorderFactory.createTitledBorder(etched, | |
| 177 | + connector.description(), | |
| 178 | + TitledBorder.LEFT, TitledBorder.TOP); | |
| 179 | + guts.setBorder(etched); | |
| 180 | + guts.setLayout(new BoxLayout(guts, BoxLayout.Y_AXIS)); | |
| 181 | + | |
| 182 | + // guts.add(new JLabel(connector.description())); | |
| 183 | + | |
| 184 | + final List<ArgRep> argReps = new ArrayList<ArgRep>(args.size()); | |
| 185 | + for (Connector.Argument arg : args.values()) { | |
| 186 | + ArgRep ar; | |
| 187 | + if (arg instanceof Connector.BooleanArgument) { | |
| 188 | + ar = new BooleanArgRep((Connector.BooleanArgument)arg, guts); | |
| 189 | + } else { | |
| 190 | + ar = new StringArgRep(arg, guts); | |
| 191 | + } | |
| 192 | + argReps.add(ar); | |
| 193 | + } | |
| 194 | + content.add(guts); | |
| 195 | + | |
| 196 | + JPanel buttonPanel = okCancel( dialog, new ActionListener() { | |
| 197 | + @Override | |
| 198 | + public void actionPerformed(ActionEvent event) { | |
| 199 | + for (ArgRep ar : argReps) { | |
| 200 | + if (!ar.isSpecified()) { | |
| 201 | + JOptionPane.showMessageDialog(dialog, | |
| 202 | + ar.arg.label() + | |
| 203 | + ": Argument must be specified", | |
| 204 | + "No argument", JOptionPane.ERROR_MESSAGE); | |
| 205 | + return; | |
| 206 | + } | |
| 207 | + if (!ar.isValid()) { | |
| 208 | + JOptionPane.showMessageDialog(dialog, | |
| 209 | + ar.arg.label() + | |
| 210 | + ": Bad argument value: " + | |
| 211 | + ar.getText(), | |
| 212 | + "Bad argument", JOptionPane.ERROR_MESSAGE); | |
| 213 | + return; | |
| 214 | + } | |
| 215 | + ar.install(); | |
| 216 | + } | |
| 217 | + try { | |
| 218 | + if (runtime.explictStart(connector, args)) { | |
| 219 | + dialog.setVisible(false); | |
| 220 | + dialog.dispose(); | |
| 221 | + } else { | |
| 222 | + JOptionPane.showMessageDialog(dialog, | |
| 223 | + "Bad arguments values: See diagnostics window.", | |
| 224 | + "Bad arguments", JOptionPane.ERROR_MESSAGE); | |
| 225 | + } | |
| 226 | + } catch (VMLaunchFailureException exc) { | |
| 227 | + JOptionPane.showMessageDialog(dialog, | |
| 228 | + "Launch Failure: " + exc, | |
| 229 | + "Launch Failed",JOptionPane.ERROR_MESSAGE); | |
| 230 | + } | |
| 231 | + } | |
| 232 | + } ); | |
| 233 | + content.add(BorderLayout.SOUTH, buttonPanel); | |
| 234 | + dialog.pack(); | |
| 235 | + dialog.setVisible(true); | |
| 236 | + } | |
| 237 | + | |
| 238 | + private JPanel okCancel(final JDialog dialog, ActionListener okListener) { | |
| 239 | + JPanel buttonPanel = new JPanel(); | |
| 240 | + JButton ok = new JButton("OK"); | |
| 241 | + JButton cancel = new JButton("Cancel"); | |
| 242 | + buttonPanel.add(ok); | |
| 243 | + buttonPanel.add(cancel); | |
| 244 | + ok.addActionListener(okListener); | |
| 245 | + cancel.addActionListener( new ActionListener() { | |
| 246 | + @Override | |
| 247 | + public void actionPerformed(ActionEvent event) { | |
| 248 | + dialog.setVisible(false); | |
| 249 | + dialog.dispose(); | |
| 250 | + } | |
| 251 | + } ); | |
| 252 | + return buttonPanel; | |
| 253 | + } | |
| 254 | + | |
| 255 | + static void queryAndLaunchVM(ExecutionManager runtime) | |
| 256 | + throws VMLaunchFailureException { | |
| 257 | + LaunchTool lt = new LaunchTool(runtime); | |
| 258 | + Connector connector = lt.selectConnector(); | |
| 259 | + if (connector != null) { | |
| 260 | + lt.configureAndConnect(connector); | |
| 261 | + } | |
| 262 | + } | |
| 263 | +} | |
| @@ -0,0 +1,90 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.util.*; | |
| 29 | + | |
| 30 | +import javax.swing.AbstractListModel; | |
| 31 | + | |
| 32 | +public class MonitorListModel extends AbstractListModel { | |
| 33 | + | |
| 34 | + private final List<String> monitors = new ArrayList<String>(); | |
| 35 | + | |
| 36 | + MonitorListModel(Environment env) { | |
| 37 | + | |
| 38 | + // Create listener. | |
| 39 | + MonitorListListener listener = new MonitorListListener(); | |
| 40 | + env.getContextManager().addContextListener(listener); | |
| 41 | + | |
| 42 | + //### remove listeners on exit! | |
| 43 | + } | |
| 44 | + | |
| 45 | + @Override | |
| 46 | + public Object getElementAt(int index) { | |
| 47 | + return monitors.get(index); | |
| 48 | + } | |
| 49 | + | |
| 50 | + @Override | |
| 51 | + public int getSize() { | |
| 52 | + return monitors.size(); | |
| 53 | + } | |
| 54 | + | |
| 55 | + public void add(String expr) { | |
| 56 | + monitors.add(expr); | |
| 57 | + int newIndex = monitors.size()-1; // order important | |
| 58 | + fireIntervalAdded(this, newIndex, newIndex); | |
| 59 | + } | |
| 60 | + | |
| 61 | + public void remove(String expr) { | |
| 62 | + int index = monitors.indexOf(expr); | |
| 63 | + remove(index); | |
| 64 | + } | |
| 65 | + | |
| 66 | + public void remove(int index) { | |
| 67 | + monitors.remove(index); | |
| 68 | + fireIntervalRemoved(this, index, index); | |
| 69 | + } | |
| 70 | + | |
| 71 | + public List<String> monitors() { | |
| 72 | + return Collections.unmodifiableList(monitors); | |
| 73 | + } | |
| 74 | + | |
| 75 | + public Iterator<?> iterator() { | |
| 76 | + return monitors().iterator(); | |
| 77 | + } | |
| 78 | + | |
| 79 | + private void invalidate() { | |
| 80 | + fireContentsChanged(this, 0, monitors.size()-1); | |
| 81 | + } | |
| 82 | + | |
| 83 | + private class MonitorListListener implements ContextListener { | |
| 84 | + | |
| 85 | + @Override | |
| 86 | + public void currentFrameChanged(final CurrentFrameChangedEvent e) { | |
| 87 | + invalidate(); | |
| 88 | + } | |
| 89 | + } | |
| 90 | +} | |
| @@ -0,0 +1,125 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import javax.swing.*; | |
| 29 | +import javax.swing.event.*; | |
| 30 | +import java.awt.*; | |
| 31 | +import com.sun.jdi.*; | |
| 32 | +import com.sun.tools.example.debug.bdi.*; | |
| 33 | +import com.sun.tools.example.debug.expr.ExpressionParser; | |
| 34 | +import com.sun.tools.example.debug.expr.ParseException; | |
| 35 | + | |
| 36 | +public class MonitorTool extends JPanel { | |
| 37 | + | |
| 38 | + private static final long serialVersionUID = -645235951031726647L; | |
| 39 | + private ExecutionManager runtime; | |
| 40 | + private ContextManager context; | |
| 41 | + | |
| 42 | + private JList list; | |
| 43 | + | |
| 44 | + public MonitorTool(Environment env) { | |
| 45 | + super(new BorderLayout()); | |
| 46 | + this.runtime = env.getExecutionManager(); | |
| 47 | + this.context = env.getContextManager(); | |
| 48 | + | |
| 49 | + list = new JList(env.getMonitorListModel()); | |
| 50 | + list.setCellRenderer(new MonitorRenderer()); | |
| 51 | + | |
| 52 | + JScrollPane listView = new JScrollPane(list); | |
| 53 | + add(listView); | |
| 54 | + | |
| 55 | + // Create listener. | |
| 56 | + MonitorToolListener listener = new MonitorToolListener(); | |
| 57 | + list.addListSelectionListener(listener); | |
| 58 | + //### remove listeners on exit! | |
| 59 | + } | |
| 60 | + | |
| 61 | + private class MonitorToolListener implements ListSelectionListener { | |
| 62 | + @Override | |
| 63 | + public void valueChanged(ListSelectionEvent e) { | |
| 64 | + int index = list.getSelectedIndex(); | |
| 65 | + if (index != -1) { | |
| 66 | + } | |
| 67 | + } | |
| 68 | + } | |
| 69 | + | |
| 70 | + private Value evaluate(String expr) throws ParseException, | |
| 71 | + InvocationException, | |
| 72 | + InvalidTypeException, | |
| 73 | + ClassNotLoadedException, | |
| 74 | + IncompatibleThreadStateException { | |
| 75 | + ExpressionParser.GetFrame frameGetter = | |
| 76 | + new ExpressionParser.GetFrame() { | |
| 77 | + @Override | |
| 78 | + public StackFrame get() | |
| 79 | + throws IncompatibleThreadStateException | |
| 80 | + { | |
| 81 | + try { | |
| 82 | + return context.getCurrentFrame(); | |
| 83 | + } catch (VMNotInterruptedException exc) { | |
| 84 | + throw new IncompatibleThreadStateException(); | |
| 85 | + } | |
| 86 | + } | |
| 87 | + }; | |
| 88 | + return ExpressionParser.evaluate(expr, runtime.vm(), frameGetter); | |
| 89 | + } | |
| 90 | + | |
| 91 | + private class MonitorRenderer extends DefaultListCellRenderer { | |
| 92 | + | |
| 93 | + @Override | |
| 94 | + public Component getListCellRendererComponent(JList list, | |
| 95 | + Object value, | |
| 96 | + int index, | |
| 97 | + boolean isSelected, | |
| 98 | + boolean cellHasFocus) { | |
| 99 | + | |
| 100 | + //### We should indicate the current thread independently of the | |
| 101 | + //### selection, e.g., with an icon, because the user may change | |
| 102 | + //### the selection graphically without affecting the current | |
| 103 | + //### thread. | |
| 104 | + | |
| 105 | + super.getListCellRendererComponent(list, value, index, | |
| 106 | + isSelected, cellHasFocus); | |
| 107 | + if (value == null) { | |
| 108 | + this.setText("<unavailable>"); | |
| 109 | + } else { | |
| 110 | + String expr = (String)value; | |
| 111 | + try { | |
| 112 | + Value result = evaluate(expr); | |
| 113 | + this.setText(expr + " = " + result); | |
| 114 | + } catch (ParseException exc) { | |
| 115 | + this.setText(expr + " ? " + exc.getMessage()); | |
| 116 | + } catch (IncompatibleThreadStateException exc) { | |
| 117 | + this.setText(expr + " ..."); | |
| 118 | + } catch (Exception exc) { | |
| 119 | + this.setText(expr + " ? " + exc); | |
| 120 | + } | |
| 121 | + } | |
| 122 | + return this; | |
| 123 | + } | |
| 124 | + } | |
| 125 | +} | |
| @@ -0,0 +1,46 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | + | |
| 30 | +// This class is used in 'CommandInterpreter' as a hook to | |
| 31 | +// allow messagebox style command output as an alternative | |
| 32 | +// to a typescript. It should be an interface, not a class. | |
| 33 | + | |
| 34 | +public class OutputSink extends PrintWriter { | |
| 35 | + | |
| 36 | + // Currently, we do no buffering, | |
| 37 | + // so 'show' is a no-op. | |
| 38 | + | |
| 39 | + OutputSink(Writer writer) { | |
| 40 | + super(writer); | |
| 41 | + } | |
| 42 | + | |
| 43 | + public void show() { | |
| 44 | + // ignore | |
| 45 | + } | |
| 46 | +} | |
| @@ -0,0 +1,95 @@ | ||
| 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | +import java.util.*; | |
| 30 | + | |
| 31 | +public class SearchPath { | |
| 32 | + | |
| 33 | + private String pathString; | |
| 34 | + | |
| 35 | + private String[] pathArray; | |
| 36 | + | |
| 37 | + public SearchPath(String searchPath) { | |
| 38 | + //### Should check searchpath for well-formedness. | |
| 39 | + StringTokenizer st = new StringTokenizer(searchPath, File.pathSeparator); | |
| 40 | + List<String> dlist = new ArrayList<String>(); | |
| 41 | + while (st.hasMoreTokens()) { | |
| 42 | + dlist.add(st.nextToken()); | |
| 43 | + } | |
| 44 | + pathString = searchPath; | |
| 45 | + pathArray = dlist.toArray(new String[dlist.size()]); | |
| 46 | + } | |
| 47 | + | |
| 48 | + public boolean isEmpty() { | |
| 49 | + return (pathArray.length == 0); | |
| 50 | + } | |
| 51 | + | |
| 52 | + public String asString() { | |
| 53 | + return pathString; | |
| 54 | + } | |
| 55 | + | |
| 56 | + public String[] asArray() { | |
| 57 | + return pathArray.clone(); | |
| 58 | + } | |
| 59 | + | |
| 60 | + public File resolve(String relativeFileName) { | |
| 61 | + for (String element : pathArray) { | |
| 62 | + File path = new File(element, relativeFileName); | |
| 63 | + if (path.exists()) { | |
| 64 | + return path; | |
| 65 | + } | |
| 66 | + } | |
| 67 | + return null; | |
| 68 | + } | |
| 69 | + | |
| 70 | + //### return List? | |
| 71 | + | |
| 72 | + public String[] children(String relativeDirName, FilenameFilter filter) { | |
| 73 | + // If a file appears at the same relative path | |
| 74 | + // with respect to multiple entries on the classpath, | |
| 75 | + // the one corresponding to the earliest entry on the | |
| 76 | + // classpath is retained. This is the one that will be | |
| 77 | + // found if we later do a 'resolve'. | |
| 78 | + SortedSet<String> s = new TreeSet<String>(); // sorted, no duplicates | |
| 79 | + for (String element : pathArray) { | |
| 80 | + File path = new File(element, relativeDirName); | |
| 81 | + if (path.exists()) { | |
| 82 | + String[] childArray = path.list(filter); | |
| 83 | + if (childArray != null) { | |
| 84 | + for (int j = 0; j < childArray.length; j++) { | |
| 85 | + if (!s.contains(childArray[j])) { | |
| 86 | + s.add(childArray[j]); | |
| 87 | + } | |
| 88 | + } | |
| 89 | + } | |
| 90 | + } | |
| 91 | + } | |
| 92 | + return s.toArray(new String[s.size()]); | |
| 93 | + } | |
| 94 | + | |
| 95 | +} | |
| @@ -0,0 +1,70 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import javax.swing.tree.*; | |
| 29 | + | |
| 30 | +public class SingleLeafTreeSelectionModel extends DefaultTreeSelectionModel { | |
| 31 | + | |
| 32 | + private static final long serialVersionUID = -7849105107888117679L; | |
| 33 | + | |
| 34 | + SingleLeafTreeSelectionModel() { | |
| 35 | + super(); | |
| 36 | + selectionMode = SINGLE_TREE_SELECTION; | |
| 37 | + } | |
| 38 | + | |
| 39 | + @Override | |
| 40 | + public void setSelectionPath(TreePath path) { | |
| 41 | + if(((TreeNode)(path.getLastPathComponent())).isLeaf()) { | |
| 42 | + super.setSelectionPath(path); | |
| 43 | + } | |
| 44 | + } | |
| 45 | + | |
| 46 | + @Override | |
| 47 | + public void setSelectionPaths(TreePath[] paths) { | |
| 48 | + // Only look at first path, as all others will be | |
| 49 | + // ignored anyway in single tree selection mode. | |
| 50 | + if(((TreeNode)(paths[0].getLastPathComponent())).isLeaf()) { | |
| 51 | + super.setSelectionPaths(paths); | |
| 52 | + } | |
| 53 | + } | |
| 54 | + | |
| 55 | + @Override | |
| 56 | + public void addSelectionPath(TreePath path) { | |
| 57 | + if(((TreeNode)(path.getLastPathComponent())).isLeaf()) { | |
| 58 | + super.setSelectionPath(path); | |
| 59 | + } | |
| 60 | + } | |
| 61 | + | |
| 62 | + @Override | |
| 63 | + public void addSelectionPaths(TreePath[] paths) { | |
| 64 | + // Only look at first path, as all others will be | |
| 65 | + // ignored anyway in single tree selection mode. | |
| 66 | + if(((TreeNode)(paths[0].getLastPathComponent())).isLeaf()) { | |
| 67 | + super.addSelectionPaths(paths); | |
| 68 | + } | |
| 69 | + } | |
| 70 | +} | |
| @@ -0,0 +1,30 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +public interface SourceListener { | |
| 29 | + void sourcepathChanged(SourcepathChangedEvent e); | |
| 30 | +} | |
| @@ -0,0 +1,180 @@ | ||
| 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | +import java.util.*; | |
| 30 | + | |
| 31 | +import com.sun.jdi.*; | |
| 32 | + | |
| 33 | +import com.sun.tools.example.debug.event.*; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * Manage the list of source files. | |
| 37 | + * Origin of SourceListener events. | |
| 38 | + */ | |
| 39 | +public class SourceManager { | |
| 40 | + | |
| 41 | + //### TODO: The source cache should be aged, and some cap | |
| 42 | + //### put on memory consumption by source files loaded into core. | |
| 43 | + | |
| 44 | + private List<SourceModel> sourceList; | |
| 45 | + private SearchPath sourcePath; | |
| 46 | + | |
| 47 | + private ArrayList<SourceListener> sourceListeners = new ArrayList<SourceListener>(); | |
| 48 | + | |
| 49 | + private Map<ReferenceType, SourceModel> classToSource = new HashMap<ReferenceType, SourceModel>(); | |
| 50 | + | |
| 51 | + private Environment env; | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * Hold on to it so it can be removed. | |
| 55 | + */ | |
| 56 | + private SMClassListener classListener = new SMClassListener(); | |
| 57 | + | |
| 58 | + public SourceManager(Environment env) { | |
| 59 | + this(env, new SearchPath("")); | |
| 60 | + } | |
| 61 | + | |
| 62 | + public SourceManager(Environment env, SearchPath sourcePath) { | |
| 63 | + this.env = env; | |
| 64 | + this.sourceList = new LinkedList<SourceModel>(); | |
| 65 | + this.sourcePath = sourcePath; | |
| 66 | + env.getExecutionManager().addJDIListener(classListener); | |
| 67 | + } | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * Set path for access to source code. | |
| 71 | + */ | |
| 72 | + public void setSourcePath(SearchPath sp) { | |
| 73 | + sourcePath = sp; | |
| 74 | + // Old cached sources are now invalid. | |
| 75 | + sourceList = new LinkedList<SourceModel>(); | |
| 76 | + notifySourcepathChanged(); | |
| 77 | + classToSource = new HashMap<ReferenceType, SourceModel>(); | |
| 78 | + } | |
| 79 | + | |
| 80 | + public void addSourceListener(SourceListener l) { | |
| 81 | + sourceListeners.add(l); | |
| 82 | + } | |
| 83 | + | |
| 84 | + public void removeSourceListener(SourceListener l) { | |
| 85 | + sourceListeners.remove(l); | |
| 86 | + } | |
| 87 | + | |
| 88 | + private void notifySourcepathChanged() { | |
| 89 | + ArrayList<SourceListener> l = new ArrayList<SourceListener>(sourceListeners); | |
| 90 | + SourcepathChangedEvent evt = new SourcepathChangedEvent(this); | |
| 91 | + for (int i = 0; i < l.size(); i++) { | |
| 92 | + l.get(i).sourcepathChanged(evt); | |
| 93 | + } | |
| 94 | + } | |
| 95 | + | |
| 96 | + /** | |
| 97 | + * Get path for access to source code. | |
| 98 | + */ | |
| 99 | + public SearchPath getSourcePath() { | |
| 100 | + return sourcePath; | |
| 101 | + } | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Get source object associated with a Location. | |
| 105 | + */ | |
| 106 | + public SourceModel sourceForLocation(Location loc) { | |
| 107 | + return sourceForClass(loc.declaringType()); | |
| 108 | + } | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * Get source object associated with a class or interface. | |
| 112 | + * Returns null if not available. | |
| 113 | + */ | |
| 114 | + public SourceModel sourceForClass(ReferenceType refType) { | |
| 115 | + SourceModel sm = classToSource.get(refType); | |
| 116 | + if (sm != null) { | |
| 117 | + return sm; | |
| 118 | + } | |
| 119 | + try { | |
| 120 | + String filename = refType.sourceName(); | |
| 121 | + String refName = refType.name(); | |
| 122 | + int iDot = refName.lastIndexOf('.'); | |
| 123 | + String pkgName = (iDot >= 0)? refName.substring(0, iDot+1) : ""; | |
| 124 | + String full = pkgName.replace('.', File.separatorChar) + filename; | |
| 125 | + File path = sourcePath.resolve(full); | |
| 126 | + if (path != null) { | |
| 127 | + sm = sourceForFile(path); | |
| 128 | + classToSource.put(refType, sm); | |
| 129 | + return sm; | |
| 130 | + } | |
| 131 | + return null; | |
| 132 | + } catch (AbsentInformationException e) { | |
| 133 | + return null; | |
| 134 | + } | |
| 135 | + } | |
| 136 | + | |
| 137 | + /** | |
| 138 | + * Get source object associated with an absolute file path. | |
| 139 | + */ | |
| 140 | + //### Use hash table for this? | |
| 141 | + public SourceModel sourceForFile(File path) { | |
| 142 | + Iterator<SourceModel> iter = sourceList.iterator(); | |
| 143 | + SourceModel sm = null; | |
| 144 | + while (iter.hasNext()) { | |
| 145 | + SourceModel candidate = iter.next(); | |
| 146 | + if (candidate.fileName().equals(path)) { | |
| 147 | + sm = candidate; | |
| 148 | + iter.remove(); // Will move to start of list. | |
| 149 | + break; | |
| 150 | + } | |
| 151 | + } | |
| 152 | + if (sm == null && path.exists()) { | |
| 153 | + sm = new SourceModel(env, path); | |
| 154 | + } | |
| 155 | + if (sm != null) { | |
| 156 | + // At start of list for faster access | |
| 157 | + sourceList.add(0, sm); | |
| 158 | + } | |
| 159 | + return sm; | |
| 160 | + } | |
| 161 | + | |
| 162 | + private class SMClassListener extends JDIAdapter | |
| 163 | + implements JDIListener { | |
| 164 | + | |
| 165 | + @Override | |
| 166 | + public void classPrepare(ClassPrepareEventSet e) { | |
| 167 | + ReferenceType refType = e.getReferenceType(); | |
| 168 | + SourceModel sm = sourceForClass(refType); | |
| 169 | + if (sm != null) { | |
| 170 | + sm.addClass(refType); | |
| 171 | + } | |
| 172 | + } | |
| 173 | + | |
| 174 | + @Override | |
| 175 | + public void classUnload(ClassUnloadEventSet e) { | |
| 176 | + //### iterate through looking for (e.getTypeName()). | |
| 177 | + //### then remove it. | |
| 178 | + } | |
| 179 | + } | |
| 180 | +} | |
| @@ -0,0 +1,247 @@ | ||
| 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | +import java.util.*; | |
| 30 | + | |
| 31 | +import com.sun.jdi.*; | |
| 32 | +import com.sun.jdi.request.*; | |
| 33 | + | |
| 34 | +import javax.swing.*; | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * Represents and manages one source file. | |
| 38 | + * Caches source lines. Holds other source file info. | |
| 39 | + */ | |
| 40 | +public class SourceModel extends AbstractListModel { | |
| 41 | + | |
| 42 | + private File path; | |
| 43 | + | |
| 44 | + boolean isActuallySource = true; | |
| 45 | + | |
| 46 | + private List<ReferenceType> classes = new ArrayList<ReferenceType>(); | |
| 47 | + | |
| 48 | + private Environment env; | |
| 49 | + | |
| 50 | + // Cached line-by-line access. | |
| 51 | + | |
| 52 | + //### Unify this with source model used in source view? | |
| 53 | + //### What is our cache-management policy for these? | |
| 54 | + //### Even with weak refs, we won't discard any part of the | |
| 55 | + //### source if the SourceModel object is reachable. | |
| 56 | + /** | |
| 57 | + * List of Line. | |
| 58 | + */ | |
| 59 | + private List<Line> sourceLines = null; | |
| 60 | + | |
| 61 | + public static class Line { | |
| 62 | + public String text; | |
| 63 | + public boolean hasBreakpoint = false; | |
| 64 | + public ReferenceType refType = null; | |
| 65 | + Line(String text) { | |
| 66 | + this.text = text; | |
| 67 | + } | |
| 68 | + public boolean isExecutable() { | |
| 69 | + return refType != null; | |
| 70 | + } | |
| 71 | + public boolean hasBreakpoint() { | |
| 72 | + return hasBreakpoint; | |
| 73 | + } | |
| 74 | + }; | |
| 75 | + | |
| 76 | + // 132 characters long, all printable characters. | |
| 77 | + public static final Line prototypeCellValue = new Line( | |
| 78 | + "abcdefghijklmnopqrstuvwxyz" + | |
| 79 | + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + | |
| 80 | + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + | |
| 81 | + "1234567890~!@#$%^&*()_+{}|" + | |
| 82 | + ":<>?`-=[];',.XXXXXXXXXXXX/\\\""); | |
| 83 | + | |
| 84 | + SourceModel(Environment env, File path) { | |
| 85 | + this.env = env; | |
| 86 | + this.path = path; | |
| 87 | + } | |
| 88 | + | |
| 89 | + public SourceModel(String message) { | |
| 90 | + this.path = null; | |
| 91 | + setMessage(message); | |
| 92 | + } | |
| 93 | + | |
| 94 | + private void setMessage(String message) { | |
| 95 | + isActuallySource = false; | |
| 96 | + sourceLines = new ArrayList<Line>(); | |
| 97 | + sourceLines.add(new Line(message)); | |
| 98 | + } | |
| 99 | + | |
| 100 | + // **** Implement ListModel ***** | |
| 101 | + | |
| 102 | + @Override | |
| 103 | + public Object getElementAt(int index) { | |
| 104 | + if (sourceLines == null) { | |
| 105 | + initialize(); | |
| 106 | + } | |
| 107 | + return sourceLines.get(index); | |
| 108 | + } | |
| 109 | + | |
| 110 | + @Override | |
| 111 | + public int getSize() { | |
| 112 | + if (sourceLines == null) { | |
| 113 | + initialize(); | |
| 114 | + } | |
| 115 | + return sourceLines.size(); | |
| 116 | + } | |
| 117 | + | |
| 118 | + // ***** Other functionality ***** | |
| 119 | + | |
| 120 | + public File fileName() { | |
| 121 | + return path; | |
| 122 | + } | |
| 123 | + | |
| 124 | + public BufferedReader sourceReader() throws IOException { | |
| 125 | + return new BufferedReader(new FileReader(path)); | |
| 126 | + } | |
| 127 | + | |
| 128 | + public Line line(int lineNo) { | |
| 129 | + if (sourceLines == null) { | |
| 130 | + initialize(); | |
| 131 | + } | |
| 132 | + int index = lineNo - 1; // list is 0-indexed | |
| 133 | + if (index >= sourceLines.size() || index < 0) { | |
| 134 | + return null; | |
| 135 | + } else { | |
| 136 | + return sourceLines.get(index); | |
| 137 | + } | |
| 138 | + } | |
| 139 | + | |
| 140 | + public String sourceLine(int lineNo) { | |
| 141 | + Line line = line(lineNo); | |
| 142 | + if (line == null) { | |
| 143 | + return null; | |
| 144 | + } else { | |
| 145 | + return line.text; | |
| 146 | + } | |
| 147 | + } | |
| 148 | + | |
| 149 | + void addClass(ReferenceType refType) { | |
| 150 | + // Logically is Set | |
| 151 | + if (classes.indexOf(refType) == -1) { | |
| 152 | + classes.add(refType); | |
| 153 | + if (sourceLines != null) { | |
| 154 | + markClassLines(refType); | |
| 155 | + } | |
| 156 | + } | |
| 157 | + } | |
| 158 | + | |
| 159 | + /** | |
| 160 | + * @return List of currently known {@link com.sun.jdi.ReferenceType} | |
| 161 | + * in this source file. | |
| 162 | + */ | |
| 163 | + public List<ReferenceType> referenceTypes() { | |
| 164 | + return Collections.unmodifiableList(classes); | |
| 165 | + } | |
| 166 | + | |
| 167 | + private void initialize() { | |
| 168 | + try { | |
| 169 | + rawInit(); | |
| 170 | + } catch (IOException exc) { | |
| 171 | + setMessage("[Error reading source code]"); | |
| 172 | + } | |
| 173 | + } | |
| 174 | + | |
| 175 | + public void showBreakpoint(int ln, boolean hasBreakpoint) { | |
| 176 | + line(ln).hasBreakpoint = hasBreakpoint; | |
| 177 | + fireContentsChanged(this, ln, ln); | |
| 178 | + } | |
| 179 | + | |
| 180 | + public void showExecutable(int ln, ReferenceType refType) { | |
| 181 | + line(ln).refType = refType; | |
| 182 | + fireContentsChanged(this, ln, ln); | |
| 183 | + } | |
| 184 | + | |
| 185 | + /** | |
| 186 | + * Mark executable lines and breakpoints, but only | |
| 187 | + * when sourceLines is set. | |
| 188 | + */ | |
| 189 | + private void markClassLines(ReferenceType refType) { | |
| 190 | + for (Method meth : refType.methods()) { | |
| 191 | + try { | |
| 192 | + for (Location loc : meth.allLineLocations()) { | |
| 193 | + showExecutable(loc.lineNumber(), refType); | |
| 194 | + } | |
| 195 | + } catch (AbsentInformationException exc) { | |
| 196 | + // do nothing | |
| 197 | + } | |
| 198 | + } | |
| 199 | + for (BreakpointRequest bp : | |
| 200 | + env.getExecutionManager().eventRequestManager().breakpointRequests()) { | |
| 201 | + if (bp.location() != null) { | |
| 202 | + Location loc = bp.location(); | |
| 203 | + if (loc.declaringType().equals(refType)) { | |
| 204 | + showBreakpoint(loc.lineNumber(),true); | |
| 205 | + } | |
| 206 | + } | |
| 207 | + } | |
| 208 | + } | |
| 209 | + | |
| 210 | + private void rawInit() throws IOException { | |
| 211 | + sourceLines = new ArrayList<Line>(); | |
| 212 | + BufferedReader reader = sourceReader(); | |
| 213 | + try { | |
| 214 | + String line = reader.readLine(); | |
| 215 | + while (line != null) { | |
| 216 | + sourceLines.add(new Line(expandTabs(line))); | |
| 217 | + line = reader.readLine(); | |
| 218 | + } | |
| 219 | + } finally { | |
| 220 | + reader.close(); | |
| 221 | + } | |
| 222 | + for (ReferenceType refType : classes) { | |
| 223 | + markClassLines(refType); | |
| 224 | + } | |
| 225 | + } | |
| 226 | + | |
| 227 | + private String expandTabs(String s) { | |
| 228 | + int col = 0; | |
| 229 | + int len = s.length(); | |
| 230 | + StringBuffer sb = new StringBuffer(132); | |
| 231 | + for (int i = 0; i < len; i++) { | |
| 232 | + char c = s.charAt(i); | |
| 233 | + sb.append(c); | |
| 234 | + if (c == '\t') { | |
| 235 | + int pad = (8 - (col % 8)); | |
| 236 | + for (int j = 0; j < pad; j++) { | |
| 237 | + sb.append(' '); | |
| 238 | + } | |
| 239 | + col += pad; | |
| 240 | + } else { | |
| 241 | + col++; | |
| 242 | + } | |
| 243 | + } | |
| 244 | + return sb.toString(); | |
| 245 | + } | |
| 246 | + | |
| 247 | +} | |
| @@ -0,0 +1,383 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | +import java.awt.*; | |
| 30 | +import java.awt.event.*; | |
| 31 | +import javax.swing.*; | |
| 32 | + | |
| 33 | +import com.sun.jdi.*; | |
| 34 | +import com.sun.jdi.request.*; | |
| 35 | + | |
| 36 | +import com.sun.tools.example.debug.bdi.*; | |
| 37 | + | |
| 38 | +public class SourceTool extends JPanel { | |
| 39 | + | |
| 40 | + private static final long serialVersionUID = -5461299294186395257L; | |
| 41 | + | |
| 42 | + private Environment env; | |
| 43 | + | |
| 44 | + private ExecutionManager runtime; | |
| 45 | + private ContextManager context; | |
| 46 | + private SourceManager sourceManager; | |
| 47 | + | |
| 48 | + private JList list; | |
| 49 | + private ListModel sourceModel; | |
| 50 | + | |
| 51 | + // Information on source file that is on display, or failed to be | |
| 52 | + // displayed due to inaccessible source. Used to update display | |
| 53 | + // when sourcepath is changed. | |
| 54 | + | |
| 55 | + private String sourceName; // relative path name, if showSourceFile | |
| 56 | + private Location sourceLocn; // location, if showSourceForLocation | |
| 57 | + private CommandInterpreter interpreter; | |
| 58 | + | |
| 59 | + public SourceTool(Environment env) { | |
| 60 | + | |
| 61 | + super(new BorderLayout()); | |
| 62 | + | |
| 63 | + this.env = env; | |
| 64 | + | |
| 65 | + runtime = env.getExecutionManager(); | |
| 66 | + sourceManager = env.getSourceManager(); | |
| 67 | + this.context = env.getContextManager(); | |
| 68 | + this.interpreter = new CommandInterpreter(env, true); | |
| 69 | + | |
| 70 | + sourceModel = new DefaultListModel(); // empty | |
| 71 | + | |
| 72 | + list = new JList(sourceModel); | |
| 73 | + list.setCellRenderer(new SourceLineRenderer()); | |
| 74 | + | |
| 75 | + list.setPrototypeCellValue(SourceModel.prototypeCellValue); | |
| 76 | + | |
| 77 | + SourceToolListener listener = new SourceToolListener(); | |
| 78 | + context.addContextListener(listener); | |
| 79 | + runtime.addSpecListener(listener); | |
| 80 | + sourceManager.addSourceListener(listener); | |
| 81 | + | |
| 82 | + MouseListener squeek = new STMouseListener(); | |
| 83 | + list.addMouseListener(squeek); | |
| 84 | + | |
| 85 | + add(new JScrollPane(list)); | |
| 86 | + } | |
| 87 | + | |
| 88 | + public void setTextFont(Font f) { | |
| 89 | + list.setFont(f); | |
| 90 | + list.setPrototypeCellValue(SourceModel.prototypeCellValue); | |
| 91 | + } | |
| 92 | + | |
| 93 | + private class SourceToolListener | |
| 94 | + implements ContextListener, SourceListener, SpecListener | |
| 95 | + { | |
| 96 | + | |
| 97 | + // ContextListener | |
| 98 | + | |
| 99 | + @Override | |
| 100 | + public void currentFrameChanged(CurrentFrameChangedEvent e) { | |
| 101 | + showSourceContext(e.getThread(), e.getIndex()); | |
| 102 | + } | |
| 103 | + | |
| 104 | + // Clear source view. | |
| 105 | + // sourceModel = new DefaultListModel(); // empty | |
| 106 | + | |
| 107 | + // SourceListener | |
| 108 | + | |
| 109 | + @Override | |
| 110 | + public void sourcepathChanged(SourcepathChangedEvent e) { | |
| 111 | + // Reload source view if its contents depend | |
| 112 | + // on the source path. | |
| 113 | + if (sourceName != null) { | |
| 114 | + showSourceFile(sourceName); | |
| 115 | + } else if (sourceLocn != null) { | |
| 116 | + showSourceForLocation(sourceLocn); | |
| 117 | + } | |
| 118 | + } | |
| 119 | + | |
| 120 | + // SpecListener | |
| 121 | + | |
| 122 | + @Override | |
| 123 | + public void breakpointSet(SpecEvent e) { | |
| 124 | + breakpointResolved(e); | |
| 125 | + } | |
| 126 | + | |
| 127 | + @Override | |
| 128 | + public void breakpointDeferred(SpecEvent e) { } | |
| 129 | + | |
| 130 | + @Override | |
| 131 | + public void breakpointDeleted(SpecEvent e) { | |
| 132 | + BreakpointRequest req = (BreakpointRequest)e.getEventRequest(); | |
| 133 | + Location loc = req.location(); | |
| 134 | + if (loc != null) { | |
| 135 | + try { | |
| 136 | + SourceModel sm = sourceManager.sourceForLocation(loc); | |
| 137 | + sm.showBreakpoint(loc.lineNumber(), false); | |
| 138 | + showSourceForLocation(loc); | |
| 139 | + } catch (Exception exc) { | |
| 140 | + } | |
| 141 | + } | |
| 142 | + } | |
| 143 | + | |
| 144 | + @Override | |
| 145 | + public void breakpointResolved(SpecEvent e) { | |
| 146 | + BreakpointRequest req = (BreakpointRequest)e.getEventRequest(); | |
| 147 | + Location loc = req.location(); | |
| 148 | + try { | |
| 149 | + SourceModel sm = sourceManager.sourceForLocation(loc); | |
| 150 | + sm.showBreakpoint(loc.lineNumber(), true); | |
| 151 | + showSourceForLocation(loc); | |
| 152 | + } catch (Exception exc) { | |
| 153 | + } | |
| 154 | + } | |
| 155 | + | |
| 156 | + @Override | |
| 157 | + public void breakpointError(SpecErrorEvent e) { | |
| 158 | + breakpointDeleted(e); | |
| 159 | + } | |
| 160 | + | |
| 161 | + @Override | |
| 162 | + public void watchpointSet(SpecEvent e) { | |
| 163 | + } | |
| 164 | + @Override | |
| 165 | + public void watchpointDeferred(SpecEvent e) { | |
| 166 | + } | |
| 167 | + @Override | |
| 168 | + public void watchpointDeleted(SpecEvent e) { | |
| 169 | + } | |
| 170 | + @Override | |
| 171 | + public void watchpointResolved(SpecEvent e) { | |
| 172 | + } | |
| 173 | + @Override | |
| 174 | + public void watchpointError(SpecErrorEvent e) { | |
| 175 | + } | |
| 176 | + | |
| 177 | + @Override | |
| 178 | + public void exceptionInterceptSet(SpecEvent e) { | |
| 179 | + } | |
| 180 | + @Override | |
| 181 | + public void exceptionInterceptDeferred(SpecEvent e) { | |
| 182 | + } | |
| 183 | + @Override | |
| 184 | + public void exceptionInterceptDeleted(SpecEvent e) { | |
| 185 | + } | |
| 186 | + @Override | |
| 187 | + public void exceptionInterceptResolved(SpecEvent e) { | |
| 188 | + } | |
| 189 | + @Override | |
| 190 | + public void exceptionInterceptError(SpecErrorEvent e) { | |
| 191 | + } | |
| 192 | + } | |
| 193 | + | |
| 194 | + private void showSourceContext(ThreadReference thread, int index) { | |
| 195 | + //### Should use ThreadInfo here. | |
| 196 | + StackFrame frame = null; | |
| 197 | + if (thread != null) { | |
| 198 | + try { | |
| 199 | + frame = thread.frame(index); | |
| 200 | + } catch (IncompatibleThreadStateException e) {} | |
| 201 | + } | |
| 202 | + if (frame == null) { | |
| 203 | + return; | |
| 204 | + } | |
| 205 | + Location locn = frame.location(); | |
| 206 | + /***** | |
| 207 | + if (!showSourceForLocation(locn)) { | |
| 208 | + env.notice("Could not display source for " | |
| 209 | + + Utils.locationString(locn)); | |
| 210 | + } | |
| 211 | + *****/ | |
| 212 | + showSourceForLocation(locn); | |
| 213 | + } | |
| 214 | + | |
| 215 | + public boolean showSourceForLocation(Location locn) { | |
| 216 | + sourceName = null; | |
| 217 | + sourceLocn = locn; | |
| 218 | + int lineNo = locn.lineNumber(); | |
| 219 | + if (lineNo != -1) { | |
| 220 | + SourceModel source = sourceManager.sourceForLocation(locn); | |
| 221 | + if (source != null) { | |
| 222 | + showSourceAtLine(source, lineNo-1); | |
| 223 | + return true; | |
| 224 | + } | |
| 225 | + } | |
| 226 | + // Here if we could not display source. | |
| 227 | + showSourceUnavailable(); | |
| 228 | + return false; | |
| 229 | + } | |
| 230 | + | |
| 231 | + public boolean showSourceFile(String fileName) { | |
| 232 | + sourceLocn = null; | |
| 233 | + File file; | |
| 234 | + if (!fileName.startsWith(File.separator)) { | |
| 235 | + sourceName = fileName; | |
| 236 | + SearchPath sourcePath = sourceManager.getSourcePath(); | |
| 237 | + file = sourcePath.resolve(fileName); | |
| 238 | + if (file == null) { | |
| 239 | + //env.failure("Source not found on current source path."); | |
| 240 | + showSourceUnavailable(); | |
| 241 | + return false; | |
| 242 | + } | |
| 243 | + } else { | |
| 244 | + sourceName = null; // Absolute pathname does not depend on sourcepath. | |
| 245 | + file = new File(fileName); | |
| 246 | + } | |
| 247 | + SourceModel source = sourceManager.sourceForFile(file); | |
| 248 | + if (source != null) { | |
| 249 | + showSource(source); | |
| 250 | + return true; | |
| 251 | + } | |
| 252 | + showSourceUnavailable(); | |
| 253 | + return false; | |
| 254 | + } | |
| 255 | + | |
| 256 | + private void showSource(SourceModel model) { | |
| 257 | + setViewModel(model); | |
| 258 | + } | |
| 259 | + | |
| 260 | + private void showSourceAtLine(SourceModel model, int lineNo) { | |
| 261 | + setViewModel(model); | |
| 262 | + if (model.isActuallySource && (lineNo < model.getSize())) { | |
| 263 | + list.setSelectedIndex(lineNo); | |
| 264 | + if (lineNo+4 < model.getSize()) { | |
| 265 | + list.ensureIndexIsVisible(lineNo+4); // give some context | |
| 266 | + } | |
| 267 | + list.ensureIndexIsVisible(lineNo); | |
| 268 | + } | |
| 269 | + } | |
| 270 | + | |
| 271 | + private void showSourceUnavailable() { | |
| 272 | + SourceModel model = new SourceModel("[Source code is not available]"); | |
| 273 | + setViewModel(model); | |
| 274 | + } | |
| 275 | + | |
| 276 | + private void setViewModel(SourceModel model) { | |
| 277 | + if (model != sourceModel) { | |
| 278 | + // install new model | |
| 279 | + list.setModel(model); | |
| 280 | + sourceModel = model; | |
| 281 | + } | |
| 282 | + } | |
| 283 | + | |
| 284 | + private class SourceLineRenderer extends DefaultListCellRenderer { | |
| 285 | + | |
| 286 | + @Override | |
| 287 | + public Component getListCellRendererComponent(JList list, | |
| 288 | + Object value, | |
| 289 | + int index, | |
| 290 | + boolean isSelected, | |
| 291 | + boolean cellHasFocus) { | |
| 292 | + | |
| 293 | + //### Should set background highlight and/or icon if breakpoint on this line. | |
| 294 | + // Configures "this" | |
| 295 | + super.getListCellRendererComponent(list, value, index, | |
| 296 | + isSelected, cellHasFocus); | |
| 297 | + | |
| 298 | + SourceModel.Line line = (SourceModel.Line)value; | |
| 299 | + | |
| 300 | + //### Tab expansion is now done when source file is read in, | |
| 301 | + //### to speed up display. This costs a lot of space, slows | |
| 302 | + //### down source file loading, and has not been demonstrated | |
| 303 | + //### to yield an observable improvement in display performance. | |
| 304 | + //### Measurements may be appropriate here. | |
| 305 | + //String sourceLine = expandTabs((String)value); | |
| 306 | + setText(line.text); | |
| 307 | + if (line.hasBreakpoint) { | |
| 308 | + setIcon(Icons.stopSignIcon); | |
| 309 | + } else if (line.isExecutable()) { | |
| 310 | + setIcon(Icons.execIcon); | |
| 311 | + } else { | |
| 312 | + setIcon(Icons.blankIcon); | |
| 313 | + } | |
| 314 | + | |
| 315 | + | |
| 316 | + return this; | |
| 317 | + } | |
| 318 | + | |
| 319 | + @Override | |
| 320 | + public Dimension getPreferredSize() { | |
| 321 | + Dimension dim = super.getPreferredSize(); | |
| 322 | + return new Dimension(dim.width, dim.height-5); | |
| 323 | + } | |
| 324 | + | |
| 325 | + } | |
| 326 | + | |
| 327 | + private class STMouseListener extends MouseAdapter implements MouseListener { | |
| 328 | + @Override | |
| 329 | + public void mousePressed(MouseEvent e) { | |
| 330 | + if (e.isPopupTrigger()) { | |
| 331 | + showPopupMenu((Component)e.getSource(), | |
| 332 | + e.getX(), e.getY()); | |
| 333 | + } | |
| 334 | + } | |
| 335 | + | |
| 336 | + @Override | |
| 337 | + public void mouseReleased(MouseEvent e) { | |
| 338 | + if (e.isPopupTrigger()) { | |
| 339 | + showPopupMenu((Component)e.getSource(), | |
| 340 | + e.getX(), e.getY()); | |
| 341 | + } | |
| 342 | + } | |
| 343 | + | |
| 344 | + private void showPopupMenu(Component invoker, int x, int y) { | |
| 345 | + JList list = (JList)invoker; | |
| 346 | + int ln = list.getSelectedIndex() + 1; | |
| 347 | + SourceModel.Line line = | |
| 348 | + (SourceModel.Line)list.getSelectedValue(); | |
| 349 | + JPopupMenu popup = new JPopupMenu(); | |
| 350 | + | |
| 351 | + if (line == null) { | |
| 352 | + popup.add(new JMenuItem("please select a line")); | |
| 353 | + } else if (line.isExecutable()) { | |
| 354 | + String className = line.refType.name(); | |
| 355 | + if (line.hasBreakpoint()) { | |
| 356 | + popup.add(commandItem("Clear Breakpoint", | |
| 357 | + "clear " + className + | |
| 358 | + ":" + ln)); | |
| 359 | + } else { | |
| 360 | + popup.add(commandItem("Set Breakpoint", | |
| 361 | + "stop at " + className + | |
| 362 | + ":" + ln)); | |
| 363 | + } | |
| 364 | + } else { | |
| 365 | + popup.add(new JMenuItem("not an executable line")); | |
| 366 | + } | |
| 367 | + | |
| 368 | + popup.show(invoker, | |
| 369 | + x + popup.getWidth()/2, y + popup.getHeight()/2); | |
| 370 | + } | |
| 371 | + | |
| 372 | + private JMenuItem commandItem(String label, final String cmd) { | |
| 373 | + JMenuItem item = new JMenuItem(label); | |
| 374 | + item.addActionListener(new ActionListener() { | |
| 375 | + @Override | |
| 376 | + public void actionPerformed(ActionEvent e) { | |
| 377 | + interpreter.executeCommand(cmd); | |
| 378 | + } | |
| 379 | + }); | |
| 380 | + return item; | |
| 381 | + } | |
| 382 | + } | |
| 383 | +} | |
| @@ -0,0 +1,283 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | +import java.util.*; | |
| 30 | + | |
| 31 | +import javax.swing.*; | |
| 32 | +import javax.swing.tree.*; | |
| 33 | +import java.awt.*; | |
| 34 | +import java.awt.event.*; | |
| 35 | + | |
| 36 | +import com.sun.tools.example.debug.bdi.*; | |
| 37 | + | |
| 38 | +public class SourceTreeTool extends JPanel { | |
| 39 | + | |
| 40 | + private static final long serialVersionUID = 3336680912107956419L; | |
| 41 | + | |
| 42 | + private Environment env; | |
| 43 | + | |
| 44 | + private ExecutionManager runtime; | |
| 45 | + private SourceManager sourceManager; | |
| 46 | + private ClassManager classManager; | |
| 47 | + | |
| 48 | + private JTree tree; | |
| 49 | + private SourceTreeNode root; | |
| 50 | + private SearchPath sourcePath; | |
| 51 | + private CommandInterpreter interpreter; | |
| 52 | + | |
| 53 | + private static String HEADING = "SOURCES"; | |
| 54 | + | |
| 55 | + public SourceTreeTool(Environment env) { | |
| 56 | + | |
| 57 | + super(new BorderLayout()); | |
| 58 | + | |
| 59 | + this.env = env; | |
| 60 | + this.runtime = env.getExecutionManager(); | |
| 61 | + this.sourceManager = env.getSourceManager(); | |
| 62 | + | |
| 63 | + this.interpreter = new CommandInterpreter(env); | |
| 64 | + | |
| 65 | + sourcePath = sourceManager.getSourcePath(); | |
| 66 | + root = createDirectoryTree(HEADING); | |
| 67 | + | |
| 68 | + // Create a tree that allows one selection at a time. | |
| 69 | + tree = new JTree(new DefaultTreeModel(root)); | |
| 70 | + tree.setSelectionModel(new SingleLeafTreeSelectionModel()); | |
| 71 | + | |
| 72 | + /****** | |
| 73 | + // Listen for when the selection changes. | |
| 74 | + tree.addTreeSelectionListener(new TreeSelectionListener() { | |
| 75 | + public void valueChanged(TreeSelectionEvent e) { | |
| 76 | + SourceTreeNode node = (SourceTreeNode) | |
| 77 | + (e.getPath().getLastPathComponent()); | |
| 78 | + interpreter.executeCommand("view " + node.getRelativePath()); | |
| 79 | + } | |
| 80 | + }); | |
| 81 | + ******/ | |
| 82 | + | |
| 83 | + MouseListener ml = new MouseAdapter() { | |
| 84 | + @Override | |
| 85 | + public void mouseClicked(MouseEvent e) { | |
| 86 | + int selRow = tree.getRowForLocation(e.getX(), e.getY()); | |
| 87 | + TreePath selPath = tree.getPathForLocation(e.getX(), e.getY()); | |
| 88 | + if(selRow != -1) { | |
| 89 | + if(e.getClickCount() == 1) { | |
| 90 | + SourceTreeNode node = | |
| 91 | + (SourceTreeNode)selPath.getLastPathComponent(); | |
| 92 | + // If user clicks on leaf, select it, and issue 'view' command. | |
| 93 | + if (node.isLeaf()) { | |
| 94 | + tree.setSelectionPath(selPath); | |
| 95 | + interpreter.executeCommand("view " + node.getRelativePath()); | |
| 96 | + } | |
| 97 | + } | |
| 98 | + } | |
| 99 | + } | |
| 100 | + }; | |
| 101 | + tree.addMouseListener(ml); | |
| 102 | + | |
| 103 | + JScrollPane treeView = new JScrollPane(tree); | |
| 104 | + add(treeView); | |
| 105 | + | |
| 106 | + // Create listener for source path changes. | |
| 107 | + | |
| 108 | + SourceTreeToolListener listener = new SourceTreeToolListener(); | |
| 109 | + sourceManager.addSourceListener(listener); | |
| 110 | + | |
| 111 | + //### remove listeners on exit! | |
| 112 | + } | |
| 113 | + | |
| 114 | + private class SourceTreeToolListener implements SourceListener { | |
| 115 | + | |
| 116 | + @Override | |
| 117 | + public void sourcepathChanged(SourcepathChangedEvent e) { | |
| 118 | + sourcePath = sourceManager.getSourcePath(); | |
| 119 | + root = createDirectoryTree(HEADING); | |
| 120 | + tree.setModel(new DefaultTreeModel(root)); | |
| 121 | + } | |
| 122 | + | |
| 123 | + } | |
| 124 | + | |
| 125 | + private static class SourceOrDirectoryFilter implements FilenameFilter { | |
| 126 | + @Override | |
| 127 | + public boolean accept(File dir, String name) { | |
| 128 | + return (name.endsWith(".java") || | |
| 129 | + new File(dir, name).isDirectory()); | |
| 130 | + } | |
| 131 | + } | |
| 132 | + | |
| 133 | + private static FilenameFilter filter = new SourceOrDirectoryFilter(); | |
| 134 | + | |
| 135 | + SourceTreeNode createDirectoryTree(String label) { | |
| 136 | + try { | |
| 137 | + return new SourceTreeNode(label, null, "", true); | |
| 138 | + } catch (SecurityException e) { | |
| 139 | + env.failure("Cannot access source file or directory"); | |
| 140 | + return null; | |
| 141 | + } | |
| 142 | + } | |
| 143 | + | |
| 144 | + | |
| 145 | + class SourceTreeNode implements TreeNode { | |
| 146 | + | |
| 147 | + private String name; | |
| 148 | + private boolean isDirectory; | |
| 149 | + private SourceTreeNode parent; | |
| 150 | + private SourceTreeNode[] children; | |
| 151 | + private String relativePath; | |
| 152 | + private boolean isExpanded; | |
| 153 | + | |
| 154 | + private SourceTreeNode(String label, | |
| 155 | + SourceTreeNode parent, | |
| 156 | + String relativePath, | |
| 157 | + boolean isDirectory) { | |
| 158 | + this.name = label; | |
| 159 | + this.relativePath = relativePath; | |
| 160 | + this.parent = parent; | |
| 161 | + this.isDirectory = isDirectory; | |
| 162 | + } | |
| 163 | + | |
| 164 | + @Override | |
| 165 | + public String toString() { | |
| 166 | + return name; | |
| 167 | + } | |
| 168 | + | |
| 169 | + public String getRelativePath() { | |
| 170 | + return relativePath; | |
| 171 | + } | |
| 172 | + | |
| 173 | + private void expandIfNeeded() { | |
| 174 | + try { | |
| 175 | + if (!isExpanded && isDirectory) { | |
| 176 | + String[] files = sourcePath.children(relativePath, filter); | |
| 177 | + children = new SourceTreeNode[files.length]; | |
| 178 | + for (int i = 0; i < files.length; i++) { | |
| 179 | + String childName = | |
| 180 | + (relativePath.equals("")) | |
| 181 | + ? files[i] | |
| 182 | + : relativePath + File.separator + files[i]; | |
| 183 | + File file = sourcePath.resolve(childName); | |
| 184 | + boolean isDir = (file != null && file.isDirectory()); | |
| 185 | + children[i] = | |
| 186 | + new SourceTreeNode(files[i], this, childName, isDir); | |
| 187 | + } | |
| 188 | + } | |
| 189 | + isExpanded = true; | |
| 190 | + } catch (SecurityException e) { | |
| 191 | + children = null; | |
| 192 | + env.failure("Cannot access source file or directory"); | |
| 193 | + } | |
| 194 | + } | |
| 195 | + | |
| 196 | + // -- interface TreeNode -- | |
| 197 | + | |
| 198 | + /* | |
| 199 | + * Returns the child <code>TreeNode</code> at index | |
| 200 | + * <code>childIndex</code>. | |
| 201 | + */ | |
| 202 | + @Override | |
| 203 | + public TreeNode getChildAt(int childIndex) { | |
| 204 | + expandIfNeeded(); | |
| 205 | + return children[childIndex]; | |
| 206 | + } | |
| 207 | + | |
| 208 | + /** | |
| 209 | + * Returns the number of children <code>TreeNode</code>s the receiver | |
| 210 | + * contains. | |
| 211 | + */ | |
| 212 | + @Override | |
| 213 | + public int getChildCount() { | |
| 214 | + expandIfNeeded(); | |
| 215 | + return children.length; | |
| 216 | + } | |
| 217 | + | |
| 218 | + /** | |
| 219 | + * Returns the parent <code>TreeNode</code> of the receiver. | |
| 220 | + */ | |
| 221 | + @Override | |
| 222 | + public TreeNode getParent() { | |
| 223 | + return parent; | |
| 224 | + } | |
| 225 | + | |
| 226 | + /** | |
| 227 | + * Returns the index of <code>node</code> in the receivers children. | |
| 228 | + * If the receiver does not contain <code>node</code>, -1 will be | |
| 229 | + * returned. | |
| 230 | + */ | |
| 231 | + @Override | |
| 232 | + public int getIndex(TreeNode node) { | |
| 233 | + expandIfNeeded(); | |
| 234 | + for (int i = 0; i < children.length; i++) { | |
| 235 | + if (children[i] == node) { | |
| 236 | + return i; | |
| 237 | + } | |
| 238 | + } | |
| 239 | + return -1; | |
| 240 | + } | |
| 241 | + | |
| 242 | + /** | |
| 243 | + * Returns true if the receiver allows children. | |
| 244 | + */ | |
| 245 | + @Override | |
| 246 | + public boolean getAllowsChildren() { | |
| 247 | + return isDirectory; | |
| 248 | + } | |
| 249 | + | |
| 250 | + /** | |
| 251 | + * Returns true if the receiver is a leaf. | |
| 252 | + */ | |
| 253 | + @Override | |
| 254 | + public boolean isLeaf() { | |
| 255 | + expandIfNeeded(); | |
| 256 | + return !isDirectory; | |
| 257 | + } | |
| 258 | + | |
| 259 | + /** | |
| 260 | + * Returns the children of the receiver as an Enumeration. | |
| 261 | + */ | |
| 262 | + @Override | |
| 263 | + public Enumeration children() { | |
| 264 | + expandIfNeeded(); | |
| 265 | + return new Enumeration() { | |
| 266 | + int i = 0; | |
| 267 | + @Override | |
| 268 | + public boolean hasMoreElements() { | |
| 269 | + return (i < children.length); | |
| 270 | + } | |
| 271 | + @Override | |
| 272 | + public Object nextElement() throws NoSuchElementException { | |
| 273 | + if (i >= children.length) { | |
| 274 | + throw new NoSuchElementException(); | |
| 275 | + } | |
| 276 | + return children[i++]; | |
| 277 | + } | |
| 278 | + }; | |
| 279 | + } | |
| 280 | + | |
| 281 | + } | |
| 282 | + | |
| 283 | +} | |
| @@ -0,0 +1,37 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.util.EventObject; | |
| 29 | + | |
| 30 | +public class SourcepathChangedEvent extends EventObject { | |
| 31 | + | |
| 32 | + private static final long serialVersionUID = 8762169481005804121L; | |
| 33 | + | |
| 34 | + public SourcepathChangedEvent(Object source) { | |
| 35 | + super(source); | |
| 36 | + } | |
| 37 | +} | |
| @@ -0,0 +1,198 @@ | ||
| 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import javax.swing.*; | |
| 29 | +import javax.swing.event.*; | |
| 30 | +import java.awt.*; | |
| 31 | +import com.sun.jdi.*; | |
| 32 | +import com.sun.tools.example.debug.bdi.*; | |
| 33 | + | |
| 34 | +public class StackTraceTool extends JPanel { | |
| 35 | + | |
| 36 | + private static final long serialVersionUID = 9140041989427965718L; | |
| 37 | + | |
| 38 | + private Environment env; | |
| 39 | + | |
| 40 | + private ExecutionManager runtime; | |
| 41 | + private ContextManager context; | |
| 42 | + | |
| 43 | + private ThreadInfo tinfo; | |
| 44 | + | |
| 45 | + private JList list; | |
| 46 | + private ListModel stackModel; | |
| 47 | + | |
| 48 | + public StackTraceTool(Environment env) { | |
| 49 | + | |
| 50 | + super(new BorderLayout()); | |
| 51 | + | |
| 52 | + this.env = env; | |
| 53 | + this.runtime = env.getExecutionManager(); | |
| 54 | + this.context = env.getContextManager(); | |
| 55 | + | |
| 56 | + stackModel = new DefaultListModel(); // empty | |
| 57 | + | |
| 58 | + list = new JList(stackModel); | |
| 59 | + list.setCellRenderer(new StackFrameRenderer()); | |
| 60 | + | |
| 61 | + JScrollPane listView = new JScrollPane(list); | |
| 62 | + add(listView); | |
| 63 | + | |
| 64 | + // Create listener. | |
| 65 | + StackTraceToolListener listener = new StackTraceToolListener(); | |
| 66 | + context.addContextListener(listener); | |
| 67 | + list.addListSelectionListener(listener); | |
| 68 | + | |
| 69 | + //### remove listeners on exit! | |
| 70 | + } | |
| 71 | + | |
| 72 | + private class StackTraceToolListener | |
| 73 | + implements ContextListener, ListSelectionListener | |
| 74 | + { | |
| 75 | + | |
| 76 | + // ContextListener | |
| 77 | + | |
| 78 | + // If the user selects a new current frame, display it in | |
| 79 | + // this view. | |
| 80 | + | |
| 81 | + //### I suspect we handle the case badly that the VM is not interrupted. | |
| 82 | + | |
| 83 | + @Override | |
| 84 | + public void currentFrameChanged(CurrentFrameChangedEvent e) { | |
| 85 | + // If the current frame of the thread appearing in this | |
| 86 | + // view is changed, move the selection to track it. | |
| 87 | + int frameIndex = e.getIndex(); | |
| 88 | + ThreadInfo ti = e.getThreadInfo(); | |
| 89 | + if (e.getInvalidate() || tinfo != ti) { | |
| 90 | + tinfo = ti; | |
| 91 | + showStack(ti, frameIndex); | |
| 92 | + } else { | |
| 93 | + if (frameIndex < stackModel.getSize()) { | |
| 94 | + list.setSelectedIndex(frameIndex); | |
| 95 | + list.ensureIndexIsVisible(frameIndex); | |
| 96 | + } | |
| 97 | + } | |
| 98 | + } | |
| 99 | + | |
| 100 | + // ListSelectionListener | |
| 101 | + | |
| 102 | + @Override | |
| 103 | + public void valueChanged(ListSelectionEvent e) { | |
| 104 | + int index = list.getSelectedIndex(); | |
| 105 | + if (index != -1) { | |
| 106 | + //### should use listener? | |
| 107 | + try { | |
| 108 | + context.setCurrentFrameIndex(index); | |
| 109 | + } catch (VMNotInterruptedException exc) { | |
| 110 | + } | |
| 111 | + } | |
| 112 | + } | |
| 113 | + } | |
| 114 | + | |
| 115 | + private class StackFrameRenderer extends DefaultListCellRenderer { | |
| 116 | + | |
| 117 | + @Override | |
| 118 | + public Component getListCellRendererComponent(JList list, | |
| 119 | + Object value, | |
| 120 | + int index, | |
| 121 | + boolean isSelected, | |
| 122 | + boolean cellHasFocus) { | |
| 123 | + | |
| 124 | + //### We should indicate the current thread independently of the | |
| 125 | + //### selection, e.g., with an icon, because the user may change | |
| 126 | + //### the selection graphically without affecting the current | |
| 127 | + //### thread. | |
| 128 | + | |
| 129 | + super.getListCellRendererComponent(list, value, index, | |
| 130 | + isSelected, cellHasFocus); | |
| 131 | + if (value == null) { | |
| 132 | + this.setText("<unavailable>"); | |
| 133 | + } else { | |
| 134 | + StackFrame frame = (StackFrame)value; | |
| 135 | + Location loc = frame.location(); | |
| 136 | + Method meth = loc.method(); | |
| 137 | + String methName = | |
| 138 | + meth.declaringType().name() + '.' + meth.name(); | |
| 139 | + String position = ""; | |
| 140 | + if (meth.isNative()) { | |
| 141 | + position = " (native method)"; | |
| 142 | + } else if (loc.lineNumber() != -1) { | |
| 143 | + position = ":" + loc.lineNumber(); | |
| 144 | + } else { | |
| 145 | + long pc = loc.codeIndex(); | |
| 146 | + if (pc != -1) { | |
| 147 | + position = ", pc = " + pc; | |
| 148 | + } | |
| 149 | + } | |
| 150 | + // Indices are presented to the user starting from 1, not 0. | |
| 151 | + this.setText("[" + (index+1) +"] " + methName + position); | |
| 152 | + } | |
| 153 | + return this; | |
| 154 | + } | |
| 155 | + } | |
| 156 | + | |
| 157 | + // Point this view at the given thread and frame. | |
| 158 | + | |
| 159 | + private void showStack(ThreadInfo tinfo, int selectFrame) { | |
| 160 | + StackTraceListModel model = new StackTraceListModel(tinfo); | |
| 161 | + stackModel = model; | |
| 162 | + list.setModel(stackModel); | |
| 163 | + list.setSelectedIndex(selectFrame); | |
| 164 | + list.ensureIndexIsVisible(selectFrame); | |
| 165 | + } | |
| 166 | + | |
| 167 | + private static class StackTraceListModel extends AbstractListModel { | |
| 168 | + | |
| 169 | + private final ThreadInfo tinfo; | |
| 170 | + | |
| 171 | + public StackTraceListModel(ThreadInfo tinfo) { | |
| 172 | + this.tinfo = tinfo; | |
| 173 | + } | |
| 174 | + | |
| 175 | + @Override | |
| 176 | + public Object getElementAt(int index) { | |
| 177 | + try { | |
| 178 | + return tinfo == null? null : tinfo.getFrame(index); | |
| 179 | + } catch (VMNotInterruptedException e) { | |
| 180 | + //### Is this the right way to handle this? | |
| 181 | + //### Would happen if user scrolled stack trace | |
| 182 | + //### while not interrupted -- should probably | |
| 183 | + //### block user interaction in this case. | |
| 184 | + return null; | |
| 185 | + } | |
| 186 | + } | |
| 187 | + | |
| 188 | + @Override | |
| 189 | + public int getSize() { | |
| 190 | + try { | |
| 191 | + return tinfo == null? 1 : tinfo.getFrameCount(); | |
| 192 | + } catch (VMNotInterruptedException e) { | |
| 193 | + //### Is this the right way to handle this? | |
| 194 | + return 0; | |
| 195 | + } | |
| 196 | + } | |
| 197 | + } | |
| 198 | +} | |
| @@ -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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.util.*; | |
| 29 | +import java.util.List; // Must import explicitly due to conflict with javax.awt.List | |
| 30 | + | |
| 31 | +import javax.swing.*; | |
| 32 | +import javax.swing.tree.*; | |
| 33 | +import java.awt.*; | |
| 34 | +import java.awt.event.*; | |
| 35 | + | |
| 36 | +import com.sun.jdi.*; | |
| 37 | +import com.sun.tools.example.debug.event.*; | |
| 38 | +import 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 | + | |
| 44 | +public 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 | +} | |
| @@ -0,0 +1,123 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.awt.*; | |
| 29 | +import java.awt.event.*; | |
| 30 | +import javax.swing.*; | |
| 31 | + | |
| 32 | +public class TypeScript extends JPanel { | |
| 33 | + | |
| 34 | + private static final long serialVersionUID = -983704841363534885L; | |
| 35 | + private JTextArea history; | |
| 36 | + private JTextField entry; | |
| 37 | + | |
| 38 | + private JLabel promptLabel; | |
| 39 | + | |
| 40 | + private JScrollBar historyVScrollBar; | |
| 41 | + private JScrollBar historyHScrollBar; | |
| 42 | + | |
| 43 | + private boolean echoInput = false; | |
| 44 | + | |
| 45 | + private static String newline = System.getProperty("line.separator"); | |
| 46 | + | |
| 47 | + public TypeScript(String prompt) { | |
| 48 | + this(prompt, true); | |
| 49 | + } | |
| 50 | + | |
| 51 | + public TypeScript(String prompt, boolean echoInput) { | |
| 52 | + this.echoInput = echoInput; | |
| 53 | + | |
| 54 | + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); | |
| 55 | + //setBorder(new EmptyBorder(5, 5, 5, 5)); | |
| 56 | + | |
| 57 | + history = new JTextArea(0, 0); | |
| 58 | + history.setEditable(false); | |
| 59 | + JScrollPane scroller = new JScrollPane(history); | |
| 60 | + historyVScrollBar = scroller.getVerticalScrollBar(); | |
| 61 | + historyHScrollBar = scroller.getHorizontalScrollBar(); | |
| 62 | + | |
| 63 | + add(scroller); | |
| 64 | + | |
| 65 | + JPanel cmdLine = new JPanel(); | |
| 66 | + cmdLine.setLayout(new BoxLayout(cmdLine, BoxLayout.X_AXIS)); | |
| 67 | + //cmdLine.setBorder(new EmptyBorder(5, 5, 0, 0)); | |
| 68 | + | |
| 69 | + promptLabel = new JLabel(prompt + " "); | |
| 70 | + cmdLine.add(promptLabel); | |
| 71 | + entry = new JTextField(); | |
| 72 | +//### Swing bug workaround. | |
| 73 | +entry.setMaximumSize(new Dimension(1000, 20)); | |
| 74 | + cmdLine.add(entry); | |
| 75 | + add(cmdLine); | |
| 76 | + } | |
| 77 | + | |
| 78 | + /****** | |
| 79 | + public void setFont(Font f) { | |
| 80 | + entry.setFont(f); | |
| 81 | + history.setFont(f); | |
| 82 | + } | |
| 83 | + ******/ | |
| 84 | + | |
| 85 | + public void setPrompt(String prompt) { | |
| 86 | + promptLabel.setText(prompt + " "); | |
| 87 | + } | |
| 88 | + | |
| 89 | + public void append(String text) { | |
| 90 | + history.append(text); | |
| 91 | + historyVScrollBar.setValue(historyVScrollBar.getMaximum()); | |
| 92 | + historyHScrollBar.setValue(historyHScrollBar.getMinimum()); | |
| 93 | + } | |
| 94 | + | |
| 95 | + public void newline() { | |
| 96 | + history.append(newline); | |
| 97 | + historyVScrollBar.setValue(historyVScrollBar.getMaximum()); | |
| 98 | + historyHScrollBar.setValue(historyHScrollBar.getMinimum()); | |
| 99 | + } | |
| 100 | + | |
| 101 | + public void flush() {} | |
| 102 | + | |
| 103 | + public void addActionListener(ActionListener a) { | |
| 104 | + entry.addActionListener(a); | |
| 105 | + } | |
| 106 | + | |
| 107 | + public void removeActionListener(ActionListener a) { | |
| 108 | + entry.removeActionListener(a); | |
| 109 | + } | |
| 110 | + | |
| 111 | + public String readln() { | |
| 112 | + String text = entry.getText(); | |
| 113 | + entry.setText(""); | |
| 114 | + if (echoInput) { | |
| 115 | + history.append(">>>"); | |
| 116 | + history.append(text); | |
| 117 | + history.append(newline); | |
| 118 | + historyVScrollBar.setValue(historyVScrollBar.getMaximum()); | |
| 119 | + historyHScrollBar.setValue(historyHScrollBar.getMinimum()); | |
| 120 | + } | |
| 121 | + return text; | |
| 122 | + } | |
| 123 | +} | |
| @@ -0,0 +1,52 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import com.sun.tools.example.debug.bdi.OutputListener; | |
| 29 | + | |
| 30 | +public class TypeScriptOutputListener implements OutputListener { | |
| 31 | + | |
| 32 | + private TypeScript script; | |
| 33 | + private boolean appendNewline; | |
| 34 | + | |
| 35 | + public TypeScriptOutputListener(TypeScript script) { | |
| 36 | + this(script, false); | |
| 37 | + } | |
| 38 | + | |
| 39 | + public TypeScriptOutputListener(TypeScript script, boolean appendNewline) { | |
| 40 | + this.script = script; | |
| 41 | + this.appendNewline = appendNewline; | |
| 42 | + } | |
| 43 | + | |
| 44 | + @Override | |
| 45 | + public void putString(String s) { | |
| 46 | + script.append(s); | |
| 47 | + if (appendNewline) { | |
| 48 | + script.newline(); | |
| 49 | + } | |
| 50 | + } | |
| 51 | + | |
| 52 | +} | |
| @@ -0,0 +1,52 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 1999, 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 | + | |
| 26 | +package com.sun.tools.example.debug.gui; | |
| 27 | + | |
| 28 | +import java.io.*; | |
| 29 | + | |
| 30 | +public class TypeScriptWriter extends Writer { | |
| 31 | + | |
| 32 | + TypeScript script; | |
| 33 | + | |
| 34 | + public TypeScriptWriter(TypeScript script) { | |
| 35 | + this.script = script; | |
| 36 | + } | |
| 37 | + | |
| 38 | + @Override | |
| 39 | + public void write(char[] cbuf, int off, int len) throws IOException { | |
| 40 | + script.append(String.valueOf(cbuf, off, len)); | |
| 41 | + } | |
| 42 | + | |
| 43 | + @Override | |
| 44 | + public void flush() { | |
| 45 | + script.flush(); | |
| 46 | + } | |
| 47 | + | |
| 48 | + @Override | |
| 49 | + public void close() { | |
| 50 | + script.flush(); | |
| 51 | + } | |
| 52 | +} | |
| @@ -0,0 +1,38 @@ | ||
| 1 | +<../../../../../../../../mkconfig | |
| 2 | + | |
| 3 | +TARG=\ | |
| 4 | + ApplicationTool.dis\ | |
| 5 | + ClassManager.dis\ | |
| 6 | + ClassTreeTool.dis\ | |
| 7 | + CommandInterpreter.dis\ | |
| 8 | + CommandTool.dis\ | |
| 9 | + ContextListener.dis\ | |
| 10 | + ContextManager.dis\ | |
| 11 | + CurrentFrameChangedEvent.dis\ | |
| 12 | + Environment.dis\ | |
| 13 | + GUI.dis\ | |
| 14 | + Icons.dis\ | |
| 15 | + JDBFileFilter.dis\ | |
| 16 | + JDBMenuBar.dis\ | |
| 17 | + JDBToolBar.dis\ | |
| 18 | + LaunchTool.dis\ | |
| 19 | + MonitorListModel.dis\ | |
| 20 | + MonitorTool.dis\ | |
| 21 | + OutputSink.dis\ | |
| 22 | + SearchPath.dis\ | |
| 23 | + SingleLeafTreeSelectionModel.dis\ | |
| 24 | + SourceListener.dis\ | |
| 25 | + SourceManager.dis\ | |
| 26 | + SourceModel.dis\ | |
| 27 | + SourcepathChangedEvent.dis\ | |
| 28 | + SourceTool.dis\ | |
| 29 | + SourceTreeTool.dis\ | |
| 30 | + StackTraceTool.dis\ | |
| 31 | + ThreadTreeTool.dis\ | |
| 32 | + TypeScript.dis\ | |
| 33 | + TypeScriptOutputListener.dis\ | |
| 34 | + TypeScriptWriter.dis\ | |
| 35 | + | |
| 36 | +DISBIN=$ROOT/java/dis/java/java/com/sun/tools/example/debug/gui | |
| 37 | + | |
| 38 | +<$ROOT/mkfiles/mkjava | |