Add ChannelHandlerContext.isRemoved() to easily detect the removal of a ChannelHandler while in a method.

This commit is contained in:
Norman Maurer 2013-06-10 11:14:41 +02:00
parent 9449efb9b2
commit 3be25694d0
8 changed files with 24 additions and 9 deletions

View File

@ -45,7 +45,6 @@ public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter
private volatile boolean singleDecode;
private boolean decodeWasNull;
private MessageList<Object> out;
private boolean removed;
/**
* If set then only one message is decoded on each {@link #messageReceived(ChannelHandlerContext, MessageList)}
@ -92,7 +91,6 @@ public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter
@Override
public final void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
removed = true;
ByteBuf buf = internalBuffer();
if (buf.isReadable()) {
if (out == null) {
@ -119,7 +117,7 @@ public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter
for (int i = 0; i < size; i ++) {
Object m = msgs.get(i);
// handler was removed in the loop
if (removed) {
if (ctx.isRemoved()) {
out.add(m);
continue;
}
@ -165,12 +163,11 @@ public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter
throw new DecoderException(t);
} finally {
// release the cumulation if the handler was removed while messages are processed
if (removed) {
if (ctx.isRemoved()) {
if (cumulation != null) {
cumulation.release();
cumulation = null;
}
removed = false;
}
MessageList<Object> out = this.out;
this.out = null;

View File

@ -66,7 +66,7 @@ public abstract class MessageToByteEncoder<I> extends ChannelOutboundHandlerAdap
int size = msgs.size();
for (int i = 0; i < size; i ++) {
Object m = msgs.get(i);
if (acceptOutboundMessage(m)) {
if (!ctx.isRemoved() && acceptOutboundMessage(m)) {
@SuppressWarnings("unchecked")
I cast = (I) m;
if (buf == null) {

View File

@ -63,7 +63,7 @@ public abstract class MessageToMessageDecoder<I> extends ChannelInboundHandlerAd
int size = msgs.size();
for (int i = 0; i < size; i ++) {
Object m = msgs.get(i);
if (acceptInboundMessage(m)) {
if (!ctx.isRemoved() && acceptInboundMessage(m)) {
@SuppressWarnings("unchecked")
I cast = (I) m;
try {

View File

@ -64,7 +64,7 @@ public abstract class MessageToMessageEncoder<I> extends ChannelOutboundHandlerA
int size = msgs.size();
for (int i = 0; i < size; i ++) {
Object m = msgs.get(i);
if (acceptOutboundMessage(m)) {
if (!ctx.isRemoved() && acceptOutboundMessage(m)) {
@SuppressWarnings("unchecked")
I cast = (I) m;
try {

View File

@ -150,6 +150,13 @@ public interface ChannelHandlerContext
*/
ChannelHandler handler();
/**
* Return {@code true} if the {@link ChannelHandler} which belongs to this {@link ChannelHandler} was removed
* from the {@link ChannelPipeline}. Note that this method is only meant to be called from with in the
* {@link EventLoop}.
*/
boolean isRemoved();
@Override
ChannelHandlerContext fireChannelRegistered();

View File

@ -33,6 +33,7 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
private final DefaultChannelPipeline pipeline;
private final String name;
private final ChannelHandler handler;
private boolean removed;
// Will be set to null if no child executor should be used, otherwise it will be set to the
// child executor.
@ -828,4 +829,13 @@ final class DefaultChannelHandlerContext extends DefaultAttributeMap implements
public ChannelPromise voidPromise() {
return channel.voidPromise();
}
void setRemoved() {
removed = true;
}
@Override
public boolean isRemoved() {
return removed;
}
}

View File

@ -522,6 +522,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
// Notify the complete removal.
try {
ctx.handler().handlerRemoved(ctx);
ctx.setRemoved();
} catch (Throwable t) {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));

View File

@ -58,7 +58,7 @@ public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandl
try {
for (int i = 0; i < size; i++) {
Object msg = msgs.get(i);
if (acceptInboundMessage(msg)) {
if (!ctx.isRemoved() && acceptInboundMessage(msg)) {
if (!unaccepted.isEmpty()) {
ctx.fireMessageReceived(unaccepted);
unaccepted = MessageList.newInstance();