/**
* Licensed to Cloudera, Inc. under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Cloudera, Inc. licenses this file
* to you 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 com.cloudera.util;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
import java.nio.channels.SelectableChannel;
import java.nio.channels.WritableByteChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Channels that wrap input streams are blocking, so this wrapper creates a
* thread that pumps data from input streams, and presents and nonblocking
* interface to the data.
*/
public class InputStreamPipe {
static final Logger LOG = LoggerFactory.getLogger(InputStreamPipe.class);
final InputStream input;
final Pipe pipe;
final CopyThread copyThread;
public InputStreamPipe(InputStream in) throws IOException {
this.input = in;
pipe = Pipe.open();
copyThread = new CopyThread(in, pipe.sink());
}
public InputStreamPipe() throws IOException {
this(System.in);
}
public void start() {
copyThread.start();
}
public void shutdown() {
copyThread.shutdown();
}
public SelectableChannel getChannel() throws IOException {
SelectableChannel channel = pipe.source();
channel.configureBlocking(false);
return (channel);
}
protected void finalize() {
copyThread.shutdown();
}
// ---------------------------------------------------
public static class CopyThread extends Thread {
volatile boolean keepRunning = true;
InputStream in;
WritableByteChannel out;
CopyThread(InputStream in, WritableByteChannel out) {
this.in = in;
this.out = out;
this.setDaemon(true);
}
public void shutdown() {
keepRunning = false;
this.interrupt();
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
byte[] bytes = new byte[4096];
ByteBuffer buffer = ByteBuffer.wrap(bytes);
try {
while (keepRunning) {
int count = in.read(bytes);
// 0 = nothing read
// -1 = EOF
if (count <= 0) {
// don't burn cpu if there is no progress
Clock.sleep(100);
break;
}
buffer.clear().limit(count);
out.write(buffer);
}
out.close();
} catch (IOException e) {
LOG.error("Input stream pipe closed", e);
} catch (InterruptedException e) {
LOG.info("Input stream pipe interrupted");
}
}
}
}