use this in Java task to get access to features such as separate error stream, redirected input, etc. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274020 13f79535-47bb-0310-9956-ffa450edef68master
@@ -54,24 +54,14 @@ | |||||
package org.apache.tools.ant.taskdefs; | package org.apache.tools.ant.taskdefs; | ||||
import java.io.BufferedReader; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.FileNotFoundException; | |||||
import java.io.FileOutputStream; | |||||
import java.io.FileInputStream; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.StringReader; | |||||
import java.io.OutputStream; | |||||
import java.io.InputStream; | |||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.Task; | import org.apache.tools.ant.Task; | ||||
import org.apache.tools.ant.types.Commandline; | import org.apache.tools.ant.types.Commandline; | ||||
import org.apache.tools.ant.types.Environment; | import org.apache.tools.ant.types.Environment; | ||||
import org.apache.tools.ant.util.StringUtils; | |||||
import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
import org.apache.tools.ant.util.TeeOutputStream; | |||||
/** | /** | ||||
* Executes a given command if the os platform is appropriate. | * Executes a given command if the os platform is appropriate. | ||||
@@ -89,11 +79,6 @@ import org.apache.tools.ant.util.TeeOutputStream; | |||||
public class ExecTask extends Task { | public class ExecTask extends Task { | ||||
private String os; | private String os; | ||||
private File out; | |||||
private File error; | |||||
private File input; | |||||
private boolean logError = false; | |||||
private File dir; | private File dir; | ||||
protected boolean failOnError = false; | protected boolean failOnError = false; | ||||
@@ -101,17 +86,13 @@ public class ExecTask extends Task { | |||||
private Long timeout = null; | private Long timeout = null; | ||||
private Environment env = new Environment(); | private Environment env = new Environment(); | ||||
protected Commandline cmdl = new Commandline(); | protected Commandline cmdl = new Commandline(); | ||||
private FileOutputStream fos = null; | |||||
private ByteArrayOutputStream baos = null; | |||||
private ByteArrayOutputStream errorBaos = null; | |||||
private String outputprop; | |||||
private String errorProperty; | |||||
private String resultProperty; | private String resultProperty; | ||||
private boolean failIfExecFails = true; | private boolean failIfExecFails = true; | ||||
private boolean append = false; | |||||
private String executable; | private String executable; | ||||
private boolean resolveExecutable = false; | private boolean resolveExecutable = false; | ||||
private Redirector redirector = new Redirector(this); | |||||
/** | /** | ||||
* Controls whether the VM (1.3 and above) is used to execute the | * Controls whether the VM (1.3 and above) is used to execute the | ||||
* command | * command | ||||
@@ -170,28 +151,32 @@ public class ExecTask extends Task { | |||||
this.cmdl = cmdl; | this.cmdl = cmdl; | ||||
} | } | ||||
/** | |||||
* Set the input to use for the task | |||||
*/ | |||||
public void setInput(File input) { | |||||
this.input = input; | |||||
} | |||||
/** | /** | ||||
* 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 | ||||
* redirected, it too will appear in the output | * redirected, it too will appear in the output | ||||
*/ | */ | ||||
public void setOutput(File out) { | public void setOutput(File out) { | ||||
this.out = out; | |||||
redirector.setOutput(out); | |||||
} | |||||
/** | |||||
* Set the input to use for the task | |||||
*/ | |||||
public void setInput(File input) { | |||||
redirector.setInput(input); | |||||
} | } | ||||
public void setInputString(String inputString) { | |||||
redirector.setInputString(inputString); | |||||
} | |||||
/** | /** | ||||
* Controls whether error output of exec is logged. This is only useful | * Controls whether error output of exec is logged. This is only useful | ||||
* when output is being redirected and error output is desired in the | * when output is being redirected and error output is desired in the | ||||
* Ant log | * Ant log | ||||
*/ | */ | ||||
public void setLogError(boolean logError) { | public void setLogError(boolean logError) { | ||||
this.logError = logError; | |||||
redirector.setLogError(logError); | |||||
} | } | ||||
/** | /** | ||||
@@ -200,15 +185,15 @@ public class ExecTask extends Task { | |||||
* @since ant 1.6 | * @since ant 1.6 | ||||
*/ | */ | ||||
public void setError(File error) { | public void setError(File error) { | ||||
this.error = error; | |||||
redirector.setError(error); | |||||
} | } | ||||
/** | /** | ||||
* Property name whose value should be set to the output of | * Property name whose value should be set to the output of | ||||
* the process. | * the process. | ||||
*/ | */ | ||||
public void setOutputproperty(String outputprop) { | |||||
this.outputprop = outputprop; | |||||
public void setOutputproperty(String outputProp) { | |||||
redirector.setOutputProperty(outputProp); | |||||
} | } | ||||
/** | /** | ||||
@@ -218,7 +203,7 @@ public class ExecTask extends Task { | |||||
* @since ant 1.6 | * @since ant 1.6 | ||||
*/ | */ | ||||
public void setErrorProperty(String errorProperty) { | public void setErrorProperty(String errorProperty) { | ||||
this.errorProperty = errorProperty; | |||||
redirector.setErrorProperty(errorProperty); | |||||
} | } | ||||
/** | /** | ||||
@@ -293,7 +278,7 @@ public class ExecTask extends Task { | |||||
* @since 1.30, Ant 1.5 | * @since 1.30, Ant 1.5 | ||||
*/ | */ | ||||
public void setAppend(boolean append) { | public void setAppend(boolean append) { | ||||
this.append = append; | |||||
redirector.setAppend(append); | |||||
} | } | ||||
@@ -382,7 +367,7 @@ public class ExecTask extends Task { | |||||
/** | /** | ||||
* If true, launch new process with VM, otherwise use the OS's shell. | * If true, launch new process with VM, otherwise use the OS's shell. | ||||
*/ | */ | ||||
public void setVMLauncher(boolean vmLauncher) { | |||||
public void setVMLauncher(boolean vmLauncher) { | |||||
this.vmLauncher = vmLauncher; | this.vmLauncher = vmLauncher; | ||||
} | } | ||||
@@ -410,22 +395,6 @@ public class ExecTask extends Task { | |||||
return exe; | return exe; | ||||
} | } | ||||
private void setPropertyFromBAOS(ByteArrayOutputStream baos, | |||||
String propertyName) throws IOException { | |||||
BufferedReader in = | |||||
new BufferedReader(new StringReader(Execute.toString(baos))); | |||||
String line = null; | |||||
StringBuffer val = new StringBuffer(); | |||||
while ((line = in.readLine()) != null) { | |||||
if (val.length() != 0) { | |||||
val.append(StringUtils.LINE_SEP); | |||||
} | |||||
val.append(line); | |||||
} | |||||
getProject().setNewProperty(propertyName, val.toString()); | |||||
} | |||||
/** | /** | ||||
* A Utility method for this classes and subclasses to run an | * A Utility method for this classes and subclasses to run an | ||||
* Execute instance (an external command). | * Execute instance (an external command). | ||||
@@ -447,12 +416,7 @@ public class ExecTask extends Task { | |||||
log("Result: " + returnCode, Project.MSG_ERR); | log("Result: " + returnCode, Project.MSG_ERR); | ||||
} | } | ||||
} | } | ||||
if (baos != null) { | |||||
setPropertyFromBAOS(baos, outputprop); | |||||
} | |||||
if (errorBaos != null) { | |||||
setPropertyFromBAOS(errorBaos, errorProperty); | |||||
} | |||||
redirector.complete(); | |||||
} | } | ||||
/** | /** | ||||
@@ -483,86 +447,7 @@ public class ExecTask extends Task { | |||||
* Create the StreamHandler to use with our Execute instance. | * Create the StreamHandler to use with our Execute instance. | ||||
*/ | */ | ||||
protected ExecuteStreamHandler createHandler() throws BuildException { | protected ExecuteStreamHandler createHandler() throws BuildException { | ||||
OutputStream outputStream = null; | |||||
OutputStream errorStream = null; | |||||
InputStream inputStream = null; | |||||
if (out == null && outputprop == null) { | |||||
outputStream = new LogOutputStream(this, Project.MSG_INFO); | |||||
errorStream = new LogOutputStream(this, Project.MSG_WARN); | |||||
} else { | |||||
if (out != null) { | |||||
try { | |||||
outputStream | |||||
= new FileOutputStream(out.getAbsolutePath(), append); | |||||
log("Output redirected to " + out, Project.MSG_VERBOSE); | |||||
} catch (FileNotFoundException fne) { | |||||
throw new BuildException("Cannot write to " + out, fne, | |||||
getLocation()); | |||||
} catch (IOException ioe) { | |||||
throw new BuildException("Cannot write to " + out, ioe, | |||||
getLocation()); | |||||
} | |||||
} | |||||
if (outputprop != null) { | |||||
baos = new ByteArrayOutputStream(); | |||||
log("Output redirected to property: " + outputprop, | |||||
Project.MSG_VERBOSE); | |||||
if (out == null) { | |||||
outputStream = baos; | |||||
} else { | |||||
outputStream = new TeeOutputStream(outputStream, baos); | |||||
} | |||||
} else { | |||||
baos = null; | |||||
} | |||||
errorStream = outputStream; | |||||
} | |||||
if (logError) { | |||||
errorStream = new LogOutputStream(this, Project.MSG_WARN); | |||||
} | |||||
if (error != null) { | |||||
try { | |||||
errorStream | |||||
= new FileOutputStream(error.getAbsolutePath(), append); | |||||
log("Error redirected to " + error, Project.MSG_VERBOSE); | |||||
} catch (FileNotFoundException fne) { | |||||
throw new BuildException("Cannot write to " + error, fne, | |||||
getLocation()); | |||||
} catch (IOException ioe) { | |||||
throw new BuildException("Cannot write to " + error, ioe, | |||||
getLocation()); | |||||
} | |||||
} | |||||
if (errorProperty != null) { | |||||
errorBaos = new ByteArrayOutputStream(); | |||||
log("Error redirected to property: " + errorProperty, | |||||
Project.MSG_VERBOSE); | |||||
if (error == null) { | |||||
errorStream = errorBaos; | |||||
} else { | |||||
errorStream = new TeeOutputStream(errorStream, errorBaos); | |||||
} | |||||
} else { | |||||
errorBaos = null; | |||||
} | |||||
if (input != null) { | |||||
try { | |||||
inputStream = new FileInputStream(input); | |||||
} catch (FileNotFoundException fne) { | |||||
throw new BuildException("Cannot read from " + input, fne, | |||||
getLocation()); | |||||
} | |||||
} | |||||
return new PumpStreamHandler(outputStream, errorStream, inputStream, | |||||
true, true, true); | |||||
return redirector.createHandler(); | |||||
} | } | ||||
/** | /** | ||||
@@ -579,14 +464,6 @@ public class ExecTask extends Task { | |||||
* Flush the output stream - if there is one. | * Flush the output stream - if there is one. | ||||
*/ | */ | ||||
protected void logFlush() { | protected void logFlush() { | ||||
try { | |||||
if (fos != null) { | |||||
fos.close(); | |||||
} | |||||
if (baos != null) { | |||||
baos.close(); | |||||
} | |||||
} catch (IOException io) {} | |||||
} | } | ||||
} | } |
@@ -55,9 +55,7 @@ | |||||
package org.apache.tools.ant.taskdefs; | package org.apache.tools.ant.taskdefs; | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.FileOutputStream; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.PrintStream; | |||||
import java.util.Vector; | import java.util.Vector; | ||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
import org.apache.tools.ant.ExitException; | import org.apache.tools.ant.ExitException; | ||||
@@ -89,12 +87,10 @@ public class Java extends Task { | |||||
private boolean fork = false; | private boolean fork = false; | ||||
private boolean newEnvironment = false; | private boolean newEnvironment = false; | ||||
private File dir = null; | private File dir = null; | ||||
private File out; | |||||
private PrintStream outStream = null; | |||||
private boolean failOnError = false; | private boolean failOnError = false; | ||||
private boolean append = false; | private boolean append = false; | ||||
private Long timeout = null; | private Long timeout = null; | ||||
private Redirector redirector = new Redirector(this); | |||||
/** | /** | ||||
* Do the execution. | * Do the execution. | ||||
*/ | */ | ||||
@@ -302,7 +298,54 @@ public class Java extends Task { | |||||
* File the output of the process is redirected to. | * File the output of the process is redirected to. | ||||
*/ | */ | ||||
public void setOutput(File out) { | public void setOutput(File out) { | ||||
this.out = out; | |||||
redirector.setOutput(out); | |||||
} | |||||
/** | |||||
* Set the input to use for the task | |||||
*/ | |||||
public void setInput(File input) { | |||||
redirector.setInput(input); | |||||
} | |||||
public void setInputString(String inputString) { | |||||
redirector.setInputString(inputString); | |||||
} | |||||
/** | |||||
* 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 | |||||
*/ | |||||
public void setLogError(boolean logError) { | |||||
redirector.setLogError(logError); | |||||
} | |||||
/** | |||||
* File the error stream of the process is redirected to. | |||||
* | |||||
* @since ant 1.6 | |||||
*/ | |||||
public void setError(File error) { | |||||
redirector.setError(error); | |||||
} | |||||
/** | |||||
* Property name whose value should be set to the output of | |||||
* the process. | |||||
*/ | |||||
public void setOutputproperty(String outputProp) { | |||||
redirector.setOutputProperty(outputProp); | |||||
} | |||||
/** | |||||
* Property name whose value should be set to the error of | |||||
* the process. | |||||
* | |||||
* @since ant 1.6 | |||||
*/ | |||||
public void setErrorProperty(String errorProperty) { | |||||
redirector.setErrorProperty(errorProperty); | |||||
} | } | ||||
/** | /** | ||||
@@ -366,8 +409,8 @@ public class Java extends Task { | |||||
* @since Ant 1.5 | * @since Ant 1.5 | ||||
*/ | */ | ||||
protected void handleOutput(String line) { | protected void handleOutput(String line) { | ||||
if (outStream != null) { | |||||
outStream.println(line); | |||||
if (redirector.getOutputStream() != null) { | |||||
redirector.handleOutput(line); | |||||
} else { | } else { | ||||
super.handleOutput(line); | super.handleOutput(line); | ||||
} | } | ||||
@@ -379,8 +422,8 @@ public class Java extends Task { | |||||
* @since Ant 1.5.2 | * @since Ant 1.5.2 | ||||
*/ | */ | ||||
protected void handleFlush(String line) { | protected void handleFlush(String line) { | ||||
if (outStream != null) { | |||||
outStream.print(line); | |||||
if (redirector.getOutputStream() != null) { | |||||
redirector.handleFlush(line); | |||||
} else { | } else { | ||||
super.handleFlush(line); | super.handleFlush(line); | ||||
} | } | ||||
@@ -392,8 +435,8 @@ public class Java extends Task { | |||||
* @since Ant 1.5 | * @since Ant 1.5 | ||||
*/ | */ | ||||
protected void handleErrorOutput(String line) { | protected void handleErrorOutput(String line) { | ||||
if (outStream != null) { | |||||
outStream.println(line); | |||||
if (redirector.getErrorStream() != null) { | |||||
redirector.handleErrorOutput(line); | |||||
} else { | } else { | ||||
super.handleErrorOutput(line); | super.handleErrorOutput(line); | ||||
} | } | ||||
@@ -405,8 +448,8 @@ public class Java extends Task { | |||||
* @since Ant 1.5.2 | * @since Ant 1.5.2 | ||||
*/ | */ | ||||
protected void handleErrorFlush(String line) { | protected void handleErrorFlush(String line) { | ||||
if (outStream != null) { | |||||
outStream.println(line); | |||||
if (redirector.getErrorStream() != null) { | |||||
redirector.handleErrorFlush(line); | |||||
} else { | } else { | ||||
super.handleErrorOutput(line); | super.handleErrorOutput(line); | ||||
} | } | ||||
@@ -417,28 +460,17 @@ public class Java extends Task { | |||||
* was a command line application. | * was a command line application. | ||||
*/ | */ | ||||
private void run(CommandlineJava command) throws BuildException { | private void run(CommandlineJava command) throws BuildException { | ||||
ExecuteJava exe = new ExecuteJava(); | |||||
exe.setJavaCommand(command.getJavaCommand()); | |||||
exe.setClasspath(command.getClasspath()); | |||||
exe.setSystemProperties(command.getSystemProperties()); | |||||
exe.setTimeout(timeout); | |||||
if (out != null) { | |||||
try { | |||||
outStream = | |||||
new PrintStream(new FileOutputStream(out.getAbsolutePath(), | |||||
append)); | |||||
exe.execute(getProject()); | |||||
System.out.flush(); | |||||
System.err.flush(); | |||||
} catch (IOException io) { | |||||
throw new BuildException(io, getLocation()); | |||||
} finally { | |||||
if (outStream != null) { | |||||
outStream.close(); | |||||
} | |||||
} | |||||
} else { | |||||
try { | |||||
ExecuteJava exe = new ExecuteJava(); | |||||
exe.setJavaCommand(command.getJavaCommand()); | |||||
exe.setClasspath(command.getClasspath()); | |||||
exe.setSystemProperties(command.getSystemProperties()); | |||||
exe.setTimeout(timeout); | |||||
redirector.createStreams(); | |||||
exe.execute(getProject()); | exe.execute(getProject()); | ||||
redirector.complete(); | |||||
} catch (IOException e) { | |||||
throw new BuildException(e); | |||||
} | } | ||||
} | } | ||||
@@ -446,19 +478,9 @@ public class Java extends Task { | |||||
* Executes the given classname with the given arguments in a separate VM. | * Executes the given classname with the given arguments in a separate VM. | ||||
*/ | */ | ||||
private int run(String[] command) throws BuildException { | private int run(String[] command) throws BuildException { | ||||
FileOutputStream fos = null; | |||||
try { | |||||
Execute exe = null; | |||||
if (out == null) { | |||||
exe = new Execute(new LogStreamHandler(this, Project.MSG_INFO, | |||||
Project.MSG_WARN), | |||||
createWatchdog()); | |||||
} else { | |||||
fos = new FileOutputStream(out.getAbsolutePath(), append); | |||||
exe = new Execute(new PumpStreamHandler(fos), | |||||
createWatchdog()); | |||||
} | |||||
Execute exe | |||||
= new Execute(redirector.createHandler(), createWatchdog()); | |||||
exe.setAntRun(getProject()); | exe.setAntRun(getProject()); | ||||
if (dir == null) { | if (dir == null) { | ||||
@@ -487,17 +509,11 @@ public class Java extends Task { | |||||
if (exe.killedProcess()) { | if (exe.killedProcess()) { | ||||
log("Timeout: killed the sub-process", Project.MSG_WARN); | log("Timeout: killed the sub-process", Project.MSG_WARN); | ||||
} | } | ||||
redirector.complete(); | |||||
return rc; | return rc; | ||||
} catch (IOException e) { | } catch (IOException e) { | ||||
throw new BuildException(e, getLocation()); | throw new BuildException(e, getLocation()); | ||||
} | } | ||||
} catch (IOException io) { | |||||
throw new BuildException(io, getLocation()); | |||||
} finally { | |||||
if (fos != null) { | |||||
try {fos.close();} catch (IOException io) {} | |||||
} | |||||
} | |||||
} | } | ||||
/** | /** | ||||
@@ -77,24 +77,15 @@ public class PumpStreamHandler implements ExecuteStreamHandler { | |||||
private OutputStream err; | private OutputStream err; | ||||
private InputStream input; | private InputStream input; | ||||
private boolean closeOutOnStop = false; | |||||
private boolean closeErrOnStop = false; | |||||
private boolean closeInputOnStop = false; | |||||
public PumpStreamHandler(OutputStream out, OutputStream err, | public PumpStreamHandler(OutputStream out, OutputStream err, | ||||
InputStream input, | |||||
boolean closeOutOnStop, boolean closeErrOnStop, | |||||
boolean closeInputOnStop) { | |||||
InputStream input) { | |||||
this.out = out; | this.out = out; | ||||
this.err = err; | this.err = err; | ||||
this.input = input; | this.input = input; | ||||
this.closeOutOnStop = closeOutOnStop; | |||||
this.closeErrOnStop = closeErrOnStop; | |||||
this.closeInputOnStop = closeInputOnStop; | |||||
} | } | ||||
public PumpStreamHandler(OutputStream out, OutputStream err) { | public PumpStreamHandler(OutputStream out, OutputStream err) { | ||||
this(out, err, null, false, false, false); | |||||
this(out, err, null); | |||||
} | } | ||||
public PumpStreamHandler(OutputStream outAndErr) { | public PumpStreamHandler(OutputStream outAndErr) { | ||||
@@ -151,29 +142,18 @@ public class PumpStreamHandler implements ExecuteStreamHandler { | |||||
if (inputThread != null) { | if (inputThread != null) { | ||||
try { | try { | ||||
inputThread.join(); | inputThread.join(); | ||||
if (closeInputOnStop) { | |||||
input.close(); | |||||
} | |||||
} catch (InterruptedException e) { | } catch (InterruptedException e) { | ||||
// ignore | // ignore | ||||
} catch (IOException e) { | |||||
// ignore | |||||
} | } | ||||
} | } | ||||
try { | try { | ||||
err.flush(); | err.flush(); | ||||
if (closeErrOnStop) { | |||||
err.close(); | |||||
} | |||||
} catch (IOException e) { | } catch (IOException e) { | ||||
// ignore | // ignore | ||||
} | } | ||||
try { | try { | ||||
out.flush(); | out.flush(); | ||||
if (closeOutOnStop) { | |||||
out.close(); | |||||
} | |||||
} catch (IOException e) { | } catch (IOException e) { | ||||
// ignore | // ignore | ||||
} | } | ||||
@@ -0,0 +1,344 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2003 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.taskdefs; | |||||
import java.io.BufferedReader; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.ByteArrayInputStream; | |||||
import java.io.File; | |||||
import java.io.FileNotFoundException; | |||||
import java.io.FileOutputStream; | |||||
import java.io.FileInputStream; | |||||
import java.io.IOException; | |||||
import java.io.StringReader; | |||||
import java.io.OutputStream; | |||||
import java.io.InputStream; | |||||
import java.io.PrintStream; | |||||
import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.Project; | |||||
import org.apache.tools.ant.Task; | |||||
import org.apache.tools.ant.util.StringUtils; | |||||
import org.apache.tools.ant.util.TeeOutputStream; | |||||
/** | |||||
* The Redirector class manages the setup and connection of | |||||
* input and output redirection for an Ant task. | |||||
* | |||||
* @author Conor MacNeill | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public class Redirector { | |||||
private File out; | |||||
private File error; | |||||
private File input; | |||||
private boolean logError = false; | |||||
private ByteArrayOutputStream baos = null; | |||||
private ByteArrayOutputStream errorBaos = null; | |||||
private String outputProperty; | |||||
private String errorProperty; | |||||
private String inputString; | |||||
private boolean append = false; | |||||
private Task managingTask; | |||||
private OutputStream outputStream = null; | |||||
private OutputStream errorStream = null; | |||||
private InputStream inputStream = null; | |||||
private PrintStream outPrintStream = null; | |||||
private PrintStream errorPrintStream = null; | |||||
public Redirector(Task managingTask) { | |||||
this.managingTask = managingTask; | |||||
} | |||||
/** | |||||
* Set the input to use for the task | |||||
*/ | |||||
public void setInput(File input) { | |||||
this.input = input; | |||||
} | |||||
public void setInputString(String inputString) { | |||||
this.inputString = inputString; | |||||
} | |||||
/** | |||||
* File the output of the process is redirected to. If error is not | |||||
* redirected, it too will appear in the output | |||||
*/ | |||||
public void setOutput(File out) { | |||||
this.out = out; | |||||
} | |||||
/** | |||||
* 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 | |||||
*/ | |||||
public void setLogError(boolean logError) { | |||||
this.logError = logError; | |||||
} | |||||
/** | |||||
* File the error stream of the process is redirected to. | |||||
* | |||||
*/ | |||||
public void setError(File error) { | |||||
this.error = error; | |||||
} | |||||
/** | |||||
* Property name whose value should be set to the output of | |||||
* the process. | |||||
*/ | |||||
public void setOutputProperty(String outputProperty) { | |||||
this.outputProperty = outputProperty; | |||||
} | |||||
/** | |||||
* Whether output should be appended to or overwrite an existing file. | |||||
* Defaults to false. | |||||
* | |||||
*/ | |||||
public void setAppend(boolean append) { | |||||
this.append = append; | |||||
} | |||||
/** | |||||
* Property name whose value should be set to the error of | |||||
* the process. | |||||
* | |||||
*/ | |||||
public void setErrorProperty(String errorProperty) { | |||||
this.errorProperty = errorProperty; | |||||
} | |||||
private void setPropertyFromBAOS(ByteArrayOutputStream baos, | |||||
String propertyName) throws IOException { | |||||
BufferedReader in = | |||||
new BufferedReader(new StringReader(Execute.toString(baos))); | |||||
String line = null; | |||||
StringBuffer val = new StringBuffer(); | |||||
while ((line = in.readLine()) != null) { | |||||
if (val.length() != 0) { | |||||
val.append(StringUtils.LINE_SEP); | |||||
} | |||||
val.append(line); | |||||
} | |||||
managingTask.getProject().setNewProperty(propertyName, val.toString()); | |||||
} | |||||
public void createStreams() { | |||||
if (out == null && outputProperty == null) { | |||||
outputStream = new LogOutputStream(managingTask, Project.MSG_INFO); | |||||
errorStream = new LogOutputStream(managingTask, Project.MSG_WARN); | |||||
} else { | |||||
if (out != null) { | |||||
try { | |||||
outputStream | |||||
= new FileOutputStream(out.getAbsolutePath(), append); | |||||
managingTask.log("Output redirected to " + out, | |||||
Project.MSG_VERBOSE); | |||||
} catch (FileNotFoundException fne) { | |||||
throw new BuildException("Cannot write to " + out, fne); | |||||
} catch (IOException ioe) { | |||||
throw new BuildException("Cannot write to " + out, ioe); | |||||
} | |||||
} | |||||
if (outputProperty != null) { | |||||
baos = new ByteArrayOutputStream(); | |||||
managingTask.log("Output redirected to property: " | |||||
+ outputProperty, Project.MSG_VERBOSE); | |||||
if (out == null) { | |||||
outputStream = baos; | |||||
} else { | |||||
outputStream = new TeeOutputStream(outputStream, baos); | |||||
} | |||||
} else { | |||||
baos = null; | |||||
} | |||||
errorStream = outputStream; | |||||
} | |||||
if (logError) { | |||||
errorStream = new LogOutputStream(managingTask, Project.MSG_WARN); | |||||
} | |||||
if (error != null) { | |||||
try { | |||||
errorStream | |||||
= new FileOutputStream(error.getAbsolutePath(), append); | |||||
managingTask.log("Error redirected to " + error, | |||||
Project.MSG_VERBOSE); | |||||
} catch (FileNotFoundException fne) { | |||||
throw new BuildException("Cannot write to " + error, fne); | |||||
} catch (IOException ioe) { | |||||
throw new BuildException("Cannot write to " + error, ioe); | |||||
} | |||||
} | |||||
if (errorProperty != null) { | |||||
errorBaos = new ByteArrayOutputStream(); | |||||
managingTask.log("Error redirected to property: " + errorProperty, | |||||
Project.MSG_VERBOSE); | |||||
if (error == null) { | |||||
errorStream = errorBaos; | |||||
} else { | |||||
errorStream = new TeeOutputStream(errorStream, errorBaos); | |||||
} | |||||
} else { | |||||
errorBaos = null; | |||||
} | |||||
if (input != null && inputString != null) { | |||||
throw new BuildException("The \"input\" and \"inputstring\" " | |||||
+ "attributes cannot both be specified"); | |||||
} | |||||
if (input != null) { | |||||
try { | |||||
inputStream = new FileInputStream(input); | |||||
} catch (FileNotFoundException fne) { | |||||
throw new BuildException("Cannot read from " + input, fne); | |||||
} | |||||
} else if (inputString != null) { | |||||
inputStream = new ByteArrayInputStream(inputString.getBytes()); | |||||
} | |||||
} | |||||
/** | |||||
* Create the StreamHandler to use with our Execute instance. | |||||
*/ | |||||
public ExecuteStreamHandler createHandler() throws BuildException { | |||||
createStreams(); | |||||
return new PumpStreamHandler(outputStream, errorStream, inputStream); | |||||
} | |||||
/** | |||||
* Pass output sent to System.out to specified output file. | |||||
* | |||||
*/ | |||||
protected void handleOutput(String line) { | |||||
if (outPrintStream == null) { | |||||
outPrintStream = new PrintStream(outputStream); | |||||
} | |||||
outPrintStream.println(line); | |||||
} | |||||
/** | |||||
* Pass output sent to System.out to specified output file. | |||||
* | |||||
*/ | |||||
protected void handleFlush(String line) { | |||||
if (outPrintStream == null) { | |||||
outPrintStream = new PrintStream(outputStream); | |||||
} | |||||
outPrintStream.print(line); | |||||
} | |||||
/** | |||||
* Pass output sent to System.err to specified output file. | |||||
* | |||||
*/ | |||||
protected void handleErrorOutput(String line) { | |||||
if (errorPrintStream == null) { | |||||
errorPrintStream = new PrintStream(errorStream); | |||||
} | |||||
errorPrintStream.println(line); | |||||
} | |||||
/** | |||||
* Pass output sent to System.err to specified output file. | |||||
* | |||||
*/ | |||||
protected void handleErrorFlush(String line) { | |||||
if (errorPrintStream == null) { | |||||
errorPrintStream = new PrintStream(errorStream); | |||||
} | |||||
errorPrintStream.print(line); | |||||
} | |||||
public OutputStream getOutputStream() { | |||||
return outputStream; | |||||
} | |||||
public OutputStream getErrorStream() { | |||||
return errorStream; | |||||
} | |||||
public void complete() throws IOException { | |||||
System.out.flush(); | |||||
System.err.flush(); | |||||
if (inputStream != null) { | |||||
inputStream.close(); | |||||
} | |||||
outputStream.close(); | |||||
errorStream.close(); | |||||
if (baos != null) { | |||||
setPropertyFromBAOS(baos, outputProperty); | |||||
} | |||||
if (errorBaos != null) { | |||||
setPropertyFromBAOS(errorBaos, errorProperty); | |||||
} | |||||
} | |||||
} |