StreamPumper.java

package org.codehaus.plexus.util.cli;

/*
 * Copyright The Codehaus Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/********************************************************************************
 * CruiseControl, a Continuous Integration Toolkit
 * Copyright (c) 2001-2003, ThoughtWorks, Inc.
 * 651 W Washington Ave. Suite 500
 * Chicago, IL 60661 USA
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *     + Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     + 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.
 *
 *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
 *       names of its contributors may be used to endorse or promote
 *       products derived from this software without specific prior
 *       written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS 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 REGENTS OR
 * 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.
 ********************************************************************************/

/* ====================================================================
 * Copyright 2003-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ====================================================================
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;

/**
 * Class to pump the error stream during Process's runtime. Copied from the Ant built-in task.
 *
 * @author <a href="mailto:fvancea@maxiq.com">Florin Vancea </a>
 * @author <a href="mailto:pj@thoughtworks.com">Paul Julius </a>
 *
 * @since June 11, 2001
 */
public class StreamPumper extends AbstractStreamHandler {
    private final BufferedReader in;

    private final StreamConsumer consumer;

    private final PrintWriter out;

    private volatile Exception exception = null;

    private static final int SIZE = 1024;

    public StreamPumper(InputStream in) {
        this(in, (StreamConsumer) null);
    }

    public StreamPumper(InputStream in, StreamConsumer consumer) {
        this(in, null, consumer);
    }

    public StreamPumper(InputStream in, PrintWriter writer) {
        this(in, writer, null);
    }

    public StreamPumper(InputStream in, PrintWriter writer, StreamConsumer consumer) {
        super();
        this.in = new BufferedReader(new InputStreamReader(in), SIZE);
        this.out = writer;
        this.consumer = consumer;
    }

    @Override
    public void run() {
        boolean outError = out != null ? out.checkError() : false;

        try {
            for (String line = in.readLine(); line != null; line = in.readLine()) {
                try {
                    if (exception == null && consumer != null && !isDisabled()) {
                        consumer.consumeLine(line);
                    }
                } catch (Exception t) {
                    exception = t;
                }

                if (out != null && !outError) {
                    out.println(line);

                    out.flush();

                    if (out.checkError()) {
                        outError = true;

                        try {
                            // Thrown to fill in stack trace elements.
                            throw new IOException(String.format("Failure printing line '%s'.", line));
                        } catch (final IOException e) {
                            exception = e;
                        }
                    }
                }
            }
        } catch (IOException e) {
            exception = e;
        } finally {
            try {
                in.close();
            } catch (final IOException e2) {
                if (exception == null) {
                    exception = e2;
                }
            }

            synchronized (this) {
                setDone();

                this.notifyAll();
            }
        }
    }

    public void flush() {
        if (out != null) {
            out.flush();

            if (out.checkError() && exception == null) {
                try {
                    // Thrown to fill in stack trace elements.
                    throw new IOException("Failure flushing output.");
                } catch (final IOException e) {
                    exception = e;
                }
            }
        }
    }

    public void close() {
        if (out != null) {
            out.close();

            if (out.checkError() && exception == null) {
                try {
                    // Thrown to fill in stack trace elements.
                    throw new IOException("Failure closing output.");
                } catch (final IOException e) {
                    exception = e;
                }
            }
        }
    }

    public Exception getException() {
        return exception;
    }
}