[#5566] Ensure using a ChannelInitializer via ServerBootstrap.handler(...) produce correct ordering.
Motivation: When a ChannelInitializer is used via ServerBootstrap.handler(...) the users handlers may be added after the internal ServerBootstrapAcceptor. This should not happen. Modifications: Delay the adding of the ServerBootstrapAcceptor until the initChannel(....) method returns. Result: Correct order of handlers in the ServerChannels ChannelPipeline.
This commit is contained in:
parent
445a547265
commit
4638df2062
@ -169,13 +169,23 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerCh
|
||||
p.addLast(new ChannelInitializer<Channel>() {
|
||||
@Override
|
||||
public void initChannel(Channel ch) throws Exception {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
final ChannelPipeline pipeline = ch.pipeline();
|
||||
ChannelHandler handler = config.handler();
|
||||
if (handler != null) {
|
||||
pipeline.addLast(handler);
|
||||
}
|
||||
pipeline.addLast(new ServerBootstrapAcceptor(
|
||||
currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
|
||||
|
||||
// We add this handler via the EventLoop as the user may have used a ChannelInitializer as handler.
|
||||
// In this case the initChannel(...) method will only be called after this method returns. Because
|
||||
// of this we need to ensure we add our handler in a delayed fashion so all the users handler are
|
||||
// placed in front of the ServerBootstrapAcceptor.
|
||||
ch.eventLoop().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
pipeline.addLast(new ServerBootstrapAcceptor(
|
||||
currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -15,13 +15,21 @@
|
||||
*/
|
||||
package io.netty.bootstrap;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.DefaultEventLoopGroup;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.local.LocalAddress;
|
||||
import io.netty.channel.local.LocalChannel;
|
||||
import io.netty.channel.local.LocalEventLoopGroup;
|
||||
import io.netty.channel.local.LocalServerChannel;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@ -59,4 +67,74 @@ public class ServerBootstrapTest {
|
||||
group.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 3000)
|
||||
public void testParentHandler() throws Exception {
|
||||
testParentHandler(false);
|
||||
}
|
||||
|
||||
@Test(timeout = 3000)
|
||||
public void testParentHandlerViaChannelInitializer() throws Exception {
|
||||
testParentHandler(true);
|
||||
}
|
||||
|
||||
private static void testParentHandler(boolean channelInitializer) throws Exception {
|
||||
final LocalAddress addr = new LocalAddress(UUID.randomUUID().toString());
|
||||
final CountDownLatch readLatch = new CountDownLatch(1);
|
||||
final CountDownLatch initLatch = new CountDownLatch(1);
|
||||
|
||||
final ChannelHandler handler = new ChannelInboundHandlerAdapter() {
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||
initLatch.countDown();
|
||||
super.handlerAdded(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
readLatch.countDown();
|
||||
super.channelRead(ctx, msg);
|
||||
}
|
||||
};
|
||||
|
||||
EventLoopGroup group = new DefaultEventLoopGroup(1);
|
||||
Channel sch = null;
|
||||
Channel cch = null;
|
||||
try {
|
||||
ServerBootstrap sb = new ServerBootstrap();
|
||||
sb.channel(LocalServerChannel.class)
|
||||
.group(group)
|
||||
.childHandler(new ChannelInboundHandlerAdapter());
|
||||
if (channelInitializer) {
|
||||
sb.handler(new ChannelInitializer<Channel>() {
|
||||
@Override
|
||||
protected void initChannel(Channel ch) throws Exception {
|
||||
ch.pipeline().addLast(handler);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
sb.handler(handler);
|
||||
}
|
||||
|
||||
Bootstrap cb = new Bootstrap();
|
||||
cb.group(group)
|
||||
.channel(LocalChannel.class)
|
||||
.handler(new ChannelInboundHandlerAdapter());
|
||||
|
||||
sch = sb.bind(addr).syncUninterruptibly().channel();
|
||||
|
||||
cch = cb.connect(addr).syncUninterruptibly().channel();
|
||||
|
||||
initLatch.await();
|
||||
readLatch.await();
|
||||
} finally {
|
||||
if (sch != null) {
|
||||
sch.close().syncUninterruptibly();
|
||||
}
|
||||
if (cch != null) {
|
||||
cch.close().syncUninterruptibly();
|
||||
}
|
||||
group.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user