/*
* Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
package com.sun.tools.example.debug.gui;
import java.io.*;
import java.util.*;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.event.*;
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import com.sun.tools.example.debug.bdi.*;
import com.sun.tools.example.debug.event.*;
public class CommandTool extends JPanel {
private static final long serialVersionUID = 8613516856378346415L;
private Environment env;
private ContextManager context;
private ExecutionManager runtime;
private SourceManager sourceManager;
private TypeScript script;
private static final String DEFAULT_CMD_PROMPT = "Command:";
public CommandTool(Environment env) {
super(new BorderLayout());
this.env = env;
this.context = env.getContextManager();
this.runtime = env.getExecutionManager();
this.sourceManager = env.getSourceManager();
script = new TypeScript(DEFAULT_CMD_PROMPT, false); //no echo
this.add(script);
final CommandInterpreter interpreter =
new CommandInterpreter(env);
// Establish handler for incoming commands.
script.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
interpreter.executeCommand(script.readln());
}
});
// Establish ourselves as the listener for VM diagnostics.
OutputListener diagnosticsListener =
new TypeScriptOutputListener(script, true);
runtime.addDiagnosticsListener(diagnosticsListener);
// Establish ourselves as the shared debugger typescript.
env.setTypeScript(new PrintWriter(new TypeScriptWriter(script)));
// Handle VM events.
TTYDebugListener listener = new TTYDebugListener(diagnosticsListener);
runtime.addJDIListener(listener);
runtime.addSessionListener(listener);
runtime.addSpecListener(listener);
context.addContextListener(listener);
//### remove listeners on exit!
}
private class TTYDebugListener implements
JDIListener, SessionListener, SpecListener, ContextListener {
private OutputListener diagnostics;
TTYDebugListener(OutputListener diagnostics) {
this.diagnostics = diagnostics;
}
// JDIListener
@Override
public void accessWatchpoint(AccessWatchpointEventSet e) {
setThread(e);
for (EventIterator it = e.eventIterator(); it.hasNext(); ) {
it.nextEvent();
diagnostics.putString("Watchpoint hit: " +
locationString(e));
}
}
@Override
public void classPrepare(ClassPrepareEventSet e) {
if (context.getVerboseFlag()) {
String name = e.getReferenceType().name();
diagnostics.putString("Class " + name + " loaded");
}
}
@Override
public void classUnload(ClassUnloadEventSet e) {
if (context.getVerboseFlag()) {
diagnostics.putString("Class " + e.getClassName() +
" unloaded.");
}
}
@Override
public void exception(ExceptionEventSet e) {
setThread(e);
String name = e.getException().referenceType().name();
diagnostics.putString("Exception: " + name);
}
@Override
public void locationTrigger(LocationTriggerEventSet e) {
String locString = locationString(e);
setThread(e);
for (EventIterator it = e.eventIterator(); it.hasNext(); ) {
Event evt = it.nextEvent();
if (evt instanceof BreakpointEvent) {
diagnostics.putString("Breakpoint hit: " + locString);
} else if (evt instanceof StepEvent) {
diagnostics.putString("Step completed: " + locString);
} else if (evt instanceof MethodEntryEvent) {
diagnostics.putString("Method entered: " + locString);
} else if (evt instanceof MethodExitEvent) {
diagnostics.putString("Method exited: " + locString);
} else {
diagnostics.putString("UNKNOWN event: " + e);
}
}
}
@Override
public void modificationWatchpoint(ModificationWatchpointEventSet e) {
setThread(e);
for (EventIterator it = e.eventIterator(); it.hasNext(); ) {
it.nextEvent();
diagnostics.putString("Watchpoint hit: " +
locationString(e));
}
}
@Override
public void threadDeath(ThreadDeathEventSet e) {
if (context.getVerboseFlag()) {
diagnostics.putString("Thread " + e.getThread() +
" ended.");
}
}
@Override
public void threadStart(ThreadStartEventSet e) {
if (context.getVerboseFlag()) {
diagnostics.putString("Thread " + e.getThread() +
" started.");
}
}
@Override
public void vmDeath(VMDeathEventSet e) {
script.setPrompt(DEFAULT_CMD_PROMPT);
diagnostics.putString("VM exited");
}
@Override
public void vmDisconnect(VMDisconnectEventSet e) {
script.setPrompt(DEFAULT_CMD_PROMPT);
diagnostics.putString("Disconnected from VM");
}
@Override
public void vmStart(VMStartEventSet e) {
script.setPrompt(DEFAULT_CMD_PROMPT);
diagnostics.putString("VM started");
}
// SessionListener
@Override
public void sessionStart(EventObject e) {}
@Override
public void sessionInterrupt(EventObject e) {
Thread.yield(); // fetch output
diagnostics.putString("VM interrupted by user.");
script.setPrompt(DEFAULT_CMD_PROMPT);
}
@Override
public void sessionContinue(EventObject e) {
diagnostics.putString("Execution resumed.");
script.setPrompt(DEFAULT_CMD_PROMPT);
}
// SpecListener
@Override
public void breakpointSet(SpecEvent e) {
EventRequestSpec spec = e.getEventRequestSpec();
diagnostics.putString("Breakpoint set at " + spec + ".");
}
@Override
public void breakpointDeferred(SpecEvent e) {
EventRequestSpec spec = e.getEventRequestSpec();
diagnostics.putString("Breakpoint will be set at " +
spec + " when its class is loaded.");
}
@Override
public void breakpointDeleted(SpecEvent e) {
EventRequestSpec spec = e.getEventRequestSpec();
diagnostics.putString("Breakpoint at " + spec.toString() + " deleted.");
}
@Override
public void breakpointResolved(SpecEvent e) {
EventRequestSpec spec = e.getEventRequestSpec();
diagnostics.putString("Breakpoint resolved to " + spec.toString() + ".");
}
@Override
public void breakpointError(SpecErrorEvent e) {
EventRequestSpec spec = e.getEventRequestSpec();
diagnostics.putString("Deferred breakpoint at " +
spec + " could not be resolved:" +
e.getReason());
}
//### Add info for watchpoints and exceptions
@Override
public void watchpointSet(SpecEvent e) {
}
@Override
public void watchpointDeferred(SpecEvent e) {
}
@Override
public void watchpointDeleted(SpecEvent e) {
}
@Override
public void watchpointResolved(SpecEvent e) {
}
@Override
public void watchpointError(SpecErrorEvent e) {
}
@Override
public void exceptionInterceptSet(SpecEvent e) {
}
@Override
public void exceptionInterceptDeferred(SpecEvent e) {
}
@Override
public void exceptionInterceptDeleted(SpecEvent e) {
}
@Override
public void exceptionInterceptResolved(SpecEvent e) {
}
@Override
public void exceptionInterceptError(SpecErrorEvent e) {
}
// ContextListener.
// If the user selects a new current thread or frame, update prompt.
@Override
public void currentFrameChanged(CurrentFrameChangedEvent e) {
// Update prompt only if affect thread is current.
ThreadReference thread = e.getThread();
if (thread == context.getCurrentThread()) {
script.setPrompt(promptString(thread, e.getIndex()));
}
}
}
private String locationString(LocatableEventSet e) {
Location loc = e.getLocation();
return "thread=\"" + e.getThread().name() +
"\", " + Utils.locationString(loc);
}
private void setThread(LocatableEventSet e) {
if (!e.suspendedNone()) {
Thread.yield(); // fetch output
script.setPrompt(promptString(e.getThread(), 0));
//### Current thread should be set elsewhere, e.g.,
//### in ContextManager
//### context.setCurrentThread(thread);
}
}
private String promptString(ThreadReference thread, int frameIndex) {
if (thread == null) {
return DEFAULT_CMD_PROMPT;
} else {
// Frame indices are presented to user as indexed from 1.
return (thread.name() + "[" + (frameIndex + 1) + "]:");
}
}
}