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 019package org.apache.commons.exec; 020 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.OutputStream; 024 025import org.apache.commons.exec.util.DebugUtils; 026 027/** 028 * Copies all data from an input stream to an output stream. 029 * 030 * @version $Id: StreamPumper.java 1557263 2014-01-10 21:18:09Z ggregory $ 031 */ 032public class StreamPumper implements Runnable { 033 034 /** the default size of the internal buffer for copying the streams */ 035 private static final int DEFAULT_SIZE = 1024; 036 037 /** the input stream to pump from */ 038 private final InputStream is; 039 040 /** the output stream to pmp into */ 041 private final OutputStream os; 042 043 /** the size of the internal buffer for copying the streams */ 044 private final int size; 045 046 /** was the end of the stream reached */ 047 private boolean finished; 048 049 /** close the output stream when exhausted */ 050 private final boolean closeWhenExhausted; 051 052 /** 053 * Create a new stream pumper. 054 * 055 * @param is input stream to read data from 056 * @param os output stream to write data to. 057 * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted. 058 */ 059 public StreamPumper(final InputStream is, final OutputStream os, 060 final boolean closeWhenExhausted) { 061 this.is = is; 062 this.os = os; 063 this.size = DEFAULT_SIZE; 064 this.closeWhenExhausted = closeWhenExhausted; 065 } 066 067 /** 068 * Create a new stream pumper. 069 * 070 * @param is input stream to read data from 071 * @param os output stream to write data to. 072 * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted. 073 * @param size the size of the internal buffer for copying the streams 074 */ 075 public StreamPumper(final InputStream is, final OutputStream os, 076 final boolean closeWhenExhausted, final int size) { 077 this.is = is; 078 this.os = os; 079 this.size = size > 0 ? size : DEFAULT_SIZE; 080 this.closeWhenExhausted = closeWhenExhausted; 081 } 082 083 /** 084 * Create a new stream pumper. 085 * 086 * @param is input stream to read data from 087 * @param os output stream to write data to. 088 */ 089 public StreamPumper(final InputStream is, final OutputStream os) { 090 this(is, os, false); 091 } 092 093 /** 094 * Copies data from the input stream to the output stream. Terminates as 095 * soon as the input stream is closed or an error occurs. 096 */ 097 public void run() { 098 synchronized (this) { 099 // Just in case this object is reused in the future 100 finished = false; 101 } 102 103 final byte[] buf = new byte[this.size]; 104 105 int length; 106 try { 107 while ((length = is.read(buf)) > 0) { 108 os.write(buf, 0, length); 109 } 110 } catch (final Exception e) { 111 // nothing to do - happens quite often with watchdog 112 } finally { 113 if (closeWhenExhausted) { 114 try { 115 os.close(); 116 } catch (final IOException e) { 117 final String msg = "Got exception while closing exhausted output stream"; 118 DebugUtils.handleException(msg ,e); 119 } 120 } 121 synchronized (this) { 122 finished = true; 123 notifyAll(); 124 } 125 } 126 } 127 128 /** 129 * Tells whether the end of the stream has been reached. 130 * 131 * @return true is the stream has been exhausted. 132 */ 133 public synchronized boolean isFinished() { 134 return finished; 135 } 136 137 /** 138 * This method blocks until the stream pumper finishes. 139 * 140 * @exception InterruptedException 141 * if any thread interrupted the current thread before or while the current thread was waiting for a 142 * notification. 143 * @see #isFinished() 144 */ 145 public synchronized void waitFor() throws InterruptedException { 146 while (!isFinished()) { 147 wait(); 148 } 149 } 150}