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 }