[#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; 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.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; 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 * {@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}. * 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 ChannelFactory factory;
private SocketAddress localAddress; private SocketAddress localAddress;
private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>(); private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>();
private ChannelHandler handler; private ChannelHandler handler;
/** /**
@ -137,6 +139,23 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<?>> {
return (B) this; 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 * Shutdown the {@link AbstractBootstrap} and the {@link EventLoopGroup} which is
* used by it. Only call this if you don't share the {@link EventLoopGroup} * 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; return options;
} }
protected final Map<AttributeKey<?>, Object> attrs() {
return attrs;
}
private final class BootstrapChannelFactory implements ChannelFactory { private final class BootstrapChannelFactory implements ChannelFactory {
private final Class<? extends Channel> clazz; private final Class<? extends Channel> clazz;

View File

@ -16,13 +16,13 @@
package io.netty.bootstrap; package io.netty.bootstrap;
import io.netty.channel.Channel; 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.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory; import io.netty.logging.InternalLoggerFactory;
import io.netty.util.AttributeKey;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; 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(); 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. * Create a new {@link Bootstrap} which has the identical configuration with this {@link Bootstrap}.
* Only the given parameters are replaced, the rest is configured exactly the same way as the template. * 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(); validate();
Bootstrap cb = new Bootstrap().handler(handler).channelFactory(factory()).group(group()) Bootstrap b = new Bootstrap()
.localAddress(localAddress).remoteAddress(remoteAddress); .group(group()).channelFactory(factory()).handler(handler())
cb.options().putAll(options()); .localAddress(localAddress()).remoteAddress(remoteAddress);
return cb; b.options().putAll(options());
} b.attrs().putAll(attrs());
return b;
/**
* 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

@ -32,6 +32,7 @@ import io.netty.channel.ServerChannel;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory; import io.netty.logging.InternalLoggerFactory;
import io.netty.util.AttributeKey;
import io.netty.util.NetworkConstants; import io.netty.util.NetworkConstants;
import java.net.InetSocketAddress; 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<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
private EventLoopGroup childGroup; private EventLoopGroup childGroup;
private ChannelHandler childHandler; private ChannelHandler childHandler;
@ -116,6 +118,18 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap> {
return this; 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. * 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; return future;
} }
for (Entry<AttributeKey<?>, Object> e: attrs().entrySet()) {
channel.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
ChannelPipeline p = future.channel().pipeline(); ChannelPipeline p = future.channel().pipeline();
if (handler() != null) { if (handler() != null) {
p.addLast(handler()); 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 { try {
childGroup.register(child); childGroup.register(child);
} catch (Throwable t) { } catch (Throwable t) {