[#275 & #686] Ability to pass a custom parameter to Bootstrap.connect() / Replace Bootstrap.newBootstrap() with duplicate()

- Add Bootstrap.attr() and ServerBootstrap.attr()/childAttr() so that a
  user can initialize the attribute map from the beginning.
- Replace newBootstrap() with duplicate()
This commit is contained in:
Trustin Lee 2012-10-26 14:52:50 -07:00
parent fb6ce4989a
commit 43dc0bd8a3
3 changed files with 68 additions and 25 deletions

View File

@ -16,19 +16,20 @@
package io.netty.bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.util.AttributeKey;
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}.
@ -39,6 +40,7 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> {
private ChannelFactory factory;
private SocketAddress localAddress;
private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>();
private ChannelHandler handler;
/**
@ -137,6 +139,23 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> {
return (B) this;
}
/**
* Allow to specify an initial attribute of the newly created {@link Channel}. If the {@code value} is
* {@code null}, the attribute of the specified {@code key} is removed.
*/
public <T> B attr(AttributeKey<T> key, T value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
attrs.remove(key);
} else {
attrs.put(key, 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}
@ -224,6 +243,10 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> {
return options;
}
protected final Map<AttributeKey<?>, Object> attrs() {
return attrs;
}
private final class BootstrapChannelFactory implements ChannelFactory {
private final Class<? extends Channel> clazz;

View File

@ -16,13 +16,13 @@
package io.netty.bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
import io.netty.util.AttributeKey;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@ -149,6 +149,10 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap> {
}
}
for (Entry<AttributeKey<?>, Object> e: attrs().entrySet()) {
channel.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
group().register(channel).syncUninterruptibly();
}
@ -161,22 +165,16 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap> {
}
/**
* 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.
* 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.
*/
public Bootstrap newBootstrap(SocketAddress localAddress, SocketAddress remoteAddress, ChannelHandler handler) {
public Bootstrap duplicate() {
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());
Bootstrap b = new Bootstrap()
.group(group()).channelFactory(factory()).handler(handler())
.localAddress(localAddress()).remoteAddress(remoteAddress);
b.options().putAll(options());
b.attrs().putAll(attrs());
return b;
}
}

View File

@ -32,6 +32,7 @@ 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.AttributeKey;
import io.netty.util.NetworkConstants;
import java.net.InetSocketAddress;
@ -57,6 +58,7 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
};
private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
private EventLoopGroup childGroup;
private ChannelHandler childHandler;
@ -116,6 +118,18 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
return this;
}
public <T> ServerBootstrap childAttr(AttributeKey<T> childKey, T value) {
if (childKey == null) {
throw new NullPointerException("childKey");
}
if (value == null) {
childAttrs.remove(childKey);
} else {
childAttrs.put(childKey, value);
}
return this;
}
/**
* Set the {@link ChannelHandler} which is used to server the request for the {@link Channel}'s.
*/
@ -151,6 +165,10 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
return future;
}
for (Entry<AttributeKey<?>, Object> e: attrs().entrySet()) {
channel.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
ChannelPipeline p = future.channel().pipeline();
if (handler() != null) {
p.addLast(handler());
@ -227,6 +245,10 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
}
}
for (Entry<AttributeKey<?>, Object> e: childAttrs.entrySet()) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
try {
childGroup.register(child);
} catch (Throwable t) {