Index: Main.java
===================================================================
RCS file: /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/Main.java,v
retrieving revision 1.6
diff -u -r1.6 Main.java
--- Main.java	2000/04/26 19:09:17	1.6
+++ Main.java	2000/06/18 23:48:29
@@ -73,20 +73,23 @@
 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 listenrs to project */
+    private Vector listeners = new Vector(5);
+
     /**
      * Command line entry point. This method kicks off the building
      * of a project object and executes a build using either a given
@@ -94,8 +97,11 @@
      *
      * @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 +143,16 @@
                     System.out.println(msg);
                     return;
                 }
+            } else if (arg.equals("-listener")) {
+                try {
+                    listeners.add(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
@@ -186,18 +202,13 @@
             System.out.println("What? Buildfile: " + buildFile + " is a dir!");
             return;
         }
-
-        // ok, so if we've made it here, let's run the damn build allready
-        runBuild();
-
-        return;
     }
 
     /**
      * Executes the build.
      */
 
-    private static void runBuild() {
+    private void runBuild() {
 
         // track when we started
 
@@ -206,7 +217,10 @@
             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 +229,8 @@
             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.
@@ -243,10 +258,7 @@
 
         // 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());
@@ -263,6 +275,31 @@
             System.out.println("Completed in " + (elapsedTime/1000)
                                + " seconds");
         }
+    }
+
+    protected void addBuildListeners(Project project) {
+
+        // Add the default listener
+        project.addBuildListener(createBuildListener());
+
+        for (int i = 0; i < listeners.size(); i++) {
+            String className = (String) listeners.get(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 createBuildListener() {
+        return new DefaultLogger(out, msgOutputLevel);
     }
 
     /**
Index: Project.java
===================================================================
RCS file: /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/Project.java,v
retrieving revision 1.20
diff -u -r1.20 Project.java
--- Project.java	2000/05/27 22:21:09	1.20
+++ Project.java	2000/06/18 23:48:29
@@ -93,8 +93,6 @@
     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,16 @@
     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() {
+    }
 
+    // Had to pull this out into a separate method so we could register
+    // all of the listeners before logging
+    public void init() {
         detectJavaVersion();
 
         String defs = "/org/apache/tools/ant/taskdefs/defaults.properties";
@@ -148,16 +151,16 @@
         }
     }
 
-    public PrintStream getOutput() {
-        return this.out;
+    public void addBuildListener(BuildListener listener) {
+        listeners.add(listener);
     }
 
-    public void setOutput(PrintStream out) {
-        this.out=out;
+    public void removeBuildListener(BuildListener listener) {
+        listeners.remove(listener);
     }
 
-    public int getOutputLevel() {
-        return this.msgOutputLevel;
+    public Vector getBuildListeners() {
+        return listeners;
     }
 
     public void log(String msg) {
@@ -165,15 +168,11 @@
     }
 
     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 +402,23 @@
         }
     }
 
+    public void executeTargets(Vector targetNames) throws BuildException {
+        Throwable error = null;
+
+        try {
+            for (int i = 0; i < targetNames.size(); i++) {
+                executeTarget((String)targetNames.get(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 +448,7 @@
     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 +688,25 @@
     // 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.");
+        }
+
+        try {
+            fireTargetStarted();
+            currentTarget.execute();
+            fireTargetFinished(null);
+        }
+        catch(RuntimeException exc) {
+            fireTargetFinished(exc);
+            throw exc;
+        }
+        finally {
+            currentTarget = null;
         }
-        log("Executing Target: "+target, MSG_INFO);
-        t.execute();
     }
 
     /**
@@ -803,5 +831,73 @@
 
     public Hashtable getReferences() {
         return references;
+    }
+
+    protected void fireBuildStarted() {
+        BuildEvent event = createBuildEvent();
+        for (int i = 0; i < listeners.size(); i++) {
+            BuildListener listener = (BuildListener) listeners.get(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.get(i);
+            listener.buildFinished(event);
+        }
+    }
+
+    protected void fireTargetStarted() {
+        BuildEvent event = createBuildEvent();
+        for (int i = 0; i < listeners.size(); i++) {
+            BuildListener listener = (BuildListener) listeners.get(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.get(i);
+            listener.targetFinished(event);
+        }
+    }
+
+    protected void fireTaskStarted() {
+        BuildEvent event = createBuildEvent();
+        for (int i = 0; i < listeners.size(); i++) {
+            BuildListener listener = (BuildListener) listeners.get(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.get(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.get(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);
     }
 }
Index: ProjectHelper.java
===================================================================
RCS file: /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/ProjectHelper.java,v
retrieving revision 1.12
diff -u -r1.12 ProjectHelper.java
--- ProjectHelper.java	2000/04/26 19:09:17	1.12
+++ ProjectHelper.java	2000/06/18 23:48:30
@@ -101,7 +101,9 @@
         try {
             parser = getParserFactory().newSAXParser().getParser();
             parser.setDocumentHandler(new RootHandler());
-            parser.parse(new InputSource(new FileReader(buildFile)));
+            InputSource source = new InputSource(new FileReader(buildFile));
+            source.setSystemId(buildFile.toURL().toString());
+            parser.parse(source);
         }
         catch(ParserConfigurationException exc) {
             throw new BuildException("Parser has not been configured correctly", exc);
@@ -299,7 +301,7 @@
             // take care of dependencies
 
             if (depends.length() > 0) {
-                StringTokenizer tok = 
+                StringTokenizer tok =
                     new StringTokenizer(depends, ",", false);
                 while (tok.hasMoreTokens()) {
                     target.addDependency(tok.nextToken().trim());
Index: Target.java
===================================================================
RCS file: /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/Target.java,v
retrieving revision 1.4
diff -u -r1.4 Target.java
--- Target.java	2000/04/26 19:09:17	1.4
+++ Target.java	2000/06/18 23:48:30
@@ -119,11 +119,21 @@
                 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);
Index: taskdefs/Ant.java
===================================================================
RCS file: /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Ant.java,v
retrieving revision 1.6
diff -u -r1.6 Ant.java
--- taskdefs/Ant.java	2000/03/28 20:40:18	1.6
+++ taskdefs/Ant.java	2000/06/18 23:48:30
@@ -86,9 +86,25 @@
 
     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.get(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 @@
             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) {
Index: taskdefs/Javac.java
===================================================================
RCS file: /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Javac.java,v
retrieving revision 1.12
diff -u -r1.12 Javac.java
--- taskdefs/Javac.java	2000/05/23 12:08:17	1.12
+++ taskdefs/Javac.java	2000/06/18 23:48:30
@@ -275,7 +275,7 @@
                                                     + ".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 @@
         // 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");
         }
     }