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 }