diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/BuildEventSupport.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/BuildEventSupport.java index 462e25639..3433b2441 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/BuildEventSupport.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/BuildEventSupport.java @@ -54,12 +54,15 @@ package org.apache.ant.antcore.execution; import java.util.ArrayList; import java.util.Iterator; - +import java.util.Map; +import java.util.HashMap; import java.util.List; -import org.apache.ant.common.model.ModelElement; -import org.apache.ant.common.event.BuildListener; -import org.apache.ant.common.event.BuildEvent; import org.apache.ant.common.antlib.Task; +import org.apache.ant.common.event.BuildEvent; +import org.apache.ant.common.event.BuildListener; +import org.apache.ant.common.model.ModelElement; +import org.apache.ant.common.util.DemuxOutputReceiver; +import org.apache.ant.common.event.MessageLevel; /** * BuildEventSupport is used by classes which which to send build events to @@ -68,13 +71,16 @@ import org.apache.ant.common.antlib.Task; * @author Conor MacNeill * @created 15 January 2002 */ -public class BuildEventSupport { +public class BuildEventSupport implements DemuxOutputReceiver { /** * The listeners attached to the object which contains this support * object */ private List listeners = new ArrayList(); + /** Records the latest task to be executed on a thread (Thread to Task). */ + private Map threadTasks = new HashMap(); + /** * Gets the listeners of the BuildEventSupport * @@ -166,6 +172,9 @@ public class BuildEventSupport { * @param task the task with which the event is associated */ public void fireTaskStarted(Task task) { + synchronized (this) { + threadTasks.put(Thread.currentThread(), task); + } BuildEvent event = new BuildEvent(task, BuildEvent.TASK_STARTED); for (Iterator i = listeners.iterator(); i.hasNext(); ) { BuildListener listener = (BuildListener)i.next(); @@ -181,6 +190,11 @@ public class BuildEventSupport { */ public void fireTaskFinished(Task task, Throwable cause) { + System.out.flush(); + System.err.flush(); + synchronized (this) { + threadTasks.remove(Thread.currentThread()); + } BuildEvent event = new BuildEvent(task, BuildEvent.TASK_FINISHED, cause); for (Iterator i = listeners.iterator(); i.hasNext(); ) { @@ -204,5 +218,28 @@ public class BuildEventSupport { listener.messageLogged(event); } } + + /** + * Demultiplexes output so that each task receives the appropriate + * messages. If the current thread is not currently executing a task, + * the message is logged directly. + * + * @param line Message to handle. Should not be null. + * @param isError Whether the text represents an error (true + * ) or information (false). + */ + public void threadOutput(String line, boolean isError) { + Task task = (Task)threadTasks.get(Thread.currentThread()); + if (task == null) { + fireMessageLogged(this, line, + isError ? MessageLevel.MSG_ERR : MessageLevel.MSG_INFO); + } else { + if (isError) { + task.handleSystemErr(line); + } else { + task.handleSystemOut(line); + } + } + } } diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ComponentManager.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ComponentManager.java index d6612e27a..a14106e95 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ComponentManager.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ComponentManager.java @@ -422,7 +422,12 @@ public class ComponentManager implements ComponentService { throws ExecutionException { ImportInfo definition = getDefinition(componentName); + if (definition == null) { + throw new ExecutionException("There is no definition of the <" + + componentName + "> component"); + } String className = definition.getClassName(); + ComponentLibrary componentLibrary = definition.getComponentLibrary(); String localName = definition.getLocalName(); diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionManager.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionManager.java index 71f5c6a23..d7c63176e 100755 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionManager.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionManager.java @@ -64,6 +64,7 @@ import org.apache.ant.common.event.BuildListener; import org.apache.ant.common.model.Project; import org.apache.ant.common.util.AntException; import org.apache.ant.common.util.ExecutionException; +import org.apache.ant.common.util.DemuxOutputReceiver; import org.apache.ant.init.InitConfig; /** @@ -75,7 +76,7 @@ import org.apache.ant.init.InitConfig; * @author Conor MacNeill * @created 12 January 2002 */ -public class ExecutionManager { +public class ExecutionManager implements DemuxOutputReceiver { /** The AntLibraries built from Ant's Populated Task Libraries. */ private Map antLibraries = new HashMap(); @@ -212,5 +213,17 @@ public class ExecutionManager { } } + /** + * Handle the content from a single thread. This method will be called + * by the thread producing the content. The content is broken up into + * separate lines + * + * @param line the content produce by the current thread. + * @param isErr true if this content is from the thread's error stream. + */ + public void threadOutput(String line, boolean isErr) { + eventSupport.threadOutput(line, isErr); + } + } diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Frame.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Frame.java index dd0b7e683..6814f1441 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Frame.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Frame.java @@ -74,6 +74,7 @@ import org.apache.ant.common.service.FileService; import org.apache.ant.common.service.MagicProperties; import org.apache.ant.common.util.AntException; import org.apache.ant.common.util.ConfigException; +import org.apache.ant.common.util.DemuxOutputReceiver; import org.apache.ant.common.util.ExecutionException; import org.apache.ant.common.util.FileUtils; import org.apache.ant.init.InitConfig; @@ -86,7 +87,7 @@ import org.apache.ant.init.InitConfig; * @author Conor MacNeill * @created 14 January 2002 */ -public class Frame { +public class Frame implements DemuxOutputReceiver { /** the base dir of the project */ private File baseDir; @@ -143,11 +144,9 @@ public class Frame { */ private ComponentManager componentManager; - /** - * The core's execution Service - */ + /** The core's execution Service */ private CoreExecService execService; - + /** * Create an Execution Frame for the given project * @@ -165,6 +164,18 @@ public class Frame { this.initConfig = initConfig; } + /** + * Replace ${} style constructions in the given value with the string + * value of the corresponding data values in the frame + * + * @param value the string to be scanned for property references. + * @return the string with all property references replaced + * @exception ExecutionException if any of the properties do not exist + */ + public String replacePropertyRefs(String value) throws ExecutionException { + return dataService.replacePropertyRefs(value); + } + /** * Sets the Project of the Frame * @@ -189,18 +200,6 @@ public class Frame { setMagicProperties(); } - /** - * Replace ${} style constructions in the given value with the string - * value of the corresponding data values in the frame - * - * @param value the string to be scanned for property references. - * @return the string with all property references replaced - * @exception ExecutionException if any of the properties do not exist - */ - public String replacePropertyRefs(String value) throws ExecutionException { - return dataService.replacePropertyRefs(value); - } - /** * Set a value in this frame or any of its imported frames. * @@ -603,7 +602,6 @@ public class Frame { } catch (ConfigException e) { throw new ExecutionException(e); } - } /** @@ -623,8 +621,8 @@ public class Frame { if (component instanceof Task) { execService.executeTask((Task)component); } else { - String typeId - = model.getAspectValue(Constants.ANT_ASPECT, "id"); + String typeId + = model.getAspectValue(Constants.ANT_ASPECT, "id"); if (typeId != null) { setDataValue(typeId, component, true); } @@ -709,6 +707,18 @@ public class Frame { executeTasks(taskIterator); } + /** + * Handle the content from a single thread. This method will be called + * by the thread producing the content. The content is broken up into + * separate lines + * + * @param line the content produce by the current thread. + * @param isErr true if this content is from the thread's error stream. + */ + public void threadOutput(String line, boolean isErr) { + eventSupport.threadOutput(line, isErr); + } + /** * Determine the base directory for each frame in the frame hierarchy * @@ -755,7 +765,7 @@ public class Frame { dataService = new CoreDataService(this, config.isUnsetPropertiesAllowed()); execService = new CoreExecService(this); - + services.put(FileService.class, fileService); services.put(ComponentService.class, componentManager); services.put(DataService.class, dataService); diff --git a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/ProjectHandler.java b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/ProjectHandler.java index b0c76363d..36ea314f0 100644 --- a/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/ProjectHandler.java +++ b/proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/ProjectHandler.java @@ -76,6 +76,15 @@ public class ProjectHandler extends ElementHandler { /** The default attribute name */ public static final String DEFAULT_ATTR = "default"; + /** The name of the element used to define references */ + public static final String REF_ELEMENT = "ant:ref"; + + /** The name of the element used to define references */ + public static final String INCLUDE_ELEMENT = "ant:include"; + + /** The name of the element used to define references */ + public static final String TARGET_ELEMENT = "target"; + /** The project being parsed. */ private Project project; @@ -148,8 +157,8 @@ public class ProjectHandler extends ElementHandler { public void startElement(String uri, String localName, String qualifiedName, Attributes attributes) throws SAXParseException { - - if (qualifiedName.equals("ref")) { + + if (qualifiedName.equals(REF_ELEMENT)) { RefHandler refHandler = new RefHandler(); refHandler.start(getParseContext(), getXMLReader(), this, getLocator(), attributes, getElementSource(), @@ -160,12 +169,12 @@ public class ProjectHandler extends ElementHandler { } catch (ModelException e) { throw new SAXParseException(e.getMessage(), getLocator(), e); } - } else if (qualifiedName.equals("include")) { + } else if (qualifiedName.equals(INCLUDE_ELEMENT)) { IncludeHandler includeHandler = new IncludeHandler(project); includeHandler.start(getParseContext(), getXMLReader(), this, getLocator(), attributes, getElementSource(), qualifiedName); - } else if (qualifiedName.equals("target")) { + } else if (qualifiedName.equals(TARGET_ELEMENT)) { TargetHandler targetHandler = new TargetHandler(); targetHandler.start(getParseContext(), getXMLReader(), this, getLocator(), attributes, @@ -175,13 +184,17 @@ public class ProjectHandler extends ElementHandler { } catch (ModelException e) { throw new SAXParseException(e.getMessage(), getLocator(), e); } - } else { + } else if (localName != null) { // everything else is a task BuildElementHandler buildElementHandler = new BuildElementHandler(); buildElementHandler.start(getParseContext(), getXMLReader(), this, getLocator(), attributes, getElementSource(), qualifiedName); project.addTask(buildElementHandler.getBuildElement()); + } else { + // ignore namespaced elements + throw new SAXParseException("Only the \"ant\" namespace is " + + "currently recognized (" + qualifiedName + ")", getLocator()); } } diff --git a/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Task.java b/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Task.java index 1b036962e..ffba40a70 100644 --- a/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Task.java +++ b/proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Task.java @@ -164,6 +164,31 @@ public abstract class Task extends ProjectComponent } } + /** + * Handle Output produced by the task. When a task prints to System.out + * the container may catch this and redirect the content back to the + * task by invoking this method. This method must NOT call System.out, + * directly or indirectly. + * + * @param line The line of content produce by the task + */ + public void handleSystemOut(String line) { + handleOutput(line); + } + + /** + * Handle error information produced by the task. When a task prints to + * System.err the container may catch this and redirect the content back + * to the task by invoking this method. This method must NOT call + * System.err, directly or indirectly. + * + * @param line The line of error info produce by the task + */ + public void handleSystemErr(String line) { + // default behaviout is to log at WARN level + handleErrorOutput(line); + } + /** * Handle output captured for this task * diff --git a/proposal/mutant/src/java/cli/org/apache/ant/cli/Commandline.java b/proposal/mutant/src/java/cli/org/apache/ant/cli/Commandline.java index f6381e8af..60cba0cef 100755 --- a/proposal/mutant/src/java/cli/org/apache/ant/cli/Commandline.java +++ b/proposal/mutant/src/java/cli/org/apache/ant/cli/Commandline.java @@ -57,6 +57,7 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; @@ -75,6 +76,7 @@ import org.apache.ant.common.event.BuildListener; import org.apache.ant.common.event.MessageLevel; import org.apache.ant.common.model.Project; import org.apache.ant.common.util.ConfigException; +import org.apache.ant.common.util.DemuxOutputStream; import org.apache.ant.init.InitConfig; import org.apache.ant.init.InitUtils; @@ -298,6 +300,12 @@ public class Commandline { // create the execution manager to execute the build executionManager = new ExecutionManager(initConfig, config); + OutputStream demuxOut + = new DemuxOutputStream(executionManager, false); + OutputStream demuxErr + = new DemuxOutputStream(executionManager, true); + System.setOut(new PrintStream(demuxOut)); + System.setErr(new PrintStream(demuxErr)); addBuildListeners(executionManager); } catch (Throwable e) { if (logger != null) { diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractTask.java b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractTask.java index 6cccaa9ba..050861cef 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractTask.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractTask.java @@ -52,6 +52,7 @@ * . */ package org.apache.ant.common.antlib; +import org.apache.ant.common.event.MessageLevel; /** * Abstract implementation of the Task interface @@ -81,5 +82,30 @@ public abstract class AbstractTask extends AbstractComponent implements Task { return taskName; } + /** + * Handle Output produced by the task. When a task prints to System.out + * the container may catch this and redirect the content back to the + * task by invoking this method. This method must NOT call System.out, + * directly or indirectly. + * + * @param line The line of content produce by the task + */ + public void handleSystemOut(String line) { + // default behaviout is to log at INFO level + log(line, MessageLevel.MSG_INFO); + } + + /** + * Handle error information produced by the task. When a task prints to + * System.err the container may catch this and redirect the content back + * to the task by invoking this method. This method must NOT call + * System.err, directly or indirectly. + * + * @param line The line of error info produce by the task + */ + public void handleSystemErr(String line) { + // default behaviout is to log at WARN level + log(line, MessageLevel.MSG_WARN); + } } diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/Task.java b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/Task.java index da16f1dd5..667bbdec1 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/antlib/Task.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/antlib/Task.java @@ -81,5 +81,25 @@ public interface Task extends ExecutionComponent { * @return the taskName value */ String getTaskName(); + + /** + * Handle Output produced by the task. When a task prints to System.out + * the container may catch this and redirect the content back to the + * task by invoking this method. This method must NOT call System.out, + * directly or indirectly. + * + * @param line The line of content produce by the task + */ + void handleSystemOut(String line); + + /** + * Handle error information produced by the task. When a task prints to + * System.err the container may catch this and redirect the content back + * to the task by invoking this method. This method must NOT call + * System.err, directly or indirectly. + * + * @param line The line of error info produce by the task + */ + void handleSystemErr(String line); } diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/model/Project.java b/proposal/mutant/src/java/common/org/apache/ant/common/model/Project.java index b6065f7c2..bc39d5a11 100644 --- a/proposal/mutant/src/java/common/org/apache/ant/common/model/Project.java +++ b/proposal/mutant/src/java/common/org/apache/ant/common/model/Project.java @@ -253,9 +253,16 @@ public class Project extends ModelElement { * * @param fullTargetName The name of the target relative to this project * @return the Target object with the given name + * @exception ModelException if the given target does not exist in this + * project */ - public Target getRefTarget(String fullTargetName) { + public Target getRefTarget(String fullTargetName) throws ModelException { Project containingProject = getRefProject(fullTargetName); + if (containingProject == null) { + throw new ModelException("The target name \"" + fullTargetName + + "\" does not exist in this project"); + } + if (containingProject == this) { return getTarget(fullTargetName); } @@ -504,19 +511,23 @@ public class Project extends ModelElement { if (flattenedList.contains(fullTargetName)) { return; } - String fullProjectName = getFullProjectName(fullTargetName); - Target target = getRefTarget(fullTargetName); - if (target == null) { - throw new ConfigException("Target " + fullTargetName - + " does not exist"); - } - for (Iterator i = target.getDependencies(); i.hasNext(); ) { - String localDependencyName = (String)i.next(); - String fullDependencyName - = fullProjectName == null ? localDependencyName - : fullProjectName + REF_DELIMITER + localDependencyName; - flattenDependency(flattenedList, fullDependencyName); - flattenedList.add(fullDependencyName); + try { + String fullProjectName = getFullProjectName(fullTargetName); + Target target = getRefTarget(fullTargetName); + if (target == null) { + throw new ConfigException("Target " + fullTargetName + + " does not exist"); + } + for (Iterator i = target.getDependencies(); i.hasNext(); ) { + String localDependencyName = (String)i.next(); + String fullDependencyName + = fullProjectName == null ? localDependencyName + : fullProjectName + REF_DELIMITER + localDependencyName; + flattenDependency(flattenedList, fullDependencyName); + flattenedList.add(fullDependencyName); + } + } catch (ModelException e) { + throw new ConfigException(e); } } } diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/util/DemuxOutputReceiver.java b/proposal/mutant/src/java/common/org/apache/ant/common/util/DemuxOutputReceiver.java new file mode 100644 index 000000000..4057c4be6 --- /dev/null +++ b/proposal/mutant/src/java/common/org/apache/ant/common/util/DemuxOutputReceiver.java @@ -0,0 +1,74 @@ +/* + * 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 + * . + */ +package org.apache.ant.common.util; + +/** + * A Demux output receiver receives buffered content which has been + * demultiplexed from the output potentially generated by multiple threads + * + * @author Conor MacNeill + * @created 22 February 2002 + */ +public interface DemuxOutputReceiver { + /** + * Handle the content from a single thread. This method will be called + * by the thread producing the content. The content is broken up into + * separate lines + * + * @param line the content produce by the current thread. + * @param isErr true if this content is from the thread's error stream. + */ + void threadOutput(String line, boolean isErr); +} + diff --git a/proposal/mutant/src/java/common/org/apache/ant/common/util/DemuxOutputStream.java b/proposal/mutant/src/java/common/org/apache/ant/common/util/DemuxOutputStream.java new file mode 100644 index 000000000..d3c07e1a3 --- /dev/null +++ b/proposal/mutant/src/java/common/org/apache/ant/common/util/DemuxOutputStream.java @@ -0,0 +1,198 @@ +/* + * 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 + * . + */ +package org.apache.ant.common.util; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import java.io.OutputStream; +import java.util.Hashtable; + +/** + * Buffers content written per thread and forwards the buffers onto the + * given receiver + * + * @author Conor MacNeill + * @created 22 February 2002 + */ +public class DemuxOutputStream extends OutputStream { + + /** + * A data class to store information about a buffer. Such informatio is + * stored on a per-thread basis. + * + * @author Conor MacNeill + * @created 22 February 2002 + */ + private static class BufferInfo { + /** The per-thread output stream */ + private ByteArrayOutputStream buffer; + + /** + * Whether the next line-terminator should be skipped in terms of + * processing the buffer or not. Used to avoid \r\n invoking + * processBuffer twice. + */ + private boolean skip = false; + } + + /** Maximum buffer size */ + private static final int MAX_SIZE = 1024; + /** Mapping from thread to buffer (Thread to BufferInfo) */ + private Hashtable buffers = new Hashtable(); + + /** The object which receives the output */ + private DemuxOutputReceiver receiver; + + /** Whether or not this stream represents an error stream */ + private boolean isErrorStream; + + /** + * Creates a new instance of this class. + * + * @param isErrorStream true if this is the error string, otherwise a + * normal output stream. This is passed to the project so it knows + * which stream it is receiving. + * @param receiver The receiver to which demux'd content is sent. + */ + public DemuxOutputStream(DemuxOutputReceiver receiver, + boolean isErrorStream) { + this.receiver = receiver; + this.isErrorStream = isErrorStream; + } + + /** + * Writes the data to the buffer and flushes the buffer if a line + * separator is detected or if the buffer has reached its maximum size. + * + * @param cc data to log (byte). + * @exception IOException if the data cannot be written to the stream + */ + public void write(int cc) throws IOException { + final byte c = (byte)cc; + + BufferInfo bufferInfo = getBufferInfo(); + if ((c == '\n') || (c == '\r')) { + if (!bufferInfo.skip) { + processBuffer(bufferInfo.buffer); + } + } else { + bufferInfo.buffer.write(cc); + if (bufferInfo.buffer.size() > MAX_SIZE) { + processBuffer(bufferInfo.buffer); + } + } + bufferInfo.skip = (c == '\r'); + } + + /** + * Equivalent to calling {@link #flush flush} on the stream. + * + * @exception IOException if there is a problem closing the stream. + */ + public void close() throws IOException { + flush(); + } + + /** + * Writes all remaining data in the buffer associated with the current + * thread to the project. + * + * @exception IOException if there is a problem flushing the stream. + */ + public void flush() throws IOException { + BufferInfo bufferInfo = getBufferInfo(); + if (bufferInfo.buffer.size() > 0) { + processBuffer(bufferInfo.buffer); + } + } + + + /** + * Converts the buffer to a string and sends it to {@link + * Project#demuxOutput(String,boolean) Project.demuxOutput}. + * + * @param buffer the ByteArrayOutputStream used to collect the output + * until a line separator is seen. + */ + protected void processBuffer(ByteArrayOutputStream buffer) { + String output = buffer.toString(); + receiver.threadOutput(output, isErrorStream); + resetBufferInfo(); + } + + /** + * Returns the buffer associated with the current thread. + * + * @return a ByteArrayOutputStream for the current thread to write data + * to + */ + private BufferInfo getBufferInfo() { + Thread current = Thread.currentThread(); + BufferInfo bufferInfo = (BufferInfo)buffers.get(current); + if (bufferInfo == null) { + bufferInfo = new BufferInfo(); + bufferInfo.buffer = new ByteArrayOutputStream(); + bufferInfo.skip = false; + buffers.put(current, bufferInfo); + } + return bufferInfo; + } + + /** Resets the buffer for the current thread. */ + private void resetBufferInfo() { + Thread current = Thread.currentThread(); + buffers.remove(current); + } +} + diff --git a/proposal/mutant/src/java/start/org/apache/tools/ant/Main.java b/proposal/mutant/src/java/start/org/apache/tools/ant/Main.java new file mode 100755 index 000000000..5a67d5d7f --- /dev/null +++ b/proposal/mutant/src/java/start/org/apache/tools/ant/Main.java @@ -0,0 +1,71 @@ +/* + * 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 + * . + */ +package org.apache.tools.ant; + +/** + * Old Ant1 entry point + * + * @author Conor MacNeill + */ +public class Main { + /** + * Entry point for starting command line Ant + * + * @param args commandline arguments + */ + public static void main(String[] args) { + org.apache.ant.start.Main.main(args); + } +} +