blob: 4d92a82c7cd37e32db397c3d99ad7ca3c78d80bd [file] [log] [blame]
package org.apache.tools.ant.listener;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.ant.debugger.Auditor;
import org.apache.ant.debugger.DebugCommandSet;
import org.apache.ant.debugger.DebugPrompt;
import org.apache.ant.debugger.DebugSupport;
import org.apache.ant.debugger.DefaultAuditor;
import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.MagicNames;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyDebugHelper;
import org.apache.tools.ant.PropertyHelper;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.input.InputHandler;
// The input-listener should itself be pluggable
/*
* We can probably build up a stack of targets in execution to allow dumping a stack of a target
* when a break point occurs?
*
* This class also doubles as a DebugSupport Command that can be used to add new targets / properties
* to debug at runtime.
*/
public class DebuggerListener implements BuildListener, DebugSupport {
/**
* The project being debugged.
*/
protected Project project = null;
/**
* List of all targets at which break points have been applied.
*/
protected List debugtargets = new LinkedList();
/**
* Indicates if this listener instance has been initialized.
*/
protected boolean inited = false;
/**
* Debugger instance.
*/
protected DebugPrompt prompt = null;
/**
* Contains the current target being executed.
*/
protected Target currentTarget = null;
/**
* An Auditor instance that keeps track of all changes to properties
* identified by the user.
*/
protected Auditor auditor = null;
/**
* InputHandler instance that may be different than the configured one.
*/
protected InputHandler inputHandler;
/**
* {@link DebugCommandSet} instance that is a container for all
* {@link DebugSupport} commands that may be used with this listener.
*/
protected DebugCommandSet commandHandler = new DebugCommandSet();
// List of all break point facilities to be available
// ==================================================
/**
* Target break point property name
*/
public static final String DEBUG_TARGET_PROPERTY = "ant.debug.target";
/**
* Exception break point property name
*/
public static final String DEBUG_EXCEPTION_PROPERTY = "ant.debug.exception";
/**
* Break point when the value of a property changes or is attempted to be
* changed.
*/
public static final String DEBUG_PROPERTY_CHANGE_PROPERTY = "ant.debug.property";
/**
* Request to audit all attempted changes to a property
*/
public static final String AUDIT_PROPERTY_PROPERTY = "ant.audit.property";
// End of all available break points
// =================================
public void init(BuildEvent event) {
project = event.getProject();
project.log("Attaching DebuggerListener to the build.");
}
public void buildFinished(BuildEvent event) {
// Anything to do?
}
protected Map getDefaultCommandSupport() {
if (auditor instanceof DebugSupport) {
Map defaults = new HashMap();
defaults.put("trace", auditor);
defaults.put("add", this);
return defaults;
}
return null;
}
public void buildStarted(BuildEvent event) {
// set audit property helper that will help keep track of properties
// being set everywhere.
project = event.getProject();
PropertyHelper helper = new PropertyDebugHelper();
helper.setProject(project);
auditor = new DefaultAuditor();
((PropertyDebugHelper) helper).setAuditor(auditor);
// Is it better to set it as a project helper or as a delegate to the
// helper?
project.addReference(MagicNames.REFID_PROPERTY_HELPER, helper);
commandHandler.setProject(project);
commandHandler.init(getDefaultCommandSupport());
prompt = new DebugPrompt(project, commandHandler);
auditor.setPrompt(prompt);
// this is how the debugging starts
prompt.prompt("Type /? to get any help.");
}
public void messageLogged(BuildEvent event) {
// Do Nothing
}
public void targetFinished(BuildEvent event) {
currentTarget = null;
}
public void targetStarted(BuildEvent event) {
currentTarget = event.getTarget();
Target target = event.getTarget();
if (debugtargets.contains(target.getName())) {
prompt.prompt("Break Point at Target: " + target.getName());
}
}
public void taskFinished(BuildEvent event) {
}
public void taskStarted(BuildEvent event) {
}
/*
* The following section of code customizes this class to double up as a
* DebugSupport command instance so that it is possible to add
* target/property break points at runtime.
*/
/**
* The current listener as a {@link DebugSupport} command only supports add
* new breakpoints.
*/
public boolean commandSupported(String command) {
return "add".equals(command);
}
public void execute(Project project, String[] params) {
if (params.length < 3) {
printUsage(project);
return;
}
if (!"property".equals(params[1]) && !"target".equals(params[1])) {
printUsage(project);
return;
}
boolean isproperty = "property".equals(params[1]);
for (int i = 2; i < params.length; i++) {
if (isproperty) {
// add as a property to be audited
auditor.addPropertyForAudits(params[i], project);
project.log("Added BreakPoint at Property: " + params[2]);
} else {
debugtargets.add(params[i]);
project.log("Added BreakPoint at Target: " + params[2]);
}
}
}
public void printUsage(Project project) {
project
.log("Some Helpful Message to add debug/property break points at runtime.");
}
}