package org.rzo.netty.ahessian.io; import java.io.InputStream; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.rzo.netty.ahessian.Constants; public class PushInputStreamConsumer extends SimpleChannelUpstreamHandler { volatile Lock _lock = new ReentrantLock(); AtomicInteger _consumerThreadsCount = new AtomicInteger(0); volatile InputStreamConsumer _consumer; volatile Executor _executor; public PushInputStreamConsumer(InputStreamConsumer consumer, Executor executor) { _consumer = consumer; _executor = executor; } @Override public void messageReceived(final ChannelHandlerContext ctx, final MessageEvent evt) throws Exception { // input stream is consumed within a separate thread // we return the current worker thread to netty, so that it may continue feeding the input stream _executor.execute(new Runnable() { public void run() { String tName = Thread.currentThread().getName(); try { PushInputStreamConsumer.this.run(ctx, evt); } finally { Thread.currentThread().setName(tName); _consumerThreadsCount.decrementAndGet(); } } }); } private void run(ChannelHandlerContext ctx, MessageEvent evt) { if (_consumer.isBufferEmpty()) { // we have nothing to consume return; } if (_consumerThreadsCount.incrementAndGet() > 2) { // there is already a thread consuming and another at the gate to consume the last chunk _consumerThreadsCount.decrementAndGet(); return; } Thread.currentThread().setName("ahessian-PushInputStreamConsumer-#"+_consumerThreadsCount.get()); // consume only with one thread at a time _lock.lock(); try { _consumer.consume(ctx, (InputStream)evt.getMessage()); } catch (Exception ex) { Constants.ahessianLogger.warn("", ex); } finally { _consumerThreadsCount.decrementAndGet(); _lock.unlock(); } } public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { _lock.lock(); _consumer.setContext(ctx); _lock.unlock(); ctx.sendUpstream(e); } }