Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make transport.Bootstrap usable with no netty-resolver on classpath #13488

Merged
merged 2 commits into from Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 46 additions & 9 deletions transport/src/main/java/io/netty/bootstrap/Bootstrap.java
Expand Up @@ -47,20 +47,18 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {

private static final InternalLogger logger = InternalLoggerFactory.getInstance(Bootstrap.class);

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;
private ExternalAddressResolver externalResolver;
private volatile boolean disableResolver;
private volatile SocketAddress remoteAddress;

public Bootstrap() { }

private Bootstrap(Bootstrap bootstrap) {
super(bootstrap);
resolver = bootstrap.resolver;
externalResolver = bootstrap.externalResolver;
disableResolver = bootstrap.disableResolver;
remoteAddress = bootstrap.remoteAddress;
}

Expand All @@ -74,7 +72,18 @@ private Bootstrap(Bootstrap bootstrap) {
*/
@SuppressWarnings("unchecked")
public Bootstrap resolver(AddressResolverGroup<?> resolver) {
this.resolver = (AddressResolverGroup<SocketAddress>) (resolver == null ? DEFAULT_RESOLVER : resolver);
this.externalResolver = resolver == null ? null : new ExternalAddressResolver(resolver);
disableResolver = false;
return this;
}

/**
* Disables address name resolution. Name resolution may be re-enabled with
* {@link Bootstrap#resolver(AddressResolverGroup)}
*/
public Bootstrap disableResolver() {
externalResolver = null;
disableResolver = true;
return this;
}

Expand Down Expand Up @@ -188,10 +197,15 @@ public void operationComplete(ChannelFuture future) throws Exception {
private ChannelFuture doResolveAndConnect0(final Channel channel, SocketAddress remoteAddress,
final SocketAddress localAddress, final ChannelPromise promise) {
try {
if (disableResolver) {
doConnect(remoteAddress, localAddress, promise);
return promise;
}

final EventLoop eventLoop = channel.eventLoop();
AddressResolver<SocketAddress> resolver;
try {
resolver = this.resolver.getResolver(eventLoop);
resolver = ExternalAddressResolver.getOrDefault(externalResolver).getResolver(eventLoop);
} catch (Throwable cause) {
channel.close();
return promise.setFailure(cause);
Expand Down Expand Up @@ -301,6 +315,29 @@ final SocketAddress remoteAddress() {
}

final AddressResolverGroup<?> resolver() {
return resolver;
if (disableResolver) {
return null;
}
return ExternalAddressResolver.getOrDefault(externalResolver);
}

/* Holder to avoid NoClassDefFoundError in case netty-resolver dependency is excluded
(e.g. some address families do not need name resolution) */
static final class ExternalAddressResolver {
final AddressResolverGroup<SocketAddress> resolverGroup;

@SuppressWarnings("unchecked")
ExternalAddressResolver(AddressResolverGroup<?> resolverGroup) {
this.resolverGroup = (AddressResolverGroup<SocketAddress>) resolverGroup;
}

@SuppressWarnings("unchecked")
static AddressResolverGroup<SocketAddress> getOrDefault(ExternalAddressResolver externalResolver) {
if (externalResolver == null) {
AddressResolverGroup<?> defaultResolverGroup = DefaultAddressResolverGroup.INSTANCE;
return (AddressResolverGroup<SocketAddress>) defaultResolverGroup;
}
return externalResolver.resolverGroup;
}
}
}
Expand Up @@ -37,7 +37,8 @@ public SocketAddress remoteAddress() {
}

/**
* Returns the configured {@link AddressResolverGroup} or the default if non is configured yet.
* Returns the configured {@link AddressResolverGroup}, {@code null} if resolver was disabled
* with {@link Bootstrap#disableResolver()}, or the default if non is configured yet.
mostroverkhov marked this conversation as resolved.
Show resolved Hide resolved
*/
public AddressResolverGroup<?> resolver() {
return bootstrap.resolver();
Expand All @@ -47,7 +48,11 @@ public AddressResolverGroup<?> resolver() {
public String toString() {
StringBuilder buf = new StringBuilder(super.toString());
buf.setLength(buf.length() - 1);
buf.append(", resolver: ").append(resolver());
AddressResolverGroup<?> resolver = resolver();
if (resolver != null) {
buf.append(", resolver: ")
.append(resolver);
}
SocketAddress remoteAddress = remoteAddress();
if (remoteAddress != null) {
buf.append(", remoteAddress: ")
Expand Down
25 changes: 25 additions & 0 deletions transport/src/test/java/io/netty/bootstrap/BootstrapTest.java
Expand Up @@ -38,6 +38,7 @@
import io.netty.resolver.AddressResolver;
import io.netty.resolver.AddressResolverGroup;
import io.netty.resolver.AbstractAddressResolver;
import io.netty.resolver.DefaultAddressResolverGroup;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
Expand Down Expand Up @@ -69,6 +70,8 @@
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
Expand Down Expand Up @@ -299,6 +302,24 @@ public void execute() {
}
}

@Test
void testResolverDefault() throws Exception {
Bootstrap bootstrap = new Bootstrap();

assertTrue(bootstrap.config().toString().contains("resolver:"));
assertNotNull(bootstrap.config().resolver());
assertEquals(DefaultAddressResolverGroup.class, bootstrap.config().resolver().getClass());
}

@Test
void testResolverDisabled() throws Exception {
Bootstrap bootstrap = new Bootstrap();
bootstrap.disableResolver();

assertFalse(bootstrap.config().toString().contains("resolver:"));
assertNull(bootstrap.config().resolver());
}

@Test
public void testAsyncResolutionSuccess() throws Exception {
final Bootstrap bootstrapA = new Bootstrap();
Expand All @@ -311,6 +332,10 @@ public void testAsyncResolutionSuccess() throws Exception {
bootstrapB.group(groupB);
bootstrapB.channel(LocalServerChannel.class);
bootstrapB.childHandler(dummyHandler);

assertTrue(bootstrapA.config().toString().contains("resolver:"));
assertThat(bootstrapA.resolver(), is(instanceOf(TestAddressResolverGroup.class)));

SocketAddress localAddress = bootstrapB.bind(LocalAddress.ANY).sync().channel().localAddress();

// Connect to the server using the asynchronous resolver.
Expand Down