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