Make Bootstrap and ServerBootstrap implement Cloneable and rename duplicate() to clone()

- Fixes #997
- Replace duplicate() with clone()
- Add copy constructor for simplicity
- Can now clone invalid/incomplete bootstrap
- Upgrade to netty-build-14 to disable SuperClone checkstyle module
- Finalize class hierarchy so no subclasses are introduced
This commit is contained in:
Trustin Lee 2013-01-30 21:12:02 +09:00
parent bd0339ce1a
commit 7c50c1e2e6
4 changed files with 69 additions and 34 deletions

View File

@ -341,7 +341,7 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-build</artifactId>
<version>13</version>
<version>14</version>
</dependency>
</dependencies>
</plugin>

View File

@ -35,15 +35,28 @@ import java.util.concurrent.ConcurrentHashMap;
* method-chaining to provide an easy way to configure the {@link AbstractBootstrap}.
*
*/
public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> {
public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> implements Cloneable {
private EventLoopGroup group;
private ChannelFactory factory;
private ChannelFactory channelFactory;
private SocketAddress localAddress;
private final Map<ChannelOption<?>, Object> options = new ConcurrentHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> attrs = new ConcurrentHashMap<AttributeKey<?>, Object>();
private ChannelHandler handler;
AbstractBootstrap() {
// Disallow extending from a different package.
}
AbstractBootstrap(AbstractBootstrap<B> bootstrap) {
group = bootstrap.group;
channelFactory = bootstrap.channelFactory;
handler = bootstrap.handler;
localAddress = bootstrap.localAddress;
options.putAll(bootstrap.options);
attrs.putAll(bootstrap.attrs);
}
/**
* The {@link EventLoopGroup} which is used to handle all the events for the to-be-creates
* {@link Channel}
@ -80,15 +93,15 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> {
* simplify your code.
*/
@SuppressWarnings("unchecked")
public B channelFactory(ChannelFactory factory) {
if (factory == null) {
throw new NullPointerException("factory");
public B channelFactory(ChannelFactory channelFactory) {
if (channelFactory == null) {
throw new NullPointerException("channelFactory");
}
if (this.factory != null) {
throw new IllegalStateException("factory set already");
if (this.channelFactory != null) {
throw new IllegalStateException("channelFactory set already");
}
this.factory = factory;
this.channelFactory = channelFactory;
return (B) this;
}
@ -178,11 +191,20 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> {
if (group == null) {
throw new IllegalStateException("group not set");
}
if (factory == null) {
if (channelFactory == null) {
throw new IllegalStateException("factory not set");
}
}
/**
* Returns a deep clone of this bootstrap which has the identical configuration. This method is useful when making
* multiple {@link Channel}s with similar settings. Please note that this method does not clone the
* {@link EventLoopGroup} deeply but shallowly, making the group a shared resource.
*/
@Override
@SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException")
public abstract B clone();
/**
* Create a new {@link Channel} and bind it.
*/
@ -245,8 +267,8 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> {
return localAddress;
}
final ChannelFactory factory() {
return factory;
final ChannelFactory channelFactory() {
return channelFactory;
}
final ChannelHandler handler() {
@ -275,9 +297,9 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> {
buf.append(group.getClass().getSimpleName());
buf.append(", ");
}
if (factory != null) {
buf.append("factory: ");
buf.append(factory);
if (channelFactory != null) {
buf.append("channelFactory: ");
buf.append(channelFactory);
buf.append(", ");
}
if (localAddress != null) {

View File

@ -34,11 +34,19 @@ import java.util.Map.Entry;
* for clients.
*
*/
public class Bootstrap extends AbstractBootstrap<Bootstrap> {
public final class Bootstrap extends AbstractBootstrap<Bootstrap> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Bootstrap.class);
private SocketAddress remoteAddress;
public Bootstrap() { }
public Bootstrap(Bootstrap bootstrap) {
super(bootstrap);
remoteAddress = bootstrap.remoteAddress;
}
/**
* The {@link SocketAddress} to connect to once the {@link #connect()} method
* is called.
@ -66,7 +74,7 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap> {
@Override
ChannelFuture doBind(SocketAddress localAddress) {
Channel channel = factory().newChannel();
Channel channel = channelFactory().newChannel();
try {
init(channel);
} catch (Throwable t) {
@ -131,7 +139,7 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap> {
* @see {@link #connect()}
*/
private ChannelFuture doConnect(SocketAddress remoteAddress, SocketAddress localAddress) {
final Channel channel = factory().newChannel();
final Channel channel = channelFactory().newChannel();
try {
init(channel);
@ -180,20 +188,10 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap> {
}
}
/**
* Create a new {@link Bootstrap} which has the identical configuration with this {@link Bootstrap}.
* This method is useful when you make multiple connections with similar settings.
*
* Be aware that if you call {@link #shutdown()} on one of them it will shutdown shared resources.
*/
public Bootstrap duplicate() {
validate();
Bootstrap b = new Bootstrap()
.group(group()).channelFactory(factory()).handler(handler())
.localAddress(localAddress()).remoteAddress(remoteAddress);
b.options().putAll(options());
b.attrs().putAll(attrs());
return b;
@Override
@SuppressWarnings("CloneDoesntCallSuperClone")
public Bootstrap clone() {
return new Bootstrap(this);
}
@Override

View File

@ -59,6 +59,16 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
private EventLoopGroup childGroup;
private ChannelHandler childHandler;
public ServerBootstrap() { }
public ServerBootstrap(ServerBootstrap bootstrap) {
super(bootstrap);
childGroup = bootstrap.childGroup;
childHandler = bootstrap.childHandler;
childOptions.putAll(bootstrap.childOptions);
childAttrs.putAll(bootstrap.childAttrs);
}
/**
* Specify the {@link EventLoopGroup} which is used for the parent (acceptor) and the child (client).
*/
@ -145,7 +155,7 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
@Override
ChannelFuture doBind(SocketAddress localAddress) {
Channel channel = factory().newChannel();
Channel channel = channelFactory().newChannel();
try {
channel.config().setOptions(options());
@ -238,6 +248,12 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
}
}
@Override
@SuppressWarnings("CloneDoesntCallSuperClone")
public ServerBootstrap clone() {
return new ServerBootstrap(this);
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(super.toString());
@ -273,4 +289,3 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
return buf.toString();
}
}