1 /* 2 * Copyright (c) 1998, 2011, 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 /* 27 * This source code is provided to illustrate the usage of a given feature 28 * or technique and has been deliberately simplified. Additional steps 29 * required for a production-quality application, such as security checks, 30 * input validation and proper error handling, might not be present in 31 * this sample code. 32 */ 33 34 35 package com.sun.tools.example.debug.gui; 36 37 import java.io.*; 38 import java.util.*; 39 40 import javax.swing.*; 41 import java.awt.BorderLayout; 42 import java.awt.event.*; 43 44 import com.sun.jdi.*; 45 import com.sun.jdi.event.*; 46 47 import com.sun.tools.example.debug.bdi.*; 48 import com.sun.tools.example.debug.event.*; 49 50 public class CommandTool extends JPanel { 51 52 private static final long serialVersionUID = 8613516856378346415L; 53 54 private Environment env; 55 56 private ContextManager context; 57 private ExecutionManager runtime; 58 private SourceManager sourceManager; 59 60 private TypeScript script; 61 62 private static final String DEFAULT_CMD_PROMPT = "Command:"; 63 64 public CommandTool(Environment env) { 65 66 super(new BorderLayout()); 67 68 this.env = env; 69 this.context = env.getContextManager(); 70 this.runtime = env.getExecutionManager(); 71 this.sourceManager = env.getSourceManager(); 72 73 script = new TypeScript(DEFAULT_CMD_PROMPT, false); //no echo 74 this.add(script); 75 76 final CommandInterpreter interpreter = 77 new CommandInterpreter(env); 78 79 // Establish handler for incoming commands. 80 81 script.addActionListener(new ActionListener() { 82 @Override 83 public void actionPerformed(ActionEvent e) { 84 interpreter.executeCommand(script.readln()); 85 } 86 }); 87 88 // Establish ourselves as the listener for VM diagnostics. 89 90 OutputListener diagnosticsListener = 91 new TypeScriptOutputListener(script, true); 92 runtime.addDiagnosticsListener(diagnosticsListener); 93 94 // Establish ourselves as the shared debugger typescript. 95 96 env.setTypeScript(new PrintWriter(new TypeScriptWriter(script))); 97 98 // Handle VM events. 99 100 TTYDebugListener listener = new TTYDebugListener(diagnosticsListener); 101 102 runtime.addJDIListener(listener); 103 runtime.addSessionListener(listener); 104 runtime.addSpecListener(listener); 105 context.addContextListener(listener); 106 107 //### remove listeners on exit! 108 109 } 110 111 private class TTYDebugListener implements 112 JDIListener, SessionListener, SpecListener, ContextListener { 113 114 private OutputListener diagnostics; 115 116 TTYDebugListener(OutputListener diagnostics) { 117 this.diagnostics = diagnostics; 118 } 119 120 // JDIListener 121 122 @Override 123 public void accessWatchpoint(AccessWatchpointEventSet e) { 124 setThread(e); 125 for (EventIterator it = e.eventIterator(); it.hasNext(); ) { 126 it.nextEvent(); 127 diagnostics.putString("Watchpoint hit: " + 128 locationString(e)); 129 } 130 } 131 132 @Override 133 public void classPrepare(ClassPrepareEventSet e) { 134 if (context.getVerboseFlag()) { 135 String name = e.getReferenceType().name(); 136 diagnostics.putString("Class " + name + " loaded"); 137 } 138 } 139 140 @Override 141 public void classUnload(ClassUnloadEventSet e) { 142 if (context.getVerboseFlag()) { 143 diagnostics.putString("Class " + e.getClassName() + 144 " unloaded."); 145 } 146 } 147 148 @Override 149 public void exception(ExceptionEventSet e) { 150 setThread(e); 151 String name = e.getException().referenceType().name(); 152 diagnostics.putString("Exception: " + name); 153 } 154 155 @Override 156 public void locationTrigger(LocationTriggerEventSet e) { 157 String locString = locationString(e); 158 setThread(e); 159 for (EventIterator it = e.eventIterator(); it.hasNext(); ) { 160 Event evt = it.nextEvent(); 161 if (evt instanceof BreakpointEvent) { 162 diagnostics.putString("Breakpoint hit: " + locString); 163 } else if (evt instanceof StepEvent) { 164 diagnostics.putString("Step completed: " + locString); 165 } else if (evt instanceof MethodEntryEvent) { 166 diagnostics.putString("Method entered: " + locString); 167 } else if (evt instanceof MethodExitEvent) { 168 diagnostics.putString("Method exited: " + locString); 169 } else { 170 diagnostics.putString("UNKNOWN event: " + e); 171 } 172 } 173 } 174 175 @Override 176 public void modificationWatchpoint(ModificationWatchpointEventSet e) { 177 setThread(e); 178 for (EventIterator it = e.eventIterator(); it.hasNext(); ) { 179 it.nextEvent(); 180 diagnostics.putString("Watchpoint hit: " + 181 locationString(e)); 182 } 183 } 184 185 @Override 186 public void threadDeath(ThreadDeathEventSet e) { 187 if (context.getVerboseFlag()) { 188 diagnostics.putString("Thread " + e.getThread() + 189 " ended."); 190 } 191 } 192 193 @Override 194 public void threadStart(ThreadStartEventSet e) { 195 if (context.getVerboseFlag()) { 196 diagnostics.putString("Thread " + e.getThread() + 197 " started."); 198 } 199 } 200 201 @Override 202 public void vmDeath(VMDeathEventSet e) { 203 script.setPrompt(DEFAULT_CMD_PROMPT); 204 diagnostics.putString("VM exited"); 205 } 206 207 @Override 208 public void vmDisconnect(VMDisconnectEventSet e) { 209 script.setPrompt(DEFAULT_CMD_PROMPT); 210 diagnostics.putString("Disconnected from VM"); 211 } 212 213 @Override 214 public void vmStart(VMStartEventSet e) { 215 script.setPrompt(DEFAULT_CMD_PROMPT); 216 diagnostics.putString("VM started"); 217 } 218 219 // SessionListener 220 221 @Override 222 public void sessionStart(EventObject e) {} 223 224 @Override 225 public void sessionInterrupt(EventObject e) { 226 Thread.yield(); // fetch output 227 diagnostics.putString("VM interrupted by user."); 228 script.setPrompt(DEFAULT_CMD_PROMPT); 229 } 230 231 @Override 232 public void sessionContinue(EventObject e) { 233 diagnostics.putString("Execution resumed."); 234 script.setPrompt(DEFAULT_CMD_PROMPT); 235 } 236 237 // SpecListener 238 239 @Override 240 public void breakpointSet(SpecEvent e) { 241 EventRequestSpec spec = e.getEventRequestSpec(); 242 diagnostics.putString("Breakpoint set at " + spec + "."); 243 } 244 @Override 245 public void breakpointDeferred(SpecEvent e) { 246 EventRequestSpec spec = e.getEventRequestSpec(); 247 diagnostics.putString("Breakpoint will be set at " + 248 spec + " when its class is loaded."); 249 } 250 @Override 251 public void breakpointDeleted(SpecEvent e) { 252 EventRequestSpec spec = e.getEventRequestSpec(); 253 diagnostics.putString("Breakpoint at " + spec.toString() + " deleted."); 254 } 255 @Override 256 public void breakpointResolved(SpecEvent e) { 257 EventRequestSpec spec = e.getEventRequestSpec(); 258 diagnostics.putString("Breakpoint resolved to " + spec.toString() + "."); 259 } 260 @Override 261 public void breakpointError(SpecErrorEvent e) { 262 EventRequestSpec spec = e.getEventRequestSpec(); 263 diagnostics.putString("Deferred breakpoint at " + 264 spec + " could not be resolved:" + 265 e.getReason()); 266 } 267 268 //### Add info for watchpoints and exceptions 269 270 @Override 271 public void watchpointSet(SpecEvent e) { 272 } 273 @Override 274 public void watchpointDeferred(SpecEvent e) { 275 } 276 @Override 277 public void watchpointDeleted(SpecEvent e) { 278 } 279 @Override 280 public void watchpointResolved(SpecEvent e) { 281 } 282 @Override 283 public void watchpointError(SpecErrorEvent e) { 284 } 285 286 @Override 287 public void exceptionInterceptSet(SpecEvent e) { 288 } 289 @Override 290 public void exceptionInterceptDeferred(SpecEvent e) { 291 } 292 @Override 293 public void exceptionInterceptDeleted(SpecEvent e) { 294 } 295 @Override 296 public void exceptionInterceptResolved(SpecEvent e) { 297 } 298 @Override 299 public void exceptionInterceptError(SpecErrorEvent e) { 300 } 301 302 303 // ContextListener. 304 305 // If the user selects a new current thread or frame, update prompt. 306 307 @Override 308 public void currentFrameChanged(CurrentFrameChangedEvent e) { 309 // Update prompt only if affect thread is current. 310 ThreadReference thread = e.getThread(); 311 if (thread == context.getCurrentThread()) { 312 script.setPrompt(promptString(thread, e.getIndex())); 313 } 314 } 315 316 } 317 318 private String locationString(LocatableEventSet e) { 319 Location loc = e.getLocation(); 320 return "thread=\"" + e.getThread().name() + 321 "\", " + Utils.locationString(loc); 322 } 323 324 private void setThread(LocatableEventSet e) { 325 if (!e.suspendedNone()) { 326 Thread.yield(); // fetch output 327 script.setPrompt(promptString(e.getThread(), 0)); 328 //### Current thread should be set elsewhere, e.g., 329 //### in ContextManager 330 //### context.setCurrentThread(thread); 331 } 332 } 333 334 private String promptString(ThreadReference thread, int frameIndex) { 335 if (thread == null) { 336 return DEFAULT_CMD_PROMPT; 337 } else { 338 // Frame indices are presented to user as indexed from 1. 339 return (thread.name() + "[" + (frameIndex + 1) + "]:"); 340 } 341 } 342 }