diff --git a/src/main/org/apache/tools/ant/BuildEvent.java b/src/main/org/apache/tools/ant/BuildEvent.java
new file mode 100644
index 000000000..4f58fee20
--- /dev/null
+++ b/src/main/org/apache/tools/ant/BuildEvent.java
@@ -0,0 +1,153 @@
+/*
+ * 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", "Tomcat", 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.tools.ant;
+
+import java.util.EventObject;
+
+public class BuildEvent extends EventObject {
+ private Project project;
+ private Target target;
+ private Task task;
+ private String message;
+ private int priority;
+ private Throwable exception;
+
+ /**
+ * Constructs a new build event. Fields that are not relevant
+ * can be set to null, except for the project field which is
+ * required.
+ */
+ public BuildEvent(
+ Project project,
+ Target target,
+ Task task,
+ String message,
+ int priority,
+ Throwable exception) {
+
+ super(getSource(project, target, task));
+
+ this.project = project;
+ this.target = target;
+ this.task = task;
+ this.message = message;
+ this.priority = priority;
+ this.exception = exception;
+ }
+
+ /**
+ * Returns the project that fired this event.
+ */
+ public Project getProject() {
+ return project;
+ }
+
+ /**
+ * Returns the target that fired this event.
+ */
+ public Target getTarget() {
+ return target;
+ }
+
+ /**
+ * Returns the task that fired this event.
+ */
+ public Task getTask() {
+ return task;
+ }
+
+ /**
+ * Returns the logging message. This field will only be set
+ * for "messageLogged" events.
+ *
+ * @see BuildListener#messageLogged(BuildEvent)
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Returns the priority of the logging message. This field will only
+ * be set for "messageLogged" events.
+ *
+ * @see BuildListener#messageLogged(BuildEvent)
+ */
+ public int getPriority(){
+ return priority;
+ }
+
+ /**
+ * Returns the exception that was thrown, if any. This field will only
+ * be set for "taskFinished", "targetFinished", and "buildFinished" events.
+ *
+ * @see BuildListener#taskFinished(BuildEvent)
+ * @see BuildListener#targetFinished(BuildEvent)
+ * @see BuildListener#buildFinished(BuildEvent)
+ */
+ public Throwable getException() {
+ return exception;
+ }
+
+ /**
+ * Returns the object that fired this event.
+ */
+ private static Object getSource(Project project, Target target, Task task) {
+ if (task != null) return task;
+ if (target != null) return target;
+ if (project != null) return project;
+
+ throw new IllegalArgumentException("Project field cannot be null");
+ }
+}
\ No newline at end of file
diff --git a/src/main/org/apache/tools/ant/BuildListener.java b/src/main/org/apache/tools/ant/BuildListener.java
new file mode 100644
index 000000000..170f3a6fd
--- /dev/null
+++ b/src/main/org/apache/tools/ant/BuildListener.java
@@ -0,0 +1,119 @@
+/*
+ * 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", "Tomcat", 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.tools.ant;
+
+import java.util.EventListener;
+
+/**
+ * Classes that implement this interface will be notified when
+ * things happend during a build.
+ *
+ * @see BuildEvent
+ * @see Project#addBuildListener(BuildListener)
+ */
+public interface BuildListener extends EventListener {
+
+ /**
+ * Fired before any targets are started.
+ */
+ public void buildStarted(BuildEvent event);
+
+ /**
+ * Fired after the last target has finished. This event
+ * will still be thrown if an error occured during the build.
+ *
+ * @see BuildEvent.getException()
+ */
+ public void buildFinished(BuildEvent event);
+
+ /**
+ * Fired when a target is started.
+ *
+ * @see BuildEvent#getTarget()
+ */
+ public void targetStarted(BuildEvent event);
+
+ /**
+ * Fired when a target has finished. This event will
+ * still be thrown if an error occured during the build.
+ *
+ * @see BuildEvent.getException()
+ */
+ public void targetFinished(BuildEvent event);
+
+ /**
+ * Fired when a task is started.
+ *
+ * @see BuildEvent#getTask()
+ */
+ public void taskStarted(BuildEvent event);
+
+ /**
+ * Fired when a task has finished. This event will still
+ * be throw if an error occured during the build.
+ *
+ * @see BuildEvent#getException()
+ */
+ public void taskFinished(BuildEvent event);
+
+ /**
+ * Fired whenever a message is logged.
+ *
+ * @see BuildEvent#getMessage()
+ * @see BuildEvent#getPriority()
+ */
+ public void messageLogged(BuildEvent event);
+
+}
\ No newline at end of file
diff --git a/src/main/org/apache/tools/ant/DefaultLogger.java b/src/main/org/apache/tools/ant/DefaultLogger.java
new file mode 100644
index 000000000..bdcb22b1e
--- /dev/null
+++ b/src/main/org/apache/tools/ant/DefaultLogger.java
@@ -0,0 +1,111 @@
+/*
+ * 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", "Tomcat", 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.tools.ant;
+
+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 BuildListener {
+ private PrintStream out;
+ private int msgOutputLevel;
+
+ /**
+ * Constructs a new logger which will write to the specified
+ * PrintStream. Messages with a priority lower (higher?) than
+ * msgOutputLevel will be ignored.
+ */
+ public DefaultLogger(PrintStream out, int msgOutputLevel) {
+ this.out = out;
+ this.msgOutputLevel = msgOutputLevel;
+ }
+
+ public void buildStarted(BuildEvent event) {}
+ public void buildFinished(BuildEvent event) {}
+
+ public void targetStarted(BuildEvent event) {
+ if (msgOutputLevel <= Project.MSG_INFO) {
+ out.println("Executing Target: " + event.getTarget().getName());
+ }
+ }
+
+ public void targetFinished(BuildEvent event) {}
+
+ public void taskStarted(BuildEvent event) {}
+ public void taskFinished(BuildEvent event) {}
+
+ public void messageLogged(BuildEvent event) {
+
+ // Filter out messages based on priority
+ if (event.getPriority() <= msgOutputLevel) {
+
+ // Print out the name of the task if we're in one
+ if (event.getTask() != null) {
+ String name = event.getTask().getClass().getName();
+ int pos = name.lastIndexOf(".");
+ if (pos != -1) {
+ name = name.substring(pos + 1);
+ }
+ out.print("[" + name + "] ");
+ }
+
+ // Print the message
+ out.println(event.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/org/apache/tools/ant/Main.java b/src/main/org/apache/tools/ant/Main.java
index b8b8621ed..e803118ac 100644
--- a/src/main/org/apache/tools/ant/Main.java
+++ b/src/main/org/apache/tools/ant/Main.java
@@ -73,19 +73,27 @@ import java.util.*;
public class Main {
/** Our current message output status. Follows Project.MSG_XXX */
- private static int msgOutputLevel = Project.MSG_INFO;
+ private int msgOutputLevel = Project.MSG_INFO;
/** File that we are using for configuration */
- private static File buildFile = new File("build.xml");
+ private File buildFile = new File("build.xml");
/** Stream that we are using for logging */
- private static PrintStream out = System.out;
+ private PrintStream out = System.out;
/** The build targets */
- private static Vector targets = new Vector(5);
+ private Vector targets = new Vector(5);
/** Set of properties that can be used by tasks */
- private static Properties definedProps = new Properties();
+ private Properties definedProps = new Properties();
+
+ /** Names of classes to add as listeners to project */
+ private Vector listeners = new Vector(5);
+
+ /**
+ * Indicates if this ant should be run.
+ */
+ private boolean readyToRun = false;
/**
* Command line entry point. This method kicks off the building
@@ -94,8 +102,11 @@ public class Main {
*
* @param args Command line args.
*/
-
public static void main(String[] args) {
+ new Main(args).runBuild();
+ }
+
+ protected Main(String[] args) {
// cycle through given args
@@ -137,6 +148,16 @@ public class Main {
System.out.println(msg);
return;
}
+ } else if (arg.equals("-listener")) {
+ try {
+ listeners.addElement(args[i+1]);
+ i++;
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ String msg = "You must specify a classname when " +
+ "using the -listener argument";
+ System.out.println(msg);
+ return;
+ }
} else if (arg.startsWith("-D")) {
/* Interestingly enough, we get to here when a user
@@ -170,6 +191,7 @@ public class Main {
// if it's no other arg, it may be the target
targets.addElement(arg);
}
+
}
// make sure buildfile exists
@@ -187,18 +209,19 @@ public class Main {
return;
}
- // ok, so if we've made it here, let's run the damn build allready
- runBuild();
-
- return;
+ readyToRun = true;
}
/**
* Executes the build.
*/
- private static void runBuild() {
+ private void runBuild() {
+ if (!readyToRun) {
+ return;
+ }
+
// track when we started
long startTime = System.currentTimeMillis();
@@ -206,7 +229,10 @@ public class Main {
System.out.println("Buildfile: " + buildFile);
}
- Project project = new Project(out, msgOutputLevel);
+ Project project = new Project();
+ addBuildListeners(project);
+ project.fireBuildStarted();
+ project.init();
// set user-define properties
Enumeration e = definedProps.keys();
@@ -215,7 +241,8 @@ public class Main {
String value = (String)definedProps.get(arg);
project.setUserProperty(arg, value);
}
- project.setUserProperty( "ant.file" , buildFile.getAbsolutePath() );
+
+ project.setUserProperty( "ant.file" , buildFile.getAbsolutePath() );
// first use the ProjectHelper to create the project object
// from the given build file.
@@ -248,10 +275,7 @@ public class Main {
// actually do some work
try {
- Enumeration en = targets.elements();
- while (en.hasMoreElements()) {
- project.executeTarget((String) en.nextElement());
- }
+ project.executeTargets(targets);
} catch (BuildException be) {
String msg = "\nBUILD FATAL ERROR\n\n";
System.out.println(msg + be.toString());
@@ -270,6 +294,31 @@ public class Main {
}
}
+ protected void addBuildListeners(Project project) {
+
+ // Add the default listener
+ project.addBuildListener(createDefaultBuildListener());
+
+ for (int i = 0; i < listeners.size(); i++) {
+ String className = (String) listeners.elementAt(i);
+ try {
+ BuildListener listener =
+ (BuildListener) Class.forName(className).newInstance();
+ project.addBuildListener(listener);
+ }
+ catch(Exception exc) {
+ throw new BuildException("Unable to instantiate " + className, exc);
+ }
+ }
+ }
+
+ /**
+ * Creates the default build listener for displaying output to the screen.
+ */
+ private BuildListener createDefaultBuildListener() {
+ return new DefaultLogger(out, msgOutputLevel);
+ }
+
/**
* Prints the usage of how to use this class to System.out
*/
@@ -282,6 +331,7 @@ public class Main {
msg.append(" -quiet be extra quiet" + lSep);
msg.append(" -verbose be extra verbose" + lSep);
msg.append(" -logfile use given file for log" + lSep);
+ msg.append(" -listener add an instance of class as a project listener" + lSep);
msg.append(" -buildfile use given buildfile" + lSep);
msg.append(" -D= use value for given property" + lSep);
System.out.println(msg.toString());
diff --git a/src/main/org/apache/tools/ant/Project.java b/src/main/org/apache/tools/ant/Project.java
index f60b5b90e..538b1f16d 100644
--- a/src/main/org/apache/tools/ant/Project.java
+++ b/src/main/org/apache/tools/ant/Project.java
@@ -93,8 +93,6 @@ public class Project {
public static final String TOKEN_END = "@";
private String name;
- private PrintStream out;
- private int msgOutputLevel = MSG_INFO;
private Hashtable properties = new Hashtable();
private Hashtable userProperties = new Hashtable();
@@ -105,11 +103,20 @@ public class Project {
private Hashtable filters = new Hashtable();
private File baseDir;
- public Project(PrintStream out, int msgOutputLevel) {
+ private Vector listeners = new Vector();
+ protected Target currentTarget = null;
+ protected Task currentTask = null;
- this.out = out;
- this.msgOutputLevel = msgOutputLevel;
+ public Project() {
+ }
+ /**
+ * Initialise the project.
+ *
+ * This involves setting the default task definitions and loading the
+ * system properties.
+ */
+ public void init() {
detectJavaVersion();
String defs = "/org/apache/tools/ant/taskdefs/defaults.properties";
@@ -148,16 +155,16 @@ public class Project {
}
}
- public PrintStream getOutput() {
- return this.out;
+ public void addBuildListener(BuildListener listener) {
+ listeners.addElement(listener);
}
- public void setOutput(PrintStream out) {
- this.out=out;
+ public void removeBuildListener(BuildListener listener) {
+ listeners.removeElement(listener);
}
- public int getOutputLevel() {
- return this.msgOutputLevel;
+ public Vector getBuildListeners() {
+ return listeners;
}
public void log(String msg) {
@@ -165,15 +172,11 @@ public class Project {
}
public void log(String msg, int msgLevel) {
- if (msgLevel <= msgOutputLevel) {
- out.println(msg);
- }
+ fireMessageLogged(msg, msgLevel);
}
public void log(String msg, String tag, int msgLevel) {
- if (msgLevel <= msgOutputLevel) {
- out.println("[" + tag + "] " + msg);
- }
+ fireMessageLogged(msg, msgLevel);
}
public void setProperty(String name, String value) {
@@ -403,6 +406,23 @@ public class Project {
}
}
+ public void executeTargets(Vector targetNames) throws BuildException {
+ Throwable error = null;
+
+ try {
+ for (int i = 0; i < targetNames.size(); i++) {
+ executeTarget((String)targetNames.elementAt(i));
+ }
+ }
+ catch(RuntimeException exc) {
+ error = exc;
+ throw exc;
+ }
+ finally {
+ fireBuildFinished(error);
+ }
+ }
+
public void executeTarget(String targetName) throws BuildException {
// sanity check ourselves, if we've been asked to build nothing
@@ -432,7 +452,7 @@ public class Project {
public File resolveFile(String fileName) {
// deal with absolute files
if (fileName.startsWith("/")) return new File( fileName );
- if (fileName.startsWith(System.getProperty("file.separator")))
+ if (fileName.startsWith(System.getProperty("file.separator")))
return new File( fileName );
// Eliminate consecutive slashes after the drive spec
@@ -672,13 +692,25 @@ public class Project {
// Target and execute it.
private final void runTarget(String target, Hashtable targets)
throws BuildException {
- Target t = (Target)targets.get(target);
- if (t == null) {
+
+ currentTarget = (Target)targets.get(target);
+ if (currentTarget == null) {
throw new RuntimeException("Unexpected missing target `"+target+
"' in this project.");
}
- log("Executing Target: "+target, MSG_INFO);
- t.execute();
+
+ try {
+ fireTargetStarted();
+ currentTarget.execute();
+ fireTargetFinished(null);
+ }
+ catch(RuntimeException exc) {
+ fireTargetFinished(exc);
+ throw exc;
+ }
+ finally {
+ currentTarget = null;
+ }
}
/**
@@ -804,4 +836,72 @@ public class Project {
public Hashtable getReferences() {
return references;
}
+
+ protected void fireBuildStarted() {
+ BuildEvent event = createBuildEvent();
+ for (int i = 0; i < listeners.size(); i++) {
+ BuildListener listener = (BuildListener) listeners.elementAt(i);
+ listener.buildStarted(event);
+ }
+ }
+
+ protected void fireBuildFinished(Throwable exception) {
+ BuildEvent event = createBuildEvent(exception);
+ for (int i = 0; i < listeners.size(); i++) {
+ BuildListener listener = (BuildListener) listeners.elementAt(i);
+ listener.buildFinished(event);
+ }
+ }
+
+ protected void fireTargetStarted() {
+ BuildEvent event = createBuildEvent();
+ for (int i = 0; i < listeners.size(); i++) {
+ BuildListener listener = (BuildListener) listeners.elementAt(i);
+ listener.targetStarted(event);
+ }
+ }
+
+ protected void fireTargetFinished(Throwable exception) {
+ BuildEvent event = createBuildEvent(exception);
+ for (int i = 0; i < listeners.size(); i++) {
+ BuildListener listener = (BuildListener) listeners.elementAt(i);
+ listener.targetFinished(event);
+ }
+ }
+
+ protected void fireTaskStarted() {
+ BuildEvent event = createBuildEvent();
+ for (int i = 0; i < listeners.size(); i++) {
+ BuildListener listener = (BuildListener) listeners.elementAt(i);
+ listener.taskStarted(event);
+ }
+ }
+
+ protected void fireTaskFinished(Throwable exception) {
+ BuildEvent event = createBuildEvent(exception);
+ for (int i = 0; i < listeners.size(); i++) {
+ BuildListener listener = (BuildListener) listeners.elementAt(i);
+ listener.taskFinished(event);
+ }
+ }
+
+ protected void fireMessageLogged(String message, int priority) {
+ BuildEvent event = createBuildEvent(message, priority);
+ for (int i = 0; i < listeners.size(); i++) {
+ BuildListener listener = (BuildListener) listeners.elementAt(i);
+ listener.messageLogged(event);
+ }
+ }
+
+ public BuildEvent createBuildEvent() {
+ return new BuildEvent(this, currentTarget, currentTask, null, MSG_VERBOSE, null);
+ }
+
+ public BuildEvent createBuildEvent(String msg, int priority) {
+ return new BuildEvent(this, currentTarget, currentTask, msg, priority, null);
+ }
+
+ public BuildEvent createBuildEvent(Throwable exception) {
+ return new BuildEvent(this, currentTarget, currentTask, null, MSG_VERBOSE, exception);
+ }
}
diff --git a/src/main/org/apache/tools/ant/ProjectHelper.java b/src/main/org/apache/tools/ant/ProjectHelper.java
index 6192ee897..5321199de 100644
--- a/src/main/org/apache/tools/ant/ProjectHelper.java
+++ b/src/main/org/apache/tools/ant/ProjectHelper.java
@@ -299,7 +299,7 @@ public class ProjectHelper {
// take care of dependencies
if (depends.length() > 0) {
- StringTokenizer tok =
+ StringTokenizer tok =
new StringTokenizer(depends, ",", false);
while (tok.hasMoreTokens()) {
target.addDependency(tok.nextToken().trim());
diff --git a/src/main/org/apache/tools/ant/Target.java b/src/main/org/apache/tools/ant/Target.java
index ddc11bb37..acd9b42d5 100644
--- a/src/main/org/apache/tools/ant/Target.java
+++ b/src/main/org/apache/tools/ant/Target.java
@@ -119,11 +119,21 @@ public class Target {
Task task = (Task) enum.nextElement();
try {
+ project.currentTask = task;
+ project.fireTaskStarted();
task.execute();
- } catch(BuildException exc) {
- exc.setLocation(task.getLocation());
- throw exc;
+ project.fireTaskFinished(null);
}
+ catch(RuntimeException exc) {
+ if (exc instanceof BuildException) {
+ ((BuildException)exc).setLocation(task.getLocation());
+ }
+ project.fireTaskFinished(exc);
+ throw exc;
+ }
+ finally {
+ project.currentTask = null;
+ }
}
} else {
project.log("Skipped because property '" + this.condition + "' not set.", this.name, Project.MSG_VERBOSE);
diff --git a/src/main/org/apache/tools/ant/XmlLogger.java b/src/main/org/apache/tools/ant/XmlLogger.java
new file mode 100644
index 000000000..72348b695
--- /dev/null
+++ b/src/main/org/apache/tools/ant/XmlLogger.java
@@ -0,0 +1,269 @@
+/*
+ * 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", "Tomcat", 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.tools.ant;
+
+import java.io.*;
+import javax.xml.parsers.*;
+import org.w3c.dom.*;
+
+/**
+ * Generates a "log.xml" file in the current directory with
+ * an XML description of what happened during a build.
+ *
+ * @see Project#addBuildListener()
+ */
+public class XmlLogger implements BuildListener {
+
+ private static final DocumentBuilder builder = getDocumentBuilder();
+
+ private static DocumentBuilder getDocumentBuilder() {
+ try {
+ return DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ }
+ catch(Exception exc) {
+ throw new ExceptionInInitializerError(exc);
+ }
+ }
+
+ // XML constants for tag names and attribute names
+ private static final String BUILD_TAG = "build";
+ private static final String TARGET_TAG = "target";
+ private static final String TASK_TAG = "task";
+ private static final String MESSAGE_TAG = "message";
+ private static final String NAME_ATTR = "name";
+ private static final String TIME_ATTR = "time";
+ private static final String PRIORITY_ATTR = "priority";
+ private static final String LOCATION_ATTR = "location";
+ private static final String ERROR_ATTR = "error";
+
+ private Document doc;
+ private Element buildElement;
+ private Element targetElement;
+ private Element taskElement;
+
+ private long buildStartTime;
+ private long targetStartTime;
+ private long taskStartTime;
+
+ /**
+ * Constructs a new BuildListener that logs build events to an XML file.
+ */
+ public XmlLogger() {
+ }
+
+ public void buildStarted(BuildEvent event) {
+ buildStartTime = System.currentTimeMillis();
+
+ doc = builder.newDocument();
+ buildElement = doc.createElement(BUILD_TAG);
+ }
+
+ public void buildFinished(BuildEvent event) {
+ long totalTime = System.currentTimeMillis() - buildStartTime;
+ buildElement.setAttribute(TIME_ATTR, formatTime(totalTime));
+
+ if (event.getException() != null) {
+ buildElement.setAttribute(ERROR_ATTR, event.getException().toString());
+ }
+
+ try {
+ Writer out = new FileWriter("log.xml");
+ out.write("\n\n");
+ write(buildElement, out, 0);
+ out.flush();
+ out.close();
+
+ }
+ catch(IOException exc) {
+ throw new BuildException("Unable to close log file", exc);
+ }
+ }
+
+ public void targetStarted(BuildEvent event) {
+ targetStartTime = System.currentTimeMillis();
+ targetElement = doc.createElement(TARGET_TAG);
+ targetElement.setAttribute(NAME_ATTR, event.getTarget().getName());
+ }
+
+ public void targetFinished(BuildEvent event) {
+ long totalTime = System.currentTimeMillis() - targetStartTime;
+ targetElement.setAttribute(TIME_ATTR, formatTime(totalTime));
+ buildElement.appendChild(targetElement);
+
+ targetElement = null;
+ }
+
+ public void taskStarted(BuildEvent event) {
+ taskStartTime = System.currentTimeMillis();
+ taskElement = doc.createElement(TASK_TAG);
+
+ String name = event.getTask().getClass().getName();
+ int pos = name.lastIndexOf(".");
+ if (pos != -1) {
+ name = name.substring(pos + 1);
+ }
+ taskElement.setAttribute(NAME_ATTR, name);
+
+ taskElement.setAttribute(LOCATION_ATTR, event.getTask().getLocation().toString());
+ }
+
+ public void taskFinished(BuildEvent event) {
+ long totalTime = System.currentTimeMillis() - taskStartTime;
+ taskElement.setAttribute(TIME_ATTR, formatTime(totalTime));
+ targetElement.appendChild(taskElement);
+
+ taskElement = null;
+ }
+
+ public void messageLogged(BuildEvent event) {
+ Element messageElement = doc.createElement(MESSAGE_TAG);
+
+ String name = "debug";
+ switch(event.getPriority()) {
+ case Project.MSG_ERR: name = "error"; break;
+ case Project.MSG_WARN: name = "warn"; break;
+ case Project.MSG_INFO: name = "info"; break;
+ default: name = "debug"; break;
+ }
+ messageElement.setAttribute(PRIORITY_ATTR, name);
+
+ Text messageText = doc.createTextNode(event.getMessage());
+ messageElement.appendChild(messageText);
+
+ if (taskElement != null) {
+ taskElement.appendChild(messageElement);
+ }
+ else if (targetElement != null) {
+ targetElement.appendChild(messageElement);
+ }
+ else {
+ buildElement.appendChild(messageElement);
+ }
+ }
+
+ /**
+ * Writes a DOM element to a file.
+ */
+ private static void write(Element element, Writer out, int indent) throws IOException {
+
+ // Write indent characters
+ for (int i = 0; i < indent; i++) {
+ out.write("\t");
+ }
+
+ // Write element
+ out.write("<");
+ out.write(element.getTagName());
+
+ // Write attributes
+ NamedNodeMap attrs = element.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Attr attr = (Attr) attrs.item(i);
+ out.write(" ");
+ out.write(attr.getName());
+ out.write("=\"");
+ out.write(attr.getValue());
+ out.write("\"");
+ }
+ out.write(">");
+
+ // Write child attributes and text
+ boolean hasChildren = false;
+ NodeList children = element.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ if (!hasChildren) {
+ out.write("\n");
+ hasChildren = true;
+ }
+ write((Element)child, out, indent + 1);
+ }
+
+ if (child.getNodeType() == Node.TEXT_NODE) {
+ out.write(((Text)child).getData());
+ }
+ }
+
+ // If we had child elements, we need to indent before we close
+ // the element, otherwise we're on the same line and don't need
+ // to indent
+ if (hasChildren) {
+ for (int i = 0; i < indent; i++) {
+ out.write("\t");
+ }
+ }
+
+ // Write element close
+ out.write("");
+ out.write(element.getTagName());
+ out.write(">\n");
+ }
+
+ private static String formatTime(long millis) {
+ long seconds = millis / 1000;
+ long minutes = seconds / 60;
+
+
+ if (minutes > 0) {
+ return Long.toString(minutes) + " minutes " + Long.toString(seconds%60) + " seconds";
+ }
+ else {
+ return Long.toString(seconds) + " seconds";
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/org/apache/tools/ant/taskdefs/Ant.java b/src/main/org/apache/tools/ant/taskdefs/Ant.java
index 68a0ef893..7ee143031 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Ant.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Ant.java
@@ -86,9 +86,25 @@ public class Ant extends Task {
Vector properties=new Vector();
Project p1;
-
+
public void init() {
- p1 = new Project(project.getOutput(), project.getOutputLevel());
+ p1 = new Project();
+ Vector listeners = project.getBuildListeners();
+ for (int i = 0; i < listeners.size(); i++) {
+ p1.addBuildListener((BuildListener)listeners.elementAt(i));
+ }
+
+ if (output != null) {
+ try {
+ PrintStream out = new PrintStream(new FileOutputStream(output));
+ p1.addBuildListener(new DefaultLogger(out, Project.MSG_INFO));
+ }
+ catch( IOException ex ) {
+ project.log( "Ant: Can't set output to " + output );
+ }
+ }
+
+ p1.init();
// set user-define properties
Hashtable prop1 = project.getProperties();
@@ -99,36 +115,27 @@ public class Ant extends Task {
p1.setProperty(arg, value);
}
}
-
+
/**
* Do the execution.
*/
public void execute() throws BuildException {
if( dir==null) dir=".";
-
- if( output != null ) {
- try {
- PrintStream out=new PrintStream(new FileOutputStream(output));
- p1.setOutput( out );
- } catch( IOException ex ) {
- project.log( "Ant: Can't set output to " + output );
- }
- }
-
- p1.setBasedir(dir);
+
+ p1.setBasedir(dir);
p1.setUserProperty("basedir" , dir);
- // Override with local-defined properties
- Enumeration e = properties.elements();
+ // Override with local-defined properties
+ Enumeration e = properties.elements();
while (e.hasMoreElements()) {
Property p=(Property) e.nextElement();
- // System.out.println("Setting " + p.getName()+ " " + p.getValue());
- p.init();
+ // System.out.println("Setting " + p.getName()+ " " + p.getValue());
+ p.init();
}
- if (antFile == null) antFile = dir + "/build.xml";
+ if (antFile == null) antFile = dir + "/build.xml";
- p1.setUserProperty( "ant.file" , antFile );
+ p1.setUserProperty( "ant.file" , antFile );
ProjectHelper.configureProject(p1, new File(antFile));
if (target == null) {
diff --git a/src/main/org/apache/tools/ant/taskdefs/Javac.java b/src/main/org/apache/tools/ant/taskdefs/Javac.java
index 5d41801ff..1328452c7 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Javac.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Javac.java
@@ -275,7 +275,7 @@ public class Javac extends MatchingTask {
+ ".class");
if (srcFile.lastModified() > now) {
- project.log("Warning: file modified in the future: " +
+ project.log("Warning: file modified in the future: " +
files[i], project.MSG_WARN);
}
@@ -423,14 +423,19 @@ public class Javac extends MatchingTask {
// XXX
// provide the compiler a different message sink - namely our own
- JavacOutputStream jos = new JavacOutputStream(project);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ sun.tools.javac.Main compiler = new sun.tools.javac.Main(out, "javac");
- sun.tools.javac.Main compiler =
- new sun.tools.javac.Main(jos, "javac");
- compiler.compile(args);
- if (jos.getErrorFlag()) {
- String msg = "Compile failed, messages should have been provided.";
- throw new BuildException(msg);
+ if (compiler.compile(args)) {
+ String output = out.toString().trim();
+ if (output.length() > 0) {
+ project.log(output, Project.MSG_WARN);
+ }
+ }
+ else {
+ project.log(out.toString().trim(), Project.MSG_ERR);
+
+ throw new BuildException("Compile failed");
}
}