[#5174] Expose Bootstrap getter methods and add some additional ones

Motivation:

The Bootstrap class (applies also to AbstractBootstrap and ServerBootstrap) has a few package private getter methods and some things such as #attr() and #options() aren't exposed at all.

Modifications:

Expose "getters" for configured things in a safe-manner via the config() method.

Result:

Easier for the user to check what is configured for a Bootstrap/ServerBootstrap.
This commit is contained in:
Norman Maurer 2016-05-09 10:57:35 +02:00
parent da46928950
commit a425a8551d
6 changed files with 383 additions and 115 deletions

View File

@ -35,6 +35,7 @@ import io.netty.util.internal.StringUtil;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
@ -314,7 +315,7 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C ext
}
final ChannelFuture initAndRegister() {
final Channel channel = channelFactory().newChannel();
final Channel channel = channelFactory.newChannel();
try {
init(channel);
} catch (Throwable t) {
@ -376,6 +377,41 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C ext
return (B) this;
}
/**
* Returns the configured {@link EventLoopGroup} or {@code null} if non is configured yet.
*
* @deprecated Use {@link #config()} instead.
*/
@Deprecated
public final EventLoopGroup group() {
return group;
}
/**
* Returns the {@link AbstractBootstrapConfig} object that can be used to obtain the current config
* of the bootstrap.
*/
public abstract AbstractBootstrapConfig<B, C> config();
static <K, V> Map<K, V> copiedMap(Map<K, V> map) {
final Map<K, V> copied;
synchronized (map) {
if (map.isEmpty()) {
return Collections.emptyMap();
}
copied = new LinkedHashMap<K, V>(map);
}
return Collections.unmodifiableMap(copied);
}
final Map<ChannelOption<?>, Object> options0() {
return options;
}
final Map<AttributeKey<?>, Object> attrs0() {
return attrs;
}
final SocketAddress localAddress() {
return localAddress;
}
@ -389,66 +425,19 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C ext
return handler;
}
/**
* Return the configured {@link EventLoopGroup} or {@code null} if non is configured yet.
*/
public EventLoopGroup group() {
return group;
}
final Map<ChannelOption<?>, Object> options() {
return options;
return copiedMap(options);
}
final Map<AttributeKey<?>, Object> attrs() {
return attrs;
return copiedMap(attrs);
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder()
.append(StringUtil.simpleClassName(this))
.append('(');
if (group != null) {
buf.append("group: ")
.append(StringUtil.simpleClassName(group))
.append(", ");
}
if (channelFactory != null) {
buf.append("channelFactory: ")
.append(channelFactory)
.append(", ");
}
if (localAddress != null) {
buf.append("localAddress: ")
.append(localAddress)
.append(", ");
}
synchronized (options) {
if (!options.isEmpty()) {
buf.append("options: ")
.append(options)
.append(", ");
}
}
synchronized (attrs) {
if (!attrs.isEmpty()) {
buf.append("attrs: ")
.append(attrs)
.append(", ");
}
}
if (handler != null) {
buf.append("handler: ")
.append(handler)
.append(", ");
}
if (buf.charAt(buf.length() - 1) == '(') {
buf.append(')');
} else {
buf.setCharAt(buf.length() - 2, ')');
buf.setLength(buf.length() - 1);
}
.append('(').append(config()).append(')');
return buf.toString();
}

View File

@ -0,0 +1,135 @@
/*
* Copyright 2016 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 io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.util.AttributeKey;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.StringUtil;
import java.net.SocketAddress;
import java.util.Map;
/**
* Exposes the configuration of an {@link AbstractBootstrap}.
*/
public abstract class AbstractBootstrapConfig<B extends AbstractBootstrap<B, C>, C extends Channel> {
protected final B bootstrap;
protected AbstractBootstrapConfig(B bootstrap) {
this.bootstrap = ObjectUtil.checkNotNull(bootstrap, "bootstrap");
}
/**
* Returns the configured local address or {@code null} if non is configured yet.
*/
public final SocketAddress localAddress() {
return bootstrap.localAddress();
}
/**
* Returns the configured {@link ChannelFactory} or {@code null} if non is configured yet.
*/
@SuppressWarnings("deprecation")
public final ChannelFactory<? extends C> channelFactory() {
return bootstrap.channelFactory();
}
/**
* Returns the configured {@link ChannelHandler} or {@code null} if non is configured yet.
*/
public final ChannelHandler handler() {
return bootstrap.handler();
}
/**
* Returns a copy of the configured options.
*/
public final Map<ChannelOption<?>, Object> options() {
return bootstrap.options();
}
/**
* Returns a copy of the configured attributes.
*/
public final Map<AttributeKey<?>, Object> attrs() {
return bootstrap.attrs();
}
/**
* Returns the configured {@link EventLoopGroup} or {@code null} if non is configured yet.
*/
@SuppressWarnings("deprecation")
public final EventLoopGroup group() {
return bootstrap.group();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder()
.append(StringUtil.simpleClassName(this))
.append('(');
EventLoopGroup group = group();
if (group != null) {
buf.append("group: ")
.append(StringUtil.simpleClassName(group))
.append(", ");
}
@SuppressWarnings("deprecation")
ChannelFactory<? extends C> factory = channelFactory();
if (factory != null) {
buf.append("channelFactory: ")
.append(factory)
.append(", ");
}
SocketAddress localAddress = localAddress();
if (localAddress != null) {
buf.append("localAddress: ")
.append(localAddress)
.append(", ");
}
Map<ChannelOption<?>, Object> options = options();
if (!options.isEmpty()) {
buf.append("options: ")
.append(options)
.append(", ");
}
Map<AttributeKey<?>, Object> attrs = attrs();
if (!attrs.isEmpty()) {
buf.append("attrs: ")
.append(attrs)
.append(", ");
}
ChannelHandler handler = handler();
if (handler != null) {
buf.append("handler: ")
.append(handler)
.append(", ");
}
if (buf.charAt(buf.length() - 1) == '(') {
buf.append(')');
} else {
buf.setCharAt(buf.length() - 2, ')');
buf.setLength(buf.length() - 1);
}
return buf.toString();
}
}

View File

@ -53,6 +53,8 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
private static final AddressResolverGroup<?> DEFAULT_RESOLVER = DefaultAddressResolverGroup.INSTANCE;
private final BootstrapConfig config = new BootstrapConfig(this);
@SuppressWarnings("unchecked")
private volatile AddressResolverGroup<SocketAddress> resolver =
(AddressResolverGroup<SocketAddress>) DEFAULT_RESOLVER;
@ -113,7 +115,7 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
throw new IllegalStateException("remoteAddress not set");
}
return doResolveAndConnect(remoteAddress, localAddress());
return doResolveAndConnect(remoteAddress, config.localAddress());
}
/**
@ -139,7 +141,7 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
}
validate();
return doResolveAndConnect(remoteAddress, localAddress());
return doResolveAndConnect(remoteAddress, config.localAddress());
}
/**
@ -256,9 +258,9 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
@SuppressWarnings("unchecked")
void init(Channel channel) throws Exception {
ChannelPipeline p = channel.pipeline();
p.addLast(handler());
p.addLast(config.handler());
final Map<ChannelOption<?>, Object> options = options();
final Map<ChannelOption<?>, Object> options = options0();
synchronized (options) {
for (Entry<ChannelOption<?>, Object> e: options.entrySet()) {
try {
@ -271,7 +273,7 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
}
}
final Map<AttributeKey<?>, Object> attrs = attrs();
final Map<AttributeKey<?>, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
channel.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
@ -282,7 +284,7 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
@Override
public Bootstrap validate() {
super.validate();
if (handler() == null) {
if (config.handler() == null) {
throw new IllegalStateException("handler not set");
}
return this;
@ -306,17 +308,15 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
}
@Override
public String toString() {
if (remoteAddress == null) {
return super.toString();
}
public final BootstrapConfig config() {
return config;
}
StringBuilder buf = new StringBuilder(super.toString());
buf.setLength(buf.length() - 1);
final SocketAddress remoteAddress() {
return remoteAddress;
}
return buf.append(", remoteAddress: ")
.append(remoteAddress)
.append(')')
.toString();
final AddressResolverGroup<?> resolver() {
return resolver;
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2016 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 io.netty.channel.Channel;
import io.netty.resolver.AddressResolverGroup;
import java.net.SocketAddress;
/**
* Exposes the configuration of a {@link Bootstrap}.
*/
public final class BootstrapConfig extends AbstractBootstrapConfig<Bootstrap, Channel> {
BootstrapConfig(Bootstrap bootstrap) {
super(bootstrap);
}
/**
* Returns the configured remote address or {@code null} if non is configured yet.
*/
public SocketAddress remoteAddress() {
return bootstrap.remoteAddress();
}
/**
* Returns the configured {@link AddressResolverGroup} or the default if non is configured yet.
*/
public AddressResolverGroup<?> resolver() {
return bootstrap.resolver();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(super.toString());
buf.setLength(buf.length() - 1);
buf.append(", resolver: ").append(resolver());
SocketAddress remoteAddress = remoteAddress();
if (remoteAddress != null) {
buf.append(", remoteAddress: ")
.append(remoteAddress);
}
return buf.append(')').toString();
}
}

View File

@ -29,7 +29,6 @@ import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import io.netty.util.AttributeKey;
import io.netty.util.internal.OneTimeTask;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
@ -48,6 +47,7 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerCh
private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
private volatile EventLoopGroup childGroup;
private volatile ChannelHandler childHandler;
@ -138,22 +138,14 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerCh
return this;
}
/**
* Return the configured {@link EventLoopGroup} which will be used for the child channels or {@code null}
* if non is configured yet.
*/
public EventLoopGroup childGroup() {
return childGroup;
}
@Override
void init(Channel channel) throws Exception {
final Map<ChannelOption<?>, Object> options = options();
final Map<ChannelOption<?>, Object> options = options0();
synchronized (options) {
channel.config().setOptions(options);
}
final Map<AttributeKey<?>, Object> attrs = attrs();
final Map<AttributeKey<?>, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
@ -179,7 +171,7 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerCh
@Override
public void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = handler();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
@ -294,42 +286,31 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerCh
return new ServerBootstrap(this);
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(super.toString());
buf.setLength(buf.length() - 1);
buf.append(", ");
if (childGroup != null) {
buf.append("childGroup: ");
buf.append(StringUtil.simpleClassName(childGroup));
buf.append(", ");
}
synchronized (childOptions) {
if (!childOptions.isEmpty()) {
buf.append("childOptions: ");
buf.append(childOptions);
buf.append(", ");
}
}
synchronized (childAttrs) {
if (!childAttrs.isEmpty()) {
buf.append("childAttrs: ");
buf.append(childAttrs);
buf.append(", ");
}
}
if (childHandler != null) {
buf.append("childHandler: ");
buf.append(childHandler);
buf.append(", ");
}
if (buf.charAt(buf.length() - 1) == '(') {
buf.append(')');
} else {
buf.setCharAt(buf.length() - 2, ')');
buf.setLength(buf.length() - 1);
}
/**
* Return the configured {@link EventLoopGroup} which will be used for the child channels or {@code null}
* if non is configured yet.
*
* @deprecated Use {@link #config()} instead.
*/
@Deprecated
public EventLoopGroup childGroup() {
return childGroup;
}
return buf.toString();
final ChannelHandler childHandler() {
return childHandler;
}
final Map<ChannelOption<?>, Object> childOptions() {
return copiedMap(childOptions);
}
final Map<AttributeKey<?>, Object> childAttrs() {
return copiedMap(childAttrs);
}
@Override
public final ServerBootstrapConfig config() {
return config;
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright 2016 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 io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import io.netty.util.AttributeKey;
import io.netty.util.internal.StringUtil;
import java.util.Map;
/**
* Exposes the configuration of a {@link ServerBootstrapConfig}.
*/
public final class ServerBootstrapConfig extends AbstractBootstrapConfig<ServerBootstrap, ServerChannel> {
ServerBootstrapConfig(ServerBootstrap bootstrap) {
super(bootstrap);
}
/**
* Returns the configured {@link EventLoopGroup} which will be used for the child channels or {@code null}
* if non is configured yet.
*/
@SuppressWarnings("deprecation")
public EventLoopGroup childGroup() {
return bootstrap.childGroup();
}
/**
* Returns the configured {@link ChannelHandler} be used for the child channels or {@code null}
* if non is configured yet.
*/
public ChannelHandler childHandler() {
return bootstrap.childHandler();
}
/**
* Returns a copy of the configured options which will be used for the child channels.
*/
public Map<ChannelOption<?>, Object> childOptions() {
return bootstrap.childOptions();
}
/**
* Returns a copy of the configured attributes which will be used for the child channels.
*/
public Map<AttributeKey<?>, Object> childAttrs() {
return bootstrap.childAttrs();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(super.toString());
buf.setLength(buf.length() - 1);
buf.append(", ");
EventLoopGroup childGroup = childGroup();
if (childGroup != null) {
buf.append("childGroup: ");
buf.append(StringUtil.simpleClassName(childGroup));
buf.append(", ");
}
Map<ChannelOption<?>, Object> childOptions = childOptions();
if (!childOptions.isEmpty()) {
buf.append("childOptions: ");
buf.append(childOptions);
buf.append(", ");
}
Map<AttributeKey<?>, Object> childAttrs = childAttrs();
if (!childAttrs.isEmpty()) {
buf.append("childAttrs: ");
buf.append(childAttrs);
buf.append(", ");
}
ChannelHandler childHandler = childHandler();
if (childHandler != null) {
buf.append("childHandler: ");
buf.append(childHandler);
buf.append(", ");
}
if (buf.charAt(buf.length() - 1) == '(') {
buf.append(')');
} else {
buf.setCharAt(buf.length() - 2, ')');
buf.setLength(buf.length() - 1);
}
return buf.toString();
}
}