Merge pull request #594 from netty/bootstrap_refactor

Bootstrap refactor
This commit is contained in:
Norman Maurer 2012-09-13 01:20:09 -07:00
commit ded98ddaf9
41 changed files with 449 additions and 289 deletions

View File

@ -39,7 +39,7 @@ public class DiscardClient {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.remoteAddress(host, port)
.handler(new DiscardClientHandler(firstMessageSize));

View File

@ -37,7 +37,7 @@ public class DiscardServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override

View File

@ -50,7 +50,7 @@ public class EchoClient {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {

View File

@ -43,7 +43,7 @@ public class EchoServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.localAddress(new InetSocketAddress(port))
.childOption(ChannelOption.TCP_NODELAY, true)

View File

@ -40,7 +40,7 @@ public class FactorialClient {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.remoteAddress(host, port)
.handler(new FactorialClientInitializer(count));

View File

@ -35,7 +35,7 @@ public class FactorialServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new FactorialServerInitializer());

View File

@ -31,7 +31,7 @@ public class HttpStaticFileServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new HttpStaticFileServerInitializer());

View File

@ -65,7 +65,7 @@ public class HttpSnoopClient {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.handler(new HttpSnoopClientInitializer(ssl))
.remoteAddress(new InetSocketAddress(host, port));

View File

@ -40,7 +40,7 @@ public class HttpSnoopServer {
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.childHandler(new HttpSnoopServerInitializer())
.localAddress(new InetSocketAddress(port));

View File

@ -36,7 +36,7 @@ public class AutobahnServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new AutobahnServerInitializer());

View File

@ -84,7 +84,7 @@ public class WebSocketClient {
uri, WebSocketVersion.V13, null, false, customHeaders);
b.group(new NioEventLoopGroup())
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.remoteAddress(uri.getHost(), uri.getPort())
.handler(new ChannelInitializer<SocketChannel>() {
@Override

View File

@ -51,7 +51,7 @@ public class WebSocketServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new WebSocketServerInitializer());

View File

@ -50,7 +50,7 @@ public class WebSocketSslServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new WebSocketSslServerInitializer());

View File

@ -50,7 +50,7 @@ public class LocalEcho {
// are handled by the same event loop thread which drives a certain socket channel
// to reduce the communication latency between socket channels and local channels.
sb.group(new LocalEventLoopGroup())
.channel(new LocalServerChannel())
.channel(LocalServerChannel.class)
.localAddress(addr)
.handler(new ChannelInitializer<LocalServerChannel>() {
@Override
@ -68,7 +68,7 @@ public class LocalEcho {
});
cb.group(new NioEventLoopGroup()) // NIO event loops are also OK
.channel(new LocalChannel())
.channel(LocalChannel.class)
.remoteAddress(addr)
.handler(new ChannelInitializer<LocalChannel>() {
@Override

View File

@ -46,7 +46,7 @@ public class LocalTimeClient {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.remoteAddress(host, port)
.handler(new LocalTimeClientInitializer());

View File

@ -35,7 +35,7 @@ public class LocalTimeServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new LocalTimeServerInitializer());

View File

@ -44,7 +44,7 @@ public class ObjectEchoClient {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.remoteAddress(host, port)
.handler(new ChannelInitializer<SocketChannel>() {
@Override

View File

@ -40,7 +40,7 @@ public class ObjectEchoServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override

View File

@ -40,7 +40,7 @@ public class PortUnificationServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override

View File

@ -40,7 +40,7 @@ public class HexDumpProxy {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(localPort)
.childHandler(new HexDumpProxyInitializer(remoteHost, remotePort));

View File

@ -45,7 +45,7 @@ public class HexDumpProxyFrontendHandler extends ChannelInboundByteHandlerAdapte
// Start the connection attempt.
Bootstrap b = new Bootstrap();
b.group(inboundChannel.eventLoop())
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.remoteAddress(remoteHost, remotePort)
.handler(new HexDumpProxyBackendHandler(inboundChannel));

View File

@ -44,7 +44,7 @@ public class QuoteOfTheMomentClient {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioDatagramChannel())
.channel(NioDatagramChannel.class)
.localAddress(new InetSocketAddress(0))
.option(ChannelOption.SO_BROADCAST, true)
.handler(new QuoteOfTheMomentClientHandler());

View File

@ -40,7 +40,7 @@ public class QuoteOfTheMomentServer {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioDatagramChannel())
.channel(NioDatagramChannel.class)
.localAddress(new InetSocketAddress(port))
.option(ChannelOption.SO_BROADCAST, true)
.handler(new QuoteOfTheMomentServerHandler());

View File

@ -15,6 +15,7 @@
*/
package io.netty.example.sctp;
import io.netty.bootstrap.AbstractBootstrap;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
@ -54,7 +55,7 @@ public class SctpEchoClient {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioSctpChannel())
.channel(NioSctpChannel.class)
.option(ChannelOption.SCTP_NODELAY, true)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SctpChannel>() {

View File

@ -45,7 +45,7 @@ public class SctpEchoServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioSctpServerChannel())
.channel(NioSctpServerChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.localAddress(new InetSocketAddress(port))
.childOption(ChannelOption.SCTP_NODELAY, true)

View File

@ -42,7 +42,7 @@ public class SecureChatClient {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.remoteAddress(host, port)
.handler(new SecureChatClientInitializer());

View File

@ -35,7 +35,7 @@ public class SecureChatServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new SecureChatServerInitializer());

View File

@ -41,7 +41,7 @@ public class TelnetClient {
Bootstrap b = new Bootstrap();
try {
b.group(new NioEventLoopGroup())
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.remoteAddress(host, port)
.handler(new TelnetClientInitializer());

View File

@ -34,7 +34,7 @@ public class TelnetServer {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(new NioServerSocketChannel())
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new TelnetServerPipelineFactory());

View File

@ -59,7 +59,7 @@ public class UptimeClient {
Bootstrap configureBootstrap(Bootstrap b, EventLoopGroup g) {
b.group(g)
.channel(new NioSocketChannel())
.channel(NioSocketChannel.class)
.remoteAddress(host, port)
.handler(new ChannelInitializer<SocketChannel>() {
@Override

View File

@ -15,6 +15,7 @@
*/
package io.netty.testsuite.transport.socket;
import io.netty.bootstrap.AbstractBootstrap;
import io.netty.bootstrap.Bootstrap;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
@ -59,7 +60,7 @@ public abstract class AbstractDatagramTest {
"Running: %s %d of %d", testName.getMethodName(), ++ i, COMBO.size()));
try {
Method m = getClass().getDeclaredMethod(
testName.getMethodName(), Bootstrap.class, Bootstrap.class);
testName.getMethodName(), AbstractBootstrap.class, AbstractBootstrap.class);
m.invoke(this, sb, cb);
} catch (InvocationTargetException ex) {
throw ex.getCause();

View File

@ -16,7 +16,7 @@
package io.netty.testsuite.transport.socket;
import static org.junit.Assert.*;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.AbstractBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
@ -40,7 +40,7 @@ public class DatagramMulticastTest extends AbstractDatagramTest {
run();
}
public void testMulticast(Bootstrap sb, Bootstrap cb) throws Throwable {
public void testMulticast(AbstractBootstrap sb, AbstractBootstrap cb) throws Throwable {
MulticastTestHandler mhandler = new MulticastTestHandler();
sb.handler(new ChannelInboundMessageHandlerAdapter<DatagramPacket>() {

View File

@ -16,7 +16,7 @@
package io.netty.testsuite.transport.socket;
import static org.junit.Assert.*;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.AbstractBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
@ -36,7 +36,7 @@ public class DatagramUnicastTest extends AbstractDatagramTest {
run();
}
public void testSimpleSend(Bootstrap sb, Bootstrap cb) throws Throwable {
public void testSimpleSend(AbstractBootstrap sb, AbstractBootstrap cb) throws Throwable {
final CountDownLatch latch = new CountDownLatch(1);
sb.handler(new ChannelInboundMessageHandlerAdapter<DatagramPacket>() {

View File

@ -15,8 +15,10 @@
*/
package io.netty.testsuite.transport.socket;
import io.netty.bootstrap.AbstractBootstrap.ChannelFactory;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.socket.aio.AioEventLoopGroup;
import io.netty.channel.socket.aio.AioServerSocketChannel;
@ -86,14 +88,18 @@ final class SocketTestPermutation {
bfs.add(new Factory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(new NioEventLoopGroup()).channel(
new NioDatagramChannel(InternetProtocolFamily.IPv4));
return new Bootstrap().group(new NioEventLoopGroup()).channelFactory(new ChannelFactory() {
@Override
public Channel newChannel() {
return new NioDatagramChannel(InternetProtocolFamily.IPv4);
}
});
}
});
bfs.add(new Factory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(new OioEventLoopGroup()).channel(new OioDatagramChannel());
return new Bootstrap().group(new OioEventLoopGroup()).channel(OioDatagramChannel.class);
}
});
@ -133,17 +139,21 @@ final class SocketTestPermutation {
public ServerBootstrap newInstance() {
return new ServerBootstrap().
group(new NioEventLoopGroup(), new NioEventLoopGroup()).
channel(new NioServerSocketChannel());
channel(NioServerSocketChannel.class);
}
});
list.add(new Factory<ServerBootstrap>() {
@Override
public ServerBootstrap newInstance() {
AioEventLoopGroup parentGroup = new AioEventLoopGroup();
AioEventLoopGroup childGroup = new AioEventLoopGroup();
return new ServerBootstrap().
group(parentGroup, childGroup).
channel(new AioServerSocketChannel(parentGroup, childGroup));
final AioEventLoopGroup parentGroup = new AioEventLoopGroup();
final AioEventLoopGroup childGroup = new AioEventLoopGroup();
return new ServerBootstrap().group(parentGroup, childGroup).channelFactory(new ChannelFactory() {
@Override
public Channel newChannel() {
return new AioServerSocketChannel(parentGroup, childGroup);
}
});
}
});
list.add(new Factory<ServerBootstrap>() {
@ -151,7 +161,7 @@ final class SocketTestPermutation {
public ServerBootstrap newInstance() {
return new ServerBootstrap().
group(new OioEventLoopGroup(), new OioEventLoopGroup()).
channel(new OioServerSocketChannel());
channel(OioServerSocketChannel.class);
}
});
@ -163,20 +173,25 @@ final class SocketTestPermutation {
list.add(new Factory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(new NioEventLoopGroup()).channel(new NioSocketChannel());
return new Bootstrap().group(new NioEventLoopGroup()).channel(NioSocketChannel.class);
}
});
list.add(new Factory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
AioEventLoopGroup loop = new AioEventLoopGroup();
return new Bootstrap().group(loop).channel(new AioSocketChannel(loop));
final AioEventLoopGroup loop = new AioEventLoopGroup();
return new Bootstrap().group(loop).channelFactory(new ChannelFactory() {
@Override
public Channel newChannel() {
return new AioSocketChannel(loop);
}
});
}
});
list.add(new Factory<Bootstrap>() {
@Override
public Bootstrap newInstance() {
return new Bootstrap().group(new OioEventLoopGroup()).channel(new OioSocketChannel());
return new Bootstrap().group(new OioEventLoopGroup()).channel(OioSocketChannel.class);
}
});
return list;

View File

@ -0,0 +1,256 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.bootstrap;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.LinkedHashMap;
import java.util.Map;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelException;
/**
* {@link AbstractBootstrap} is a helper class that makes it easy to bootstrap a {@link Channel}. It support
* method-chaining to provide an easy way to configure the {@link AbstractBootstrap}.
*
*/
public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> {
private EventLoopGroup group;
private ChannelFactory factory;
private SocketAddress localAddress;
private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
private ChannelHandler handler;
/**
* The {@link EventLoopGroup} which is used to handle all the events for the to-be-creates
* {@link Channel}
*/
@SuppressWarnings("unchecked")
public B group(EventLoopGroup group) {
if (group == null) {
throw new NullPointerException("group");
}
if (this.group != null) {
throw new IllegalStateException("group set already");
}
this.group = group;
return (B) this;
}
/**
* The {@link Class} which is used to create {@link Channel} instances from.
* You either use this or {@link #channelFactory(ChannelFactory)} if your
* {@link Channel} implementation has no no-args constructor.
*/
public B channel(Class<? extends Channel> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new BootstrapChannelFactory(channelClass));
}
/**
* {@link ChannelFactory} which is used to create {@link Channel} instances from
* when calling {@link #bind()}. This method is usually only used if {@link #channel(Class)}
* is not working for you because of some more complex needs. If your {@link Channel} implementation
* has a no-args constructor, its highly recommend to just use {@link #channel(Class)} for
* simplify your code.
*/
@SuppressWarnings("unchecked")
public B channelFactory(ChannelFactory factory) {
if (factory == null) {
throw new NullPointerException("factory");
}
if (this.factory != null) {
throw new IllegalStateException("factory set already");
}
this.factory = factory;
return (B) this;
}
/**
* The {@link SocketAddress} which is used to bind the local "end" to.
*
*/
@SuppressWarnings("unchecked")
public B localAddress(SocketAddress localAddress) {
this.localAddress = localAddress;
return (B) this;
}
/**
* See {@link #localAddress(SocketAddress)}
*/
public B localAddress(int port) {
return localAddress(new InetSocketAddress(port));
}
/**
* See {@link #localAddress(SocketAddress)}
*/
public B localAddress(String host, int port) {
return localAddress(new InetSocketAddress(host, port));
}
/**
* See {@link #localAddress(SocketAddress)}
*/
public B localAddress(InetAddress host, int port) {
return localAddress(new InetSocketAddress(host, port));
}
/**
* Allow to specify a {@link ChannelOption} which is used for the {@link Channel} instances once they got
* created. Use a value of <code>null</code> to remove a previous set {@link ChannelOption}.
*/
@SuppressWarnings("unchecked")
public <T> B option(ChannelOption<T> option, T value) {
if (option == null) {
throw new NullPointerException("option");
}
if (value == null) {
options.remove(option);
} else {
options.put(option, value);
}
return (B) this;
}
/**
* Shutdown the {@link AbstractBootstrap} and the {@link EventLoopGroup} which is
* used by it. Only call this if you don't share the {@link EventLoopGroup}
* between different {@link AbstractBootstrap}'s.
*/
public void shutdown() {
if (group != null) {
group.shutdown();
}
}
/**
* Validate all the parameters. Sub-classes may override this, but should
* call the super method in that case.
*/
protected void validate() {
if (group == null) {
throw new IllegalStateException("group not set");
}
if (factory == null) {
throw new IllegalStateException("factory not set");
}
}
protected final void validate(ChannelFuture future) {
if (future == null) {
throw new NullPointerException("future");
}
validate();
}
/**
* Create a new {@link Channel} and bind it.
*/
public ChannelFuture bind() {
validate();
Channel channel = factory().newChannel();
return bind(channel.newFuture());
}
/**
* the {@link ChannelHandler} to use for serving the requests.
*/
@SuppressWarnings("unchecked")
public B handler(ChannelHandler handler) {
if (handler == null) {
throw new NullPointerException("handler");
}
this.handler = handler;
return (B) this;
}
protected static boolean ensureOpen(ChannelFuture future) {
if (!future.channel().isOpen()) {
// Registration was successful but the channel was closed due to some failure in
// handler.
future.setFailure(new ChannelException("initialization failure"));
return false;
}
return true;
}
/**
* Bind the {@link Channel} of the given {@link ChannelFactory}.
*/
public abstract ChannelFuture bind(ChannelFuture future);
protected final SocketAddress localAddress() {
return localAddress;
}
protected final ChannelFactory factory() {
return factory;
}
protected final ChannelHandler handler() {
return handler;
}
protected final EventLoopGroup group() {
return group;
}
protected final Map<ChannelOption<?>, Object> options() {
return options;
}
private final class BootstrapChannelFactory implements ChannelFactory {
private final Class<? extends Channel> clazz;
BootstrapChannelFactory(Class<? extends Channel> clazz) {
this.clazz = clazz;
}
@Override
public Channel newChannel() {
try {
return clazz.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + clazz, t);
}
}
}
/**
* Factory that is responsible to create new {@link Channel}'s on {@link AbstractBootstrap#bind()}
* requests.
*
*/
public interface ChannelFactory {
/**
* {@link Channel} to use in the {@link AbstractBootstrap}
*/
Channel newChannel();
}
}

View File

@ -16,13 +16,11 @@
package io.netty.bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
@ -30,111 +28,53 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.ClosedChannelException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
public class Bootstrap {
/**
* A {@link Bootstrap} that makes it easy to bootstrap a {@link Channel} to use
* for clients.
*
*/
public class Bootstrap extends AbstractBootstrap<Bootstrap> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Bootstrap.class);
private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
private EventLoopGroup group;
private Channel channel;
private ChannelHandler handler;
private SocketAddress localAddress;
private SocketAddress remoteAddress;
public Bootstrap group(EventLoopGroup group) {
if (group == null) {
throw new NullPointerException("group");
}
if (this.group != null) {
throw new IllegalStateException("group set already");
}
this.group = group;
return this;
}
public Bootstrap channel(Channel channel) {
if (channel == null) {
throw new NullPointerException("channel");
}
if (this.channel != null) {
throw new IllegalStateException("channel set already");
}
this.channel = channel;
return this;
}
public <T> Bootstrap option(ChannelOption<T> option, T value) {
if (option == null) {
throw new NullPointerException("option");
}
if (value == null) {
options.remove(option);
} else {
options.put(option, value);
}
return this;
}
public Bootstrap handler(ChannelHandler handler) {
if (handler == null) {
throw new NullPointerException("handler");
}
this.handler = handler;
return this;
}
public Bootstrap localAddress(SocketAddress localAddress) {
this.localAddress = localAddress;
return this;
}
public Bootstrap localAddress(int port) {
localAddress = new InetSocketAddress(port);
return this;
}
public Bootstrap localAddress(String host, int port) {
localAddress = new InetSocketAddress(host, port);
return this;
}
public Bootstrap localAddress(InetAddress host, int port) {
localAddress = new InetSocketAddress(host, port);
return this;
}
/**
* The {@link SocketAddress} to connect to once the {@link #connect()} method
* is called.
*/
public Bootstrap remoteAddress(SocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
return this;
}
/**
* See {@link #remoteAddress(SocketAddress)}
*/
public Bootstrap remoteAddress(String host, int port) {
remoteAddress = new InetSocketAddress(host, port);
return this;
}
/**
* See {@link #remoteAddress(SocketAddress)}
*/
public Bootstrap remoteAddress(InetAddress host, int port) {
remoteAddress = new InetSocketAddress(host, port);
return this;
}
public ChannelFuture bind() {
validate();
return bind(channel.newFuture());
}
@Override
public ChannelFuture bind(ChannelFuture future) {
validate(future);
if (localAddress == null) {
if (localAddress() == null) {
throw new IllegalStateException("localAddress not set");
}
try {
init();
init(future.channel());
} catch (Throwable t) {
future.setFailure(t);
return future;
@ -144,14 +84,21 @@ public class Bootstrap {
return future;
}
return channel.bind(localAddress, future).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
return future.channel().bind(localAddress(), future).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
/**
* Connect a {@link Channel} to the remote peer.
*/
public ChannelFuture connect() {
validate();
Channel channel = factory().newChannel();
return connect(channel.newFuture());
}
/**
* See {@link #connect()}
*/
public ChannelFuture connect(ChannelFuture future) {
validate(future);
if (remoteAddress == null) {
@ -159,7 +106,7 @@ public class Bootstrap {
}
try {
init();
init(future.channel());
} catch (Throwable t) {
future.setFailure(t);
return future;
@ -169,15 +116,16 @@ public class Bootstrap {
return future;
}
if (localAddress == null) {
channel.connect(remoteAddress, future);
if (localAddress() == null) {
future.channel().connect(remoteAddress, future);
} else {
channel.connect(remoteAddress, localAddress, future);
future.channel().connect(remoteAddress, localAddress(), future);
}
return future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
private void init() throws Exception {
@SuppressWarnings("unchecked")
private void init(Channel channel) throws Exception {
if (channel.isActive()) {
throw new IllegalStateException("channel already active:: " + channel);
}
@ -189,9 +137,9 @@ public class Bootstrap {
}
ChannelPipeline p = channel.pipeline();
p.addLast(handler);
p.addLast(handler());
for (Entry<ChannelOption<?>, Object> e: options.entrySet()) {
for (Entry<ChannelOption<?>, Object> e: options().entrySet()) {
try {
if (!channel.config().setOption((ChannelOption<Object>) e.getKey(), e.getValue())) {
logger.warn("Unknown channel option: " + e);
@ -201,45 +149,34 @@ public class Bootstrap {
}
}
group.register(channel).syncUninterruptibly();
group().register(channel).syncUninterruptibly();
}
private static boolean ensureOpen(ChannelFuture future) {
if (!future.channel().isOpen()) {
// Registration was successful but the channel was closed due to some failure in
// handler.
future.setFailure(new ChannelException("initialization failure"));
return false;
}
return true;
}
public void shutdown() {
if (group != null) {
group.shutdown();
}
}
private void validate() {
if (group == null) {
throw new IllegalStateException("group not set");
}
if (channel == null) {
throw new IllegalStateException("channel not set");
}
if (handler == null) {
@Override
protected void validate() {
super.validate();
if (handler() == null) {
throw new IllegalStateException("handler not set");
}
}
private void validate(ChannelFuture future) {
if (future == null) {
throw new NullPointerException("future");
}
if (future.channel() != channel) {
throw new IllegalArgumentException("future.channel() must be the same channel.");
}
/**
* Create a new {@link Bootstrap} using this "full-setup" {@link Bootstrap} as template.
* Only the given parameters are replaced, the rest is configured exactly the same way as the template.
*/
public Bootstrap newBootstrap(SocketAddress localAddress, SocketAddress remoteAddress, ChannelHandler handler) {
validate();
Bootstrap cb = new Bootstrap().handler(handler).channelFactory(factory()).group(group())
.localAddress(localAddress).remoteAddress(remoteAddress);
cb.options().putAll(options());
return cb;
}
/**
* Create a new {@link Bootstrap} using this "full-setup" {@link Bootstrap} as template.
* Only the given parameters are replaced, the rest is configured exactly the same way as the template.
*/
public Bootstrap newBootstrap(SocketAddress localAddress, SocketAddress remoteAddress) {
return newBootstrap(localAddress, remoteAddress, handler());
}
}

View File

@ -17,32 +17,35 @@ package io.netty.bootstrap;
import io.netty.buffer.MessageBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInboundMessageHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
import io.netty.util.NetworkConstants;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.ClosedChannelException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
public class ServerBootstrap {
/**
* {@link Bootstrap} sub-class which allows easy bootstrap of {@link ServerChannel}
*
*/
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class);
private static final InetSocketAddress DEFAULT_LOCAL_ADDR = new InetSocketAddress(NetworkConstants.LOCALHOST, 0);
@ -54,62 +57,55 @@ public class ServerBootstrap {
}
};
private final Map<ChannelOption<?>, Object> parentOptions = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
private EventLoopGroup parentGroup;
private EventLoopGroup childGroup;
private ServerChannel channel;
private ChannelHandler handler;
private ChannelHandler childHandler;
private SocketAddress localAddress;
/**
* Specify the {@link EventLoopGroup} which is used for the parent (acceptor) and the child (client).
*/
@Override
public ServerBootstrap group(EventLoopGroup group) {
if (group == null) {
throw new NullPointerException("group");
}
if (parentGroup != null) {
throw new IllegalStateException("parentGroup set already");
}
parentGroup = group;
childGroup = group;
return this;
return group(group, group);
}
/**
* Set the {@link EventLoopGroup} for the parent (acceptor) and the child (client). These
* {@link EventLoopGroup}'s are used to handle all the events and IO for {@link SocketChannel} and
* {@link Channel}'s.
*/
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
if (parentGroup == null) {
throw new NullPointerException("parentGroup");
super.group(parentGroup);
if (childGroup == null) {
throw new NullPointerException("childGroup");
}
if (this.parentGroup != null) {
throw new IllegalStateException("parentGroup set already");
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
}
this.parentGroup = parentGroup;
this.childGroup = childGroup;
return this;
}
public ServerBootstrap channel(ServerChannel channel) {
if (channel == null) {
throw new NullPointerException("channel");
/**
* The {@link Class} which is used to create the {@link ServerChannel} from (for the acceptor).
*/
@Override
public ServerBootstrap channel(Class<? extends Channel> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
if (this.channel != null) {
throw new IllegalStateException("channel set already");
if (!ServerChannel.class.isAssignableFrom(channelClass)) {
throw new IllegalArgumentException();
}
this.channel = channel;
return this;
}
public <T> ServerBootstrap option(ChannelOption<T> parentOption, T value) {
if (parentOption == null) {
throw new NullPointerException("parentOption");
}
if (value == null) {
parentOptions.remove(parentOption);
} else {
parentOptions.put(parentOption, value);
}
return this;
return super.channel(channelClass);
}
/**
* Allow to specify a {@link ChannelOption} which is used for the {@link Channel} instances once they get created
* (after the acceptor accepted the {@link Channel}). Use a value of <code>null</code> to remove a previous set
* {@link ChannelOption}.
*/
public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
if (childOption == null) {
throw new NullPointerException("childOption");
@ -122,11 +118,9 @@ public class ServerBootstrap {
return this;
}
public ServerBootstrap handler(ChannelHandler handler) {
this.handler = handler;
return this;
}
/**
* Set the {@link ChannelHandler} which is used to server the request for the {@link Channel}'s.
*/
public ServerBootstrap childHandler(ChannelHandler childHandler) {
if (childHandler == null) {
throw new NullPointerException("childHandler");
@ -135,36 +129,10 @@ public class ServerBootstrap {
return this;
}
public ServerBootstrap localAddress(SocketAddress localAddress) {
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
this.localAddress = localAddress;
return this;
}
public ServerBootstrap localAddress(int port) {
localAddress = new InetSocketAddress(port);
return this;
}
public ServerBootstrap localAddress(String host, int port) {
localAddress = new InetSocketAddress(host, port);
return this;
}
public ServerBootstrap localAddress(InetAddress host, int port) {
localAddress = new InetSocketAddress(host, port);
return this;
}
public ChannelFuture bind() {
validate();
return bind(channel.newFuture());
}
@Override
public ChannelFuture bind(ChannelFuture future) {
validate(future);
Channel channel = future.channel();
if (channel.isActive()) {
future.setFailure(new IllegalStateException("channel already bound: " + channel));
return future;
@ -179,75 +147,57 @@ public class ServerBootstrap {
}
try {
channel.config().setOptions(parentOptions);
channel.config().setOptions(options());
} catch (Exception e) {
future.setFailure(e);
return future;
}
ChannelPipeline p = channel.pipeline();
ChannelPipeline p = future.channel().pipeline();
if (handler != null) {
p.addLast(handler);
}
p.addLast(acceptor);
ChannelFuture f = parentGroup.register(channel).awaitUninterruptibly();
ChannelFuture f = group().register(channel).awaitUninterruptibly();
if (!f.isSuccess()) {
future.setFailure(f.cause());
return future;
}
if (!channel.isOpen()) {
// Registration was successful but the channel was closed due to some failure in
// handler.
future.setFailure(new ChannelException("initialization failure"));
if (!ensureOpen(future)) {
return future;
}
channel.bind(localAddress, future).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
channel.bind(localAddress(), future).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
return future;
}
@Override
public void shutdown() {
if (parentGroup != null) {
parentGroup.shutdown();
}
super.shutdown();
if (childGroup != null) {
childGroup.shutdown();
}
}
private void validate() {
if (parentGroup == null) {
throw new IllegalStateException("parentGroup not set");
}
if (channel == null) {
throw new IllegalStateException("channel not set");
}
@Override
protected void validate() {
super.validate();
if (childHandler == null) {
throw new IllegalStateException("childHandler not set");
}
if (childGroup == null) {
logger.warn("childGroup is not set. Using parentGroup instead.");
childGroup = parentGroup;
childGroup = group();
}
if (localAddress == null) {
if (localAddress() == null) {
logger.warn("localAddress is not set. Using " + DEFAULT_LOCAL_ADDR + " instead.");
localAddress = DEFAULT_LOCAL_ADDR;
localAddress(DEFAULT_LOCAL_ADDR);
}
}
private void validate(ChannelFuture future) {
if (future == null) {
throw new NullPointerException("future");
}
if (future.channel() != channel) {
throw new IllegalArgumentException("future.channel() must be the same channel.");
}
validate();
}
private class Acceptor
extends ChannelInboundHandlerAdapter implements ChannelInboundMessageHandler<Channel> {
@ -257,6 +207,7 @@ public class ServerBootstrap {
return Unpooled.messageBuffer();
}
@SuppressWarnings("unchecked")
@Override
public void inboundBufferUpdated(ChannelHandlerContext ctx) {
MessageBuf<Channel> in = ctx.inboundMessageBuffer();

View File

@ -129,7 +129,7 @@ import java.util.concurrent.TimeUnit;
* connect timeout should be configured via a transport-specific option:
* <pre>
* // BAD - NEVER DO THIS
* {@link ClientBootstrap} b = ...;
* {@link Bootstrap} b = ...;
* {@link ChannelFuture} f = b.connect(...);
* f.awaitUninterruptibly(10, TimeUnit.SECONDS);
* if (f.isCancelled()) {
@ -143,7 +143,7 @@ import java.util.concurrent.TimeUnit;
* }
*
* // GOOD
* {@link ClientBootstrap} b = ...;
* {@link Bootstrap} b = ...;
* // Configure the connect timeout option.
* <b>b.setOption("connectTimeoutMillis", 10000);</b>
* {@link ChannelFuture} f = b.connect(...);

View File

@ -15,7 +15,6 @@
*/
package io.netty.channel;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.group.ChannelGroup;
import java.lang.annotation.Documented;
@ -87,7 +86,7 @@ import java.nio.channels.Channels;
* the confidential information:
* <pre>
* // Create a new handler instance per channel.
* // See {@link Bootstrap#setPipelineFactory(ChannelPipelineFactory)}.
* // See {@link ClientBootstrap#setPipelineFactory(ChannelPipelineFactory)}.
* public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} {
* public {@link ChannelPipeline} getPipeline() {
* return {@link Channels}.pipeline(<b>new DataServerHandler()</b>);

View File

@ -43,12 +43,12 @@ public class LocalChannelRegistryTest {
ServerBootstrap sb = new ServerBootstrap();
cb.group(new LocalEventLoopGroup())
.channel(new LocalChannel())
.channel(LocalChannel.class)
.remoteAddress(addr)
.handler(new TestHandler());
sb.group(new LocalEventLoopGroup())
.channel(new LocalServerChannel())
.channel(LocalServerChannel.class)
.localAddress(addr)
.childHandler(new ChannelInitializer<LocalChannel>() {
@Override

View File

@ -58,7 +58,7 @@ public class LocalTransportThreadModelTest {
// Configure a test server
sb = new ServerBootstrap();
sb.group(new LocalEventLoopGroup())
.channel(new LocalServerChannel())
.channel(LocalServerChannel.class)
.localAddress(LocalAddress.ANY)
.childHandler(new ChannelInitializer<LocalChannel>() {
@Override