You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by jk...@apache.org on 2009/02/06 13:36:49 UTC
svn commit: r741554 - in /ant/core/trunk: WHATSNEW
src/main/org/apache/tools/ant/taskdefs/Redirector.java
Author: jkf
Date: Fri Feb 6 12:36:48 2009
New Revision: 741554
URL: http://svn.apache.org/viewvc?rev=741554&view=rev
Log:
Pr 44544: Deadlock between in, out and err in the redirector.
Modified:
ant/core/trunk/WHATSNEW
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Redirector.java
Modified: ant/core/trunk/WHATSNEW
URL: http://svn.apache.org/viewvc/ant/core/trunk/WHATSNEW?rev=741554&r1=741553&r2=741554&view=diff
==============================================================================
--- ant/core/trunk/WHATSNEW (original)
+++ ant/core/trunk/WHATSNEW Fri Feb 6 12:36:48 2009
@@ -137,6 +137,9 @@
Fixed bugs:
-----------
+ * Got rid of deadlock between in in, out and err in the Redirector.
+ Bugzilla Report 44544.
+
* Caused by AssertionError no longer filtered. Bugzilla report 45631.
* <zip> would sometimes recreate JARs unnecessarily. Bugzilla report 45902.
Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Redirector.java
URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Redirector.java?rev=741554&r1=741553&r2=741554&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Redirector.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Redirector.java Fri Feb 6 12:36:48 2009
@@ -47,19 +47,20 @@
import org.apache.tools.ant.util.KeepAliveOutputStream;
/**
- * The Redirector class manages the setup and connection of
- * input and output redirection for an Ant project component.
- *
+ * The Redirector class manages the setup and connection of input and output
+ * redirection for an Ant project component.
+ *
* @since Ant 1.6
*/
public class Redirector {
private static final int STREAMPUMPER_WAIT_INTERVAL = 1000;
- private static final String DEFAULT_ENCODING
- = System.getProperty("file.encoding");
+ private static final String DEFAULT_ENCODING = System
+ .getProperty("file.encoding");
private class PropertyOutputStream extends ByteArrayOutputStream {
private String property;
+
private boolean closed = false;
PropertyOutputStream(String property) {
@@ -68,16 +69,18 @@
}
public void close() throws IOException {
- if (!closed && !(append && appendProperties)) {
- setPropertyFromBAOS(this, property);
- closed = true;
+ synchronized (outMutex) {
+ if (!closed && !(appendOut && appendProperties)) {
+ setPropertyFromBAOS(this, property);
+ closed = true;
+ }
}
}
}
/**
- * The file(s) from which standard input is being taken.
- * If > 1, files' content will be concatenated in the order received.
+ * The file(s) from which standard input is being taken. If > 1, files'
+ * content will be concatenated in the order received.
*/
private File[] input;
@@ -93,10 +96,10 @@
private File[] error;
/**
- * Indicates if standard error should be logged to Ant's log system
- * rather than the output. This has no effect if standard error is
- * redirected to a file or property.
- */
+ * Indicates if standard error should be logged to Ant's log system rather
+ * than the output. This has no effect if standard error is redirected to a
+ * file or property.
+ */
private boolean logError = false;
/**
@@ -119,13 +122,19 @@
private String inputString;
/** Flag which indicates if error and output files are to be appended. */
- private boolean append = false;
+ private boolean appendOut = false;
+
+ private boolean appendErr = false;
/** Flag which indicates that output should be always sent to the log */
- private boolean alwaysLog = false;
+ private boolean alwaysLogOut = false;
+
+ private boolean alwaysLogErr = false;
/** Flag which indicates whether files should be created even when empty. */
- private boolean createEmptyFiles = true;
+ private boolean createEmptyFilesOut = true;
+
+ private boolean createEmptyFilesErr = true;
/** The task for which this redirector is working */
private ProjectComponent managingTask;
@@ -172,10 +181,20 @@
/** whether to log the inputstring */
private boolean logInputString = true;
+ /** Mutex for in */
+ private Object inMutex = new Object();
+
+ /** Mutex for out */
+ private Object outMutex = new Object();
+
+ /** Mutex for err */
+ private Object errMutex = new Object();
+
/**
* Create a redirector instance for the given task
- *
- * @param managingTask the task for which the redirector is to work
+ *
+ * @param managingTask
+ * the task for which the redirector is to work
*/
public Redirector(Task managingTask) {
this((ProjectComponent) managingTask);
@@ -183,9 +202,9 @@
/**
* Create a redirector instance for the given task
- *
- * @param managingTask the project component for which the
- * redirector is to work
+ *
+ * @param managingTask
+ * the project component for which the redirector is to work
* @since Ant 1.6.3
*/
public Redirector(ProjectComponent managingTask) {
@@ -194,35 +213,48 @@
/**
* Set the input to use for the task
- *
- * @param input the file from which input is read.
+ *
+ * @param input
+ * the file from which input is read.
*/
public void setInput(File input) {
- setInput((input == null) ? null : new File[] {input});
+ setInput((input == null) ? null : new File[] { input });
}
/**
* Set the input to use for the task
- *
- * @param input the files from which input is read.
- */
- public synchronized void setInput(File[] input) {
- this.input = input;
+ *
+ * @param input
+ * the files from which input is read.
+ */
+ public void setInput(File[] input) {
+ synchronized (inMutex) {
+ if (input == null) {
+ this.input = null;
+ } else {
+ this.input = input.clone();
+ }
+ }
}
/**
* Set the string to use as input
- *
- * @param inputString the string which is used as the input source
- */
- public synchronized void setInputString(String inputString) {
- this.inputString = inputString;
+ *
+ * @param inputString
+ * the string which is used as the input source
+ */
+ public void setInputString(String inputString) {
+ synchronized (inMutex) {
+ this.inputString = inputString;
+ }
}
/**
* Set whether to include the value of the input string in log messages.
* Defaults to true.
- * @param logInputString true or false.
+ *
+ * @param logInputString
+ * true or false.
* @since Ant 1.7
*/
public void setLogInputString(boolean logInputString) {
@@ -231,218 +263,280 @@
/**
* Set a stream to use as input.
- *
- * @param inputStream the stream from which input will be read
+ *
+ * @param inputStream
+ * the stream from which input will be read
* @since Ant 1.6.3
*/
- /*public*/ void setInputStream(InputStream inputStream) {
- this.inputStream = inputStream;
+ /* public */void setInputStream(InputStream inputStream) {
+ synchronized (inMutex) {
+ this.inputStream = inputStream;
+ }
}
/**
* File the output of the process is redirected to. If error is not
* redirected, it too will appear in the output
- *
- * @param out the file to which output stream is written
+ *
+ * @param out
+ * the file to which output stream is written
*/
public void setOutput(File out) {
- setOutput((out == null) ? null : new File[] {out});
+ setOutput((out == null) ? null : new File[] { out });
}
/**
* Files the output of the process is redirected to. If error is not
* redirected, it too will appear in the output
- *
- * @param out the files to which output stream is written
- */
- public synchronized void setOutput(File[] out) {
- this.out = out;
+ *
+ * @param out
+ * the files to which output stream is written
+ */
+ public void setOutput(File[] out) {
+ synchronized (outMutex) {
+ if (out == null) {
+ this.out = null;
+ } else {
+ this.out = out.clone();
+ }
+ }
}
/**
* Set the output encoding.
- *
- * @param outputEncoding <code>String</code>.
+ *
+ * @param outputEncoding
+ * <code>String</code>.
*/
- public synchronized void setOutputEncoding(String outputEncoding) {
+ public void setOutputEncoding(String outputEncoding) {
if (outputEncoding == null) {
throw new IllegalArgumentException(
- "outputEncoding must not be null");
- } else {
+ "outputEncoding must not be null");
+ }
+ synchronized (outMutex) {
this.outputEncoding = outputEncoding;
}
}
/**
* Set the error encoding.
- *
- * @param errorEncoding <code>String</code>.
+ *
+ * @param errorEncoding
+ * <code>String</code>.
*/
- public synchronized void setErrorEncoding(String errorEncoding) {
+ public void setErrorEncoding(String errorEncoding) {
if (errorEncoding == null) {
- throw new IllegalArgumentException(
- "errorEncoding must not be null");
- } else {
+ throw new IllegalArgumentException("errorEncoding must not be null");
+ }
+ synchronized (errMutex) {
this.errorEncoding = errorEncoding;
}
}
/**
* Set the input encoding.
- *
- * @param inputEncoding <code>String</code>.
+ *
+ * @param inputEncoding
+ * <code>String</code>.
*/
- public synchronized void setInputEncoding(String inputEncoding) {
+ public void setInputEncoding(String inputEncoding) {
if (inputEncoding == null) {
- throw new IllegalArgumentException(
- "inputEncoding must not be null");
- } else {
+ throw new IllegalArgumentException("inputEncoding must not be null");
+ }
+ synchronized (inMutex) {
this.inputEncoding = inputEncoding;
}
}
/**
- * Controls whether error output of exec is logged. This is only useful
- * when output is being redirected and error output is desired in the
- * Ant log
- *
- * @param logError if true the standard error is sent to the Ant log system
- * and not sent to output.
- */
- public synchronized void setLogError(boolean logError) {
- this.logError = logError;
+ * Controls whether error output of exec is logged. This is only useful when
+ * output is being redirected and error output is desired in the Ant log
+ *
+ * @param logError
+ * if true the standard error is sent to the Ant log system and
+ * not sent to output.
+ */
+ public void setLogError(boolean logError) {
+ synchronized (errMutex) {
+ this.logError = logError;
+ }
}
/**
* This <code>Redirector</code>'s subordinate
* <code>PropertyOutputStream</code>s will not set their respective
* properties <code>while (appendProperties && append)</code>.
- *
- * @param appendProperties whether to append properties.
- */
- public synchronized void setAppendProperties(boolean appendProperties) {
- this.appendProperties = appendProperties;
+ *
+ * @param appendProperties
+ * whether to append properties.
+ */
+ public void setAppendProperties(boolean appendProperties) {
+ synchronized (outMutex) {
+ this.appendProperties = appendProperties;
+ }
}
/**
* Set the file to which standard error is to be redirected.
- *
- * @param error the file to which error is to be written
+ *
+ * @param error
+ * the file to which error is to be written
*/
public void setError(File error) {
- setError((error == null) ? null : new File[] {error});
+ setError((error == null) ? null : new File[] { error });
}
/**
* Set the files to which standard error is to be redirected.
- *
- * @param error the file to which error is to be written
- */
- public synchronized void setError(File[] error) {
- this.error = error;
+ *
+ * @param error
+ * the file to which error is to be written
+ */
+ public void setError(File[] error) {
+ synchronized (errMutex) {
+ if (error == null) {
+ this.error = null;
+ } else {
+ this.error = error.clone();
+ }
+ }
}
/**
- * Property name whose value should be set to the output of
- * the process.
- *
- * @param outputProperty the name of the property to be set with the
- * task's output.
+ * Property name whose value should be set to the output of the process.
+ *
+ * @param outputProperty
+ * the name of the property to be set with the task's output.
*/
- public synchronized void setOutputProperty(String outputProperty) {
+ public void setOutputProperty(String outputProperty) {
if (outputProperty == null
- || !(outputProperty.equals(this.outputProperty))) {
- this.outputProperty = outputProperty;
- baos = null;
+ || !(outputProperty.equals(this.outputProperty))) {
+ synchronized (outMutex) {
+ this.outputProperty = outputProperty;
+ baos = null;
+ }
}
}
/**
* Whether output should be appended to or overwrite an existing file.
* Defaults to false.
- *
- * @param append if true output and error streams are appended to their
- * respective files, if specified.
+ *
+ * @param append
+ * if true output and error streams are appended to their
+ * respective files, if specified.
*/
- public synchronized void setAppend(boolean append) {
- this.append = append;
+ public void setAppend(boolean append) {
+ synchronized (outMutex) {
+ appendOut = append;
+ }
+ synchronized (errMutex) {
+ appendErr = append;
+ }
}
/**
- * If true, (error and non-error) output will be "teed", redirected
- * as specified while being sent to Ant's logging mechanism as if no
- * redirection had taken place. Defaults to false.
- * @param alwaysLog <code>boolean</code>
+ * If true, (error and non-error) output will be "teed", redirected as
+ * specified while being sent to Ant's logging mechanism as if no
+ * redirection had taken place. Defaults to false.
+ *
+ * @param alwaysLog
+ * <code>boolean</code>
* @since Ant 1.6.3
*/
- public synchronized void setAlwaysLog(boolean alwaysLog) {
- this.alwaysLog = alwaysLog;
+ public void setAlwaysLog(boolean alwaysLog) {
+ synchronized (outMutex) {
+ alwaysLogOut = alwaysLog;
+ }
+ synchronized (errMutex) {
+ alwaysLogErr = alwaysLog;
+ }
}
/**
* Whether output and error files should be created even when empty.
* Defaults to true.
- * @param createEmptyFiles <code>boolean</code>.
+ *
+ * @param createEmptyFiles
+ * <code>boolean</code>.
*/
- public synchronized void setCreateEmptyFiles(boolean createEmptyFiles) {
- this.createEmptyFiles = createEmptyFiles;
+ public void setCreateEmptyFiles(boolean createEmptyFiles) {
+ synchronized (outMutex) {
+ createEmptyFilesOut = createEmptyFiles;
+ }
+ synchronized (outMutex) {
+ createEmptyFilesErr = createEmptyFiles;
+ }
}
/**
- * Property name whose value should be set to the error of
- * the process.
- *
- * @param errorProperty the name of the property to be set
- * with the error output.
+ * Property name whose value should be set to the error of the process.
+ *
+ * @param errorProperty
+ * the name of the property to be set with the error output.
*/
- public synchronized void setErrorProperty(String errorProperty) {
- if (errorProperty == null
- || !(errorProperty.equals(this.errorProperty))) {
- this.errorProperty = errorProperty;
- errorBaos = null;
+ public void setErrorProperty(String errorProperty) {
+ synchronized (errMutex) {
+ if (errorProperty == null
+ || !(errorProperty.equals(this.errorProperty))) {
+ this.errorProperty = errorProperty;
+ errorBaos = null;
+ }
}
}
/**
* Set the input <code>FilterChain</code>s.
- *
- * @param inputFilterChains <code>Vector</code> containing <code>FilterChain</code>.
- */
- public synchronized void setInputFilterChains(Vector inputFilterChains) {
- this.inputFilterChains = inputFilterChains;
+ *
+ * @param inputFilterChains
+ * <code>Vector</code> containing <code>FilterChain</code>.
+ */
+ public void setInputFilterChains(Vector inputFilterChains) {
+ synchronized (inMutex) {
+ this.inputFilterChains = inputFilterChains;
+ }
}
/**
* Set the output <code>FilterChain</code>s.
- *
- * @param outputFilterChains <code>Vector</code> containing <code>FilterChain</code>.
- */
- public synchronized void setOutputFilterChains(Vector outputFilterChains) {
- this.outputFilterChains = outputFilterChains;
+ *
+ * @param outputFilterChains
+ * <code>Vector</code> containing <code>FilterChain</code>.
+ */
+ public void setOutputFilterChains(Vector outputFilterChains) {
+ synchronized (outMutex) {
+ this.outputFilterChains = outputFilterChains;
+ }
}
/**
* Set the error <code>FilterChain</code>s.
- *
- * @param errorFilterChains <code>Vector</code> containing <code>FilterChain</code>.
- */
- public synchronized void setErrorFilterChains(Vector errorFilterChains) {
- this.errorFilterChains = errorFilterChains;
+ *
+ * @param errorFilterChains
+ * <code>Vector</code> containing <code>FilterChain</code>.
+ */
+ public void setErrorFilterChains(Vector errorFilterChains) {
+ synchronized (errMutex) {
+ this.errorFilterChains = errorFilterChains;
+ }
}
/**
* Set a property from a ByteArrayOutputStream
- *
- * @param baos contains the property value.
- * @param propertyName the property name.
- *
- * @exception IOException if the value cannot be read form the stream.
+ *
+ * @param baos
+ * contains the property value.
+ * @param propertyName
+ * the property name.
+ *
+ * @exception IOException
+ * if the value cannot be read form the stream.
*/
private void setPropertyFromBAOS(ByteArrayOutputStream baos,
- String propertyName) throws IOException {
+ String propertyName) throws IOException {
- BufferedReader in
- = new BufferedReader(new StringReader(Execute.toString(baos)));
+ BufferedReader in = new BufferedReader(new StringReader(Execute
+ .toString(baos)));
String line = null;
StringBuffer val = new StringBuffer();
while ((line = in.readLine()) != null) {
@@ -455,121 +549,138 @@
}
/**
- * Create the input, error and output streams based on the
- * configuration options.
+ * Create the input, error and output streams based on the configuration
+ * options.
*/
- public synchronized void createStreams() {
- outStreams();
- errorStreams();
- if (alwaysLog || outputStream == null) {
- OutputStream outputLog
- = new LogOutputStream(managingTask, Project.MSG_INFO);
- outputStream = (outputStream == null)
- ? outputLog : new TeeOutputStream(outputLog, outputStream);
- }
- if (alwaysLog || errorStream == null) {
- OutputStream errorLog
- = new LogOutputStream(managingTask, Project.MSG_WARN);
- errorStream = (errorStream == null)
- ? errorLog : new TeeOutputStream(errorLog, errorStream);
- }
- if ((outputFilterChains != null && outputFilterChains.size() > 0)
- || !(outputEncoding.equalsIgnoreCase(inputEncoding))) {
- try {
- LeadPipeInputStream snk = new LeadPipeInputStream();
- snk.setManagingComponent(managingTask);
-
- InputStream outPumpIn = snk;
+ public void createStreams() {
- Reader reader = new InputStreamReader(outPumpIn, inputEncoding);
+ synchronized (outMutex) {
+ outStreams();
+ if (alwaysLogOut || outputStream == null) {
+ OutputStream outputLog = new LogOutputStream(managingTask,
+ Project.MSG_INFO);
+ outputStream = (outputStream == null) ? outputLog
+ : new TeeOutputStream(outputLog, outputStream);
+ }
+
+ if ((outputFilterChains != null && outputFilterChains.size() > 0)
+ || !(outputEncoding.equalsIgnoreCase(inputEncoding))) {
+ try {
+ LeadPipeInputStream snk = new LeadPipeInputStream();
+ snk.setManagingComponent(managingTask);
+
+ InputStream outPumpIn = snk;
+
+ Reader reader = new InputStreamReader(outPumpIn,
+ inputEncoding);
+
+ if (outputFilterChains != null
+ && outputFilterChains.size() > 0) {
+ ChainReaderHelper helper = new ChainReaderHelper();
+ helper.setProject(managingTask.getProject());
+ helper.setPrimaryReader(reader);
+ helper.setFilterChains(outputFilterChains);
+ reader = helper.getAssembledReader();
+ }
+ outPumpIn = new ReaderInputStream(reader, outputEncoding);
- if (outputFilterChains != null && outputFilterChains.size() > 0) {
- ChainReaderHelper helper = new ChainReaderHelper();
- helper.setProject(managingTask.getProject());
- helper.setPrimaryReader(reader);
- helper.setFilterChains(outputFilterChains);
- reader = helper.getAssembledReader();
+ Thread t = new Thread(threadGroup, new StreamPumper(
+ outPumpIn, outputStream, true), "output pumper");
+ t.setPriority(Thread.MAX_PRIORITY);
+ outputStream = new PipedOutputStream(snk);
+ t.start();
+ } catch (IOException eyeOhEx) {
+ throw new BuildException("error setting up output stream",
+ eyeOhEx);
}
- outPumpIn = new ReaderInputStream(reader, outputEncoding);
-
- Thread t = new Thread(threadGroup, new StreamPumper(
- outPumpIn, outputStream, true), "output pumper");
- t.setPriority(Thread.MAX_PRIORITY);
- outputStream = new PipedOutputStream(snk);
- t.start();
- } catch (IOException eyeOhEx) {
- throw new BuildException(
- "error setting up output stream", eyeOhEx);
}
}
- if ((errorFilterChains != null && errorFilterChains.size() > 0)
- || !(errorEncoding.equalsIgnoreCase(inputEncoding))) {
- try {
- LeadPipeInputStream snk = new LeadPipeInputStream();
- snk.setManagingComponent(managingTask);
-
- InputStream errPumpIn = snk;
-
- Reader reader = new InputStreamReader(errPumpIn, inputEncoding);
+ synchronized (errMutex) {
+ errorStreams();
+ if (alwaysLogErr || errorStream == null) {
+ OutputStream errorLog = new LogOutputStream(managingTask,
+ Project.MSG_WARN);
+ errorStream = (errorStream == null) ? errorLog
+ : new TeeOutputStream(errorLog, errorStream);
+ }
+
+ if ((errorFilterChains != null && errorFilterChains.size() > 0)
+ || !(errorEncoding.equalsIgnoreCase(inputEncoding))) {
+ try {
+ LeadPipeInputStream snk = new LeadPipeInputStream();
+ snk.setManagingComponent(managingTask);
+
+ InputStream errPumpIn = snk;
+
+ Reader reader = new InputStreamReader(errPumpIn,
+ inputEncoding);
+
+ if (errorFilterChains != null
+ && errorFilterChains.size() > 0) {
+ ChainReaderHelper helper = new ChainReaderHelper();
+ helper.setProject(managingTask.getProject());
+ helper.setPrimaryReader(reader);
+ helper.setFilterChains(errorFilterChains);
+ reader = helper.getAssembledReader();
+ }
+ errPumpIn = new ReaderInputStream(reader, errorEncoding);
- if (errorFilterChains != null && errorFilterChains.size() > 0) {
- ChainReaderHelper helper = new ChainReaderHelper();
- helper.setProject(managingTask.getProject());
- helper.setPrimaryReader(reader);
- helper.setFilterChains(errorFilterChains);
- reader = helper.getAssembledReader();
+ Thread t = new Thread(threadGroup, new StreamPumper(
+ errPumpIn, errorStream, true), "error pumper");
+ t.setPriority(Thread.MAX_PRIORITY);
+ errorStream = new PipedOutputStream(snk);
+ t.start();
+ } catch (IOException eyeOhEx) {
+ throw new BuildException("error setting up error stream",
+ eyeOhEx);
}
- errPumpIn = new ReaderInputStream(reader, errorEncoding);
-
- Thread t = new Thread(threadGroup, new StreamPumper(
- errPumpIn, errorStream, true), "error pumper");
- t.setPriority(Thread.MAX_PRIORITY);
- errorStream = new PipedOutputStream(snk);
- t.start();
- } catch (IOException eyeOhEx) {
- throw new BuildException(
- "error setting up error stream", eyeOhEx);
}
}
- // if input files are specified, inputString and inputStream are ignored;
- // classes that work with redirector attributes can enforce
- // whatever warnings are needed
- if (input != null && input.length > 0) {
- managingTask.log("Redirecting input from file"
- + ((input.length == 1) ? "" : "s"), Project.MSG_VERBOSE);
- try {
- inputStream = new ConcatFileInputStream(input);
- } catch (IOException eyeOhEx) {
- throw new BuildException(eyeOhEx);
- }
- ((ConcatFileInputStream) inputStream).setManagingComponent(managingTask);
- } else if (inputString != null) {
- StringBuffer buf = new StringBuffer("Using input ");
- if (logInputString) {
- buf.append('"').append(inputString).append('"');
- } else {
- buf.append("string");
+ synchronized (inMutex) {
+ // if input files are specified, inputString and inputStream are
+ // ignored;
+ // classes that work with redirector attributes can enforce
+ // whatever warnings are needed
+ if (input != null && input.length > 0) {
+ managingTask
+ .log("Redirecting input from file"
+ + ((input.length == 1) ? "" : "s"),
+ Project.MSG_VERBOSE);
+ try {
+ inputStream = new ConcatFileInputStream(input);
+ } catch (IOException eyeOhEx) {
+ throw new BuildException(eyeOhEx);
+ }
+ ((ConcatFileInputStream) inputStream)
+ .setManagingComponent(managingTask);
+ } else if (inputString != null) {
+ StringBuffer buf = new StringBuffer("Using input ");
+ if (logInputString) {
+ buf.append('"').append(inputString).append('"');
+ } else {
+ buf.append("string");
+ }
+ managingTask.log(buf.toString(), Project.MSG_VERBOSE);
+ inputStream = new ByteArrayInputStream(inputString.getBytes());
}
- managingTask.log(buf.toString(), Project.MSG_VERBOSE);
- inputStream = new ByteArrayInputStream(inputString.getBytes());
- }
- if (inputStream != null
- && inputFilterChains != null && inputFilterChains.size() > 0) {
- ChainReaderHelper helper = new ChainReaderHelper();
- helper.setProject(managingTask.getProject());
- try {
- helper.setPrimaryReader(
- new InputStreamReader(inputStream, inputEncoding));
- } catch (IOException eyeOhEx) {
- throw new BuildException(
- "error setting up input stream", eyeOhEx);
+ if (inputStream != null && inputFilterChains != null
+ && inputFilterChains.size() > 0) {
+ ChainReaderHelper helper = new ChainReaderHelper();
+ helper.setProject(managingTask.getProject());
+ try {
+ helper.setPrimaryReader(new InputStreamReader(inputStream,
+ inputEncoding));
+ } catch (IOException eyeOhEx) {
+ throw new BuildException("error setting up input stream",
+ eyeOhEx);
+ }
+ helper.setFilterChains(inputFilterChains);
+ inputStream = new ReaderInputStream(
+ helper.getAssembledReader(), inputEncoding);
}
- helper.setFilterChains(inputFilterChains);
- inputStream = new ReaderInputStream(
- helper.getAssembledReader(), inputEncoding);
}
}
@@ -577,20 +688,21 @@
private void outStreams() {
if (out != null && out.length > 0) {
String logHead = new StringBuffer("Output ").append(
- ((append) ? "appended" : "redirected")).append(
- " to ").toString();
- outputStream = foldFiles(out, logHead, Project.MSG_VERBOSE);
+ ((appendOut) ? "appended" : "redirected")).append(" to ")
+ .toString();
+ outputStream = foldFiles(out, logHead, Project.MSG_VERBOSE,
+ appendOut, createEmptyFilesOut);
}
if (outputProperty != null) {
if (baos == null) {
baos = new PropertyOutputStream(outputProperty);
managingTask.log("Output redirected to property: "
- + outputProperty, Project.MSG_VERBOSE);
+ + outputProperty, Project.MSG_VERBOSE);
}
- //shield it from being closed by a filtering StreamPumper
+ // shield it from being closed by a filtering StreamPumper
OutputStream keepAliveOutput = new KeepAliveOutputStream(baos);
outputStream = (outputStream == null) ? keepAliveOutput
- : new TeeOutputStream(outputStream, keepAliveOutput);
+ : new TeeOutputStream(outputStream, keepAliveOutput);
} else {
baos = null;
}
@@ -599,31 +711,32 @@
private void errorStreams() {
if (error != null && error.length > 0) {
String logHead = new StringBuffer("Error ").append(
- ((append) ? "appended" : "redirected")).append(
- " to ").toString();
- errorStream = foldFiles(error, logHead, Project.MSG_VERBOSE);
+ ((appendErr) ? "appended" : "redirected")).append(" to ")
+ .toString();
+ errorStream = foldFiles(error, logHead, Project.MSG_VERBOSE,
+ appendErr, createEmptyFilesErr);
} else if (!(logError || outputStream == null)) {
long funnelTimeout = 0L;
- OutputStreamFunneler funneler
- = new OutputStreamFunneler(outputStream, funnelTimeout);
+ OutputStreamFunneler funneler = new OutputStreamFunneler(
+ outputStream, funnelTimeout);
try {
outputStream = funneler.getFunnelInstance();
errorStream = funneler.getFunnelInstance();
} catch (IOException eyeOhEx) {
throw new BuildException(
- "error splitting output/error streams", eyeOhEx);
+ "error splitting output/error streams", eyeOhEx);
}
}
if (errorProperty != null) {
if (errorBaos == null) {
errorBaos = new PropertyOutputStream(errorProperty);
- managingTask.log("Error redirected to property: " + errorProperty,
- Project.MSG_VERBOSE);
+ managingTask.log("Error redirected to property: "
+ + errorProperty, Project.MSG_VERBOSE);
}
- //shield it from being closed by a filtering StreamPumper
+ // shield it from being closed by a filtering StreamPumper
OutputStream keepAliveError = new KeepAliveOutputStream(errorBaos);
errorStream = (error == null || error.length == 0) ? keepAliveError
- : new TeeOutputStream(errorStream, keepAliveError);
+ : new TeeOutputStream(errorStream, keepAliveError);
} else {
errorBaos = null;
}
@@ -631,198 +744,245 @@
/**
* Create the StreamHandler to use with our Execute instance.
- *
- * @return the execute stream handler to manage the input, output and
- * error streams.
- *
- * @throws BuildException if the execute stream handler cannot be created.
+ *
+ * @return the execute stream handler to manage the input, output and error
+ * streams.
+ *
+ * @throws BuildException
+ * if the execute stream handler cannot be created.
*/
- public synchronized ExecuteStreamHandler createHandler()
- throws BuildException {
+ public ExecuteStreamHandler createHandler() throws BuildException {
createStreams();
- return new PumpStreamHandler(outputStream, errorStream, inputStream);
+ return new PumpStreamHandler(getOutputStream(), getErrorStream(),
+ getInputStream());
+
}
/**
* Pass output sent to System.out to specified output.
- *
- * @param output the data to be output
- */
- protected synchronized void handleOutput(String output) {
- if (outPrintStream == null) {
- outPrintStream = new PrintStream(outputStream);
+ *
+ * @param output
+ * the data to be output
+ */
+ protected void handleOutput(String output) {
+ synchronized (outMutex) {
+ if (outPrintStream == null) {
+ outPrintStream = new PrintStream(outputStream);
+ }
+ outPrintStream.print(output);
}
- outPrintStream.print(output);
}
/**
* Handle an input request
- *
- * @param buffer the buffer into which data is to be read.
- * @param offset the offset into the buffer at which data is stored.
- * @param length the amount of data to read
- *
+ *
+ * @param buffer
+ * the buffer into which data is to be read.
+ * @param offset
+ * the offset into the buffer at which data is stored.
+ * @param length
+ * the amount of data to read
+ *
* @return the number of bytes read
- *
- * @exception IOException if the data cannot be read
- */
- protected synchronized int handleInput(byte[] buffer, int offset,
- int length) throws IOException {
- if (inputStream == null) {
- return managingTask.getProject().defaultInput(buffer, offset,
- length);
- } else {
+ *
+ * @exception IOException
+ * if the data cannot be read
+ */
+ protected int handleInput(byte[] buffer, int offset, int length)
+ throws IOException {
+ synchronized (inMutex) {
+ if (inputStream == null) {
+ return managingTask.getProject().defaultInput(buffer, offset,
+ length);
+ }
return inputStream.read(buffer, offset, length);
+
}
}
/**
* Process data due to a flush operation.
- *
- * @param output the data being flushed.
- */
- protected synchronized void handleFlush(String output) {
- if (outPrintStream == null) {
- outPrintStream = new PrintStream(outputStream);
+ *
+ * @param output
+ * the data being flushed.
+ */
+ protected void handleFlush(String output) {
+ synchronized (outMutex) {
+ if (outPrintStream == null) {
+ outPrintStream = new PrintStream(outputStream);
+ }
+ outPrintStream.print(output);
+ outPrintStream.flush();
}
- outPrintStream.print(output);
- outPrintStream.flush();
}
/**
* Process error output
- *
- * @param output the error output data.
- */
- protected synchronized void handleErrorOutput(String output) {
- if (errorPrintStream == null) {
- errorPrintStream = new PrintStream(errorStream);
+ *
+ * @param output
+ * the error output data.
+ */
+ protected void handleErrorOutput(String output) {
+ synchronized (errMutex) {
+ if (errorPrintStream == null) {
+ errorPrintStream = new PrintStream(errorStream);
+ }
+ errorPrintStream.print(output);
}
- errorPrintStream.print(output);
}
/**
* Handle a flush operation on the error stream
- *
- * @param output the error information being flushed.
- */
- protected synchronized void handleErrorFlush(String output) {
- if (errorPrintStream == null) {
- errorPrintStream = new PrintStream(errorStream);
+ *
+ * @param output
+ * the error information being flushed.
+ */
+ protected void handleErrorFlush(String output) {
+ synchronized (errMutex) {
+ if (errorPrintStream == null) {
+ errorPrintStream = new PrintStream(errorStream);
+ }
+ errorPrintStream.print(output);
}
- errorPrintStream.print(output);
}
/**
* Get the output stream for the redirector
- *
- * @return the redirector's output stream or null if no output
- * has been configured
- */
- public synchronized OutputStream getOutputStream() {
- return outputStream;
+ *
+ * @return the redirector's output stream or null if no output has been
+ * configured
+ */
+ public OutputStream getOutputStream() {
+ synchronized (outMutex) {
+ return outputStream;
+ }
}
/**
* Get the error stream for the redirector
- *
- * @return the redirector's error stream or null if no output
- * has been configured
- */
- public synchronized OutputStream getErrorStream() {
- return errorStream;
+ *
+ * @return the redirector's error stream or null if no output has been
+ * configured
+ */
+ public OutputStream getErrorStream() {
+ synchronized (errMutex) {
+ return errorStream;
+ }
}
/**
* Get the input stream for the redirector
- *
- * @return the redirector's input stream or null if no output
- * has been configured
- */
- public synchronized InputStream getInputStream() {
- return inputStream;
+ *
+ * @return the redirector's input stream or null if no output has been
+ * configured
+ */
+ public InputStream getInputStream() {
+ synchronized (inMutex) {
+ return inputStream;
+ }
}
/**
* Complete redirection.
- *
- * This operation will close any streams and create any specified
- * property values.
- *
- * @throws IOException if the output properties cannot be read from their
- * output streams.
+ *
+ * This operation will close any streams and create any specified property
+ * values.
+ *
+ * @throws IOException
+ * if the output properties cannot be read from their output
+ * streams.
*/
- public synchronized void complete() throws IOException {
+ public void complete() throws IOException {
System.out.flush();
System.err.flush();
- if (inputStream != null) {
- inputStream.close();
+ synchronized (inMutex) {
+ if (inputStream != null) {
+ inputStream.close();
+ }
}
- outputStream.flush();
- outputStream.close();
-
- errorStream.flush();
- errorStream.close();
-
- //wait for the StreamPumpers to finish
- while (threadGroup.activeCount() > 0) {
- try {
- managingTask.log("waiting for " + threadGroup.activeCount()
- + " Threads:", Project.MSG_DEBUG);
- Thread[] thread = new Thread[threadGroup.activeCount()];
- threadGroup.enumerate(thread);
- for (int i = 0; i < thread.length && thread[i] != null; i++) {
- try {
- managingTask.log(thread[i].toString(), Project.MSG_DEBUG);
- } catch (NullPointerException enPeaEx) {
- // Ignore exception
+ synchronized (outMutex) {
+ outputStream.flush();
+ outputStream.close();
+ }
+
+ synchronized (errMutex) {
+ errorStream.flush();
+ errorStream.close();
+ }
+
+ // wait for the StreamPumpers to finish
+ synchronized (this) {
+ while (threadGroup.activeCount() > 0) {
+ try {
+ managingTask.log("waiting for " + threadGroup.activeCount()
+ + " Threads:", Project.MSG_DEBUG);
+ Thread[] thread = new Thread[threadGroup.activeCount()];
+ threadGroup.enumerate(thread);
+ for (int i = 0; i < thread.length && thread[i] != null; i++) {
+ try {
+ managingTask.log(thread[i].toString(),
+ Project.MSG_DEBUG);
+ } catch (NullPointerException enPeaEx) {
+ // Ignore exception
+ }
+ }
+ wait(STREAMPUMPER_WAIT_INTERVAL);
+ } catch (InterruptedException eyeEx) {
+ Thread[] thread = new Thread[threadGroup.activeCount()];
+ threadGroup.enumerate(thread);
+ for (int i = 0; i < thread.length && thread[i] != null; i++) {
+ thread[i].interrupt();
}
- }
- wait(STREAMPUMPER_WAIT_INTERVAL);
- } catch (InterruptedException eyeEx) {
- Thread[] thread = new Thread[threadGroup.activeCount()];
- threadGroup.enumerate(thread);
- for (int i = 0; i < thread.length && thread[i] != null; i++) {
- thread[i].interrupt();
}
}
}
setProperties();
- inputStream = null;
- outputStream = null;
- errorStream = null;
- outPrintStream = null;
- errorPrintStream = null;
- }
+ synchronized (inMutex) {
+ inputStream = null;
+ }
+ synchronized (outMutex) {
+ outputStream = null;
+ outPrintStream = null;
+ }
+ synchronized (errMutex) {
+ errorStream = null;
+ errorPrintStream = null;
+ }
+ }
/**
- * Notify the <code>Redirector</code> that it is now okay
- * to set any output and/or error properties.
+ * Notify the <code>Redirector</code> that it is now okay to set any output
+ * and/or error properties.
*/
- public synchronized void setProperties() {
- if (baos != null) {
- try {
- baos.close();
- } catch (IOException eyeOhEx) {
- // Ignore exception
+ public void setProperties() {
+ synchronized (outMutex) {
+ if (baos != null) {
+ try {
+ baos.close();
+ } catch (IOException eyeOhEx) {
+ // Ignore exception
+ }
}
}
- if (errorBaos != null) {
- try {
- errorBaos.close();
- } catch (IOException eyeOhEx) {
- // Ignore exception
+ synchronized (errMutex) {
+ if (errorBaos != null) {
+ try {
+ errorBaos.close();
+ } catch (IOException eyeOhEx) {
+ // Ignore exception
+ }
}
}
}
- private OutputStream foldFiles(File[] file, String logHead, int loglevel) {
- OutputStream result
- = new LazyFileOutputStream(file[0], append, createEmptyFiles);
+ private OutputStream foldFiles(File[] file, String logHead, int loglevel,
+ boolean append, boolean createEmptyFiles) {
+ OutputStream result = new LazyFileOutputStream(file[0], append,
+ createEmptyFiles);
managingTask.log(logHead + file[0], loglevel);
char[] c = new char[logHead.length()];
@@ -831,7 +991,7 @@
for (int i = 1; i < file.length; i++) {
outputStream = new TeeOutputStream(outputStream,
- new LazyFileOutputStream(file[i], append, createEmptyFiles));
+ new LazyFileOutputStream(file[i], append, createEmptyFiles));
managingTask.log(indent + file[i], loglevel);
}
return result;