diff --git a/WHATSNEW b/WHATSNEW index 563f2536a..484c717a6 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -123,6 +123,10 @@ Fixed bugs: attribute has been specified. Bugzilla Report 49755. + * If forked, after finished was still reading the input stream + for a bunch of characters, then stealing them from a following . + Bugzilla Report 49119. + Other changes: -------------- diff --git a/src/main/org/apache/tools/ant/taskdefs/PumpStreamHandler.java b/src/main/org/apache/tools/ant/taskdefs/PumpStreamHandler.java index 573f40679..5071824ec 100644 --- a/src/main/org/apache/tools/ant/taskdefs/PumpStreamHandler.java +++ b/src/main/org/apache/tools/ant/taskdefs/PumpStreamHandler.java @@ -32,23 +32,38 @@ public class PumpStreamHandler implements ExecuteStreamHandler { private Thread outputThread; private Thread errorThread; - private StreamPumper inputPump; + private Thread inputThread; private OutputStream out; private OutputStream err; private InputStream input; + private final boolean nonBlockingRead; /** * Construct a new PumpStreamHandler. * @param out the output OutputStream. * @param err the error OutputStream. * @param input the input InputStream. + * @param nonBlockingRead set it to true if the input should be + * read with simulated non blocking IO. */ public PumpStreamHandler(OutputStream out, OutputStream err, - InputStream input) { + InputStream input, boolean nonBlockingRead) { this.out = out; this.err = err; this.input = input; + this.nonBlockingRead = nonBlockingRead; + } + + /** + * Construct a new PumpStreamHandler. + * @param out the output OutputStream. + * @param err the error OutputStream. + * @param input the input InputStream. + */ + public PumpStreamHandler(OutputStream out, OutputStream err, + InputStream input) { + this(out, err, input, false); } /** @@ -102,7 +117,7 @@ public class PumpStreamHandler implements ExecuteStreamHandler { */ public void setProcessInputStream(OutputStream os) { if (input != null) { - inputPump = createInputPump(input, os, true); + inputThread = createPump(input, os, true, nonBlockingRead); } else { try { os.close(); @@ -118,9 +133,7 @@ public class PumpStreamHandler implements ExecuteStreamHandler { public void start() { outputThread.start(); errorThread.start(); - if (inputPump != null) { - Thread inputThread = new Thread(inputPump); - inputThread.setDaemon(true); + if (inputThread != null) { inputThread.start(); } } @@ -129,10 +142,7 @@ public class PumpStreamHandler implements ExecuteStreamHandler { * Stop pumping the streams. */ public void stop() { - - if (inputPump != null) { - inputPump.stop(); - } + finish(inputThread); try { err.flush(); @@ -159,6 +169,10 @@ public class PumpStreamHandler implements ExecuteStreamHandler { * @since Ant 1.8.0 */ protected final void finish(Thread t) { + if (t == null) { + // nothing to terminate + return; + } try { StreamPumper s = null; if (t instanceof ThreadWithPumper) { @@ -241,25 +255,30 @@ public class PumpStreamHandler implements ExecuteStreamHandler { */ protected Thread createPump(InputStream is, OutputStream os, boolean closeWhenExhausted) { - final Thread result - = new ThreadWithPumper(new StreamPumper(is, os, - closeWhenExhausted, - true)); - result.setDaemon(true); - return result; + return createPump(is, os, closeWhenExhausted, true); } /** * Creates a stream pumper to copy the given input stream to the - * given output stream. Used for standard input. - * @since Ant 1.6.3 + * given output stream. + * @param is the input stream to copy from. + * @param os the output stream to copy to. + * @param closeWhenExhausted if true close the inputstream. + * @param useAvailable set it to true to use simulated non + * blocking IO. + * @return a thread object that does the pumping, subclasses + * should return an instance of {@link ThreadWithPumper + * ThreadWithPumper}. + * @since Ant 1.8.2 */ - /*protected*/ StreamPumper createInputPump(InputStream is, OutputStream os, - boolean closeWhenExhausted) { - StreamPumper pumper = new StreamPumper(is, os, closeWhenExhausted, - false); - pumper.setAutoflush(true); - return pumper; + protected Thread createPump(InputStream is, OutputStream os, + boolean closeWhenExhausted, boolean nonBlockingIO) { + final Thread result + = new ThreadWithPumper(new StreamPumper(is, os, + closeWhenExhausted, + nonBlockingIO)); + result.setDaemon(true); + return result; } /** diff --git a/src/main/org/apache/tools/ant/taskdefs/Redirector.java b/src/main/org/apache/tools/ant/taskdefs/Redirector.java index 7f39a5e17..6e3e28a99 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Redirector.java +++ b/src/main/org/apache/tools/ant/taskdefs/Redirector.java @@ -753,9 +753,9 @@ public class Redirector { */ public ExecuteStreamHandler createHandler() throws BuildException { createStreams(); + boolean nonBlockingRead = input == null && inputString == null; return new PumpStreamHandler(getOutputStream(), getErrorStream(), - getInputStream()); - + getInputStream(), nonBlockingRead); } /** diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java index 187285bcb..fd8226d2c 100644 --- a/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java +++ b/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java @@ -21,10 +21,14 @@ package org.apache.tools.ant.taskdefs; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; import org.apache.tools.ant.BuildFileTest; +import org.apache.tools.ant.input.DefaultInputHandler; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.TeeOutputStream; @@ -214,6 +218,49 @@ public class JavaTest extends BuildFileTest { executeTarget("redirector2"); } + public void testReleasedInput() throws Exception { + PipedOutputStream out = new PipedOutputStream(); + final PipedInputStream in = new PipedInputStream(out); + project.setInputHandler(new DefaultInputHandler() { + protected InputStream getInputStream() { + return in; + } + }); + project.setDefaultInputStream(in); + + Java java = new Java(); + java.setProject(project); + java.setClassname("org.apache.tools.ant.Main"); + java.setArgs("-version"); + java.setFork(true); + // note: due to the missing classpath it will fail, but the input stream + // reader will be read + java.execute(); + + Thread inputThread = new Thread(new Runnable() { + public void run() { + Input input = new Input(); + input.setProject(project); + input.setAddproperty("input.value"); + input.execute(); + } + }); + inputThread.start(); + + // wait a little bit for the task to wait for input + Thread.sleep(100); + + // write some stuff in the input stream to be catched by the input task + out.write("foo\n".getBytes()); + out.flush(); + out.write("bar\n".getBytes()); + out.flush(); + + inputThread.join(2000); + + assertEquals("foo", project.getProperty("input.value")); + } + /** * entry point class with no dependencies other * than normal JRE runtime