Ensure that a user implements flush() or inboundBufferUpdated()

- Also prohibited a user from overriding
  ChannelInbound(Byte|Message)HandlerAdapter.  If a user wants to do
  that, he or she should extend ChannelInboundHandlerAdapter instead.
This commit is contained in:
Trustin Lee 2012-06-10 10:48:11 +09:00
parent b6d5593e6a
commit 87f52aa604
20 changed files with 99 additions and 116 deletions

View File

@ -22,18 +22,18 @@ import io.netty.channel.ChannelInboundByteHandlerAdapter;
public abstract class ByteToByteDecoder extends ChannelInboundByteHandlerAdapter { public abstract class ByteToByteDecoder extends ChannelInboundByteHandlerAdapter {
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx, ChannelBuffer in) throws Exception {
callDecode(ctx); callDecode(ctx, in, ctx.nextOutboundByteBuffer());
} }
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ChannelBuffer in = ctx.inboundByteBuffer(); ChannelBuffer in = ctx.inboundByteBuffer();
ChannelBuffer out = ctx.nextInboundByteBuffer();
if (!in.readable()) { if (!in.readable()) {
callDecode(ctx); callDecode(ctx, in, out);
} }
ChannelBuffer out = ctx.nextInboundByteBuffer();
int oldOutSize = out.readableBytes(); int oldOutSize = out.readableBytes();
try { try {
decodeLast(ctx, in, out); decodeLast(ctx, in, out);
@ -53,10 +53,7 @@ public abstract class ByteToByteDecoder extends ChannelInboundByteHandlerAdapter
ctx.fireChannelInactive(); ctx.fireChannelInactive();
} }
private void callDecode(ChannelHandlerContext ctx) { private void callDecode(ChannelHandlerContext ctx, ChannelBuffer in, ChannelBuffer out) {
ChannelBuffer in = ctx.inboundByteBuffer();
ChannelBuffer out = ctx.nextInboundByteBuffer();
int oldOutSize = out.readableBytes(); int oldOutSize = out.readableBytes();
while (in.readable()) { while (in.readable()) {
int oldInSize = in.readableBytes(); int oldInSize = in.readableBytes();

View File

@ -16,12 +16,14 @@
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ChannelBuffer; import io.netty.buffer.ChannelBuffer;
import io.netty.channel.ChannelBufferHolder;
import io.netty.channel.ChannelBufferHolders;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler; import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundByteHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
public abstract class ByteToMessageDecoder<O> extends ChannelInboundByteHandlerAdapter { public abstract class ByteToMessageDecoder<O> extends ChannelInboundHandlerAdapter<Byte> {
private ChannelHandlerContext ctx; private ChannelHandlerContext ctx;
@ -31,6 +33,11 @@ public abstract class ByteToMessageDecoder<O> extends ChannelInboundByteHandlerA
super.beforeAdd(ctx); super.beforeAdd(ctx);
} }
@Override
public ChannelBufferHolder<Byte> newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return ChannelBufferHolders.byteBuffer();
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
callDecode(ctx); callDecode(ctx);

View File

@ -47,30 +47,30 @@ final class CodecUtil {
} }
if (inbound) { if (inbound) {
try { if (ctx.hasNextInboundMessageBuffer()) {
ctx.nextInboundMessageBuffer().add(msg); ctx.nextInboundMessageBuffer().add(msg);
return true; return true;
} catch (NoSuchBufferException e) { }
if (msg instanceof ChannelBuffer) {
if (msg instanceof ChannelBuffer && ctx.hasNextInboundByteBuffer()) {
ChannelBuffer altDst = ctx.nextInboundByteBuffer(); ChannelBuffer altDst = ctx.nextInboundByteBuffer();
ChannelBuffer src = (ChannelBuffer) msg; ChannelBuffer src = (ChannelBuffer) msg;
altDst.writeBytes(src, src.readerIndex(), src.readableBytes()); altDst.writeBytes(src, src.readerIndex(), src.readableBytes());
return true; return true;
} }
}
} else { } else {
try { if (ctx.hasNextOutboundMessageBuffer()) {
ctx.nextOutboundMessageBuffer().add(msg); ctx.nextOutboundMessageBuffer().add(msg);
return true; return true;
} catch (NoSuchBufferException e) { }
if (msg instanceof ChannelBuffer) {
if (msg instanceof ChannelBuffer && ctx.hasNextOutboundByteBuffer()) {
ChannelBuffer altDst = ctx.nextOutboundByteBuffer(); ChannelBuffer altDst = ctx.nextOutboundByteBuffer();
ChannelBuffer src = (ChannelBuffer) msg; ChannelBuffer src = (ChannelBuffer) msg;
altDst.writeBytes(src, src.readerIndex(), src.readableBytes()); altDst.writeBytes(src, src.readerIndex(), src.readableBytes());
return true; return true;
} }
} }
}
throw new NoSuchBufferException(); throw new NoSuchBufferException();
} }

View File

@ -15,12 +15,19 @@
*/ */
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.channel.ChannelBufferHolder;
import io.netty.channel.ChannelBufferHolders;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.Queue; import java.util.Queue;
public abstract class MessageToMessageDecoder<I, O> extends ChannelInboundMessageHandlerAdapter<I> { public abstract class MessageToMessageDecoder<I, O> extends ChannelInboundHandlerAdapter<I> {
@Override
public ChannelBufferHolder<I> newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return ChannelBufferHolders.messageBuffer();
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) public void inboundBufferUpdated(ChannelHandlerContext ctx)

View File

@ -53,16 +53,14 @@ public class PortUnificationServerHandler extends ChannelInboundByteHandlerAdapt
} }
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx, ChannelBuffer in) throws Exception {
ChannelBuffer buffer = ctx.inboundByteBuffer();
// Will use the first two bytes to detect a protocol. // Will use the first two bytes to detect a protocol.
if (buffer.readableBytes() < 2) { if (in.readableBytes() < 2) {
return; return;
} }
final int magic1 = buffer.getUnsignedByte(buffer.readerIndex()); final int magic1 = in.getUnsignedByte(in.readerIndex());
final int magic2 = buffer.getUnsignedByte(buffer.readerIndex() + 1); final int magic2 = in.getUnsignedByte(in.readerIndex() + 1);
if (isSsl(magic1)) { if (isSsl(magic1)) {
enableSsl(ctx); enableSsl(ctx);
@ -74,13 +72,13 @@ public class PortUnificationServerHandler extends ChannelInboundByteHandlerAdapt
switchToFactorial(ctx); switchToFactorial(ctx);
} else { } else {
// Unknown protocol; discard everything and close the connection. // Unknown protocol; discard everything and close the connection.
buffer.clear(); in.clear();
ctx.close(); ctx.close();
return; return;
} }
// Forward the current read buffer as is to the new handlers. // Forward the current read buffer as is to the new handlers.
ctx.nextInboundByteBuffer().writeBytes(buffer); ctx.nextInboundByteBuffer().writeBytes(in);
ctx.fireInboundBufferUpdated(); ctx.fireInboundBufferUpdated();
} }

View File

@ -34,8 +34,7 @@ public class HexDumpProxyBackendHandler extends ChannelInboundByteHandlerAdapter
} }
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx, ChannelBuffer in) throws Exception {
ChannelBuffer in = ctx.inboundByteBuffer();
ChannelBuffer out = inboundChannel.outboundByteBuffer(); ChannelBuffer out = inboundChannel.outboundByteBuffer();
out.discardReadBytes(); out.discardReadBytes();
out.writeBytes(in); out.writeBytes(in);

View File

@ -66,8 +66,7 @@ public class HexDumpProxyFrontendHandler extends ChannelInboundByteHandlerAdapte
} }
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx, ChannelBuffer in) throws Exception {
ChannelBuffer in = ctx.inboundByteBuffer();
ChannelBuffer out = outboundChannel.outboundByteBuffer(); ChannelBuffer out = outboundChannel.outboundByteBuffer();
out.discardReadBytes(); out.discardReadBytes();
out.writeBytes(in); out.writeBytes(in);

View File

@ -218,4 +218,10 @@ public class BlockingReadHandler<E> extends ChannelInboundMessageHandlerAdapter<
queue.add(e); queue.add(e);
} }
} }
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
// TODO Auto-generated method stub
}
} }

View File

@ -144,11 +144,8 @@ public class ChunkedWriteHandlerTest {
@Override @Override
public void flush(ChannelHandlerContext ctx, ChannelFuture future) throws Exception { public void flush(ChannelHandlerContext ctx, ChannelFuture future) throws Exception {
super.flush(ctx, future);
future.setSuccess(); future.setSuccess();
} }
}; };
EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new ChunkedWriteHandler(), testHandler); EmbeddedMessageChannel ch = new EmbeddedMessageChannel(new ChunkedWriteHandler(), testHandler);

View File

@ -22,8 +22,8 @@ import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBuffers; import io.netty.buffer.ChannelBuffers;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelInboundByteHandlerAdapter; import io.netty.channel.ChannelInboundByteHandlerAdapter;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.spdy.SpdyConstants; import io.netty.handler.codec.spdy.SpdyConstants;
@ -255,10 +255,9 @@ public class SocketSpdyEchoTest extends AbstractSocketTest {
} }
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx, ChannelBuffer in) throws Exception {
ChannelBuffer m = ctx.inboundByteBuffer(); byte[] actual = new byte[in.readableBytes()];
byte[] actual = new byte[m.readableBytes()]; in.readBytes(actual);
m.readBytes(actual);
int lastIdx = counter; int lastIdx = counter;
for (int i = 0; i < actual.length; i ++) { for (int i = 0; i < actual.length; i ++) {

View File

@ -16,12 +16,14 @@
package io.netty.bootstrap; package io.netty.bootstrap;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelBufferHolder;
import io.netty.channel.ChannelBufferHolders;
import io.netty.channel.ChannelException; import io.netty.channel.ChannelException;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
@ -228,7 +230,11 @@ public class ServerBootstrap {
validate(); validate();
} }
private class Acceptor extends ChannelInboundMessageHandlerAdapter<Channel> { private class Acceptor extends ChannelInboundHandlerAdapter<Channel> {
@Override
public ChannelBufferHolder<Channel> newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
return ChannelBufferHolders.messageBuffer();
}
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) { public void inboundBufferUpdated(ChannelHandlerContext ctx) {

View File

@ -15,10 +15,7 @@
*/ */
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ChannelBuffer;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.Queue;
public class ChannelHandlerAdapter extends ChannelStateHandlerAdapter implements ChannelOperationHandler { public class ChannelHandlerAdapter extends ChannelStateHandlerAdapter implements ChannelOperationHandler {
@ -51,27 +48,11 @@ public class ChannelHandlerAdapter extends ChannelStateHandlerAdapter implements
@Override @Override
public void flush(ChannelHandlerContext ctx, ChannelFuture future) throws Exception { public void flush(ChannelHandlerContext ctx, ChannelFuture future) throws Exception {
flush0(ctx, future); if (this instanceof ChannelOutboundHandler) {
throw new IllegalStateException(
"flush(...) must be overridden by " + getClass().getName() +
", which implements " + ChannelOutboundHandler.class.getSimpleName());
} }
static <O> void flush0(ChannelHandlerContext ctx, ChannelFuture future) {
if (ctx.hasOutboundMessageBuffer()) {
Queue<O> out = ctx.outboundMessageBuffer();
Queue<Object> nextOut = ctx.nextOutboundMessageBuffer();
for (;;) {
O msg = out.poll();
if (msg == null) {
break;
}
nextOut.add(msg);
}
} else if (ctx.hasOutboundByteBuffer()) {
ChannelBuffer out = ctx.outboundByteBuffer();
ChannelBuffer nextOut = ctx.nextOutboundByteBuffer();
nextOut.writeBytes(out);
out.discardReadBytes();
}
ctx.flush(future); ctx.flush(future);
} }
} }

View File

@ -18,7 +18,7 @@ package io.netty.channel;
import io.netty.buffer.ChannelBuffer; import io.netty.buffer.ChannelBuffer;
public class ChannelInboundByteHandlerAdapter extends ChannelInboundHandlerAdapter<Byte> { public abstract class ChannelInboundByteHandlerAdapter extends ChannelInboundHandlerAdapter<Byte> {
@Override @Override
public ChannelBufferHolder<Byte> newInboundBuffer(ChannelHandlerContext ctx) throws Exception { public ChannelBufferHolder<Byte> newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
@ -26,12 +26,16 @@ public class ChannelInboundByteHandlerAdapter extends ChannelInboundHandlerAdapt
} }
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public final void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
inboundBufferUpdated(ctx, ctx.inboundByteBuffer()); ChannelBuffer in = ctx.inboundByteBuffer();
} try {
inboundBufferUpdated(ctx, in);
public void inboundBufferUpdated(ChannelHandlerContext ctx, ChannelBuffer in) throws Exception { } finally {
ctx.nextInboundByteBuffer().writeBytes(in); if (!in.readable()) {
in.discardReadBytes(); in.discardReadBytes();
} }
}
}
public abstract void inboundBufferUpdated(ChannelHandlerContext ctx, ChannelBuffer in) throws Exception;
} }

View File

@ -18,5 +18,6 @@ package io.netty.channel;
public abstract class ChannelInboundHandlerAdapter<I> extends ChannelStateHandlerAdapter public abstract class ChannelInboundHandlerAdapter<I> extends ChannelStateHandlerAdapter
implements ChannelInboundHandler<I> { implements ChannelInboundHandler<I> {
// Useful when you have to create an anonymous class @Override
public abstract void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception;
} }

View File

@ -17,7 +17,7 @@ package io.netty.channel;
import java.util.Queue; import java.util.Queue;
public class ChannelInboundMessageHandlerAdapter<I> extends ChannelInboundHandlerAdapter<I> { public abstract class ChannelInboundMessageHandlerAdapter<I> extends ChannelInboundHandlerAdapter<I> {
@Override @Override
public ChannelBufferHolder<I> newInboundBuffer(ChannelHandlerContext ctx) throws Exception { public ChannelBufferHolder<I> newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
@ -25,7 +25,7 @@ public class ChannelInboundMessageHandlerAdapter<I> extends ChannelInboundHandle
} }
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public final void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
Queue<I> in = ctx.inboundMessageBuffer(); Queue<I> in = ctx.inboundMessageBuffer();
for (;;) { for (;;) {
I msg = in.poll(); I msg = in.poll();
@ -34,14 +34,11 @@ public class ChannelInboundMessageHandlerAdapter<I> extends ChannelInboundHandle
} }
try { try {
messageReceived(ctx, msg); messageReceived(ctx, msg);
ctx.fireInboundBufferUpdated();
} catch (Throwable t) { } catch (Throwable t) {
ctx.fireExceptionCaught(t); ctx.fireExceptionCaught(t);
} }
} }
} }
public void messageReceived(ChannelHandlerContext ctx, I msg) throws Exception { public abstract void messageReceived(ChannelHandlerContext ctx, I msg) throws Exception;
ctx.nextInboundMessageBuffer().add(msg);
}
} }

View File

@ -84,6 +84,11 @@ public class ChannelOperationHandlerAdapter implements ChannelOperationHandler {
@Override @Override
public void flush(ChannelHandlerContext ctx, ChannelFuture future) public void flush(ChannelHandlerContext ctx, ChannelFuture future)
throws Exception { throws Exception {
ChannelHandlerAdapter.flush0(ctx, future); if (this instanceof ChannelOutboundHandler) {
throw new IllegalStateException(
"flush(...) must be overridden by " + getClass().getName() +
", which implements " + ChannelOutboundHandler.class.getSimpleName());
}
ctx.flush(future);
} }
} }

View File

@ -15,7 +15,7 @@
*/ */
package io.netty.channel; package io.netty.channel;
public class ChannelOutboundByteHandlerAdapter extends ChannelOutboundHandlerAdapter<Byte> { public abstract class ChannelOutboundByteHandlerAdapter extends ChannelOutboundHandlerAdapter<Byte> {
@Override @Override
public ChannelBufferHolder<Byte> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public ChannelBufferHolder<Byte> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return ChannelBufferHolders.byteBuffer(); return ChannelBufferHolders.byteBuffer();

View File

@ -15,8 +15,8 @@
*/ */
package io.netty.channel; package io.netty.channel;
public abstract class ChannelOutboundHandlerAdapter<O> public abstract class ChannelOutboundHandlerAdapter<O>
extends ChannelOperationHandlerAdapter implements ChannelOutboundHandler<O> { extends ChannelOperationHandlerAdapter implements ChannelOutboundHandler<O> {
// Useful when you have to create an anonymous class @Override
public abstract void flush(ChannelHandlerContext ctx, ChannelFuture future) throws Exception;
} }

View File

@ -16,7 +16,7 @@
package io.netty.channel; package io.netty.channel;
public class ChannelOutboundMessageHandlerAdapter<I> extends ChannelOutboundHandlerAdapter<I> { public abstract class ChannelOutboundMessageHandlerAdapter<I> extends ChannelOutboundHandlerAdapter<I> {
@Override @Override
public ChannelBufferHolder<I> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { public ChannelBufferHolder<I> newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
return ChannelBufferHolders.messageBuffer(); return ChannelBufferHolders.messageBuffer();

View File

@ -15,9 +15,6 @@
*/ */
package io.netty.channel; package io.netty.channel;
import io.netty.buffer.ChannelBuffer;
import java.util.Queue;
public class ChannelStateHandlerAdapter implements ChannelStateHandler { public class ChannelStateHandlerAdapter implements ChannelStateHandler {
@ -82,28 +79,11 @@ public class ChannelStateHandlerAdapter implements ChannelStateHandler {
@Override @Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
inboundBufferUpdated0(ctx); if (this instanceof ChannelInboundHandler) {
throw new IllegalStateException(
"inboundBufferUpdated(...) must be overridden by " + getClass().getName() +
", which implements " + ChannelInboundHandler.class.getSimpleName());
} }
static <I> void inboundBufferUpdated0(ChannelHandlerContext ctx) {
if (ctx.hasInboundMessageBuffer()) {
Queue<I> in = ctx.inboundMessageBuffer();
Queue<Object> nextIn = ctx.nextInboundMessageBuffer();
for (;;) {
I msg = in.poll();
if (msg == null) {
break;
}
nextIn.add(msg);
}
} else if (ctx.hasInboundByteBuffer()) {
ChannelBuffer in = ctx.inboundByteBuffer();
ChannelBuffer nextIn = ctx.nextInboundByteBuffer();
nextIn.writeBytes(in);
in.discardReadBytes();
}
ctx.fireInboundBufferUpdated(); ctx.fireInboundBufferUpdated();
} }
} }