/*
* Copyright 2010 netling project <http://netling.org>
*
* 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.
*/
package org.netling.io;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StreamCopier
extends Thread {
private static final Logger LOG = LoggerFactory.getLogger(StreamCopier.class);
public interface ErrorCallback {
void onError(IOException ioe);
}
public static ErrorCallback closeOnErrorCallback(final Closeable... toClose) {
return new ErrorCallback() {
@Override
public void onError(IOException ioe) {
Util.closeQuietly(toClose);
}
};
}
public interface Listener {
void reportProgress(long transferred);
}
public static long copy(InputStream in, OutputStream out, int bufSize, boolean keepFlushing, Listener listener)
throws CopyStreamException {
long count = 0;
final boolean reportProgress = listener != null;
final long startTime = System.currentTimeMillis();
final byte[] buf = new byte[bufSize];
int read;
try {
while ((read = in.read(buf)) != -1) {
if (read == 0)
continue;
out.write(buf, 0, read);
count += read;
if (keepFlushing)
out.flush();
if (reportProgress)
listener.reportProgress(count);
}
if (!keepFlushing)
out.flush();
} catch (IOException ioe) {
throw new CopyStreamException("IOException caught while copying", count, ioe);
}
final double sizeKiB = count / 1024.0;
final double timeSeconds = (System.currentTimeMillis() - startTime) / 1000.0;
LOG.info(sizeKiB + " KiB transferred in {} seconds ({} KiB/s)", timeSeconds, (sizeKiB / timeSeconds));
return count;
}
public static long copy(InputStream in, OutputStream out, int bufSize, boolean keepFlushing)
throws IOException {
return copy(in, out, bufSize, keepFlushing, null);
}
public static String copyStreamToString(InputStream stream)
throws IOException {
final StringBuilder sb = new StringBuilder();
int read;
while ((read = stream.read()) != -1)
sb.append((char) read);
return sb.toString();
}
private final Logger log = LoggerFactory.getLogger(getClass());
private final InputStream in;
private final OutputStream out;
private int bufSize = 1;
private boolean keepFlushing = true;
private ErrorCallback errCB = new ErrorCallback() {
@Override
public void onError(IOException ioe) {
}
}; // Default null cb
public StreamCopier(String name, InputStream in, OutputStream out) {
this.in = in;
this.out = out;
setName(name);
}
public StreamCopier bufSize(int size) {
bufSize = size;
return this;
}
public StreamCopier keepFlushing(boolean choice) {
keepFlushing = choice;
return this;
}
public StreamCopier daemon(boolean choice) {
setDaemon(choice);
return this;
}
public StreamCopier errorCallback(ErrorCallback errCB) {
this.errCB = errCB;
return this;
}
@Override
public void run() {
try {
log.debug("Wil pipe from {} to {}", in, out);
copy(in, out, bufSize, keepFlushing);
log.debug("EOF on {}", in);
} catch (IOException ioe) {
log.error("In pipe from {} to {}: " + ioe.toString(), in, out);
errCB.onError(ioe);
}
}
}