FileDocCategorySizeDatePackage
Redirector.javaAPI DocApache Ant 1.7028057Wed Dec 13 06:16:20 GMT 2006org.apache.tools.ant.taskdefs

Redirector

public class Redirector extends Object
The Redirector class manages the setup and connection of input and output redirection for an Ant project component.
since
Ant 1.6

Fields Summary
private static final String
DEFAULT_ENCODING
private File[]
input
The file(s) from which standard input is being taken. If > 1, files' content will be concatenated in the order received.
private File[]
out
The file(s) receiving standard output. Will also receive standard error unless standard error is redirected or logError is true.
private File[]
error
The file(s) to which standard error is being redirected
private boolean
logError
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 PropertyOutputStream
baos
Buffer used to capture output for storage into a property
private PropertyOutputStream
errorBaos
Buffer used to capture error output for storage into a property
private String
outputProperty
The name of the property into which output is to be stored
private String
errorProperty
The name of the property into which error output is to be stored
private String
inputString
String from which input is taken
private boolean
append
Flag which indicates if error and output files are to be appended.
private boolean
alwaysLog
Flag which indicates that output should be always sent to the log
private boolean
createEmptyFiles
Flag which indicates whether files should be created even when empty.
private org.apache.tools.ant.ProjectComponent
managingTask
The task for which this redirector is working
private OutputStream
outputStream
The stream for output data
private OutputStream
errorStream
The stream for error output
private InputStream
inputStream
The stream for input
private PrintStream
outPrintStream
Stream which is used for line oriented output
private PrintStream
errorPrintStream
Stream which is used for line oriented error output
private Vector
outputFilterChains
The output filter chains
private Vector
errorFilterChains
The error filter chains
private Vector
inputFilterChains
The input filter chains
private String
outputEncoding
The output encoding
private String
errorEncoding
The error encoding
private String
inputEncoding
The input encoding
private boolean
appendProperties
Whether to complete properties settings
private ThreadGroup
threadGroup
The thread group used for starting StreamPumper threads
private boolean
logInputString
whether to log the inputstring
Constructors Summary
public Redirector(org.apache.tools.ant.Task managingTask)
Create a redirector instance for the given task

param
managingTask the task for which the redirector is to work


                            
       
        this((ProjectComponent) managingTask);
    
public Redirector(org.apache.tools.ant.ProjectComponent managingTask)
Create a redirector instance for the given task

param
managingTask the project component for which the redirector is to work
since
Ant 1.6.3

        this.managingTask = managingTask;
    
Methods Summary
public synchronized voidcomplete()
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.

        System.out.flush();
        System.err.flush();

        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
                    }
                }
                wait(1000);
            } catch (InterruptedException eyeEx) {
                // Ignore exception
            }
        }

        setProperties();

        inputStream = null;
        outputStream = null;
        errorStream = null;
        outPrintStream = null;
        errorPrintStream = null;
   
public synchronized ExecuteStreamHandlercreateHandler()
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.

        createStreams();
        return new PumpStreamHandler(outputStream, errorStream, inputStream);
    
public synchronized voidcreateStreams()
Create the input, error and output streams based on the configuration options.

        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);
        }
        if (outputProperty != null) {
            if (baos == null) {
                baos = new PropertyOutputStream(outputProperty);
                managingTask.log("Output redirected to property: "
                    + outputProperty, Project.MSG_VERBOSE);
            }
            //shield it from being closed by a filtering StreamPumper
            OutputStream keepAliveOutput = new KeepAliveOutputStream(baos);
            outputStream = (outputStream == null) ? keepAliveOutput
                : new TeeOutputStream(outputStream, keepAliveOutput);
        } else {
            baos = null;
        }

        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);
        } else if (!(logError || outputStream == null)) {
            long funnelTimeout = 0L;
            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);
            }
        }
        if (errorProperty != null) {
            if (errorBaos == null) {
                errorBaos = new PropertyOutputStream(errorProperty);
                managingTask.log("Error redirected to property: " + errorProperty,
                    Project.MSG_VERBOSE);
            }
            //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);
        } else {
            errorBaos = null;
        }
        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;

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

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

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

                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");
            }
            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);
            }
            helper.setFilterChains(inputFilterChains);
            inputStream = new ReaderInputStream(
                helper.getAssembledReader(), inputEncoding);
        }
    
private java.io.OutputStreamfoldFiles(java.io.File[] file, java.lang.String logHead, int loglevel)

        OutputStream result
            = new LazyFileOutputStream(file[0], append, createEmptyFiles);

        managingTask.log(logHead + file[0], loglevel);
        char[] c = new char[logHead.length()];
        Arrays.fill(c, ' ");
        String indent = new String(c);

        for (int i = 1; i < file.length; i++) {
            outputStream = new TeeOutputStream(outputStream,
                new LazyFileOutputStream(file[i], append, createEmptyFiles));
            managingTask.log(indent + file[i], loglevel);
        }
        return result;
    
public synchronized java.io.OutputStreamgetErrorStream()
Get the error stream for the redirector

return
the redirector's error stream or null if no output has been configured

        return errorStream;
    
public synchronized java.io.InputStreamgetInputStream()
Get the input stream for the redirector

return
the redirector's input stream or null if no output has been configured

        return inputStream;
    
public synchronized java.io.OutputStreamgetOutputStream()
Get the output stream for the redirector

return
the redirector's output stream or null if no output has been configured

        return outputStream;
    
protected synchronized voidhandleErrorFlush(java.lang.String output)
Handle a flush operation on the error stream

param
output the error information being flushed.

        if (errorPrintStream == null) {
            errorPrintStream = new PrintStream(errorStream);
        }
        errorPrintStream.print(output);
    
protected synchronized voidhandleErrorOutput(java.lang.String output)
Process error output

param
output the error output data.

        if (errorPrintStream == null) {
            errorPrintStream = new PrintStream(errorStream);
        }
        errorPrintStream.print(output);
    
protected synchronized voidhandleFlush(java.lang.String output)
Process data due to a flush operation.

param
output the data being flushed.

        if (outPrintStream == null) {
            outPrintStream = new PrintStream(outputStream);
        }
        outPrintStream.print(output);
        outPrintStream.flush();
    
protected synchronized inthandleInput(byte[] buffer, int offset, int length)
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
return
the number of bytes read
exception
IOException if the data cannot be read

        if (inputStream == null) {
            return managingTask.getProject().defaultInput(buffer, offset,
                                                          length);
        } else {
            return inputStream.read(buffer, offset, length);
        }
    
protected synchronized voidhandleOutput(java.lang.String output)
Pass output sent to System.out to specified output.

param
output the data to be output

        if (outPrintStream == null) {
            outPrintStream = new PrintStream(outputStream);
        }
        outPrintStream.print(output);
    
public synchronized voidsetAlwaysLog(boolean alwaysLog)
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 boolean
since
Ant 1.6.3

        this.alwaysLog = alwaysLog;
    
public synchronized voidsetAppend(boolean append)
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.

        this.append = append;
    
public synchronized voidsetAppendProperties(boolean appendProperties)
This Redirector's subordinate PropertyOutputStreams will not set their respective properties while (appendProperties && append).

param
appendProperties whether to append properties.

        this.appendProperties = appendProperties;
    
public synchronized voidsetCreateEmptyFiles(boolean createEmptyFiles)
Whether output and error files should be created even when empty. Defaults to true.

param
createEmptyFiles boolean.

        this.createEmptyFiles = createEmptyFiles;
    
public voidsetError(java.io.File error)
Set the file to which standard error is to be redirected.

param
error the file to which error is to be written

        setError((error == null) ? null : new File[] {error});
    
public synchronized voidsetError(java.io.File[] error)
Set the files to which standard error is to be redirected.

param
error the file to which error is to be written

        this.error = error;
    
public synchronized voidsetErrorEncoding(java.lang.String errorEncoding)
Set the error encoding.

param
errorEncoding String.

        if (errorEncoding == null) {
            throw new IllegalArgumentException(
                "errorEncoding must not be null");
        } else {
            this.errorEncoding = errorEncoding;
        }
    
public synchronized voidsetErrorFilterChains(java.util.Vector errorFilterChains)
Set the error FilterChains.

param
errorFilterChains Vector containing FilterChain.

        this.errorFilterChains = errorFilterChains;
    
public synchronized voidsetErrorProperty(java.lang.String errorProperty)
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.

        if (errorProperty == null
         || !(errorProperty.equals(this.errorProperty))) {
            this.errorProperty = errorProperty;
            errorBaos = null;
        }
    
public voidsetInput(java.io.File input)
Set the input to use for the task

param
input the file from which input is read.

        setInput((input == null) ? null : new File[] {input});
    
public synchronized voidsetInput(java.io.File[] input)
Set the input to use for the task

param
input the files from which input is read.

        this.input = input;
    
public synchronized voidsetInputEncoding(java.lang.String inputEncoding)
Set the input encoding.

param
inputEncoding String.

        if (inputEncoding == null) {
            throw new IllegalArgumentException(
                "inputEncoding must not be null");
        } else {
            this.inputEncoding = inputEncoding;
        }
    
public synchronized voidsetInputFilterChains(java.util.Vector inputFilterChains)
Set the input FilterChains.

param
inputFilterChains Vector containing FilterChain.

        this.inputFilterChains = inputFilterChains;
    
voidsetInputStream(java.io.InputStream inputStream)
Set a stream to use as input.

param
inputStream the stream from which input will be read
since
Ant 1.6.3

        this.inputStream = inputStream;
    
public synchronized voidsetInputString(java.lang.String inputString)
Set the string to use as input

param
inputString the string which is used as the input source

        this.inputString = inputString;
    
public synchronized voidsetLogError(boolean 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.

        this.logError = logError;
    
public voidsetLogInputString(boolean logInputString)
Set whether to include the value of the input string in log messages. Defaults to true.

param
logInputString true or false.
since
Ant 1.7

        this.logInputString = logInputString;
    
public voidsetOutput(java.io.File out)
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

        setOutput((out == null) ? null : new File[] {out});
    
public synchronized voidsetOutput(java.io.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

        this.out = out;
    
public synchronized voidsetOutputEncoding(java.lang.String outputEncoding)
Set the output encoding.

param
outputEncoding String.

        if (outputEncoding == null) {
            throw new IllegalArgumentException(
                "outputEncoding must not be null");
        } else {
            this.outputEncoding = outputEncoding;
        }
    
public synchronized voidsetOutputFilterChains(java.util.Vector outputFilterChains)
Set the output FilterChains.

param
outputFilterChains Vector containing FilterChain.

        this.outputFilterChains = outputFilterChains;
    
public synchronized voidsetOutputProperty(java.lang.String outputProperty)
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.

        if (outputProperty == null
         || !(outputProperty.equals(this.outputProperty))) {
            this.outputProperty = outputProperty;
            baos = null;
        }
    
public synchronized voidsetProperties()
Notify the Redirector that it is now okay to set any output and/or error properties.

        if (baos != null) {
            try {
                baos.close();
            } catch (IOException eyeOhEx) {
                // Ignore exception
            }
        }
        if (errorBaos != null) {
            try {
                errorBaos.close();
            } catch (IOException eyeOhEx) {
                // Ignore exception
            }
        }
    
private voidsetPropertyFromBAOS(java.io.ByteArrayOutputStream baos, java.lang.String propertyName)
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.


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