StreamPumper.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */

  17. package org.apache.commons.exec;

  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.OutputStream;

  21. import org.apache.commons.exec.util.DebugUtils;

  22. /**
  23.  * Copies all data from an input stream to an output stream.
  24.  */
  25. public class StreamPumper implements Runnable {

  26.     /** The default size of the internal buffer for copying the streams. */
  27.     private static final int DEFAULT_SIZE = 1024;

  28.     /** The input stream to pump from. */
  29.     private final InputStream is;

  30.     /** The output stream to pmp into. */
  31.     private final OutputStream os;

  32.     /** The size of the internal buffer for copying the streams. */
  33.     private final int size;

  34.     /** Was the end of the stream reached. */
  35.     private boolean finished;

  36.     /** Close the output stream when exhausted. */
  37.     private final boolean closeWhenExhausted;

  38.     /**
  39.      * Constructs a new stream pumper.
  40.      *
  41.      * @param is input stream to read data from.
  42.      * @param os output stream to write data to.
  43.      */
  44.     public StreamPumper(final InputStream is, final OutputStream os) {
  45.         this(is, os, false);
  46.     }

  47.     /**
  48.      * Constructs a new stream pumper.
  49.      *
  50.      * @param is                 input stream to read data from.
  51.      * @param os                 output stream to write data to.
  52.      * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted.
  53.      */
  54.     public StreamPumper(final InputStream is, final OutputStream os, final boolean closeWhenExhausted) {
  55.         this.is = is;
  56.         this.os = os;
  57.         this.size = DEFAULT_SIZE;
  58.         this.closeWhenExhausted = closeWhenExhausted;
  59.     }

  60.     /**
  61.      * Constructs a new stream pumper.
  62.      *
  63.      * @param is                 input stream to read data from.
  64.      * @param os                 output stream to write data to.
  65.      * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted.
  66.      * @param size               the size of the internal buffer for copying the streams.
  67.      */
  68.     public StreamPumper(final InputStream is, final OutputStream os, final boolean closeWhenExhausted, final int size) {
  69.         this.is = is;
  70.         this.os = os;
  71.         this.size = size > 0 ? size : DEFAULT_SIZE;
  72.         this.closeWhenExhausted = closeWhenExhausted;
  73.     }

  74.     /**
  75.      * Tests whether the end of the stream has been reached.
  76.      *
  77.      * @return true is the stream has been exhausted.
  78.      */
  79.     public synchronized boolean isFinished() {
  80.         return finished;
  81.     }

  82.     /**
  83.      * Copies data from the input stream to the output stream. Terminates as soon as the input stream is closed or an error occurs.
  84.      */
  85.     @Override
  86.     public void run() {
  87.         synchronized (this) {
  88.             // Just in case this object is reused in the future
  89.             finished = false;
  90.         }

  91.         final byte[] buf = new byte[this.size];

  92.         int length;
  93.         try {
  94.             while ((length = is.read(buf)) > 0) {
  95.                 os.write(buf, 0, length);
  96.             }
  97.         } catch (final Exception ignored) {
  98.             // nothing to do - happens quite often with watchdog
  99.         } finally {
  100.             if (closeWhenExhausted) {
  101.                 try {
  102.                     os.close();
  103.                 } catch (final IOException e) {
  104.                     final String msg = "Got exception while closing exhausted output stream";
  105.                     DebugUtils.handleException(msg, e);
  106.                 }
  107.             }
  108.             synchronized (this) {
  109.                 finished = true;
  110.                 notifyAll();
  111.             }
  112.         }
  113.     }

  114.     /**
  115.      * This method blocks until the stream pumper finishes.
  116.      *
  117.      * @throws InterruptedException if any thread interrupted the current thread before or while the current thread was waiting for a notification.
  118.      * @see #isFinished()
  119.      */
  120.     public synchronized void waitFor() throws InterruptedException {
  121.         while (!isFinished()) {
  122.             wait();
  123.         }
  124.     }
  125. }