Browse Source

IMplement DemuxOutputStreams to capture System.out and System.err usage

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271542 13f79535-47bb-0310-9956-ffa450edef68
master
Conor MacNeill 23 years ago
parent
commit
1dcdf4c05f
13 changed files with 557 additions and 46 deletions
  1. +42
    -5
      proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/BuildEventSupport.java
  2. +5
    -0
      proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ComponentManager.java
  3. +14
    -1
      proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionManager.java
  4. +31
    -21
      proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Frame.java
  5. +18
    -5
      proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/ProjectHandler.java
  6. +25
    -0
      proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Task.java
  7. +8
    -0
      proposal/mutant/src/java/cli/org/apache/ant/cli/Commandline.java
  8. +26
    -0
      proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractTask.java
  9. +20
    -0
      proposal/mutant/src/java/common/org/apache/ant/common/antlib/Task.java
  10. +25
    -14
      proposal/mutant/src/java/common/org/apache/ant/common/model/Project.java
  11. +74
    -0
      proposal/mutant/src/java/common/org/apache/ant/common/util/DemuxOutputReceiver.java
  12. +198
    -0
      proposal/mutant/src/java/common/org/apache/ant/common/util/DemuxOutputStream.java
  13. +71
    -0
      proposal/mutant/src/java/start/org/apache/tools/ant/Main.java

+ 42
- 5
proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/BuildEventSupport.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @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 <code>null</code>.
* @param isError Whether the text represents an error (<code>true</code>
* ) or information (<code>false</code>).
*/
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);
}
}
}
}


+ 5
- 0
proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ComponentManager.java View File

@@ -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();


+ 14
- 1
proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ExecutionManager.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @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);
}

}


+ 31
- 21
proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Frame.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @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);


+ 18
- 5
proposal/mutant/src/java/antcore/org/apache/ant/antcore/modelparser/ProjectHandler.java View File

@@ -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());
}
}



+ 25
- 0
proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Task.java View File

@@ -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
*


+ 8
- 0
proposal/mutant/src/java/cli/org/apache/ant/cli/Commandline.java View File

@@ -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) {


+ 26
- 0
proposal/mutant/src/java/common/org/apache/ant/common/antlib/AbstractTask.java View File

@@ -52,6 +52,7 @@
* <http://www.apache.org/>.
*/
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);
}
}


+ 20
- 0
proposal/mutant/src/java/common/org/apache/ant/common/antlib/Task.java View File

@@ -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);
}


+ 25
- 14
proposal/mutant/src/java/common/org/apache/ant/common/model/Project.java View File

@@ -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);
}
}
}


+ 74
- 0
proposal/mutant/src/java/common/org/apache/ant/common/util/DemuxOutputReceiver.java View File

@@ -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
* <http://www.apache.org/>.
*/
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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @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);
}


+ 198
- 0
proposal/mutant/src/java/common/org/apache/ant/common/util/DemuxOutputStream.java View File

@@ -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
* <http://www.apache.org/>.
*/
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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @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);
}
}


+ 71
- 0
proposal/mutant/src/java/start/org/apache/tools/ant/Main.java View File

@@ -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
* <http://www.apache.org/>.
*/
package org.apache.tools.ant;

/**
* Old Ant1 entry point
*
* @author <a href="mailto:conor@apache.org">Conor MacNeill</a>
*/
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);
}
}


Loading…
Cancel
Save