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> + * <someelement><br> + * <acommandline executable="/executable/to/run"><br> + * <argument value="argument 1" /><br> + * <argument line="argument_1 argument_2 argument_3" /><br> + * <argument value="argument 4" /><br> + * </acommandline><br> + * </someelement><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("<"); + break; + case '>': + temp.append(">"); + break; + case '&': + temp.append("&"); + 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> + * <sometask><br> + * <somepath> + * <element location="/path/to/file.jar" /> + * <element path="/path/to/file2.jar:/path/to/class2;/path/to/class3" /> + * <element location="/path/to/file3.jar" /> + * <element location="/path/to/file4.jar" /> + * </somepath> + * </sometask><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; + } +}
