[#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,16 +169,26 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerCh
|
|||||||
p.addLast(new ChannelInitializer<Channel>() {
|
p.addLast(new ChannelInitializer<Channel>() {
|
||||||
@Override
|
@Override
|
||||||
public void initChannel(Channel ch) throws Exception {
|
public void initChannel(Channel ch) throws Exception {
|
||||||
ChannelPipeline pipeline = ch.pipeline();
|
final ChannelPipeline pipeline = ch.pipeline();
|
||||||
ChannelHandler handler = config.handler();
|
ChannelHandler handler = config.handler();
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
pipeline.addLast(handler);
|
pipeline.addLast(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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(
|
pipeline.addLast(new ServerBootstrapAcceptor(
|
||||||
currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
|
currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServerBootstrap validate() {
|
public ServerBootstrap validate() {
|
||||||
|
@ -15,13 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.bootstrap;
|
package io.netty.bootstrap;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerAdapter;
|
import io.netty.channel.ChannelHandlerAdapter;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
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.LocalEventLoopGroup;
|
||||||
import io.netty.channel.local.LocalServerChannel;
|
import io.netty.channel.local.LocalServerChannel;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@ -59,4 +67,74 @@ public class ServerBootstrapTest {
|
|||||||
group.shutdownGracefully();
|
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