Sources for implementing PoC for debugger

git-svn-id: https://svn.apache.org/repos/asf/incubator/easyant/tasks/trunk@1132876 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/command-line-debugger/src/main/org/apache/tools/ant/DebugTask.java b/command-line-debugger/src/main/org/apache/tools/ant/DebugTask.java
new file mode 100644
index 0000000..6049b1b
--- /dev/null
+++ b/command-line-debugger/src/main/org/apache/tools/ant/DebugTask.java
@@ -0,0 +1,329 @@
+package org.apache.tools.ant;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.input.DefaultInputHandler;
+import org.apache.tools.ant.input.InputHandler;
+import org.apache.tools.ant.input.InputRequest;
+import org.apache.tools.ant.taskdefs.PathConvert;
+import org.apache.tools.ant.taskdefs.Property;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * A stand alone debug task that plugs into the build through projecthelper
+ * class by injecting a dependency at the end of a target. This is a POC and
+ * does not yet work for Extension-Points.
+ */
+public class DebugTask extends Task {
+	/**
+	 * Debugger prompt
+	 */
+	public static final String PROMPT = "DEBUGGER> ";
+
+	/**
+	 * Standard target name for the internal debugger
+	 */
+	public static final String DEBUG_TARGET_NAME = "-internal-debugger";
+
+	/*
+	 * A static final debug target that is injected as a dependency. We may need
+	 * to have more than one such target if we are to allow multiple
+	 * break-points in the build.
+	 */
+	private static final Target debugTarget = new Target();
+
+	/*
+	 * Set of all commands that can be interpreted at runtime.
+	 */
+	private static Set supportedCommands = new HashSet();
+
+	static {
+		// add any more commands to be supported here
+		// if need be, this can be considered to be
+		// moved to a separate properties file
+		supportedCommands.add("locate");
+		supportedCommands.add("inspect");
+		supportedCommands.add("return");
+	}
+
+	public void execute() throws BuildException {
+		// expect input here
+		InputRequest ir = new InputRequest(PROMPT);
+		InputHandler ih = new DefaultInputHandler();
+		String command = null;
+		getProject().log(
+				StringUtils.LINE_SEP
+						+ "-------- Ant Command Line Debugger --------"
+						+ StringUtils.LINE_SEP + StringUtils.LINE_SEP);
+
+		// keep accepting inputs, until the user enters the return command
+		do {
+			ih.handleInput(ir);
+			command = ir.getInput();
+			handleCommand(command);
+			getProject().log(""); // log a new line
+		} while (!"return".equals(command));
+
+		// resume build execution on this
+		getProject().log(
+				StringUtils.LINE_SEP
+						+ "--------- Resuming Ant Execution ----------"
+						+ StringUtils.LINE_SEP);
+	}
+
+	/**
+	 * Static method to create a runtime-debug target. For purposes of Command
+	 * Line Debugger (CLD), the target returned by this method, and identified
+	 * by DEBUG_TARGET_NAME must be added at the end of the dependency list of
+	 * the target where the break point exists.
+	 * 
+	 * @param project
+	 * @return
+	 */
+	public static Target createDebugTarget(Project project) {
+		// see what is the best value for the Location to assume?
+		// Location loc = new Location(??);
+
+		debugTarget.setProject(project);
+		debugTarget.setName(DEBUG_TARGET_NAME);
+		project.addTarget(debugTarget);
+		// create an instance of debug task and attach it to this project
+		Task debugtask = project.createTask("debug");
+		debugtask.setProject(project);
+		debugtask.setTaskName("Debugger");
+		debugTarget.addTask(debugtask);
+		return debugTarget;
+	}
+
+	/*
+	 * Interprets user input and decides if the command is supported or should
+	 * be rejected.
+	 */
+	protected void handleCommand(String command) {
+		if (command == null || command.trim().length() == 0) {
+			getProject().log("Invalid command. Use /? for more information.");
+		}
+		command = command.trim();
+		if (command.equals("/?")) {
+			printUsage();
+			return;
+		}
+
+		String[] tokens = command.split(" ");
+		if (!supportedCommands.contains(tokens[0])) {
+			printUsage();
+			return;
+		}
+
+		DebugSupport[] debuggers = new DebugSupport[] { new NoOp(),
+				new Inspector(), new Locator() };
+		DebugSupport selected = null;
+		for (int j = 0; j < debuggers.length; j++) {
+			if (debuggers[j].commandSupported(tokens[0]))
+				selected = debuggers[j];
+		}
+		selected.execute(getProject(), tokens);
+	}
+
+	protected void printUsage() {
+		// log all help stuff here
+		getProject()
+				.log(
+						"You may use one of the following commands: locate, inspect, return");
+		getProject()
+				.log(
+						"Type the command followed by /? for more information. Eg. inspect /?");
+	}
+
+	protected static List searchTask(Class expectedTaskClass, Project project) {
+		List result = new ArrayList();
+		for (Iterator iterator = project.getTargets().values().iterator(); iterator
+				.hasNext();) {
+			Target t = (Target) iterator.next();
+			for (int i = 0; i < t.getTasks().length; i++) {
+				Task task = t.getTasks()[i];
+				Class taskClass = ComponentHelper.getComponentHelper(project)
+						.getComponentClass(task.getTaskType());
+				// will need to see in what cases it could return a null type
+				// perhaps failing when the task is using a custom antlib
+				// defined task
+				if (taskClass != null && taskClass.equals(expectedTaskClass)) {
+					result.add(task);
+				}
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * An interface for supporting debug commands.
+	 */
+	public static interface DebugSupport {
+
+		/**
+		 * Check if this command is supported.
+		 * 
+		 * @param command
+		 * @return
+		 */
+		public boolean commandSupported(String command);
+
+		/**
+		 * Main execution body of the class. Pass all command parameters.
+		 * 
+		 * @param project
+		 * @param params
+		 */
+		public void execute(Project project, String[] params);
+
+		/**
+		 * Prints usage of the command.
+		 * 
+		 * @param project
+		 */
+		public void printUsage(Project project);
+
+	}
+
+	/**
+	 * Used to implement commands that should not be handled by
+	 * {@link DebugSupport} at all. Example, the 'return' command
+	 */
+	public static final class NoOp implements DebugSupport {
+
+		public boolean commandSupported(String command) {
+			return "return".equalsIgnoreCase(command);
+		}
+
+		public void execute(Project project, String[] params) {
+			// do nothing
+		}
+
+		public void printUsage(Project project) {
+		};
+	}
+
+	/**
+	 * Locates properties / paths in static build sources
+	 */
+	public static final class Locator implements DebugSupport {
+
+		public boolean commandSupported(String command) {
+			return "locate".equalsIgnoreCase(command);
+		}
+
+		public void execute(Project project, String[] params) {
+			// the command syntax is 'locate property some.property'
+			// or 'locate path some.path
+			if (params.length != 3 || "/?".equals(params[1])) {
+				printUsage(project);
+				return;
+			}
+
+			List matches = null;
+			String key = null;
+			if ("property".equalsIgnoreCase(params[1])) {
+				// locate and publish the property
+				matches = DebugTask.searchTask(Property.class, project);
+				key = "name";
+			} else if ("path".equalsIgnoreCase(params[1])) {
+				// locate and publish the path
+				matches = DebugTask.searchTask(Path.class, project);
+				key = "id";
+			} else {
+				// see if any other component may be supported
+				project.log("Unexpected component: " + params[1]);
+				project.log("Supported components are property, path.");
+				return;
+			}
+
+			// probably accept some kind of a query from end user and select the
+			// target object based on the query
+			for (Iterator iterator = matches.iterator(); iterator.hasNext();) {
+				Task task = (Task) iterator.next();
+				// display attributes
+				Map attributeMap = task.getWrapper().getAttributeMap();
+				if (!params[2].equals(attributeMap.get(key))) {
+					continue;
+				}
+				String value = (String) attributeMap.get("value");
+				project.log("Detected a property by name [" + params[2]
+						+ "]. Build file value: " + value);
+				// and their respected location
+				project.log("Located at: " + task.getLocation().toString());
+			}
+		}
+
+		public void printUsage(Project project) {
+			project.log("Incorrect Parameters");
+			project.log("Usage: locate property/path propertyname/pathname");
+		}
+	}
+
+	/**
+	 * Inspects the current value of a property, path or some reference.
+	 */
+	public static final class Inspector implements DebugSupport {
+
+		public boolean commandSupported(String command) {
+			return "inspect".equalsIgnoreCase(command);
+		}
+
+		public void execute(Project project, String[] params) {
+			if (params.length < 3 || "/?".equals(params[1])) {
+				printUsage(project);
+			}
+
+			if ("property".equalsIgnoreCase(params[1])) {
+				// show all matches for a property
+				Object value = PropertyHelper.getProperty(project, params[2]);
+				if (value != null) {
+					project.log("Detected a property by name [" + params[1]
+							+ "]. Current value: " + value);
+				} else {
+					project.log("Found no such property.");
+				}
+			} else if ("path".equalsIgnoreCase(params[1])) {
+				// look optional component
+				// the remaining part of the string could be:
+				// id=<someid> or refid=<somerefid>
+				Object ref = project.getReference(params[2]);
+				if (ref instanceof ResourceCollection) {
+					if (ref != null) {
+						PathConvert path = (PathConvert) project
+								.createTask("pathconvert");
+						path.setProject(project);
+						path.setPathSep(StringUtils.LINE_SEP + "    - ");
+						path.add((ResourceCollection) ref);
+						path.execute();
+					} else {
+						project.log("No path-reference found for " + params[2]);
+					}
+				} else {
+					project.log("No path found for reference id: " + params[2]);
+				}
+			}
+
+		}
+
+		public void printUsage(Project project) {
+			project.log("Incorrect Parameters");
+			project.log("Usage: inspect property some.property");
+			project.log("       inspect path path.id");
+		}
+	}
+}
diff --git a/command-line-debugger/src/main/org/apache/tools/ant/Main.java b/command-line-debugger/src/main/org/apache/tools/ant/Main.java
new file mode 100644
index 0000000..d85ddf9
--- /dev/null
+++ b/command-line-debugger/src/main/org/apache/tools/ant/Main.java
@@ -0,0 +1,1235 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.tools.ant.input.DefaultInputHandler;
+import org.apache.tools.ant.input.InputHandler;
+import org.apache.tools.ant.launch.AntMain;
+import org.apache.tools.ant.property.ResolvePropertyMap;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.ProxySetup;
+
+
+/**
+ * Command line entry point into Ant. This class is entered via the
+ * canonical `public static void main` entry point and reads the
+ * command line arguments. It then assembles and executes an Ant
+ * project.
+ * <p>
+ * If you integrating Ant into some other tool, this is not the class
+ * to use as an entry point. Please see the source code of this
+ * class to see how it manipulates the Ant project classes.
+ *
+ */
+public class Main implements AntMain {
+
+    /**
+     * A Set of args are are handled by the launcher and should
+     * not be seen by Main.
+     */
+    private static final Set LAUNCH_COMMANDS = new HashSet();
+    static {
+        LAUNCH_COMMANDS.add("-lib");
+        LAUNCH_COMMANDS.add("-cp");
+        LAUNCH_COMMANDS.add("-noclasspath");
+        LAUNCH_COMMANDS.add("--noclasspath");
+        LAUNCH_COMMANDS.add("-nouserlib");
+        LAUNCH_COMMANDS.add("-main");
+    }
+
+    /** The default build file name. {@value} */
+    public static final String DEFAULT_BUILD_FILENAME = "build.xml";
+
+    /** Our current message output status. Follows Project.MSG_XXX. */
+    private int msgOutputLevel = Project.MSG_INFO;
+
+    /** File that we are using for configuration. */
+    private File buildFile; /* null */
+
+    /** Stream to use for logging. */
+    private static PrintStream out = System.out;
+
+    /** Stream that we are using for logging error messages. */
+    private static PrintStream err = System.err;
+
+    /** The build targets. */
+    private Vector targets = new Vector();
+
+    /** Set of properties that can be used by tasks. */
+    private Properties definedProps = new Properties();
+
+    /** Names of classes to add as listeners to project. */
+    private Vector listeners = new Vector(1);
+
+    /** File names of property files to load on startup. */
+    private Vector propertyFiles = new Vector(1);
+
+    /** Indicates whether this build is to support interactive input */
+    private boolean allowInput = true;
+
+    /** keep going mode */
+    private boolean keepGoingMode = false;
+
+    /**
+     * The Ant logger class. There may be only one logger. It will have
+     * the right to use the 'out' PrintStream. The class must implements the
+     * BuildLogger interface.
+     */
+    private String loggerClassname = null;
+
+    /**
+     * The Ant InputHandler class.  There may be only one input
+     * handler.
+     */
+    private String inputHandlerClassname = null;
+
+    /**
+     * Whether or not output to the log is to be unadorned.
+     */
+    private boolean emacsMode = false;
+
+    /**
+     * Whether or not this instance has successfully been
+     * constructed and is ready to run.
+     */
+    private boolean readyToRun = false;
+
+    /**
+     * Whether or not we should only parse and display the project help
+     * information.
+     */
+    private boolean projectHelp = false;
+
+    /**
+     * Whether or not a logfile is being used. This is used to
+     * check if the output streams must be closed.
+     */
+    private static boolean isLogFileUsed = false;
+
+    /**
+     * optional thread priority
+     */
+    private Integer threadPriority = null;
+
+    /**
+     * proxy flag: default is false
+     */
+    private boolean proxy = false;
+
+    /**
+     * Target at which to break execution sequence
+     */
+    private String breakAt = null;
+    
+    /**
+     * Prints the message of the Throwable if it (the message) is not
+     * <code>null</code>.
+     *
+     * @param t Throwable to print the message of.
+     *          Must not be <code>null</code>.
+     */
+    private static void printMessage(Throwable t) {
+        String message = t.getMessage();
+        if (message != null) {
+            System.err.println(message);
+        }
+    }
+
+    /**
+     * Creates a new instance of this class using the
+     * arguments specified, gives it any extra user properties which have been
+     * specified, and then runs the build using the classloader provided.
+     *
+     * @param args Command line arguments. Must not be <code>null</code>.
+     * @param additionalUserProperties Any extra properties to use in this
+     *        build. May be <code>null</code>, which is the equivalent to
+     *        passing in an empty set of properties.
+     * @param coreLoader Classloader used for core classes. May be
+     *        <code>null</code> in which case the system classloader is used.
+     */
+    public static void start(String[] args, Properties additionalUserProperties,
+                             ClassLoader coreLoader) {
+        Main m = new Main();
+        m.startAnt(args, additionalUserProperties, coreLoader);
+    }
+
+    /**
+     * Start Ant
+     * @param args command line args
+     * @param additionalUserProperties properties to set beyond those that
+     *        may be specified on the args list
+     * @param coreLoader - not used
+     *
+     * @since Ant 1.6
+     */
+    public void startAnt(String[] args, Properties additionalUserProperties,
+                         ClassLoader coreLoader) {
+
+        try {
+            processArgs(args);
+        } catch (Throwable exc) {
+            handleLogfile();
+            printMessage(exc);
+            exit(1);
+            return;
+        }
+
+        if (additionalUserProperties != null) {
+            for (Enumeration e = additionalUserProperties.keys();
+                    e.hasMoreElements();) {
+                String key = (String) e.nextElement();
+                String property = additionalUserProperties.getProperty(key);
+                definedProps.put(key, property);
+            }
+        }
+
+        // expect the worst
+        int exitCode = 1;
+        try {
+            try {
+                runBuild(coreLoader);
+                exitCode = 0;
+            } catch (ExitStatusException ese) {
+                exitCode = ese.getStatus();
+                if (exitCode != 0) {
+                    throw ese;
+                }
+            }
+        } catch (BuildException be) {
+            if (err != System.err) {
+                printMessage(be);
+            }
+        } catch (Throwable exc) {
+            exc.printStackTrace();
+            printMessage(exc);
+        } finally {
+            handleLogfile();
+        }
+        exit(exitCode);
+    }
+
+    /**
+     * This operation is expected to call {@link System#exit(int)}, which
+     * is what the base version does.
+     * However, it is possible to do something else.
+     * @param exitCode code to exit with
+     */
+    protected void exit(int exitCode) {
+        System.exit(exitCode);
+    }
+
+    /**
+     * Close logfiles, if we have been writing to them.
+     *
+     * @since Ant 1.6
+     */
+    private static void handleLogfile() {
+        if (isLogFileUsed) {
+            FileUtils.close(out);
+            FileUtils.close(err);
+        }
+    }
+
+    /**
+     * Command line entry point. This method kicks off the building
+     * of a project object and executes a build using either a given
+     * target or the default target.
+     *
+     * @param args Command line arguments. Must not be <code>null</code>.
+     */
+    public static void main(String[] args) {
+        start(args, null, null);
+    }
+
+    /**
+     * Constructor used when creating Main for later arg processing
+     * and startup
+     */
+    public Main() {
+    }
+
+    /**
+     * Sole constructor, which parses and deals with command line
+     * arguments.
+     *
+     * @param args Command line arguments. Must not be <code>null</code>.
+     *
+     * @exception BuildException if the specified build file doesn't exist
+     *                           or is a directory.
+     *
+     * @deprecated since 1.6.x
+     */
+    protected Main(String[] args) throws BuildException {
+        processArgs(args);
+    }
+
+    /**
+     * Process command line arguments.
+     * When ant is started from Launcher, launcher-only arguments do not get
+     * passed through to this routine.
+     *
+     * @param args the command line arguments.
+     *
+     * @since Ant 1.6
+     */
+    private void processArgs(String[] args) {
+        String searchForThis = null;
+        boolean searchForFile = false;
+        PrintStream logTo = null;
+
+        // cycle through given args
+
+        boolean justPrintUsage = false;
+        boolean justPrintVersion = false;
+        boolean justPrintDiagnostics = false;
+
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+
+            if (arg.equals("-help") || arg.equals("-h")) {
+                justPrintUsage = true;
+            } else if (arg.equals("-version")) {
+                justPrintVersion = true;
+            } else if (arg.equals("-diagnostics")) {
+                justPrintDiagnostics = true;
+            } else if (arg.equals("-quiet") || arg.equals("-q")) {
+                msgOutputLevel = Project.MSG_WARN;
+            } else if (arg.equals("-verbose") || arg.equals("-v")) {
+                msgOutputLevel = Project.MSG_VERBOSE;
+            } else if (arg.equals("-debug") || arg.equals("-d")) {
+                msgOutputLevel = Project.MSG_DEBUG;
+            } else if (arg.equals("-noinput")) {
+                allowInput = false;
+            } else if (arg.equals("-logfile") || arg.equals("-l")) {
+                try {
+                    File logFile = new File(args[i + 1]);
+                    i++;
+                    logTo = new PrintStream(new FileOutputStream(logFile));
+                    isLogFileUsed = true;
+                } catch (IOException ioe) {
+                    String msg = "Cannot write on the specified log file. "
+                        + "Make sure the path exists and you have write "
+                        + "permissions.";
+                    throw new BuildException(msg);
+                } catch (ArrayIndexOutOfBoundsException aioobe) {
+                    String msg = "You must specify a log file when "
+                        + "using the -log argument";
+                    throw new BuildException(msg);
+                }
+            } else if (arg.equals("-buildfile") || arg.equals("-file")
+                       || arg.equals("-f")) {
+                i = handleArgBuildFile(args, i);
+            } else if (arg.equals("-listener")) {
+                i = handleArgListener(args, i);
+            } else if (arg.startsWith("-D")) {
+                i = handleArgDefine(args, i);
+            } else if (arg.equals("-logger")) {
+                i = handleArgLogger(args, i);
+            } else if (arg.equals("-inputhandler")) {
+                i = handleArgInputHandler(args, i);
+            } else if (arg.equals("-emacs") || arg.equals("-e")) {
+                emacsMode = true;
+            } else if (arg.equals("-projecthelp") || arg.equals("-p")) {
+                // set the flag to display the targets and quit
+                projectHelp = true;
+            } else if (arg.equals("-find") || arg.equals("-s")) {
+                searchForFile = true;
+                // eat up next arg if present, default to build.xml
+                if (i < args.length - 1) {
+                    searchForThis = args[++i];
+                }
+            } else if (arg.startsWith("-propertyfile")) {
+                i = handleArgPropertyFile(args, i);
+            } else if (arg.equals("-k") || arg.equals("-keep-going")) {
+                keepGoingMode = true;
+            } else if (arg.equals("-nice")) {
+                i = handleArgNice(args, i);
+            } else if (LAUNCH_COMMANDS.contains(arg)) {
+                //catch script/ant mismatch with a meaningful message
+                //we could ignore it, but there are likely to be other
+                //version problems, so we stamp down on the configuration now
+                String msg = "Ant's Main method is being handed "
+                        + "an option " + arg + " that is only for the launcher class."
+                        + "\nThis can be caused by a version mismatch between "
+                        + "the ant script/.bat file and Ant itself.";
+                throw new BuildException(msg);
+            } else if (arg.equals("-autoproxy")) {
+                proxy = true;
+            } else if (arg.equals("-breakAt")) {
+            	breakAt = args[++i];
+            } else if (arg.startsWith("-")) {
+                // we don't have any more args to recognize!
+                String msg = "Unknown argument: " + arg;
+                System.err.println(msg);
+                printUsage();
+                throw new BuildException("");
+            } else {
+                // if it's no other arg, it may be the target
+                targets.addElement(arg);
+            }
+        }
+
+        if (msgOutputLevel >= Project.MSG_VERBOSE || justPrintVersion) {
+            printVersion(msgOutputLevel);
+        }
+
+        if (justPrintUsage || justPrintVersion || justPrintDiagnostics) {
+            if (justPrintUsage) {
+                printUsage();
+            }
+            if (justPrintDiagnostics) {
+                Diagnostics.doReport(System.out, msgOutputLevel);
+            }
+            return;
+        }
+
+        // if buildFile was not specified on the command line,
+        if (buildFile == null) {
+            // but -find then search for it
+            if (searchForFile) {
+                if (searchForThis != null) {
+                    buildFile = findBuildFile(System.getProperty("user.dir"), searchForThis);
+                    if (buildFile == null) {
+                        throw new BuildException("Could not locate a build file!");
+                    }
+                } else {
+                    // no search file specified: so search an existing default file
+                    Iterator it = ProjectHelperRepository.getInstance().getHelpers();
+                    do {
+                        ProjectHelper helper = (ProjectHelper) it.next();
+                        searchForThis = helper.getDefaultBuildFile();
+                        if (msgOutputLevel >= Project.MSG_VERBOSE) {
+                            System.out.println("Searching the default build file: " + searchForThis);
+                        }
+                        buildFile = findBuildFile(System.getProperty("user.dir"), searchForThis);
+                    } while (buildFile == null && it.hasNext());
+                    if (buildFile == null) {
+                        throw new BuildException("Could not locate a build file!");
+                    }
+                }
+            } else {
+                // no build file specified: so search an existing default file
+                Iterator it = ProjectHelperRepository.getInstance().getHelpers();
+                do {
+                    ProjectHelper helper = (ProjectHelper) it.next();
+                    buildFile = new File(helper.getDefaultBuildFile());
+                    if (msgOutputLevel >= Project.MSG_VERBOSE) {
+                        System.out.println("Trying the default build file: " + buildFile);
+                    }
+                } while (!buildFile.exists() && it.hasNext());
+            }
+        }
+
+        // make sure buildfile exists
+        if (!buildFile.exists()) {
+            System.out.println("Buildfile: " + buildFile + " does not exist!");
+            throw new BuildException("Build failed");
+        }
+
+        // make sure it's not a directory (this falls into the ultra
+        // paranoid lets check everything category
+
+        if (buildFile.isDirectory()) {
+            System.out.println("What? Buildfile: " + buildFile + " is a dir!");
+            throw new BuildException("Build failed");
+        }
+
+        // Normalize buildFile for re-import detection
+        buildFile =
+            FileUtils.getFileUtils().normalize(buildFile.getAbsolutePath());
+
+        // Load the property files specified by -propertyfile
+        loadPropertyFiles();
+
+        if (msgOutputLevel >= Project.MSG_INFO) {
+            System.out.println("Buildfile: " + buildFile);
+        }
+
+        if (logTo != null) {
+            out = logTo;
+            err = logTo;
+            System.setOut(out);
+            System.setErr(err);
+        }
+        readyToRun = true;
+    }
+
+    // --------------------------------------------------------
+    //    Methods for handling the command line arguments
+    // --------------------------------------------------------
+
+    /** Handle the -buildfile, -file, -f argument */
+    private int handleArgBuildFile(String[] args, int pos) {
+        try {
+            buildFile = new File(
+                args[++pos].replace('/', File.separatorChar));
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            throw new BuildException(
+                "You must specify a buildfile when using the -buildfile argument");
+        }
+        return pos;
+    }
+
+    /** Handle -listener argument */
+    private int handleArgListener(String[] args, int pos) {
+        try {
+            listeners.addElement(args[pos + 1]);
+            pos++;
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            String msg = "You must specify a classname when "
+                + "using the -listener argument";
+            throw new BuildException(msg);
+        }
+        return pos;
+    }
+
+    /** Handler -D argument */
+    private int handleArgDefine(String[] args, int argPos) {
+        /* Interestingly enough, we get to here when a user
+         * uses -Dname=value. However, in some cases, the OS
+         * goes ahead and parses this out to args
+         *   {"-Dname", "value"}
+         * so instead of parsing on "=", we just make the "-D"
+         * characters go away and skip one argument forward.
+         *
+         * I don't know how to predict when the JDK is going
+         * to help or not, so we simply look for the equals sign.
+         */
+        String arg = args[argPos];
+        String name = arg.substring(2, arg.length());
+        String value = null;
+        int posEq = name.indexOf("=");
+        if (posEq > 0) {
+            value = name.substring(posEq + 1);
+            name = name.substring(0, posEq);
+        } else if (argPos < args.length - 1) {
+            value = args[++argPos];
+        } else {
+            throw new BuildException("Missing value for property "
+                                     + name);
+        }
+        definedProps.put(name, value);
+        return argPos;
+    }
+
+    /** Handle the -logger argument. */
+    private int handleArgLogger(String[] args, int pos) {
+        if (loggerClassname != null) {
+            throw new BuildException(
+                "Only one logger class may be specified.");
+        }
+        try {
+            loggerClassname = args[++pos];
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            throw new BuildException(
+                "You must specify a classname when using the -logger argument");
+        }
+        return pos;
+    }
+
+    /** Handle the -inputhandler argument. */
+    private int handleArgInputHandler(String[] args, int pos) {
+        if (inputHandlerClassname != null) {
+            throw new BuildException("Only one input handler class may "
+                                     + "be specified.");
+        }
+        try {
+            inputHandlerClassname = args[++pos];
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            throw new BuildException("You must specify a classname when"
+                                     + " using the -inputhandler"
+                                     + " argument");
+        }
+        return pos;
+    }
+
+    /** Handle the -propertyfile argument. */
+    private int handleArgPropertyFile(String[] args, int pos) {
+        try {
+            propertyFiles.addElement(args[++pos]);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            String msg = "You must specify a property filename when "
+                + "using the -propertyfile argument";
+            throw new BuildException(msg);
+        }
+        return pos;
+    }
+
+    /** Handle the -nice argument. */
+    private int handleArgNice(String[] args, int pos) {
+        try {
+            threadPriority = Integer.decode(args[++pos]);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            throw new BuildException(
+                "You must supply a niceness value (1-10)"
+                + " after the -nice option");
+        } catch (NumberFormatException e) {
+            throw new BuildException("Unrecognized niceness value: "
+                                     + args[pos]);
+        }
+
+        if (threadPriority.intValue() < Thread.MIN_PRIORITY
+            || threadPriority.intValue() > Thread.MAX_PRIORITY) {
+            throw new BuildException(
+                "Niceness value is out of the range 1-10");
+        }
+        return pos;
+    }
+
+    // --------------------------------------------------------
+    //    other methods
+    // --------------------------------------------------------
+
+    /** Load the property files specified by -propertyfile */
+    private void loadPropertyFiles() {
+        for (int propertyFileIndex = 0;
+             propertyFileIndex < propertyFiles.size();
+             propertyFileIndex++) {
+            String filename
+                = (String) propertyFiles.elementAt(propertyFileIndex);
+            Properties props = new Properties();
+            FileInputStream fis = null;
+            try {
+                fis = new FileInputStream(filename);
+                props.load(fis);
+            } catch (IOException e) {
+                System.out.println("Could not load property file "
+                                   + filename + ": " + e.getMessage());
+            } finally {
+                FileUtils.close(fis);
+            }
+
+            // ensure that -D properties take precedence
+            Enumeration propertyNames = props.propertyNames();
+            while (propertyNames.hasMoreElements()) {
+                String name = (String) propertyNames.nextElement();
+                if (definedProps.getProperty(name) == null) {
+                    definedProps.put(name, props.getProperty(name));
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper to get the parent file for a given file.
+     * <p>
+     * Added to simulate File.getParentFile() from JDK 1.2.
+     * @deprecated since 1.6.x
+     *
+     * @param file   File to find parent of. Must not be <code>null</code>.
+     * @return       Parent file or null if none
+     */
+    private File getParentFile(File file) {
+        File parent = file.getParentFile();
+
+        if (parent != null && msgOutputLevel >= Project.MSG_VERBOSE) {
+            System.out.println("Searching in " + parent.getAbsolutePath());
+        }
+
+        return parent;
+    }
+
+    /**
+     * Search parent directories for the build file.
+     * <p>
+     * Takes the given target as a suffix to append to each
+     * parent directory in search of a build file.  Once the
+     * root of the file-system has been reached <code>null</code>
+     * is returned.
+     *
+     * @param start  Leaf directory of search.
+     *               Must not be <code>null</code>.
+     * @param suffix  Suffix filename to look for in parents.
+     *                Must not be <code>null</code>.
+     *
+     * @return A handle to the build file if one is found, <code>null</code> if not
+     */
+    private File findBuildFile(String start, String suffix) {
+        if (msgOutputLevel >= Project.MSG_INFO) {
+            System.out.println("Searching for " + suffix + " ...");
+        }
+
+        File parent = new File(new File(start).getAbsolutePath());
+        File file = new File(parent, suffix);
+
+        // check if the target file exists in the current directory
+        while (!file.exists()) {
+            // change to parent directory
+            parent = getParentFile(parent);
+
+            // if parent is null, then we are at the root of the fs,
+            // complain that we can't find the build file.
+            if (parent == null) {
+                return null;
+            }
+
+            // refresh our file handle
+            file = new File(parent, suffix);
+        }
+
+        return file;
+    }
+
+    /**
+     * Executes the build. If the constructor for this instance failed
+     * (e.g. returned after issuing a warning), this method returns
+     * immediately.
+     *
+     * @param coreLoader The classloader to use to find core classes.
+     *                   May be <code>null</code>, in which case the
+     *                   system classloader is used.
+     *
+     * @exception BuildException if the build fails
+     */
+    private void runBuild(ClassLoader coreLoader) throws BuildException {
+
+        if (!readyToRun) {
+            return;
+        }
+
+        final Project project = new Project();
+        project.setCoreLoader(coreLoader);
+
+        Throwable error = null;
+
+        try {
+            addBuildListeners(project);
+            addInputHandler(project);
+
+            PrintStream savedErr = System.err;
+            PrintStream savedOut = System.out;
+            InputStream savedIn = System.in;
+
+            // use a system manager that prevents from System.exit()
+            SecurityManager oldsm = null;
+            oldsm = System.getSecurityManager();
+
+                //SecurityManager can not be installed here for backwards
+                //compatibility reasons (PD). Needs to be loaded prior to
+                //ant class if we are going to implement it.
+                //System.setSecurityManager(new NoExitSecurityManager());
+            try {
+                if (allowInput) {
+                    project.setDefaultInputStream(System.in);
+                }
+                System.setIn(new DemuxInputStream(project));
+                System.setOut(new PrintStream(new DemuxOutputStream(project, false)));
+                System.setErr(new PrintStream(new DemuxOutputStream(project, true)));
+
+
+                if (!projectHelp) {
+                    project.fireBuildStarted();
+                }
+
+                // set the thread priorities
+                if (threadPriority != null) {
+                    try {
+                        project.log("Setting Ant's thread priority to "
+                                + threadPriority, Project.MSG_VERBOSE);
+                        Thread.currentThread().setPriority(threadPriority.intValue());
+                    } catch (SecurityException swallowed) {
+                        //we cannot set the priority here.
+                        project.log("A security manager refused to set the -nice value");
+                    }
+                }
+
+
+
+                project.init();
+                project.setBreakAt(breakAt);
+                // resolve properties
+                PropertyHelper propertyHelper
+                    = (PropertyHelper) PropertyHelper.getPropertyHelper(project);
+                HashMap props = new HashMap(definedProps);
+                new ResolvePropertyMap(project, propertyHelper,
+                                       propertyHelper.getExpanders())
+                    .resolveAllProperties(props, null, false);
+
+                // set user-define properties
+                for (Iterator e = props.entrySet().iterator(); e.hasNext(); ) {
+                    Map.Entry ent = (Map.Entry) e.next();
+                    String arg = (String) ent.getKey();
+                    Object value = ent.getValue();
+                    project.setUserProperty(arg, String.valueOf(value));
+                }
+
+                project.setUserProperty(MagicNames.ANT_FILE,
+                                        buildFile.getAbsolutePath());
+                project.setUserProperty(MagicNames.ANT_FILE_TYPE,
+                                        MagicNames.ANT_FILE_TYPE_FILE);
+
+                project.setKeepGoingMode(keepGoingMode);
+                if (proxy) {
+                    //proxy setup if enabled
+                    ProxySetup proxySetup = new ProxySetup(project);
+                    proxySetup.enableProxies();
+                }
+
+                ProjectHelper.configureProject(project, buildFile);
+
+                if (projectHelp) {
+                    printDescription(project);
+                    printTargets(project, msgOutputLevel > Project.MSG_INFO,
+                            msgOutputLevel > Project.MSG_VERBOSE);
+                    return;
+                }
+
+                // make sure that we have a target to execute
+                if (targets.size() == 0) {
+                    if (project.getDefaultTarget() != null) {
+                        targets.addElement(project.getDefaultTarget());
+                    }
+                }
+
+                project.executeTargets(targets);
+            } finally {
+                // put back the original security manager
+                //The following will never eval to true. (PD)
+                if (oldsm != null) {
+                    System.setSecurityManager(oldsm);
+                }
+
+                System.setOut(savedOut);
+                System.setErr(savedErr);
+                System.setIn(savedIn);
+            }
+        } catch (RuntimeException exc) {
+            error = exc;
+            throw exc;
+        } catch (Error e) {
+            error = e;
+            throw e;
+        } finally {
+            if (!projectHelp) {
+                try {
+                    project.fireBuildFinished(error);
+                } catch (Throwable t) {
+                    // yes, I know it is bad style to catch Throwable,
+                    // but if we don't, we lose valuable information
+                    System.err.println("Caught an exception while logging the"
+                                       + " end of the build.  Exception was:");
+                    t.printStackTrace();
+                    if (error != null) {
+                        System.err.println("There has been an error prior to"
+                                           + " that:");
+                        error.printStackTrace();
+                    }
+                    throw new BuildException(t);
+                }
+            } else if (error != null) {
+                project.log(error.toString(), Project.MSG_ERR);
+            }
+        }
+    }
+
+    /**
+     * Adds the listeners specified in the command line arguments,
+     * along with the default listener, to the specified project.
+     *
+     * @param project The project to add listeners to.
+     *                Must not be <code>null</code>.
+     */
+    protected void addBuildListeners(Project project) {
+
+        // Add the default listener
+        project.addBuildListener(createLogger());
+
+        final int count = listeners.size();
+        for (int i = 0; i < count; i++) {
+            String className = (String) listeners.elementAt(i);
+            BuildListener listener =
+                    (BuildListener) ClasspathUtils.newInstance(className,
+                            Main.class.getClassLoader(), BuildListener.class);
+            project.setProjectReference(listener);
+
+            project.addBuildListener(listener);
+        }
+    }
+
+    /**
+     * Creates the InputHandler and adds it to the project.
+     *
+     * @param project the project instance.
+     *
+     * @exception BuildException if a specified InputHandler
+     *                           implementation could not be loaded.
+     */
+    private void addInputHandler(Project project) throws BuildException {
+        InputHandler handler = null;
+        if (inputHandlerClassname == null) {
+            handler = new DefaultInputHandler();
+        } else {
+            handler = (InputHandler) ClasspathUtils.newInstance(
+                    inputHandlerClassname, Main.class.getClassLoader(),
+                    InputHandler.class);
+            project.setProjectReference(handler);
+        }
+        project.setInputHandler(handler);
+    }
+
+    // XXX: (Jon Skeet) Any reason for writing a message and then using a bare
+    // RuntimeException rather than just using a BuildException here? Is it
+    // in case the message could end up being written to no loggers (as the
+    // loggers could have failed to be created due to this failure)?
+    /**
+     * Creates the default build logger for sending build events to the ant
+     * log.
+     *
+     * @return the logger instance for this build.
+     */
+    private BuildLogger createLogger() {
+        BuildLogger logger = null;
+        if (loggerClassname != null) {
+            try {
+                logger = (BuildLogger) ClasspathUtils.newInstance(
+                        loggerClassname, Main.class.getClassLoader(),
+                        BuildLogger.class);
+            } catch (BuildException e) {
+                System.err.println("The specified logger class "
+                    + loggerClassname
+                    + " could not be used because " + e.getMessage());
+                throw new RuntimeException();
+            }
+        } else {
+            logger = new DefaultLogger();
+        }
+
+        logger.setMessageOutputLevel(msgOutputLevel);
+        logger.setOutputPrintStream(out);
+        logger.setErrorPrintStream(err);
+        logger.setEmacsMode(emacsMode);
+
+        return logger;
+    }
+
+    /**
+     * Prints the usage information for this class to <code>System.out</code>.
+     */
+    private static void printUsage() {
+        String lSep = System.getProperty("line.separator");
+        StringBuffer msg = new StringBuffer();
+        msg.append("ant [options] [target [target2 [target3] ...]]" + lSep);
+        msg.append("Options: " + lSep);
+        msg.append("  -help, -h              print this message" + lSep);
+        msg.append("  -projecthelp, -p       print project help information" + lSep);
+        msg.append("  -version               print the version information and exit" + lSep);
+        msg.append("  -diagnostics           print information that might be helpful to" + lSep);
+        msg.append("                         diagnose or report problems." + lSep);
+        msg.append("  -quiet, -q             be extra quiet" + lSep);
+        msg.append("  -verbose, -v           be extra verbose" + lSep);
+        msg.append("  -debug, -d             print debugging information" + lSep);
+        msg.append("  -emacs, -e             produce logging information without adornments"
+                   + lSep);
+        msg.append("  -lib <path>            specifies a path to search for jars and classes"
+                   + lSep);
+        msg.append("  -logfile <file>        use given file for log" + lSep);
+        msg.append("    -l     <file>                ''" + lSep);
+        msg.append("  -logger <classname>    the class which is to perform logging" + lSep);
+        msg.append("  -listener <classname>  add an instance of class as a project listener"
+                   + lSep);
+        msg.append("  -noinput               do not allow interactive input" + lSep);
+        msg.append("  -buildfile <file>      use given buildfile" + lSep);
+        msg.append("    -file    <file>              ''" + lSep);
+        msg.append("    -f       <file>              ''" + lSep);
+        msg.append("  -D<property>=<value>   use value for given property" + lSep);
+        msg.append("  -keep-going, -k        execute all targets that do not depend" + lSep);
+        msg.append("                         on failed target(s)" + lSep);
+        msg.append("  -propertyfile <name>   load all properties from file with -D" + lSep);
+        msg.append("                         properties taking precedence" + lSep);
+        msg.append("  -inputhandler <class>  the class which will handle input requests" + lSep);
+        msg.append("  -find <file>           (s)earch for buildfile towards the root of" + lSep);
+        msg.append("    -s  <file>           the filesystem and use it" + lSep);
+        msg.append("  -nice  number          A niceness value for the main thread:" + lSep
+                   + "                         1 (lowest) to 10 (highest); 5 is the default"
+                   + lSep);
+        msg.append("  -nouserlib             Run ant without using the jar files from" + lSep
+                   + "                         ${user.home}/.ant/lib" + lSep);
+        msg.append("  -noclasspath           Run ant without using CLASSPATH" + lSep);
+        msg.append("  -autoproxy             Java1.5+: use the OS proxy settings"
+                + lSep);
+        msg.append("  -main <class>          override Ant's normal entry point");
+        System.out.println(msg.toString());
+    }
+
+    /**
+     * Prints the Ant version information to <code>System.out</code>.
+     *
+     * @exception BuildException if the version information is unavailable
+     */
+    private static void printVersion(int logLevel) throws BuildException {
+        System.out.println(getAntVersion());
+    }
+
+    /**
+     * Cache of the Ant version information when it has been loaded.
+     */
+    private static String antVersion = null;
+
+    /**
+     * Returns the Ant version information, if available. Once the information
+     * has been loaded once, it's cached and returned from the cache on future
+     * calls.
+     *
+     * @return the Ant version information as a String
+     *         (always non-<code>null</code>)
+     *
+     * @exception BuildException if the version information is unavailable
+     */
+    public static synchronized String getAntVersion() throws BuildException {
+        if (antVersion == null) {
+            try {
+                Properties props = new Properties();
+                InputStream in =
+                    Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt");
+                props.load(in);
+                in.close();
+
+                StringBuffer msg = new StringBuffer();
+                msg.append("Apache Ant(TM) version ");
+                msg.append(props.getProperty("VERSION"));
+                msg.append(" compiled on ");
+                msg.append(props.getProperty("DATE"));
+                antVersion = msg.toString();
+            } catch (IOException ioe) {
+                throw new BuildException("Could not load the version information:"
+                                         + ioe.getMessage());
+            } catch (NullPointerException npe) {
+                throw new BuildException("Could not load the version information.");
+            }
+        }
+        return antVersion;
+    }
+
+     /**
+      * Prints the description of a project (if there is one) to
+      * <code>System.out</code>.
+      *
+      * @param project The project to display a description of.
+      *                Must not be <code>null</code>.
+      */
+    private static void printDescription(Project project) {
+       if (project.getDescription() != null) {
+          project.log(project.getDescription());
+       }
+    }
+
+    /**
+     * Targets in imported files with a project name
+     * and not overloaded by the main build file will
+     * be in the target map twice. This method
+     * removes the duplicate target.
+     * @param targets the targets to filter.
+     * @return the filtered targets.
+     */
+    private static Map removeDuplicateTargets(Map targets) {
+        Map locationMap = new HashMap();
+        for (Iterator i = targets.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            String name = (String) entry.getKey();
+            Target target = (Target) entry.getValue();
+            Target otherTarget =
+                (Target) locationMap.get(target.getLocation());
+            // Place this entry in the location map if
+            //  a) location is not in the map
+            //  b) location is in map, but it's name is longer
+            //     (an imported target will have a name. prefix)
+            if (otherTarget == null
+                || otherTarget.getName().length() > name.length()) {
+                locationMap.put(
+                    target.getLocation(), target); // Smallest name wins
+            }
+        }
+        Map ret = new HashMap();
+        for (Iterator i = locationMap.values().iterator(); i.hasNext();) {
+            Target target = (Target) i.next();
+            ret.put(target.getName(), target);
+        }
+        return ret;
+    }
+
+    /**
+     * Prints a list of all targets in the specified project to
+     * <code>System.out</code>, optionally including subtargets.
+     *
+     * @param project The project to display a description of.
+     *                Must not be <code>null</code>.
+     * @param printSubTargets Whether or not subtarget names should also be
+     *                        printed.
+     */
+    private static void printTargets(Project project, boolean printSubTargets,
+            boolean printDependencies) {
+        // find the target with the longest name
+        int maxLength = 0;
+        Map ptargets = removeDuplicateTargets(project.getTargets());
+        String targetName;
+        String targetDescription;
+        Target currentTarget;
+        // split the targets in top-level and sub-targets depending
+        // on the presence of a description
+        Vector topNames = new Vector();
+        Vector topDescriptions = new Vector();
+        Vector/*<Enumeration<String>>*/ topDependencies = new Vector();
+        Vector subNames = new Vector();
+        Vector/*<Enumeration<String>>*/ subDependencies = new Vector();
+
+        for (Iterator i = ptargets.values().iterator(); i.hasNext();) {
+            currentTarget = (Target) i.next();
+            targetName = currentTarget.getName();
+            if (targetName.equals("")) {
+                continue;
+            }
+            targetDescription = currentTarget.getDescription();
+            // maintain a sorted list of targets
+            if (targetDescription == null) {
+                int pos = findTargetPosition(subNames, targetName);
+                subNames.insertElementAt(targetName, pos);
+                if (printDependencies) {
+                    subDependencies.insertElementAt(currentTarget.getDependencies(), pos);
+                }
+            } else {
+                int pos = findTargetPosition(topNames, targetName);
+                topNames.insertElementAt(targetName, pos);
+                topDescriptions.insertElementAt(targetDescription, pos);
+                if (targetName.length() > maxLength) {
+                    maxLength = targetName.length();
+                }
+                if (printDependencies) {
+                    topDependencies.insertElementAt(currentTarget.getDependencies(), pos);
+                }
+            }
+        }
+
+        printTargets(project, topNames, topDescriptions, topDependencies,
+                "Main targets:", maxLength);
+        //if there were no main targets, we list all subtargets
+        //as it means nothing has a description
+        if (topNames.size() == 0) {
+            printSubTargets = true;
+        }
+        if (printSubTargets) {
+            printTargets(project, subNames, null, subDependencies, "Other targets:", 0);
+        }
+
+        String defaultTarget = project.getDefaultTarget();
+        if (defaultTarget != null && !"".equals(defaultTarget)) {
+            // shouldn't need to check but...
+            project.log("Default target: " + defaultTarget);
+        }
+    }
+
+    /**
+     * Searches for the correct place to insert a name into a list so as
+     * to keep the list sorted alphabetically.
+     *
+     * @param names The current list of names. Must not be <code>null</code>.
+     * @param name  The name to find a place for.
+     *              Must not be <code>null</code>.
+     *
+     * @return the correct place in the list for the given name
+     */
+    private static int findTargetPosition(Vector names, String name) {
+        final int size = names.size();
+        int res = size;
+        for (int i = 0; i < size && res == size; i++) {
+            if (name.compareTo((String) names.elementAt(i)) < 0) {
+                res = i;
+            }
+        }
+        return res;
+    }
+
+    /**
+     * Writes a formatted list of target names to <code>System.out</code>
+     * with an optional description.
+     *
+     *
+     * @param project the project instance.
+     * @param names The names to be printed.
+     *              Must not be <code>null</code>.
+     * @param descriptions The associated target descriptions.
+     *                     May be <code>null</code>, in which case
+     *                     no descriptions are displayed.
+     *                     If non-<code>null</code>, this should have
+     *                     as many elements as <code>names</code>.
+     * @param topDependencies The list of dependencies for each target.
+     *                        The dependencies are listed as a non null
+     *                        enumeration of String.
+     * @param heading The heading to display.
+     *                Should not be <code>null</code>.
+     * @param maxlen The maximum length of the names of the targets.
+     *               If descriptions are given, they are padded to this
+     *               position so they line up (so long as the names really
+     *               <i>are</i> shorter than this).
+     */
+    private static void printTargets(Project project, Vector names,
+                                     Vector descriptions, Vector dependencies,
+                                     String heading,
+                                     int maxlen) {
+        // now, start printing the targets and their descriptions
+        String lSep = System.getProperty("line.separator");
+        // got a bit annoyed that I couldn't find a pad function
+        String spaces = "    ";
+        while (spaces.length() <= maxlen) {
+            spaces += spaces;
+        }
+        StringBuffer msg = new StringBuffer();
+        msg.append(heading + lSep + lSep);
+        final int size = names.size();
+        for (int i = 0; i < size; i++) {
+            msg.append(" ");
+            msg.append(names.elementAt(i));
+            if (descriptions != null) {
+                msg.append(
+                    spaces.substring(0, maxlen - ((String) names.elementAt(i)).length() + 2));
+                msg.append(descriptions.elementAt(i));
+            }
+            msg.append(lSep);
+            if (!dependencies.isEmpty()) {
+                Enumeration deps = (Enumeration) dependencies.elementAt(i);
+                if (deps.hasMoreElements()) {
+                    msg.append("   depends on: ");
+                    while (deps.hasMoreElements()) {
+                        msg.append(deps.nextElement());
+                        if (deps.hasMoreElements()) {
+                            msg.append(", ");
+                        }
+                    }
+                    msg.append(lSep);                
+                }
+            }
+        }
+        project.log(msg.toString(), Project.MSG_WARN);
+    }
+}
diff --git a/command-line-debugger/src/main/org/apache/tools/ant/Project.java b/command-line-debugger/src/main/org/apache/tools/ant/Project.java
new file mode 100644
index 0000000..5a0a0a9
--- /dev/null
+++ b/command-line-debugger/src/main/org/apache/tools/ant/Project.java
@@ -0,0 +1,2637 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.WeakHashMap;
+
+import org.apache.tools.ant.helper.DefaultExecutor;
+import org.apache.tools.ant.input.DefaultInputHandler;
+import org.apache.tools.ant.input.InputHandler;
+import org.apache.tools.ant.types.Description;
+import org.apache.tools.ant.types.FilterSet;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceFactory;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.CollectionUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.VectorSet;
+
+/**
+ * Central representation of an Ant project. This class defines an Ant project
+ * with all of its targets, tasks and various other properties. It also provides
+ * the mechanism to kick off a build using a particular target name.
+ * <p>
+ * This class also encapsulates methods which allow files to be referred to
+ * using abstract path names which are translated to native system file paths at
+ * runtime.
+ * 
+ */
+public class Project implements ResourceFactory {
+	/** Message priority of &quot;error&quot;. */
+	public static final int MSG_ERR = 0;
+	/** Message priority of &quot;warning&quot;. */
+	public static final int MSG_WARN = 1;
+	/** Message priority of &quot;information&quot;. */
+	public static final int MSG_INFO = 2;
+	/** Message priority of &quot;verbose&quot;. */
+	public static final int MSG_VERBOSE = 3;
+	/** Message priority of &quot;debug&quot;. */
+	public static final int MSG_DEBUG = 4;
+
+	/**
+	 * Constant for the &quot;visiting&quot; state, used when traversing a DFS
+	 * of target dependencies.
+	 */
+	private static final String VISITING = "VISITING";
+	/**
+	 * Constant for the &quot;visited&quot; state, used when traversing a DFS of
+	 * target dependencies.
+	 */
+	private static final String VISITED = "VISITED";
+
+	/**
+	 * Version constant for Java 1.0 .
+	 * 
+	 * @deprecated since 1.5.x. Use {@link JavaEnvUtils#JAVA_1_0} instead.
+	 */
+	public static final String JAVA_1_0 = JavaEnvUtils.JAVA_1_0;
+	/**
+	 * Version constant for Java 1.1 .
+	 * 
+	 * @deprecated since 1.5.x. Use {@link JavaEnvUtils#JAVA_1_1} instead.
+	 */
+	public static final String JAVA_1_1 = JavaEnvUtils.JAVA_1_1;
+	/**
+	 * Version constant for Java 1.2 .
+	 * 
+	 * @deprecated since 1.5.x. Use {@link JavaEnvUtils#JAVA_1_2} instead.
+	 */
+	public static final String JAVA_1_2 = JavaEnvUtils.JAVA_1_2;
+	/**
+	 * Version constant for Java 1.3 .
+	 * 
+	 * @deprecated since 1.5.x. Use {@link JavaEnvUtils#JAVA_1_3} instead.
+	 */
+	public static final String JAVA_1_3 = JavaEnvUtils.JAVA_1_3;
+	/**
+	 * Version constant for Java 1.4 .
+	 * 
+	 * @deprecated since 1.5.x. Use {@link JavaEnvUtils#JAVA_1_4} instead.
+	 */
+	public static final String JAVA_1_4 = JavaEnvUtils.JAVA_1_4;
+
+	/** Default filter start token. */
+	public static final String TOKEN_START = FilterSet.DEFAULT_TOKEN_START;
+	/** Default filter end token. */
+	public static final String TOKEN_END = FilterSet.DEFAULT_TOKEN_END;
+
+	/** Instance of a utility class to use for file operations. */
+	private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+	/** Name of this project. */
+	private String name;
+	/** Description for this project (if any). */
+	private String description;
+
+	/** Map of references within the project (paths etc) (String to Object). */
+	private Hashtable references = new AntRefTable();
+
+	/** Map of id references - used for indicating broken build files */
+	private HashMap idReferences = new HashMap();
+
+	/** the parent project for old id resolution (if inheritreferences is set) */
+	private Project parentIdProject = null;
+
+	/** Name of the project's default target. */
+	private String defaultTarget;
+
+	/** Map from target names to targets (String to Target). */
+	private Hashtable targets = new Hashtable();
+	/** Set of global filters. */
+	private FilterSet globalFilterSet = new FilterSet();
+	{
+		// Initialize the globalFileSet's project
+		globalFilterSet.setProject(this);
+	}
+
+	/**
+	 * Wrapper around globalFilterSet. This collection only ever contains one
+	 * FilterSet, but the wrapper is needed in order to make it easier to use
+	 * the FileUtils interface.
+	 */
+	private FilterSetCollection globalFilters = new FilterSetCollection(
+			globalFilterSet);
+
+	/** Project base directory. */
+	private File baseDir;
+
+	/** lock object used when adding/removing listeners */
+	private final Object listenersLock = new Object();
+
+	/** List of listeners to notify of build events. */
+	private volatile BuildListener[] listeners = new BuildListener[0];
+
+	/**
+	 * for each thread, record whether it is currently executing messageLogged
+	 */
+	private final ThreadLocal isLoggingMessage = new ThreadLocal() {
+		protected Object initialValue() {
+			return Boolean.FALSE;
+		}
+	};
+
+	/**
+	 * The Ant core classloader--may be <code>null</code> if using parent
+	 * classloader.
+	 */
+	private ClassLoader coreLoader = null;
+
+	/** Records the latest task to be executed on a thread. */
+	private final Map/* <Thread,Task> */threadTasks = Collections
+			.synchronizedMap(new WeakHashMap());
+
+	/** Records the latest task to be executed on a thread group. */
+	private final Map/* <ThreadGroup,Task> */threadGroupTasks = Collections
+			.synchronizedMap(new WeakHashMap());
+
+	/**
+	 * Called to handle any input requests.
+	 */
+	private InputHandler inputHandler = null;
+
+	/**
+	 * The default input stream used to read any input.
+	 */
+	private InputStream defaultInputStream = null;
+
+	/**
+	 * Keep going flag.
+	 */
+	private boolean keepGoingMode = false;
+
+	/**
+	 * Set the input handler.
+	 * 
+	 * @param handler
+	 *            the InputHandler instance to use for gathering input.
+	 */
+	public void setInputHandler(InputHandler handler) {
+		inputHandler = handler;
+	}
+
+	/**
+	 * Set the default System input stream. Normally this stream is set to
+	 * System.in. This inputStream is used when no task input redirection is
+	 * being performed.
+	 * 
+	 * @param defaultInputStream
+	 *            the default input stream to use when input is requested.
+	 * @since Ant 1.6
+	 */
+	public void setDefaultInputStream(InputStream defaultInputStream) {
+		this.defaultInputStream = defaultInputStream;
+	}
+
+	/**
+	 * Get this project's input stream.
+	 * 
+	 * @return the InputStream instance in use by this Project instance to read
+	 *         input.
+	 */
+	public InputStream getDefaultInputStream() {
+		return defaultInputStream;
+	}
+
+	/**
+	 * Retrieve the current input handler.
+	 * 
+	 * @return the InputHandler instance currently in place for the project
+	 *         instance.
+	 */
+	public InputHandler getInputHandler() {
+		return inputHandler;
+	}
+
+	/**
+	 * Create a new Ant project.
+	 */
+	public Project() {
+		inputHandler = new DefaultInputHandler();
+	}
+
+	/**
+	 * Create and initialize a subproject. By default the subproject will be of
+	 * the same type as its parent. If a no-arg constructor is unavailable, the
+	 * <code>Project</code> class will be used.
+	 * 
+	 * @return a Project instance configured as a subproject of this Project.
+	 * @since Ant 1.7
+	 */
+	public Project createSubProject() {
+		Project subProject = null;
+		try {
+			subProject = (Project) (getClass().newInstance());
+		} catch (Exception e) {
+			subProject = new Project();
+		}
+		initSubProject(subProject);
+		return subProject;
+	}
+
+	/**
+	 * Initialize a subproject.
+	 * 
+	 * @param subProject
+	 *            the subproject to initialize.
+	 */
+	public void initSubProject(Project subProject) {
+		ComponentHelper.getComponentHelper(subProject).initSubProject(
+				ComponentHelper.getComponentHelper(this));
+		subProject.setDefaultInputStream(getDefaultInputStream());
+		subProject.setKeepGoingMode(this.isKeepGoingMode());
+		subProject.setExecutor(getExecutor().getSubProjectExecutor());
+	}
+
+	/**
+	 * Initialise the project.
+	 * 
+	 * This involves setting the default task definitions and loading the system
+	 * properties.
+	 * 
+	 * @exception BuildException
+	 *                if the default task list cannot be loaded.
+	 */
+	public void init() throws BuildException {
+		initProperties();
+
+		ComponentHelper.getComponentHelper(this).initDefaultDefinitions();
+	}
+
+	/**
+	 * Initializes the properties.
+	 * 
+	 * @exception BuildException
+	 *                if an vital property could not be set.
+	 * @since Ant 1.7
+	 */
+	public void initProperties() throws BuildException {
+		setJavaVersionProperty();
+		setSystemProperties();
+		setPropertyInternal(MagicNames.ANT_VERSION, Main.getAntVersion());
+		setAntLib();
+	}
+
+	/**
+	 * Set a property to the location of ant.jar. Use the locator to find the
+	 * location of the Project.class, and if this is not null, set the property
+	 * {@link MagicNames#ANT_LIB} to the result
+	 */
+	private void setAntLib() {
+		File antlib = org.apache.tools.ant.launch.Locator
+				.getClassSource(Project.class);
+		if (antlib != null) {
+			setPropertyInternal(MagicNames.ANT_LIB, antlib.getAbsolutePath());
+		}
+	}
+
+	/**
+	 * Factory method to create a class loader for loading classes from a given
+	 * path.
+	 * 
+	 * @param path
+	 *            the path from which classes are to be loaded.
+	 * 
+	 * @return an appropriate classloader.
+	 */
+	public AntClassLoader createClassLoader(Path path) {
+		return AntClassLoader.newAntClassLoader(getClass().getClassLoader(),
+				this, path, true);
+	}
+
+	/**
+	 * Factory method to create a class loader for loading classes from a given
+	 * path.
+	 * 
+	 * @param parent
+	 *            the parent classloader for the new loader.
+	 * @param path
+	 *            the path from which classes are to be loaded.
+	 * 
+	 * @return an appropriate classloader.
+	 */
+	public AntClassLoader createClassLoader(ClassLoader parent, Path path) {
+		return AntClassLoader.newAntClassLoader(parent, this, path, true);
+	}
+
+	/**
+	 * Set the core classloader for the project. If a <code>null</code>
+	 * classloader is specified, the parent classloader should be used.
+	 * 
+	 * @param coreLoader
+	 *            The classloader to use for the project. May be
+	 *            <code>null</code>.
+	 */
+	public void setCoreLoader(ClassLoader coreLoader) {
+		this.coreLoader = coreLoader;
+	}
+
+	/**
+	 * Return the core classloader to use for this project. This may be
+	 * <code>null</code>, indicating that the parent classloader should be used.
+	 * 
+	 * @return the core classloader to use for this project.
+	 * 
+	 */
+	public ClassLoader getCoreLoader() {
+		return coreLoader;
+	}
+
+	/**
+	 * Add a build listener to the list. This listener will be notified of build
+	 * events for this project.
+	 * 
+	 * @param listener
+	 *            The listener to add to the list. Must not be <code>null</code>
+	 *            .
+	 */
+	public void addBuildListener(BuildListener listener) {
+		synchronized (listenersLock) {
+			// If the listeners already has this listener, do nothing
+			for (int i = 0; i < listeners.length; i++) {
+				if (listeners[i] == listener) {
+					return;
+				}
+			}
+			// copy on write semantics
+			BuildListener[] newListeners = new BuildListener[listeners.length + 1];
+			System.arraycopy(listeners, 0, newListeners, 0, listeners.length);
+			newListeners[listeners.length] = listener;
+			listeners = newListeners;
+		}
+	}
+
+	/**
+	 * Remove a build listener from the list. This listener will no longer be
+	 * notified of build events for this project.
+	 * 
+	 * @param listener
+	 *            The listener to remove from the list. Should not be
+	 *            <code>null</code>.
+	 */
+	public void removeBuildListener(BuildListener listener) {
+		synchronized (listenersLock) {
+			// copy on write semantics
+			for (int i = 0; i < listeners.length; i++) {
+				if (listeners[i] == listener) {
+					BuildListener[] newListeners = new BuildListener[listeners.length - 1];
+					System.arraycopy(listeners, 0, newListeners, 0, i);
+					System.arraycopy(listeners, i + 1, newListeners, i,
+							listeners.length - i - 1);
+					listeners = newListeners;
+					break;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Return a copy of the list of build listeners for the project.
+	 * 
+	 * @return a list of build listeners for the project
+	 */
+	public Vector getBuildListeners() {
+		synchronized (listenersLock) {
+			Vector r = new Vector(listeners.length);
+			for (int i = 0; i < listeners.length; i++) {
+				r.add(listeners[i]);
+			}
+			return r;
+		}
+	}
+
+	/**
+	 * Write a message to the log with the default log level of MSG_INFO .
+	 * 
+	 * @param message
+	 *            The text to log. Should not be <code>null</code>.
+	 */
+
+	public void log(String message) {
+		log(message, MSG_INFO);
+	}
+
+	/**
+	 * Write a project level message to the log with the given log level.
+	 * 
+	 * @param message
+	 *            The text to log. Should not be <code>null</code>.
+	 * @param msgLevel
+	 *            The log priority level to use.
+	 */
+	public void log(String message, int msgLevel) {
+		log(message, null, msgLevel);
+	}
+
+	/**
+	 * Write a project level message to the log with the given log level.
+	 * 
+	 * @param message
+	 *            The text to log. Should not be <code>null</code>.
+	 * @param throwable
+	 *            The exception causing this log, may be <code>null</code>.
+	 * @param msgLevel
+	 *            The log priority level to use.
+	 * @since 1.7
+	 */
+	public void log(String message, Throwable throwable, int msgLevel) {
+		fireMessageLogged(this, message, throwable, msgLevel);
+	}
+
+	/**
+	 * Write a task level message to the log with the given log level.
+	 * 
+	 * @param task
+	 *            The task to use in the log. Must not be <code>null</code>.
+	 * @param message
+	 *            The text to log. Should not be <code>null</code>.
+	 * @param msgLevel
+	 *            The log priority level to use.
+	 */
+	public void log(Task task, String message, int msgLevel) {
+		fireMessageLogged(task, message, null, msgLevel);
+	}
+
+	/**
+	 * Write a task level message to the log with the given log level.
+	 * 
+	 * @param task
+	 *            The task to use in the log. Must not be <code>null</code>.
+	 * @param message
+	 *            The text to log. Should not be <code>null</code>.
+	 * @param throwable
+	 *            The exception causing this log, may be <code>null</code>.
+	 * @param msgLevel
+	 *            The log priority level to use.
+	 * @since 1.7
+	 */
+	public void log(Task task, String message, Throwable throwable, int msgLevel) {
+		fireMessageLogged(task, message, throwable, msgLevel);
+	}
+
+	/**
+	 * Write a target level message to the log with the given log level.
+	 * 
+	 * @param target
+	 *            The target to use in the log. Must not be <code>null</code>.
+	 * @param message
+	 *            The text to log. Should not be <code>null</code>.
+	 * @param msgLevel
+	 *            The log priority level to use.
+	 */
+	public void log(Target target, String message, int msgLevel) {
+		log(target, message, null, msgLevel);
+	}
+
+	/**
+	 * Write a target level message to the log with the given log level.
+	 * 
+	 * @param target
+	 *            The target to use in the log. Must not be <code>null</code>.
+	 * @param message
+	 *            The text to log. Should not be <code>null</code>.
+	 * @param throwable
+	 *            The exception causing this log, may be <code>null</code>.
+	 * @param msgLevel
+	 *            The log priority level to use.
+	 * @since 1.7
+	 */
+	public void log(Target target, String message, Throwable throwable,
+			int msgLevel) {
+		fireMessageLogged(target, message, throwable, msgLevel);
+	}
+
+	/**
+	 * Return the set of global filters.
+	 * 
+	 * @return the set of global filters.
+	 */
+	public FilterSet getGlobalFilterSet() {
+		return globalFilterSet;
+	}
+
+	/**
+	 * Set a property. Any existing property of the same name is overwritten,
+	 * unless it is a user property.
+	 * 
+	 * @param name
+	 *            The name of property to set. Must not be <code>null</code>.
+	 * @param value
+	 *            The new value of the property. Must not be <code>null</code>.
+	 */
+	public void setProperty(String name, String value) {
+		PropertyHelper.getPropertyHelper(this).setProperty(name, value, true);
+	}
+
+	/**
+	 * Set a property if no value currently exists. If the property exists
+	 * already, a message is logged and the method returns with no other effect.
+	 * 
+	 * @param name
+	 *            The name of property to set. Must not be <code>null</code>.
+	 * @param value
+	 *            The new value of the property. Must not be <code>null</code>.
+	 * @since 1.5
+	 */
+	public void setNewProperty(String name, String value) {
+		PropertyHelper.getPropertyHelper(this).setNewProperty(name, value);
+	}
+
+	/**
+	 * Set a user property, which cannot be overwritten by set/unset property
+	 * calls. Any previous value is overwritten.
+	 * 
+	 * @param name
+	 *            The name of property to set. Must not be <code>null</code>.
+	 * @param value
+	 *            The new value of the property. Must not be <code>null</code>.
+	 * @see #setProperty(String,String)
+	 */
+	public void setUserProperty(String name, String value) {
+		PropertyHelper.getPropertyHelper(this).setUserProperty(name, value);
+	}
+
+	/**
+	 * Set a user property, which cannot be overwritten by set/unset property
+	 * calls. Any previous value is overwritten. Also marks these properties as
+	 * properties that have not come from the command line.
+	 * 
+	 * @param name
+	 *            The name of property to set. Must not be <code>null</code>.
+	 * @param value
+	 *            The new value of the property. Must not be <code>null</code>.
+	 * @see #setProperty(String,String)
+	 */
+	public void setInheritedProperty(String name, String value) {
+		PropertyHelper.getPropertyHelper(this)
+				.setInheritedProperty(name, value);
+	}
+
+	/**
+	 * Set a property unless it is already defined as a user property (in which
+	 * case the method returns silently).
+	 * 
+	 * @param name
+	 *            The name of the property. Must not be <code>null</code>.
+	 * @param value
+	 *            The property value. Must not be <code>null</code>.
+	 */
+	private void setPropertyInternal(String name, String value) {
+		PropertyHelper.getPropertyHelper(this).setProperty(name, value, false);
+	}
+
+	/**
+	 * Return the value of a property, if it is set.
+	 * 
+	 * @param propertyName
+	 *            The name of the property. May be <code>null</code>, in which
+	 *            case the return value is also <code>null</code>.
+	 * @return the property value, or <code>null</code> for no match or if a
+	 *         <code>null</code> name is provided.
+	 */
+	public String getProperty(String propertyName) {
+		Object value = PropertyHelper.getPropertyHelper(this).getProperty(
+				propertyName);
+		return value == null ? null : String.valueOf(value);
+	}
+
+	/**
+	 * Replace ${} style constructions in the given value with the string value
+	 * of the corresponding data types.
+	 * 
+	 * @param value
+	 *            The string to be scanned for property references. May be
+	 *            <code>null</code>.
+	 * 
+	 * @return the given string with embedded property names replaced by values,
+	 *         or <code>null</code> if the given string is <code>null</code>.
+	 * 
+	 * @exception BuildException
+	 *                if the given value has an unclosed property name, e.g.
+	 *                <code>${xxx</code>.
+	 */
+	public String replaceProperties(String value) throws BuildException {
+		return PropertyHelper.getPropertyHelper(this).replaceProperties(null,
+				value, null);
+	}
+
+	/**
+	 * Return the value of a user property, if it is set.
+	 * 
+	 * @param propertyName
+	 *            The name of the property. May be <code>null</code>, in which
+	 *            case the return value is also <code>null</code>.
+	 * @return the property value, or <code>null</code> for no match or if a
+	 *         <code>null</code> name is provided.
+	 */
+	public String getUserProperty(String propertyName) {
+		return (String) PropertyHelper.getPropertyHelper(this).getUserProperty(
+				propertyName);
+	}
+
+	/**
+	 * Return a copy of the properties table.
+	 * 
+	 * @return a hashtable containing all properties (including user
+	 *         properties).
+	 */
+	public Hashtable getProperties() {
+		return PropertyHelper.getPropertyHelper(this).getProperties();
+	}
+
+	/**
+	 * Return a copy of the user property hashtable.
+	 * 
+	 * @return a hashtable containing just the user properties.
+	 */
+	public Hashtable getUserProperties() {
+		return PropertyHelper.getPropertyHelper(this).getUserProperties();
+	}
+
+	/**
+	 * Return a copy of the inherited property hashtable.
+	 * 
+	 * @return a hashtable containing just the inherited properties.
+	 * @since Ant 1.8.0
+	 */
+	public Hashtable getInheritedProperties() {
+		return PropertyHelper.getPropertyHelper(this).getInheritedProperties();
+	}
+
+	/**
+	 * Copy all user properties that have been set on the command line or a GUI
+	 * tool from this instance to the Project instance given as the argument.
+	 * 
+	 * <p>
+	 * To copy all &quot;user&quot; properties, you will also have to call
+	 * {@link #copyInheritedProperties copyInheritedProperties}.
+	 * </p>
+	 * 
+	 * @param other
+	 *            the project to copy the properties to. Must not be null.
+	 * 
+	 * @since Ant 1.5
+	 */
+	public void copyUserProperties(Project other) {
+		PropertyHelper.getPropertyHelper(this).copyUserProperties(other);
+	}
+
+	/**
+	 * Copy all user properties that have not been set on the command line or a
+	 * GUI tool from this instance to the Project instance given as the
+	 * argument.
+	 * 
+	 * <p>
+	 * To copy all &quot;user&quot; properties, you will also have to call
+	 * {@link #copyUserProperties copyUserProperties}.
+	 * </p>
+	 * 
+	 * @param other
+	 *            the project to copy the properties to. Must not be null.
+	 * 
+	 * @since Ant 1.5
+	 */
+	public void copyInheritedProperties(Project other) {
+		PropertyHelper.getPropertyHelper(this).copyInheritedProperties(other);
+	}
+
+	/**
+	 * Set the default target of the project.
+	 * 
+	 * @param defaultTarget
+	 *            The name of the default target for this project. May be
+	 *            <code>null</code>, indicating that there is no default target.
+	 * 
+	 * @deprecated since 1.5.x. Use setDefault.
+	 * @see #setDefault(String)
+	 */
+	public void setDefaultTarget(String defaultTarget) {
+		setDefault(defaultTarget);
+	}
+
+	/**
+	 * Return the name of the default target of the project.
+	 * 
+	 * @return name of the default target or <code>null</code> if no default has
+	 *         been set.
+	 */
+	public String getDefaultTarget() {
+		return defaultTarget;
+	}
+
+	/**
+	 * Set the default target of the project.
+	 * 
+	 * @param defaultTarget
+	 *            The name of the default target for this project. May be
+	 *            <code>null</code>, indicating that there is no default target.
+	 */
+	public void setDefault(String defaultTarget) {
+		if (defaultTarget != null) {
+			setUserProperty(MagicNames.PROJECT_DEFAULT_TARGET, defaultTarget);
+		}
+		this.defaultTarget = defaultTarget;
+	}
+
+	/**
+	 * Set the name of the project, also setting the user property
+	 * <code>ant.project.name</code>.
+	 * 
+	 * @param name
+	 *            The name of the project. Must not be <code>null</code>.
+	 */
+	public void setName(String name) {
+		setUserProperty(MagicNames.PROJECT_NAME, name);
+		this.name = name;
+	}
+
+	/**
+	 * Return the project name, if one has been set.
+	 * 
+	 * @return the project name, or <code>null</code> if it hasn't been set.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Set the project description.
+	 * 
+	 * @param description
+	 *            The description of the project. May be <code>null</code>.
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	/**
+	 * Return the project description, if one has been set.
+	 * 
+	 * @return the project description, or <code>null</code> if it hasn't been
+	 *         set.
+	 */
+	public String getDescription() {
+		if (description == null) {
+			description = Description.getDescription(this);
+		}
+		return description;
+	}
+
+	/**
+	 * Add a filter to the set of global filters.
+	 * 
+	 * @param token
+	 *            The token to filter. Must not be <code>null</code>.
+	 * @param value
+	 *            The replacement value. Must not be <code>null</code>.
+	 * @deprecated since 1.4.x. Use getGlobalFilterSet().addFilter(token,value)
+	 * 
+	 * @see #getGlobalFilterSet()
+	 * @see FilterSet#addFilter(String,String)
+	 */
+	public void addFilter(String token, String value) {
+		if (token == null) {
+			return;
+		}
+		globalFilterSet.addFilter(new FilterSet.Filter(token, value));
+	}
+
+	/**
+	 * Return a hashtable of global filters, mapping tokens to values.
+	 * 
+	 * @return a hashtable of global filters, mapping tokens to values (String
+	 *         to String).
+	 * 
+	 * @deprecated since 1.4.x Use getGlobalFilterSet().getFilterHash().
+	 * 
+	 * @see #getGlobalFilterSet()
+	 * @see FilterSet#getFilterHash()
+	 */
+	public Hashtable getFilters() {
+		// we need to build the hashtable dynamically
+		return globalFilterSet.getFilterHash();
+	}
+
+	/**
+	 * Set the base directory for the project, checking that the given filename
+	 * exists and is a directory.
+	 * 
+	 * @param baseD
+	 *            The project base directory. Must not be <code>null</code>.
+	 * 
+	 * @exception BuildException
+	 *                if the directory if invalid.
+	 */
+	public void setBasedir(String baseD) throws BuildException {
+		setBaseDir(new File(baseD));
+	}
+
+	/**
+	 * Set the base directory for the project, checking that the given file
+	 * exists and is a directory.
+	 * 
+	 * @param baseDir
+	 *            The project base directory. Must not be <code>null</code>.
+	 * @exception BuildException
+	 *                if the specified file doesn't exist or isn't a directory.
+	 */
+	public void setBaseDir(File baseDir) throws BuildException {
+		baseDir = FILE_UTILS.normalize(baseDir.getAbsolutePath());
+		if (!baseDir.exists()) {
+			throw new BuildException("Basedir " + baseDir.getAbsolutePath()
+					+ " does not exist");
+		}
+		if (!baseDir.isDirectory()) {
+			throw new BuildException("Basedir " + baseDir.getAbsolutePath()
+					+ " is not a directory");
+		}
+		this.baseDir = baseDir;
+		setPropertyInternal(MagicNames.PROJECT_BASEDIR, this.baseDir.getPath());
+		String msg = "Project base dir set to: " + this.baseDir;
+		log(msg, MSG_VERBOSE);
+	}
+
+	/**
+	 * Return the base directory of the project as a file object.
+	 * 
+	 * @return the project base directory, or <code>null</code> if the base
+	 *         directory has not been successfully set to a valid value.
+	 */
+	public File getBaseDir() {
+		if (baseDir == null) {
+			try {
+				setBasedir(".");
+			} catch (BuildException ex) {
+				ex.printStackTrace();
+			}
+		}
+		return baseDir;
+	}
+
+	/**
+	 * Set &quot;keep-going&quot; mode. In this mode Ant will try to execute as
+	 * many targets as possible. All targets that do not depend on failed
+	 * target(s) will be executed. If the keepGoing settor/getter methods are
+	 * used in conjunction with the <code>ant.executor.class</code> property,
+	 * they will have no effect.
+	 * 
+	 * @param keepGoingMode
+	 *            &quot;keep-going&quot; mode
+	 * @since Ant 1.6
+	 */
+	public void setKeepGoingMode(boolean keepGoingMode) {
+		this.keepGoingMode = keepGoingMode;
+	}
+
+	/**
+	 * Return the keep-going mode. If the keepGoing settor/getter methods are
+	 * used in conjunction with the <code>ant.executor.class</code> property,
+	 * they will have no effect.
+	 * 
+	 * @return &quot;keep-going&quot; mode
+	 * @since Ant 1.6
+	 */
+	public boolean isKeepGoingMode() {
+		return this.keepGoingMode;
+	}
+
+	/**
+	 * Return the version of Java this class is running under.
+	 * 
+	 * @return the version of Java as a String, e.g. "1.1" .
+	 * @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion
+	 * @deprecated since 1.5.x. Use org.apache.tools.ant.util.JavaEnvUtils
+	 *             instead.
+	 */
+	public static String getJavaVersion() {
+		return JavaEnvUtils.getJavaVersion();
+	}
+
+	/**
+	 * Set the <code>ant.java.version</code> property and tests for unsupported
+	 * JVM versions. If the version is supported, verbose log messages are
+	 * generated to record the Java version and operating system name.
+	 * 
+	 * @exception BuildException
+	 *                if this Java version is not supported.
+	 * 
+	 * @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion
+	 */
+	public void setJavaVersionProperty() throws BuildException {
+		String javaVersion = JavaEnvUtils.getJavaVersion();
+		setPropertyInternal(MagicNames.ANT_JAVA_VERSION, javaVersion);
+
+		// sanity check
+		if (!JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_1_4)) {
+			throw new BuildException("Ant cannot work on Java prior to 1.4");
+		}
+		log("Detected Java version: " + javaVersion + " in: "
+				+ System.getProperty("java.home"), MSG_VERBOSE);
+
+		log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE);
+	}
+
+	/**
+	 * Add all system properties which aren't already defined as user properties
+	 * to the project properties.
+	 */
+	public void setSystemProperties() {
+		Properties systemP = System.getProperties();
+		Enumeration e = systemP.propertyNames();
+		while (e.hasMoreElements()) {
+			String propertyName = (String) e.nextElement();
+			String value = systemP.getProperty(propertyName);
+			if (value != null) {
+				this.setPropertyInternal(propertyName, value);
+			}
+		}
+	}
+
+	/**
+	 * Add a new task definition to the project. Attempting to override an
+	 * existing definition with an equivalent one (i.e. with the same classname)
+	 * results in a verbose log message. Attempting to override an existing
+	 * definition with a different one results in a warning log message and
+	 * invalidates any tasks which have already been created with the old
+	 * definition.
+	 * 
+	 * @param taskName
+	 *            The name of the task to add. Must not be <code>null</code>.
+	 * @param taskClass
+	 *            The full name of the class implementing the task. Must not be
+	 *            <code>null</code>.
+	 * 
+	 * @exception BuildException
+	 *                if the class is unsuitable for being an Ant task. An error
+	 *                level message is logged before this exception is thrown.
+	 * 
+	 * @see #checkTaskClass(Class)
+	 */
+	public void addTaskDefinition(String taskName, Class taskClass)
+			throws BuildException {
+		ComponentHelper.getComponentHelper(this).addTaskDefinition(taskName,
+				taskClass);
+	}
+
+	/**
+	 * Check whether or not a class is suitable for serving as Ant task. Ant
+	 * task implementation classes must be public, concrete, and have a no-arg
+	 * constructor.
+	 * 
+	 * @param taskClass
+	 *            The class to be checked. Must not be <code>null</code>.
+	 * 
+	 * @exception BuildException
+	 *                if the class is unsuitable for being an Ant task. An error
+	 *                level message is logged before this exception is thrown.
+	 */
+	public void checkTaskClass(final Class taskClass) throws BuildException {
+		ComponentHelper.getComponentHelper(this).checkTaskClass(taskClass);
+
+		if (!Modifier.isPublic(taskClass.getModifiers())) {
+			final String message = taskClass + " is not public";
+			log(message, Project.MSG_ERR);
+			throw new BuildException(message);
+		}
+		if (Modifier.isAbstract(taskClass.getModifiers())) {
+			final String message = taskClass + " is abstract";
+			log(message, Project.MSG_ERR);
+			throw new BuildException(message);
+		}
+		try {
+			taskClass.getConstructor((Class[]) null);
+			// don't have to check for public, since
+			// getConstructor finds public constructors only.
+		} catch (NoSuchMethodException e) {
+			final String message = "No public no-arg constructor in "
+					+ taskClass;
+			log(message, Project.MSG_ERR);
+			throw new BuildException(message);
+		} catch (LinkageError e) {
+			String message = "Could not load " + taskClass + ": " + e;
+			log(message, Project.MSG_ERR);
+			throw new BuildException(message, e);
+		}
+		if (!Task.class.isAssignableFrom(taskClass)) {
+			TaskAdapter.checkTaskClass(taskClass, this);
+		}
+	}
+
+	/**
+	 * Return the current task definition hashtable. The returned hashtable is
+	 * &quot;live&quot; and so should not be modified.
+	 * 
+	 * @return a map of from task name to implementing class (String to Class).
+	 */
+	public Hashtable getTaskDefinitions() {
+		return ComponentHelper.getComponentHelper(this).getTaskDefinitions();
+	}
+
+	/**
+	 * Return the current task definition map. The returned map is a copy of the
+	 * &quot;live&quot; definitions.
+	 * 
+	 * @return a map of from task name to implementing class (String to Class).
+	 * 
+	 * @since Ant 1.8.1
+	 */
+	public Map getCopyOfTaskDefinitions() {
+		return new HashMap(getTaskDefinitions());
+	}
+
+	/**
+	 * Add a new datatype definition. Attempting to override an existing
+	 * definition with an equivalent one (i.e. with the same classname) results
+	 * in a verbose log message. Attempting to override an existing definition
+	 * with a different one results in a warning log message, but the definition
+	 * is changed.
+	 * 
+	 * @param typeName
+	 *            The name of the datatype. Must not be <code>null</code>.
+	 * @param typeClass
+	 *            The full name of the class implementing the datatype. Must not
+	 *            be <code>null</code>.
+	 */
+	public void addDataTypeDefinition(String typeName, Class typeClass) {
+		ComponentHelper.getComponentHelper(this).addDataTypeDefinition(
+				typeName, typeClass);
+	}
+
+	/**
+	 * Return the current datatype definition hashtable. The returned hashtable
+	 * is &quot;live&quot; and so should not be modified.
+	 * 
+	 * @return a map of from datatype name to implementing class (String to
+	 *         Class).
+	 */
+	public Hashtable getDataTypeDefinitions() {
+		return ComponentHelper.getComponentHelper(this)
+				.getDataTypeDefinitions();
+	}
+
+	/**
+	 * Return the current datatype definition map. The returned map is a copy pf
+	 * the &quot;live&quot; definitions.
+	 * 
+	 * @return a map of from datatype name to implementing class (String to
+	 *         Class).
+	 * 
+	 * @since Ant 1.8.1
+	 */
+	public Map getCopyOfDataTypeDefinitions() {
+		return new HashMap(getDataTypeDefinitions());
+	}
+
+	/**
+	 * Add a <em>new</em> target to the project.
+	 * 
+	 * @param target
+	 *            The target to be added to the project. Must not be
+	 *            <code>null</code>.
+	 * 
+	 * @exception BuildException
+	 *                if the target already exists in the project
+	 * 
+	 * @see Project#addOrReplaceTarget(Target)
+	 */
+	public void addTarget(Target target) throws BuildException {
+		addTarget(target.getName(), target);
+	}
+
+	/**
+	 * Add a <em>new</em> target to the project.
+	 * 
+	 * @param targetName
+	 *            The name to use for the target. Must not be <code>null</code>.
+	 * @param target
+	 *            The target to be added to the project. Must not be
+	 *            <code>null</code>.
+	 * 
+	 * @exception BuildException
+	 *                if the target already exists in the project.
+	 * 
+	 * @see Project#addOrReplaceTarget(String, Target)
+	 */
+	public void addTarget(String targetName, Target target)
+			throws BuildException {
+		if (targets.get(targetName) != null) {
+			throw new BuildException("Duplicate target: `" + targetName + "'");
+		}
+		addOrReplaceTarget(targetName, target);
+	}
+
+	/**
+	 * Add a target to the project, or replaces one with the same name.
+	 * 
+	 * @param target
+	 *            The target to be added or replaced in the project. Must not be
+	 *            <code>null</code>.
+	 */
+	public void addOrReplaceTarget(Target target) {
+		addOrReplaceTarget(target.getName(), target);
+	}
+
+	/**
+	 * Add a target to the project, or replaces one with the same name.
+	 * 
+	 * @param targetName
+	 *            The name to use for the target. Must not be <code>null</code>.
+	 * @param target
+	 *            The target to be added or replaced in the project. Must not be
+	 *            <code>null</code>.
+	 */
+	public void addOrReplaceTarget(String targetName, Target target) {
+		String msg = " +Target: " + targetName;
+		log(msg, MSG_DEBUG);
+		target.setProject(this);
+		targets.put(targetName, target);
+	}
+
+	/**
+	 * Return the hashtable of targets. The returned hashtable is
+	 * &quot;live&quot; and so should not be modified.
+	 * 
+	 * @return a map from name to target (String to Target).
+	 */
+	public Hashtable getTargets() {
+		return targets;
+	}
+
+	/**
+	 * Return the map of targets. The returned map is a copy of the
+	 * &quot;live&quot; targets.
+	 * 
+	 * @return a map from name to target (String to Target).
+	 * @since Ant 1.8.1
+	 */
+	public Map getCopyOfTargets() {
+		return new HashMap(targets);
+	}
+
+	/**
+	 * Create a new instance of a task, adding it to a list of created tasks for
+	 * later invalidation. This causes all tasks to be remembered until the
+	 * containing project is removed
+	 * 
+	 * @param taskType
+	 *            The name of the task to create an instance of. Must not be
+	 *            <code>null</code>.
+	 * 
+	 * @return an instance of the specified task, or <code>null</code> if the
+	 *         task name is not recognised.
+	 * 
+	 * @exception BuildException
+	 *                if the task name is recognised but task creation fails.
+	 */
+	public Task createTask(String taskType) throws BuildException {
+		return ComponentHelper.getComponentHelper(this).createTask(taskType);
+	}
+
+	/**
+	 * Create a new instance of a data type.
+	 * 
+	 * @param typeName
+	 *            The name of the data type to create an instance of. Must not
+	 *            be <code>null</code>.
+	 * 
+	 * @return an instance of the specified data type, or <code>null</code> if
+	 *         the data type name is not recognised.
+	 * 
+	 * @exception BuildException
+	 *                if the data type name is recognised but instance creation
+	 *                fails.
+	 */
+	public Object createDataType(String typeName) throws BuildException {
+		return ComponentHelper.getComponentHelper(this)
+				.createDataType(typeName);
+	}
+
+	/**
+	 * Set the Executor instance for this Project.
+	 * 
+	 * @param e
+	 *            the Executor to use.
+	 */
+	public void setExecutor(Executor e) {
+		addReference(MagicNames.ANT_EXECUTOR_REFERENCE, e);
+	}
+
+	/**
+	 * Get this Project's Executor (setting it if necessary).
+	 * 
+	 * @return an Executor instance.
+	 */
+	public Executor getExecutor() {
+		Object o = getReference(MagicNames.ANT_EXECUTOR_REFERENCE);
+		if (o == null) {
+			String classname = getProperty(MagicNames.ANT_EXECUTOR_CLASSNAME);
+			if (classname == null) {
+				classname = DefaultExecutor.class.getName();
+			}
+			log("Attempting to create object of type " + classname, MSG_DEBUG);
+			try {
+				o = Class.forName(classname, true, coreLoader).newInstance();
+			} catch (ClassNotFoundException seaEnEfEx) {
+				// try the current classloader
+				try {
+					o = Class.forName(classname).newInstance();
+				} catch (Exception ex) {
+					log(ex.toString(), MSG_ERR);
+				}
+			} catch (Exception ex) {
+				log(ex.toString(), MSG_ERR);
+			}
+			if (o == null) {
+				throw new BuildException(
+						"Unable to obtain a Target Executor instance.");
+			}
+			setExecutor((Executor) o);
+		}
+		return (Executor) o;
+	}
+
+	/**
+	 * Execute the specified sequence of targets, and the targets they depend
+	 * on.
+	 * 
+	 * @param names
+	 *            A vector of target name strings to execute. Must not be
+	 *            <code>null</code>.
+	 * 
+	 * @exception BuildException
+	 *                if the build failed.
+	 */
+	public void executeTargets(Vector names) throws BuildException {
+		setUserProperty(MagicNames.PROJECT_INVOKED_TARGETS, CollectionUtils
+				.flattenToString(names));
+		getExecutor().executeTargets(this,
+				(String[]) (names.toArray(new String[names.size()])));
+	}
+
+	/**
+	 * Demultiplex output so that each task receives the appropriate messages.
+	 * If the current thread is not currently executing a task, the message is
+	 * logged directly.
+	 * 
+	 * @param output
+	 *            Message to handle. Should not be <code>null</code>.
+	 * @param isWarning
+	 *            Whether the text represents an warning (<code>true</code>) or
+	 *            information (<code>false</code>).
+	 */
+	public void demuxOutput(String output, boolean isWarning) {
+		Task task = getThreadTask(Thread.currentThread());
+		if (task == null) {
+			log(output, isWarning ? MSG_WARN : MSG_INFO);
+		} else {
+			if (isWarning) {
+				task.handleErrorOutput(output);
+			} else {
+				task.handleOutput(output);
+			}
+		}
+	}
+
+	/**
+	 * Read data from the default input stream. If no default has been
+	 * specified, System.in is used.
+	 * 
+	 * @param buffer
+	 *            the buffer into which data is to be read.
+	 * @param offset
+	 *            the offset into the buffer at which data is stored.
+	 * @param length
+	 *            the amount of data to read.
+	 * 
+	 * @return the number of bytes read.
+	 * 
+	 * @exception IOException
+	 *                if the data cannot be read.
+	 * @since Ant 1.6
+	 */
+	public int defaultInput(byte[] buffer, int offset, int length)
+			throws IOException {
+		if (defaultInputStream != null) {
+			System.out.flush();
+			return defaultInputStream.read(buffer, offset, length);
+		} else {
+			throw new EOFException("No input provided for project");
+		}
+	}
+
+	/**
+	 * Demux an input request to the correct task.
+	 * 
+	 * @param buffer
+	 *            the buffer into which data is to be read.
+	 * @param offset
+	 *            the offset into the buffer at which data is stored.
+	 * @param length
+	 *            the amount of data to read.
+	 * 
+	 * @return the number of bytes read.
+	 * 
+	 * @exception IOException
+	 *                if the data cannot be read.
+	 * @since Ant 1.6
+	 */
+	public int demuxInput(byte[] buffer, int offset, int length)
+			throws IOException {
+		Task task = getThreadTask(Thread.currentThread());
+		if (task == null) {
+			return defaultInput(buffer, offset, length);
+		} else {
+			return task.handleInput(buffer, offset, length);
+		}
+	}
+
+	/**
+	 * Demultiplex flush operations so that each task receives the appropriate
+	 * messages. If the current thread is not currently executing a task, the
+	 * message is logged directly.
+	 * 
+	 * @since Ant 1.5.2
+	 * 
+	 * @param output
+	 *            Message to handle. Should not be <code>null</code>.
+	 * @param isError
+	 *            Whether the text represents an error (<code>true</code>) or
+	 *            information (<code>false</code>).
+	 */
+	public void demuxFlush(String output, boolean isError) {
+		Task task = getThreadTask(Thread.currentThread());
+		if (task == null) {
+			fireMessageLogged(this, output, isError ? MSG_ERR : MSG_INFO);
+		} else {
+			if (isError) {
+				task.handleErrorFlush(output);
+			} else {
+				task.handleFlush(output);
+			}
+		}
+	}
+
+	/**
+	 * Execute the specified target and any targets it depends on.
+	 * 
+	 * @param targetName
+	 *            The name of the target to execute. Must not be
+	 *            <code>null</code>.
+	 * 
+	 * @exception BuildException
+	 *                if the build failed.
+	 */
+	public void executeTarget(String targetName) throws BuildException {
+
+		// sanity check ourselves, if we've been asked to build nothing
+		// then we should complain
+
+		if (targetName == null) {
+			String msg = "No target specified";
+			throw new BuildException(msg);
+		}
+
+		// Sort and run the dependency tree.
+		// Sorting checks if all the targets (and dependencies)
+		// exist, and if there is any cycle in the dependency
+		// graph.
+		executeSortedTargets(topoSort(targetName, targets, false));
+	}
+
+	protected String breakAt;
+	
+	public void setBreakAt(String breakAt) {
+		this.breakAt = breakAt;
+	}
+	
+	public String getBreakAt() {
+		return breakAt;
+	}
+	
+	/**
+	 * Execute a <code>Vector</code> of sorted targets.
+	 * 
+	 * @param sortedTargets
+	 *            the aforementioned <code>Vector</code>.
+	 * @throws BuildException
+	 *             on error.
+	 */
+	public void executeSortedTargets(Vector sortedTargets)
+			throws BuildException {
+		Set succeededTargets = new HashSet();
+		BuildException buildException = null; // first build exception
+//		int i = -1;
+//		for (Enumeration iter = sortedTargets.elements(); iter
+//				.hasMoreElements() && getBreakAt() != null && getBreakAt().trim().length() > 0;) {
+//			i++;
+//			Target curTarget = (Target) iter.nextElement();
+//			if(curTarget.getName().equals(getBreakAt())) {
+//				log("Adding default DebugTarget");
+//				sortedTargets.add(i, DebugTask.createDebugTarget(this));
+//				break;
+//			}
+//		}
+		for (Enumeration iter = sortedTargets.elements(); iter
+				.hasMoreElements();) {
+			Target curtarget = (Target) iter.nextElement();
+			boolean canExecute = true;
+			for (Enumeration depIter = curtarget.getDependencies(); depIter
+					.hasMoreElements();) {
+				String dependencyName = ((String) depIter.nextElement());
+				if (!succeededTargets.contains(dependencyName)) {
+					canExecute = false;
+					log(curtarget, "Cannot execute '" + curtarget.getName()
+							+ "' - '" + dependencyName
+							+ "' failed or was not executed.", MSG_ERR);
+					break;
+				}
+			}
+			if (canExecute) {
+				Throwable thrownException = null;
+				try {
+					curtarget.performTasks();
+					succeededTargets.add(curtarget.getName());
+				} catch (RuntimeException ex) {
+					if (!(keepGoingMode)) {
+						throw ex; // throw further
+					}
+					thrownException = ex;
+				} catch (Throwable ex) {
+					if (!(keepGoingMode)) {
+						throw new BuildException(ex);
+					}
+					thrownException = ex;
+				}
+				if (thrownException != null) {
+					if (thrownException instanceof BuildException) {
+						log(curtarget, "Target '" + curtarget.getName()
+								+ "' failed with message '"
+								+ thrownException.getMessage() + "'.", MSG_ERR);
+						// only the first build exception is reported
+						if (buildException == null) {
+							buildException = (BuildException) thrownException;
+						}
+					} else {
+						log(curtarget, "Target '" + curtarget.getName()
+								+ "' failed with message '"
+								+ thrownException.getMessage() + "'.", MSG_ERR);
+						thrownException.printStackTrace(System.err);
+						if (buildException == null) {
+							buildException = new BuildException(thrownException);
+						}
+					}
+				}
+			}
+		}
+		if (buildException != null) {
+			throw buildException;
+		}
+	}
+
+	/**
+	 * Return the canonical form of a filename.
+	 * <p>
+	 * If the specified file name is relative it is resolved with respect to the
+	 * given root directory.
+	 * 
+	 * @param fileName
+	 *            The name of the file to resolve. Must not be <code>null</code>
+	 *            .
+	 * 
+	 * @param rootDir
+	 *            The directory respective to which relative file names are
+	 *            resolved. May be <code>null</code>, in which case the current
+	 *            directory is used.
+	 * 
+	 * @return the resolved File.
+	 * 
+	 * @deprecated since 1.4.x
+	 */
+	public File resolveFile(String fileName, File rootDir) {
+		return FILE_UTILS.resolveFile(rootDir, fileName);
+	}
+
+	/**
+	 * Return the canonical form of a filename.
+	 * <p>
+	 * If the specified file name is relative it is resolved with respect to the
+	 * project's base directory.
+	 * 
+	 * @param fileName
+	 *            The name of the file to resolve. Must not be <code>null</code>
+	 *            .
+	 * 
+	 * @return the resolved File.
+	 * 
+	 */
+	public File resolveFile(String fileName) {
+		return FILE_UTILS.resolveFile(baseDir, fileName);
+	}
+
+	/**
+	 * Translate a path into its native (platform specific) format.
+	 * <p>
+	 * This method uses PathTokenizer to separate the input path into its
+	 * components. This handles DOS style paths in a relatively sensible way.
+	 * The file separators are then converted to their platform specific
+	 * versions.
+	 * 
+	 * @param toProcess
+	 *            The path to be translated. May be <code>null</code>.
+	 * 
+	 * @return the native version of the specified path or an empty string if
+	 *         the path is <code>null</code> or empty.
+	 * 
+	 * @deprecated since 1.7 Use FileUtils.translatePath instead.
+	 * 
+	 * @see PathTokenizer
+	 */
+	public static String translatePath(String toProcess) {
+		return FileUtils.translatePath(toProcess);
+	}
+
+	/**
+	 * Convenience method to copy a file from a source to a destination. No
+	 * filtering is performed.
+	 * 
+	 * @param sourceFile
+	 *            Name of file to copy from. Must not be <code>null</code>.
+	 * @param destFile
+	 *            Name of file to copy to. Must not be <code>null</code>.
+	 * 
+	 * @exception IOException
+	 *                if the copying fails.
+	 * 
+	 * @deprecated since 1.4.x
+	 */
+	public void copyFile(String sourceFile, String destFile) throws IOException {
+		FILE_UTILS.copyFile(sourceFile, destFile);
+	}
+
+	/**
+	 * Convenience method to copy a file from a source to a destination
+	 * specifying if token filtering should be used.
+	 * 
+	 * @param sourceFile
+	 *            Name of file to copy from. Must not be <code>null</code>.
+	 * @param destFile
+	 *            Name of file to copy to. Must not be <code>null</code>.
+	 * @param filtering
+	 *            Whether or not token filtering should be used during the copy.
+	 * 
+	 * @exception IOException
+	 *                if the copying fails.
+	 * 
+	 * @deprecated since 1.4.x
+	 */
+	public void copyFile(String sourceFile, String destFile, boolean filtering)
+			throws IOException {
+		FILE_UTILS.copyFile(sourceFile, destFile, filtering ? globalFilters
+				: null);
+	}
+
+	/**
+	 * Convenience method to copy a file from a source to a destination
+	 * specifying if token filtering should be used and if source files may
+	 * overwrite newer destination files.
+	 * 
+	 * @param sourceFile
+	 *            Name of file to copy from. Must not be <code>null</code>.
+	 * @param destFile
+	 *            Name of file to copy to. Must not be <code>null</code>.
+	 * @param filtering
+	 *            Whether or not token filtering should be used during the copy.
+	 * @param overwrite
+	 *            Whether or not the destination file should be overwritten if
+	 *            it already exists.
+	 * 
+	 * @exception IOException
+	 *                if the copying fails.
+	 * 
+	 * @deprecated since 1.4.x
+	 */
+	public void copyFile(String sourceFile, String destFile, boolean filtering,
+			boolean overwrite) throws IOException {
+		FILE_UTILS.copyFile(sourceFile, destFile, filtering ? globalFilters
+				: null, overwrite);
+	}
+
+	/**
+	 * Convenience method to copy a file from a source to a destination
+	 * specifying if token filtering should be used, if source files may
+	 * overwrite newer destination files, and if the last modified time of the
+	 * resulting file should be set to that of the source file.
+	 * 
+	 * @param sourceFile
+	 *            Name of file to copy from. Must not be <code>null</code>.
+	 * @param destFile
+	 *            Name of file to copy to. Must not be <code>null</code>.
+	 * @param filtering
+	 *            Whether or not token filtering should be used during the copy.
+	 * @param overwrite
+	 *            Whether or not the destination file should be overwritten if
+	 *            it already exists.
+	 * @param preserveLastModified
+	 *            Whether or not the last modified time of the resulting file
+	 *            should be set to that of the source file.
+	 * 
+	 * @exception IOException
+	 *                if the copying fails.
+	 * 
+	 * @deprecated since 1.4.x
+	 */
+	public void copyFile(String sourceFile, String destFile, boolean filtering,
+			boolean overwrite, boolean preserveLastModified) throws IOException {
+		FILE_UTILS.copyFile(sourceFile, destFile, filtering ? globalFilters
+				: null, overwrite, preserveLastModified);
+	}
+
+	/**
+	 * Convenience method to copy a file from a source to a destination. No
+	 * filtering is performed.
+	 * 
+	 * @param sourceFile
+	 *            File to copy from. Must not be <code>null</code>.
+	 * @param destFile
+	 *            File to copy to. Must not be <code>null</code>.
+	 * 
+	 * @exception IOException
+	 *                if the copying fails.
+	 * 
+	 * @deprecated since 1.4.x
+	 */
+	public void copyFile(File sourceFile, File destFile) throws IOException {
+		FILE_UTILS.copyFile(sourceFile, destFile);
+	}
+
+	/**
+	 * Convenience method to copy a file from a source to a destination
+	 * specifying if token filtering should be used.
+	 * 
+	 * @param sourceFile
+	 *            File to copy from. Must not be <code>null</code>.
+	 * @param destFile
+	 *            File to copy to. Must not be <code>null</code>.
+	 * @param filtering
+	 *            Whether or not token filtering should be used during the copy.
+	 * 
+	 * @exception IOException
+	 *                if the copying fails.
+	 * 
+	 * @deprecated since 1.4.x
+	 */
+	public void copyFile(File sourceFile, File destFile, boolean filtering)
+			throws IOException {
+		FILE_UTILS.copyFile(sourceFile, destFile, filtering ? globalFilters
+				: null);
+	}
+
+	/**
+	 * Convenience method to copy a file from a source to a destination
+	 * specifying if token filtering should be used and if source files may
+	 * overwrite newer destination files.
+	 * 
+	 * @param sourceFile
+	 *            File to copy from. Must not be <code>null</code>.
+	 * @param destFile
+	 *            File to copy to. Must not be <code>null</code>.
+	 * @param filtering
+	 *            Whether or not token filtering should be used during the copy.
+	 * @param overwrite
+	 *            Whether or not the destination file should be overwritten if
+	 *            it already exists.
+	 * 
+	 * @exception IOException
+	 *                if the file cannot be copied.
+	 * 
+	 * @deprecated since 1.4.x
+	 */
+	public void copyFile(File sourceFile, File destFile, boolean filtering,
+			boolean overwrite) throws IOException {
+		FILE_UTILS.copyFile(sourceFile, destFile, filtering ? globalFilters
+				: null, overwrite);
+	}
+
+	/**
+	 * Convenience method to copy a file from a source to a destination
+	 * specifying if token filtering should be used, if source files may
+	 * overwrite newer destination files, and if the last modified time of the
+	 * resulting file should be set to that of the source file.
+	 * 
+	 * @param sourceFile
+	 *            File to copy from. Must not be <code>null</code>.
+	 * @param destFile
+	 *            File to copy to. Must not be <code>null</code>.
+	 * @param filtering
+	 *            Whether or not token filtering should be used during the copy.
+	 * @param overwrite
+	 *            Whether or not the destination file should be overwritten if
+	 *            it already exists.
+	 * @param preserveLastModified
+	 *            Whether or not the last modified time of the resulting file
+	 *            should be set to that of the source file.
+	 * 
+	 * @exception IOException
+	 *                if the file cannot be copied.
+	 * 
+	 * @deprecated since 1.4.x
+	 */
+	public void copyFile(File sourceFile, File destFile, boolean filtering,
+			boolean overwrite, boolean preserveLastModified) throws IOException {
+		FILE_UTILS.copyFile(sourceFile, destFile, filtering ? globalFilters
+				: null, overwrite, preserveLastModified);
+	}
+
+	/**
+	 * Call File.setLastModified(long time) on Java above 1.1, and logs a
+	 * warning on Java 1.1.
+	 * 
+	 * @param file
+	 *            The file to set the last modified time on. Must not be
+	 *            <code>null</code>.
+	 * 
+	 * @param time
+	 *            the required modification time.
+	 * 
+	 * @deprecated since 1.4.x
+	 * 
+	 * @exception BuildException
+	 *                if the last modified time cannot be set despite running on
+	 *                a platform with a version above 1.1.
+	 */
+	public void setFileLastModified(File file, long time) throws BuildException {
+		FILE_UTILS.setFileLastModified(file, time);
+		log("Setting modification time for " + file, MSG_VERBOSE);
+	}
+
+	/**
+	 * Return the boolean equivalent of a string, which is considered
+	 * <code>true</code> if either <code>"on"</code>, <code>"true"</code>, or
+	 * <code>"yes"</code> is found, ignoring case.
+	 * 
+	 * @param s
+	 *            The string to convert to a boolean value.
+	 * 
+	 * @return <code>true</code> if the given string is <code>"on"</code>,
+	 *         <code>"true"</code> or <code>"yes"</code>, or <code>false</code>
+	 *         otherwise.
+	 */
+	public static boolean toBoolean(String s) {
+		return ("on".equalsIgnoreCase(s) || "true".equalsIgnoreCase(s) || "yes"
+				.equalsIgnoreCase(s));
+	}
+
+	/**
+	 * Get the Project instance associated with the specified object.
+	 * 
+	 * @param o
+	 *            the object to query.
+	 * @return Project instance, if any.
+	 * @since Ant 1.7.1
+	 */
+	public static Project getProject(Object o) {
+		if (o instanceof ProjectComponent) {
+			return ((ProjectComponent) o).getProject();
+		}
+		try {
+			Method m = o.getClass().getMethod("getProject", (Class[]) null);
+			if (Project.class == m.getReturnType()) {
+				return (Project) m.invoke(o, (Object[]) null);
+			}
+		} catch (Exception e) {
+			// too bad
+		}
+		return null;
+	}
+
+	/**
+	 * Topologically sort a set of targets. Equivalent to calling
+	 * <code>topoSort(new String[] {root}, targets, true)</code>.
+	 * 
+	 * @param root
+	 *            The name of the root target. The sort is created in such a way
+	 *            that the sequence of Targets up to the root target is the
+	 *            minimum possible such sequence. Must not be <code>null</code>.
+	 * @param targetTable
+	 *            A Hashtable mapping names to Targets. Must not be
+	 *            <code>null</code>.
+	 * @return a Vector of ALL Target objects in sorted order.
+	 * @exception BuildException
+	 *                if there is a cyclic dependency among the targets, or if a
+	 *                named target does not exist.
+	 */
+	public final Vector topoSort(String root, Hashtable targetTable)
+			throws BuildException {
+		return topoSort(new String[] { root }, targetTable, true);
+	}
+
+	/**
+	 * Topologically sort a set of targets. Equivalent to calling
+	 * <code>topoSort(new String[] {root}, targets, returnAll)</code>.
+	 * 
+	 * @param root
+	 *            The name of the root target. The sort is created in such a way
+	 *            that the sequence of Targets up to the root target is the
+	 *            minimum possible such sequence. Must not be <code>null</code>.
+	 * @param targetTable
+	 *            A Hashtable mapping names to Targets. Must not be
+	 *            <code>null</code>.
+	 * @param returnAll
+	 *            <code>boolean</code> indicating whether to return all targets,
+	 *            or the execution sequence only.
+	 * @return a Vector of Target objects in sorted order.
+	 * @exception BuildException
+	 *                if there is a cyclic dependency among the targets, or if a
+	 *                named target does not exist.
+	 * @since Ant 1.6.3
+	 */
+	public final Vector topoSort(String root, Hashtable targetTable,
+			boolean returnAll) throws BuildException {
+		return topoSort(new String[] { root }, targetTable, returnAll);
+	}
+
+	/**
+	 * Topologically sort a set of targets.
+	 * 
+	 * @param root
+	 *            <code>String[]</code> containing the names of the root
+	 *            targets. The sort is created in such a way that the ordered
+	 *            sequence of Targets is the minimum possible such sequence to
+	 *            the specified root targets. Must not be <code>null</code>.
+	 * @param targetTable
+	 *            A map of names to targets (String to Target). Must not be
+	 *            <code>null</code>.
+	 * @param returnAll
+	 *            <code>boolean</code> indicating whether to return all targets,
+	 *            or the execution sequence only.
+	 * @return a Vector of Target objects in sorted order.
+	 * @exception BuildException
+	 *                if there is a cyclic dependency among the targets, or if a
+	 *                named target does not exist.
+	 * @since Ant 1.6.3
+	 */
+	public final Vector topoSort(String[] root, Hashtable targetTable,
+			boolean returnAll) throws BuildException {
+		Vector ret = new VectorSet();
+		Hashtable state = new Hashtable();
+		Stack visiting = new Stack();
+
+		// We first run a DFS based sort using each root as a starting node.
+		// This creates the minimum sequence of Targets to the root node(s).
+		// We then do a sort on any remaining unVISITED targets.
+		// This is unnecessary for doing our build, but it catches
+		// circular dependencies or missing Targets on the entire
+		// dependency tree, not just on the Targets that depend on the
+		// build Target.
+
+		for (int i = 0; i < root.length; i++) {
+			String st = (String) (state.get(root[i]));
+			if (st == null) {
+				tsort(root[i], targetTable, state, visiting, ret);
+			} else if (st == VISITING) {
+				throw new RuntimeException(
+						"Unexpected node in visiting state: " + root[i]);
+			}
+		}
+		StringBuffer buf = new StringBuffer("Build sequence for target(s)");
+
+		for (int j = 0; j < root.length; j++) {
+			buf.append((j == 0) ? " `" : ", `").append(root[j]).append('\'');
+		}
+		buf.append(" is " + ret);
+		log(buf.toString(), MSG_VERBOSE);
+
+		Vector complete = (returnAll) ? ret : new Vector(ret);
+		for (Enumeration en = targetTable.keys(); en.hasMoreElements();) {
+			String curTarget = (String) en.nextElement();
+			String st = (String) state.get(curTarget);
+			if (st == null) {
+				tsort(curTarget, targetTable, state, visiting, complete);
+			} else if (st == VISITING) {
+				throw new RuntimeException(
+						"Unexpected node in visiting state: " + curTarget);
+			}
+		}
+		log("Complete build sequence is " + complete, MSG_VERBOSE);
+		return ret;
+	}
+
+	/**
+	 * Perform a single step in a recursive depth-first-search traversal of the
+	 * target dependency tree.
+	 * <p>
+	 * The current target is first set to the &quot;visiting&quot; state, and
+	 * pushed onto the &quot;visiting&quot; stack.
+	 * <p>
+	 * An exception is then thrown if any child of the current node is in the
+	 * visiting state, as that implies a circular dependency. The exception
+	 * contains details of the cycle, using elements of the &quot;visiting&quot;
+	 * stack.
+	 * <p>
+	 * If any child has not already been &quot;visited&quot;, this method is
+	 * called recursively on it.
+	 * <p>
+	 * The current target is then added to the ordered list of targets. Note
+	 * that this is performed after the children have been visited in order to
+	 * get the correct order. The current target is set to the
+	 * &quot;visited&quot; state.
+	 * <p>
+	 * By the time this method returns, the ordered list contains the sequence
+	 * of targets up to and including the current target.
+	 * 
+	 * @param root
+	 *            The current target to inspect. Must not be <code>null</code>.
+	 * @param targetTable
+	 *            A mapping from names to targets (String to Target). Must not
+	 *            be <code>null</code>.
+	 * @param state
+	 *            A mapping from target names to states (String to String). The
+	 *            states in question are &quot;VISITING&quot; and
+	 *            &quot;VISITED&quot;. Must not be <code>null</code>.
+	 * @param visiting
+	 *            A stack of targets which are currently being visited. Must not
+	 *            be <code>null</code>.
+	 * @param ret
+	 *            The list to add target names to. This will end up containing
+	 *            the complete list of dependencies in dependency order. Must
+	 *            not be <code>null</code>.
+	 * 
+	 * @exception BuildException
+	 *                if a non-existent target is specified or if a circular
+	 *                dependency is detected.
+	 */
+	private void tsort(String root, Hashtable targetTable, Hashtable state,
+			Stack visiting, Vector ret) throws BuildException {
+		state.put(root, VISITING);
+		visiting.push(root);
+
+		Target target = (Target) targetTable.get(root);
+
+		// Make sure we exist
+		if (target == null) {
+			StringBuffer sb = new StringBuffer("Target \"");
+			sb.append(root);
+			sb.append("\" does not exist in the project \"");
+			sb.append(name);
+			sb.append("\". ");
+			visiting.pop();
+			if (!visiting.empty()) {
+				String parent = (String) visiting.peek();
+				sb.append("It is used from target \"");
+				sb.append(parent);
+				sb.append("\".");
+			}
+			throw new BuildException(new String(sb));
+		}
+		for (Enumeration en = target.getDependencies(); en.hasMoreElements();) {
+			String cur = (String) en.nextElement();
+			String m = (String) state.get(cur);
+			if (m == null) {
+				// Not been visited
+				tsort(cur, targetTable, state, visiting, ret);
+			} else if (m == VISITING) {
+				// Currently visiting this node, so have a cycle
+				throw makeCircularException(cur, visiting);
+			}
+		}
+		String p = (String) visiting.pop();
+		if (root != p) {
+			throw new RuntimeException(
+					"Unexpected internal error: expected to " + "pop " + root
+							+ " but got " + p);
+		}
+		state.put(root, VISITED);
+		ret.addElement(target);
+	}
+
+	/**
+	 * Build an appropriate exception detailing a specified circular dependency.
+	 * 
+	 * @param end
+	 *            The dependency to stop at. Must not be <code>null</code>.
+	 * @param stk
+	 *            A stack of dependencies. Must not be <code>null</code>.
+	 * 
+	 * @return a BuildException detailing the specified circular dependency.
+	 */
+	private static BuildException makeCircularException(String end, Stack stk) {
+		StringBuffer sb = new StringBuffer("Circular dependency: ");
+		sb.append(end);
+		String c;
+		do {
+			c = (String) stk.pop();
+			sb.append(" <- ");
+			sb.append(c);
+		} while (!c.equals(end));
+		return new BuildException(new String(sb));
+	}
+
+	/**
+	 * Inherit the id references.
+	 * 
+	 * @param parent
+	 *            the parent project of this project.
+	 */
+	public void inheritIDReferences(Project parent) {
+		parentIdProject = parent;
+	}
+
+	/**
+	 * Add an id reference. Used for broken build files.
+	 * 
+	 * @param id
+	 *            the id to set.
+	 * @param value
+	 *            the value to set it to (Unknown element in this case.
+	 */
+	public void addIdReference(String id, Object value) {
+		idReferences.put(id, value);
+	}
+
+	/**
+	 * Add a reference to the project.
+	 * 
+	 * @param referenceName
+	 *            The name of the reference. Must not be <code>null</code>.
+	 * @param value
+	 *            The value of the reference.
+	 */
+	public void addReference(String referenceName, Object value) {
+		Object old = ((AntRefTable) references).getReal(referenceName);
+		if (old == value) {
+			// no warning, this is not changing anything
+			return;
+		}
+		if (old != null && !(old instanceof UnknownElement)) {
+			log("Overriding previous definition of reference to "
+					+ referenceName, MSG_VERBOSE);
+		}
+		log("Adding reference: " + referenceName, MSG_DEBUG);
+		references.put(referenceName, value);
+	}
+
+	/**
+	 * Return a map of the references in the project (String to Object). The
+	 * returned hashtable is &quot;live&quot; and so must not be modified.
+	 * 
+	 * @return a map of the references in the project (String to Object).
+	 */
+	public Hashtable getReferences() {
+		return references;
+	}
+
+	/**
+	 * Does the project know this reference?
+	 * 
+	 * @since Ant 1.8.0
+	 */
+	public boolean hasReference(String key) {
+		return references.containsKey(key);
+	}
+
+	/**
+	 * Return a map of the references in the project (String to Object). The
+	 * returned hashtable is a copy of the &quot;live&quot; references.
+	 * 
+	 * @return a map of the references in the project (String to Object).
+	 * 
+	 * @since Ant 1.8.1
+	 */
+	public Map getCopyOfReferences() {
+		return new HashMap(references);
+	}
+
+	/**
+	 * Look up a reference by its key (ID).
+	 * 
+	 * @param key
+	 *            The key for the desired reference. Must not be
+	 *            <code>null</code>.
+	 * 
+	 * @return the reference with the specified ID, or <code>null</code> if
+	 *         there is no such reference in the project.
+	 */
+	public Object getReference(String key) {
+		Object ret = references.get(key);
+		if (ret != null) {
+			return ret;
+		}
+		if (!key.equals(MagicNames.REFID_PROPERTY_HELPER)) {
+			try {
+				if (PropertyHelper.getPropertyHelper(this).containsProperties(
+						key)) {
+					log(
+							"Unresolvable reference "
+									+ key
+									+ " might be a misuse of property expansion syntax.",
+							MSG_WARN);
+				}
+			} catch (Exception e) {
+				// ignore
+			}
+		}
+		return ret;
+	}
+
+	/**
+	 * Return a description of the type of the given element, with special
+	 * handling for instances of tasks and data types.
+	 * <p>
+	 * This is useful for logging purposes.
+	 * 
+	 * @param element
+	 *            The element to describe. Must not be <code>null</code>.
+	 * 
+	 * @return a description of the element type.
+	 * 
+	 * @since 1.95, Ant 1.5
+	 */
+	public String getElementName(Object element) {
+		return ComponentHelper.getComponentHelper(this).getElementName(element);
+	}
+
+	/**
+	 * Send a &quot;build started&quot; event to the build listeners for this
+	 * project.
+	 */
+	public void fireBuildStarted() {
+		BuildEvent event = new BuildEvent(this);
+		BuildListener[] currListeners = listeners;
+		for (int i = 0; i < currListeners.length; i++) {
+			currListeners[i].buildStarted(event);
+		}
+	}
+
+	/**
+	 * Send a &quot;build finished&quot; event to the build listeners for this
+	 * project.
+	 * 
+	 * @param exception
+	 *            an exception indicating a reason for a build failure. May be
+	 *            <code>null</code>, indicating a successful build.
+	 */
+	public void fireBuildFinished(Throwable exception) {
+		BuildEvent event = new BuildEvent(this);
+		event.setException(exception);
+		BuildListener[] currListeners = listeners;
+		for (int i = 0; i < currListeners.length; i++) {
+			currListeners[i].buildFinished(event);
+		}
+		// Inform IH to clear the cache
+		IntrospectionHelper.clearCache();
+	}
+
+	/**
+	 * Send a &quot;subbuild started&quot; event to the build listeners for this
+	 * project.
+	 * 
+	 * @since Ant 1.6.2
+	 */
+	public void fireSubBuildStarted() {
+		BuildEvent event = new BuildEvent(this);
+		BuildListener[] currListeners = listeners;
+		for (int i = 0; i < currListeners.length; i++) {
+			if (currListeners[i] instanceof SubBuildListener) {
+				((SubBuildListener) currListeners[i]).subBuildStarted(event);
+			}
+		}
+	}
+
+	/**
+	 * Send a &quot;subbuild finished&quot; event to the build listeners for
+	 * this project.
+	 * 
+	 * @param exception
+	 *            an exception indicating a reason for a build failure. May be
+	 *            <code>null</code>, indicating a successful build.
+	 * 
+	 * @since Ant 1.6.2
+	 */
+	public void fireSubBuildFinished(Throwable exception) {
+		BuildEvent event = new BuildEvent(this);
+		event.setException(exception);
+		BuildListener[] currListeners = listeners;
+		for (int i = 0; i < currListeners.length; i++) {
+			if (currListeners[i] instanceof SubBuildListener) {
+				((SubBuildListener) currListeners[i]).subBuildFinished(event);
+			}
+		}
+	}
+
+	/**
+	 * Send a &quot;target started&quot; event to the build listeners for this
+	 * project.
+	 * 
+	 * @param target
+	 *            The target which is starting to build. Must not be
+	 *            <code>null</code>.
+	 */
+	protected void fireTargetStarted(Target target) {
+		BuildEvent event = new BuildEvent(target);
+		BuildListener[] currListeners = listeners;
+		for (int i = 0; i < currListeners.length; i++) {
+			currListeners[i].targetStarted(event);
+		}
+
+	}
+
+	/**
+	 * Send a &quot;target finished&quot; event to the build listeners for this
+	 * project.
+	 * 
+	 * @param target
+	 *            The target which has finished building. Must not be
+	 *            <code>null</code>.
+	 * @param exception
+	 *            an exception indicating a reason for a build failure. May be
+	 *            <code>null</code>, indicating a successful build.
+	 */
+	protected void fireTargetFinished(Target target, Throwable exception) {
+		BuildEvent event = new BuildEvent(target);
+		event.setException(exception);
+		BuildListener[] currListeners = listeners;
+		for (int i = 0; i < currListeners.length; i++) {
+			currListeners[i].targetFinished(event);
+		}
+
+	}
+
+	/**
+	 * Send a &quot;task started&quot; event to the build listeners for this
+	 * project.
+	 * 
+	 * @param task
+	 *            The target which is starting to execute. Must not be
+	 *            <code>null</code>.
+	 */
+	protected void fireTaskStarted(Task task) {
+		// register this as the current task on the current thread.
+		registerThreadTask(Thread.currentThread(), task);
+		BuildEvent event = new BuildEvent(task);
+		BuildListener[] currListeners = listeners;
+		for (int i = 0; i < currListeners.length; i++) {
+			currListeners[i].taskStarted(event);
+		}
+	}
+
+	/**
+	 * Send a &quot;task finished&quot; event to the build listeners for this
+	 * project.
+	 * 
+	 * @param task
+	 *            The task which has finished executing. Must not be
+	 *            <code>null</code>.
+	 * @param exception
+	 *            an exception indicating a reason for a build failure. May be
+	 *            <code>null</code>, indicating a successful build.
+	 */
+	protected void fireTaskFinished(Task task, Throwable exception) {
+		registerThreadTask(Thread.currentThread(), null);
+		System.out.flush();
+		System.err.flush();
+		BuildEvent event = new BuildEvent(task);
+		event.setException(exception);
+		BuildListener[] currListeners = listeners;
+		for (int i = 0; i < currListeners.length; i++) {
+			currListeners[i].taskFinished(event);
+		}
+
+	}
+
+	/**
+	 * Send a &quot;message logged&quot; event to the build listeners for this
+	 * project.
+	 * 
+	 * @param event
+	 *            The event to send. This should be built up with the
+	 *            appropriate task/target/project by the caller, so that this
+	 *            method can set the message and priority, then send the event.
+	 *            Must not be <code>null</code>.
+	 * @param message
+	 *            The message to send. Should not be <code>null</code>.
+	 * @param priority
+	 *            The priority of the message.
+	 */
+	private void fireMessageLoggedEvent(BuildEvent event, String message,
+			int priority) {
+
+		if (message == null) {
+			message = String.valueOf(message);
+		}
+		if (message.endsWith(StringUtils.LINE_SEP)) {
+			int endIndex = message.length() - StringUtils.LINE_SEP.length();
+			event.setMessage(message.substring(0, endIndex), priority);
+		} else {
+			event.setMessage(message, priority);
+		}
+		if (isLoggingMessage.get() != Boolean.FALSE) {
+			/*
+			 * One of the Listeners has attempted to access System.err or
+			 * System.out.
+			 * 
+			 * We used to throw an exception in this case, but sometimes
+			 * Listeners can't prevent it(like our own Log4jListener which
+			 * invokes getLogger() which in turn wants to write to the console).
+			 * 
+			 * @see http://marc.theaimsgroup.com/?t=110538624200006&r=1&w=2
+			 * 
+			 * We now (Ant 1.6.3 and later) simply swallow the message.
+			 */
+			return;
+		}
+		try {
+			isLoggingMessage.set(Boolean.TRUE);
+			BuildListener[] currListeners = listeners;
+			for (int i = 0; i < currListeners.length; i++) {
+				currListeners[i].messageLogged(event);
+			}
+		} finally {
+			isLoggingMessage.set(Boolean.FALSE);
+		}
+	}
+
+	/**
+	 * Send a &quot;message logged&quot; project level event to the build
+	 * listeners for this project.
+	 * 
+	 * @param project
+	 *            The project generating the event. Should not be
+	 *            <code>null</code>.
+	 * @param message
+	 *            The message to send. Should not be <code>null</code>.
+	 * @param priority
+	 *            The priority of the message.
+	 */
+	protected void fireMessageLogged(Project project, String message,
+			int priority) {
+		fireMessageLogged(project, message, null, priority);
+	}
+
+	/**
+	 * Send a &quot;message logged&quot; project level event to the build
+	 * listeners for this project.
+	 * 
+	 * @param project
+	 *            The project generating the event. Should not be
+	 *            <code>null</code>.
+	 * @param message
+	 *            The message to send. Should not be <code>null</code>.
+	 * @param throwable
+	 *            The exception that caused this message. May be
+	 *            <code>null</code>.
+	 * @param priority
+	 *            The priority of the message.
+	 * @since 1.7
+	 */
+	protected void fireMessageLogged(Project project, String message,
+			Throwable throwable, int priority) {
+		BuildEvent event = new BuildEvent(project);
+		event.setException(throwable);
+		fireMessageLoggedEvent(event, message, priority);
+	}
+
+	/**
+	 * Send a &quot;message logged&quot; target level event to the build
+	 * listeners for this project.
+	 * 
+	 * @param target
+	 *            The target generating the event. Must not be <code>null</code>
+	 *            .
+	 * @param message
+	 *            The message to send. Should not be <code>null</code>.
+	 * @param priority
+	 *            The priority of the message.
+	 */
+	protected void fireMessageLogged(Target target, String message, int priority) {
+		fireMessageLogged(target, message, null, priority);
+	}
+
+	/**
+	 * Send a &quot;message logged&quot; target level event to the build
+	 * listeners for this project.
+	 * 
+	 * @param target
+	 *            The target generating the event. Must not be <code>null</code>
+	 *            .
+	 * @param message
+	 *            The message to send. Should not be <code>null</code>.
+	 * @param throwable
+	 *            The exception that caused this message. May be
+	 *            <code>null</code>.
+	 * @param priority
+	 *            The priority of the message.
+	 * @since 1.7
+	 */
+	protected void fireMessageLogged(Target target, String message,
+			Throwable throwable, int priority) {
+		BuildEvent event = new BuildEvent(target);
+		event.setException(throwable);
+		fireMessageLoggedEvent(event, message, priority);
+	}
+
+	/**
+	 * Send a &quot;message logged&quot; task level event to the build listeners
+	 * for this project.
+	 * 
+	 * @param task
+	 *            The task generating the event. Must not be <code>null</code>.
+	 * @param message
+	 *            The message to send. Should not be <code>null</code>.
+	 * @param priority
+	 *            The priority of the message.
+	 */
+	protected void fireMessageLogged(Task task, String message, int priority) {
+		fireMessageLogged(task, message, null, priority);
+	}
+
+	/**
+	 * Send a &quot;message logged&quot; task level event to the build listeners
+	 * for this project.
+	 * 
+	 * @param task
+	 *            The task generating the event. Must not be <code>null</code>.
+	 * @param message
+	 *            The message to send. Should not be <code>null</code>.
+	 * @param throwable
+	 *            The exception that caused this message. May be
+	 *            <code>null</code>.
+	 * @param priority
+	 *            The priority of the message.
+	 * @since 1.7
+	 */
+	protected void fireMessageLogged(Task task, String message,
+			Throwable throwable, int priority) {
+		BuildEvent event = new BuildEvent(task);
+		event.setException(throwable);
+		fireMessageLoggedEvent(event, message, priority);
+	}
+
+	/**
+	 * Register a task as the current task for a thread. If the task is null,
+	 * the thread's entry is removed.
+	 * 
+	 * @param thread
+	 *            the thread on which the task is registered.
+	 * @param task
+	 *            the task to be registered.
+	 * @since Ant 1.5
+	 */
+	public void registerThreadTask(Thread thread, Task task) {
+		synchronized (threadTasks) {
+			if (task != null) {
+				threadTasks.put(thread, task);
+				threadGroupTasks.put(thread.getThreadGroup(), task);
+			} else {
+				threadTasks.remove(thread);
+				threadGroupTasks.remove(thread.getThreadGroup());
+			}
+		}
+	}
+
+	/**
+	 * Get the current task associated with a thread, if any.
+	 * 
+	 * @param thread
+	 *            the thread for which the task is required.
+	 * @return the task which is currently registered for the given thread or
+	 *         null if no task is registered.
+	 */
+	public Task getThreadTask(Thread thread) {
+		synchronized (threadTasks) {
+			Task task = (Task) threadTasks.get(thread);
+			if (task == null) {
+				ThreadGroup group = thread.getThreadGroup();
+				while (task == null && group != null) {
+					task = (Task) threadGroupTasks.get(group);
+					group = group.getParent();
+				}
+			}
+			return task;
+		}
+	}
+
+	// Should move to a separate public class - and have API to add
+	// listeners, etc.
+	private static class AntRefTable extends Hashtable {
+
+		AntRefTable() {
+			super();
+		}
+
+		/**
+		 * Returns the unmodified original object. This method should be called
+		 * internally to get the &quot;real&quot; object. The normal get method
+		 * will do the replacement of UnknownElement (this is similar with the
+		 * JDNI refs behavior).
+		 */
+		private Object getReal(Object key) {
+			return super.get(key);
+		}
+
+		/**
+		 * Get method for the reference table. It can be used to hook dynamic
+		 * references and to modify some references on the fly--for example for
+		 * delayed evaluation.
+		 * 
+		 * It is important to make sure that the processing that is done inside
+		 * is not calling get indirectly.
+		 * 
+		 * @param key
+		 *            lookup key.
+		 * @return mapped value.
+		 */
+		public Object get(Object key) {
+			// System.out.println("AntRefTable.get " + key);
+			Object o = getReal(key);
+			if (o instanceof UnknownElement) {
+				// Make sure that
+				UnknownElement ue = (UnknownElement) o;
+				ue.maybeConfigure();
+				o = ue.getRealThing();
+			}
+			return o;
+		}
+	}
+
+	/**
+	 * Set a reference to this Project on the parameterized object. Need to set
+	 * the project before other set/add elements are called.
+	 * 
+	 * @param obj
+	 *            the object to invoke setProject(this) on.
+	 */
+	public final void setProjectReference(final Object obj) {
+		if (obj instanceof ProjectComponent) {
+			((ProjectComponent) obj).setProject(this);
+			return;
+		}
+		try {
+			Method method = obj.getClass().getMethod("setProject",
+					new Class[] { Project.class });
+			if (method != null) {
+				method.invoke(obj, new Object[] { this });
+			}
+		} catch (Throwable e) {
+			// ignore this if the object does not have
+			// a set project method or the method
+			// is private/protected.
+		}
+	}
+
+	/**
+	 * Resolve the file relative to the project's basedir and return it as a
+	 * FileResource.
+	 * 
+	 * @param name
+	 *            the name of the file to resolve.
+	 * @return the file resource.
+	 * @since Ant 1.7
+	 */
+	public Resource getResource(String name) {
+		return new FileResource(getBaseDir(), name);
+	}
+}
diff --git a/command-line-debugger/src/main/org/apache/tools/ant/helper/ProjectHelper2.java b/command-line-debugger/src/main/org/apache/tools/ant/helper/ProjectHelper2.java
new file mode 100644
index 0000000..2876598
--- /dev/null
+++ b/command-line-debugger/src/main/org/apache/tools/ant/helper/ProjectHelper2.java
@@ -0,0 +1,1279 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.helper;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ExtensionPoint;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.RuntimeConfigurable;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.UnknownElement;
+import org.apache.tools.ant.DebugTask;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileProvider;
+import org.apache.tools.ant.types.resources.URLProvider;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.apache.tools.zip.ZipFile;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Sax2 based project reader
+ *
+ */
+public class ProjectHelper2 extends ProjectHelper {
+
+    /** Reference holding the (ordered) target Vector */
+    public static final String REFID_TARGETS = "ant.targets";
+
+    /* Stateless */
+
+    // singletons - since all state is in the context
+    private static AntHandler elementHandler = new ElementHandler();
+    private static AntHandler targetHandler = new TargetHandler();
+    private static AntHandler mainHandler = new MainHandler();
+    private static AntHandler projectHandler = new ProjectHandler();
+
+    /** Specific to ProjectHelper2 so not a true Ant "magic name:" */
+    private static final String REFID_CONTEXT = "ant.parsing.context";
+
+    /**
+     * helper for path -> URI and URI -> path conversions.
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Whether this instance of ProjectHelper can parse an Antlib
+     * descriptor given by the URL and return its content as an
+     * UnknownElement ready to be turned into an Antlib task.
+     *
+     * <p>This implementation returns true.</p>
+     *
+     * @since Ant 1.8.0
+     */
+    public boolean canParseAntlibDescriptor(Resource resource) {
+        return true;
+    }
+
+    /**
+     * Parse the given URL as an antlib descriptor and return the
+     * content as something that can be turned into an Antlib task.
+     *
+     * <p>simply delegates to {@link #parseUnknownElement
+     * parseUnknownElement} if the resource provides an URL and throws
+     * an exception otherwise.</p>
+     *
+     * @since Ant 1.8.0
+     */
+    public UnknownElement parseAntlibDescriptor(Project containingProject,
+                                                Resource resource) {
+        URLProvider up = (URLProvider) resource.as(URLProvider.class);
+        if (up == null) {
+            throw new BuildException("Unsupported resource type: " + resource);
+        }
+        return parseUnknownElement(containingProject, up.getURL());
+    }
+
+    /**
+     * Parse an unknown element from a url
+     *
+     * @param project the current project
+     * @param source  the url containing the task
+     * @return a configured task
+     * @exception BuildException if an error occurs
+     */
+    public UnknownElement parseUnknownElement(Project project, URL source)
+        throws BuildException {
+        Target dummyTarget = new Target();
+        dummyTarget.setProject(project);
+
+        AntXMLContext context = new AntXMLContext(project);
+        context.addTarget(dummyTarget);
+        context.setImplicitTarget(dummyTarget);
+
+        parse(context.getProject(), source, new RootHandler(context, elementHandler));
+        Task[] tasks = dummyTarget.getTasks();
+        if (tasks.length != 1) {
+            throw new BuildException("No tasks defined");
+        }
+        return (UnknownElement) tasks[0];
+    }
+
+    /**
+     * Parse a source xml input.
+     *
+     * @param project the current project
+     * @param source  the xml source
+     * @exception BuildException if an error occurs
+     */
+    public void parse(Project project, Object source) throws BuildException {
+        getImportStack().addElement(source);
+        AntXMLContext context = null;
+        context = (AntXMLContext) project.getReference(REFID_CONTEXT);
+        if (context == null) {
+            context = new AntXMLContext(project);
+            project.addReference(REFID_CONTEXT, context);
+            project.addReference(REFID_TARGETS, context.getTargets());
+        }
+        if (getImportStack().size() > 1) {
+            // we are in an imported file.
+            context.setIgnoreProjectTag(true);
+            Target currentTarget = context.getCurrentTarget();
+            Target currentImplicit = context.getImplicitTarget();
+            Map    currentTargets = context.getCurrentTargets();
+            try {
+                Target newCurrent = new Target();
+                newCurrent.setProject(project);
+                newCurrent.setName("");
+                context.setCurrentTarget(newCurrent);
+                context.setCurrentTargets(new HashMap());
+                context.setImplicitTarget(newCurrent);
+                parse(project, source, new RootHandler(context, mainHandler));
+                newCurrent.execute();
+            } finally {
+                context.setCurrentTarget(currentTarget);
+                context.setImplicitTarget(currentImplicit);
+                context.setCurrentTargets(currentTargets);
+            }
+        } else {
+            // top level file
+            context.setCurrentTargets(new HashMap());
+            parse(project, source, new RootHandler(context, mainHandler));
+            // Execute the top-level target
+            context.getImplicitTarget().execute();
+
+            // resolve extensionOf attributes
+            for (Iterator i = getExtensionStack().iterator(); i.hasNext(); ) {
+                String[] extensionInfo = (String[]) i.next();
+                String tgName = extensionInfo[0];
+                String name = extensionInfo[1];
+                OnMissingExtensionPoint missingBehaviour = OnMissingExtensionPoint
+                        .valueOf(extensionInfo[2]);
+                Hashtable projectTargets = project.getTargets();
+                if (!projectTargets.containsKey(tgName)) {
+                    String message = "can't add target " + name
+                        + " to extension-point " + tgName
+                        + " because the extension-point is unknown.";
+                    if (missingBehaviour == OnMissingExtensionPoint.FAIL) {
+                        throw new BuildException(message);
+                    } else if (missingBehaviour == OnMissingExtensionPoint.WARN) {
+                        Target target = (Target) projectTargets.get(name);
+                        context.getProject().log(target,
+                                                 "Warning: " + message,
+                                                 Project.MSG_WARN);
+                    }
+                } else {
+                    Target t = (Target) projectTargets.get(tgName);
+                    if (!(t instanceof ExtensionPoint)) {
+                        throw new BuildException("referenced target "
+                                                 + tgName
+                                                 + " is not an extension-point");
+                    }
+                    t.addDependency(name);
+                }
+            }
+        }
+    }
+
+    /**
+     * Parses the project file, configuring the project as it goes.
+     *
+     * @param project the current project
+     * @param source  the xml source
+     * @param handler the root handler to use (contains the current context)
+     * @exception BuildException if the configuration is invalid or cannot
+     *                           be read
+     */
+    public void parse(Project project, Object source, RootHandler handler) throws BuildException {
+
+        AntXMLContext context = handler.context;
+
+        File buildFile = null;
+        URL  url = null;
+        String buildFileName = null;
+
+        if (source instanceof File) {
+            buildFile = (File) source;
+        } else if (source instanceof URL) {
+            url = (URL) source;
+        } else if (source instanceof Resource) {
+            FileProvider fp =
+                (FileProvider) ((Resource) source).as(FileProvider.class);
+            if (fp != null) {
+                buildFile = fp.getFile();
+            } else {
+                URLProvider up =
+                    (URLProvider) ((Resource) source).as(URLProvider.class);
+                if (up != null) {
+                    url = up.getURL();
+                }
+            }
+        }
+        if (buildFile != null) {
+            buildFile = FILE_UTILS.normalize(buildFile.getAbsolutePath());
+            context.setBuildFile(buildFile);
+            buildFileName = buildFile.toString();
+        } else if (url != null) {
+            try {
+                context.setBuildFile((File) null);
+                context.setBuildFile(url);
+            } catch (java.net.MalformedURLException ex) {
+                throw new BuildException(ex);
+            }
+            buildFileName = url.toString();
+        } else {
+            throw new BuildException("Source " + source.getClass().getName()
+                                     + " not supported by this plugin");
+        }
+        InputStream inputStream = null;
+        InputSource inputSource = null;
+        ZipFile zf = null;
+
+        try {
+            /**
+             * SAX 2 style parser used to parse the given file.
+             */
+            XMLReader parser = JAXPUtils.getNamespaceXMLReader();
+
+            String uri = null;
+            if (buildFile != null) {
+                uri = FILE_UTILS.toURI(buildFile.getAbsolutePath());
+                inputStream = new FileInputStream(buildFile);
+            } else {
+                uri = url.toString();
+                int pling = -1;
+                if (uri.startsWith("jar:file")
+                    && (pling = uri.indexOf("!/")) > -1) {
+                    zf = new ZipFile(org.apache.tools.ant.launch.Locator
+                                     .fromJarURI(uri), "UTF-8");
+                    inputStream =
+                        zf.getInputStream(zf.getEntry(uri.substring(pling + 1)));
+                } else {
+                    inputStream = url.openStream();
+                }
+            }
+
+            inputSource = new InputSource(inputStream);
+            if (uri != null) {
+                inputSource.setSystemId(uri);
+            }
+            project.log("parsing buildfile " + buildFileName + " with URI = "
+                        + uri + (zf != null ? " from a zip file" : ""),
+                        Project.MSG_VERBOSE);
+
+            DefaultHandler hb = handler;
+
+            parser.setContentHandler(hb);
+            parser.setEntityResolver(hb);
+            parser.setErrorHandler(hb);
+            parser.setDTDHandler(hb);
+            parser.parse(inputSource);
+        } catch (SAXParseException exc) {
+            Location location = new Location(exc.getSystemId(), exc.getLineNumber(), exc
+                                             .getColumnNumber());
+
+            Throwable t = exc.getException();
+            if (t instanceof BuildException) {
+                BuildException be = (BuildException) t;
+                if (be.getLocation() == Location.UNKNOWN_LOCATION) {
+                    be.setLocation(location);
+                }
+                throw be;
+            }
+            throw new BuildException(exc.getMessage(), t == null ? exc : t, location);
+        } catch (SAXException exc) {
+            Throwable t = exc.getException();
+            if (t instanceof BuildException) {
+                throw (BuildException) t;
+            }
+            throw new BuildException(exc.getMessage(), t == null ? exc : t);
+        } catch (FileNotFoundException exc) {
+            throw new BuildException(exc);
+        } catch (UnsupportedEncodingException exc) {
+            throw new BuildException("Encoding of project file " + buildFileName + " is invalid.",
+                                     exc);
+        } catch (IOException exc) {
+            throw new BuildException("Error reading project file " + buildFileName + ": "
+                                     + exc.getMessage(), exc);
+        } finally {
+            FileUtils.close(inputStream);
+            ZipFile.closeQuietly(zf);
+        }
+    }
+
+    /**
+     * Returns main handler
+     * @return main handler
+     */
+    protected static AntHandler getMainHandler() {
+        return mainHandler;
+    }
+
+    /**
+     * Sets main handler
+     * @param handler  new main handler
+     */
+    protected static void setMainHandler(AntHandler handler) {
+        mainHandler = handler;
+    }
+
+    /**
+     * Returns project handler
+     * @return project handler
+     */
+    protected static AntHandler getProjectHandler() {
+        return projectHandler;
+    }
+
+    /**
+     * Sets project handler
+     * @param handler  new project handler
+     */
+    protected static void setProjectHandler(AntHandler handler) {
+        projectHandler = handler;
+    }
+
+    /**
+     * Returns target handler
+     * @return target handler
+     */
+    protected static AntHandler getTargetHandler() {
+        return targetHandler;
+    }
+
+    /**
+     * Sets target handler
+     * @param handler  new target handler
+     */
+    protected static void setTargetHandler(AntHandler handler) {
+        targetHandler = handler;
+    }
+
+    /**
+     * Returns element handler
+     * @return element handler
+     */
+    protected static AntHandler getElementHandler() {
+        return elementHandler;
+    }
+
+    /**
+     * Sets element handler
+     * @param handler  new element handler
+     */
+    protected static void setElementHandler(AntHandler handler) {
+        elementHandler = handler;
+    }
+
+    /**
+     * The common superclass for all SAX event handlers used to parse
+     * the configuration file.
+     *
+     * The context will hold all state information. At each time
+     * there is one active handler for the current element. It can
+     * use onStartChild() to set an alternate handler for the child.
+     */
+    public static class AntHandler  {
+        /**
+         * Handles the start of an element. This base implementation does
+         * nothing.
+         *
+         * @param uri the namespace URI for the tag
+         * @param tag The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name of the element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * @param context The context that this element is in.
+         *
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public void onStartElement(String uri, String tag, String qname, Attributes attrs,
+                                   AntXMLContext context) throws SAXParseException {
+        }
+
+        /**
+         * Handles the start of an element. This base implementation just
+         * throws an exception - you must override this method if you expect
+         * child elements.
+         *
+         * @param uri The namespace uri for this element.
+         * @param tag The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * @param context The current context.
+         * @return a handler (in the derived classes)
+         *
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs,
+                                       AntXMLContext context) throws SAXParseException {
+            throw new SAXParseException("Unexpected element \"" + qname + " \"", context
+                                        .getLocator());
+        }
+
+        /**
+         * Handle the end of a element.
+         *
+         * @param uri the namespace uri of the element
+         * @param tag the tag of the element
+         * @param qname the qualified name of the element
+         * @param context the current context
+         * @exception SAXParseException if an error occurs
+         */
+        public void onEndChild(String uri, String tag, String qname, AntXMLContext context)
+            throws SAXParseException {
+        }
+
+        /**
+         * This method is called when this element and all elements nested into it have been
+         * handled. I.e., this happens at the &lt;/end_tag_of_the_element&gt;.
+         * @param uri the namespace uri for this element
+         * @param tag the element name
+         * @param context the current context
+         */
+        public void onEndElement(String uri, String tag, AntXMLContext context) {
+        }
+
+        /**
+         * Handles text within an element. This base implementation just
+         * throws an exception, you must override it if you expect content.
+         *
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         * @param context The current context.
+         *
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public void characters(char[] buf, int start, int count, AntXMLContext context)
+            throws SAXParseException {
+            String s = new String(buf, start, count).trim();
+
+            if (s.length() > 0) {
+                throw new SAXParseException("Unexpected text \"" + s + "\"", context.getLocator());
+            }
+        }
+
+        /**
+         * Will be called every time a namespace is reached.
+         * It'll verify if the ns was processed, and if not load the task definitions.
+         * @param uri The namespace uri.
+         */
+        protected void checkNamespace(String uri) {
+        }
+    }
+
+    /**
+     * Handler for ant processing. Uses a stack of AntHandlers to
+     * implement each element ( the original parser used a recursive behavior,
+     * with the implicit execution stack )
+     */
+    public static class RootHandler extends DefaultHandler {
+        private Stack antHandlers = new Stack();
+        private AntHandler currentHandler = null;
+        private AntXMLContext context;
+
+        /**
+         * Creates a new RootHandler instance.
+         *
+         * @param context The context for the handler.
+         * @param rootHandler The handler for the root element.
+         */
+        public RootHandler(AntXMLContext context, AntHandler rootHandler) {
+            currentHandler = rootHandler;
+            antHandlers.push(currentHandler);
+            this.context = context;
+        }
+
+        /**
+         * Returns the current ant handler object.
+         * @return the current ant handler.
+         */
+        public AntHandler getCurrentAntHandler() {
+            return currentHandler;
+        }
+
+        /**
+         * Resolves file: URIs relative to the build file.
+         *
+         * @param publicId The public identifier, or <code>null</code>
+         *                 if none is available. Ignored in this
+         *                 implementation.
+         * @param systemId The system identifier provided in the XML
+         *                 document. Will not be <code>null</code>.
+         * @return an inputsource for this identifier
+         */
+        public InputSource resolveEntity(String publicId, String systemId) {
+
+            context.getProject().log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
+
+            if (systemId.startsWith("file:")) {
+                String path = FILE_UTILS.fromURI(systemId);
+
+                File file = new File(path);
+                if (!file.isAbsolute()) {
+                    file = FILE_UTILS.resolveFile(context.getBuildFileParent(), path);
+                    context.getProject().log(
+                                             "Warning: '" + systemId + "' in " + context.getBuildFile()
+                                             + " should be expressed simply as '" + path.replace('\\', '/')
+                                             + "' for compliance with other XML tools", Project.MSG_WARN);
+                }
+                context.getProject().log("file=" + file, Project.MSG_DEBUG);
+                try {
+                    InputSource inputSource = new InputSource(new FileInputStream(file));
+                    inputSource.setSystemId(FILE_UTILS.toURI(file.getAbsolutePath()));
+                    return inputSource;
+                } catch (FileNotFoundException fne) {
+                    context.getProject().log(file.getAbsolutePath() + " could not be found",
+                                             Project.MSG_WARN);
+                }
+
+            }
+            // use default if not file or file not found
+            context.getProject().log("could not resolve systemId", Project.MSG_DEBUG);
+            return null;
+        }
+
+        /**
+         * Handles the start of a project element. A project handler is created
+         * and initialised with the element name and attributes.
+         *
+         * @param uri The namespace uri for this element.
+         * @param tag The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         *
+         * @exception org.xml.sax.SAXParseException if the tag given is not
+         *                              <code>"project"</code>
+         */
+        public void startElement(String uri, String tag, String qname, Attributes attrs)
+            throws SAXParseException {
+            AntHandler next = currentHandler.onStartChild(uri, tag, qname, attrs, context);
+            antHandlers.push(currentHandler);
+            currentHandler = next;
+            currentHandler.onStartElement(uri, tag, qname, attrs, context);
+        }
+
+        /**
+         * Sets the locator in the project helper for future reference.
+         *
+         * @param locator The locator used by the parser.
+         *                Will not be <code>null</code>.
+         */
+        public void setDocumentLocator(Locator locator) {
+            context.setLocator(locator);
+        }
+
+        /**
+         * Handles the end of an element. Any required clean-up is performed
+         * by the onEndElement() method and then the original handler is restored to the parser.
+         *
+         * @param uri  The namespace URI for this element.
+         * @param name The name of the element which is ending.
+         *             Will not be <code>null</code>.
+         * @param qName The qualified name for this element.
+         *
+         * @exception SAXException in case of error (not thrown in this implementation)
+         */
+        public void endElement(String uri, String name, String qName) throws SAXException {
+            currentHandler.onEndElement(uri, name, context);
+            AntHandler prev = (AntHandler) antHandlers.pop();
+            currentHandler = prev;
+            if (currentHandler != null) {
+                currentHandler.onEndChild(uri, name, qName, context);
+            }
+        }
+
+        /**
+         * Handle text within an element, calls currentHandler.characters.
+         *
+         * @param buf  A character array of the test.
+         * @param start The start offset in the array.
+         * @param count The number of characters to read.
+         * @exception SAXParseException if an error occurs
+         */
+        public void characters(char[] buf, int start, int count) throws SAXParseException {
+            currentHandler.characters(buf, start, count, context);
+        }
+
+        /**
+         * Start a namespace prefix to uri mapping
+         *
+         * @param prefix the namespace prefix
+         * @param uri the namespace uri
+         */
+        public void startPrefixMapping(String prefix, String uri) {
+            context.startPrefixMapping(prefix, uri);
+        }
+
+        /**
+         * End a namepace prefix to uri mapping
+         *
+         * @param prefix the prefix that is not mapped anymore
+         */
+        public void endPrefixMapping(String prefix) {
+            context.endPrefixMapping(prefix);
+        }
+    }
+
+    /**
+     * The main handler - it handles the &lt;project&gt; tag.
+     *
+     * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler
+     */
+    public static class MainHandler extends AntHandler {
+
+        /**
+         * Handle the project tag
+         *
+         * @param uri The namespace uri.
+         * @param name The element tag.
+         * @param qname The element qualified name.
+         * @param attrs The attributes of the element.
+         * @param context The current context.
+         * @return The project handler that handles subelements of project
+         * @exception SAXParseException if the qualified name is not "project".
+         */
+        public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
+                                       AntXMLContext context) throws SAXParseException {
+            if (name.equals("project")
+                && (uri.equals("") || uri.equals(ANT_CORE_URI))) {
+                return ProjectHelper2.projectHandler;
+            }
+            if (name.equals(qname)) {
+                throw new SAXParseException("Unexpected element \"{" + uri
+                                            + "}" + name + "\" {" + ANT_CORE_URI + "}" + name, context.getLocator());
+            }
+            throw new SAXParseException("Unexpected element \"" + qname
+                                        + "\" " + name, context.getLocator());
+        }
+    }
+
+    /**
+     * Handler for the top level "project" element.
+     */
+    public static class ProjectHandler extends AntHandler {
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. The attributes which
+         * this handler can deal with are: <code>"default"</code>,
+         * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
+         *
+         * @param uri The namespace URI for this element.
+         * @param tag Name of the element which caused this handler
+         *            to be created. Should not be <code>null</code>.
+         *            Ignored in this implementation.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         * @param context The current context.
+         *
+         * @exception SAXParseException if an unexpected attribute is
+         *            encountered or if the <code>"default"</code> attribute
+         *            is missing.
+         */
+        public void onStartElement(String uri, String tag, String qname, Attributes attrs,
+                                   AntXMLContext context) throws SAXParseException {
+            String baseDir = null;
+            boolean nameAttributeSet = false;
+
+            Project project = context.getProject();
+            // Set the location of the implicit target associated with the project tag
+            context.getImplicitTarget().setLocation(new Location(context.getLocator()));
+
+            /** XXX I really don't like this - the XML processor is still
+             * too 'involved' in the processing. A better solution (IMO)
+             * would be to create UE for Project and Target too, and
+             * then process the tree and have Project/Target deal with
+             * its attributes ( similar with Description ).
+             *
+             * If we eventually switch to ( or add support for ) DOM,
+             * things will work smoothly - UE can be avoided almost completely
+             * ( it could still be created on demand, for backward compatibility )
+             */
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String attrUri = attrs.getURI(i);
+                if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
+                    continue; // Ignore attributes from unknown uris
+                }
+                String key = attrs.getLocalName(i);
+                String value = attrs.getValue(i);
+
+                if (key.equals("default")) {
+                    if (value != null && !value.equals("")) {
+                        if (!context.isIgnoringProjectTag()) {
+                            project.setDefault(value);
+                        }
+                    }
+                } else if (key.equals("name")) {
+                    if (value != null) {
+                        context.setCurrentProjectName(value);
+                        nameAttributeSet = true;
+                        if (!context.isIgnoringProjectTag()) {
+                            project.setName(value);
+                            project.addReference(value, project);
+                        } else if (isInIncludeMode()) {
+                            if (!"".equals(value)
+                                && (getCurrentTargetPrefix() == null
+                                    || getCurrentTargetPrefix().length() == 0)
+                                ) {
+                                // help nested include tasks
+                                setCurrentTargetPrefix(value);
+                            }
+                        }
+                    }
+                } else if (key.equals("id")) {
+                    if (value != null) {
+                        // What's the difference between id and name ?
+                        if (!context.isIgnoringProjectTag()) {
+                            project.addReference(value, project);
+                        }
+                    }
+                } else if (key.equals("basedir")) {
+                    if (!context.isIgnoringProjectTag()) {
+                        baseDir = value;
+                    }
+                } else {
+                    // XXX ignore attributes in a different NS ( maybe store them ? )
+                    throw new SAXParseException("Unexpected attribute \"" + attrs.getQName(i)
+                                                + "\"", context.getLocator());
+                }
+            }
+
+            // XXX Move to Project ( so it is shared by all helpers )
+            String antFileProp =
+                MagicNames.ANT_FILE + "." + context.getCurrentProjectName();
+            String dup = project.getProperty(antFileProp);
+            String typeProp =
+                MagicNames.ANT_FILE_TYPE + "." + context.getCurrentProjectName();
+            String dupType = project.getProperty(typeProp);
+            if (dup != null && nameAttributeSet) {
+                Object dupFile = null;
+                Object contextFile = null;
+                if (MagicNames.ANT_FILE_TYPE_URL.equals(dupType)) {
+                    try {
+                        dupFile = new URL(dup);
+                    } catch (java.net.MalformedURLException mue) {
+                        throw new BuildException("failed to parse "
+                                                 + dup + " as URL while looking"
+                                                 + " at a duplicate project"
+                                                 + " name.", mue);
+                    }
+                    contextFile = context.getBuildFileURL();
+                } else {
+                    dupFile = new File(dup);
+                    contextFile = context.getBuildFile();
+                }
+
+                if (context.isIgnoringProjectTag() && !dupFile.equals(contextFile)) {
+                    project.log("Duplicated project name in import. Project "
+                                + context.getCurrentProjectName() + " defined first in " + dup
+                                + " and again in " + contextFile, Project.MSG_WARN);
+                }
+            }
+            if (nameAttributeSet) {
+                if (context.getBuildFile() != null) {
+                    project.setUserProperty(antFileProp,
+                                            context.getBuildFile().toString());
+                    project.setUserProperty(typeProp,
+                                            MagicNames.ANT_FILE_TYPE_FILE);
+                } else if (context.getBuildFileURL() != null) {
+                    project.setUserProperty(antFileProp,
+                                            context.getBuildFileURL().toString());
+                    project.setUserProperty(typeProp,
+                                            MagicNames.ANT_FILE_TYPE_URL);
+                }
+            }
+            if (context.isIgnoringProjectTag()) {
+                // no further processing
+                return;
+            }
+            // set explicitly before starting ?
+            if (project.getProperty("basedir") != null) {
+                project.setBasedir(project.getProperty("basedir"));
+            } else {
+                // Default for baseDir is the location of the build file.
+                if (baseDir == null) {
+                    project.setBasedir(context.getBuildFileParent().getAbsolutePath());
+                } else {
+                    // check whether the user has specified an absolute path
+                    if ((new File(baseDir)).isAbsolute()) {
+                        project.setBasedir(baseDir);
+                    } else {
+                        project.setBaseDir(FILE_UTILS.resolveFile(context.getBuildFileParent(),
+                                                                  baseDir));
+                    }
+                }
+            }
+            project.addTarget("", context.getImplicitTarget());
+            context.setCurrentTarget(context.getImplicitTarget());
+        }
+
+        /**
+         * Handles the start of a top-level element within the project. An
+         * appropriate handler is created and initialised with the details
+         * of the element.
+         *
+         * @param uri The namespace URI for this element.
+         * @param name The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * @param context The context for this element.
+         * @return a target or an element handler.
+         *
+         * @exception org.xml.sax.SAXParseException if the tag given is not
+         *            <code>"taskdef"</code>, <code>"typedef"</code>,
+         *            <code>"property"</code>, <code>"target"</code>,
+         *            <code>"extension-point"</code>
+         *            or a data type definition
+         */
+        public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
+                                       AntXMLContext context) throws SAXParseException {
+            return (name.equals("target") || name.equals("extension-point"))
+                && (uri.equals("") || uri.equals(ANT_CORE_URI))
+                ? ProjectHelper2.targetHandler : ProjectHelper2.elementHandler;
+        }
+    }
+
+    /**
+     * Handler for "target" and "extension-point" elements.
+     */
+    public static class TargetHandler extends AntHandler {
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. The attributes which
+         * this handler can deal with are: <code>"name"</code>,
+         * <code>"depends"</code>, <code>"if"</code>,
+         * <code>"unless"</code>, <code>"id"</code> and
+         * <code>"description"</code>.
+         *
+         * @param uri The namespace URI for this element.
+         * @param tag Name of the element which caused this handler
+         *            to be created. Should not be <code>null</code>.
+         *            Ignored in this implementation.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         * @param context The current context.
+         *
+         * @exception SAXParseException if an unexpected attribute is encountered
+         *            or if the <code>"name"</code> attribute is missing.
+         */
+        public void onStartElement(String uri, String tag, String qname, Attributes attrs,
+                                   AntXMLContext context) throws SAXParseException {
+            String name = null;
+            String depends = "";
+            String extensionPoint = null;
+            OnMissingExtensionPoint extensionPointMissing = null;
+
+            Project project = context.getProject();
+            Target target = "target".equals(tag)
+                ? new Target() : new ExtensionPoint();
+            target.setProject(project);
+            target.setLocation(new Location(context.getLocator()));
+            context.addTarget(target);
+            boolean isTarget = false;
+            if(!(target instanceof ExtensionPoint)) {
+            	isTarget = true;
+            }
+            
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String attrUri = attrs.getURI(i);
+                if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
+                    continue; // Ignore attributes from unknown uris
+                }
+                String key = attrs.getLocalName(i);
+                String value = attrs.getValue(i);
+
+                if (key.equals("name")) {
+                    name = value;
+                    if ("".equals(name)) {
+                        throw new BuildException("name attribute must " + "not be empty");
+                    }
+                } else if (key.equals("depends")) {
+                    depends = value;
+                } else if (key.equals("if")) {
+                    target.setIf(value);
+                } else if (key.equals("unless")) {
+                    target.setUnless(value);
+                } else if (key.equals("id")) {
+                    if (value != null && !value.equals("")) {
+                        context.getProject().addReference(value, target);
+                    }
+                } else if (key.equals("description")) {
+                    target.setDescription(value);
+                } else if (key.equals("extensionOf")) {
+                    extensionPoint = value;
+                } else if (key.equals("onMissingExtensionPoint")) {
+                    try {
+                        extensionPointMissing = OnMissingExtensionPoint.valueOf(value);
+                    } catch (IllegalArgumentException e) {
+                        throw new BuildException("Invalid onMissingExtensionPoint " + value);
+                    }
+                } else {
+                    throw new SAXParseException("Unexpected attribute \"" + key + "\"", context
+                                                .getLocator());
+                }
+            }
+
+            if (name == null) {
+                throw new SAXParseException("target element appears without a name attribute",
+                                            context.getLocator());
+            }
+
+            String prefix = null;
+            boolean isInIncludeMode =
+                context.isIgnoringProjectTag() && isInIncludeMode();
+            String sep = getCurrentPrefixSeparator();
+
+            if (isInIncludeMode) {
+                prefix = getTargetPrefix(context);
+                if (prefix == null) {
+                    throw new BuildException("can't include build file "
+                                             + context.getBuildFileURL()
+                                             + ", no as attribute has been given"
+                                             + " and the project tag doesn't"
+                                             + " specify a name attribute");
+                }
+                name = prefix + sep + name;
+            }
+
+            // Check if this target is in the current build file
+            if (context.getCurrentTargets().get(name) != null) {
+                throw new BuildException("Duplicate target '" + name + "'",
+                                         target.getLocation());
+            }
+            Hashtable projectTargets = project.getTargets();
+            boolean   usedTarget = false;
+            // If the name has not already been defined define it
+            if (projectTargets.containsKey(name)) {
+                project.log("Already defined in main or a previous import, ignore " + name,
+                            Project.MSG_VERBOSE);
+            } else {
+                target.setName(name);
+                context.getCurrentTargets().put(name, target);
+                project.addOrReplaceTarget(name, target);
+                usedTarget = true;
+            }
+
+            if (depends.length() > 0) {
+                if (!isInIncludeMode) {
+                    target.setDepends(depends);
+                } else {
+                    for (Iterator iter =
+                             Target.parseDepends(depends, name, "depends")
+                             .iterator();
+                         iter.hasNext(); ) {
+                        target.addDependency(prefix + sep + iter.next());
+                    }
+                }
+            }
+
+        	if(isTarget && name.equals(project.getBreakAt())) {
+        		// If the current element is a target and it is the same one as specified
+        		// for Ant to suspend execution at, then add an internal dependency on
+        		// the Debug Target
+        		DebugTask.createDebugTarget(project);
+        		
+        		// add this dependency to the end of the dependency list so that this target 
+        		// executes immediately ahead of the -breakAt target
+        		target.addDependency(DebugTask.DEBUG_TARGET_NAME);
+        	}
+
+            if (!isInIncludeMode && context.isIgnoringProjectTag()
+                && (prefix = getTargetPrefix(context)) != null) {
+                // In an imported file (and not completely
+                // ignoring the project tag or having a preconfigured prefix)
+                String newName = prefix + sep + name;
+                Target newTarget = usedTarget ? new Target(target) : target;
+                newTarget.setName(newName);
+                context.getCurrentTargets().put(newName, newTarget);
+                project.addOrReplaceTarget(newName, newTarget);
+            }
+            if (extensionPointMissing != null && extensionPoint == null) {
+                throw new BuildException("onMissingExtensionPoint attribute cannot " +
+                                         "be specified unless extensionOf is specified", 
+                                         target.getLocation());
+
+            }
+            if (extensionPoint != null) {
+                ProjectHelper helper =
+                    (ProjectHelper) context.getProject().
+                    getReference(ProjectHelper.PROJECTHELPER_REFERENCE);
+                for (Iterator iter =
+                         Target.parseDepends(extensionPoint, name, "extensionOf")
+                         .iterator();
+                     iter.hasNext(); ) {
+                    String tgName = (String) iter.next();
+                    if (isInIncludeMode()) {
+                        tgName = prefix + sep + tgName;
+                    }
+                    if (extensionPointMissing == null) {
+                        extensionPointMissing = OnMissingExtensionPoint.FAIL;
+                    }
+                    // defer extensionpoint resolution until the full
+                    // import stack has been processed
+                    helper.getExtensionStack().add(new String[] {
+                            tgName, name, extensionPointMissing.name() });
+                }
+            }
+        }
+
+        private String getTargetPrefix(AntXMLContext context) {
+            String configuredValue = getCurrentTargetPrefix();
+            if (configuredValue != null && configuredValue.length() == 0) {
+                configuredValue = null;
+            }
+            if (configuredValue != null) {
+                return configuredValue;
+            }
+
+            String projectName = context.getCurrentProjectName();
+            if ("".equals(projectName)) {
+                projectName = null;
+            }
+
+            return projectName;
+        }
+
+        /**
+         * Handles the start of an element within a target.
+         *
+         * @param uri The namespace URI for this element.
+         * @param name The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * @param context The current context.
+         * @return an element handler.
+         *
+         * @exception SAXParseException if an error occurs when initialising
+         *                              the appropriate child handler
+         */
+        public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
+                                       AntXMLContext context) throws SAXParseException {
+            return ProjectHelper2.elementHandler;
+        }
+
+        /**
+         * Handle the end of the project, sets the current target of the
+         * context to be the implicit target.
+         *
+         * @param uri The namespace URI of the element.
+         * @param tag The name of the element.
+         * @param context The current context.
+         */
+        public void onEndElement(String uri, String tag, AntXMLContext context) {
+            context.setCurrentTarget(context.getImplicitTarget());
+        }
+    }
+
+    /**
+     * Handler for all project elements ( tasks, data types )
+     */
+    public static class ElementHandler extends AntHandler {
+
+        /**
+         * Constructor.
+         */
+        public ElementHandler() {
+        }
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. This configures
+         * the element with its attributes and sets it up with
+         * its parent container (if any). Nested elements are then
+         * added later as the parser encounters them.
+         *
+         * @param uri The namespace URI for this element.
+         * @param tag Name of the element which caused this handler
+         *            to be created. Must not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         * @param context The current context.
+         *
+         * @exception SAXParseException in case of error (not thrown in
+         *                              this implementation)
+         */
+        public void onStartElement(String uri, String tag, String qname, Attributes attrs,
+                                   AntXMLContext context) throws SAXParseException {
+            RuntimeConfigurable parentWrapper = context.currentWrapper();
+            Object parent = null;
+
+            if (parentWrapper != null) {
+                parent = parentWrapper.getProxy();
+            }
+
+            /* UnknownElement is used for tasks and data types - with
+               delayed eval */
+            UnknownElement task = new UnknownElement(tag);
+            task.setProject(context.getProject());
+            task.setNamespace(uri);
+            task.setQName(qname);
+            task.setTaskType(ProjectHelper.genComponentName(task.getNamespace(), tag));
+            task.setTaskName(qname);
+
+            Location location = new Location(context.getLocator().getSystemId(), context
+                                             .getLocator().getLineNumber(), context.getLocator().getColumnNumber());
+            task.setLocation(location);
+            task.setOwningTarget(context.getCurrentTarget());
+
+            if (parent != null) {
+                // Nested element
+                ((UnknownElement) parent).addChild(task);
+            }  else {
+                // Task included in a target ( including the default one ).
+                context.getCurrentTarget().addTask(task);
+            }
+
+            context.configureId(task, attrs);
+
+            // container.addTask(task);
+            // This is a nop in UE: task.init();
+
+            RuntimeConfigurable wrapper = new RuntimeConfigurable(task, task.getTaskName());
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String name = attrs.getLocalName(i);
+                String attrUri = attrs.getURI(i);
+                if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
+                    name = attrUri + ":" + attrs.getQName(i);
+                }
+                String value = attrs.getValue(i);
+                // PR: Hack for ant-type value
+                //  an ant-type is a component name which can
+                // be namespaced, need to extract the name
+                // and convert from qualified name to uri/name
+                if (ANT_TYPE.equals(name)
+                    || (ANT_CORE_URI.equals(attrUri)
+                        && ANT_TYPE.equals(attrs.getLocalName(i)))) {
+                    name = ANT_TYPE;
+                    int index = value.indexOf(":");
+                    if (index >= 0) {
+                        String prefix = value.substring(0, index);
+                        String mappedUri = context.getPrefixMapping(prefix);
+                        if (mappedUri == null) {
+                            throw new BuildException("Unable to find XML NS prefix \"" + prefix
+                                                     + "\"");
+                        }
+                        value = ProjectHelper.genComponentName(mappedUri, value
+                                                               .substring(index + 1));
+                    }
+                }
+                wrapper.setAttribute(name, value);
+            }
+            if (parentWrapper != null) {
+                parentWrapper.addChild(wrapper);
+            }
+            context.pushWrapper(wrapper);
+        }
+
+        /**
+         * Adds text to the task, using the wrapper
+         *
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         * @param context The current context.
+         *
+         * @exception SAXParseException if the element doesn't support text
+         *
+         * @see ProjectHelper#addText(Project,java.lang.Object,char[],int,int)
+         */
+        public void characters(char[] buf, int start, int count,
+                               AntXMLContext context) throws SAXParseException {
+            RuntimeConfigurable wrapper = context.currentWrapper();
+            wrapper.addText(buf, start, count);
+        }
+
+        /**
+         * Handles the start of an element within a target. Task containers
+         * will always use another task handler, and all other tasks
+         * will always use a nested element handler.
+         *
+         * @param uri The namespace URI for this element.
+         * @param tag The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * @param context The current context.
+         * @return The handler for elements.
+         *
+         * @exception SAXParseException if an error occurs when initialising
+         *                              the appropriate child handler
+         */
+        public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs,
+                                       AntXMLContext context) throws SAXParseException {
+            return ProjectHelper2.elementHandler;
+        }
+
+        /**
+         * Handles the end of the element. This pops the wrapper from
+         * the context.
+         *
+         * @param uri The namespace URI for the element.
+         * @param tag The name of the element.
+         * @param context The current context.
+         */
+        public void onEndElement(String uri, String tag, AntXMLContext context) {
+            context.popWrapper();
+        }
+    }
+}
diff --git a/command-line-debugger/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/command-line-debugger/src/main/org/apache/tools/ant/taskdefs/defaults.properties
new file mode 100644
index 0000000..435a1a2
--- /dev/null
+++ b/command-line-debugger/src/main/org/apache/tools/ant/taskdefs/defaults.properties
@@ -0,0 +1,233 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# standard ant tasks
+ant=org.apache.tools.ant.taskdefs.Ant
+antcall=org.apache.tools.ant.taskdefs.CallTarget
+antstructure=org.apache.tools.ant.taskdefs.AntStructure
+antversion=org.apache.tools.ant.taskdefs.condition.AntVersion
+apply=org.apache.tools.ant.taskdefs.Transform
+apt=org.apache.tools.ant.taskdefs.Apt
+augment=org.apache.tools.ant.taskdefs.AugmentReference
+available=org.apache.tools.ant.taskdefs.Available
+basename=org.apache.tools.ant.taskdefs.Basename
+bindtargets=org.apache.tools.ant.taskdefs.BindTargets
+buildnumber=org.apache.tools.ant.taskdefs.BuildNumber
+bunzip2=org.apache.tools.ant.taskdefs.BUnzip2
+bzip2=org.apache.tools.ant.taskdefs.BZip2
+checksum=org.apache.tools.ant.taskdefs.Checksum
+chmod=org.apache.tools.ant.taskdefs.Chmod
+classloader=org.apache.tools.ant.taskdefs.Classloader
+componentdef=org.apache.tools.ant.taskdefs.Componentdef
+concat=org.apache.tools.ant.taskdefs.Concat
+condition=org.apache.tools.ant.taskdefs.ConditionTask
+copy=org.apache.tools.ant.taskdefs.Copy
+cvs=org.apache.tools.ant.taskdefs.Cvs
+cvschangelog=org.apache.tools.ant.taskdefs.cvslib.ChangeLogTask
+cvspass=org.apache.tools.ant.taskdefs.CVSPass
+cvstagdiff=org.apache.tools.ant.taskdefs.cvslib.CvsTagDiff
+cvsversion=org.apache.tools.ant.taskdefs.cvslib.CvsVersion
+defaultexcludes=org.apache.tools.ant.taskdefs.DefaultExcludes
+delete=org.apache.tools.ant.taskdefs.Delete
+dependset=org.apache.tools.ant.taskdefs.DependSet
+diagnostics=org.apache.tools.ant.taskdefs.DiagnosticsTask
+dirname=org.apache.tools.ant.taskdefs.Dirname
+ear=org.apache.tools.ant.taskdefs.Ear
+echo=org.apache.tools.ant.taskdefs.Echo
+echoproperties=org.apache.tools.ant.taskdefs.optional.EchoProperties
+echoxml=org.apache.tools.ant.taskdefs.EchoXML
+exec=org.apache.tools.ant.taskdefs.ExecTask
+fail=org.apache.tools.ant.taskdefs.Exit
+filter=org.apache.tools.ant.taskdefs.Filter
+fixcrlf=org.apache.tools.ant.taskdefs.FixCRLF
+#funtest=org.apache.tools.ant.taskdefs.optional.testing.Funtest
+genkey=org.apache.tools.ant.taskdefs.GenerateKey
+get=org.apache.tools.ant.taskdefs.Get
+gunzip=org.apache.tools.ant.taskdefs.GUnzip
+gzip=org.apache.tools.ant.taskdefs.GZip
+hostinfo=org.apache.tools.ant.taskdefs.HostInfo
+import=org.apache.tools.ant.taskdefs.ImportTask
+include=org.apache.tools.ant.taskdefs.ImportTask
+input=org.apache.tools.ant.taskdefs.Input
+jar=org.apache.tools.ant.taskdefs.Jar
+java=org.apache.tools.ant.taskdefs.Java
+javac=org.apache.tools.ant.taskdefs.Javac
+javadoc=org.apache.tools.ant.taskdefs.Javadoc
+length=org.apache.tools.ant.taskdefs.Length
+loadfile=org.apache.tools.ant.taskdefs.LoadFile
+loadproperties=org.apache.tools.ant.taskdefs.LoadProperties
+loadresource=org.apache.tools.ant.taskdefs.LoadResource
+local=org.apache.tools.ant.taskdefs.Local
+macrodef=org.apache.tools.ant.taskdefs.MacroDef
+mail=org.apache.tools.ant.taskdefs.email.EmailTask
+makeurl=org.apache.tools.ant.taskdefs.MakeUrl
+manifest=org.apache.tools.ant.taskdefs.ManifestTask
+manifestclasspath=org.apache.tools.ant.taskdefs.ManifestClassPath
+mkdir=org.apache.tools.ant.taskdefs.Mkdir
+move=org.apache.tools.ant.taskdefs.Move
+nice=org.apache.tools.ant.taskdefs.Nice
+parallel=org.apache.tools.ant.taskdefs.Parallel
+patch=org.apache.tools.ant.taskdefs.Patch
+pathconvert=org.apache.tools.ant.taskdefs.PathConvert
+presetdef=org.apache.tools.ant.taskdefs.PreSetDef
+projecthelper=org.apache.tools.ant.taskdefs.ProjectHelperTask
+property=org.apache.tools.ant.taskdefs.Property
+propertyhelper=org.apache.tools.ant.taskdefs.PropertyHelperTask
+record=org.apache.tools.ant.taskdefs.Recorder
+replace=org.apache.tools.ant.taskdefs.Replace
+resourcecount=org.apache.tools.ant.taskdefs.ResourceCount
+retry=org.apache.tools.ant.taskdefs.Retry
+rmic=org.apache.tools.ant.taskdefs.Rmic
+sequential=org.apache.tools.ant.taskdefs.Sequential
+signjar=org.apache.tools.ant.taskdefs.SignJar
+sleep=org.apache.tools.ant.taskdefs.Sleep
+sql=org.apache.tools.ant.taskdefs.SQLExec
+subant=org.apache.tools.ant.taskdefs.SubAnt
+sync=org.apache.tools.ant.taskdefs.Sync
+tar=org.apache.tools.ant.taskdefs.Tar
+taskdef=org.apache.tools.ant.taskdefs.Taskdef
+tempfile=org.apache.tools.ant.taskdefs.TempFile
+touch=org.apache.tools.ant.taskdefs.Touch
+tstamp=org.apache.tools.ant.taskdefs.Tstamp
+truncate=org.apache.tools.ant.taskdefs.Truncate
+typedef=org.apache.tools.ant.taskdefs.Typedef
+unjar=org.apache.tools.ant.taskdefs.Expand
+untar=org.apache.tools.ant.taskdefs.Untar
+unwar=org.apache.tools.ant.taskdefs.Expand
+unzip=org.apache.tools.ant.taskdefs.Expand
+uptodate=org.apache.tools.ant.taskdefs.UpToDate
+waitfor=org.apache.tools.ant.taskdefs.WaitFor
+war=org.apache.tools.ant.taskdefs.War
+whichresource=org.apache.tools.ant.taskdefs.WhichResource
+xmlproperty=org.apache.tools.ant.taskdefs.XmlProperty
+xslt=org.apache.tools.ant.taskdefs.XSLTProcess
+zip=org.apache.tools.ant.taskdefs.Zip
+
+# optional tasks
+antlr=org.apache.tools.ant.taskdefs.optional.ANTLR
+attrib=org.apache.tools.ant.taskdefs.optional.windows.Attrib
+blgenclient=org.apache.tools.ant.taskdefs.optional.ejb.BorlandGenerateClient
+cab=org.apache.tools.ant.taskdefs.optional.Cab
+cccheckin=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckin
+cccheckout=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckout
+cclock=org.apache.tools.ant.taskdefs.optional.clearcase.CCLock
+ccmcheckin=org.apache.tools.ant.taskdefs.optional.ccm.CCMCheckin
+ccmcheckintask=org.apache.tools.ant.taskdefs.optional.ccm.CCMCheckinDefault
+ccmcheckout=org.apache.tools.ant.taskdefs.optional.ccm.CCMCheckout
+ccmcreatetask=org.apache.tools.ant.taskdefs.optional.ccm.CCMCreateTask
+ccmkattr=org.apache.tools.ant.taskdefs.optional.clearcase.CCMkattr
+ccmkbl=org.apache.tools.ant.taskdefs.optional.clearcase.CCMkbl
+ccmkdir=org.apache.tools.ant.taskdefs.optional.clearcase.CCMkdir
+ccmkelem=org.apache.tools.ant.taskdefs.optional.clearcase.CCMkelem
+ccmklabel=org.apache.tools.ant.taskdefs.optional.clearcase.CCMklabel
+ccmklbtype=org.apache.tools.ant.taskdefs.optional.clearcase.CCMklbtype
+ccmreconfigure=org.apache.tools.ant.taskdefs.optional.ccm.CCMReconfigure
+ccrmtype=org.apache.tools.ant.taskdefs.optional.clearcase.CCRmtype
+ccuncheckout=org.apache.tools.ant.taskdefs.optional.clearcase.CCUnCheckout
+ccunlock=org.apache.tools.ant.taskdefs.optional.clearcase.CCUnlock
+ccupdate=org.apache.tools.ant.taskdefs.optional.clearcase.CCUpdate
+chgrp=org.apache.tools.ant.taskdefs.optional.unix.Chgrp
+chown=org.apache.tools.ant.taskdefs.optional.unix.Chown
+ddcreator=org.apache.tools.ant.taskdefs.optional.ejb.DDCreator
+depend=org.apache.tools.ant.taskdefs.optional.depend.Depend
+ejbc=org.apache.tools.ant.taskdefs.optional.ejb.Ejbc
+ejbjar=org.apache.tools.ant.taskdefs.optional.ejb.EjbJar
+ftp=org.apache.tools.ant.taskdefs.optional.net.FTP
+image=org.apache.tools.ant.taskdefs.optional.image.Image
+iplanet-ejbc=org.apache.tools.ant.taskdefs.optional.ejb.IPlanetEjbcTask
+jarlib-available=org.apache.tools.ant.taskdefs.optional.extension.JarLibAvailableTask
+jarlib-display=org.apache.tools.ant.taskdefs.optional.extension.JarLibDisplayTask
+jarlib-manifest=org.apache.tools.ant.taskdefs.optional.extension.JarLibManifestTask
+jarlib-resolve=org.apache.tools.ant.taskdefs.optional.extension.JarLibResolveTask
+javacc=org.apache.tools.ant.taskdefs.optional.javacc.JavaCC
+javah=org.apache.tools.ant.taskdefs.optional.Javah
+jdepend=org.apache.tools.ant.taskdefs.optional.jdepend.JDependTask
+jjdoc=org.apache.tools.ant.taskdefs.optional.javacc.JJDoc
+jjtree=org.apache.tools.ant.taskdefs.optional.javacc.JJTree
+junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask
+junitreport=org.apache.tools.ant.taskdefs.optional.junit.XMLResultAggregator
+native2ascii=org.apache.tools.ant.taskdefs.optional.Native2Ascii
+netrexxc=org.apache.tools.ant.taskdefs.optional.NetRexxC
+p4add=org.apache.tools.ant.taskdefs.optional.perforce.P4Add
+p4change=org.apache.tools.ant.taskdefs.optional.perforce.P4Change
+p4counter=org.apache.tools.ant.taskdefs.optional.perforce.P4Counter
+p4delete=org.apache.tools.ant.taskdefs.optional.perforce.P4Delete
+p4edit=org.apache.tools.ant.taskdefs.optional.perforce.P4Edit
+p4fstat=org.apache.tools.ant.taskdefs.optional.perforce.P4Fstat
+p4have=org.apache.tools.ant.taskdefs.optional.perforce.P4Have
+p4integrate=org.apache.tools.ant.taskdefs.optional.perforce.P4Integrate
+p4label=org.apache.tools.ant.taskdefs.optional.perforce.P4Label
+p4labelsync=org.apache.tools.ant.taskdefs.optional.perforce.P4Labelsync
+p4reopen=org.apache.tools.ant.taskdefs.optional.perforce.P4Reopen
+p4resolve=org.apache.tools.ant.taskdefs.optional.perforce.P4Resolve
+p4revert=org.apache.tools.ant.taskdefs.optional.perforce.P4Revert
+p4submit=org.apache.tools.ant.taskdefs.optional.perforce.P4Submit
+p4sync=org.apache.tools.ant.taskdefs.optional.perforce.P4Sync
+propertyfile=org.apache.tools.ant.taskdefs.optional.PropertyFile
+pvcs=org.apache.tools.ant.taskdefs.optional.pvcs.Pvcs
+replaceregexp=org.apache.tools.ant.taskdefs.optional.ReplaceRegExp
+rexec=org.apache.tools.ant.taskdefs.optional.net.RExecTask
+rpm=org.apache.tools.ant.taskdefs.optional.Rpm
+schemavalidate=org.apache.tools.ant.taskdefs.optional.SchemaValidate
+scp=org.apache.tools.ant.taskdefs.optional.ssh.Scp
+script=org.apache.tools.ant.taskdefs.optional.Script
+scriptdef=org.apache.tools.ant.taskdefs.optional.script.ScriptDef
+serverdeploy=org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+setproxy=org.apache.tools.ant.taskdefs.optional.net.SetProxy
+soscheckin=org.apache.tools.ant.taskdefs.optional.sos.SOSCheckin
+soscheckout=org.apache.tools.ant.taskdefs.optional.sos.SOSCheckout
+sosget=org.apache.tools.ant.taskdefs.optional.sos.SOSGet
+soslabel=org.apache.tools.ant.taskdefs.optional.sos.SOSLabel
+sound=org.apache.tools.ant.taskdefs.optional.sound.SoundTask
+splash=org.apache.tools.ant.taskdefs.optional.splash.SplashTask
+sshexec=org.apache.tools.ant.taskdefs.optional.ssh.SSHExec
+sshsession=org.apache.tools.ant.taskdefs.optional.ssh.SSHSession
+stcheckin=org.apache.tools.ant.taskdefs.optional.starteam.StarTeamCheckin
+stcheckout=org.apache.tools.ant.taskdefs.optional.starteam.StarTeamCheckout
+stlabel=org.apache.tools.ant.taskdefs.optional.starteam.StarTeamLabel
+stlist=org.apache.tools.ant.taskdefs.optional.starteam.StarTeamList
+symlink=org.apache.tools.ant.taskdefs.optional.unix.Symlink
+telnet=org.apache.tools.ant.taskdefs.optional.net.TelnetTask
+translate=org.apache.tools.ant.taskdefs.optional.i18n.Translate
+verifyjar=org.apache.tools.ant.taskdefs.VerifyJar
+vssadd=org.apache.tools.ant.taskdefs.optional.vss.MSVSSADD
+vsscheckin=org.apache.tools.ant.taskdefs.optional.vss.MSVSSCHECKIN
+vsscheckout=org.apache.tools.ant.taskdefs.optional.vss.MSVSSCHECKOUT
+vsscp=org.apache.tools.ant.taskdefs.optional.vss.MSVSSCP
+vsscreate=org.apache.tools.ant.taskdefs.optional.vss.MSVSSCREATE
+vssget=org.apache.tools.ant.taskdefs.optional.vss.MSVSSGET
+vsshistory=org.apache.tools.ant.taskdefs.optional.vss.MSVSSHISTORY
+vsslabel=org.apache.tools.ant.taskdefs.optional.vss.MSVSSLABEL
+wljspc=org.apache.tools.ant.taskdefs.optional.jsp.WLJspc
+wlrun=org.apache.tools.ant.taskdefs.optional.ejb.WLRun
+wlstop=org.apache.tools.ant.taskdefs.optional.ejb.WLStop
+xmlvalidate=org.apache.tools.ant.taskdefs.optional.XMLValidateTask
+
+
+# deprecated ant tasks (kept for back compatibility)
+copydir=org.apache.tools.ant.taskdefs.Copydir
+copyfile=org.apache.tools.ant.taskdefs.Copyfile
+copypath=org.apache.tools.ant.taskdefs.CopyPath
+deltree=org.apache.tools.ant.taskdefs.Deltree
+execon=org.apache.tools.ant.taskdefs.ExecuteOn
+javadoc2=org.apache.tools.ant.taskdefs.Javadoc
+jlink=org.apache.tools.ant.taskdefs.optional.jlink.JlinkTask
+jspc=org.apache.tools.ant.taskdefs.optional.jsp.JspC
+mimemail=org.apache.tools.ant.taskdefs.optional.net.MimeMail
+rename=org.apache.tools.ant.taskdefs.Rename
+renameext=org.apache.tools.ant.taskdefs.optional.RenameExtensions
+starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut
+style=org.apache.tools.ant.taskdefs.XSLTProcess
+debug=org.apache.tools.ant.DebugTask
\ No newline at end of file