Hi

Please find attached patches for the mutch discussed Path object, JUnit
task, JavaCC task and the execution framework.
I put these into different patches for easier review.

If no disagreement is expressed on the list till tuesday, I will commit the
patches. Any enhancements sent to me by tuesday will go in as well.
Patches to build.xml and taskef are not included in ths email.


TODO
- add Project.resolveFile functionality to Path.
- Path should use the FileTokenizer instead of my home brew parser.
- Commandline should be able to change the current directory of the running
subprocess, like the Execute task does.
- improve documentation.


Thanks
- tom

--
* Thomas Haas             <mailto:[EMAIL PROTECTED]>
* SoftWired AG                   <http://ww.softwired-inc.com/>
* Technoparkstr. 1  ***  CH-8005 Zurich  ***  +41-1-4452370


--- Commandline.java.orig       Sun Jul 02 14:07:38 2000
+++ Commandline.java    Wed Jun 07 16:45:38 2000
@@ -0,0 +1,207 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildException;
+import java.util.Vector;
+import java.util.StringTokenizer;
+
+
+/**
+ * Commandline objects help handling command lines specifying processes to
+ * execute.
+ *
+ * The class can be used to define a command line as nested elements or as a
+ * helper to define a command line by an application.
+ * <p>
+ * <code>
+ * &lt;someelement&gt;<br>
+ * &nbsp;&nbsp;&lt;acommandline executable="/executable/to/run"&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 1" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument line="argument_1 argument_2 
argument_3" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 4" /&gt;<br>
+ * &nbsp;&nbsp;&lt;/acommandline&gt;<br>
+ * &lt;/someelement&gt;<br>
+ * </code>
+ * The element <code>someelement</code> must provide a method
+ * <code>createAcommandline</code> which returns an instance of this class.
+ *
+ * @author [EMAIL PROTECTED]
+ */
+public class Commandline {
+
+    private Vector definition = new Vector();
+    private String executable = null;
+    private Argument argument = null;
+
+    /**
+     * Used for nested xml command line definitions.
+     */
+    public class Argument {
+
+        /**
+         * Sets a single commandline argument.
+         *
+         * @param value a single commandline argument.
+         */
+        public void setValue(String value) {
+            Commandline.this.addValue(value);
+        }
+
+        /**
+         * Line to split into several commandline arguments.
+         *
+         * @param line line to split into several commandline arguments
+         */
+        public void setLine(String line) {
+            Commandline.this.addLine(translateCommandline(line));
+        }
+    }
+
+
+    /**
+     * Creates an argument object.
+     * Each commandline object has at most one instance of the argument class.
+     * @return the argument object.
+     */
+    public Argument createArgument() {
+        if (argument == null) {
+            argument = new Argument();
+        }
+        return argument;
+    }
+
+
+    /**
+     * Sets the executable to run.
+     */
+    public void setExecutable(String executable) {
+        if (executable == null || executable.length() == 0) return;
+        this.executable = executable;
+    }
+
+
+    public String getExecutable() {
+        return executable;
+    }
+
+
+    public void addValue(String value) {
+        if (value == null || value.length() == 0) return;
+        definition.addElement(value);
+    }
+
+
+    public void addLine(String[] line) {
+        for (int i=0; i < line.length; i++) {
+            createArgument().setValue(line[i]);
+        }
+    }
+
+
+    /**
+     * Returns the executable and all defined arguments.
+     */
+    public String[] getCommandline() {
+        if (executable == null) return getArguments();
+        final String[] args = getArguments();
+        final String[] result = new String[args.length+1];
+        result[0] = executable;
+        System.arraycopy(args, 0, result, 1, args.length);
+        return result;
+    }
+
+
+    /**
+     * Returns all arguments defined by <code>addLine</code>,
+     * <code>addValue</code> or the argument object.
+     */
+    public String[] getArguments() {
+        final String [] result;
+        result = new String[definition.size()];
+        definition.copyInto(result);
+        return result;
+    }
+
+
+    public String toString() {
+        return toString(getCommandline());
+    }
+
+    public static String toString(String [] line) {
+        // empty path return empty string
+        if (line.length == 0) return "";
+
+        // path containing one or more elements
+        final StringBuffer result = new StringBuffer(line[0]);
+        for (int i=1; i < line.length; i++) {
+            result.append(' ');
+            result.append(line[i]);
+        }
+        return result.toString();
+    }
+
+
+    public static String[] translateCommandline(String to_process) {
+        // Runtime uses the same tokenizer.
+        final StringTokenizer token = new StringTokenizer(to_process);
+
+        final Commandline result = new Commandline();
+        while (token.hasMoreTokens()) {
+            result.addValue(token.nextToken());
+        }
+        return result.getArguments();
+    }
+}
--- CommandlineJava.java.orig   Sun Jul 02 14:07:46 2000
+++ CommandlineJava.java        Fri Jun 09 13:57:38 2000
@@ -0,0 +1,78 @@
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Path;
+import org.apache.tools.ant.Project;
+
+public class CommandlineJava {
+
+    private Commandline vmCommand = new Commandline();
+    private Commandline javaCommand = new Commandline();
+    private Path classpath = new Path();
+    private String vmVersion;
+
+
+    public CommandlineJava() {
+        setVm("java");
+        setVmversion(Project.getJavaVersion());
+    }
+
+    public Commandline.Argument createArgument() {
+        return javaCommand.createArgument();
+    }
+
+    public Commandline.Argument createVmArgument() {
+        return vmCommand.createArgument();
+    }
+
+    public void setVm(String vm) {
+        vmCommand.setExecutable(vm);
+    }
+
+    public void setVmversion(String value) {
+        vmVersion = value;
+    }
+
+    public void setClassname(String classname) {
+        javaCommand.setExecutable(classname);
+    }
+
+    public Path createClasspath() {
+        return classpath;
+    }
+
+    public String getVmversion() {
+        return vmVersion;
+    }
+
+    public String[] getCommandline() {
+        final Commandline result = new Commandline();
+        result.addLine(vmCommand.getCommandline());
+        final String classpath = this.classpath.toString();
+        if (classpath.length() > 0) {
+            result.createArgument().setValue("-classpath");
+            result.createArgument().setValue(classpath);
+        }
+        result.addLine(javaCommand.getCommandline());
+        return result.getCommandline();
+    }
+
+
+    public String toString() {
+        String[] list = getCommandline();
+
+        // empty path return empty string
+        if (list.length == 0) return "";
+
+        // path containing one or more elements
+        final StringBuffer result = new StringBuffer(list[0]);
+        for (int i=1; i < list.length; i++) {
+            result.append(' ');
+            result.append(list[i]);
+        }
+
+        return result.toString();
+    }
+
+}
--- Execute.java.orig   Sun Jul 02 14:07:58 2000
+++ Execute.java        Wed Jun 07 16:45:38 2000
@@ -0,0 +1,165 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+
+/**
+ * Runs an external program.
+ *
+ * @author [EMAIL PROTECTED]
+ */
+public class Execute {
+
+    /** Invalid exit code. **/
+    public final static int INVALID = Integer.MAX_VALUE;
+
+    private String[] cmdl = null;
+    private int exitValue = INVALID;
+    private ExecuteStreamHandler streamHandler;
+    private ExecuteWatchdog watchdog;
+
+
+    /**
+     * Creates a new execute object using <code>PumpStreamHandler</code> for
+     * stream handling.
+     */
+    public Execute() {
+        this(new PumpStreamHandler(), null);
+    }
+
+
+    /**
+     * Creates a new execute object.
+     *
+     * @param streamHandler the stream handler used to handle the input and
+     *        output streams of the subprocess.
+     * @param watchdog a watchdog for the subprocess or <code>null</code> to
+     *        to disable a timeout for the subprocess.
+     */
+    public Execute(ExecuteStreamHandler streamHandler, ExecuteWatchdog 
watchdog) {
+        this.streamHandler = streamHandler;
+        this.watchdog = watchdog;
+    }
+
+
+    /**
+     * Returns the commandline used to create a subprocess.
+     *
+     * @return the commandline used to create a subprocess
+     */
+    public String[] getCommandline() {
+        return cmdl;
+    }
+
+
+    /**
+     * Sets the commandline of the subprocess to launch.
+     *
+     * @param commandline the commandline of the subprocess to launch
+     */
+    public void setCommandline(String[] commandline) {
+        cmdl = commandline;
+    }
+
+
+    /**
+     * Runs a process defined by the command line and returns its exit status.
+     *
+     * @return the exit status of the subprocess or <code>INVALID</code>
+     * @exception java.io.IOExcpetion The exception is thrown, if launching
+     *            of the subprocess failed
+     */
+    public int execute() throws IOException {
+        final Process process = exec();
+        try {
+            streamHandler.setProcessInputStream(process.getOutputStream());
+            streamHandler.setProcessOutputStream(process.getInputStream());
+            streamHandler.setProcessErrorStream(process.getErrorStream());
+        } catch (IOException e) {
+            process.destroy();
+            throw e;
+        }
+        streamHandler.start();
+        if (watchdog != null) watchdog.start(process);
+        waitFor(process);
+        if (watchdog != null) watchdog.stop();
+        streamHandler.stop();
+        return getExitValue();
+    }
+
+
+    protected Process exec() throws IOException {
+        return Runtime.getRuntime().exec(getCommandline());
+    }
+
+    protected void waitFor(Process process) {
+        try {
+            process.waitFor();
+            setExitValue(process.exitValue());
+        } catch (InterruptedException e) {}
+    }
+
+    protected void setExitValue(int value) {
+        exitValue = value;
+    }
+
+    protected int getExitValue() {
+        return exitValue;
+    }
+}
--- ExecuteJava.java.orig       Sun Jul 02 14:08:06 2000
+++ ExecuteJava.java    Wed Jun 07 16:45:38 2000
@@ -0,0 +1,41 @@
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Path;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class ExecuteJava {
+
+    private Commandline javaCommand = null;
+
+    public void setJavaCommand(Commandline javaCommand) {
+        this.javaCommand = javaCommand;
+    }
+
+    public void execute() throws BuildException{
+        final String classname = javaCommand.getExecutable();
+        final Object[] argument = { javaCommand.getArguments() };
+        final Class[] param = { argument[0].getClass() };
+        try {
+            final Class target = Class.forName(classname);
+            final Method main = target.getMethod("main", param);
+            main.invoke(null, argument);
+        } catch (NullPointerException e) {
+            throw new BuildException("Could not find main() method in " + 
classname);
+        } catch (ClassNotFoundException e) {
+            throw new BuildException("Could not find " + classname + ". Make 
sure you have it in your classpath");
+        } catch (InvocationTargetException e) {
+            Throwable t = e.getTargetException();
+            if (!(t instanceof SecurityException)) {
+                throw new BuildException(t.toString());
+            }
+            // else ignore because the security exception is thrown
+            // if the invoked application tried to call System.exit()
+        } catch (Exception e) {
+            throw new BuildException(e.toString());
+        }
+   }
+}
\ No newline at end of file
--- ExecuteStreamHandler.java.orig      Sun Jul 02 14:08:18 2000
+++ ExecuteStreamHandler.java   Wed Jun 07 16:45:38 2000
@@ -0,0 +1,100 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Used by <code>Execute</code> to handle input and output stream of
+ * subprocesses.
+ *
+ * @author [EMAIL PROTECTED]
+ */
+public interface ExecuteStreamHandler {
+
+    /**
+     * Install a handler for the input stream of the subprocess.
+     *
+     * @param os output stream to write to the standard input stream of the
+     *           subprocess
+     */
+    public void setProcessInputStream(OutputStream os) throws IOException;
+
+    /**
+     * Install a handler for the error stream of the subprocess.
+     *
+     * @param is input stream to read from the error stream from the subprocess
+     */
+    public void setProcessErrorStream(InputStream is) throws IOException;
+
+    /**
+     * Install a handler for the output stream of the subprocess.
+     *
+     * @param is input stream to read from the error stream from the subprocess
+     */
+    public void setProcessOutputStream(InputStream is) throws IOException;
+
+    /**
+     * Start handling of the streams.
+     */
+    public void start() throws IOException;
+
+    /**
+     * Stop handlin of the streams - will not be restarted.
+     */
+    public void stop();
+}
--- ExecuteWatchdog.java.orig   Sun Jul 02 14:08:30 2000
+++ ExecuteWatchdog.java        Tue Jun 20 16:32:36 2000
@@ -0,0 +1,136 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+
+/**
+ * Destroys a process running for to long.
+ *
+ * @author [EMAIL PROTECTED]
+ */
+public class ExecuteWatchdog implements Runnable {
+
+    private Process process;
+    private int timeout;
+    private boolean watch = true;
+
+
+    /**
+     * Creates a new watchdog.
+     *
+     * @param timeout the timeout for the process.
+     */
+    public ExecuteWatchdog(int timeout) {
+        if (timeout < 1) {
+            throw new IllegalArgumentException("timeout lesser than 1.");
+        }
+        this.timeout = timeout;
+    }
+
+
+    /**
+     * Watches the given process and terminates it, if it runs for to long.
+     *
+     * @param process the process to watch.
+     */
+    public synchronized void start(Process process) {
+        if (process == null) {
+            throw new NullPointerException("process is null.");
+        }
+        if (this.process != null) {
+            throw new IllegalStateException("Already running.");
+        }
+        watch = true;
+        this.process = process;
+        final Thread thread = new Thread(this, "WATCHDOG");
+        thread.setDaemon(true);
+        thread.start();
+    }
+
+
+    /**
+     * Stops the watcher.
+     */
+    public synchronized void stop() {
+        watch = false;
+        notifyAll();
+        process = null;
+    }
+
+
+    /**
+     * Watches the process and terminates it, if it runs for to long.
+     */
+    public synchronized void run() {
+       try {
+           // This isn't a Task, don't have a Project object to log.
+           // project.log("ExecuteWatchdog: timeout = "+timeout+" msec",  
Project.MSG_VERBOSE);
+           final long until = System.currentTimeMillis() + timeout;
+           long now;
+           while (watch && until > (now = System.currentTimeMillis())) {
+               try {
+                   wait(until - now);
+               } catch (InterruptedException e) {}
+           }
+           if (watch) {
+               process.destroy();
+           }
+           stop();
+       } catch(Exception e) {
+           System.err.println("Exception in ExecuteWatchdog.run: "+e);
+        }
+    }
+}
+
--- LogOutputStream.java.orig   Sun Jul 02 14:08:44 2000
+++ LogOutputStream.java        Wed Jun 07 16:45:38 2000
@@ -0,0 +1,137 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.Project;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+
+
+/**
+ * Logs each line written to this stream to the log system of ant.
+ *
+ * Tries to be smart about line separators.<br>
+ * TODO: This class can be split to implement other line based processing
+ * of data written to the stream.
+ *
+ * @author [EMAIL PROTECTED]
+ */
+public class LogOutputStream extends OutputStream {
+
+    private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+    private boolean skip = false;
+
+    private Project project;
+    private String tag = null;
+    private int level = Project.MSG_INFO;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param project the project to log to.
+     * @param tag text to label data written to this stream.
+     * @param level loglevel used to log data written to this stream.
+     */
+    public LogOutputStream(Project project, String tag, int level) {
+        this.project = project;
+        this.tag = tag;
+        this.level = level;
+    }
+
+
+    /**
+     * Write the data to the buffer and flush the buffer, if a line
+     * separator is detected.
+     *
+     * @cc data to log (byte).
+     */
+    public void write(int cc) throws IOException {
+        final byte c = (byte)cc;
+        if ((c == '\n') || (c == '\r')) {
+            if (!skip) processBuffer();
+        } else buffer.write(cc);
+        skip = (c == '\r');
+    }
+
+
+    /**
+     * Converts the buffer to a string and sends it to <code>processLine</code>
+     */
+    protected void processBuffer() {
+        processLine(buffer.toString());
+        buffer.reset();
+    }
+
+    /**
+     * Logs a line to the log system of ant.
+     *
+     * @param line the line to log.
+     */
+    protected void processLine(String line) {
+        if (tag == null) project.log(line, level);
+        else project.log(line, tag, level);
+    }
+
+
+    /**
+     * Writes all remaining
+     */
+    public void close() throws IOException {
+        if (buffer.size() > 0) processBuffer();
+        super.close();
+    }
+}
--- LogStreamHandler.java.orig  Sun Jul 02 14:08:58 2000
+++ LogStreamHandler.java       Wed Jun 07 16:45:38 2000
@@ -0,0 +1,102 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.Project;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+
+/**
+ * Logs standard output and error of a subprocess to the log system of ant.
+ *
+ * @author [EMAIL PROTECTED]
+ */
+public class LogStreamHandler extends PumpStreamHandler {
+
+    private Project project;
+    private String outtag = null;
+    private String errtag = null;
+    private int outlevel = Project.MSG_INFO;
+    private int errlevel = Project.MSG_INFO;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param project the project to log to.
+     * @param outtag tag to label standard output
+     * @param outlevel the loglevel used to log standard output
+     * @param errtag tag to label standard error
+     * @param errlevel the loglevel used to log standard error
+     */
+    public LogStreamHandler(Project project,
+        String outtag, int outlevel, String errtag, int errlevel) {
+
+        this.project = project;
+        this.outtag = outtag;
+        this.errtag = errtag;
+        this.outlevel = outlevel;
+        this.errlevel = errlevel;
+    }
+
+    public void setProcessOutputStream(InputStream is) {
+        createProcessOutputPump(is, new LogOutputStream(project, outtag, 
outlevel));
+    }
+
+    public void setProcessErrorStream(InputStream is) {
+        createProcessErrorPump(is, new LogOutputStream(project, errtag, 
errlevel));
+    }
+
+}
\ No newline at end of file
--- PumpStreamHandler.java.orig Sun Jul 02 14:10:20 2000
+++ PumpStreamHandler.java      Wed Jun 07 16:45:38 2000
@@ -0,0 +1,122 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Copies standard output and error of subprocesses to standard output and
+ * error of the parent process.
+ *
+ * TODO: standard input of the subprocess is not implemented.
+ *
+ * @author [EMAIL PROTECTED]
+ */
+public class PumpStreamHandler implements ExecuteStreamHandler {
+
+    private Thread inputThread;
+    private Thread errorThread;
+
+
+    public void setProcessOutputStream(InputStream is) {
+        createProcessOutputPump(is, System.out);
+    }
+
+
+    public void setProcessErrorStream(InputStream is) {
+        createProcessErrorPump(is, System.err);
+    }
+
+
+    public void setProcessInputStream(OutputStream os) {
+    }
+
+
+    public void start() {
+        inputThread.start();
+        errorThread.start();
+    }
+
+
+    public void stop() {
+        try {
+            inputThread.join();
+        } catch(InterruptedException e) {}
+        try {
+            errorThread.join();
+        } catch(InterruptedException e) {}
+    }
+
+    protected void createProcessOutputPump(InputStream is, OutputStream os) {
+        inputThread = createPump(is, os);
+    }
+
+    protected void createProcessErrorPump(InputStream is, OutputStream os) {
+        errorThread = createPump(is, os);
+    }
+
+
+    /**
+     * Creates a stream pumper to copy the given input stream to the given 
output stream.
+     */
+    protected Thread createPump(InputStream is, OutputStream os) {
+        final Thread result = new Thread(new StreamPumper(is, os));
+        result.setDaemon(true);
+        return result;
+    }
+
+}
\ No newline at end of file
--- StreamPumper.java.orig      Sun Jul 02 14:10:26 2000
+++ StreamPumper.java   Wed Jun 07 16:45:38 2000
@@ -0,0 +1,109 @@
+
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+
+/**
+ * Copies all data from an input stream to an output stream.
+ *
+ * @author [EMAIL PROTECTED]
+ */
+public class StreamPumper implements Runnable {
+
+    // TODO: make SIZE and SLEEP instance variables.
+    // TODO: add a status flag to note if an error occured in run.
+
+    private final static int SLEEP = 5;
+    private final static int SIZE = 128;
+    private InputStream is;
+    private OutputStream os;
+
+
+    /**
+     * Create a new stream pumper.
+     *
+     * @param is input stream to read data from
+     * @param os output stream to write data to.
+     */
+    public StreamPumper(InputStream is, OutputStream os) {
+        this.is = is;
+        this.os = os;
+    }
+
+
+    /**
+     * Copies data from the input stream to the output stream.
+     *
+     * Terminates as soon as the input stream is closed or an error occurs.
+     */
+    public void run() {
+        final byte[] buf = new byte[SIZE];
+
+        int length;
+        try {
+            while ((length = is.read(buf)) > 0) {
+                os.write(buf, 0, length);
+                try {
+                    Thread.sleep(SLEEP);
+                } catch (InterruptedException e) {}
+            }
+        } catch(IOException e) {}
+    }
+}
--- JavaCC.java.orig    Sun Jul 02 14:15:10 2000
+++ JavaCC.java Fri Jun 09 14:05:24 2000
@@ -0,0 +1,178 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Path;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+import java.io.File;
+import java.io.IOException;
+
+public class JavaCC extends Task {
+
+    private Path userclasspath = new Path();
+    private File metahome = null;
+    private File metaworkingdir = null;
+    private File target = null;
+    private boolean cleanupHack = false;
+    private CommandlineJava cmdl = new CommandlineJava();
+
+
+    public void setMetamatahome(String metamatahome) {
+        this.metahome = new File(metamatahome);
+    }
+
+    public void setWorkingdir(String workingdir) {
+        this.metaworkingdir = new File(workingdir);
+    }
+
+    public void setTarget(String testcase) {
+        target = new File(Path.translateFile(testcase));
+    }
+
+    public Path createUserclasspath() {
+        return userclasspath;
+    }
+
+
+    public void setCleanupHack(String value) {
+        cleanupHack = project.toBoolean(value);
+    }
+
+    public JavaCC() {
+        cmdl.setVm("java");
+        cmdl.setClassname("com.metamata.jj.MParse");
+    }
+
+
+    public void execute() throws BuildException {
+
+        if (target == null || !target.isFile()) {
+            throw new BuildException("Invalid target: " + target);
+        }
+        final File javaFile = new File(target.toString().substring(0,
+                              target.toString().indexOf(".jj")) + ".java");
+        if (javaFile.exists() && target.lastModified() < 
javaFile.lastModified()) {
+            project.log("Target is already build - skipping (" + target + ")");
+            return;
+        }
+        cmdl.createArgument().setValue(target.getAbsolutePath());
+
+        if (metahome == null || !metahome.isDirectory()) {
+            throw new BuildException("Metamatahome not valid.");
+        }
+        if (metaworkingdir == null || !metaworkingdir.isDirectory()) {
+            throw new BuildException("Workingdir not set.");
+        }
+        if (userclasspath == null) {
+            throw new BuildException("Userclasspath not set.");
+        }
+
+        final Path classpath = cmdl.createClasspath();
+        classpath.createElement().setLocation(metahome.getAbsolutePath() + 
"/lib/metamatadebug.jar");
+        classpath.createElement().setLocation(metahome.getAbsolutePath() + 
"/lib/metamata.jar");
+        classpath.createElement().setLocation(metahome.getAbsolutePath() + 
"/lib/JavaCC.zip");
+
+        final Commandline.Argument arg = cmdl.createVmArgument();
+        arg.setValue("-mx140M");
+        arg.setValue("-Dmwp=" + metaworkingdir.getAbsolutePath());
+        arg.setValue("-Dmetamata.home=" + metahome.getAbsolutePath());
+        arg.setValue("-Dmetamata.java=java");
+        arg.setValue("-Dmetamata.java.options=-mx140M");
+        arg.setValue("-Dmetamata.java.options.classpath=-classpath");
+        arg.setValue("-Dmetamata.java.compiler=javac");
+        arg.setValue("-Dmetamata.java.compiler.options.0=-J-mx64M");
+        arg.setValue("-Dmetamata.java.compiler.options.classpath=-classpath");
+        arg.setValue("-Dmetamata.language=en");
+        arg.setValue("-Dmetamata.country=US");
+        arg.setValue("-Dmetamata.classpath=" + userclasspath);
+
+        final Execute process = new Execute(new LogStreamHandler(project,
+            "  JavaCC", Project.MSG_INFO,
+            "X JavaCC", Project.MSG_INFO), null);
+        project.log(cmdl.toString(), Project.MSG_VERBOSE);
+        process.setCommandline(cmdl.getCommandline());
+
+        try {
+            try {
+                if (process.execute() != 0) {
+                    throw new BuildException("JavaCC failed.");
+                }
+            } finally {
+                if (cleanupHack) {
+                    final File oo393 = new File(javaFile.getParentFile(),
+                            "OO393.class");
+                    if (oo393.exists()) {
+                        project.log("Removing stale file: " + oo393.getName());
+                        oo393.delete();
+                    }
+                    final File sunjj = new File(javaFile.getParentFile(),
+                            "__jj" + javaFile.getName().substring(0,
+                            javaFile.getName().indexOf(".java")) + ".sunjj");
+                    if (sunjj.exists()) {
+                        project.log("Removing stale file: " + sunjj.getName());
+                        sunjj.delete();
+                    }
+                }
+            }
+        }
+        catch (IOException e) {
+            throw new BuildException("Failed to launch JavaCC: " + e);
+        }
+    }
+
+}
--- JUnitResultFormatter.java.orig      Sun Jul 02 14:15:56 2000
+++ JUnitResultFormatter.java   Wed Jun 07 16:45:38 2000
@@ -0,0 +1,75 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import junit.framework.TestListener;
+
+/**
+ * This Interface describes classes that format the results of a JUnit
+ * testrun.
+ * 
+ * @author Stefan Bodewig <a href="mailto:[EMAIL PROTECTED]">[EMAIL 
PROTECTED]</a>
+ */
+
+public interface JUnitResultFormatter extends TestListener {
+    /**
+     * The whole testsuite started.
+     */
+    public void startTestSuite(JUnitTest suite);
+    /**
+     * The whole testsuite ended.
+     */
+    public void endTestSuite(JUnitTest suite);
+}
--- JUnitTask.java.orig Sun Jul 02 14:16:08 2000
+++ JUnitTask.java      Thu Jun 22 17:40:38 2000
@@ -0,0 +1,279 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Path;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * Ant task to run JUnit tests.
+ *
+ * JUnit is a framework to create unit test. It has been initially
+ * created by Erich Gamma and Kent Beck.
+ * JUnit can be found at <a
+ * href="ftp://www.armaties.com/D/home/armaties/ftp/TestingFramework/JUnit/";
+ * >ftp://www.armaties.com/D/home/armaties/ftp/TestingFramework/JUnit/</a>.
+ * <p>
+ * This ant task runs a single TestCase. By default it spans a new Java VM
+ * to prevent interferences between different testcases, unless
+ * <code>fork</code> has been disabled.
+ *
+ * @author Thomas Haas
+ */
+public class JUnitTask extends Task {
+
+    // <XXX> private final static int HALT_NOT = 1;
+    // <XXX> private final static int HALT_IMMEDIATELY = 2;
+    // <XXX> private final static int HALT_AT_END = 3;
+
+    private CommandlineJava commandline = new CommandlineJava();
+    private Vector tests = new Vector();
+
+    private JUnitTest defaults = new JUnitTest();
+    private boolean defaultOutfile = true;
+    private Integer timeout = null;
+
+    // <XXX> private int haltOnError = HALT_AT_END;
+    // <XXX> private int haltOnFailure = HALT_AT_END;
+
+    /**
+     * Set the path to junit classes.
+     * @param junit path to junit classes.
+     */
+    public void setJunit(String junit) {
+        commandline.createClasspath().createElement().setLocation(junit);
+    }
+
+    public void setDefaulthaltonerror(String value) {
+        defaults.setHaltonerror(value);
+    }
+
+    public void setDefaulthaltonfailure(String value) {
+        defaults.setHaltonfailure(value);
+    }
+
+    public void setDefaultprintsummary(String value) {
+        defaults.setPrintsummary(value);
+    }
+
+    public void setDefaultprintxml(String value) {
+        defaults.setPrintxml(value);
+    }
+
+    public void setDefaultOutFile(String value) {
+        defaultOutfile = Project.toBoolean(value);
+    }
+
+    public void setTimeout(String value) {
+        timeout = new Integer(value);
+    }
+
+    public void setFork(String value) {
+        defaults.setFork(value);
+    }
+
+    public void setJvm(String value) {
+        defaults.setName(value);
+       commandline.setVm(value);
+    }
+
+    public void setJvmargs(String value) {
+       commandline.createVmArgument().setLine(value);
+    }
+
+
+    /**
+     * Set the classpath to be used by the testcase.
+     * @param classpath the classpath used to run the testcase.
+     */
+    /*public void setClasspath(String classpath) {
+        this.classpath = classpath;
+    }*/
+
+
+    public Path createClasspath() {
+        return commandline.createClasspath();
+    }
+
+    public JUnitTest createTest() {
+        final JUnitTest result;
+        result = new JUnitTest(
+            defaults.getFork(),
+            defaults.getHaltonerror(),
+            defaults.getHaltonfailure(),
+            defaults.getPrintsummary(),
+            defaults.getPrintxml(),
+            null, null);
+
+        tests.addElement(result);
+        return result;
+    }
+
+
+    /**
+     * Creates a new JUnitRunner and enables fork of a new Java VM.
+     */
+    public JUnitTask() throws Exception {
+        
commandline.setClassname("org.apache.tools.ant.taskdefs.optional.JUnitTestRunner");
+    }
+
+    /**
+     * Runs the testcase.
+     */
+    public void execute() throws BuildException {
+        boolean errorOccurred = false;
+        boolean failureOccurred = false;
+
+        final String oldclasspath = System.getProperty("java.class.path");
+
+        commandline.createClasspath().createElement().setPath(oldclasspath);
+        System.setProperty("java.class.path", 
commandline.createClasspath().toString());
+
+        Enumeration list = tests.elements();
+        while (list.hasMoreElements()) {
+            final JUnitTest test = (JUnitTest)list.nextElement();
+
+            final String filename = "TEST-" + test.getName() + ".xml";
+            if (new File(filename).exists()) {
+                project.log("Skipping " + test.getName());
+                continue;
+            }
+            project.log("Running " + test.getName());
+
+            if (defaultOutfile && (test.getOutfile() == null ||
+                test.getOutfile().length() == 0)) {
+
+                test.setOutfile("RUNNING-" + filename);
+            }
+
+            int exitValue = 2;
+
+            if (test.getFork()) {
+                try {
+                   // Create a watchdog based on the timeout attribute
+                    final Execute execute = new Execute(new 
PumpStreamHandler(), createWatchdog());
+                    final Commandline cmdl = new Commandline();
+                    cmdl.addLine(commandline.getCommandline());
+                    cmdl.addLine(test.getCommandline());
+                    execute.setCommandline(cmdl.getCommandline());
+                    project.log("Execute JUnit: " + cmdl, Project.MSG_VERBOSE);
+                    exitValue = execute.execute();
+                }
+                catch (IOException e) {
+                    throw new BuildException("Process fork failed.");
+                }
+            } else {
+                final Object[] arg = { test };
+                final Class[] argType = { arg[0].getClass() };
+                try {
+                    final Class target = 
Class.forName("org.apache.tools.ant.taskdefs.optional.JUnitTestRunner");
+                    final Method main = target.getMethod("runTest", argType);
+                    project.log("Load JUnit: " + test, Project.MSG_VERBOSE);
+                    exitValue = ((Integer)main.invoke(null, arg)).intValue();
+                } catch (InvocationTargetException e) {
+                    e.getTargetException().printStackTrace();
+                    throw new BuildException("Running test failed: " + 
e.getTargetException());
+                } catch (Exception e) {
+                    throw new BuildException("Running test failed: " + e);
+                }
+            }
+
+            boolean errorOccurredHere = exitValue == 2;
+            boolean failureOccurredHere = exitValue == 1;
+            if (exitValue != 0) {
+                rename("RUNNING-" + filename, "ERROR-" + filename);
+            } else {
+                rename("RUNNING-" + filename, filename);
+            }
+           // <XXX> later distinguish HALT_AT_END case
+            if (errorOccurredHere && test.getHaltonerror()
+                || failureOccurredHere && test.getHaltonfailure()) {
+                throw new BuildException("JUNIT FAILED");
+           } else if (errorOccurredHere || failureOccurredHere) {
+                project.log("JUNIT FAILED");
+            }
+
+           // Update overall test status
+            errorOccurred = errorOccurred || errorOccurredHere ;
+            failureOccurred = failureOccurred || failureOccurredHere ;
+        }
+
+       // <XXX> later add HALT_AT_END option
+        // Then test errorOccurred and failureOccurred here.
+    }
+
+    protected ExecuteWatchdog createWatchdog() throws BuildException {
+        if (timeout == null) return null;
+        return new ExecuteWatchdog(timeout.intValue());
+    }
+
+    private void rename(String source, String destination) throws 
BuildException {
+        final File src = new File(source);
+        final File dest = new File(destination);
+
+        if (dest.exists()) dest.delete();
+        src.renameTo(dest);
+    }
+}
--- JUnitTest.java.orig Sun Jul 02 14:16:18 2000
+++ JUnitTest.java      Wed Jun 07 16:45:38 2000
@@ -0,0 +1,150 @@
+
+/**
+ * Title:        <p>
+ * Description:  <p>
+ * Copyright:    Copyright (c) <p>
+ * Company:      <p>
+ * @author
+ * @version 1.0
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.Project;
+
+public class JUnitTest {
+    private boolean systemExit = false;
+    private boolean haltOnError = false;
+    private boolean haltOnFail = false;
+    private boolean printSummary = true;
+    private boolean printXml = true;
+    private String name = null;
+    private String outfile = null;
+    private boolean fork = false;
+
+    private long runs, failures, errors;
+    private long runTime;
+
+    public JUnitTest() {
+    }
+
+    public JUnitTest(boolean fork, boolean haltOnError, boolean haltOnFail, 
boolean printSummary, boolean printXml, String name, String outfile) {
+        this.fork = fork;
+        this.haltOnError = haltOnError;
+        this.haltOnFail = haltOnFail;
+        this.printSummary = printSummary;
+        this.printXml = printXml;
+        this.name  = name;
+        this.outfile = outfile;
+    }
+
+    public void setFork(String value) {
+        fork = Project.toBoolean(value);
+    }
+
+    public boolean getFork() {
+        return fork;
+    }
+
+    public void setHaltonerror(String value) {
+        haltOnError = Project.toBoolean(value);
+    }
+
+    public void setHaltonfailure(String value) {
+        haltOnFail = Project.toBoolean(value);
+    }
+
+    public void setPrintsummary(String value) {
+        printSummary = Project.toBoolean(value);
+    }
+
+    public void setPrintxml(String value) {
+        printXml = Project.toBoolean(value);
+    }
+
+    public void setName(String value) {
+        name = value;
+    }
+
+    public void setOutfile(String value) {
+        outfile = value;
+    }
+
+
+    public boolean getHaltonerror() {
+        return haltOnError;
+    }
+
+    public boolean getHaltonfailure() {
+        return haltOnFail;
+    }
+
+    public boolean getPrintsummary() {
+        return printSummary;
+    }
+
+    public boolean getPrintxml() {
+        return printXml;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getOutfile() {
+        return outfile;
+    }
+
+    public void setCommandline(String [] args) {
+        for (int i=0; i<args.length; i++) {
+            if (args[i] == null) continue;
+            if (args[i].startsWith("haltOnError=")) {
+                haltOnError = Project.toBoolean(args[i].substring(12));
+            } else if (args[i].startsWith("haltOnFailure=")) {
+                haltOnFail = Project.toBoolean(args[i].substring(14));
+            } else if (args[i].startsWith("printSummary=")) {
+                printSummary = Project.toBoolean(args[i].substring(13));
+            } else if (args[i].startsWith("printXML=")) {
+                printXml = Project.toBoolean(args[i].substring(9));
+            } else if (args[i].startsWith("outfile=")) {
+                outfile = args[i].substring(8);
+            }
+        }
+    }
+
+    public String[] getCommandline() {
+        final Commandline result = new Commandline();
+        if (name != null && name.length() > 0) {
+            result.setExecutable(name);
+        }
+        result.createArgument().setValue("exit=" + systemExit);
+        result.createArgument().setValue("haltOnError=" + haltOnError);
+        result.createArgument().setValue("haltOnFailure=" + haltOnFail);
+        result.createArgument().setValue("printSummary=" + printSummary);
+        result.createArgument().setValue("printXML=" + printXml);
+        if (outfile != null && outfile.length() > 0) {
+            result.createArgument().setValue("outfile=" + outfile);
+        }
+        return result.getCommandline();
+    }
+
+    public void setCounts(long runs, long failures, long errors) {
+        this.runs = runs;
+        this.failures = failures;
+        this.errors = errors;
+    }
+
+    public void setRunTime(long runTime) {
+        this.runTime = runTime;
+    }
+
+    public long runCount() {return runs;}
+    public long failureCount() {return failures;}
+    public long errorCount() {return errors;}
+    public long getRunTime() {return runTime;}
+
+
+    public String toString() {
+        return Commandline.toString(getCommandline());
+    }
+
+}
--- JUnitTestRunner.java.orig   Sun Jul 02 14:16:26 2000
+++ JUnitTestRunner.java        Wed Jun 07 16:45:38 2000
@@ -0,0 +1,325 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.Project;
+
+import junit.framework.*;
+import java.lang.reflect.*;
+import java.io.*;
+import java.util.Vector;
+
+/**
+ * Simple Testrunner for JUnit that runs all tests of a testsuite.
+ *
+ * <p>This TestRunner expects a name of a TestCase class as its
+ * argument. If this class provides a static suite() method it will be
+ * called and the resulting Test will be run.
+ *
+ * <p>Otherwise all public methods starting with "test" and taking no
+ * argument will be run.
+ *
+ * <p>Summary output is generated at the end.
+ *
+ * @author Stefan Bodewig <a href="mailto:[EMAIL PROTECTED]">[EMAIL 
PROTECTED]</a>
+ */
+
+public class JUnitTestRunner implements TestListener {
+
+    /**
+     * Holds the registered formatters.
+     */
+    private Vector formatters = new Vector();
+
+    /**
+     * Collects TestResults.
+     */
+    private TestResult res;
+
+    /**
+     * Flag for endTest.
+     */
+    private boolean failed = true;
+
+    /**
+     * The test I'm going to run.
+     */
+    private JUnitTest junitTest;
+
+    /**
+     * The corresponding testsuite.
+     */
+    private Test suite = null;
+
+    /**
+     * Returncode
+     */
+    private int retCode = 0;
+
+    public JUnitTestRunner(JUnitTest test) {
+        junitTest = test;
+        try {
+            if (junitTest.getPrintxml()) {
+                if (test.getOutfile() != null
+                    && test.getOutfile().length() > 0) {
+
+                    addFormatter(new XMLJUnitResultFormatter(
+                                     new PrintWriter(
+                                         new FileWriter(test.getOutfile(), 
false)
+                                             )
+                                         )
+                        );
+                } else {
+                    addFormatter(new XMLJUnitResultFormatter(
+                                     new PrintWriter(
+                                         new OutputStreamWriter(System.out), 
true)
+                                         )
+                        );
+                }
+            }
+
+            if (junitTest.getPrintsummary()) {
+                addFormatter(new SummaryJUnitResultFormatter());
+            }
+
+            Class testClass = Class.forName(junitTest.getName());
+
+            try {
+                Method suiteMethod= testClass.getMethod("suite", new Class[0]);
+                suite = (Test)suiteMethod.invoke(null, new Class[0]);
+            } catch(NoSuchMethodException e) {
+            } catch(InvocationTargetException e) {
+            } catch(IllegalAccessException e) {
+            }
+
+            if (suite == null) {
+                // try to extract a test suite automatically
+                // this will generate warnings if the class is no suitable Test
+                suite= new TestSuite(testClass);
+            }
+
+            res = new TestResult();
+            res.addListener(this);
+            for (int i=0; i < formatters.size(); i++) {
+                res.addListener((TestListener)formatters.elementAt(i));
+            }
+
+        } catch(Exception e) {
+            retCode = 2;
+
+            fireStartTestSuite();
+            for (int i=0; i < formatters.size(); i++) {
+                ((TestListener)formatters.elementAt(i)).addError(null, e);
+            }
+            junitTest.setCounts(1, 0, 1);
+            junitTest.setRunTime(0);
+            fireEndTestSuite();
+        }
+    }
+
+    public void run() {
+        long start = System.currentTimeMillis();
+
+        if (retCode != 0) { // had an exception in the constructor
+            return;
+        }
+
+        fireStartTestSuite();
+        suite.run(res);
+        junitTest.setRunTime(System.currentTimeMillis()-start);
+        junitTest.setCounts(res.runCount(), res.failureCount(),
+                            res.errorCount());
+        fireEndTestSuite();
+
+        if (res.errorCount() != 0) {
+            retCode = 2;
+        } else if (res.failureCount() != 0) {
+            retCode = 1;
+        }
+    }
+
+    /**
+     * Returns what System.exit() would return in the standalone version.
+     *
+     * @return 2 if errors occurred, 1 if tests failed else 0.
+     */
+    public int getRetCode() {
+        return retCode;
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A new Test is started.
+     */
+    public void startTest(Test t) {
+        failed = false;
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A Test is finished.
+     */
+    public void endTest(Test test) {
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A Test failed.
+     */
+    public void addFailure(Test test, Throwable t) {
+        failed = true;
+
+        if (junitTest.getHaltonfailure()) {
+            res.stop();
+        }
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>An error occured while running the test.
+     */
+    public void addError(Test test, Throwable t) {
+        failed = true;
+
+        if (junitTest.getHaltonerror()) {
+            res.stop();
+        }
+    }
+
+    private void fireStartTestSuite() {
+        for (int i=0; i<formatters.size(); i++) {
+            
((JUnitResultFormatter)formatters.elementAt(i)).startTestSuite(junitTest);
+        }
+    }
+
+    private void fireEndTestSuite() {
+        for (int i=0; i<formatters.size(); i++) {
+            
((JUnitResultFormatter)formatters.elementAt(i)).endTestSuite(junitTest);
+        }
+    }
+
+    public void addFormatter(JUnitResultFormatter f) {
+        formatters.addElement(f);
+    }
+
+    /**
+     * Entry point for standalone (forked) mode.
+     *
+     * Parameters: testcaseclassname plus (up to) 6 parameters in the
+     * format key=value.
+     *
+     * <table cols="3" border="1">
+     * <tr><th>key</th><th>description</th><th>default value</th></tr>
+     *
+     * <tr><td>exit</td><td>exit with System.exit after testcase is
+     * complete?</td><td>true</td></tr>
+     *
+     * <tr><td>haltOnError</td><td>halt test on
+     * errors?</td><td>false</td></tr>
+     *
+     * <tr><td>haltOnFailure</td><td>halt test on
+     * failures?</td><td>false</td></tr>
+     *
+     * <tr><td>printSummary</td><td>print summary to System.out?</td>
+     * <td>true</td></tr>
+     *
+     * <tr><td>printXML</td><td>generate XML report?</td>
+     * <td>false</td></tr>
+     *
+     * <tr><td>outfile</td><td>where to print the XML report - a
+     * filename</td> <td>System.out</td></tr>
+     *
+     * </table>
+     */
+    public static void main(String[] args) throws IOException {
+        boolean exitAtEnd = true;
+        boolean haltError = false;
+        boolean haltFail = false;
+        boolean printSummary = true;
+        boolean printXml = false;
+        PrintWriter out = null;
+
+        if (args.length == 0) {
+            System.err.println("required argument TestClassName missing");
+            if (exitAtEnd) {
+                System.exit(2);
+            }
+        } else {
+
+            JUnitTest test = new JUnitTest();
+            test.setName(args[0]);
+            args[0] = null;
+            test.setCommandline(args);
+            JUnitTestRunner runner = new JUnitTestRunner(test);
+            runner.run();
+
+            if (exitAtEnd) {
+                System.exit(runner.getRetCode());
+            }
+        }
+    }
+
+
+    public static int runTest(JUnitTest test) {
+        final JUnitTestRunner runner = new JUnitTestRunner(test);
+        runner.run();
+        return runner.getRetCode();
+    }
+
+} // JUnitTestRunner
--- XMLJUnitResultFormatter.java.orig   Sun Jul 02 14:16:46 2000
+++ XMLJUnitResultFormatter.java        Wed Jun 07 16:45:38 2000
@@ -0,0 +1,235 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.CharacterIterator;
+import java.text.NumberFormat;
+import java.text.StringCharacterIterator;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * Prints XML output of the test to a specified Writer.
+ *
+ * @author Stefan Bodewig <a href="mailto:[EMAIL PROTECTED]">[EMAIL 
PROTECTED]</a>
+ */
+
+public class XMLJUnitResultFormatter implements JUnitResultFormatter {
+
+    /**
+     * OutputStream for XML output.
+     */
+    private PrintWriter out;
+    /**
+     * Collects output during the test run.
+     */
+    private StringBuffer results = new StringBuffer();
+    /**
+     * platform independent line separator.
+     */
+    private static String newLine = System.getProperty("line.separator");
+    /**
+     * Formatter for timings.
+     */
+    private NumberFormat nf = NumberFormat.getInstance();
+    /**
+     * Timing helper.
+     */
+    private long lastTestStart = 0;
+
+    public XMLJUnitResultFormatter(PrintWriter out) {
+        this.out = out;
+    }
+
+    /**
+     * The whole testsuite ended.
+     */
+    public void endTestSuite(JUnitTest suite) {
+        out.println("<?xml version=\"1.0\"?>");
+        out.print("<testsuite name=\"");
+        out.print(suite.getName());
+        out.print("\" tests=\"");
+        out.print(suite.runCount());
+        out.print("\" failures=\"");
+        out.print(suite.failureCount());
+        out.print("\" errors=\"");
+        out.print(suite.errorCount());
+        out.print("\" time=\"");
+        out.print(nf.format(suite.getRunTime()/1000.0));
+        out.println(" sec\">");
+        out.print(results.toString());
+        out.println("</testsuite>");
+        out.flush();
+        out.close();
+    }
+
+    /**
+     * The whole testsuite started.
+     */
+    public void startTestSuite(JUnitTest suite) {
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A new Test is started.
+     */
+    public void startTest(Test t) {
+        lastTestStart = System.currentTimeMillis();
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A Test is finished.
+     */
+    public void endTest(Test test) {
+        formatTestCaseOpenTag(test);
+        results.append("  </testcase>");
+        results.append(newLine);
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A Test failed.
+     */
+    public void addFailure(Test test, Throwable t) {
+        formatError("failure", test, t);
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>An error occured while running the test.
+     */
+    public void addError(Test test, Throwable t) {
+        formatError("error", test, t);
+    }
+
+    /**
+     * Translates <, & and > to corresponding entities.
+     */
+    private String xmlEscape(String orig) {
+        if (orig == null) return "";
+        StringBuffer temp = new StringBuffer();
+        StringCharacterIterator sci = new StringCharacterIterator(orig);
+        for (char c = sci.first(); c != CharacterIterator.DONE;
+             c = sci.next()) {
+
+            switch (c) {
+            case '<':
+                temp.append("&lt;");
+                break;
+            case '>':
+                temp.append("&gt;");
+                break;
+            case '&':
+                temp.append("&amp;");
+                break;
+            default:
+                temp.append(c);
+                break;
+            }
+        }
+        return temp.toString();
+    }
+
+    private void formatTestCaseOpenTag(Test test) {
+        results.append("  <testcase");
+        if (test != null && test instanceof TestCase) {
+            results.append(" name=\"");
+            results.append(((TestCase) test).name());
+            results.append("\"");
+        }
+        results.append(" time=\"");
+        results.append(nf.format((System.currentTimeMillis()-lastTestStart)
+                                 / 1000.0));
+        results.append("\">");
+        results.append(newLine);
+    }
+
+    private void formatError(String type, Test test, Throwable t) {
+        formatTestCaseOpenTag(test);
+        results.append("    <");
+        results.append(type);
+        results.append(" message=\"");
+        results.append(xmlEscape(t.getMessage()));
+        results.append("\" type=\"");
+        results.append(t.getClass().getName());
+        results.append("\">");
+        results.append(newLine);
+
+        results.append("<![CDATA[");
+        results.append(newLine);
+        StringWriter swr = new StringWriter();
+        t.printStackTrace(new PrintWriter(swr, true));
+        results.append(swr.toString());
+        results.append("]]>");
+        results.append(newLine);
+
+        results.append("    </");
+        results.append(type);
+        results.append(">");
+        results.append(newLine);
+
+        results.append("  </testcase>");
+        results.append(newLine);
+    }
+
+
+} // XMLJUnitResultFormatter
--- Path.java.orig      Sun Jul 02 14:18:38 2000
+++ Path.java   Thu Jun 08 14:57:10 2000
@@ -0,0 +1,218 @@
+/*
+ * 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 [EMAIL PROTECTED]
+ *
+ * 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
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.util.Vector;
+import java.util.StringTokenizer;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+
+/**
+ * This object represents a path as used by CLASSPATH or PATH
+ * environment variable.
+ *
+ * <code>
+ * &lt;sometask&gt;<br>
+ * &nbsp;&nbsp;&lt;somepath&gt;
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;element location="/path/to/file.jar" /&gt;
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;element 
path="/path/to/file2.jar:/path/to/class2;/path/to/class3" /&gt;
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;element location="/path/to/file3.jar" /&gt;
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;element location="/path/to/file4.jar" /&gt;
+ * &nbsp;&nbsp;&lt;/somepath&gt;
+ * &lt;/sometask&gt;<br>
+ * </code>
+ *
+ * The object implemention <code>sometask</code> must provide a method called
+ * <code>createSomepath</code> which returns an instance of <code>Path</code>.
+ * Nested path definitions are handled by the Path object and must be labeled
+ * <code>path</code>.<p>
+ *
+ * The path element takes a parameter <code>path</code> which will be parsed
+ * and split into single elements. It will usually be used
+ * to define a path from an environment variable.
+ *
+ * @author [EMAIL PROTECTED]
+ */
+
+public class Path {
+
+    final static boolean DETECT_DOS = (File.pathSeparatorChar == ';');
+    private Vector definition = new Vector();
+
+
+
+    /**
+    * Adds a element definition to the path.
+    * @param location the location of the element to add (must not be
+    * <code>null</code> nor empty.
+    **/
+    public void setLocation(String location) {
+        if (location != null && location.length() > 0) {
+            definition.addElement(translateFile(location));
+        }
+    }
+
+
+    /**
+     * Parses a path definition and creates single PatheElements.
+     * @param path the path definition.
+     */
+    public void setPath(String path) {
+        final Vector elements = translatePath(path);
+        for (int i=0; i < elements.size(); i++) {
+            definition.addElement(elements.elementAt(i));
+        }
+    }
+
+
+    public Path createElement() {
+        return this;
+    }
+
+
+    /**
+     * Returns all path elements defined by this and netsed path objects.
+     * @return list of path elements.
+     */
+    public String[] list() {
+        final String[] result = new String[definition.size()];
+        definition.copyInto(result);
+        return result;
+    }
+
+
+    /**
+     * Returns a textual representation of the path, which can be used as
+     * CLASSPATH or PATH environment variable definition.
+     * @return a textual representation of the path.
+     */
+    public String toString() {
+        final String[] list = list();
+
+        // empty path return empty string
+        if (list.length == 0) return "";
+
+        // path containing one or more elements
+        final StringBuffer result = new StringBuffer(list[0].toString());
+        for (int i=1; i < list.length; i++) {
+            result.append(File.pathSeparatorChar);
+            result.append(list[i]);
+        }
+
+        return result.toString();
+    }
+
+
+
+    public static Vector translatePath(String source) {
+        final Vector result = new Vector();
+        if (source == null) return result;
+
+        final StringBuffer path = new StringBuffer(source);
+        int start = 0;
+
+        for (int i=0; i < path.length(); i++) {
+            if (!translateFileSep(path, i)) {
+                if (endOfElement(path, start, i)) {
+                    // EMPTY ELEMENT DETECTION
+                    if (start < i) {
+                        result.addElement(path.substring(start, i));
+                    }
+                    start = i+1;
+                }
+            }
+        }
+        if (start < (path.length())) {
+            result.addElement(path.substring(start));
+        }
+
+        return result;
+    }
+
+
+    public static String translateFile(String source) {
+        if (source == null) return "";
+
+        final StringBuffer result = new StringBuffer(source);
+        for (int i=0; i < result.length(); i++) {
+            translateFileSep(result, i);
+        }
+
+        return result.toString();
+    }
+
+
+    protected static boolean translateFileSep(StringBuffer buffer, int pos) {
+        if (buffer.charAt(pos) == '/' || buffer.charAt(pos) == '\\') {
+            buffer.setCharAt(pos, File.separatorChar);
+            return true;
+        }
+        return false;
+    }
+
+
+    protected static boolean endOfElement(StringBuffer buffer, int start, int 
pos) {
+        final char c = buffer.charAt(pos);
+
+        // DOS PATH DETECTION: SECOND CHARACTER IN ELEMENT IS :
+        if (DETECT_DOS && c == ':' && (pos - start) == 1) {
+            return false;
+        }
+
+        // PATH SEPERATOR DETECTION ON ':' AND ';' AND CURRENT PLATFORM
+        return c == ':' || c == ';' || c == File.pathSeparatorChar;
+    }
+}

Reply via email to