element", getLocator());
+ }
+ }
+ if (targetName == null) {
+ throw new SAXParseException("Targets must have a name attribute", locator);
+ }
+ target = new Target(getLocation(locator), targetName);
+ target.setAspects(aspects);
+
+ if (depends != null) {
+ StringTokenizer tokenizer = new StringTokenizer(depends, ",");
+ while (tokenizer.hasMoreTokens()) {
+ String dependency = tokenizer.nextToken();
+ target.addDependency(dependency);
+ }
+ }
+ }
+
+ /*
+ * Process an element within this target. All elements within the target are
+ * treated as tasks.
+ *
+ * @param uri The Namespace URI.
+ * @param localName The local name (without prefix).
+ * @param qualifiedName The qualified name (with prefix)
+ * @param attributes The attributes attached to the element.
+ *
+ * @throws SAXParseException if there is a parsing problem.
+ */
+ public void startElement(String uri, String localName, String qualifiedName,
+ Attributes attributes) throws SAXParseException {
+ // everything is a task
+ TaskHandler taskHandler
+ = new TaskHandler(getXMLReader(), this, getLocator(),
+ attributes, qualifiedName);
+ target.addTask(taskHandler.getTask());
+ }
+
+ /**
+ * Get the target parsed by this handler.
+ *
+ * @return the Target model object parsed by this handler.
+ */
+ public Target getTarget() {
+ return target;
+ }
+ }
+
+ /**
+ * A Task Handler is used to parse tasks.
+ */
+ private class TaskHandler extends ElementHandler {
+ /**
+ * The task being parsed by this handler.
+ */
+ private Task task;
+
+ /**
+ * Create a task handler to parse the Task element
+ *
+ * @param xmlReader the XML parser being used to parse the task element.
+ * @param parent the parent element handler.
+ * @param locator the SAX locator object used to associate elements with source
+ * locations.
+ * @param attributes attributes of the task
+ * @param taskTagName the name of the task.
+ */
+ public TaskHandler(XMLReader xmlReader, ContentHandler parent, Locator locator,
+ Attributes attributes, String taskTagName) {
+ super(xmlReader, parent, locator);
+ task = new Task(getLocation(locator), taskTagName);
+
+ Map aspects = new HashMap();
+ for (int i = 0; i < attributes.getLength(); ++i) {
+ String attributeName = attributes.getQName(i);
+ String attributeValue = attributes.getValue(i);
+ if (attributeName.indexOf(":") != -1) {
+ // potential aspect attribute
+ aspects.put(attributeName, attributeValue);
+ }
+ else {
+ task.addAttribute(attributeName, attributeValue);
+ }
+ }
+ task.setAspects(aspects);
+ }
+
+ /*
+ * Process a nested element within this task. All nested elements within
+ * the task are treated as taskelements.
+ *
+ * @param uri The Namespace URI.
+ * @param localName The local name (without prefix).
+ * @param qualifiedName The qualified name (with prefix)
+ * @param attributes The attributes attached to the element.
+ *
+ * @throws SAXParseException if there is a parsing problem.
+ */
+ public void startElement(String uri, String localName, String qualifiedName,
+ Attributes attributes) throws SAXParseException {
+ // everything within a task is a task element
+ TaskElementHandler taskElementHandler
+ = new TaskElementHandler(getXMLReader(), this, getLocator(),
+ attributes, qualifiedName);
+ task.addTaskElement(taskElementHandler.getTaskElement());
+ }
+
+ public void characters(char[] buf, int start, int end) throws SAXParseException {
+ task.addText(new String(buf, start, end));
+ }
+
+ /**
+ * Get the task that is being parsed
+ *
+ * @return the task being parsed by this task handler.
+ */
+ public Task getTask() {
+ return task;
+ }
+ }
+
+ /**
+ * A Task Element Handler parses the nested elements of tasks.
+ */
+ private class TaskElementHandler extends ElementHandler {
+ /**
+ * The task element being parsed by this handler.
+ */
+ private TaskElement taskElement;
+
+ /**
+ * Create a task element handler to parse a task element
+ *
+ * @param xmlReader the XML parser being used to parse the task element.
+ * @param parent the parent element handler.
+ * @param locator the SAX locator object used to associate elements with source
+ * locations.
+ * @param attributes attributes of the task element
+ * @param elementTagName the name of the task element.
+ */
+ public TaskElementHandler(XMLReader xmlReader, ContentHandler parent, Locator locator,
+ Attributes attributes, String elementTagName) {
+ super(xmlReader, parent, locator);
+ taskElement
+ = new TaskElement(getLocation(locator), elementTagName);
+
+ Map aspects = new HashMap();
+ for (int i = 0; i < attributes.getLength(); ++i) {
+ String attributeName = attributes.getQName(i);
+ String attributeValue = attributes.getValue(i);
+ if (attributeName.indexOf(":") != -1) {
+ // potential aspect attribute
+ aspects.put(attributeName, attributeValue);
+ }
+ else {
+ taskElement.addAttribute(attributeName, attributeValue);
+ }
+ }
+ taskElement.setAspects(aspects);
+ }
+
+ /**
+ * Process a nested element of this task element. All nested elements
+ * of a taskElement are themselves taskElements.
+ *
+ * @param uri The Namespace URI.
+ * @param localName The local name (without prefix).
+ * @param qualifiedName The qualified name (with prefix)
+ * @param attributes The attributes attached to the element.
+ *
+ * @throws SAXParseException if there is a parsing problem.
+ */
+ public void startElement(String uri, String localName, String qualifiedName,
+ Attributes attributes) throws SAXParseException {
+ // everything within a task element is also a task element
+ TaskElementHandler taskElementHandler
+ = new TaskElementHandler(getXMLReader(), this, getLocator(),
+ attributes, qualifiedName);
+ taskElement.addTaskElement(taskElementHandler.getTaskElement());
+ }
+
+ public void characters(char[] buf, int start, int end) throws SAXParseException {
+ taskElement.addText(new String(buf, start, end));
+ }
+
+ /**
+ * Get the task element being parsed by this handler.
+ *
+ * @return the TaskElement being parsed.
+ */
+ public TaskElement getTaskElement() {
+ return taskElement;
+ }
+ }
+
+ /**
+ * A NoProjectReadException is used to indicate that a project
+ * was not read from the particular source. This will happen
+ * if the source is empty.
+ */
+ private class NoProjectReadException extends Exception {
+ }
+}
+
diff --git a/proposal/mutant/src/main/org/apache/ant/frontend/BuildLogger.java b/proposal/mutant/src/main/org/apache/ant/frontend/BuildLogger.java
new file mode 100644
index 000000000..8a654c885
--- /dev/null
+++ b/proposal/mutant/src/main/org/apache/ant/frontend/BuildLogger.java
@@ -0,0 +1,94 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.ant.frontend;
+
+import org.apache.ant.core.execution.*;
+
+import java.io.*;
+
+/**
+ * Interface used by Ant to log the build output.
+ *
+ * A build logger is a build listener which has the 'right' to send output to the
+ * ant log, which is usually System.out unles redirected by the -logfile option.
+ *
+ * @author Conor MacNeill
+ */
+public interface BuildLogger extends BuildListener {
+ /**
+ * Set the msgOutputLevel this logger is to respond to.
+ *
+ * Only messages with a message level lower than or equal to the given level are
+ * output to the log.
+ *
+ * @param level the logging level for the logger.
+ */
+ public void setMessageOutputLevel(int level);
+
+ /**
+ * Set the output stream to which this logger is to send its output.
+ *
+ * @param output the output stream for the logger.
+ */
+ public void setOutputPrintStream(PrintStream output);
+
+ /**
+ * Set the output stream to which this logger is to send error messages.
+ *
+ * @param err the error stream for the logger.
+ */
+ public void setErrorPrintStream(PrintStream err);
+
+}
diff --git a/proposal/mutant/src/main/org/apache/ant/frontend/Commandline.java b/proposal/mutant/src/main/org/apache/ant/frontend/Commandline.java
new file mode 100644
index 000000000..461080d57
--- /dev/null
+++ b/proposal/mutant/src/main/org/apache/ant/frontend/Commandline.java
@@ -0,0 +1,307 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.ant.frontend;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.xml.parsers.*;
+import org.xml.sax.SAXParseException;
+import java.lang.reflect.*;
+
+import org.apache.ant.core.execution.*;
+import org.apache.ant.core.support.*;
+import org.apache.ant.core.xml.*;
+import org.apache.ant.core.config.*;
+import org.apache.ant.core.model.*;
+
+/**
+ * This is the command line front end to end. It drives the core
+ *
+ * @author Conor MacNeill
+ */
+public class Commandline {
+ /** The default build file name */
+ static public final String DEFAULT_BUILD_FILENAME = "build.ant";
+
+ /** Stream that we are using for logging */
+ private PrintStream out = System.out;
+
+ /** Stream that we are using for logging error messages */
+ private PrintStream err = System.err;
+
+ /** Names of classes to add as listeners to project */
+ private List listeners = new ArrayList(2);
+
+ /** The list of targets to be evaluated in this invocation */
+ private List targets = new ArrayList(4);
+
+ /** Our current message output status. Follows Project.MSG_XXX */
+ private int messageOutputLevel = BuildEvent.MSG_VERBOSE;
+
+ /**
+ * This is the build file to run. By default it is a file: type URL
+ * but other URL protocols can be used.
+ */
+ private URL buildFileURL;
+
+ /**
+ * 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;
+
+ public static void start(String[] args) {
+ // create a command line and use it to run ant
+ Commandline commandline = new Commandline();
+ commandline.runAnt(args);
+ }
+
+ public void runAnt(String[] args) {
+ ExecutionManager executionManager = null;
+ try {
+ parseArguments(args);
+ Project project = getProject();
+ for (Iterator i = project.getTargets(); i.hasNext();) {
+ Target target = (Target)i.next();
+ }
+
+ // Get the list of library components
+ AntLibrary[] libraries = ComponentManager.getComponents();
+ executionManager = new ExecutionManager();
+ executionManager.addLibraries(libraries);
+ executionManager.setProject(project);
+ addBuildListeners(executionManager);
+ }
+ catch (AntException e) {
+ Location location = e.getLocation();
+ Throwable cause = e.getCause();
+ if (location != null && location != Location.UNKNOWN_LOCATION) {
+ System.out.print(location);
+ }
+ System.out.print(e.getMessage());
+
+ if (cause != null) {
+ System.out.println();
+ System.out.print("Root cause: " + cause.getClass().getName() + ": " + cause.getMessage());
+ }
+ System.out.println();
+
+ System.exit(1);
+ }
+
+ try {
+ executionManager.runBuild(targets);
+ System.exit(0);
+ }
+ catch (Exception e) {
+ System.exit(1);
+ }
+ }
+
+ protected void addBuildListeners(ExecutionManager executionManager)
+ throws ConfigException {
+
+ // Add the default listener
+ executionManager.addBuildListener(createLogger());
+
+ for (Iterator i = listeners.iterator(); i.hasNext(); ) {
+ String className = (String) i.next();
+ try {
+ BuildListener listener =
+ (BuildListener) Class.forName(className).newInstance();
+ executionManager.addBuildListener(listener);
+ }
+ catch(Exception exc) {
+ throw new ConfigException("Unable to instantiate listener " + className, exc);
+ }
+ }
+ }
+
+ /**
+ * Creates the default build logger for sending build events to the ant log.
+ */
+ private BuildLogger createLogger() throws ConfigException {
+ BuildLogger logger = null;
+ if (loggerClassname != null) {
+ try {
+ logger = (BuildLogger)(Class.forName(loggerClassname).newInstance());
+ }
+ catch (ClassCastException e) {
+ System.err.println("The specified logger class " + loggerClassname +
+ " does not implement the BuildLogger interface");
+ throw new ConfigException("Unable to instantiate logger " + loggerClassname, e);
+ }
+ catch (Exception e) {
+ System.err.println("Unable to instantiate specified logger class " +
+ loggerClassname + " : " + e.getClass().getName());
+ throw new ConfigException("Unable to instantiate logger " + loggerClassname, e);
+ }
+ }
+ else {
+ logger = new DefaultLogger();
+ }
+
+ logger.setMessageOutputLevel(messageOutputLevel);
+ logger.setOutputPrintStream(out);
+ logger.setErrorPrintStream(err);
+
+ return logger;
+ }
+
+
+ /**
+ * Parse the command line arguments.
+ */
+ private void parseArguments(String[] args) throws ConfigException {
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+
+ if (arg.equals("-buildfile") || arg.equals("-file") || arg.equals("-f")) {
+ try {
+ String url = args[i+1];
+ if (url.indexOf(":") == -1) {
+ File file = new File(url);
+ String uri = "file:" + file.getAbsolutePath().replace('\\', '/');
+ for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) {
+ uri = uri.substring(0, index) + "%23" + uri.substring(index+1);
+ }
+ buildFileURL = new URL(uri);
+ // We convert any hash characters to their URL escape.
+ }
+ else {
+ buildFileURL = new URL(url);
+ }
+ i++;
+ }
+ catch (MalformedURLException e) {
+ System.err.println("Buildfile is not valid: " + e.getMessage());
+ throw new ConfigException("Build file is not valid", e);
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ System.err.println("You must specify a buildfile when " +
+ "using the -buildfile argument");
+ return;
+ }
+ }
+ else if (arg.equals("-logfile") || arg.equals("-l")) {
+ try {
+ File logFile = new File(args[i+1]);
+ i++;
+ out = new PrintStream(new FileOutputStream(logFile));
+ err = out;
+ } catch (IOException ioe) {
+ System.err.println("Cannot write on the specified log file. " +
+ "Make sure the path exists and you have write permissions.");
+ return;
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ System.err.println("You must specify a log file when " +
+ "using the -log argument");
+ return;
+ }
+ }
+ else if (arg.equals("-listener")) {
+ try {
+ listeners.add(args[i+1]);
+ i++;
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ System.err.println("You must specify a classname when " +
+ "using the -listener argument");
+ return;
+ }
+ }
+ else if (arg.equals("-logger")) {
+ if (loggerClassname != null) {
+ System.err.println("Only one logger class may be specified.");
+ return;
+ }
+ try {
+ loggerClassname = args[++i];
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ System.err.println("You must specify a classname when " +
+ "using the -logger argument");
+ return;
+ }
+ }
+ else if (arg.startsWith("-")) {
+ // we don't have any more args to recognize!
+ System.out.println("Unknown argument: " + arg);
+ return;
+ } else {
+ // if it's no other arg, it must be a target
+ targets.add(arg);
+ }
+ }
+
+ if (buildFileURL == null) {
+ File defaultBuildFile = new File(DEFAULT_BUILD_FILENAME);
+ try {
+ buildFileURL = defaultBuildFile.toURL();
+ }
+ catch (MalformedURLException e) {
+ System.err.println("Buildfile is not valid: " + e.getMessage());
+ throw new ConfigException("Build file is not valid", e);
+ }
+ }
+ }
+
+ private Project getProject() throws ConfigException {
+ XMLProjectParser parser = new XMLProjectParser();
+ Project project = parser.parseBuildFile(buildFileURL);
+ return project;
+ }
+}
+
diff --git a/proposal/mutant/src/main/org/apache/ant/frontend/DefaultLogger.java b/proposal/mutant/src/main/org/apache/ant/frontend/DefaultLogger.java
new file mode 100644
index 000000000..076fff869
--- /dev/null
+++ b/proposal/mutant/src/main/org/apache/ant/frontend/DefaultLogger.java
@@ -0,0 +1,227 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.ant.frontend;
+
+import org.apache.ant.core.support.*;
+import org.apache.ant.core.model.*;
+import org.apache.ant.core.execution.*;
+import java.io.*;
+
+/**
+ * Writes build event to a PrintStream. Currently, it
+ * only writes which targets are being executed, and
+ * any messages that get logged.
+ */
+public class DefaultLogger implements BuildLogger {
+ private static int LEFT_COLUMN_SIZE = 12;
+
+ protected PrintStream out;
+ protected PrintStream err;
+ protected int msgOutputLevel = BuildEvent.MSG_ERR;
+ private long startTime = System.currentTimeMillis();
+
+ protected static String lSep = System.getProperty("line.separator");
+
+ protected boolean emacsMode = false;
+
+ /**
+ * Set the msgOutputLevel this logger is to respond to.
+ *
+ * Only messages with a message level lower than or equal to the given level are
+ * output to the log.
+ *
+ * Constants for the message levels are in Project.java. The order of
+ * the levels, from least to most verbose, is MSG_ERR, MSG_WARN,
+ * MSG_INFO, MSG_VERBOSE, MSG_DEBUG.
+ *
+ * The default message level for DefaultLogger is Project.MSG_ERR.
+ *
+ * @param level the logging level for the logger.
+ */
+ public void setMessageOutputLevel(int level) {
+ this.msgOutputLevel = level;
+ }
+
+
+ /**
+ * Set the output stream to which this logger is to send its output.
+ *
+ * @param output the output stream for the logger.
+ */
+ public void setOutputPrintStream(PrintStream output) {
+ this.out = output;
+ }
+
+ /**
+ * Set the output stream to which this logger is to send error messages.
+ *
+ * @param err the error stream for the logger.
+ */
+ public void setErrorPrintStream(PrintStream err) {
+ this.err = err;
+ }
+
+ /**
+ * Set this logger to produce emacs (and other editor) friendly output.
+ *
+ * @param emacsMode true if output is to be unadorned so that emacs and other
+ * editors can parse files names, etc.
+ */
+ public void setEmacsMode(boolean emacsMode) {
+ this.emacsMode = emacsMode;
+ }
+
+ public void reportException(Throwable t) {
+ if (t instanceof AntException) {
+ AntException e = (AntException)t;
+ Location location = e.getLocation();
+ Throwable cause = e.getCause();
+ if (location != null && location != Location.UNKNOWN_LOCATION) {
+ out.print(location);
+ }
+ out.print(e.getMessage());
+
+ if (cause != null) {
+ out.println();
+ out.print("Root cause: " + cause.getClass().getName() + ": " + cause.getMessage());
+ }
+ out.println();
+ }
+ else {
+ t.printStackTrace(err);
+ }
+ }
+
+ public void processBuildEvent(BuildEvent event) {
+ switch (event.getEventType()) {
+ case BuildEvent.BUILD_STARTED:
+ startTime = System.currentTimeMillis();
+ break;
+ case BuildEvent.BUILD_FINISHED:
+ Throwable cause = event.getCause();
+
+ if (cause == null) {
+ out.println(lSep + "BUILD SUCCESSFUL");
+ }
+ else {
+ err.println(lSep + "BUILD FAILED" + lSep);
+
+ reportException(cause);
+ }
+
+ out.println(lSep + "Total time: " + formatTime(System.currentTimeMillis() - startTime));
+ break;
+ case BuildEvent.TARGET_STARTED:
+ if (BuildEvent.MSG_INFO <= msgOutputLevel) {
+ Target target = (Target)event.getBuildElement();
+ out.println(lSep + target.getName() + ":");
+ }
+ break;
+ case BuildEvent.TARGET_FINISHED:
+ break;
+ case BuildEvent.TASK_STARTED:
+ break;
+ case BuildEvent.TASK_FINISHED:
+ break;
+ case BuildEvent.MESSAGE:
+ PrintStream logTo = event.getPriority() == BuildEvent.MSG_ERR ? err : out;
+
+ // Filter out messages based on priority
+ if (event.getPriority() <= msgOutputLevel) {
+
+ // Print out the name of the task if we're in one
+ Object buildElement = event.getBuildElement();
+ if (buildElement instanceof Task) {
+ Task task = (Task)buildElement;
+ String name = task.getType();
+
+ if (!emacsMode) {
+ String msg = "[" + name + "] ";
+ for (int i = 0; i < (LEFT_COLUMN_SIZE - msg.length()); i++) {
+ logTo.print(" ");
+ }
+ logTo.print(msg);
+ }
+ }
+
+ // Print the message
+ logTo.println(event.getMessage());
+ }
+ break;
+ default:
+ err.println("Unrecognized event type = " + event.getEventType());
+ break;
+ }
+ }
+
+ protected static String formatTime(long millis) {
+ long seconds = millis / 1000;
+ long minutes = seconds / 60;
+
+
+ if (minutes > 0) {
+ return Long.toString(minutes) + " minute"
+ + (minutes == 1 ? " " : "s ")
+ + Long.toString(seconds%60) + " second"
+ + (seconds%60 == 1 ? "" : "s");
+ }
+ else {
+ return Long.toString(seconds) + " second"
+ + (seconds%60 == 1 ? "" : "s");
+ }
+
+ }
+
+}
diff --git a/proposal/mutant/src/main/org/apache/ant/frontend/EmbedTest.java b/proposal/mutant/src/main/org/apache/ant/frontend/EmbedTest.java
new file mode 100644
index 000000000..10f001885
--- /dev/null
+++ b/proposal/mutant/src/main/org/apache/ant/frontend/EmbedTest.java
@@ -0,0 +1,77 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.ant.frontend;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.xml.parsers.*;
+import org.xml.sax.SAXParseException;
+import java.lang.reflect.*;
+
+import org.apache.ant.core.support.*;
+import org.apache.ant.core.xml.*;
+import org.apache.ant.core.config.*;
+
+/**
+ * This class illustrates the use of the ExecutionFrame class
+ * standalone to execute tasks
+ *
+ * @author Conor MacNeill
+ */
+public class EmbedTest {
+
+}
+
diff --git a/proposal/mutant/src/main/org/apache/ant/frontend/Launcher.java b/proposal/mutant/src/main/org/apache/ant/frontend/Launcher.java
new file mode 100644
index 000000000..ccc024848
--- /dev/null
+++ b/proposal/mutant/src/main/org/apache/ant/frontend/Launcher.java
@@ -0,0 +1,89 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.ant.frontend;
+
+import java.io.*;
+import java.net.*;
+import javax.xml.parsers.*;
+import java.lang.reflect.*;
+
+import org.apache.ant.core.support.*;
+
+/**
+ * This is the command line front end to end. It drives the core
+ *
+ * @author Conor MacNeill
+ */
+public class Launcher {
+ public static void main(String[] args) throws Exception {
+
+ // we need to find the parser jars and makre sure we are going to use
+ // those in preference to anything else that may be lying about in the
+ // user's classpath
+ AntClassLoader coreClassLoader = AntLocator.getCoreClassLoader(System.getProperties());
+
+ URL frontEndURL = AntLocator.getClassLocationURL(Launcher.class);
+ coreClassLoader.addURL(frontEndURL);
+
+ Class commandLineClass = Class.forName("org.apache.ant.frontend.Commandline", true, coreClassLoader);
+
+ final Class[] param = {Class.forName("[Ljava.lang.String;")};
+ Class target = null;
+ final Method startMethod = commandLineClass.getMethod("start", param);
+ final Object[] argument = {args};
+ startMethod.invoke(null, argument);
+ }
+}
+
diff --git a/proposal/mutant/src/main/org/apache/ant/frontend/RemoteLauncher.java b/proposal/mutant/src/main/org/apache/ant/frontend/RemoteLauncher.java
new file mode 100644
index 000000000..63cea5ab9
--- /dev/null
+++ b/proposal/mutant/src/main/org/apache/ant/frontend/RemoteLauncher.java
@@ -0,0 +1,97 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.ant.frontend;
+
+import java.io.*;
+import java.net.*;
+import javax.xml.parsers.*;
+import java.lang.reflect.*;
+
+import org.apache.ant.core.support.*;
+
+/**
+ * Command line to run Ant core from a remote server
+ *
+ * @author Conor MacNeill
+ */
+public class RemoteLauncher {
+ public static void main(String[] args) throws Exception {
+
+ String antHome = args[0];
+ String parserHome = args[1];
+
+ URL[] remoteCore = new URL[3];
+ remoteCore[0] = new URL(antHome + "/lib/core.jar");
+ remoteCore[1] = new URL(antHome + "/lib/frontend.jar");
+ remoteCore[2] = new URL(parserHome);
+ AntClassLoader coreClassLoader = new AntClassLoader(remoteCore);
+
+ String[] realArgs = new String[args.length - 2];
+ System.arraycopy(args, 2, realArgs, 0, realArgs.length);
+
+
+ System.out.print("Loading remote Ant ... ");
+ Class launcher = Class.forName("org.apache.ant.frontend.Commandline", true, coreClassLoader);
+
+ final Class[] param = { Class.forName("[Ljava.lang.String;") };
+ Class target = null;
+ final Method startMethod = launcher.getMethod("start", param);
+ final Object[] argument = {realArgs};
+ System.out.println("Done");
+ System.out.println("Starting remote Ant");
+ startMethod.invoke(null, argument);
+ }
+}
+
diff --git a/proposal/mutant/src/main/org/apache/ant/frontend/eggmanifest.mf b/proposal/mutant/src/main/org/apache/ant/frontend/eggmanifest.mf
new file mode 100644
index 000000000..99001c238
--- /dev/null
+++ b/proposal/mutant/src/main/org/apache/ant/frontend/eggmanifest.mf
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+Created-By: Ant 2.0alpha
+Main-Class: org.apache.ant.frontend.RemoteLauncher
+Class-Path: core.jar
+Sealed: true
\ No newline at end of file
diff --git a/proposal/mutant/src/main/org/apache/ant/frontend/manifest.mf b/proposal/mutant/src/main/org/apache/ant/frontend/manifest.mf
new file mode 100644
index 000000000..bffb78055
--- /dev/null
+++ b/proposal/mutant/src/main/org/apache/ant/frontend/manifest.mf
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+Created-By: Ant 2.0alpha
+Main-Class: org.apache.ant.frontend.Launcher
+Class-Path: core.jar
+Sealed: true
\ No newline at end of file