It introduces the concept of a TaskContainer to allow a task to contain other tasks. This allows Task composition It introduces a <parallel> task for multithreading support. There is also a <sequential> task. It reworks System.out management to handle all task generated output and route it through the Ant event system. This handles multithreaded output. This is a major rework to the patch originally submitted by Thomas. I have taken a different route for the output management, in particular. Based on patch by Thomas Christen <chr@active.ch> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@269371 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -0,0 +1,151 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 2000 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; | |||||
| import java.io.*; | |||||
| import java.util.*; | |||||
| /** | |||||
| * Logs content written by a thread and forwards the buffers onto the | |||||
| * project object which will forward the content to the appropriate | |||||
| * task | |||||
| * | |||||
| * @author Conor MacNeill | |||||
| */ | |||||
| public class DemuxOutputStream extends OutputStream { | |||||
| static private final int MAX_SIZE = 1024; | |||||
| private Hashtable buffers = new Hashtable(); | |||||
| // private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | |||||
| private boolean skip = false; | |||||
| private Project project; | |||||
| private boolean isErrorStream; | |||||
| /** | |||||
| * Creates a new instance of this class. | |||||
| * | |||||
| * @param task the task for whom to log | |||||
| * @param level loglevel used to log data written to this stream. | |||||
| */ | |||||
| public DemuxOutputStream(Project project, boolean isErrorStream) { | |||||
| this.project = project; | |||||
| this.isErrorStream = isErrorStream; | |||||
| } | |||||
| private ByteArrayOutputStream getBuffer() { | |||||
| Thread current = Thread.currentThread(); | |||||
| ByteArrayOutputStream buffer = (ByteArrayOutputStream)buffers.get(current); | |||||
| if (buffer == null) { | |||||
| buffer = new ByteArrayOutputStream(); | |||||
| buffers.put(current, buffer); | |||||
| } | |||||
| return buffer; | |||||
| } | |||||
| private void resetBuffer() { | |||||
| Thread current = Thread.currentThread(); | |||||
| buffers.remove(current); | |||||
| } | |||||
| /** | |||||
| * Write the data to the buffer and flush the buffer, if a line | |||||
| * separator is detected. | |||||
| * | |||||
| * @param cc data to log (byte). | |||||
| */ | |||||
| public void write(int cc) throws IOException { | |||||
| final byte c = (byte)cc; | |||||
| if ((c == '\n') || (c == '\r')) { | |||||
| if (!skip) { | |||||
| processBuffer(); | |||||
| } | |||||
| } else { | |||||
| ByteArrayOutputStream buffer = getBuffer(); | |||||
| buffer.write(cc); | |||||
| if (buffer.size() > MAX_SIZE) { | |||||
| processBuffer(); | |||||
| } | |||||
| } | |||||
| skip = (c == '\r'); | |||||
| } | |||||
| /** | |||||
| * Converts the buffer to a string and sends it to <code>processLine</code> | |||||
| */ | |||||
| protected void processBuffer() { | |||||
| String output = getBuffer().toString(); | |||||
| project.demuxOutput(output, isErrorStream); | |||||
| resetBuffer(); | |||||
| } | |||||
| /** | |||||
| * Writes all remaining | |||||
| */ | |||||
| public void close() throws IOException { | |||||
| flush(); | |||||
| } | |||||
| /** | |||||
| * Writes all remaining | |||||
| */ | |||||
| public void flush() throws IOException { | |||||
| if (getBuffer().size() > 0) { | |||||
| processBuffer(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -267,7 +267,14 @@ public class Main { | |||||
| System.out.println("Only one logger class may be specified."); | System.out.println("Only one logger class may be specified."); | ||||
| return; | return; | ||||
| } | } | ||||
| loggerClassname = args[++i]; | |||||
| try { | |||||
| loggerClassname = args[++i]; | |||||
| } | |||||
| catch (ArrayIndexOutOfBoundsException aioobe) { | |||||
| System.out.println("You must specify a classname when " + | |||||
| "using the -logger argument"); | |||||
| return; | |||||
| } | |||||
| } else if (arg.equals("-emacs")) { | } else if (arg.equals("-emacs")) { | ||||
| emacsMode = true; | emacsMode = true; | ||||
| } else if (arg.equals("-projecthelp")) { | } else if (arg.equals("-projecthelp")) { | ||||
| @@ -403,43 +410,54 @@ public class Main { | |||||
| try { | try { | ||||
| addBuildListeners(project); | addBuildListeners(project); | ||||
| project.fireBuildStarted(); | |||||
| project.init(); | |||||
| project.setUserProperty("ant.version", getAntVersion()); | |||||
| // set user-define properties | |||||
| Enumeration e = definedProps.keys(); | |||||
| while (e.hasMoreElements()) { | |||||
| String arg = (String)e.nextElement(); | |||||
| String value = (String)definedProps.get(arg); | |||||
| project.setUserProperty(arg, value); | |||||
| } | |||||
| project.setUserProperty("ant.file" , buildFile.getAbsolutePath() ); | |||||
| // first use the ProjectHelper to create the project object | |||||
| // from the given build file. | |||||
| PrintStream err = System.err; | |||||
| PrintStream out = System.out; | |||||
| try { | try { | ||||
| Class.forName("javax.xml.parsers.SAXParserFactory"); | |||||
| ProjectHelper.configureProject(project, buildFile); | |||||
| } catch (NoClassDefFoundError ncdfe) { | |||||
| throw new BuildException("No JAXP compliant XML parser found. See http://java.sun.com/xml for the\nreference implementation.", ncdfe); | |||||
| } catch (ClassNotFoundException cnfe) { | |||||
| throw new BuildException("No JAXP compliant XML parser found. See http://java.sun.com/xml for the\nreference implementation.", cnfe); | |||||
| } catch (NullPointerException npe) { | |||||
| throw new BuildException("No JAXP compliant XML parser found. See http://java.sun.com/xml for the\nreference implementation.", npe); | |||||
| System.setOut(new PrintStream(new DemuxOutputStream(project, false))); | |||||
| System.setErr(new PrintStream(new DemuxOutputStream(project, true))); | |||||
| project.fireBuildStarted(); | |||||
| project.init(); | |||||
| project.setUserProperty("ant.version", getAntVersion()); | |||||
| // set user-define properties | |||||
| Enumeration e = definedProps.keys(); | |||||
| while (e.hasMoreElements()) { | |||||
| String arg = (String)e.nextElement(); | |||||
| String value = (String)definedProps.get(arg); | |||||
| project.setUserProperty(arg, value); | |||||
| } | |||||
| project.setUserProperty("ant.file" , buildFile.getAbsolutePath() ); | |||||
| // first use the ProjectHelper to create the project object | |||||
| // from the given build file. | |||||
| try { | |||||
| Class.forName("javax.xml.parsers.SAXParserFactory"); | |||||
| ProjectHelper.configureProject(project, buildFile); | |||||
| } catch (NoClassDefFoundError ncdfe) { | |||||
| throw new BuildException("No JAXP compliant XML parser found. See http://java.sun.com/xml for the\nreference implementation.", ncdfe); | |||||
| } catch (ClassNotFoundException cnfe) { | |||||
| throw new BuildException("No JAXP compliant XML parser found. See http://java.sun.com/xml for the\nreference implementation.", cnfe); | |||||
| } catch (NullPointerException npe) { | |||||
| throw new BuildException("No JAXP compliant XML parser found. See http://java.sun.com/xml for the\nreference implementation.", npe); | |||||
| } | |||||
| // make sure that we have a target to execute | |||||
| if (targets.size() == 0) { | |||||
| targets.addElement(project.getDefaultTarget()); | |||||
| } | |||||
| if (!projectHelp) { | |||||
| project.executeTargets(targets); | |||||
| } | |||||
| } | } | ||||
| // make sure that we have a target to execute | |||||
| if (targets.size() == 0) { | |||||
| targets.addElement(project.getDefaultTarget()); | |||||
| finally { | |||||
| System.setOut(out); | |||||
| System.setErr(err); | |||||
| } | } | ||||
| if (projectHelp) { | if (projectHelp) { | ||||
| printTargets(project); | |||||
| } else { | |||||
| // actually do some work | |||||
| project.executeTargets(targets); | |||||
| printTargets(project); | |||||
| } | } | ||||
| } | } | ||||
| catch(RuntimeException exc) { | catch(RuntimeException exc) { | ||||
| @@ -113,6 +113,9 @@ public class Project { | |||||
| /** The system classloader - may be null */ | /** The system classloader - may be null */ | ||||
| private ClassLoader systemLoader = null; | private ClassLoader systemLoader = null; | ||||
| /** Records the latest task on a thread */ | |||||
| private Hashtable threadTasks = new Hashtable(); | |||||
| static { | static { | ||||
| @@ -525,6 +528,21 @@ public class Project { | |||||
| } | } | ||||
| } | } | ||||
| public void demuxOutput(String line, boolean isError) { | |||||
| Task task = (Task)threadTasks.get(Thread.currentThread()); | |||||
| if (task == null) { | |||||
| fireMessageLogged(this, line, isError ? MSG_ERR : MSG_INFO); | |||||
| } | |||||
| else { | |||||
| if (isError) { | |||||
| task.handleOutput(line); | |||||
| } | |||||
| else { | |||||
| task.handleErrorOutput(line); | |||||
| } | |||||
| } | |||||
| } | |||||
| public void executeTarget(String targetName) throws BuildException { | public void executeTarget(String targetName) throws BuildException { | ||||
| // sanity check ourselves, if we've been asked to build nothing | // sanity check ourselves, if we've been asked to build nothing | ||||
| @@ -547,7 +565,7 @@ public class Project { | |||||
| do { | do { | ||||
| curtarget = (Target) sortedTargets.elementAt(curidx++); | curtarget = (Target) sortedTargets.elementAt(curidx++); | ||||
| runTarget(curtarget); | |||||
| curtarget.performTasks(); | |||||
| } while (!curtarget.getName().equals(targetName)); | } while (!curtarget.getName().equals(targetName)); | ||||
| } | } | ||||
| @@ -903,23 +921,6 @@ public class Project { | |||||
| s.equalsIgnoreCase("yes")); | s.equalsIgnoreCase("yes")); | ||||
| } | } | ||||
| // Given a string defining a target name, and a Hashtable | |||||
| // containing the "name to Target" mapping, pick out the | |||||
| // Target and execute it. | |||||
| public void runTarget(Target target) | |||||
| throws BuildException { | |||||
| try { | |||||
| fireTargetStarted(target); | |||||
| target.execute(); | |||||
| fireTargetFinished(target, null); | |||||
| } | |||||
| catch(RuntimeException exc) { | |||||
| fireTargetFinished(target, exc); | |||||
| throw exc; | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Topologically sort a set of Targets. | * Topologically sort a set of Targets. | ||||
| * @param root is the (String) name of the root Target. The sort is | * @param root is the (String) name of the root Target. The sort is | ||||
| @@ -1084,6 +1085,8 @@ public class Project { | |||||
| } | } | ||||
| protected void fireTaskStarted(Task task) { | protected void fireTaskStarted(Task task) { | ||||
| // register this as the current task on the current thread. | |||||
| threadTasks.put(Thread.currentThread(), task); | |||||
| BuildEvent event = new BuildEvent(task); | BuildEvent event = new BuildEvent(task); | ||||
| for (int i = 0; i < listeners.size(); i++) { | for (int i = 0; i < listeners.size(); i++) { | ||||
| BuildListener listener = (BuildListener) listeners.elementAt(i); | BuildListener listener = (BuildListener) listeners.elementAt(i); | ||||
| @@ -1092,6 +1095,9 @@ public class Project { | |||||
| } | } | ||||
| protected void fireTaskFinished(Task task, Throwable exception) { | protected void fireTaskFinished(Task task, Throwable exception) { | ||||
| threadTasks.remove(Thread.currentThread()); | |||||
| System.out.flush(); | |||||
| System.err.flush(); | |||||
| BuildEvent event = new BuildEvent(task); | BuildEvent event = new BuildEvent(task); | ||||
| for (int i = 0; i < listeners.size(); i++) { | for (int i = 0; i < listeners.size(); i++) { | ||||
| BuildListener listener = (BuildListener) listeners.elementAt(i); | BuildListener listener = (BuildListener) listeners.elementAt(i); | ||||
| @@ -348,11 +348,11 @@ public class ProjectHelper { | |||||
| } | } | ||||
| private void handleTaskdef(String name, AttributeList attrs) throws SAXParseException { | private void handleTaskdef(String name, AttributeList attrs) throws SAXParseException { | ||||
| (new TaskHandler(this, null)).init(name, attrs); | |||||
| (new TaskHandler(this, null, null)).init(name, attrs); | |||||
| } | } | ||||
| private void handleProperty(String name, AttributeList attrs) throws SAXParseException { | private void handleProperty(String name, AttributeList attrs) throws SAXParseException { | ||||
| (new TaskHandler(this, null)).init(name, attrs); | |||||
| (new TaskHandler(this, null, null)).init(name, attrs); | |||||
| } | } | ||||
| private void handleTarget(String tag, AttributeList attrs) throws SAXParseException { | private void handleTarget(String tag, AttributeList attrs) throws SAXParseException { | ||||
| @@ -433,7 +433,7 @@ public class ProjectHelper { | |||||
| if (project.getDataTypeDefinitions().get(name) != null) { | if (project.getDataTypeDefinitions().get(name) != null) { | ||||
| new DataTypeHandler(this, target).init(name, attrs); | new DataTypeHandler(this, target).init(name, attrs); | ||||
| } else { | } else { | ||||
| new TaskHandler(this, target).init(name, attrs); | |||||
| new TaskHandler(this, target, target).init(name, attrs); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -443,12 +443,13 @@ public class ProjectHelper { | |||||
| */ | */ | ||||
| private class TaskHandler extends AbstractHandler { | private class TaskHandler extends AbstractHandler { | ||||
| private Target target; | private Target target; | ||||
| private TaskContainer container; | |||||
| private Task task; | private Task task; | ||||
| private RuntimeConfigurable wrapper = null; | private RuntimeConfigurable wrapper = null; | ||||
| public TaskHandler(DocumentHandler parentHandler, Target target) { | |||||
| public TaskHandler(DocumentHandler parentHandler, TaskContainer container, Target target) { | |||||
| super(parentHandler); | super(parentHandler); | ||||
| this.container = container; | |||||
| this.target = target; | this.target = target; | ||||
| } | } | ||||
| @@ -471,7 +472,7 @@ public class ProjectHelper { | |||||
| // Top level tasks don't have associated targets | // Top level tasks don't have associated targets | ||||
| if (target != null) { | if (target != null) { | ||||
| task.setOwningTarget(target); | task.setOwningTarget(target); | ||||
| target.addTask(task); | |||||
| container.addTask(task); | |||||
| task.init(); | task.init(); | ||||
| wrapper = task.getRuntimeConfigurableWrapper(); | wrapper = task.getRuntimeConfigurableWrapper(); | ||||
| wrapper.setAttributes(attrs); | wrapper.setAttributes(attrs); | ||||
| @@ -500,7 +501,13 @@ public class ProjectHelper { | |||||
| } | } | ||||
| public void startElement(String name, AttributeList attrs) throws SAXParseException { | public void startElement(String name, AttributeList attrs) throws SAXParseException { | ||||
| new NestedElementHandler(this, task, wrapper).init(name, attrs); | |||||
| if (task instanceof TaskContainer) { | |||||
| // task can contain other tasks - no other nested elements possible | |||||
| new TaskHandler(this, (TaskContainer)task, target).init(name, attrs); | |||||
| } | |||||
| else { | |||||
| new NestedElementHandler(this, task, wrapper, target).init(name, attrs); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -508,35 +515,38 @@ public class ProjectHelper { | |||||
| * Handler for all nested properties. | * Handler for all nested properties. | ||||
| */ | */ | ||||
| private class NestedElementHandler extends AbstractHandler { | private class NestedElementHandler extends AbstractHandler { | ||||
| private Object target; | |||||
| private Object parent; | |||||
| private Object child; | private Object child; | ||||
| private RuntimeConfigurable parentWrapper; | private RuntimeConfigurable parentWrapper; | ||||
| private RuntimeConfigurable childWrapper = null; | private RuntimeConfigurable childWrapper = null; | ||||
| private Target target; | |||||
| public NestedElementHandler(DocumentHandler parentHandler, | public NestedElementHandler(DocumentHandler parentHandler, | ||||
| Object target, | |||||
| RuntimeConfigurable parentWrapper) { | |||||
| Object parent, | |||||
| RuntimeConfigurable parentWrapper, | |||||
| Target target) { | |||||
| super(parentHandler); | super(parentHandler); | ||||
| if (target instanceof TaskAdapter) { | |||||
| this.target = ((TaskAdapter) target).getProxy(); | |||||
| if (parent instanceof TaskAdapter) { | |||||
| this.parent = ((TaskAdapter) parent).getProxy(); | |||||
| } else { | } else { | ||||
| this.target = target; | |||||
| this.parent = parent; | |||||
| } | } | ||||
| this.parentWrapper = parentWrapper; | this.parentWrapper = parentWrapper; | ||||
| this.target = target; | |||||
| } | } | ||||
| public void init(String propType, AttributeList attrs) throws SAXParseException { | public void init(String propType, AttributeList attrs) throws SAXParseException { | ||||
| Class targetClass = target.getClass(); | |||||
| Class parentClass = parent.getClass(); | |||||
| IntrospectionHelper ih = | IntrospectionHelper ih = | ||||
| IntrospectionHelper.getHelper(targetClass); | |||||
| IntrospectionHelper.getHelper(parentClass); | |||||
| try { | try { | ||||
| if (target instanceof UnknownElement) { | |||||
| if (parent instanceof UnknownElement) { | |||||
| child = new UnknownElement(propType.toLowerCase()); | child = new UnknownElement(propType.toLowerCase()); | ||||
| ((UnknownElement) target).addChild((UnknownElement) child); | |||||
| ((UnknownElement) parent).addChild((UnknownElement) child); | |||||
| } else { | } else { | ||||
| child = ih.createElement(project, target, propType.toLowerCase()); | |||||
| child = ih.createElement(project, parent, propType.toLowerCase()); | |||||
| } | } | ||||
| configureId(child, attrs); | configureId(child, attrs); | ||||
| @@ -566,7 +576,14 @@ public class ProjectHelper { | |||||
| } | } | ||||
| public void startElement(String name, AttributeList attrs) throws SAXParseException { | public void startElement(String name, AttributeList attrs) throws SAXParseException { | ||||
| new NestedElementHandler(this, child, childWrapper).init(name, attrs); | |||||
| if (child instanceof TaskContainer) { | |||||
| // taskcontainer nested element can contain other tasks - no other | |||||
| // nested elements possible | |||||
| new TaskHandler(this, (TaskContainer)child, target).init(name, attrs); | |||||
| } | |||||
| else { | |||||
| new NestedElementHandler(this, child, childWrapper, target).init(name, attrs); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -616,7 +633,7 @@ public class ProjectHelper { | |||||
| } | } | ||||
| public void startElement(String name, AttributeList attrs) throws SAXParseException { | public void startElement(String name, AttributeList attrs) throws SAXParseException { | ||||
| new NestedElementHandler(this, element, wrapper).init(name, attrs); | |||||
| new NestedElementHandler(this, element, wrapper, target).init(name, attrs); | |||||
| } | } | ||||
| } | } | ||||
| @@ -62,7 +62,7 @@ import java.util.*; | |||||
| * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a> | ||||
| */ | */ | ||||
| public class Target { | |||||
| public class Target implements TaskContainer { | |||||
| private String name; | private String name; | ||||
| private String ifCondition = ""; | private String ifCondition = ""; | ||||
| @@ -161,23 +161,7 @@ public class Target { | |||||
| Object o = enum.nextElement(); | Object o = enum.nextElement(); | ||||
| if (o instanceof Task) { | if (o instanceof Task) { | ||||
| Task task = (Task) o; | Task task = (Task) o; | ||||
| try { | |||||
| project.fireTaskStarted(task); | |||||
| task.maybeConfigure(); | |||||
| task.execute(); | |||||
| project.fireTaskFinished(task, null); | |||||
| } | |||||
| catch(RuntimeException exc) { | |||||
| if (exc instanceof BuildException) { | |||||
| BuildException be = (BuildException) exc; | |||||
| if (be.getLocation() == Location.UNKNOWN_LOCATION) { | |||||
| be.setLocation(task.getLocation()); | |||||
| } | |||||
| } | |||||
| project.fireTaskFinished(task, exc); | |||||
| throw exc; | |||||
| } | |||||
| task.perform(); | |||||
| } else { | } else { | ||||
| RuntimeConfigurable r = (RuntimeConfigurable) o; | RuntimeConfigurable r = (RuntimeConfigurable) o; | ||||
| r.maybeConfigure(project); | r.maybeConfigure(project); | ||||
| @@ -192,6 +176,18 @@ public class Target { | |||||
| } | } | ||||
| } | } | ||||
| public final void performTasks() { | |||||
| try { | |||||
| project.fireTargetStarted(this); | |||||
| execute(); | |||||
| project.fireTargetFinished(this, null); | |||||
| } | |||||
| catch(RuntimeException exc) { | |||||
| project.fireTargetFinished(this, exc); | |||||
| throw exc; | |||||
| } | |||||
| } | |||||
| void replaceTask(UnknownElement el, Task t) { | void replaceTask(UnknownElement el, Task t) { | ||||
| int index = -1; | int index = -1; | ||||
| while ((index = children.indexOf(el)) >= 0) { | while ((index = children.indexOf(el)) >= 0) { | ||||
| @@ -220,5 +220,36 @@ public abstract class Task { | |||||
| wrapper.maybeConfigure(project); | wrapper.maybeConfigure(project); | ||||
| } | } | ||||
| } | } | ||||
| protected void handleOutput(String line) { | |||||
| log(line, Project.MSG_INFO); | |||||
| } | |||||
| protected void handleErrorOutput(String line) { | |||||
| log(line, Project.MSG_ERR); | |||||
| } | |||||
| /** | |||||
| * Perform this task | |||||
| */ | |||||
| public final void perform() { | |||||
| try { | |||||
| project.fireTaskStarted(this); | |||||
| maybeConfigure(); | |||||
| execute(); | |||||
| project.fireTaskFinished(this, null); | |||||
| } | |||||
| catch(RuntimeException exc) { | |||||
| if (exc instanceof BuildException) { | |||||
| BuildException be = (BuildException) exc; | |||||
| if (be.getLocation() == Location.UNKNOWN_LOCATION) { | |||||
| be.setLocation(getLocation()); | |||||
| } | |||||
| } | |||||
| project.fireTaskFinished(this, exc); | |||||
| throw exc; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -0,0 +1,70 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 2001 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; | |||||
| /** | |||||
| * Interface for objects which can contain tasks | |||||
| * | |||||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
| */ | |||||
| public interface TaskContainer { | |||||
| /** | |||||
| * Add a task to this task container | |||||
| * | |||||
| * @param task the task to be added to this container | |||||
| */ | |||||
| void addTask(Task task); | |||||
| } | |||||
| @@ -76,7 +76,6 @@ public class ExecuteJava { | |||||
| private Commandline javaCommand = null; | private Commandline javaCommand = null; | ||||
| private Path classpath = null; | private Path classpath = null; | ||||
| private CommandlineJava.SysProperties sysProperties = null; | private CommandlineJava.SysProperties sysProperties = null; | ||||
| private PrintStream out; | |||||
| public void setJavaCommand(Commandline javaCommand) { | public void setJavaCommand(Commandline javaCommand) { | ||||
| this.javaCommand = javaCommand; | this.javaCommand = javaCommand; | ||||
| @@ -93,15 +92,13 @@ public class ExecuteJava { | |||||
| /** | /** | ||||
| * All output (System.out as well as System.err) will be written | * All output (System.out as well as System.err) will be written | ||||
| * to this Stream. | * to this Stream. | ||||
| * | |||||
| * @deprecated manage output at the task level | |||||
| */ | */ | ||||
| public void setOutput(PrintStream out) { | public void setOutput(PrintStream out) { | ||||
| this.out = out; | |||||
| } | } | ||||
| public void execute(Project project) throws BuildException{ | public void execute(Project project) throws BuildException{ | ||||
| PrintStream sOut = System.out; | |||||
| PrintStream sErr = System.err; | |||||
| final String classname = javaCommand.getExecutable(); | final String classname = javaCommand.getExecutable(); | ||||
| final Object[] argument = { javaCommand.getArguments() }; | final Object[] argument = { javaCommand.getArguments() }; | ||||
| @@ -111,11 +108,6 @@ public class ExecuteJava { | |||||
| sysProperties.setSystem(); | sysProperties.setSystem(); | ||||
| } | } | ||||
| if (out != null) { | |||||
| System.setErr(out); | |||||
| System.setOut(out); | |||||
| } | |||||
| final Class[] param = { Class.forName("[Ljava.lang.String;") }; | final Class[] param = { Class.forName("[Ljava.lang.String;") }; | ||||
| Class target = null; | Class target = null; | ||||
| if (classpath == null) { | if (classpath == null) { | ||||
| @@ -150,11 +142,6 @@ public class ExecuteJava { | |||||
| if (sysProperties != null) { | if (sysProperties != null) { | ||||
| sysProperties.restoreSystem(); | sysProperties.restoreSystem(); | ||||
| } | } | ||||
| if (out != null) { | |||||
| System.setOut(sOut); | |||||
| System.setErr(sErr); | |||||
| out.close(); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -76,6 +76,7 @@ public class Java extends Task { | |||||
| private boolean fork = false; | private boolean fork = false; | ||||
| private File dir = null; | private File dir = null; | ||||
| private File out; | private File out; | ||||
| private PrintStream outStream = null; | |||||
| private boolean failOnError = false; | private boolean failOnError = false; | ||||
| /** | /** | ||||
| @@ -239,6 +240,24 @@ public class Java extends Task { | |||||
| } | } | ||||
| } | } | ||||
| protected void handleOutput(String line) { | |||||
| if (outStream != null) { | |||||
| outStream.println(line); | |||||
| } | |||||
| else { | |||||
| super.handleOutput(line); | |||||
| } | |||||
| } | |||||
| protected void handleErrorOutput(String line) { | |||||
| if (outStream != null) { | |||||
| outStream.println(line); | |||||
| } | |||||
| else { | |||||
| super.handleErrorOutput(line); | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Executes the given classname with the given arguments as it | * Executes the given classname with the given arguments as it | ||||
| * was a command line application. | * was a command line application. | ||||
| @@ -250,13 +269,20 @@ public class Java extends Task { | |||||
| exe.setSystemProperties(command.getSystemProperties()); | exe.setSystemProperties(command.getSystemProperties()); | ||||
| if (out != null) { | if (out != null) { | ||||
| try { | try { | ||||
| exe.setOutput(new PrintStream(new FileOutputStream(out))); | |||||
| outStream = new PrintStream(new FileOutputStream(out)); | |||||
| exe.execute(project); | |||||
| } catch (IOException io) { | } catch (IOException io) { | ||||
| throw new BuildException(io, location); | throw new BuildException(io, location); | ||||
| } | } | ||||
| finally { | |||||
| if (outStream != null) { | |||||
| outStream.close(); | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| exe.execute(project); | |||||
| } | } | ||||
| exe.execute(project); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -0,0 +1,179 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 2001 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; | |||||
| import org.apache.tools.ant.*; | |||||
| import org.apache.tools.ant.types.*; | |||||
| import java.util.*; | |||||
| import java.text.*; | |||||
| import java.lang.RuntimeException; | |||||
| /** | |||||
| * Implements a multi threaded task execution. | |||||
| * <p> | |||||
| * @author Thomas Christen <a href="mailto:chr@active.ch">chr@active.ch</a> | |||||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill </a> | |||||
| */ | |||||
| public class Parallel extends Task | |||||
| implements TaskContainer { | |||||
| /** Collection holding the nested tasks */ | |||||
| private Vector nestedTasks = new Vector(); | |||||
| /** | |||||
| * Add a nested task to execute parallel (asynchron). | |||||
| * <p> | |||||
| * @param nestedTask Nested task to be executed in parallel | |||||
| */ | |||||
| public void addTask(Task nestedTask) throws BuildException { | |||||
| nestedTasks.addElement(nestedTask); | |||||
| } | |||||
| /** | |||||
| * Block execution until the specified time or for a | |||||
| * specified amount of milliseconds and if defined, | |||||
| * execute the wait status. | |||||
| */ | |||||
| public void execute() throws BuildException { | |||||
| TaskThread[] threads = new TaskThread[nestedTasks.size()]; | |||||
| int threadNumber = 0; | |||||
| for (Enumeration e = nestedTasks.elements(); e.hasMoreElements(); threadNumber++) { | |||||
| Task nestedTask = (Task)e.nextElement(); | |||||
| threads[threadNumber] = new TaskThread(threadNumber, nestedTask); | |||||
| } | |||||
| // now start all threads | |||||
| for (int i = 0; i < threads.length; ++i) { | |||||
| threads[i].start(); | |||||
| } | |||||
| // now join to all the threads | |||||
| for (int i = 0; i < threads.length; ++i) { | |||||
| try { | |||||
| threads[i].join(); | |||||
| } | |||||
| catch (InterruptedException ie) { | |||||
| // who would interrupt me at a time like this? | |||||
| } | |||||
| } | |||||
| // now did any of the threads throw an exception | |||||
| StringBuffer exceptionMessage = new StringBuffer(); | |||||
| String lSep = System.getProperty("line.separator"); | |||||
| int numExceptions = 0; | |||||
| Throwable firstException = null; | |||||
| Location firstLocation = Location.UNKNOWN_LOCATION;; | |||||
| for (int i = 0; i < threads.length; ++i) { | |||||
| Throwable t = threads[i].getException(); | |||||
| if (t != null) { | |||||
| numExceptions++; | |||||
| if (firstException == null) { | |||||
| firstException = t; | |||||
| } | |||||
| if (t instanceof BuildException && | |||||
| firstLocation == Location.UNKNOWN_LOCATION) { | |||||
| firstLocation = ((BuildException)t).getLocation(); | |||||
| } | |||||
| exceptionMessage.append(lSep); | |||||
| exceptionMessage.append(t.getMessage()); | |||||
| } | |||||
| } | |||||
| if (numExceptions == 1) { | |||||
| if (firstException instanceof BuildException) { | |||||
| throw (BuildException)firstException; | |||||
| } | |||||
| else { | |||||
| throw new BuildException(firstException); | |||||
| } | |||||
| } | |||||
| else if (numExceptions > 1) { | |||||
| throw new BuildException(exceptionMessage.toString(), firstLocation); | |||||
| } | |||||
| } | |||||
| class TaskThread extends Thread { | |||||
| private Throwable exception; | |||||
| private Task task; | |||||
| private int taskNumber; | |||||
| /** | |||||
| * Construct a new TaskThread<p> | |||||
| * | |||||
| * @param task the Task to be executed in a seperate thread | |||||
| */ | |||||
| TaskThread(int taskNumber, Task task) { | |||||
| this.task = task; | |||||
| this.taskNumber = taskNumber; | |||||
| } | |||||
| /** | |||||
| * Executes the task within a thread and takes care about | |||||
| * Exceptions raised within the task. | |||||
| */ | |||||
| public void run() { | |||||
| try { | |||||
| task.perform(); | |||||
| } | |||||
| catch (Throwable t) { | |||||
| exception = t; | |||||
| } | |||||
| } | |||||
| public Throwable getException() { | |||||
| return exception; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,92 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 2001 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; | |||||
| import org.apache.tools.ant.*; | |||||
| import org.apache.tools.ant.types.*; | |||||
| import java.util.*; | |||||
| import java.text.*; | |||||
| import java.lang.RuntimeException; | |||||
| /** | |||||
| * Implements a single threaded task execution. | |||||
| * <p> | |||||
| * @author Thomas Christen <a href="mailto:chr@active.ch">chr@active.ch</a> | |||||
| */ | |||||
| public class Sequential extends Task | |||||
| implements TaskContainer { | |||||
| /** Optional Vector holding the nested tasks */ | |||||
| private Vector nestedTasks = new Vector(); | |||||
| /** | |||||
| * Add a nested task to Sequential. | |||||
| * <p> | |||||
| * @param nestedTask Nested task to execute Sequential | |||||
| * <p> | |||||
| */ | |||||
| public void addTask(Task nestedTask) { | |||||
| nestedTasks.addElement(nestedTask); | |||||
| } | |||||
| /** | |||||
| * Execute all nestedTasks. | |||||
| */ | |||||
| public void execute() throws BuildException { | |||||
| for (Enumeration e = nestedTasks.elements(); e.hasMoreElements();) { | |||||
| Task nestedTask = (Task)e.nextElement(); | |||||
| nestedTask.perform(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -83,15 +83,8 @@ public class Javac13 extends DefaultCompilerAdapter { | |||||
| attributes.log("Using modern compiler", Project.MSG_VERBOSE); | attributes.log("Using modern compiler", Project.MSG_VERBOSE); | ||||
| Commandline cmd = setupJavacCommand(); | Commandline cmd = setupJavacCommand(); | ||||
| PrintStream err = System.err; | |||||
| PrintStream out = System.out; | |||||
| PrintStream logstr = | |||||
| new PrintStream(new LogOutputStream(attributes, Project.MSG_WARN)); | |||||
| // Use reflection to be able to build on all JDKs >= 1.1: | // Use reflection to be able to build on all JDKs >= 1.1: | ||||
| try { | try { | ||||
| System.setOut(logstr); | |||||
| System.setErr(logstr); | |||||
| Class c = Class.forName ("com.sun.tools.javac.Main"); | Class c = Class.forName ("com.sun.tools.javac.Main"); | ||||
| Object compiler = c.newInstance (); | Object compiler = c.newInstance (); | ||||
| Method compile = c.getMethod ("compile", | Method compile = c.getMethod ("compile", | ||||
| @@ -105,10 +98,6 @@ public class Javac13 extends DefaultCompilerAdapter { | |||||
| } else { | } else { | ||||
| throw new BuildException("Error starting modern compiler", ex, location); | throw new BuildException("Error starting modern compiler", ex, location); | ||||
| } | } | ||||
| } finally { | |||||
| System.setErr(err); | |||||
| System.setOut(out); | |||||
| logstr.close(); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -49,6 +49,8 @@ typedef=org.apache.tools.ant.taskdefs.Typedef | |||||
| sleep=org.apache.tools.ant.taskdefs.Sleep | sleep=org.apache.tools.ant.taskdefs.Sleep | ||||
| pathconvert=org.apache.tools.ant.taskdefs.PathConvert | pathconvert=org.apache.tools.ant.taskdefs.PathConvert | ||||
| ear=org.apache.tools.ant.taskdefs.Ear | ear=org.apache.tools.ant.taskdefs.Ear | ||||
| parallel=org.apache.tools.ant.taskdefs.Parallel | |||||
| sequential=org.apache.tools.ant.taskdefs.Sequential | |||||
| # optional tasks | # optional tasks | ||||
| script=org.apache.tools.ant.taskdefs.optional.Script | script=org.apache.tools.ant.taskdefs.optional.Script | ||||
| @@ -308,19 +308,12 @@ public class Javah extends Task { | |||||
| throw new BuildException("Compile failed"); | throw new BuildException("Compile failed"); | ||||
| } | } | ||||
| */ | */ | ||||
| PrintStream err = System.err; | |||||
| PrintStream out = System.out; | |||||
| PrintStream logstr = | |||||
| new PrintStream(new LogOutputStream(this, Project.MSG_WARN)); | |||||
| try { | try { | ||||
| // Javac uses logstr to change the output stream and calls | // Javac uses logstr to change the output stream and calls | ||||
| // the constructor's invoke method to create a compiler instance | // the constructor's invoke method to create a compiler instance | ||||
| // dynamically. However, javah has a different interface and this | // dynamically. However, javah has a different interface and this | ||||
| // makes it harder, so here's a simple alternative. | // makes it harder, so here's a simple alternative. | ||||
| //------------------------------------------------------------------ | //------------------------------------------------------------------ | ||||
| System.setOut(logstr); | |||||
| System.setErr(logstr); | |||||
| com.sun.tools.javah.Main main = new com.sun.tools.javah.Main( cmd.getArguments() ); | com.sun.tools.javah.Main main = new com.sun.tools.javah.Main( cmd.getArguments() ); | ||||
| main.run(); | main.run(); | ||||
| } | } | ||||
| @@ -335,10 +328,6 @@ public class Javah extends Task { | |||||
| } else { | } else { | ||||
| throw new BuildException("Error starting javah: ", ex, location); | throw new BuildException("Error starting javah: ", ex, location); | ||||
| } | } | ||||
| } finally { | |||||
| System.setErr(err); | |||||
| System.setOut(out); | |||||
| logstr.close(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -155,7 +155,8 @@ public class JUnitTask extends Task { | |||||
| private Integer timeout = null; | private Integer timeout = null; | ||||
| private boolean summary = false; | private boolean summary = false; | ||||
| private String summaryValue = ""; | private String summaryValue = ""; | ||||
| private JUnitTestRunner runner = null; | |||||
| /** | /** | ||||
| * Tells this task to halt when there is an error in a test. | * Tells this task to halt when there is an error in a test. | ||||
| * this property is applied on all BatchTest (batchtest) and JUnitTest (test) | * this property is applied on all BatchTest (batchtest) and JUnitTest (test) | ||||
| @@ -509,6 +510,25 @@ public class JUnitTask extends Task { | |||||
| // whole build. IMHO this method should be avoided and it would be best | // whole build. IMHO this method should be avoided and it would be best | ||||
| // to remove it in future versions. TBD. (SBa) | // to remove it in future versions. TBD. (SBa) | ||||
| protected void handleOutput(String line) { | |||||
| if (runner != null) { | |||||
| runner.handleOutput(line); | |||||
| } | |||||
| else { | |||||
| super.handleOutput(line); | |||||
| } | |||||
| } | |||||
| protected void handleErrorOutput(String line) { | |||||
| if (runner != null) { | |||||
| runner.handleErrorOutput(line); | |||||
| } | |||||
| else { | |||||
| super.handleErrorOutput(line); | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Execute inside VM. | * Execute inside VM. | ||||
| */ | */ | ||||
| @@ -535,7 +555,7 @@ public class JUnitTask extends Task { | |||||
| // will cause trouble in JDK 1.1 if omitted | // will cause trouble in JDK 1.1 if omitted | ||||
| cl.addSystemPackageRoot("org.apache.tools.ant"); | cl.addSystemPackageRoot("org.apache.tools.ant"); | ||||
| } | } | ||||
| JUnitTestRunner runner = new JUnitTestRunner(test, test.getHaltonerror(), test.getHaltonfailure(), cl); | |||||
| runner = new JUnitTestRunner(test, test.getHaltonerror(), test.getHaltonfailure(), cl); | |||||
| if (summary) { | if (summary) { | ||||
| log("Running " + test.getName(), Project.MSG_INFO); | log("Running " + test.getName(), Project.MSG_INFO); | ||||
| @@ -138,6 +138,12 @@ public class JUnitTestRunner implements TestListener { | |||||
| */ | */ | ||||
| private JUnitTest junitTest; | private JUnitTest junitTest; | ||||
| /** output written during the test */ | |||||
| private PrintStream systemError; | |||||
| /** Error output during the test */ | |||||
| private PrintStream systemOut; | |||||
| /** | /** | ||||
| * Constructor for fork=true or when the user hasn't specified a | * Constructor for fork=true or when the user hasn't specified a | ||||
| * classpath. | * classpath. | ||||
| @@ -212,22 +218,19 @@ public class JUnitTestRunner implements TestListener { | |||||
| } else { | } else { | ||||
| PrintStream oldErr = System.err; | |||||
| PrintStream oldOut = System.out; | |||||
| ByteArrayOutputStream errStrm = new ByteArrayOutputStream(); | ByteArrayOutputStream errStrm = new ByteArrayOutputStream(); | ||||
| System.setErr(new PrintStream(errStrm)); | |||||
| systemError = new PrintStream(errStrm); | |||||
| ByteArrayOutputStream outStrm = new ByteArrayOutputStream(); | ByteArrayOutputStream outStrm = new ByteArrayOutputStream(); | ||||
| System.setOut(new PrintStream(outStrm)); | |||||
| systemOut = new PrintStream(outStrm); | |||||
| try { | try { | ||||
| suite.run(res); | suite.run(res); | ||||
| } finally { | } finally { | ||||
| System.err.close(); | |||||
| System.out.close(); | |||||
| System.setErr(oldErr); | |||||
| System.setOut(oldOut); | |||||
| systemError.close(); | |||||
| systemError = null; | |||||
| systemOut.close(); | |||||
| systemOut = null; | |||||
| sendOutAndErr(new String(outStrm.toByteArray()), | sendOutAndErr(new String(outStrm.toByteArray()), | ||||
| new String(errStrm.toByteArray())); | new String(errStrm.toByteArray())); | ||||
| @@ -299,6 +302,18 @@ public class JUnitTestRunner implements TestListener { | |||||
| } | } | ||||
| } | } | ||||
| protected void handleOutput(String line) { | |||||
| if (systemOut != null) { | |||||
| systemOut.println(line); | |||||
| } | |||||
| } | |||||
| protected void handleErrorOutput(String line) { | |||||
| if (systemError != null) { | |||||
| systemError.println(line); | |||||
| } | |||||
| } | |||||
| private void sendOutAndErr(String out, String err) { | private void sendOutAndErr(String out, String err) { | ||||
| for (int i=0; i<formatters.size(); i++) { | for (int i=0; i<formatters.size(); i++) { | ||||
| JUnitResultFormatter formatter = | JUnitResultFormatter formatter = | ||||
| @@ -74,15 +74,7 @@ public class KaffeRmic extends DefaultRmicAdapter { | |||||
| getRmic().log("Using Kaffe rmic", Project.MSG_VERBOSE); | getRmic().log("Using Kaffe rmic", Project.MSG_VERBOSE); | ||||
| Commandline cmd = setupRmicCommand(); | Commandline cmd = setupRmicCommand(); | ||||
| PrintStream err = System.err; | |||||
| PrintStream out = System.out; | |||||
| // the project log | |||||
| PrintStream logstr = | |||||
| new PrintStream(new LogOutputStream(getRmic(), Project.MSG_WARN)); | |||||
| try { | try { | ||||
| System.setOut(logstr); | |||||
| System.setErr(logstr); | |||||
| Class c = Class.forName("kaffe.rmi.rmic.RMIC"); | Class c = Class.forName("kaffe.rmi.rmic.RMIC"); | ||||
| Constructor cons = c.getConstructor(new Class[] { String[].class }); | Constructor cons = c.getConstructor(new Class[] { String[].class }); | ||||
| @@ -103,10 +95,6 @@ public class KaffeRmic extends DefaultRmicAdapter { | |||||
| } else { | } else { | ||||
| throw new BuildException("Error starting Kaffe rmic: ", ex, getRmic().getLocation()); | throw new BuildException("Error starting Kaffe rmic: ", ex, getRmic().getLocation()); | ||||
| } | } | ||||
| } finally { | |||||
| System.setErr(err); | |||||
| System.setOut(out); | |||||
| logstr.close(); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -75,15 +75,7 @@ public class WLRmic extends DefaultRmicAdapter { | |||||
| getRmic().log("Using WebLogic rmic", Project.MSG_VERBOSE); | getRmic().log("Using WebLogic rmic", Project.MSG_VERBOSE); | ||||
| Commandline cmd = setupRmicCommand(new String[] {"-noexit"}); | Commandline cmd = setupRmicCommand(new String[] {"-noexit"}); | ||||
| PrintStream err = System.err; | |||||
| PrintStream out = System.out; | |||||
| PrintStream logstr = | |||||
| new PrintStream(new LogOutputStream(getRmic(), Project.MSG_WARN)); | |||||
| try { | try { | ||||
| System.setOut(logstr); | |||||
| System.setErr(logstr); | |||||
| // Create an instance of the rmic | // Create an instance of the rmic | ||||
| Class c = Class.forName("weblogic.rmic"); | Class c = Class.forName("weblogic.rmic"); | ||||
| Method doRmic = c.getMethod("main", | Method doRmic = c.getMethod("main", | ||||
| @@ -101,10 +93,6 @@ public class WLRmic extends DefaultRmicAdapter { | |||||
| } else { | } else { | ||||
| throw new BuildException("Error starting WebLogic rmic: ", ex, getRmic().getLocation()); | throw new BuildException("Error starting WebLogic rmic: ", ex, getRmic().getLocation()); | ||||
| } | } | ||||
| } finally { | |||||
| System.setErr(err); | |||||
| System.setOut(out); | |||||
| logstr.close(); | |||||
| } | } | ||||
| } | } | ||||