ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sbaill...@apache.org
Subject cvs commit: jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote Base64.java EventDispatcher.java Messenger.java Server.java SocketUtil.java TestRunEvent.java TestRunListener.java TestRunner.java
Date Fri, 01 Feb 2002 23:53:23 GMT
sbailliez    02/02/01 15:53:23

  Added:       proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit
                        ArrayEnumeration.java BatchTestElement.java
                        ClasspathTestCollector.java ClientElement.java
                        CompoundEnumeration.java FilterElement.java
                        JUnitHelper.java KeepAliveOutputStream.java
                        OutputAttribute.java RJUnitTask.java
                        Resources.properties ResultFormatterElement.java
                        ServerElement.java TestElement.java
                        WatchdogTest.java ZipScanner.java usecase.xml
               proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter
                        BaseFormatter.java BaseStreamFormatter.java
                        BriefFormatter.java FilterFormatter.java
                        FilterStackFormatter.java Formatter.java
                        PlainFormatter.java Resources.properties
                        SummaryFormatter.java XMLFormatter.java
               proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote
                        Base64.java EventDispatcher.java Messenger.java
                        Server.java SocketUtil.java TestRunEvent.java
                        TestRunListener.java TestRunner.java
  Removed:     proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/junit
                        ArrayEnumeration.java BatchTestElement.java
                        ClasspathTestCollector.java ClientElement.java
                        CompoundEnumeration.java FilterElement.java
                        FormatterElement.java JUnitHelper.java
                        KeepAliveOutputStream.java OutputAttribute.java
                        RJUnitTask.java Resources.properties
                        ServerElement.java TestElement.java
                        WatchdogTest.java ZipScanner.java
               proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/junit/formatter
                        BaseFormatter.java BaseStreamFormatter.java
                        BriefFormatter.java FilterFormatter.java
                        FilterStackFormatter.java Formatter.java
                        PlainFormatter.java Resources.properties
                        SummaryFormatter.java XMLFormatter.java
               proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/junit/remote
                        Base64.java EventDispatcher.java Messenger.java
                        Server.java SocketUtil.java TestRunEvent.java
                        TestRunListener.java TestRunner.java
  Log:
  Moving to rjunit package to avoid conflicts
  
  Revision  Changes    Path
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ArrayEnumeration.java
  
  Index: ArrayEnumeration.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.util.Enumeration;
  import java.util.NoSuchElementException;
  
  /**
   * Convenient enumeration over an array of objects.
   * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a>
   */
  class ArrayEnumeration implements Enumeration {
  
          /** object array */
          private Object[] array;
  
          /** current index */
          private int pos;
  
          /**
           * Initialize a new enumeration that wraps an array.
           * @param       array   the array of object to enumerate.
           */
          public ArrayEnumeration(Object[] array){
                  this.array = array;
                  this.pos = 0;
          }
          /**
           * Tests if this enumeration contains more elements.
           *
           * @return  <code>true</code> if and only if this enumeration object
           *           contains at least one more element to provide;
           *          <code>false</code> otherwise.
           */
          public boolean hasMoreElements() {
                  return (pos < array.length);
          }
  
          /**
           * Returns the next element of this enumeration if this enumeration
           * object has at least one more element to provide.
           *
           * @return     the next element of this enumeration.
           * @throws  NoSuchElementException  if no more elements exist.
           */
          public Object nextElement() throws NoSuchElementException {
                  if (hasMoreElements()) {
                          Object o = array[pos];
                          pos++;
                          return o;
                  }
                  throw new NoSuchElementException();
          }
  }
  
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/BatchTestElement.java
  
  Index: BatchTestElement.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.util.Enumeration;
  
  import junit.runner.TestCollector;
  
  import org.apache.tools.ant.types.Path;
  import org.apache.tools.ant.types.PatternSet;
  
  /**
   * A test element where tests files are specified by include/exclude
   * patterns. tests files location are specified by one ore multiple
   * path elements. (directory or archive).
   *
   * <pre>
   * <!ELEMENT batchtest>
   * <!ATTLIST batchtest path CDATA required>
   * </pre>
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class BatchTestElement implements TestCollector {
  
      private ClasspathTestCollector collector = new ClasspathTestCollector();
  
  // Test collector implementation
  
      public Enumeration collectTests() {
          return collector.collectTests();
      }
  
  // Ant bean accessors
  
      public void setPath(Path path) {
          collector.setPath(path);
      }
  
      public PatternSet.NameEntry createInclude() {
          return collector.createInclude();
      }
  
      public PatternSet.NameEntry createExclude() {
          return collector.createExclude();
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ClasspathTestCollector.java
  
  Index: ClasspathTestCollector.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.io.File;
  import java.util.Enumeration;
  import java.util.Hashtable;
  import java.util.Vector;
  
  import junit.runner.TestCollector;
  
  import org.apache.tools.ant.DirectoryScanner;
  import org.apache.tools.ant.Project;
  import org.apache.tools.ant.ProjectComponent;
  import org.apache.tools.ant.types.Path;
  import org.apache.tools.ant.types.PatternSet;
  
  /**
   * A rough implementation of a test collector that will collect tests
   * using include/exclude patterns in a set of paths. A path can either
   * be a directory or an archive. (zip or jar file)
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class ClasspathTestCollector extends ProjectComponent
          implements TestCollector {
  
      private final static int SUFFIX_LENGTH = ".class".length();
  
      private PatternSet patterns = new PatternSet();
  
      private Path path = null;
  
      public Enumeration collectTests() {
          Hashtable collected = new Hashtable();
          // start from last, so that first elements
          // override last one in case there are duplicates.
          // ie mimic classpath behavior.
          String[] paths = path.list();
          for (int i = paths.length - 1; i >= 0; i--) {
              File f = new File(paths[i]);
              Vector included = null;
              if (f.isDirectory()) {
                  included = gatherFromDirectory(f);
              } else if (f.getName().endsWith(".zip")
                      || f.getName().endsWith(".jar")) {
                  included = gatherFromArchive(f);
              } else {
                  continue;
              }
              // add tests to the already collected one
              final int includedCount = included.size();
              for (int j = 0; j < includedCount; j++) {
                  String testname = (String) included.elementAt(i);
                  collected.put(testname, "");
              }
          }
          return collected.keys();
      }
  
  
      protected Vector gatherFromDirectory(File dir) {
          Project project = getProject();
          DirectoryScanner ds = new DirectoryScanner();
          ds.setBasedir(dir);
          ds.setIncludes(patterns.getIncludePatterns(project));
          ds.setExcludes(patterns.getExcludePatterns(project));
          ds.scan();
          String[] included = ds.getIncludedFiles();
          return testClassNameFromFile(included);
      }
  
      protected Vector gatherFromArchive(File zip) {
          ZipScanner zs = new ZipScanner();
          zs.setBasedir(zip);
          zs.setIncludes(patterns.getIncludePatterns(project));
          zs.setExcludes(patterns.getExcludePatterns(project));
          zs.scan();
          String[] included = zs.getIncludedFiles();
          return testClassNameFromFile(included);
      }
  
      protected Vector testClassNameFromFile(String[] classFileNames) {
          Vector tests = new Vector(classFileNames.length);
          for (int i = 0; i < classFileNames.length; i++) {
              String file = classFileNames[i];
              if (isTestClass(file)) {
                  String classname = classNameFromFile(file);
                  tests.addElement(classname);
              }
          }
          return tests;
      }
  
      protected boolean isTestClass(String classFileName) {
          return classFileName.endsWith(".class");
      }
  
      protected String classNameFromFile(String classFileName) {
          // convert /a/b.class to a.b
          String s = classFileName.substring(0, classFileName.length() - SUFFIX_LENGTH);
          String s2 = s.replace(File.separatorChar, '.');
          if (s2.startsWith(".")) {
              s2 = s2.substring(1);
          }
          return s2;
      }
  
  // Ant bean accessors
  
      public void setPath(Path path) {
          this.path = path;
      }
  
      public PatternSet.NameEntry createInclude() {
          return patterns.createInclude();
      }
  
      public PatternSet.NameEntry createExclude() {
          return patterns.createExclude();
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ClientElement.java
  
  Index: ClientElement.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.io.BufferedOutputStream;
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.util.Enumeration;
  import java.util.Properties;
  import java.util.Vector;
  
  import junit.runner.TestCollector;
  
  import org.apache.avalon.excalibur.i18n.ResourceManager;
  import org.apache.avalon.excalibur.i18n.Resources;
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.Project;
  import org.apache.tools.ant.ProjectComponent;
  import org.apache.tools.ant.taskdefs.Execute;
  import org.apache.tools.ant.taskdefs.LogStreamHandler;
  import org.apache.tools.ant.types.Commandline;
  import org.apache.tools.ant.types.CommandlineJava;
  import org.apache.tools.ant.types.Path;
  import org.apache.tools.ant.util.FileUtils;
  
  /**
   * An element representing the client configuration.
   *
   * <pre>
   * <!ELEMENT server (jvmarg)* (classpath)* (test)* (batchtest)*>
   * <!ATTLIST server port numeric 6666>
   * <!ATTLIST server host CDATA 127.0.0.1>
   * </pre>
  
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public final class ClientElement extends ProjectComponent {
      /** resources */
      private final static Resources RES =
              ResourceManager.getPackageResources(ClientElement.class);
  
      /** port to contact the server. Default to 6666 */
      private int port = 6666;
  
      /** server hostname to connect to. Default to 127.0.0.1 */
      private String host = "127.0.0.1";
  
      /** test collector elements */
      private Vector testCollectors = new Vector();
  
      /** the command line to launch the TestRunner */
      private CommandlineJava cmd = new CommandlineJava();
  
      /** the parent task */
      private RJUnitTask parent;
  
      /** create a new client */
      public ClientElement(RJUnitTask value) {
          parent = value;
          cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunner");
      }
  
      /** core entry point */
      public final void execute() throws BuildException {
          try {
              preExecute();
              doExecute();
          } finally {
              postExecute();
          }
      }
  
      protected void preExecute() throws BuildException {
          // must appended to classpath to avoid conflicts.
          JUnitHelper.addClasspathEntry(createClasspath(), "/junit/framework/TestCase.class");
          JUnitHelper.addClasspathEntry(createClasspath(), "/org/apache/tools/ant/Task.class");
          JUnitHelper.addClasspathEntry(createClasspath(), "/org/apache/tools/ant/taskdefs/optional/junit/remote/TestRunner.class");
      }
  
      protected void doExecute() throws BuildException {
          File tmp = configureTestRunner();
          Execute execute = new Execute(new LogStreamHandler(parent, Project.MSG_INFO, Project.MSG_WARN));
          execute.setCommandline(cmd.getCommandline());
          execute.setAntRun(project);
  
          log(RES.getString("task.process-cmdline.log", cmd.toString()), Project.MSG_VERBOSE);
          int retVal = 0;
          try {
              retVal = execute.execute();
              if (retVal != 0){
                  throw new BuildException("task.process-failed.error");
              }
          } catch (IOException e) {
              String msg = RES.getString("task.process-failed.error");
              throw new BuildException(msg, e);
          } finally {
              tmp.delete();
          }
      }
  
      protected void postExecute() {
          // nothing
      }
  
      /**
       * @return all collected tests specified with test elements.
       */
      protected Enumeration collectTests() {
          Enumeration[] tests = new Enumeration[testCollectors.size()];
          for (int i = 0; i < testCollectors.size(); i++) {
              TestCollector te = (TestCollector) testCollectors.elementAt(i);
              tests[i] = te.collectTests();
          }
          return new CompoundEnumeration(tests);
      }
  
      /**
       * Configure the runner with the appropriate configuration file.
       * @return the reference to the temporary configuration file
       * to be deleted once the TestRunner has ended.
       */
      protected File configureTestRunner() throws BuildException {
          Properties props = new Properties();
          props.setProperty("debug", "true");
          props.setProperty("host", "127.0.0.1");
          props.setProperty("port", String.valueOf(port));
          // get all test classes to run...
          StringBuffer buf = new StringBuffer(10240);
          Enumeration classnames = collectTests();
          while (classnames.hasMoreElements()) {
              String classname = (String) classnames.nextElement();
              buf.append(classname).append(" ");
          }
          props.setProperty("classnames", buf.toString());
  
          // dump the properties to a temporary file.
          FileUtils futils = FileUtils.newFileUtils();
          File f = futils.createTempFile("junit-antrunner", "tmp", new File("."));
          OutputStream os = null;
          try {
              os = new BufferedOutputStream(new FileOutputStream(f));
              props.store(os, "JUnit Ant Runner configuration file");
          } catch (IOException e) {
              throw new BuildException(e);
          } finally {
              if (os != null) {
                  try {
                      os.close();
                  } catch (IOException e) {
                  }
              }
          }
  
          // configure the runner
          cmd.createArgument().setValue("-file");
          cmd.createArgument().setValue(f.getAbsolutePath());
          return f;
      }
  
  // --- Ant bean setters
  
      /** set the port to connect to */
      public void setPort(int value) {
          port = value;
      }
  
      /** set the host to contact */
      public void setHost(String value) {
          host = value;
      }
  
      /** Create a new JVM argument. */
      public Commandline.Argument createJvmarg() {
          return cmd.createVmArgument();
      }
  
      /** classpath to be set for running tests */
      public Path createClasspath() {
          return cmd.createClasspath(project);
      }
  
      /** add a single test element */
      public void addTest(TestElement value) {
          testCollectors.addElement(value);
      }
  
      /** add a batch test element */
      public void addBatchTest(BatchTestElement value) {
          testCollectors.addElement(value);
      }
  
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/CompoundEnumeration.java
  
  Index: CompoundEnumeration.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.util.Enumeration;
  import java.util.NoSuchElementException;
  
  /**
   * Convenient enumeration over an array of enumeration. For example:
   * <pre>
   * Enumeration e1 = v1.elements();
   * while (e1.hasMoreElements()){
   *    // do something
   * }
   * Enumeration e2 = v2.elements();
   * while (e2.hasMoreElements()){
   *    // do the same thing
   * }
   * </pre>
   * can be written as:
   * <pre>
   * Enumeration[] enums = { v1.elements(), v2.elements() };
   * Enumeration e = Enumerations.fromCompound(enums);
   * while (e.hasMoreElements()){
   *    // do something
   * }
   * </pre>
   * Note that the enumeration will skip null elements in the array. The following is
   * thus possible:
   * <pre>
   * Enumeration[] enums = { v1.elements(), null, v2.elements() }; // a null enumeration in the array
   * Enumeration e = Enumerations.fromCompound(enums);
   * while (e.hasMoreElements()){
   *    // do something
   * }
   * </pre>
   * @author <a href="mailto:sbailliez@imediation.com">Stephane Bailliez</a>
   */
  public class CompoundEnumeration implements Enumeration {
  
          /** enumeration array */
          private Enumeration[] enumArray;
  
          /** index in the enums array */
          private int index = 0;
  
      public CompoundEnumeration(Enumeration[] enumarray) {
                  this.enumArray = enumarray;
      }
  
          /**
           * Tests if this enumeration contains more elements.
           *
           * @return  <code>true</code> if and only if this enumeration object
           *           contains at least one more element to provide;
           *          <code>false</code> otherwise.
           */
      public boolean hasMoreElements() {
                  while (index < enumArray.length) {
                          if (enumArray[index] != null && enumArray[index].hasMoreElements()) {
                                  return true;
                          }
                          index++;
                  }
                  return false;
      }
  
          /**
           * Returns the next element of this enumeration if this enumeration
           * object has at least one more element to provide.
           *
           * @return     the next element of this enumeration.
           * @throws  NoSuchElementException  if no more elements exist.
           */
      public Object nextElement() throws NoSuchElementException {
                  if ( hasMoreElements() ) {
                          return enumArray[index].nextElement();
                  }
                  throw new NoSuchElementException();
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/FilterElement.java
  
  Index: FilterElement.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.lang.reflect.Constructor;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.FilterFormatter;
  import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.FilterStackFormatter;
  import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.Formatter;
  import org.apache.tools.ant.types.EnumeratedAttribute;
  
  /**
   * A filter element that can be used inside a ResultFormatterElement to denote
   * a filtering. Note that the filtering order correspond to the element
   * order. The first element being the top filter, the last element
   * being the bottom filter.
   *
   * <pre>
   * <!ELEMENT filter>
   * <!ATTLIST filter type (stack) required>
   * <!ATTLIST filter classname CDATA required>
   * </pre>
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class FilterElement {
  
      /** filter classname, is should inherit from FilterFormatter */
      private String classname;
  
      /**
       * Called by introspection on <tt>type</tt> attribute.
       * @see FilterAttribute
       */
      public void setType(FilterAttribute fa) {
          setClassName(fa.getClassName());
      }
  
      /**
       * Called by introspection on <tt>classname</tt> attribute.
       * It must inherit from <tt>FilterFormatter</tt>
       * @see FilterFormatter
       */
      public void setClassName(String name) {
          classname = name;
      }
  
      /**
       * Wrap this filter around a given formatter.
       * @throws BuildException if any error happens when creating this filter.
       */
      public Formatter createFilterFormatter(Formatter f) throws BuildException {
          try {
              Class clazz = Class.forName(classname);
              if (!FilterFormatter.class.isAssignableFrom(clazz)) {
                  throw new BuildException(clazz + " must be a FilterFormatter.");
              }
              Constructor ctor = clazz.getConstructor(new Class[]{Formatter.class});
              return (Formatter) ctor.newInstance(new Object[]{f});
          } catch (BuildException e) {
              throw e;
          } catch (Exception e) {
              throw new BuildException(e);
          }
      }
  
      /** a predefined set of filters w/ their class mapping */
      public static class FilterAttribute extends EnumeratedAttribute {
          /** the predefined alias for filters */
          private final static String[] VALUES = {"stack"};
  
          /** the class corresponding to the alias (in the same order) */
          private final static String[] CLASSNAMES = {FilterStackFormatter.class.getName()};
  
          public String[] getValues() {
              return VALUES;
          }
  
          /** get the classname matching the alias */
          public String getClassName() {
              return CLASSNAMES[getIndex()];
          }
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/JUnitHelper.java
  
  Index: JUnitHelper.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.io.File;
  import java.lang.reflect.Method;
  import java.net.URL;
  
  import junit.framework.Test;
  import junit.framework.TestSuite;
  
  import org.apache.tools.ant.types.Path;
  
  /**
   * A set of helpers functions to deal with JUnit.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public final class JUnitHelper {
  
      private final static String SUITE_METHODNAME = "suite";
  
      /**
       * This method parse the output of the method <tt>toString()</tt>
       * from the <tt>TestCase</tt> class. The format returned is:
       * <tt>name(classname)</tt>
       * @return an array with the elements in the order name, classname.
       */
      public static String[] parseTestString(String testname) {
          int p1 = testname.indexOf('(');
          int p2 = testname.indexOf(')', p1);
          return new String[]{
              testname.substring(0, p1),
              testname.substring(p1 + 1, p2)};
      }
  
      /**
       * Returns the Test corresponding to to the given class name
       * @param loader classloader to use when loading the class or
       * <tt>null</tt> for system classloader.
       * @param classname the classname of the test we want to extract.
       * @throws Exception a generic exception
       */
      public static Test getTest(ClassLoader loader, String classname) throws Exception {
          Class clazz = null;
          if (loader == null) {
              clazz = Class.forName(classname);
          } else {
              loader.loadClass(classname);
          }
          return getTest(clazz);
      }
  
  
      /**
       * Extract a test from a given class
       * @param clazz the class to extract a test from.
       * @throws Exception a generic exception
       */
      public static Test getTest(Class clazz) {
          try {
              Object obj = clazz.newInstance();
              if (obj instanceof TestSuite) {
                  return (TestSuite) obj;
              }
          } catch (Exception e) {
          }
          try {
              // check if there is a suite method
              Method suiteMethod = clazz.getMethod(SUITE_METHODNAME, new Class[0]);
              return (Test) suiteMethod.invoke(null, new Class[0]);
          } catch (Exception e) {
          }
          // try to extract a test suite automatically
          // this will generate warnings if the class is no suitable Test
          try {
              return new TestSuite(clazz);
          } catch (Exception e) {
          }
          return null;
      }
  
      /**
       * Search for the given resource and return the directory or archive
       * that contains it.
       *
       * <p>Doesn't work for archives in JDK 1.1 as the URL returned by
       * getResource doesn't contain the name of the archive.</p>
       *
       * @param resource the resource to look for in the JVM classpath.
       * @return the file or directory containing the resource or
       * <tt>null</tt> if it does not know how to handle it.
       */
      public static File getResourceEntry(String resource) {
          URL url = JUnitHelper.class.getResource(resource);
          if (url != null) {
              // can't find the resource...
              return null;
          }
          String u = url.toString();
          if (u.startsWith("jar:file:")) {
              int pling = u.indexOf("!");
              String jarName = u.substring(9, pling);
              return new File((new File(jarName)).getAbsolutePath());
          } else if (u.startsWith("file:")) {
              int tail = u.indexOf(resource);
              String dirName = u.substring(5, tail);
              return new File((new File(dirName)).getAbsolutePath());
          }
          // don't know how to handle it...
          return null;
      }
  
      /**
       * Add the entry corresponding to a specific resource to the
       * specified path instance. The entry can either be a directory
       * or an archive.
       * @param path the path to add the resource entry to.
       * @param resource the resource to look for.
       * @see #getResourceEntry(String)
       */
      public static void addClasspathEntry(Path path, String resource) {
          File f = getResourceEntry(resource);
          if (f != null) {
              path.createPathElement().setLocation(f);
          }
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/KeepAliveOutputStream.java
  
  Index: KeepAliveOutputStream.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.io.FilterOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  
  /**
   * Class that can be used to wrap <tt>System.out</tt> and <tt>System.err</tt>
   * without getting anxious about the client closing the stream.
   *
   * <p>
   * In code-language it means that it is not necessary to do:
   * <pre>
   * if (out != System.out && out!= System.err){
   *   out.close();
   * }
   * </pre>
   * </p>
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class KeepAliveOutputStream extends FilterOutputStream {
  
      public KeepAliveOutputStream(OutputStream out) {
          super(out);
      }
  
      /** this method does nothing */
      public void close() throws IOException {
          //
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/OutputAttribute.java
  
  Index: OutputAttribute.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.ProjectComponent;
  
  /**
   * Attempt to create an output specific attribute.
   * <p>
   * The possible output values are 'stdout' and 'stderr', otherwise
   * it is assumed that the value represent a file.
   * </p>
   * Note that stdout and stderr are wrapped by a <tt>KeepAliveOutputStream</tt>
   * so that the stream cannot be closed.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   * @see KeepAliveOutputStream
   */
  public class OutputAttribute extends ProjectComponent {
  
      /** keyword to represent stdout output */
      public final static String STDOUT = "stdout";
  
      /** keyword to represent stderr output */
      public final static String STDERR = "stderr";
  
      /** the selected value for output, either stdout,stderr or filepath */
      private String value;
  
      /**
       * Create a new output attribute from a value.
       */
      public OutputAttribute(String value) {
          this.value = value;
      }
  
      /**
       * @return the outputstream corresponding to the selected attribute.
       */
      public OutputStream getOutputStream() {
          if (STDOUT.equals(value)) {
              return new KeepAliveOutputStream(System.out);
          } else if (STDERR.equals(value)) {
              return new KeepAliveOutputStream(System.err);
          }
          File f = getProject().resolveFile(value);
          try {
              return new FileOutputStream(f);
          } catch (IOException e) {
              throw new BuildException(e);
          }
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/RJUnitTask.java
  
  Index: RJUnitTask.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import org.apache.avalon.excalibur.i18n.ResourceManager;
  import org.apache.avalon.excalibur.i18n.Resources;
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.Task;
  
  /**
   * The core JUnit task.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class RJUnitTask extends Task {
  
      private final static Resources RES =
              ResourceManager.getPackageResources(RJUnitTask.class);
  
      /** port to run the server on */
      private int port = -1;
  
      /** timeout period in ms */
      private long timeout = -1;
  
      /** client configuraiton element */
      private ClientElement client = null;
  
      /** server configuration element */
      private ServerElement server = null;
  
  // task implementation
  
      public void execute() throws BuildException {
          if (client == null && server == null) {
              throw new BuildException("Invalid state: need to be server, client or both");
          }
  
          // 1) server and client
          if (server != null && client != null) {
              ServerWorker worker = new ServerWorker();
              worker.start();
              client.execute();
              Exception caught = null;
              try {
                  worker.join();
                  caught = worker.getException();
              } catch (InterruptedException e){
                  caught = e;
              }
              if (caught != null){
                  throw new BuildException(caught);
              }
              return;
          }
  
          // 2) server only (waiting for client)
          if (server != null && client == null) {
              server.execute();
              return;
          }
  
          // 3) client only (connecting to server)
          if (server == null && client != null) {
              client.execute();
              return;
          }
      }
  
  // Ant bean accessors
  
      public void setPort(int port) {
          this.port = port;
      }
  
      public void setTimeout(long timeout) {
          this.timeout = timeout;
      }
  
      /**
       * create a new client in charge of running tests and sending
       * the results to the server that collect them.
       */
      public ClientElement createClient() {
          if (client == null) {
              client = new ClientElement(this);
          }
          return client;
      }
  
      /**
       * create a new client in charge of running tests and sending
       * the results to the server that collect them.
       */
      public ServerElement createServer() {
          if (server == null) {
              server = new ServerElement(this);
          }
          return server;
      }
  
  
      /** the worker to run the server on */
      class ServerWorker extends Thread {
          private Exception caught = null;
  
          public void run() {
              try {
                  server.execute();
                  System.out.println("PANIC !!!!!!");
              } catch (Exception e) {
                  caught = e;
              }
          }
  
          public Exception getException() {
              return caught;
          }
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/Resources.properties
  
  Index: Resources.properties
  ===================================================================
  # task
  task.process-cmdline.log = Executing {0}
  task.process-failed.error = Process failed.
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ResultFormatterElement.java
  
  Index: ResultFormatterElement.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.io.OutputStream;
  import java.io.File;
  import java.util.Properties;
  import java.util.StringTokenizer;
  import java.util.Vector;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.BriefFormatter;
  import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.Formatter;
  import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.XMLFormatter;
  import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.PlainFormatter;
  import org.apache.tools.ant.types.EnumeratedAttribute;
  
  /**
   * An element representing a <tt>Formatter</tt>
   *
   * <pre>
   * <!ELEMENT formatter (filter)*>
   * <!ATTLIST formatter type (plain|xml|brief) #REQUIRED>
   * <!ATTLIST formatter classname CDATA #REQUIRED>
   * <!ATTLIST formatter extension CDATA #IMPLIED>
   * <!ATTLIST formatter usefile (yes|no) no>
   * </pre>
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   *
   * @see RJUnitTask
   * @see Formatter
   */
  public class ResultFormatterElement {
  
      /** output stream for the formatter */
      private OutputStream out = new KeepAliveOutputStream(System.out);
  
      /** formatter classname */
      private String classname;
  
      /** the filters to apply to this formatter */
      private Vector filters = new Vector();
  
      /** the parameters set for configuration purposes */
      private Vector params = new Vector();
  
      /**
       * set an existing type of formatter.
       * @see TypeAttribute
       * @see #setClassname(String)
       */
      public void setType(TypeAttribute type) {
          setClassname(type.getClassName());
      }
  
      /**
       * <p> Set name of class to be used as the formatter.
       *
       * <p> This class must implement <code>Formatter</code>
       */
      public void setClassname(String classname) {
          this.classname = classname;
      }
  
      /**
       * Setting a comma separated list of filters in the specified order.
       * @see #addFilter(FilterElement)
       * @see FilterAttribute
       */
      public void setFilters(String filters) {
          StringTokenizer st = new StringTokenizer(filters, ",");
          while (st.hasMoreTokens()) {
              FilterElement fe = new FilterElement();
              FilterElement.FilterAttribute fa = new FilterElement.FilterAttribute();
              fa.setValue(st.nextToken());
              fe.setType(fa);
              addFilter(fe);
          }
      }
  
      /**
       * Add a filter to this formatter.
       */
      public void addFilter(FilterElement fe) {
          filters.addElement(fe);
      }
  
      /**
       * Add a parameter that can be used for configuration.
       */
      public void addParam(Parameter param) {
          params.addElement(param);
      }
  
      /**
       * Set whether the formatter should log to file.
       */
      public void setOutput(OutputAttribute output) {
          this.out = output.getOutputStream();
      }
  
      /**
       * create the Formatter corresponding to this element.
       */
      protected Formatter createFormatter() throws BuildException {
          if (classname == null) {
              throw new BuildException("you must specify type or classname");
          }
          Formatter f = null;
          try {
              Class clazz = Class.forName(classname);
              if (!Formatter.class.isAssignableFrom(clazz)) {
                  throw new BuildException(clazz + " is not a Formatter");
              }
              f = (Formatter) clazz.newInstance();
          } catch (BuildException e) {
              throw e;
          } catch (Exception e) {
              throw new BuildException(e);
          }
  
          // wrap filters in the reverse order: first = top, last = bottom.
          for (int i = filters.size() - 1; i >= 0; i--) {
              FilterElement fe = (FilterElement) filters.elementAt(i);
              f = fe.createFilterFormatter(f);
          }
  
          // create properties from parameters
          Properties props = new Properties();
          for (int i = 0; i < params.size(); i++){
              Parameter param = (Parameter)params.elementAt(i);
              props.put(param.getName(), param.getValue());
          }
          // it is assumed here that the filters are chaining til the
          // wrapped formatter.
          f.init(props);
          return f;
      }
  
      /**
       * <p> Enumerated attribute with the values "plain", "xml" and "brief".
       * <p> Use to enumerate options for <tt>type</tt> attribute.
       */
      public final static class TypeAttribute extends EnumeratedAttribute {
          private final static String[] VALUES = {"plain", "xml", "brief"};
          private final static String[] CLASSNAMES = {PlainFormatter.class.getName(), XMLFormatter.class.getName(), BriefFormatter.class.getName()};
  
          public String[] getValues() {
              return VALUES;
          }
  
          public String getClassName() {
              return CLASSNAMES[getIndex()];
          }
      }
  
      /** a parameter that be used to configure a formatter */
      public final static class Parameter {
          private String name;
          private String value;
  
          public void setName(String name) {
              this.name = name;
          }
  
          public void setLocation(File file) {
              setValue(file.getAbsolutePath());
          }
  
          public void setValue(String value) {
              this.value = value;
          }
  
          public String getName() {
              return this.name;
          }
  
          public String getValue() {
              return this.value;
          }
      }
  }
  
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ServerElement.java
  
  Index: ServerElement.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.util.Enumeration;
  import java.util.Vector;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.ProjectComponent;
  import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.Formatter;
  import org.apache.tools.ant.taskdefs.optional.rjunit.remote.Server;
  
  /**
   * An element representing the server configuration.
   *
   * <pre>
   * <!ELEMENT server (formatter)*>
   * <!ATTLIST server port numeric 6666>
   * <!ATTLIST server haltonfailure (yes|no) no>
   * <!ATTLIST server haltonerror (yes|no) no>
   * </pre>
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public final class ServerElement extends ProjectComponent {
  
      /** formatters that write the tests results */
      private Vector formatterElements = new Vector();
  
      /** port to run the server on. Default to 6666 */
      private int port = 6666;
  
      /** stop the client run if a failure occurs */
      private boolean haltOnFailure = false;
  
      /** stop the client run if an error occurs */
      private boolean haltOnError = false;
  
      /** the parent task */
      private RJUnitTask parent;
  
      private Server server;
  
      /** create a new server */
      public ServerElement(RJUnitTask value) {
          parent = value;
      }
  
      /** start the server and block until client has finished */
      public void execute() throws BuildException {
          // configure the server...
          server = new Server(port);
          Enumeration listeners = formatterElements.elements();
          while (listeners.hasMoreElements()) {
              ResultFormatterElement fe = (ResultFormatterElement)listeners.nextElement();
              Formatter formatter = fe.createFormatter();
              server.addListener( formatter );
          }
          // and run it. It will stop once a client has finished.
          try {
              server.start(true);
              server.shutdown();
          } catch (InterruptedException e){
              throw new BuildException(e);
          }
      }
  
      /** set the port to listen to */
      public void setPort(int value) {
          port = value;
      }
  
  //@fixme  logic problem here, should the server say to the client
  // that there it should stop or should the client do it itself ?
  
      public void setHaltOnFailure(boolean value) {
          haltOnFailure = value;
      }
  
      public void setHaltOnError(boolean value) {
          haltOnError = value;
      }
  
      /** add a new formatter element */
      public void addFormatter(ResultFormatterElement fe) {
          formatterElements.addElement(fe);
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/TestElement.java
  
  Index: TestElement.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.util.Enumeration;
  
  import junit.runner.TestCollector;
  
  /**
   * A simple test element.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class TestElement implements TestCollector {
  
      /** classname of JUnit test */
      private String name;
  
  //@fixme, a path is needed for a test.
  
      public Enumeration collectTests() {
          return new ArrayEnumeration(new String[]{name});
      }
  
  // Ant bean setters
  
      public void setName(String value) {
          this.name = value;
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/WatchdogTest.java
  
  Index: WatchdogTest.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 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", "Jakarta-Regexp", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import junit.extensions.TestDecorator;
  import junit.framework.AssertionFailedError;
  import junit.framework.Test;
  import junit.framework.TestResult;
  
  /**
   * A Test decorator that allows to cancel a test if it exceeds
   * a certain time. It can be used globally or individually over
   * each testcase.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class WatchdogTest extends TestDecorator {
  
      /** the time out delay in msecs */
      private long timeOut;
  
      /**
       * Create a new watchdog.
       * @param test the test to watch for
       * @param msecs the time out delay in msecs.
       */
      public WatchdogTest(Test test, long msecs) {
          super(test);
          timeOut = msecs;
      }
  
      public void run(TestResult result) {
          Thread worker = createWorker(result);
          worker.start();
  
          try {
              // wait at most the timeOut time.
              worker.join(timeOut);
  
              // if the thread is still alive, it must be killed.
              if (worker.isAlive()) {
                  worker.interrupt();
                  result.addFailure(getTest(),
                          new AssertionFailedError("Timed out after " + timeOut + "ms"));
              }
          } catch (InterruptedException e) {
              worker.interrupt();
              result.addError(getTest(), e);
              result.stop();
          }
      }
  
      /** create a new worker thread */
      protected Thread createWorker(final TestResult result) {
          Thread worker = new Thread("JUnit Test Worker") {
              public void run() {
                  getTest().run(result);
              }
          };
          return worker;
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ZipScanner.java
  
  Index: ZipScanner.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit;
  
  import java.io.File;
  import java.io.IOException;
  import java.util.Enumeration;
  import java.util.Vector;
  import java.util.zip.ZipEntry;
  import java.util.zip.ZipFile;
  
  import org.apache.tools.ant.DirectoryScanner;
  
  /**
   * Provide a way to scan entries in a zip file. Note that it extends
   * DirectoryScanner to make use of protected methods but implementation
   * may not be valid for some methods.
   * <p>
   * the setBaseDir() must be called to set the reference to the archive
   * file (.jar or .zip).
   * </p>
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class ZipScanner extends DirectoryScanner {
      public ZipScanner() {
      }
  
      public void setExcludes(String[] excludes) {
          super.setExcludes(excludes);
          normalize(this.excludes);
      }
  
      public void setIncludes(String[] includes) {
          super.setIncludes(includes);
          normalize(this.includes);
      }
  
      /**
       * normalize a set of paths so that it uses / otherwise matching will
       * fail beautifully since archives use / to denote a path.
       */
      protected void normalize(String[] files) {
          if (files != null) {
              for (int i = 0; i < files.length; i++) {
                  files[i] = files[i].replace('\\', '/');
              }
          }
      }
  
      /**
       * Scans the archive for files that match at least one include
       * pattern, and don't match any exclude patterns.
       *
       * @exception IllegalStateException when the zip file was set incorrecly
       */
      public void scan() {
          if (basedir == null) {
              throw new IllegalStateException("No zipfile set");
          }
          if (!basedir.exists()) {
              throw new IllegalStateException("zipfile " + basedir
                      + " does not exist");
          }
          if (basedir.isDirectory()) {
              throw new IllegalStateException("zipfile " + basedir
                      + " is not a file");
          }
  
          if (includes == null) {
              // No includes supplied, so set it to 'matches all'
              includes = new String[1];
              includes[0] = "**";
          }
          if (excludes == null) {
              excludes = new String[0];
          }
  
          filesIncluded = new Vector();
          filesNotIncluded = new Vector();
          filesExcluded = new Vector();
          dirsIncluded = new Vector();
          dirsNotIncluded = new Vector();
          dirsExcluded = new Vector();
  
          if (isIncluded("")) {
              if (!isExcluded("")) {
                  dirsIncluded.addElement("");
              } else {
                  dirsExcluded.addElement("");
              }
          } else {
              dirsNotIncluded.addElement("");
          }
          scandir(basedir, "", true);
      }
  
      protected void scandir(File file, String vpath, boolean fast) {
          ZipFile zip = null;
          try {
              zip = new ZipFile(file);
          } catch (IOException e) {
              throw new IllegalStateException(e.getMessage());
          }
  
          Enumeration entries = zip.entries();
          while (entries.hasMoreElements()) {
              ZipEntry entry = (ZipEntry) entries.nextElement();
              String name = entry.getName();
              // @fixme do we need to strip out entries that starts
              // with . or ./ ?
              if (entry.isDirectory()) {
                  if (isIncluded(name)) {
                      if (!isExcluded(name)) {
                          dirsIncluded.addElement(name);
                      } else {
                          everythingIncluded = false;
                          dirsExcluded.addElement(name);
                      }
                  } else {
                      everythingIncluded = false;
                      dirsNotIncluded.addElement(name);
                  }
              } else {
                  if (isIncluded(name)) {
                      if (!isExcluded(name)) {
                          filesIncluded.addElement(name);
                      } else {
                          everythingIncluded = false;
                          filesExcluded.addElement(name);
                      }
                  } else {
                      everythingIncluded = false;
                      filesNotIncluded.addElement(name);
                  }
              }
          }
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/usecase.xml
  
  Index: usecase.xml
  ===================================================================
  <project name="" basedir="." default="tests">
  
      <target name="tests">
  
          <rjunit port="1234">
              <server>
                  <formatter type="xml" filters="stacktrace"/>
                  <formatter type="plain" filters="stacktrace"/>
                  <formatter type="jms" filters="stacktrace">
                      <param name="queue" value="test_queue"/>
                  </formatter>
                  <formatter type="rmi" filters="stacktrace">
                      <param name="host" value="127.0.0.1"/>
                      <param name="port" value="6789"/>
                  </formatter>
              </server>
  
              <client host="127.0.0.1">
                  <classpath refid="test-classpath"/>
                  <jvmarg value="-Xmx=512MB"/>
                  <test name="org.apache.test.NullTest" if="condition1">
                  <batchtest path="${classpath}" unless="condition2">
                      <include name="**Test*"/>
                  </batchtest>
              </client>
          <rjunit>
      </target>
  
      <target name="server-only">
          <!-- will block until a client connect and finishes -->
          <rjunit port="1234">
              <server>
                  <formatter type="xml" filters="stacktrace"/>
                      <param name="file" location="test.xml"/>
                  </formatter>
              </server>
         </rjunit>
      </target>
  
      <target name="server-only">
          <!-- will connect to an existing server and send results -->
          <rjunit port="1234">
              <client host="127.0.0.1">
                  <classpath refid="test-classpath"/>
                  <jvmarg value="-Xmx=512MB"/>
                  <test name="org.apache.test.NullTest" if="condition1">
              </client>
         </rjunit>
      </target>
  
  </project>
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BaseFormatter.java
  
  Index: BaseFormatter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
  
  import java.util.Properties;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
  
  /**
   * Provide a common set of attributes and methods to factorize
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public abstract class BaseFormatter implements Formatter {
  
      /** number of errors */
      private int errorCount;
  
      /** number of failures */
      private int failureCount;
  
      /** number of runs (success + failure + error) */
      private int runCount;
  
      public void init(Properties props) throws BuildException {
      }
  
      protected void finalize() throws Throwable {
          super.finalize();
          close();
      }
  
      public void onTestStarted(TestRunEvent evt) {
          runCount++;
      }
  
      public void onTestEnded(TestRunEvent evt) {
      }
  
      public void onTestFailure(TestRunEvent evt) {
          failureCount++;
      }
  
      public void onTestError(TestRunEvent evt) {
          errorCount++;
      }
  
      public void onSuiteStarted(TestRunEvent evt) {
      }
  
      public void onSuiteEnded(TestRunEvent evt) {
      }
  
      public void onRunStarted(TestRunEvent evt) {
      }
  
      public void onRunEnded(TestRunEvent evt) {
          finished();
      }
  
      public void onRunStopped(TestRunEvent evt) {
          finished();
      }
  
      protected void finished() {
          close();
      }
  
      /** @return the number of errors */
      protected final int getErrorCount() {
          return errorCount;
      }
  
      /** @return the number of failures */
      protected final int getFailureCount() {
          return failureCount;
      }
  
      /** @return the number of runs */
      protected final int getRunCount() {
          return runCount;
      }
  
      /** helper method to flush and close the stream */
      protected void close() {
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BaseStreamFormatter.java
  
  Index: BaseStreamFormatter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
  
  import java.io.BufferedWriter;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.io.OutputStreamWriter;
  import java.io.PrintWriter;
  import java.util.Properties;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.taskdefs.optional.rjunit.KeepAliveOutputStream;
  
  /**
   * Base formatter providing default implementation to deal with
   * either stdout or a file.
   * <p>
   * The file is specified by initializing the formatter with
   * a filepath mapped by the key 'file'.
   * </p>
   * <p>
   * if no file key exists in the properties, it defaults to stdout.
   * </p>
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class BaseStreamFormatter extends BaseFormatter {
  
      /** the key used to specifiy a filepath */
      public final static String FILE_KEY = "file";
  
      /** writer to output the data to */
      private PrintWriter writer;
  
      public void init(Properties props) throws BuildException {
          String file = props.getProperty(FILE_KEY);
          OutputStream os = null;
          if (file != null) {
              try {
                  // fixme need to resolve the file !!!!
                  os = new FileOutputStream(file);
              } catch (IOException e) {
                  throw new BuildException(e);
              }
          } else {
              os = new KeepAliveOutputStream(System.out);
          }
          setOutput(os);
      }
  
      /**
       * Helper method to wrap the stream over an UTF8 buffered writer.
       */
      protected void setOutput(OutputStream value) {
          try {
              writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(value, "UTF8")), true);
          } catch (IOException e) {
              // should not happen
              throw new BuildException(e);
          }
      }
  
  
      protected void close() {
          if (writer != null) {
              writer.flush();
              writer.close();
          }
      }
  
      /**
       * @return the writer used to print data.
       */
      protected final PrintWriter getWriter() {
          return writer;
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BriefFormatter.java
  
  Index: BriefFormatter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
  
  import org.apache.avalon.excalibur.i18n.ResourceManager;
  import org.apache.avalon.excalibur.i18n.Resources;
  import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
  
  /**
   * Display additional messages from a <tt>SummaryFormatter</tt>
   * for failures and errors.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class BriefFormatter extends SummaryFormatter {
  
      private final static Resources RES =
              ResourceManager.getPackageResources(BriefFormatter.class);
  
      public void onTestFailure(TestRunEvent evt) {
          String msg = RES.getString("brief.status-failure.msg", evt.getName(), evt.getStackTrace());
          getWriter().println(msg);
          super.onTestFailure(evt);
      }
  
      public void onTestError(TestRunEvent evt) {
          String msg = RES.getString("brief.status-error.msg", evt.getName(), evt.getStackTrace());
          getWriter().println(msg);
          super.onTestError(evt);
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterFormatter.java
  
  Index: FilterFormatter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
  
  import java.util.Properties;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
  
  /**
   * A base class that can be used to filter data.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public abstract class FilterFormatter implements Formatter {
  
      private Formatter formatter;
  
      protected FilterFormatter(Formatter formatter) {
          setFormatter(formatter);
      }
  
      /** final to enforce chaining of initialization */
      public final void init(Properties props) throws BuildException {
          formatter.init(props);
      }
  
      public void onSuiteStarted(TestRunEvent evt) {
          formatter.onSuiteStarted(evt);
      }
  
      public void onSuiteEnded(TestRunEvent evt) {
          formatter.onSuiteEnded(evt);
      }
  
      public void onTestStarted(TestRunEvent evt) {
          formatter.onTestStarted(evt);
      }
  
      public void onTestEnded(TestRunEvent evt) {
          formatter.onTestEnded(evt);
      }
  
      public void onTestFailure(TestRunEvent evt) {
          formatter.onTestFailure(evt);
      }
  
      public void onTestError(TestRunEvent evt) {
          formatter.onTestError(evt);
      }
  
      public void onRunStarted(TestRunEvent evt) {
          formatter.onRunStarted(evt);
      }
  
      public void onRunEnded(TestRunEvent evt) {
          formatter.onRunEnded(evt);
      }
  
      public void onRunStopped(TestRunEvent evt) {
          formatter.onRunEnded(evt);
      }
  
      /** set the wrapped formatter */
      protected void setFormatter(Formatter value) {
          formatter = value;
      }
  
      /** return the wrapped formatter */
      protected Formatter getFormatter() {
          return formatter;
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterStackFormatter.java
  
  Index: FilterStackFormatter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
  
  import java.util.StringTokenizer;
  
  import org.apache.tools.ant.util.StringUtils;
  import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
  
  /**
   * Filtered Formatter that strips out unwanted stack frames from the full
   * stack trace, for instance it will filter the lines containing the
   * following matches:
   * <pre>
   *   junit.framework.TestCase
   *   junit.framework.TestResult
   *   junit.framework.TestSuite
   *   junit.framework.Assert.
   *   junit.swingui.TestRunner
   *   junit.awtui.TestRunner
   *   junit.textui.TestRunner
   *   java.lang.reflect.Method.invoke(
   *   org.apache.tools.ant.
   * </pre>
   * Removing all the above will help to make stacktrace more readable.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class FilterStackFormatter extends FilterFormatter {
  
      /** the set of matches to look for in a stack trace */
      private final static String[] DEFAULT_TRACE_FILTERS = new String[]{
          "junit.framework.TestCase",
          "junit.framework.TestResult",
          "junit.framework.TestSuite",
          "junit.framework.Assert.", // don't filter AssertionFailure
          "junit.swingui.TestRunner",
          "junit.awtui.TestRunner",
          "junit.textui.TestRunner",
          "java.lang.reflect.Method.invoke(",
          "org.apache.tools.ant."
      };
  
      /**
       * Creates a new <tt>FilterStackFormatter</tt>
       * @param formatter the formatter to be filtered.
       */
      public FilterStackFormatter(Formatter formatter) {
          super(formatter);
      }
  
      public void onTestFailure(TestRunEvent evt) {
          String filteredTrace = filter(evt.getStackTrace());
          evt.setStackTrace(filteredTrace);
          super.onTestFailure(evt);
      }
  
      public void onTestError(TestRunEvent evt) {
          String filteredTrace = filter(evt.getStackTrace());
          evt.setStackTrace(filteredTrace);
          super.onTestFailure(evt);
      }
  
      protected String filter(String trace){
          StringTokenizer st = new StringTokenizer(trace, "\r\n");
          StringBuffer buf = new StringBuffer(trace.length());
          while (st.hasMoreTokens()) {
              String line = st.nextToken();
              if (accept(line)) {
                  buf.append(line).append(StringUtils.LINE_SEP);
              }
          }
          return buf.toString();
      }
      /**
       * Check whether or not the line should be accepted.
       * @param the line to be check for acceptance.
       * @return <tt>true</tt> if the line is accepted, <tt>false</tt> if not.
       */
      protected boolean accept(String line) {
          for (int i = 0; i < DEFAULT_TRACE_FILTERS.length; i++) {
              if (line.indexOf(DEFAULT_TRACE_FILTERS[i]) > 0) {
                  return false;
              }
          }
          return true;
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/Formatter.java
  
  Index: Formatter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
  
  import java.util.Properties;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener;
  
  /**
   * The formatter interface.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public interface Formatter extends TestRunListener {
      /**
       * Initialize the formatter with some custom properties
       * For example it could be a filename, a port and hostname,
       * a database, etc...
       */
      public void init(Properties props) throws BuildException;
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/PlainFormatter.java
  
  Index: PlainFormatter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
  
  import java.util.Properties;
  
  import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
  
  /**
   * Default formatter to text.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class PlainFormatter extends BaseStreamFormatter {
  
      public void onSuiteStarted(TestRunEvent evt) {
          getWriter().println("  suite: " + evt.getName());
          super.onSuiteStarted(evt);
      }
  
      public void onSuiteEnded(TestRunEvent evt) {
          getWriter().println("  end suite");
          super.onSuiteEnded(evt);
      }
  
      public void onTestStarted(TestRunEvent evt) {
          getWriter().println("    running test: " + evt.getName());
      }
  
      public void onTestEnded(TestRunEvent evt) {
          getWriter().println("    success: " + evt.getName());
      }
  
      public void onTestFailure(TestRunEvent evt) {
          getWriter().println("    failure: " + evt.getName());
          getWriter().println(evt.getStackTrace());
      }
  
      public void onTestError(TestRunEvent evt) {
          getWriter().println("    error: " + evt.getName());
          getWriter().println(evt.getStackTrace());
      }
  
      public void onRunEnded(TestRunEvent evt) {
          getWriter().println("run ended");
      }
  
      public void onRunStopped(TestRunEvent evt) {
          getWriter().println("run stopped");
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/Resources.properties
  
  Index: Resources.properties
  ===================================================================
  # Summary formatter
  summary.finished.msg = TestSuite: \nTests run: {0, number, integer}, Failures: {1, number, integer}, Errors: {2, number, integer}, Time elapsed: {3, number, integer} sec\n
  
  # Brief formatter
  brief.status-error.msg = TestCase: {0}\tCaused an ERROR\n{1}\n
  brief.status-failure.msg = TestCase: {0}\tFAILED\n{1}\n
  
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/SummaryFormatter.java
  
  Index: SummaryFormatter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
  
  import org.apache.avalon.excalibur.i18n.ResourceManager;
  import org.apache.avalon.excalibur.i18n.Resources;
  
  /**
   * Display a summary message at the end of a testsuite stating
   * runs, failures, errors, and elapsed time.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class SummaryFormatter extends BaseStreamFormatter {
  
      private final static Resources RES =
              ResourceManager.getPackageResources(SummaryFormatter.class);
  
      protected void finished(long elapsedtime) {
          String msg = RES.getString("summary.finished.msg",
                  new Integer(getRunCount()),
                  new Integer(getFailureCount()),
                  new Integer(getErrorCount()),
                  new Long(elapsedtime / 1000));
          getWriter().println(msg);
          close();
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/XMLFormatter.java
  
  Index: XMLFormatter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
  
  import java.util.Hashtable;
  import java.io.IOException;
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  import org.w3c.dom.Text;
  
  import org.apache.tools.ant.util.DOMElementWriter;
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
  
  /**
   * XML Formatter. Due to the nature of the XML we are forced to store
   * everything in memory until it is finished. It might be resource
   * intensive when running lots of testcases.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class XMLFormatter extends BaseStreamFormatter {
  
      /** the testsuites element for the aggregate document */
      public final static String TESTSUITES = "testsuites";
  
      /** the testsuite element */
      public final static String TESTSUITE = "testsuite";
  
      /** the testcase element */
      public final static String TESTCASE = "testcase";
  
      /** the error element */
      public final static String ERROR = "error";
  
      /** the failure element */
      public final static String FAILURE = "failure";
  
      /** the system-err element */
      public final static String SYSTEM_ERR = "system-err";
  
      /** the system-out element */
      public final static String SYSTEM_OUT = "system-out";
  
      /** package attribute for the aggregate document */
      public final static String ATTR_PACKAGE = "package";
  
      /** name attribute for property, testcase and testsuite elements */
      public final static String ATTR_NAME = "name";
  
      /** time attribute for testcase and testsuite elements */
      public final static String ATTR_TIME = "time";
  
      /** errors attribute for testsuite elements */
      public final static String ATTR_ERRORS = "errors";
  
      /** failures attribute for testsuite elements */
      public final static String ATTR_FAILURES = "failures";
  
      /** tests attribute for testsuite elements */
      public final static String ATTR_TESTS = "tests";
  
      /** type attribute for failure and error elements */
      public final static String ATTR_TYPE = "type";
  
      /** message attribute for failure elements */
      public final static String ATTR_MESSAGE = "message";
  
      /** the properties element */
      public final static String PROPERTIES = "properties";
  
      /** the property element */
      public final static String PROPERTY = "property";
  
      /** value attribute for property elements */
      public final static String ATTR_VALUE = "value";
  
      /** The XML document. */
      private Document doc = getDocumentBuilder().newDocument();
  
      /**  The wrapper for the whole testsuite. */
      private Element rootElement = doc.createElement(TESTSUITE);
  
      /** Element for the current test. */
      private Hashtable testElements = new Hashtable();
  
      /** Timing helper. */
      private Hashtable testStarts = new Hashtable();
  
      public void onTestStarted(TestRunEvent evt) {
          //@fixme, eh, a testname only can obviouslly be a duplicate...
          testStarts.put(evt.getName(), evt);
          Element currentTest = doc.createElement(TESTCASE);
          currentTest.setAttribute(ATTR_NAME, evt.getName());
          rootElement.appendChild(currentTest);
          testElements.put(evt.getName(), currentTest);
          super.onTestStarted(evt);
          removeEvent(evt);
      }
  
      public void onTestEnded(TestRunEvent evt) {
          Element currentTest = (Element) testElements.get(evt);
          // with a TestSetup, startTest and endTest are not called.
          if (currentTest == null) {
              onTestStarted(evt);
              currentTest = (Element) testElements.get(evt.getName());
          }
          TestRunEvent start = (TestRunEvent)testStarts.get(evt);
          float time = ((evt.getTimeStamp() - start.getTimeStamp()) / 1000.0f);
          currentTest.setAttribute(ATTR_TIME, Float.toString(time));
          super.onTestEnded(evt);
          removeEvent(evt);
      }
  
      public void onTestFailure(TestRunEvent evt) {
          String type = evt.getType() == TestRunEvent.TEST_FAILURE ? FAILURE : ERROR;
          Element nested = doc.createElement(type);
          Element currentTest = (Element) testElements.get(evt.getName());
          currentTest.appendChild(nested);
  
          String[] args = parseFirstLine(evt.getStackTrace());
          if (args[1] != null && args[1].length() > 0) {
              nested.setAttribute(ATTR_MESSAGE, args[1]);
          }
          nested.setAttribute(ATTR_TYPE, args[0]);
          Text text = doc.createTextNode(evt.getStackTrace());
          nested.appendChild(text);
          super.onTestFailure(evt);
          removeEvent(evt);
      }
  
      protected void removeEvent(TestRunEvent evt){
          testStarts.remove(evt.getName());
          testElements.remove(evt.getName());
      }
  
      public void onRunStarted(TestRunEvent evt) {
          super.onRunStarted(evt);
      }
  
      public void onRunEnded(TestRunEvent evt) {
          super.onRunEnded(evt);
      }
  
      public void onRunStopped(TestRunEvent evt) {
          super.onRunStopped(evt);
      }
  
      protected void close() {
          DOMElementWriter domWriter = new DOMElementWriter();
          // the underlying writer uses UTF8 encoding
          getWriter().println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
          try {
              domWriter.write(rootElement, getWriter(), 0, "  ");
          } catch (IOException e){
              throw new BuildException(e);
          } finally {
              super.close();
          }
      }
  
      private static DocumentBuilder getDocumentBuilder() {
          try {
              return DocumentBuilderFactory.newInstance().newDocumentBuilder();
          } catch (Exception exc) {
              throw new ExceptionInInitializerError(exc);
          }
      }
  
      protected static String[] parseFirstLine(String trace) {
          int pos = trace.indexOf('\n');
          if (pos == -1) {
              return new String[]{trace, ""};
          }
          String line = trace.substring(0, pos);
          pos = line.indexOf(':');
          if (pos != -1) {
              String classname = line.substring(0, pos).trim();
              String message = line.substring(pos + 1).trim();
              return new String[]{classname, message};
          }
          return new String[]{trace, ""};
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Base64.java
  
  Index: Base64.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
  
  /**
   * This class has been taken from jakarta-commons-sandbox in the
   * util project. Once there is an official release of commons, it should
   * be replace to avoid duplication.
   * <p>
   * This class provides encode/decode for RFC 2045 Base64 as defined by
   * RFC 2045, N. Freed and N. Borenstein.  <a
   * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>:
   * Multipurpose Internet Mail Extensions (MIME) Part One: Format of
   * Internet Message Bodies. Reference 1996
   *
   * @author Jeffrey Rodriguez
   */
  public final class Base64 {
      static private final int BASELENGTH = 255;
      static private final int LOOKUPLENGTH = 64;
      static private final int TWENTYFOURBITGROUP = 24;
      static private final int EIGHTBIT = 8;
      static private final int SIXTEENBIT = 16;
      static private final int SIXBIT = 6;
      static private final int FOURBYTE = 4;
      static private final int SIGN = -128;
      static private final byte PAD = (byte) '=';
      static private byte[] base64Alphabet = new byte[BASELENGTH];
      static private byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
      //static private final Log log = LogSource.getInstance("org.apache.commons.util.Base64");
  
      static {
          for (int i = 0; i < BASELENGTH; i++) {
              base64Alphabet[i] = -1;
          }
          for (int i = 'Z'; i >= 'A'; i--) {
              base64Alphabet[i] = (byte) (i - 'A');
          }
          for (int i = 'z'; i >= 'a'; i--) {
              base64Alphabet[i] = (byte) (i - 'a' + 26);
          }
          for (int i = '9'; i >= '0'; i--) {
              base64Alphabet[i] = (byte) (i - '0' + 52);
          }
  
          base64Alphabet['+'] = 62;
          base64Alphabet['/'] = 63;
  
          for (int i = 0; i <= 25; i++)
              lookUpBase64Alphabet[i] = (byte) ('A' + i);
  
          for (int i = 26,  j = 0; i <= 51; i++, j++)
              lookUpBase64Alphabet[i] = (byte) ('a' + j);
  
          for (int i = 52,  j = 0; i <= 61; i++, j++)
              lookUpBase64Alphabet[i] = (byte) ('0' + j);
  
          lookUpBase64Alphabet[62] = (byte) '+';
          lookUpBase64Alphabet[63] = (byte) '/';
      }
  
      public static boolean isBase64(String isValidString) {
          return isArrayByteBase64(isValidString.getBytes());
      }
  
      public static boolean isBase64(byte octect) {
          //shall we ignore white space? JEFF??
          return (octect == PAD || base64Alphabet[octect] != -1);
      }
  
      public static boolean isArrayByteBase64(byte[] arrayOctect) {
          int length = arrayOctect.length;
          if (length == 0) {
              // shouldn't a 0 length array be valid base64 data?
              // return false;
              return true;
          }
          for (int i = 0; i < length; i++) {
              if (!Base64.isBase64(arrayOctect[i]))
                  return false;
          }
          return true;
      }
  
      /**
       * Encodes hex octects into Base64.
       *
       * @param binaryData Array containing binary data to encode.
       * @return Base64-encoded data.
       */
      public static byte[] encode(byte[] binaryData) {
          int lengthDataBits = binaryData.length * EIGHTBIT;
          int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
          int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
          byte encodedData[] = null;
  
  
          if (fewerThan24bits != 0) {
              //data not divisible by 24 bit
              encodedData = new byte[(numberTriplets + 1) * 4];
          } else {
              // 16 or 8 bit
              encodedData = new byte[numberTriplets * 4];
          }
  
          byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
  
          int encodedIndex = 0;
          int dataIndex = 0;
          int i = 0;
          //log.debug("number of triplets = " + numberTriplets);
          for (i = 0; i < numberTriplets; i++) {
              dataIndex = i * 3;
              b1 = binaryData[dataIndex];
              b2 = binaryData[dataIndex + 1];
              b3 = binaryData[dataIndex + 2];
  
              //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
  
              l = (byte) (b2 & 0x0f);
              k = (byte) (b1 & 0x03);
  
              encodedIndex = i * 4;
              byte val1 = ((b1 & SIGN) == 0)?(byte) (b1 >> 2):(byte) ((b1) >> 2 ^ 0xc0);
              byte val2 = ((b2 & SIGN) == 0)?(byte) (b2 >> 4):(byte) ((b2) >> 4 ^ 0xf0);
              byte val3 = ((b3 & SIGN) == 0)?(byte) (b3 >> 6):(byte) ((b3) >> 6 ^ 0xfc);
  
              encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
              //log.debug( "val2 = " + val2 );
              //log.debug( "k4   = " + (k<<4) );
              //log.debug(  "vak  = " + (val2 | (k<<4)) );
              encodedData[encodedIndex + 1] =
                      lookUpBase64Alphabet[val2 | (k << 4)];
              encodedData[encodedIndex + 2] =
                      lookUpBase64Alphabet[(l << 2) | val3];
              encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
          }
  
          // form integral number of 6-bit groups
          dataIndex = i * 3;
          encodedIndex = i * 4;
          if (fewerThan24bits == EIGHTBIT) {
              b1 = binaryData[dataIndex];
              k = (byte) (b1 & 0x03);
              //log.debug("b1=" + b1);
              //log.debug("b1<<2 = " + (b1>>2) );
              byte val1 = ((b1 & SIGN) == 0)?(byte) (b1 >> 2):(byte) ((b1) >> 2 ^ 0xc0);
              encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
              encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
              encodedData[encodedIndex + 2] = PAD;
              encodedData[encodedIndex + 3] = PAD;
          } else if (fewerThan24bits == SIXTEENBIT) {
  
              b1 = binaryData[dataIndex];
              b2 = binaryData[dataIndex + 1];
              l = (byte) (b2 & 0x0f);
              k = (byte) (b1 & 0x03);
  
              byte val1 = ((b1 & SIGN) == 0)?(byte) (b1 >> 2):(byte) ((b1) >> 2 ^ 0xc0);
              byte val2 = ((b2 & SIGN) == 0)?(byte) (b2 >> 4):(byte) ((b2) >> 4 ^ 0xf0);
  
              encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
              encodedData[encodedIndex + 1] =
                      lookUpBase64Alphabet[val2 | (k << 4)];
              encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
              encodedData[encodedIndex + 3] = PAD;
          }
  
          return encodedData;
      }
  
      /**
       * Decodes Base64 data into octects
       *
       * @param binaryData Byte array containing Base64 data
       * @return Array containing decoded data.
       */
      public static byte[] decode(byte[] base64Data) {
          // handle the edge case, so we don't have to worry about it later
          if (base64Data.length == 0) {
              return new byte[0];
          }
  
          int numberQuadruple = base64Data.length / FOURBYTE;
          byte decodedData[] = null;
          byte b1 = 0,b2 = 0,b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
  
          // Throw away anything not in base64Data
  
          int encodedIndex = 0;
          int dataIndex = 0;
          {
              // this sizes the output array properly - rlw
              int lastData = base64Data.length;
              // ignore the '=' padding
              while (base64Data[lastData - 1] == PAD) {
                  if (--lastData == 0) {
                      return new byte[0];
                  }
              }
              decodedData = new byte[lastData - numberQuadruple];
          }
  
          for (int i = 0; i < numberQuadruple; i++) {
              dataIndex = i * 4;
              marker0 = base64Data[dataIndex + 2];
              marker1 = base64Data[dataIndex + 3];
  
              b1 = base64Alphabet[base64Data[dataIndex]];
              b2 = base64Alphabet[base64Data[dataIndex + 1]];
  
              if (marker0 != PAD && marker1 != PAD) {
                  //No PAD e.g 3cQl
                  b3 = base64Alphabet[marker0];
                  b4 = base64Alphabet[marker1];
  
                  decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
                  decodedData[encodedIndex + 1] =
                          (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
                  decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
              } else if (marker0 == PAD) {
                  //Two PAD e.g. 3c[Pad][Pad]
                  decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
              } else if (marker1 == PAD) {
                  //One PAD e.g. 3cQ[Pad]
                  b3 = base64Alphabet[marker0];
  
                  decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
                  decodedData[encodedIndex + 1] =
                          (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
              }
              encodedIndex += 3;
          }
          return decodedData;
      }
  }
  
  
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/EventDispatcher.java
  
  Index: EventDispatcher.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
  
  import java.util.Vector;
  import java.io.InputStream;
  import java.io.IOException;
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  
  /**
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class EventDispatcher {
  
      /** the set of registered listeners */
      private Vector listeners = new Vector();
  
     /**
       * Add a new listener.
       * @param listener a listener that will receive events from the client.
       */
      public void addListener(TestRunListener listener) {
          listeners.addElement(listener);
      }
  
      public void removeListener(org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener listener) {
          listeners.removeElement(listener);
      }
  
     /**
       * Process a message from the client and dispatch the
       * appropriate message to the listeners.
       */
      public void dispatchEvent(TestRunEvent evt) {
         // I hate switch/case but no need to design a complex
         // system for limited events.
          switch (evt.getType()){
              case TestRunEvent.RUN_STARTED:
                  fireRunStarted(evt);
                  break;
              case TestRunEvent.RUN_ENDED:
                  fireRunEnded(evt);
                  break;
              case TestRunEvent.RUN_STOPPED:
                  fireRunStopped(evt);
                  break;
              case TestRunEvent.TEST_STARTED:
                  fireTestStarted(evt);
                  break;
              case TestRunEvent.TEST_ERROR:
                  fireTestError(evt);
                  break;
              case TestRunEvent.TEST_FAILURE:
                  fireTestFailure(evt);
                  break;
              case TestRunEvent.TEST_ENDED:
                  fireTestEnded(evt);
                  break;
              case TestRunEvent.SUITE_ENDED:
                  fireSuiteEnded(evt);
                  break;
              case TestRunEvent.SUITE_STARTED:
                  fireSuiteStarted(evt);
                  break;
              default:
                  // should not happen
          }
      }
  
      protected void fireRunStarted(TestRunEvent evt) {
          synchronized (listeners) {
              for (int i = 0; i < listeners.size(); i++) {
                  ((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onRunStarted(evt);
              }
          }
      }
  
      protected void fireRunEnded(TestRunEvent evt) {
          synchronized (listeners) {
              for (int i = 0; i < listeners.size(); i++) {
                  ((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onRunEnded(evt);
              }
          }
      }
  
      protected void fireTestStarted(TestRunEvent evt) {
          synchronized (listeners) {
              for (int i = 0; i < listeners.size(); i++) {
                  ((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onTestStarted(evt);
              }
          }
      }
  
      protected void fireTestEnded(TestRunEvent evt) {
          synchronized (listeners) {
              for (int i = 0; i < listeners.size(); i++) {
                  ((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onTestEnded(evt);
              }
          }
      }
  
      protected void fireTestFailure(TestRunEvent evt) {
          synchronized (listeners) {
              for (int i = 0; i < listeners.size(); i++) {
                  ((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onTestFailure(evt);
              }
          }
      }
  
      protected void fireTestError(TestRunEvent evt) {
          synchronized (listeners) {
              for (int i = 0; i < listeners.size(); i++) {
                  ((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onTestError(evt);
              }
          }
      }
  
      protected void fireSuiteStarted(TestRunEvent evt) {
          synchronized (listeners) {
              for (int i = 0; i < listeners.size(); i++) {
                  ((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onSuiteStarted(evt);
              }
          }
      }
  
      protected void fireSuiteEnded(TestRunEvent evt) {
          synchronized (listeners) {
              for (int i = 0; i < listeners.size(); i++) {
                  ((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onSuiteEnded(evt);
              }
          }
      }
  
      protected void fireRunStopped(TestRunEvent evt) {
          synchronized (listeners) {
              for (int i = 0; i < listeners.size(); i++) {
                  ((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onRunStopped(evt);
              }
          }
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Messenger.java
  
  Index: Messenger.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
  
  import java.io.OutputStream;
  import java.io.InputStream;
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  
  /**
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class Messenger {
  
      private InputStream in;
  
      private OutputStream out;
  
      public Messenger(InputStream in, OutputStream out) throws IOException {
          setOutputStream( new ObjectOutputStream(out) );
          setInputStream( new ObjectInputStream(in) );
      }
  
      protected void finalize() throws Throwable {
          close();
      }
  
      public void close() throws IOException {
          if (out != null) {
              out.flush();
              out.close();
              out = null;
          }
          if (in != null) {
              in.close();
              in = null;
          }
      }
  
      public TestRunEvent read() throws Exception {
          return (TestRunEvent)((ObjectInputStream)in).readObject();
      }
  
      public void writeEvent(TestRunEvent evt) throws IOException {
          ((ObjectOutputStream)out).writeObject(evt);
      }
  
      protected OutputStream getOutputStream(){
          return out;
      }
  
      protected InputStream getInputStream(){
          return in;
      }
  
      protected void setOutputStream(OutputStream out){
          this.out = out;
      }
  
      protected void setInputStream(InputStream in){
          this.in = in;
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Server.java
  
  Index: Server.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
  
  import java.io.IOException;
  import java.net.ServerSocket;
  import java.net.Socket;
  
  /**
   * The server that will receive events from a remote client.
   *
   * <i>
   * This code is based on the code from Erich Gamma made for the
   * JUnit plugin for <a href="http://www.eclipse.org">Eclipse</a> and is
   * merged with code originating from Ant 1.4.x.
   * </i>
   *
   * @see TestRunner
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class Server {
  
      /** the port where the server is listening */
      private int port = -1;
  
      /** the server socket */
      private ServerSocket server;
  
      /** the client that is connected to the server */
      private Socket client;
  
      /** the reader in charge of interpreting messages from the client */
      private Messenger messenger;
  
      private EventDispatcher dispatcher = new EventDispatcher();
  
      public Server(int port) {
          this.port = port;
      }
  
      protected void finalize() throws Exception {
          cancel();
          shutdown();
      }
  
      /**
       * add a new listener
       * @param listener a instance of a listener.
       */
      public void addListener(TestRunListener listener) {
          dispatcher.addListener(listener);
      }
  
      /**
       * remove an existing listener
       * @param listener a instance of a listener.
       */
      public void removeListener(TestRunListener listener) {
          dispatcher.removeListener(listener);
      }
  
      /** return whether there is a client running or not */
      public synchronized boolean isRunning() {
          return client != null && server != null && messenger != null;
      }
  
      /** start a server to the specified port */
      public void start() {
          try {
              start(false);
          } catch (InterruptedException e){
          }
      }
  
      /** start a server to the specified port and wait for end */
      public void start(boolean flag) throws InterruptedException {
          Worker worker = new Worker();
          worker.start();
          if (flag){
              worker.join();
          }
      }
  
      /** cancel the connection to the client */
      public synchronized void cancel() {
          if (isRunning()) {
              TestRunEvent evt = new TestRunEvent(new Integer(-1), TestRunEvent.RUN_STOP);
              try {
                  messenger.writeEvent(evt);
              } catch (IOException e){
              }
          }
      }
  
      /** shutdown the server and any running client */
      public synchronized void shutdown() {
          try {
              if (messenger != null) {
                  messenger.close();
                  messenger = null;
              }
          } catch (IOException e){
          }
          try {
              if (client != null) {
                  client.shutdownInput();
                  client.shutdownOutput();
                  client.close();
                  client = null;
              }
          } catch (IOException e) {
          }
          try {
              if (server != null) {
                  server.close();
                  server = null;
              }
          } catch (IOException e) {
          }
      }
  
  //-----
  
      private class Worker extends Thread {
          public void run() {
              try {
                  server = new ServerSocket(port);
                  client = server.accept();
                  messenger = new Messenger(client.getInputStream(), client.getOutputStream());
                  TestRunEvent evt = null;
                  while ( (evt = messenger.read()) != null ) {
                      dispatcher.dispatchEvent(evt);
                  }
              } catch (Exception e) {
                  //@fixme this stacktrace might be normal when closing
                  // the socket. So decompose the above in distinct steps
              } finally {
                  cancel();
                  shutdown();
              }
          }
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/SocketUtil.java
  
  Index: SocketUtil.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
  
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  
  /**
   * A set of helper methods related to sockets.
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class SocketUtil {
  
  
      /**
       * Helper method to deserialize an object
       * @param bytes the binary data representing the serialized object.
       * @return the deserialized object.
       * @throws Exception a generic exception if an error occurs when
       * deserializing the object.
       */
      public static Object deserialize(byte[] bytes) throws Exception {
          ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
          return ois.readObject();
      }
  
      /**
       * Helper method to serialize an object
       * @param o the object to serialize.
       * @return the binary data representing the serialized object.
       * @throws Exception a generic exception if an error occurs when
       * serializing the object.
       */
      public static byte[] serialize(Object o) throws Exception {
          ByteArrayOutputStream out = new ByteArrayOutputStream();
          ObjectOutputStream oos = new ObjectOutputStream(out);
          oos.writeObject(o);
          oos.close();
          return out.toByteArray();
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunEvent.java
  
  Index: TestRunEvent.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
  
  import java.util.EventObject;
  import java.util.Properties;
  
  import org.apache.tools.ant.util.StringUtils;
  
  /**
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class TestRunEvent extends EventObject {
  
      // received from clients
      public final static int RUN_STARTED = 0;
      public final static int RUN_ENDED = 1;
      public final static int RUN_STOPPED = 2;
      public final static int TEST_STARTED = 3;
      public final static int TEST_FAILURE = 4;
      public final static int TEST_ERROR = 5;
      public final static int TEST_ENDED = 6;
      public final static int SUITE_STARTED = 7;
      public final static int SUITE_ENDED = 8;
  
      // received from server
      public final static int RUN_STOP = 9;
  
      /** the type of event */
      private int type = -1;
  
      /** timestamp for all tests */
      private long timestamp = System.currentTimeMillis();
  
      /** name of testcase(method name) or testsuite (classname) */
      private String name;
  
      /** stacktrace for error or failure */
      private String stacktrace;
  
      /** properties for end of testrun */
      private Properties props;
  
      public TestRunEvent(Integer id, int type){
          super(id);
          this.type = type;
      }
  
      public TestRunEvent(Integer id, int type, String name){
          this(id, type);
          this.name = name;
      }
  
      public TestRunEvent(Integer id, int type, Properties props){
          this(id, type);
          this.props = props;
      }
  
      public TestRunEvent(Integer id, int type, String name, Throwable t){
          this(id, type, name);
          this.stacktrace = StringUtils.getStackTrace(t);
      }
  
      public void setType(int type) {
          this.type = type;
      }
  
      public void setTimeStamp(long timestamp) {
          this.timestamp = timestamp;
      }
  
      public void setStackTrace(String stacktrace) {
          this.stacktrace = stacktrace;
      }
  
      public void setName(String name) {
          this.name = name;
      }
  
      public void setProperties(Properties props) {
          this.props = props;
      }
  
      public int getType(){
          return type;
      }
  
      public long getTimeStamp(){
          return timestamp;
      }
  
      public String getName(){
          return name;
      }
  
      public String getStackTrace(){
          return stacktrace;
      }
  
      public Properties getProperties(){
          return props;
      }
  
      public boolean equals(Object o){
          if (o instanceof TestRunEvent){
              TestRunEvent other = (TestRunEvent)o;
              return ( (type == other.type) &&
                      (timestamp == other.timestamp) &&
                      ( name == null ? other.name == null :  name.equals(other.name) ) &&
                      ( stacktrace == null ? other.stacktrace == null : stacktrace.equals(other.stacktrace) ) &&
                      ( props == null ? other.props == null : props.equals(other.props) ) ) ;
          }
          return false;
      }
  
      public String toString(){
          StringBuffer buf = new StringBuffer();
          buf.append("id: ").append(source);
          buf.append("type: ").append(type);
          return buf.toString();
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunListener.java
  
  Index: TestRunListener.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
  
  import java.util.EventListener;
  
  
  /**
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public interface TestRunListener extends EventListener {
  
      void onRunStarted(TestRunEvent evt);
      void onRunEnded(TestRunEvent evt);
      void onRunStopped(TestRunEvent evt);
  
      void onSuiteStarted(TestRunEvent evt);
      void onSuiteEnded(TestRunEvent evt);
  
      void onTestStarted(TestRunEvent evt);
      void onTestError(TestRunEvent evt);
      void onTestFailure(TestRunEvent evt);
      void onTestEnded(TestRunEvent evt);
  }
  
  
  
  1.1                  jakarta-ant/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunner.java
  
  Index: TestRunner.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
  
  import java.io.BufferedReader;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.Socket;
  import java.util.Properties;
  import java.util.StringTokenizer;
  import java.util.Vector;
  import java.util.Random;
  
  import junit.framework.AssertionFailedError;
  import junit.framework.Test;
  import junit.framework.TestCase;
  import junit.framework.TestListener;
  import junit.framework.TestResult;
  import junit.framework.TestSuite;
  
  import org.apache.tools.ant.taskdefs.optional.rjunit.JUnitHelper;
  import org.apache.tools.ant.util.StringUtils;
  
  /**
   * TestRunner for running tests and send results to a remote server.
   *
   * <i>
   * This code is based on the code from Erich Gamma made for the
   * JUnit plugin for <a href="http://www.eclipse.org">Eclipse</a> and is
   * merged with code originating from Ant 1.4.x.
   * </i>
   *
   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
   */
  public class TestRunner implements TestListener {
  
      /** unique identifier for the runner */
      private final Integer id = new Integer( (new Random()).nextInt() );
  
      /** host to connect to */
      private String host = "127.0.0.1";
  
      /** port to connect to */
      private int port = -1;
  
      private boolean debug = false;
  
      /** the list of test class names to run */
      private Vector testClassNames = new Vector();
  
      /** result of the current test */
      private TestResult testResult;
  
      /** client socket to communicate with the server */
      private Socket clientSocket;
  
      /** writer to send message to the server */
      private Messenger messenger;
  
      /** bean constructor */
      public TestRunner() {
      }
  
      /**
       * Set the debug mode.
       * @param debug true to set to debug mode otherwise false.
       */
      public void setDebug(boolean debug) {
          this.debug = debug;
      }
  
      /**
       * Set the port to connect to the server
       * @param port a valid port number.
       */
      public void setPort(int port) {
          this.port = port;
      }
  
      /**
       * Set the hostname of the server
       * @param host the hostname or ip of the server
       */
      public void setHost(String host) {
          this.host = host;
      }
  
      /**
       * Add a test class name to be executed by this runner.
       * @param classname the class name of the test to run.
       */
      public void addTestClassName(String classname) {
          testClassNames.addElement(classname);
      }
  
      /**
       * Thread listener for a shutdown from the server
       * Note that it will stop any running test.
       */
      private class StopThread extends Thread {
          public void run() {
              try {
                  TestRunEvent evt = null;
                  if ((evt = messenger.read()) != null) {
                      if (evt.getType() == TestRunEvent.RUN_STOP) {
                          TestRunner.this.stop();
                      }
                  }
              } catch (Exception e) {
                  TestRunner.this.stop();
              }
          }
      }
  
      /**
       * Entry point for command line.
       * Usage:
       * <pre>
       * TestRunner -classnames <classnames> -port <port> -host <host> -debug
       * -file
       * -classnames <list of whitespace separated classnames to run>
       * -port       <port to connect to>
       * -host       <host to connect to>
       * -debug      to run in debug mode
       * </pre>
       */
      public static void main(String[] args) throws Exception {
          TestRunner testRunServer = new TestRunner();
          testRunServer.init(args);
          testRunServer.run();
      }
  
      /**
       * Parses the arguments of command line.
       * testClassNames, host, port, listeners and debug mode are set
       * @see  #main(String[])
       */
      protected void init(String[] args) throws Exception {
          for (int i = 0; i < args.length; i++) {
              if ("-file".equalsIgnoreCase(args[i])) {
                  // @fixme if you mix file and other options it will be a mess,
                  // not important right now.
                  FileInputStream fis = new FileInputStream(args[++i]);
                  Properties props = new Properties();
                  props.load(fis);
                  fis.close();
                  init(props);
              }
              if ("-classnames".equalsIgnoreCase(args[i])) {
                  for (int j = ++i; j < args.length; j++) {
                      if (args[j].startsWith("-"))
                          break;
                      addTestClassName(args[j]);
                  }
              }
              if ("-port".equalsIgnoreCase(args[i])) {
                  setPort(Integer.parseInt(args[++i]));
              }
              if ("-host".equalsIgnoreCase(args[i])) {
                  setHost(args[++i]);
              }
              if ("-debug".equalsIgnoreCase(args[i])) {
                  setDebug(true);
              }
          }
      }
  
      /**
       * Initialize the TestRunner from properties.
       * @param the properties containing configuration data.
       * @see #init(String[])
       */
      protected void init(Properties props) {
          if (props.getProperty("debug") != null) {
              setDebug(true);
          }
          String port = props.getProperty("port");
          if (port != null) {
              setPort(Integer.parseInt(port));
          }
          String host = props.getProperty("host");
          if (host != null) {
              setHost(host);
          }
          String classnames = props.getProperty("classnames");
          if (classnames != null) {
              StringTokenizer st = new StringTokenizer(classnames);
              while (st.hasMoreTokens()) {
                  addTestClassName(st.nextToken());
              }
          }
      }
  
      public final void run() throws Exception {
          if (testClassNames.size() == 0) {
              throw new IllegalArgumentException("No TestCase specified");
          }
          connect();
  
          testResult = new TestResult();
          testResult.addListener(this);
          runTests();
  
          testResult.removeListener(this);
          if (testResult != null) {
              testResult.stop();
              testResult = null;
          }
      }
  
      /**
       * Transform all classnames into instantiated <tt>Test</tt>.
       * @throws Exception a generic exception that can be thrown while
       * instantiating a test case.
       */
      protected Test[] getSuites() throws Exception {
          final int count = testClassNames.size();
          log("Extracting testcases from " + count + " classnames...");
          final Vector suites = new Vector(count);
          for (int i = 0; i < count; i++) {
              String classname = (String) testClassNames.elementAt(i);
              try {
                  Test test = JUnitHelper.getTest(null, classname);
                  if (test != null) {
                      suites.addElement(test);
                  }
              } catch (Exception e) {
                  // notify log error instead ?
                  log("Could not get Test instance from " + classname);
                  log(e);
              }
          }
          log("Extracted " + suites.size() + " testcases.");
          Test[] array = new Test[suites.size()];
          suites.copyInto(array);
          return array;
      }
  
      /**
       * @param testClassNames String array of full qualified class names of test classes
       */
      private void runTests() throws Exception {
  
          Test[] suites = getSuites();
  
          // count all testMethods and inform TestRunListeners
          int count = countTests(suites);
          log("Total tests to run: " + count);
          fireEvent(new TestRunEvent(id, TestRunEvent.RUN_STARTED));
  
          long startTime = System.currentTimeMillis();
          for (int i = 0; i < suites.length; i++) {
              String name = suites[i].getClass().getName();
              if (suites[i] instanceof TestCase) {
                  suites[i] = new TestSuite(name);
              }
              log("running suite: " + suites[i]);
              fireEvent(new TestRunEvent(id, TestRunEvent.SUITE_STARTED, name));
              suites[i].run(testResult);
              fireEvent(new TestRunEvent(id, TestRunEvent.SUITE_ENDED, name));
          }
  
          // inform TestRunListeners of test end
          long elapsedTime = System.currentTimeMillis() - startTime;
          if (testResult == null || testResult.shouldStop()) {
              fireEvent(new TestRunEvent(id, TestRunEvent.RUN_STOPPED, System.getProperties()));
          } else {
              fireEvent(new TestRunEvent(id, TestRunEvent.RUN_ENDED, System.getProperties()));
          }
          log("Finished after " + elapsedTime + "ms");
          shutDown();
      }
  
      /** count the number of test methods in all tests */
      private final int countTests(Test[] tests) {
          int count = 0;
          for (int i = 0; i < tests.length; i++) {
              count = count + tests[i].countTestCases();
          }
          return count;
      }
  
      protected void stop() {
          if (testResult != null) {
              testResult.stop();
          }
      }
  
      /**
       * connect to the specified host and port.
       * @throws IOException if any error occurs during connection.
       */
      protected void connect() throws IOException {
          log("Connecting to " + host + " on port " + port + "...");
          clientSocket = new Socket(host, port);
          messenger = new Messenger(clientSocket.getInputStream(), clientSocket.getOutputStream());
          new StopThread().start();
      }
  
  
      protected void shutDown() {
          try {
              if (messenger != null) {
                  messenger.close();
                  messenger = null;
              }
          } catch (IOException e) {
              log(e);
          }
  
          try {
              if (clientSocket != null) {
                  clientSocket.close();
                  clientSocket = null;
              }
          } catch (IOException e) {
              log(e);
          }
      }
  
      protected void fireEvent(TestRunEvent evt){
          try {
              messenger.writeEvent(evt);
          } catch (IOException e){
              log(e);
          }
      }
  
  // -------- JUnit TestListener implementation
  
  
      public void startTest(Test test) {
          String testName = test.toString();
          log("starting test: " + test);
          fireEvent(new TestRunEvent(id, TestRunEvent.TEST_STARTED, testName));
      }
  
      public void addError(Test test, Throwable t) {
          log("Adding error for test: " + test);
          String testName = test.toString();
          fireEvent(new TestRunEvent(id, TestRunEvent.TEST_ERROR, testName, t));
      }
  
      /**
       * this implementation is for JUnit &lt; 3.4
       * @see addFailure(Test, Throwable)
       */
      public void addFailure(Test test, AssertionFailedError afe) {
          addFailure(test, (Throwable) afe);
      }
  
      /**
       * This implementation is for JUnit &lt;= 3.4
       * @see addFailure(Test, AssertionFailedError)
       */
      public void addFailure(Test test, Throwable t) {
          log("Adding failure for test: " + test);
          String testName = test.toString();
          fireEvent(new TestRunEvent(id, TestRunEvent.TEST_FAILURE, testName, t));
      }
  
      public void endTest(Test test) {
          log("Ending test: " + test);
          String testName = test.toString();
          fireEvent(new TestRunEvent(id, TestRunEvent.TEST_ENDED, testName));
      }
  
      public void log(String msg) {
          if (debug) {
              System.out.println(msg);
          }
      }
  
      public void log(Throwable t) {
          if (debug) {
              t.printStackTrace();
          }
      }
  }
  
  
  
  

--
To unsubscribe, e-mail:   <mailto:ant-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>


Mime
View raw message