    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     *  contributor license agreements.  See the NOTICE file distributed with
    004     *  this work for additional information regarding copyright ownership.
    005     *  The ASF licenses this file to You under the Apache License, Version 2.0
    006     *  (the "License"); you may not use this file except in compliance with
    007     *  the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     *  Unless required by applicable law or agreed to in writing, software
    012     *  distributed under the License is distributed on an "AS IS" BASIS,
    013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     *  See the License for the specific language governing permissions and
    015     *  limitations under the License.
    016     *
    017     */
    018
    019    package org.apache.commons.exec;
    020
    021    import org.apache.commons.exec.util.DebugUtils;
    022
    023    import java.io.IOException;
    024    import java.io.InputStream;
    025    import java.io.OutputStream;
    026
    027    /**
    028     * Copies all data from an input stream to an output stream.
    029     */
    030    public class StreamPumper implements Runnable {
    031
    032        /** the default size of the internal buffer for copying the streams */
    033        private static final int DEFAULT_SIZE = 1024;
    034
    035        /** the input stream to pump from */
    036        private final InputStream is;
    037
    038        /** the output stream to pmp into */
    039        private final OutputStream os;
    040
    041        /** the size of the internal buffer for copying the streams */
    042        private final int size;
    043
    044        /** was the end of the stream reached */
    045        private boolean finished;
    046
    047        /** close the output stream when exhausted */
    048        private final boolean closeWhenExhausted;
    049
    050        /**
    051         * Create a new stream pumper.
    052         *
    053         * @param is input stream to read data from
    054         * @param os output stream to write data to.
    055         * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted.
    056         */
    057        public StreamPumper(final InputStream is, final OutputStream os,
    058                final boolean closeWhenExhausted) {
    059            this.is = is;
    060            this.os = os;
    061            this.size = DEFAULT_SIZE;
    062            this.closeWhenExhausted = closeWhenExhausted;
    063        }
    064
    065        /**
    066         * Create a new stream pumper.
    067         *
    068         * @param is input stream to read data from
    069         * @param os output stream to write data to.
    070         * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted.
    071         * @param size the size of the internal buffer for copying the streams
    072         */
    073        public StreamPumper(final InputStream is, final OutputStream os,
    074                final boolean closeWhenExhausted, final int size) {
    075            this.is = is;
    076            this.os = os;
    077            this.size = (size > 0 ? size : DEFAULT_SIZE);
    078            this.closeWhenExhausted = closeWhenExhausted;
    079        }
    080
    081        /**
    082         * Create a new stream pumper.
    083         *
    084         * @param is input stream to read data from
    085         * @param os output stream to write data to.
    086         */
    087        public StreamPumper(final InputStream is, final OutputStream os) {
    088            this(is, os, false);
    089        }
    090
    091        /**
    092         * Copies data from the input stream to the output stream. Terminates as
    093         * soon as the input stream is closed or an error occurs.
    094         */
    095        public void run() {
    096            synchronized (this) {
    097                // Just in case this object is reused in the future
    098                finished = false;
    099            }
    100
    101            final byte[] buf = new byte[this.size];
    102
    103            int length;
    104            try {
    105                while ((length = is.read(buf)) > 0) {
    106                    os.write(buf, 0, length);
    107                }
    108            } catch (Exception e) {
    109                String msg = "Got exception while reading/writing the stream";
    110                DebugUtils.handleException(msg ,e);
    111            } finally {
    112                if (closeWhenExhausted) {
    113                    try {
    114                        os.close();
    115                    } catch (IOException e) {
    116                        String msg = "Got exception while closing exhausted output stream";
    117                        DebugUtils.handleException(msg ,e);
    118                    }
    119                }
    120                synchronized (this) {
    121                    finished = true;
    122                    notifyAll();
    123                }
    124            }
    125        }
    126
    127        /**
    128         * Tells whether the end of the stream has been reached.
    129         *
    130         * @return true is the stream has been exhausted.
    131         */
    132        public synchronized boolean isFinished() {
    133            return finished;
    134        }
    135
    136        /**
    137         * This method blocks until the stream pumper finishes.
    138         *
    139         * @see #isFinished()
    140         */
    141        public synchronized void waitFor() throws InterruptedException {
    142            while (!isFinished()) {
    143                wait();
    144            }
    145        }
    146    }