/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
* select the license that you prefer but you may not use this file except in
* compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
package org.restlet.ext.netty.internal;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.restlet.engine.io.IoUtils;
/**
*
* @author Jerome Louvel
*/
public class HttpContentInputStream extends InputStream {
private final CyclicBarrier barrier;
private volatile ByteBuf content;
private volatile boolean lastContent;
private final ChannelHandlerContext nettyContext;
public HttpContentInputStream(ChannelHandlerContext nettyContext) {
this.nettyContext = nettyContext;
this.lastContent = false;
this.content = null;
this.barrier = new CyclicBarrier(2);
}
@Override
public int available() throws IOException {
return (content == null) ? 0 : content.readableBytes();
}
protected void getMoreContent() {
try {
// Ask to read more content
nettyContext.channel().config().setAutoRead(true);
// Block until new content is available
barrier.await(IoUtils.TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
protected boolean isLastContent() {
return lastContent;
}
public void onContent(ByteBuf content, boolean lastContent)
throws IOException {
try {
// Set the new content
this.content = content;
this.lastContent = lastContent;
// Unblock waiting consumer thread
barrier.await(IoUtils.TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
@Override
public int read() throws IOException {
int available = available();
if (available == 0) {
if (isLastContent()) {
return -1;
} else {
getMoreContent();
available = available();
}
}
return content.readByte() & 0xff;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int available = available();
if (available == 0) {
if (isLastContent()) {
return -1;
} else {
getMoreContent();
available = available();
}
}
len = Math.min(available, len);
content.readBytes(b, off, len);
return len;
}
}