PR: 24918 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277513 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -24,6 +24,10 @@ Changes that could break older environments: | |||||
| Fixed bugs: | Fixed bugs: | ||||
| ----------- | ----------- | ||||
| * Programs run with <java fork="true"> can now accept standard input | |||||
| from the Ant console. (Programs run with <java fork="false"> could | |||||
| already do so.) Bugzilla Report 24918. | |||||
| * Translate task does not remove tokens when a key is not found. | * Translate task does not remove tokens when a key is not found. | ||||
| It logs a verbose message. Bugzilla Report 13936. | It logs a verbose message. Bugzilla Report 13936. | ||||
| @@ -15,10 +15,9 @@ specified.</p> | |||||
| If odd things go wrong when you run this task, set fork="true" to use a new | If odd things go wrong when you run this task, set fork="true" to use a new | ||||
| JVM. | JVM. | ||||
| <p>Note that you cannot interact with a forked VM, the only way to | |||||
| send input to it is via the input and inputstring attributes. Also note that | |||||
| in Ant 1.6, any attempt to read input in the forked VM will receive an | |||||
| EOF (-1). This is a change from Ant 1.5, where such an attempt would block.</p> | |||||
| <p>As of Ant 1.7, you can interact with a forked VM, as well as | |||||
| sending input to it via the <code>input</code> and <code>inputstring</code> | |||||
| attributes.</p> | |||||
| <h3>Parameters</h3> | <h3>Parameters</h3> | ||||
| <table border="1" cellpadding="2" cellspacing="0"> | <table border="1" cellpadding="2" cellspacing="0"> | ||||
| @@ -157,14 +156,16 @@ EOF (-1). This is a change from Ant 1.5, where such an attempt would block.</p> | |||||
| <td valign="top">A file from which the executed command's standard input | <td valign="top">A file from which the executed command's standard input | ||||
| is taken. This attribute is mutually exclusive with the | is taken. This attribute is mutually exclusive with the | ||||
| inputstring attribute</td> | inputstring attribute</td> | ||||
| <td align="center" valign="top">No</td> | |||||
| <td align="center" valign="top">No; default is to take standard input from console | |||||
| (unless <code>spawn="true"</code>)</td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td valign="top">inputstring</td> | <td valign="top">inputstring</td> | ||||
| <td valign="top">A string which serves as the input stream for the | <td valign="top">A string which serves as the input stream for the | ||||
| executed command. This attribute is mutually exclusive with the | executed command. This attribute is mutually exclusive with the | ||||
| input attribute.</td> | input attribute.</td> | ||||
| <td align="center" valign="top">No</td> | |||||
| <td align="center" valign="top">No; default is to take standard input from console | |||||
| (unless <code>spawn="true"</code>)</td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td valign="top">newenvironment</td> | <td valign="top">newenvironment</td> | ||||
| @@ -353,4 +354,3 @@ Reserved.</p> | |||||
| </body> | </body> | ||||
| </html> | </html> | ||||
| @@ -1,5 +1,5 @@ | |||||
| /* | /* | ||||
| * Copyright 2000-2004 The Apache Software Foundation | |||||
| * Copyright 2000-2005 The Apache Software Foundation | |||||
| * | * | ||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| * you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
| @@ -37,6 +37,7 @@ import org.apache.tools.ant.types.Permissions; | |||||
| import org.apache.tools.ant.types.RedirectorElement; | import org.apache.tools.ant.types.RedirectorElement; | ||||
| import org.apache.tools.ant.taskdefs.condition.Os; | import org.apache.tools.ant.taskdefs.condition.Os; | ||||
| import org.apache.tools.ant.util.JavaEnvUtils; | import org.apache.tools.ant.util.JavaEnvUtils; | ||||
| import org.apache.tools.ant.util.KeepAliveInputStream; | |||||
| /** | /** | ||||
| * Launcher for Java applications. Allows use of | * Launcher for Java applications. Allows use of | ||||
| @@ -639,11 +640,8 @@ public class Java extends Task { | |||||
| */ | */ | ||||
| public int handleInput(byte[] buffer, int offset, int length) | public int handleInput(byte[] buffer, int offset, int length) | ||||
| throws IOException { | throws IOException { | ||||
| if (redirector.getInputStream() != null) { | |||||
| return redirector.handleInput(buffer, offset, length); | |||||
| } else { | |||||
| return super.handleInput(buffer, offset, length); | |||||
| } | |||||
| // Should work whether or not redirector.inputStream == null: | |||||
| return redirector.handleInput(buffer, offset, length); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -702,6 +700,10 @@ public class Java extends Task { | |||||
| if (redirectorElement != null) { | if (redirectorElement != null) { | ||||
| redirectorElement.configure(redirector); | redirectorElement.configure(redirector); | ||||
| } | } | ||||
| if (!spawn && input == null && inputString == null) { | |||||
| // #24918: send standard input to the process by default. | |||||
| redirector.setInputStream(new KeepAliveInputStream(getProject().getDefaultInputStream())); | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -1,5 +1,5 @@ | |||||
| /* | /* | ||||
| * Copyright 2000-2004 The Apache Software Foundation | |||||
| * Copyright 2000-2005 The Apache Software Foundation | |||||
| * | * | ||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| * you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
| @@ -31,7 +31,7 @@ public class PumpStreamHandler implements ExecuteStreamHandler { | |||||
| private Thread outputThread; | private Thread outputThread; | ||||
| private Thread errorThread; | private Thread errorThread; | ||||
| private Thread inputThread; | |||||
| private StreamPumper inputPump; | |||||
| private OutputStream out; | private OutputStream out; | ||||
| private OutputStream err; | private OutputStream err; | ||||
| @@ -101,7 +101,7 @@ public class PumpStreamHandler implements ExecuteStreamHandler { | |||||
| */ | */ | ||||
| public void setProcessInputStream(OutputStream os) { | public void setProcessInputStream(OutputStream os) { | ||||
| if (input != null) { | if (input != null) { | ||||
| inputThread = createPump(input, os, true); | |||||
| inputPump = createInputPump(input, os, true); | |||||
| } else { | } else { | ||||
| try { | try { | ||||
| os.close(); | os.close(); | ||||
| @@ -117,7 +117,9 @@ public class PumpStreamHandler implements ExecuteStreamHandler { | |||||
| public void start() { | public void start() { | ||||
| outputThread.start(); | outputThread.start(); | ||||
| errorThread.start(); | errorThread.start(); | ||||
| if (inputThread != null) { | |||||
| if (inputPump != null) { | |||||
| Thread inputThread = new Thread(inputPump); | |||||
| inputThread.setDaemon(true); | |||||
| inputThread.start(); | inputThread.start(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -137,12 +139,8 @@ public class PumpStreamHandler implements ExecuteStreamHandler { | |||||
| // ignore | // ignore | ||||
| } | } | ||||
| if (inputThread != null) { | |||||
| try { | |||||
| inputThread.join(); | |||||
| } catch (InterruptedException e) { | |||||
| // ignore | |||||
| } | |||||
| if (inputPump != null) { | |||||
| inputPump.stop(); | |||||
| } | } | ||||
| try { | try { | ||||
| @@ -210,5 +208,17 @@ public class PumpStreamHandler implements ExecuteStreamHandler { | |||||
| result.setDaemon(true); | result.setDaemon(true); | ||||
| return result; | return result; | ||||
| } | } | ||||
| /** | |||||
| * Creates a stream pumper to copy the given input stream to the | |||||
| * given output stream. Used for standard input. | |||||
| * @since Ant 1.7 | |||||
| */ | |||||
| /*protected*/ StreamPumper createInputPump(InputStream is, OutputStream os, | |||||
| boolean closeWhenExhausted) { | |||||
| StreamPumper pumper = new StreamPumper(is, os, closeWhenExhausted); | |||||
| pumper.setAutoflush(true); | |||||
| return pumper; | |||||
| } | |||||
| } | } | ||||
| @@ -202,6 +202,15 @@ public class Redirector { | |||||
| this.inputString = inputString; | this.inputString = inputString; | ||||
| } | } | ||||
| /** | |||||
| * Set a stream to use as input. | |||||
| * | |||||
| * @param inputStream the stream from which input will be read | |||||
| * @since Ant 1.7 | |||||
| */ | |||||
| /*public*/ void setInputStream(InputStream inputStream) { | |||||
| this.inputStream = inputStream; | |||||
| } | |||||
| /** | /** | ||||
| * File the output of the process is redirected to. If error is not | * File the output of the process is redirected to. If error is not | ||||
| @@ -543,7 +552,7 @@ public class Redirector { | |||||
| } | } | ||||
| } | } | ||||
| // if input files are specified, inputString is ignored; | |||||
| // if input files are specified, inputString and inputStream are ignored; | |||||
| // classes that work with redirector attributes can enforce | // classes that work with redirector attributes can enforce | ||||
| // whatever warnings are needed | // whatever warnings are needed | ||||
| if (input != null && input.length > 0) { | if (input != null && input.length > 0) { | ||||
| @@ -1,5 +1,5 @@ | |||||
| /* | /* | ||||
| * Copyright 2000,2002-2004 The Apache Software Foundation | |||||
| * Copyright 2000,2002-2005 The Apache Software Foundation | |||||
| * | * | ||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| * you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
| @@ -36,6 +36,7 @@ public class StreamPumper implements Runnable { | |||||
| private OutputStream os; | private OutputStream os; | ||||
| private boolean finished; | private boolean finished; | ||||
| private boolean closeWhenExhausted; | private boolean closeWhenExhausted; | ||||
| private boolean autoflush = false; | |||||
| /** | /** | ||||
| * Create a new stream pumper. | * Create a new stream pumper. | ||||
| @@ -62,6 +63,14 @@ public class StreamPumper implements Runnable { | |||||
| this(is, os, false); | this(is, os, false); | ||||
| } | } | ||||
| /** | |||||
| * Set whether data should be flushed through to the output stream. | |||||
| * @param autoflush if true, push through data; if false, let it be buffered | |||||
| * @since Ant 1.7 | |||||
| */ | |||||
| /*public*/ void setAutoflush(boolean autoflush) { | |||||
| this.autoflush = autoflush; | |||||
| } | |||||
| /** | /** | ||||
| * Copies data from the input stream to the output stream. | * Copies data from the input stream to the output stream. | ||||
| @@ -78,8 +87,11 @@ public class StreamPumper implements Runnable { | |||||
| int length; | int length; | ||||
| try { | try { | ||||
| while ((length = is.read(buf)) > 0) { | |||||
| while ((length = is.read(buf)) > 0 && !finished) { | |||||
| os.write(buf, 0, length); | os.write(buf, 0, length); | ||||
| if (autoflush) { | |||||
| os.flush(); | |||||
| } | |||||
| } | } | ||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| // ignore errors | // ignore errors | ||||
| @@ -116,4 +128,17 @@ public class StreamPumper implements Runnable { | |||||
| wait(); | wait(); | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Stop the pumper as soon as possible. | |||||
| * Note that it may continue to block on the input stream | |||||
| * but it will really stop the thread as soon as it gets EOF | |||||
| * or any byte, and it will be marked as finished. | |||||
| * @since Ant 1.7 | |||||
| */ | |||||
| /*public*/ synchronized void stop() { | |||||
| finished = true; | |||||
| notifyAll(); | |||||
| } | |||||
| } | } | ||||