From 541fe86fe01b8296d03acae4bd75fe9cc2e66103 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sun, 13 Dec 2015 00:11:59 +0100 Subject: [PATCH] Extract SocketAdress logic from NameResolver Motivation: As discussed in #4529, NameResolver design shouldn't be resolving SocketAddresses (or String name + port) and return InetSocketAddresses. It should resolve String names and return InetAddresses. This SocketAddress to InetSocketAddresses resolution is actually a different concern, used by Bootstrap. Modifications: Extract SocketAddress to InetSocketAddresses resolution concern to a new class hierarchy named AddressResolver. These AddressResolvers delegate to NameResolvers. Result: Better separation of concerns. Note that new AddressResolvers generate a bit more allocations because of the intermediate Promise and List. --- .../netty/handler/proxy/ProxyHandlerTest.java | 8 +- ...roup.java => DnsAddressResolverGroup.java} | 24 +- .../netty/resolver/dns/DnsNameResolver.java | 101 ++++----- .../resolver/dns/DnsNameResolverTest.java | 36 ++- .../resolver/AbstractAddressResolver.java | 206 ++++++++++++++++++ .../io/netty/resolver/AddressResolver.java | 90 ++++++++ ...erGroup.java => AddressResolverGroup.java} | 30 +-- ....java => DefaultAddressResolverGroup.java} | 14 +- .../netty/resolver/DefaultNameResolver.java | 33 +-- .../io/netty/resolver/InetNameResolver.java | 54 +++++ .../resolver/InetSocketAddressResolver.java | 91 ++++++++ .../java/io/netty/resolver/NameResolver.java | 88 ++------ ...Resolver.java => NoopAddressResolver.java} | 6 +- ...oup.java => NoopAddressResolverGroup.java} | 12 +- .../io/netty/resolver/SimpleNameResolver.java | 175 ++------------- .../java/io/netty/resolver/package-info.java | 2 +- .../java/io/netty/bootstrap/Bootstrap.java | 16 +- .../io/netty/bootstrap/BootstrapTest.java | 18 +- 18 files changed, 603 insertions(+), 401 deletions(-) rename resolver-dns/src/main/java/io/netty/resolver/dns/{DnsNameResolverGroup.java => DnsAddressResolverGroup.java} (81%) create mode 100644 resolver/src/main/java/io/netty/resolver/AbstractAddressResolver.java create mode 100644 resolver/src/main/java/io/netty/resolver/AddressResolver.java rename resolver/src/main/java/io/netty/resolver/{NameResolverGroup.java => AddressResolverGroup.java} (76%) rename resolver/src/main/java/io/netty/resolver/{DefaultNameResolverGroup.java => DefaultAddressResolverGroup.java} (58%) create mode 100644 resolver/src/main/java/io/netty/resolver/InetNameResolver.java create mode 100644 resolver/src/main/java/io/netty/resolver/InetSocketAddressResolver.java rename resolver/src/main/java/io/netty/resolver/{NoopNameResolver.java => NoopAddressResolver.java} (85%) rename resolver/src/main/java/io/netty/resolver/{NoopNameResolverGroup.java => NoopAddressResolverGroup.java} (63%) diff --git a/handler-proxy/src/test/java/io/netty/handler/proxy/ProxyHandlerTest.java b/handler-proxy/src/test/java/io/netty/handler/proxy/ProxyHandlerTest.java index 06f0053c25..63ce6d1198 100644 --- a/handler-proxy/src/test/java/io/netty/handler/proxy/ProxyHandlerTest.java +++ b/handler-proxy/src/test/java/io/netty/handler/proxy/ProxyHandlerTest.java @@ -36,7 +36,7 @@ import io.netty.handler.codec.LineBasedFrameDecoder; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.ssl.util.SelfSignedCertificate; -import io.netty.resolver.NoopNameResolverGroup; +import io.netty.resolver.NoopAddressResolverGroup; import io.netty.util.CharsetUtil; import io.netty.util.concurrent.DefaultExecutorServiceFactory; import io.netty.util.concurrent.Future; @@ -523,7 +523,7 @@ public class ProxyHandlerTest { Bootstrap b = new Bootstrap(); b.group(group); b.channel(NioSocketChannel.class); - b.resolver(NoopNameResolverGroup.INSTANCE); + b.resolver(NoopAddressResolverGroup.INSTANCE); b.handler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel ch) throws Exception { @@ -571,7 +571,7 @@ public class ProxyHandlerTest { Bootstrap b = new Bootstrap(); b.group(group); b.channel(NioSocketChannel.class); - b.resolver(NoopNameResolverGroup.INSTANCE); + b.resolver(NoopAddressResolverGroup.INSTANCE); b.handler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel ch) throws Exception { @@ -616,7 +616,7 @@ public class ProxyHandlerTest { Bootstrap b = new Bootstrap(); b.group(group); b.channel(NioSocketChannel.class); - b.resolver(NoopNameResolverGroup.INSTANCE); + b.resolver(NoopAddressResolverGroup.INSTANCE); b.handler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel ch) throws Exception { diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverGroup.java b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsAddressResolverGroup.java similarity index 81% rename from resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverGroup.java rename to resolver-dns/src/main/java/io/netty/resolver/dns/DnsAddressResolverGroup.java index d763e88b6c..7f53ec37e3 100644 --- a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverGroup.java +++ b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsAddressResolverGroup.java @@ -20,8 +20,8 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.EventLoop; import io.netty.channel.ReflectiveChannelFactory; import io.netty.channel.socket.DatagramChannel; -import io.netty.resolver.NameResolver; -import io.netty.resolver.NameResolverGroup; +import io.netty.resolver.AddressResolver; +import io.netty.resolver.AddressResolverGroup; import io.netty.util.concurrent.EventExecutor; import io.netty.util.internal.StringUtil; @@ -30,31 +30,31 @@ import java.net.InetSocketAddress; import static io.netty.resolver.dns.DnsNameResolver.ANY_LOCAL_ADDR; /** - * A {@link NameResolverGroup} of {@link DnsNameResolver}s. + * A {@link AddressResolverGroup} of {@link DnsNameResolver}s. */ -public class DnsNameResolverGroup extends NameResolverGroup { +public class DnsAddressResolverGroup extends AddressResolverGroup { private final ChannelFactory channelFactory; private final InetSocketAddress localAddress; private final DnsServerAddresses nameServerAddresses; - public DnsNameResolverGroup( + public DnsAddressResolverGroup( Class channelType, DnsServerAddresses nameServerAddresses) { this(channelType, ANY_LOCAL_ADDR, nameServerAddresses); } - public DnsNameResolverGroup( + public DnsAddressResolverGroup( Class channelType, InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) { this(new ReflectiveChannelFactory(channelType), localAddress, nameServerAddresses); } - public DnsNameResolverGroup( + public DnsAddressResolverGroup( ChannelFactory channelFactory, DnsServerAddresses nameServerAddresses) { this(channelFactory, ANY_LOCAL_ADDR, nameServerAddresses); } - public DnsNameResolverGroup( + public DnsAddressResolverGroup( ChannelFactory channelFactory, InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) { this.channelFactory = channelFactory; @@ -63,7 +63,7 @@ public class DnsNameResolverGroup extends NameResolverGroup { } @Override - protected final NameResolver newResolver(EventExecutor executor) throws Exception { + protected final AddressResolver newResolver(EventExecutor executor) throws Exception { if (!(executor instanceof EventLoop)) { throw new IllegalStateException( "unsupported executor type: " + StringUtil.simpleClassName(executor) + @@ -77,11 +77,11 @@ public class DnsNameResolverGroup extends NameResolverGroup { * Creates a new {@link DnsNameResolver}. Override this method to create an alternative {@link DnsNameResolver} * implementation or override the default configuration. */ - protected DnsNameResolver newResolver( + protected AddressResolver newResolver( EventLoop eventLoop, ChannelFactory channelFactory, InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) throws Exception { - return new DnsNameResolver( - eventLoop, channelFactory, localAddress, nameServerAddresses); + return new DnsNameResolver(eventLoop, channelFactory, localAddress, nameServerAddresses) + .asAddressResolver(); } } diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java index 7ba7149a9f..43f60d6ebd 100644 --- a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java +++ b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java @@ -33,8 +33,7 @@ import io.netty.handler.codec.dns.DatagramDnsResponse; import io.netty.handler.codec.dns.DatagramDnsResponseDecoder; import io.netty.handler.codec.dns.DnsQuestion; import io.netty.handler.codec.dns.DnsResponse; -import io.netty.resolver.NameResolver; -import io.netty.resolver.SimpleNameResolver; +import io.netty.resolver.InetNameResolver; import io.netty.util.NetUtil; import io.netty.util.ReferenceCountUtil; import io.netty.util.concurrent.FastThreadLocal; @@ -42,14 +41,12 @@ import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; import io.netty.util.internal.OneTimeTask; import io.netty.util.internal.PlatformDependent; -import io.netty.util.internal.SystemPropertyUtil; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import java.net.IDN; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -62,9 +59,9 @@ import java.util.concurrent.TimeUnit; import static io.netty.util.internal.ObjectUtil.checkNotNull; /** - * A DNS-based {@link NameResolver}. + * A DNS-based {@link InetNameResolver}. */ -public class DnsNameResolver extends SimpleNameResolver { +public class DnsNameResolver extends InetNameResolver { private static final InternalLogger logger = InternalLoggerFactory.getInstance(DnsNameResolver.class); @@ -74,7 +71,7 @@ public class DnsNameResolver extends SimpleNameResolver { static { // Note that we did not use SystemPropertyUtil.getBoolean() here to emulate the behavior of JDK. - if ("true".equalsIgnoreCase(SystemPropertyUtil.get("java.net.preferIPv6Addresses"))) { + if (Boolean.getBoolean("java.net.preferIPv6Addresses")) { DEFAULT_RESOLVE_ADDRESS_TYPES[0] = InternetProtocolFamily.IPv6; DEFAULT_RESOLVE_ADDRESS_TYPES[1] = InternetProtocolFamily.IPv4; logger.debug("-Djava.net.preferIPv6Addresses: true"); @@ -98,7 +95,7 @@ public class DnsNameResolver extends SimpleNameResolver { final DnsQueryContextManager queryContextManager = new DnsQueryContextManager(); /** - * Cache for {@link #doResolve(InetSocketAddress, Promise)} and {@link #doResolveAll(InetSocketAddress, Promise)}. + * Cache for {@link #doResolve(String, Promise)} and {@link #doResolveAll(String, Promise)}. */ final ConcurrentMap> resolveCache = PlatformDependent.newConcurrentHashMap(); @@ -329,7 +326,7 @@ public class DnsNameResolver extends SimpleNameResolver { } /** - * Returns the list of the protocol families of the address resolved by {@link #resolve(SocketAddress)} + * Returns the list of the protocol families of the address resolved by {@link #resolve(String)} * in the order of preference. * The default value depends on the value of the system property {@code "java.net.preferIPv6Addresses"}. * @@ -344,7 +341,7 @@ public class DnsNameResolver extends SimpleNameResolver { } /** - * Sets the list of the protocol families of the address resolved by {@link #resolve(SocketAddress)}. + * Sets the list of the protocol families of the address resolved by {@link #resolve(String)}. * Usually, both {@link InternetProtocolFamily#IPv4} and {@link InternetProtocolFamily#IPv6} are specified in the * order of preference. To enforce the resolve to retrieve the address of a specific protocol family, specify * only a single {@link InternetProtocolFamily}. @@ -382,7 +379,7 @@ public class DnsNameResolver extends SimpleNameResolver { } /** - * Sets the list of the protocol families of the address resolved by {@link #resolve(SocketAddress)}. + * Sets the list of the protocol families of the address resolved by {@link #resolve(String)}. * Usually, both {@link InternetProtocolFamily#IPv4} and {@link InternetProtocolFamily#IPv6} are specified in the * order of preference. To enforce the resolve to retrieve the address of a specific protocol family, specify * only a single {@link InternetProtocolFamily}. @@ -594,28 +591,22 @@ public class DnsNameResolver extends SimpleNameResolver { } @Override - protected boolean doIsResolved(InetSocketAddress address) { - return !address.isUnresolved(); - } - - @Override - protected void doResolve(InetSocketAddress unresolvedAddress, Promise promise) throws Exception { - final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(unresolvedAddress.getHostName()); + protected void doResolve(String inetHost, Promise promise) throws Exception { + final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(inetHost); if (bytes != null) { - // The unresolvedAddress was created via a String that contains an ipaddress. - promise.setSuccess(new InetSocketAddress(InetAddress.getByAddress(bytes), unresolvedAddress.getPort())); + // The inetHost is actually an ipaddress. + promise.setSuccess(InetAddress.getByAddress(bytes)); return; } - final String hostname = hostname(unresolvedAddress); - final int port = unresolvedAddress.getPort(); + final String hostname = hostname(inetHost); - if (!doResolveCached(hostname, port, promise)) { - doResolveUncached(hostname, port, promise); + if (!doResolveCached(hostname, promise)) { + doResolveUncached(hostname, promise); } } - private boolean doResolveCached(String hostname, int port, Promise promise) { + private boolean doResolveCached(String hostname, Promise promise) { final List cachedEntries = resolveCache.get(hostname); if (cachedEntries == null) { return false; @@ -644,7 +635,7 @@ public class DnsNameResolver extends SimpleNameResolver { } if (address != null) { - setSuccess(promise, new InetSocketAddress(address, port)); + setSuccess(promise, address); } else if (cause != null) { if (!promise.tryFailure(cause)) { logger.warn("Failed to notify failure to a promise: {}", promise, cause); @@ -656,15 +647,15 @@ public class DnsNameResolver extends SimpleNameResolver { return true; } - private static void setSuccess(Promise promise, InetSocketAddress result) { + private static void setSuccess(Promise promise, InetAddress result) { if (!promise.trySuccess(result)) { logger.warn("Failed to notify success ({}) to a promise: {}", result, promise); } } - private void doResolveUncached(String hostname, final int port, Promise promise) { - final DnsNameResolverContext ctx = - new DnsNameResolverContext(this, hostname, promise) { + private void doResolveUncached(String hostname, Promise promise) { + final DnsNameResolverContext ctx = + new DnsNameResolverContext(this, hostname, promise) { @Override protected boolean finishResolve( Class addressType, List resolvedEntries) { @@ -673,7 +664,7 @@ public class DnsNameResolver extends SimpleNameResolver { for (int i = 0; i < numEntries; i++) { final InetAddress a = resolvedEntries.get(i).address(); if (addressType.isInstance(a)) { - setSuccess(promise(), new InetSocketAddress(a, port)); + setSuccess(promise(), a); return true; } } @@ -685,32 +676,29 @@ public class DnsNameResolver extends SimpleNameResolver { } @Override - protected void doResolveAll( - InetSocketAddress unresolvedAddress, Promise> promise) throws Exception { + protected void doResolveAll(String inetHost, Promise> promise) throws Exception { - final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(unresolvedAddress.getHostName()); + final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(inetHost); if (bytes != null) { // The unresolvedAddress was created via a String that contains an ipaddress. - promise.setSuccess(Collections.singletonList( - new InetSocketAddress(InetAddress.getByAddress(bytes), unresolvedAddress.getPort()))); + promise.setSuccess(Collections.singletonList(InetAddress.getByAddress(bytes))); return; } - final String hostname = hostname(unresolvedAddress); - final int port = unresolvedAddress.getPort(); + final String hostname = hostname(inetHost); - if (!doResolveAllCached(hostname, port, promise)) { - doResolveAllUncached(hostname, port, promise); + if (!doResolveAllCached(hostname, promise)) { + doResolveAllUncached(hostname, promise); } } - private boolean doResolveAllCached(String hostname, int port, Promise> promise) { + private boolean doResolveAllCached(String hostname, Promise> promise) { final List cachedEntries = resolveCache.get(hostname); if (cachedEntries == null) { return false; } - List result = null; + List result = null; Throwable cause = null; synchronized (cachedEntries) { final int numEntries = cachedEntries.size(); @@ -724,9 +712,9 @@ public class DnsNameResolver extends SimpleNameResolver { final DnsCacheEntry e = cachedEntries.get(i); if (f.addressType().isInstance(e.address())) { if (result == null) { - result = new ArrayList(numEntries); + result = new ArrayList(numEntries); } - result.add(new InetSocketAddress(e.address(), port)); + result.add(e.address()); } } } @@ -744,23 +732,22 @@ public class DnsNameResolver extends SimpleNameResolver { return true; } - private void doResolveAllUncached(final String hostname, final int port, - final Promise> promise) { - final DnsNameResolverContext> ctx = - new DnsNameResolverContext>(this, hostname, promise) { + private void doResolveAllUncached(final String hostname, final Promise> promise) { + final DnsNameResolverContext> ctx = + new DnsNameResolverContext>(this, hostname, promise) { @Override protected boolean finishResolve( Class addressType, List resolvedEntries) { - List result = null; + List result = null; final int numEntries = resolvedEntries.size(); for (int i = 0; i < numEntries; i++) { final InetAddress a = resolvedEntries.get(i).address(); if (addressType.isInstance(a)) { if (result == null) { - result = new ArrayList(numEntries); + result = new ArrayList(numEntries); } - result.add(new InetSocketAddress(a, port)); + result.add(a); } } @@ -775,16 +762,8 @@ public class DnsNameResolver extends SimpleNameResolver { ctx.resolve(); } - private static String hostname(InetSocketAddress addr) { - // InetSocketAddress.getHostString() is available since Java 7. - final String hostname; - if (PlatformDependent.javaVersion() < 7) { - hostname = addr.getHostName(); - } else { - hostname = addr.getHostString(); - } - - return IDN.toASCII(hostname); + private static String hostname(String inetHost) { + return IDN.toASCII(inetHost); } void cache(String hostname, InetAddress address, long originalTtl) { diff --git a/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java b/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java index a1ca634386..858215aae6 100644 --- a/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java +++ b/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java @@ -320,7 +320,7 @@ public class DnsNameResolverTest { InetAddress actual = resultB.get(e.getKey()); if (!actual.equals(expected)) { // Print the content of the cache when test failure is expected. - System.err.println("Cache for " + e.getKey() + ": " + resolver.resolveAll(e.getKey(), 0).getNow()); + System.err.println("Cache for " + e.getKey() + ": " + resolver.resolveAll(e.getKey()).getNow()); } assertThat(actual, is(expected)); } @@ -347,8 +347,8 @@ public class DnsNameResolverTest { final Map results = new HashMap(); try { - final Map> futures = - new LinkedHashMap>(); + final Map> futures = + new LinkedHashMap>(); for (String name : DOMAINS) { if (excludedDomains.contains(name)) { @@ -358,19 +358,17 @@ public class DnsNameResolverTest { resolve(futures, name); } - for (Entry> e : futures.entrySet()) { - InetSocketAddress unresolved = e.getKey(); - InetSocketAddress resolved = e.getValue().sync().getNow(); + for (Entry> e : futures.entrySet()) { + String unresolved = e.getKey(); + InetAddress resolved = e.getValue().sync().getNow(); - logger.info("{}: {}", unresolved.getHostString(), resolved.getAddress().getHostAddress()); + logger.info("{}: {}", unresolved, resolved.getHostAddress()); - assertThat(resolved.isUnresolved(), is(false)); - assertThat(resolved.getHostString(), is(unresolved.getHostString())); - assertThat(resolved.getPort(), is(unresolved.getPort())); + assertThat(resolved.getHostName(), is(unresolved)); boolean typeMatches = false; for (InternetProtocolFamily f: famililies) { - Class resolvedType = resolved.getAddress().getClass(); + Class resolvedType = resolved.getClass(); if (f.addressType().isAssignableFrom(resolvedType)) { typeMatches = true; } @@ -378,7 +376,7 @@ public class DnsNameResolverTest { assertThat(typeMatches, is(true)); - results.put(resolved.getHostString(), resolved.getAddress()); + results.put(resolved.getHostName(), resolved); } } finally { resolver.setResolveAddressTypes(oldResolveAddressTypes); @@ -477,7 +475,7 @@ public class DnsNameResolverTest { private static UnknownHostException resolveNonExistentDomain() { try { - resolver.resolve("non-existent.netty.io", 0).sync(); + resolver.resolve("non-existent.netty.io").sync(); fail(); return null; } catch (Exception e) { @@ -488,20 +486,14 @@ public class DnsNameResolverTest { @Test public void testResolveIp() { - InetSocketAddress unresolved = - InetSocketAddress.createUnresolved("10.0.0.1", ThreadLocalRandom.current().nextInt(65536)); - - InetSocketAddress address = resolver.resolve(unresolved).syncUninterruptibly().getNow(); + InetAddress address = resolver.resolve("10.0.0.1").syncUninterruptibly().getNow(); assertEquals("10.0.0.1", address.getHostName()); } - private static void resolve( - Map> futures, String hostname) { - InetSocketAddress unresolved = - InetSocketAddress.createUnresolved(hostname, ThreadLocalRandom.current().nextInt(65536)); + private static void resolve(Map> futures, String hostname) { - futures.put(unresolved, resolver.resolve(unresolved)); + futures.put(hostname, resolver.resolve(hostname)); } private static void queryMx( diff --git a/resolver/src/main/java/io/netty/resolver/AbstractAddressResolver.java b/resolver/src/main/java/io/netty/resolver/AbstractAddressResolver.java new file mode 100644 index 0000000000..35ed52e3a2 --- /dev/null +++ b/resolver/src/main/java/io/netty/resolver/AbstractAddressResolver.java @@ -0,0 +1,206 @@ +/* + * Copyright 2015 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.resolver; + +import io.netty.util.concurrent.EventExecutor; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.Promise; +import io.netty.util.internal.TypeParameterMatcher; + +import java.net.SocketAddress; +import java.nio.channels.UnsupportedAddressTypeException; +import java.util.Collections; +import java.util.List; + +import static io.netty.util.internal.ObjectUtil.checkNotNull; + +/** + * A skeletal {@link AddressResolver} implementation. + */ +public abstract class AbstractAddressResolver implements AddressResolver { + + private final EventExecutor executor; + private final TypeParameterMatcher matcher; + + /** + * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned + * by {@link #resolve(SocketAddress)} + */ + protected AbstractAddressResolver(EventExecutor executor) { + this.executor = checkNotNull(executor, "executor"); + matcher = TypeParameterMatcher.find(this, AbstractAddressResolver.class, "T"); + } + + /** + * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned + * by {@link #resolve(SocketAddress)} + * @param addressType the type of the {@link SocketAddress} supported by this resolver + */ + protected AbstractAddressResolver(EventExecutor executor, Class addressType) { + this.executor = checkNotNull(executor, "executor"); + matcher = TypeParameterMatcher.get(addressType); + } + + /** + * Returns the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned + * by {@link #resolve(SocketAddress)}. + */ + protected EventExecutor executor() { + return executor; + } + + @Override + public boolean isSupported(SocketAddress address) { + return matcher.match(address); + } + + @Override + public final boolean isResolved(SocketAddress address) { + if (!isSupported(address)) { + throw new UnsupportedAddressTypeException(); + } + + @SuppressWarnings("unchecked") + final T castAddress = (T) address; + return doIsResolved(castAddress); + } + + /** + * Invoked by {@link #isResolved(SocketAddress)} to check if the specified {@code address} has been resolved + * already. + */ + protected abstract boolean doIsResolved(T address); + + @Override + public final Future resolve(SocketAddress address) { + if (!isSupported(checkNotNull(address, "address"))) { + // Address type not supported by the resolver + return executor().newFailedFuture(new UnsupportedAddressTypeException()); + } + + if (isResolved(address)) { + // Resolved already; no need to perform a lookup + @SuppressWarnings("unchecked") + final T cast = (T) address; + return executor.newSucceededFuture(cast); + } + + try { + @SuppressWarnings("unchecked") + final T cast = (T) address; + final Promise promise = executor().newPromise(); + doResolve(cast, promise); + return promise; + } catch (Exception e) { + return executor().newFailedFuture(e); + } + } + + @Override + public final Future resolve(SocketAddress address, Promise promise) { + checkNotNull(address, "address"); + checkNotNull(promise, "promise"); + + if (!isSupported(address)) { + // Address type not supported by the resolver + return promise.setFailure(new UnsupportedAddressTypeException()); + } + + if (isResolved(address)) { + // Resolved already; no need to perform a lookup + @SuppressWarnings("unchecked") + final T cast = (T) address; + return promise.setSuccess(cast); + } + + try { + @SuppressWarnings("unchecked") + final T cast = (T) address; + doResolve(cast, promise); + return promise; + } catch (Exception e) { + return promise.setFailure(e); + } + } + + @Override + public final Future> resolveAll(SocketAddress address) { + if (!isSupported(checkNotNull(address, "address"))) { + // Address type not supported by the resolver + return executor().newFailedFuture(new UnsupportedAddressTypeException()); + } + + if (isResolved(address)) { + // Resolved already; no need to perform a lookup + @SuppressWarnings("unchecked") + final T cast = (T) address; + return executor.newSucceededFuture(Collections.singletonList(cast)); + } + + try { + @SuppressWarnings("unchecked") + final T cast = (T) address; + final Promise> promise = executor().newPromise(); + doResolveAll(cast, promise); + return promise; + } catch (Exception e) { + return executor().newFailedFuture(e); + } + } + + @Override + public final Future> resolveAll(SocketAddress address, Promise> promise) { + checkNotNull(address, "address"); + checkNotNull(promise, "promise"); + + if (!isSupported(address)) { + // Address type not supported by the resolver + return promise.setFailure(new UnsupportedAddressTypeException()); + } + + if (isResolved(address)) { + // Resolved already; no need to perform a lookup + @SuppressWarnings("unchecked") + final T cast = (T) address; + return promise.setSuccess(Collections.singletonList(cast)); + } + + try { + @SuppressWarnings("unchecked") + final T cast = (T) address; + doResolveAll(cast, promise); + return promise; + } catch (Exception e) { + return promise.setFailure(e); + } + } + + /** + * Invoked by {@link #resolve(SocketAddress)} to perform the actual name + * resolution. + */ + protected abstract void doResolve(T unresolvedAddress, Promise promise) throws Exception; + + /** + * Invoked by {@link #resolveAll(SocketAddress)} to perform the actual name + * resolution. + */ + protected abstract void doResolveAll(T unresolvedAddress, Promise> promise) throws Exception; + + @Override + public void close() { } +} diff --git a/resolver/src/main/java/io/netty/resolver/AddressResolver.java b/resolver/src/main/java/io/netty/resolver/AddressResolver.java new file mode 100644 index 0000000000..85b7df47c9 --- /dev/null +++ b/resolver/src/main/java/io/netty/resolver/AddressResolver.java @@ -0,0 +1,90 @@ +/* + * Copyright 2015 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.resolver; + +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.Promise; + +import java.io.Closeable; +import java.net.SocketAddress; +import java.nio.channels.UnsupportedAddressTypeException; +import java.util.List; + +/** + * Resolves a possibility unresolved {@link {@link SocketAddress}}. + */ +public interface AddressResolver extends Closeable { + + /** + * Returns {@code true} if and only if the specified address is supported by this resolved. + */ + boolean isSupported(SocketAddress address); + + /** + * Returns {@code true} if and only if the specified address has been resolved. + * + * @throws UnsupportedAddressTypeException if the specified address is not supported by this resolver + */ + boolean isResolved(SocketAddress address); + + /** + * Resolves the specified address. If the specified address is resolved already, this method does nothing + * but returning the original address. + * + * @param address the address to resolve + * + * @return the {@link SocketAddress} as the result of the resolution + */ + Future resolve(SocketAddress address); + + /** + * Resolves the specified address. If the specified address is resolved already, this method does nothing + * but returning the original address. + * + * @param address the address to resolve + * @param promise the {@link Promise} which will be fulfilled when the name resolution is finished + * + * @return the {@link SocketAddress} as the result of the resolution + */ + Future resolve(SocketAddress address, Promise promise); + + /** + * Resolves the specified address. If the specified address is resolved already, this method does nothing + * but returning the original address. + * + * @param address the address to resolve + * + * @return the list of the {@link SocketAddress}es as the result of the resolution + */ + Future> resolveAll(SocketAddress address); + + /** + * Resolves the specified address. If the specified address is resolved already, this method does nothing + * but returning the original address. + * + * @param address the address to resolve + * @param promise the {@link Promise} which will be fulfilled when the name resolution is finished + * + * @return the list of the {@link SocketAddress}es as the result of the resolution + */ + Future> resolveAll(SocketAddress address, Promise> promise); + + /** + * Closes all the resources allocated and used by this resolver. + */ + @Override + void close(); +} diff --git a/resolver/src/main/java/io/netty/resolver/NameResolverGroup.java b/resolver/src/main/java/io/netty/resolver/AddressResolverGroup.java similarity index 76% rename from resolver/src/main/java/io/netty/resolver/NameResolverGroup.java rename to resolver/src/main/java/io/netty/resolver/AddressResolverGroup.java index 8ca35037ea..9cd0e90746 100644 --- a/resolver/src/main/java/io/netty/resolver/NameResolverGroup.java +++ b/resolver/src/main/java/io/netty/resolver/AddressResolverGroup.java @@ -31,25 +31,25 @@ import java.util.concurrent.ConcurrentMap; /** * Creates and manages {@link NameResolver}s so that each {@link EventExecutor} has its own resolver instance. */ -public abstract class NameResolverGroup implements Closeable { +public abstract class AddressResolverGroup implements Closeable { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(NameResolverGroup.class); + private static final InternalLogger logger = InternalLoggerFactory.getInstance(AddressResolverGroup.class); /** * Note that we do not use a {@link ConcurrentMap} here because it is usually expensive to instantiate a resolver. */ - private final Map> resolvers = - new IdentityHashMap>(); + private final Map> resolvers = + new IdentityHashMap>(); - protected NameResolverGroup() { } + protected AddressResolverGroup() { } /** - * Returns the {@link NameResolver} associated with the specified {@link EventExecutor}. If there's no associated + * Returns the {@link AddressResolver} associated with the specified {@link EventExecutor}. If there's no associated * resolved found, this method creates and returns a new resolver instance created by * {@link #newResolver(EventExecutor)} so that the new resolver is reused on another * {@link #getResolver(EventExecutor)} call with the same {@link EventExecutor}. */ - public NameResolver getResolver(EventExecutor executor) { + public AddressResolver getResolver(final EventExecutor executor) { if (executor == null) { throw new NullPointerException("executor"); } @@ -61,12 +61,12 @@ public abstract class NameResolverGroup implements Clos return getResolver0(executor.unwrap()); } - private NameResolver getResolver0(final EventExecutor executor) { - NameResolver r; + private AddressResolver getResolver0(final EventExecutor executor) { + AddressResolver r; synchronized (resolvers) { r = resolvers.get(executor); if (r == null) { - final NameResolver newResolver; + final AddressResolver newResolver; try { newResolver = newResolver(executor); } catch (Exception e) { @@ -90,9 +90,9 @@ public abstract class NameResolverGroup implements Clos } /** - * Invoked by {@link #getResolver(EventExecutor)} to create a new {@link NameResolver}. + * Invoked by {@link #getResolver(EventExecutor)} to create a new {@link AddressResolver}. */ - protected abstract NameResolver newResolver(EventExecutor executor) throws Exception; + protected abstract AddressResolver newResolver(EventExecutor executor) throws Exception; /** * Closes all {@link NameResolver}s created by this group. @@ -100,13 +100,13 @@ public abstract class NameResolverGroup implements Clos @Override @SuppressWarnings({ "unchecked", "SuspiciousToArrayCall" }) public void close() { - final NameResolver[] rArray; + final AddressResolver[] rArray; synchronized (resolvers) { - rArray = (NameResolver[]) resolvers.values().toArray(new NameResolver[resolvers.size()]); + rArray = (AddressResolver[]) resolvers.values().toArray(new AddressResolver[resolvers.size()]); resolvers.clear(); } - for (NameResolver r: rArray) { + for (AddressResolver r: rArray) { try { r.close(); } catch (Throwable t) { diff --git a/resolver/src/main/java/io/netty/resolver/DefaultNameResolverGroup.java b/resolver/src/main/java/io/netty/resolver/DefaultAddressResolverGroup.java similarity index 58% rename from resolver/src/main/java/io/netty/resolver/DefaultNameResolverGroup.java rename to resolver/src/main/java/io/netty/resolver/DefaultAddressResolverGroup.java index f5b76ae1e5..1b6fb53178 100644 --- a/resolver/src/main/java/io/netty/resolver/DefaultNameResolverGroup.java +++ b/resolver/src/main/java/io/netty/resolver/DefaultAddressResolverGroup.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 The Netty Project + * Copyright 2015 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 @@ -21,16 +21,16 @@ import io.netty.util.concurrent.EventExecutor; import java.net.InetSocketAddress; /** - * A {@link NameResolverGroup} of {@link DefaultNameResolver}s. + * A {@link AddressResolverGroup} of {@link DefaultNameResolver}s. */ -public final class DefaultNameResolverGroup extends NameResolverGroup { +public final class DefaultAddressResolverGroup extends AddressResolverGroup { - public static final DefaultNameResolverGroup INSTANCE = new DefaultNameResolverGroup(); + public static final DefaultAddressResolverGroup INSTANCE = new DefaultAddressResolverGroup(); - private DefaultNameResolverGroup() { } + private DefaultAddressResolverGroup() { } @Override - protected NameResolver newResolver(EventExecutor executor) throws Exception { - return new DefaultNameResolver(executor); + protected AddressResolver newResolver(EventExecutor executor) throws Exception { + return new DefaultNameResolver(executor).asAddressResolver(); } } diff --git a/resolver/src/main/java/io/netty/resolver/DefaultNameResolver.java b/resolver/src/main/java/io/netty/resolver/DefaultNameResolver.java index a34d86918b..751e463ae5 100644 --- a/resolver/src/main/java/io/netty/resolver/DefaultNameResolver.java +++ b/resolver/src/main/java/io/netty/resolver/DefaultNameResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 The Netty Project + * Copyright 2015 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 @@ -22,49 +22,32 @@ import io.netty.util.concurrent.Promise; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; -import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** - * A {@link NameResolver} that resolves an {@link InetSocketAddress} using JDK's built-in domain name lookup mechanism. + * A {@link InetNameResolver} that resolves using JDK's built-in domain name lookup mechanism. * Note that this resolver performs a blocking name lookup from the caller thread. */ -public class DefaultNameResolver extends SimpleNameResolver { +public class DefaultNameResolver extends InetNameResolver { public DefaultNameResolver(EventExecutor executor) { super(executor); } @Override - protected boolean doIsResolved(InetSocketAddress address) { - return !address.isUnresolved(); - } - - @Override - protected void doResolve(InetSocketAddress unresolvedAddress, Promise promise) throws Exception { + protected void doResolve(String inetHost, Promise promise) throws Exception { try { - // Note that InetSocketAddress.getHostName() will never incur a reverse lookup here, - // because an unresolved address always has a host name. - promise.setSuccess(new InetSocketAddress( - InetAddress.getByName(unresolvedAddress.getHostName()), unresolvedAddress.getPort())); + promise.setSuccess(InetAddress.getByName(inetHost)); } catch (UnknownHostException e) { promise.setFailure(e); } } @Override - protected void doResolveAll( - InetSocketAddress unresolvedAddress, Promise> promise) throws Exception { - + protected void doResolveAll(String inetHost, Promise> promise) throws Exception { try { - // Note that InetSocketAddress.getHostName() will never incur a reverse lookup here, - // because an unresolved address always has a host name. - final InetAddress[] resolved = InetAddress.getAllByName(unresolvedAddress.getHostName()); - final List result = new ArrayList(resolved.length); - for (InetAddress a: resolved) { - result.add(new InetSocketAddress(a, unresolvedAddress.getPort())); - } - promise.setSuccess(result); + promise.setSuccess(Arrays.asList(InetAddress.getAllByName(inetHost))); } catch (UnknownHostException e) { promise.setFailure(e); } diff --git a/resolver/src/main/java/io/netty/resolver/InetNameResolver.java b/resolver/src/main/java/io/netty/resolver/InetNameResolver.java new file mode 100644 index 0000000000..debc694aa1 --- /dev/null +++ b/resolver/src/main/java/io/netty/resolver/InetNameResolver.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 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.resolver; + +import io.netty.util.concurrent.EventExecutor; +import io.netty.util.concurrent.Future; + +import java.net.InetAddress; +import java.net.InetSocketAddress; + +/** + * A skeletal {@link NameResolver} implementation that resolves {@link InetAddress}. + */ +public abstract class InetNameResolver extends SimpleNameResolver { + + private volatile AddressResolver addressResolver; + + /** + * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned + * by {@link #resolve(String)} + */ + protected InetNameResolver(EventExecutor executor) { + super(executor); + } + + /** + * Creates a new {@link AddressResolver} that will use this name resolver underneath. + */ + public AddressResolver asAddressResolver() { + AddressResolver result = addressResolver; + if (result == null) { + synchronized (this) { + result = addressResolver; + if (result == null) { + addressResolver = result = new InetSocketAddressResolver(executor(), this); + } + } + } + return result; + } +} diff --git a/resolver/src/main/java/io/netty/resolver/InetSocketAddressResolver.java b/resolver/src/main/java/io/netty/resolver/InetSocketAddressResolver.java new file mode 100644 index 0000000000..a6114b0d9b --- /dev/null +++ b/resolver/src/main/java/io/netty/resolver/InetSocketAddressResolver.java @@ -0,0 +1,91 @@ +/* + * Copyright 2015 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.resolver; + +import io.netty.util.concurrent.EventExecutor; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import io.netty.util.concurrent.Promise; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; + +/** + * A {@link AbstractAddressResolver} that resolves {@link InetAddress}. + */ +public class InetSocketAddressResolver extends AbstractAddressResolver { + + private final NameResolver nameResolver; + + /** + * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned + * by {@link #resolve(java.net.SocketAddress)} + * @param nameResolver the {@link NameResolver} used for name resolution + */ + public InetSocketAddressResolver(EventExecutor executor, NameResolver nameResolver) { + super(executor, InetSocketAddress.class); + this.nameResolver = nameResolver; + } + + @Override + protected boolean doIsResolved(InetSocketAddress address) { + return !address.isUnresolved(); + } + + @Override + protected void doResolve(final InetSocketAddress unresolvedAddress, final Promise promise) + throws Exception { + // Note that InetSocketAddress.getHostName() will never incur a reverse lookup here, + // because an unresolved address always has a host name. + nameResolver.resolve(unresolvedAddress.getHostName()) + .addListener(new GenericFutureListener>() { + @Override + public void operationComplete(Future future) throws Exception { + if (future.isSuccess()) { + promise.setSuccess(new InetSocketAddress(future.getNow(), unresolvedAddress.getPort())); + } else { + promise.setFailure(future.cause()); + } + } + }); + } + + @Override + protected void doResolveAll(final InetSocketAddress unresolvedAddress, + final Promise> promise) throws Exception { + // Note that InetSocketAddress.getHostName() will never incur a reverse lookup here, + // because an unresolved address always has a host name. + nameResolver.resolveAll(unresolvedAddress.getHostName()) + .addListener(new GenericFutureListener>>() { + @Override + public void operationComplete(Future> future) throws Exception { + if (future.isSuccess()) { + List inetAddresses = future.getNow(); + List socketAddresses = + new ArrayList(inetAddresses.size()); + for (InetAddress inetAddress : inetAddresses) { + socketAddresses.add(new InetSocketAddress(inetAddress, unresolvedAddress.getPort())); + } + promise.setSuccess(socketAddresses); + } else { + promise.setFailure(future.cause()); + } + } + }); + } +} diff --git a/resolver/src/main/java/io/netty/resolver/NameResolver.java b/resolver/src/main/java/io/netty/resolver/NameResolver.java index 4938a43815..818122c4af 100644 --- a/resolver/src/main/java/io/netty/resolver/NameResolver.java +++ b/resolver/src/main/java/io/netty/resolver/NameResolver.java @@ -20,110 +20,50 @@ import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; import java.io.Closeable; -import java.net.SocketAddress; -import java.nio.channels.UnsupportedAddressTypeException; import java.util.List; /** - * Resolves an arbitrary string that represents the name of an endpoint into a {@link SocketAddress}. + * Resolves an arbitrary string that represents the name of an endpoint into an address. */ -public interface NameResolver extends Closeable { +public interface NameResolver extends Closeable { /** - * Returns {@code true} if and only if the specified address is supported by this resolved. - */ - boolean isSupported(SocketAddress address); - - /** - * Returns {@code true} if and only if the specified address has been resolved. - * - * @throws UnsupportedAddressTypeException if the specified address is not supported by this resolver - */ - boolean isResolved(SocketAddress address); - - /** - * Resolves the specified name into a {@link SocketAddress}. + * Resolves the specified name into an address. * * @param inetHost the name to resolve - * @param inetPort the port number * - * @return the {@link SocketAddress} as the result of the resolution + * @return the address as the result of the resolution */ - Future resolve(String inetHost, int inetPort); + Future resolve(String inetHost); /** - * Resolves the specified name into a {@link SocketAddress}. + * Resolves the specified name into an address. * * @param inetHost the name to resolve - * @param inetPort the port number * @param promise the {@link Promise} which will be fulfilled when the name resolution is finished * - * @return the {@link SocketAddress} as the result of the resolution + * @return the address as the result of the resolution */ - Future resolve(String inetHost, int inetPort, Promise promise); + Future resolve(String inetHost, Promise promise); /** - * Resolves the specified address. If the specified address is resolved already, this method does nothing - * but returning the original address. - * - * @param address the address to resolve - * - * @return the {@link SocketAddress} as the result of the resolution - */ - Future resolve(SocketAddress address); - - /** - * Resolves the specified address. If the specified address is resolved already, this method does nothing - * but returning the original address. - * - * @param address the address to resolve - * @param promise the {@link Promise} which will be fulfilled when the name resolution is finished - * - * @return the {@link SocketAddress} as the result of the resolution - */ - Future resolve(SocketAddress address, Promise promise); - - /** - * Resolves the specified host name and port into a list of {@link SocketAddress}es. + * Resolves the specified host name and port into a list of address. * * @param inetHost the name to resolve - * @param inetPort the port number * - * @return the list of the {@link SocketAddress}es as the result of the resolution + * @return the list of the address as the result of the resolution */ - Future> resolveAll(String inetHost, int inetPort); + Future> resolveAll(String inetHost); /** - * Resolves the specified host name and port into a list of {@link SocketAddress}es. + * Resolves the specified host name and port into a list of address. * * @param inetHost the name to resolve - * @param inetPort the port number * @param promise the {@link Promise} which will be fulfilled when the name resolution is finished * - * @return the list of the {@link SocketAddress}es as the result of the resolution + * @return the list of the address as the result of the resolution */ - Future> resolveAll(String inetHost, int inetPort, Promise> promise); - - /** - * Resolves the specified address. If the specified address is resolved already, this method does nothing - * but returning the original address. - * - * @param address the address to resolve - * - * @return the list of the {@link SocketAddress}es as the result of the resolution - */ - Future> resolveAll(SocketAddress address); - - /** - * Resolves the specified address. If the specified address is resolved already, this method does nothing - * but returning the original address. - * - * @param address the address to resolve - * @param promise the {@link Promise} which will be fulfilled when the name resolution is finished - * - * @return the list of the {@link SocketAddress}es as the result of the resolution - */ - Future> resolveAll(SocketAddress address, Promise> promise); + Future> resolveAll(String inetHost, Promise> promise); /** * Closes all the resources allocated and used by this resolver. diff --git a/resolver/src/main/java/io/netty/resolver/NoopNameResolver.java b/resolver/src/main/java/io/netty/resolver/NoopAddressResolver.java similarity index 85% rename from resolver/src/main/java/io/netty/resolver/NoopNameResolver.java rename to resolver/src/main/java/io/netty/resolver/NoopAddressResolver.java index 8d5999727d..c34bb576f0 100644 --- a/resolver/src/main/java/io/netty/resolver/NoopNameResolver.java +++ b/resolver/src/main/java/io/netty/resolver/NoopAddressResolver.java @@ -24,12 +24,12 @@ import java.util.Collections; import java.util.List; /** - * A {@link NameResolver} that does not perform any resolution but always reports successful resolution. + * A {@link AddressResolver} that does not perform any resolution but always reports successful resolution. * This resolver is useful when name resolution is performed by a handler in a pipeline, such as a proxy handler. */ -public class NoopNameResolver extends SimpleNameResolver { +public class NoopAddressResolver extends AbstractAddressResolver { - public NoopNameResolver(EventExecutor executor) { + public NoopAddressResolver(EventExecutor executor) { super(executor); } diff --git a/resolver/src/main/java/io/netty/resolver/NoopNameResolverGroup.java b/resolver/src/main/java/io/netty/resolver/NoopAddressResolverGroup.java similarity index 63% rename from resolver/src/main/java/io/netty/resolver/NoopNameResolverGroup.java rename to resolver/src/main/java/io/netty/resolver/NoopAddressResolverGroup.java index 7c6d601afd..980cc50d8e 100644 --- a/resolver/src/main/java/io/netty/resolver/NoopNameResolverGroup.java +++ b/resolver/src/main/java/io/netty/resolver/NoopAddressResolverGroup.java @@ -21,16 +21,16 @@ import io.netty.util.concurrent.EventExecutor; import java.net.SocketAddress; /** - * A {@link NameResolverGroup} of {@link NoopNameResolver}s. + * A {@link AddressResolverGroup} of {@link NoopAddressResolver}s. */ -public final class NoopNameResolverGroup extends NameResolverGroup { +public final class NoopAddressResolverGroup extends AddressResolverGroup { - public static final NoopNameResolverGroup INSTANCE = new NoopNameResolverGroup(); + public static final NoopAddressResolverGroup INSTANCE = new NoopAddressResolverGroup(); - private NoopNameResolverGroup() { } + private NoopAddressResolverGroup() { } @Override - protected NameResolver newResolver(EventExecutor executor) throws Exception { - return new NoopNameResolver(executor); + protected AddressResolver newResolver(EventExecutor executor) throws Exception { + return new NoopAddressResolver(executor); } } diff --git a/resolver/src/main/java/io/netty/resolver/SimpleNameResolver.java b/resolver/src/main/java/io/netty/resolver/SimpleNameResolver.java index 3c48d1e3d6..e5083975ff 100644 --- a/resolver/src/main/java/io/netty/resolver/SimpleNameResolver.java +++ b/resolver/src/main/java/io/netty/resolver/SimpleNameResolver.java @@ -19,12 +19,7 @@ package io.netty.resolver; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; -import io.netty.util.internal.TypeParameterMatcher; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.nio.channels.UnsupportedAddressTypeException; -import java.util.Collections; import java.util.List; import static io.netty.util.internal.ObjectUtil.*; @@ -32,124 +27,39 @@ import static io.netty.util.internal.ObjectUtil.*; /** * A skeletal {@link NameResolver} implementation. */ -public abstract class SimpleNameResolver implements NameResolver { +public abstract class SimpleNameResolver implements NameResolver { private final EventExecutor executor; - private final TypeParameterMatcher matcher; /** * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned - * by {@link #resolve(SocketAddress)} + * by {@link #resolve(String)} */ protected SimpleNameResolver(EventExecutor executor) { - if (executor == null) { - throw new NullPointerException("executor"); - } - - this.executor = executor; - matcher = TypeParameterMatcher.find(this, SimpleNameResolver.class, "T"); - } - - /** - * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned - * by {@link #resolve(SocketAddress)} - * @param addressType the type of the {@link SocketAddress} supported by this resolver - */ - protected SimpleNameResolver(EventExecutor executor, Class addressType) { - if (executor == null) { - throw new NullPointerException("executor"); - } - - this.executor = executor; - matcher = TypeParameterMatcher.get(addressType); + this.executor = checkNotNull(executor, "executor"); } /** * Returns the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned - * by {@link #resolve(SocketAddress)}. + * by {@link #resolve(String)}. */ protected EventExecutor executor() { return executor; } @Override - public boolean isSupported(SocketAddress address) { - return matcher.match(address); + public final Future resolve(String inetHost) { + final Promise promise = executor().newPromise(); + return resolve(inetHost, promise); } @Override - public final boolean isResolved(SocketAddress address) { - if (!isSupported(address)) { - throw new UnsupportedAddressTypeException(); - } - - @SuppressWarnings("unchecked") - final T castAddress = (T) address; - return doIsResolved(castAddress); - } - - /** - * Invoked by {@link #isResolved(SocketAddress)} to check if the specified {@code address} has been resolved - * already. - */ - protected abstract boolean doIsResolved(T address); - - @Override - public final Future resolve(String inetHost, int inetPort) { - return resolve(InetSocketAddress.createUnresolved(checkNotNull(inetHost, "inetHost"), inetPort)); - } - - @Override - public Future resolve(String inetHost, int inetPort, Promise promise) { - return resolve(InetSocketAddress.createUnresolved(checkNotNull(inetHost, "inetHost"), inetPort), promise); - } - - @Override - public final Future resolve(SocketAddress address) { - if (!isSupported(checkNotNull(address, "address"))) { - // Address type not supported by the resolver - return executor().newFailedFuture(new UnsupportedAddressTypeException()); - } - - if (isResolved(address)) { - // Resolved already; no need to perform a lookup - @SuppressWarnings("unchecked") - final T cast = (T) address; - return executor.newSucceededFuture(cast); - } - - try { - @SuppressWarnings("unchecked") - final T cast = (T) address; - final Promise promise = executor().newPromise(); - doResolve(cast, promise); - return promise; - } catch (Exception e) { - return executor().newFailedFuture(e); - } - } - - @Override - public final Future resolve(SocketAddress address, Promise promise) { - checkNotNull(address, "address"); + public Future resolve(String inetHost, Promise promise) { + checkNotNull(inetHost, "inetHost"); checkNotNull(promise, "promise"); - if (!isSupported(address)) { - // Address type not supported by the resolver - return promise.setFailure(new UnsupportedAddressTypeException()); - } - - if (isResolved(address)) { - // Resolved already; no need to perform a lookup - @SuppressWarnings("unchecked") - final T cast = (T) address; - return promise.setSuccess(cast); - } - try { - @SuppressWarnings("unchecked") - final T cast = (T) address; - doResolve(cast, promise); + doResolve(inetHost, promise); return promise; } catch (Exception e) { return promise.setFailure(e); @@ -157,61 +67,18 @@ public abstract class SimpleNameResolver implements Nam } @Override - public final Future> resolveAll(String inetHost, int inetPort) { - return resolveAll(InetSocketAddress.createUnresolved(checkNotNull(inetHost, "inetHost"), inetPort)); + public final Future> resolveAll(String inetHost) { + final Promise> promise = executor().newPromise(); + return resolveAll(inetHost, promise); } @Override - public Future> resolveAll(String inetHost, int inetPort, Promise> promise) { - return resolveAll(InetSocketAddress.createUnresolved(checkNotNull(inetHost, "inetHost"), inetPort), promise); - } - - @Override - public final Future> resolveAll(SocketAddress address) { - if (!isSupported(checkNotNull(address, "address"))) { - // Address type not supported by the resolver - return executor().newFailedFuture(new UnsupportedAddressTypeException()); - } - - if (isResolved(address)) { - // Resolved already; no need to perform a lookup - @SuppressWarnings("unchecked") - final T cast = (T) address; - return executor.newSucceededFuture(Collections.singletonList(cast)); - } - - try { - @SuppressWarnings("unchecked") - final T cast = (T) address; - final Promise> promise = executor().newPromise(); - doResolveAll(cast, promise); - return promise; - } catch (Exception e) { - return executor().newFailedFuture(e); - } - } - - @Override - public final Future> resolveAll(SocketAddress address, Promise> promise) { - checkNotNull(address, "address"); + public Future> resolveAll(String inetHost, Promise> promise) { + checkNotNull(inetHost, "inetHost"); checkNotNull(promise, "promise"); - if (!isSupported(address)) { - // Address type not supported by the resolver - return promise.setFailure(new UnsupportedAddressTypeException()); - } - - if (isResolved(address)) { - // Resolved already; no need to perform a lookup - @SuppressWarnings("unchecked") - final T cast = (T) address; - return promise.setSuccess(Collections.singletonList(cast)); - } - try { - @SuppressWarnings("unchecked") - final T cast = (T) address; - doResolveAll(cast, promise); + doResolveAll(inetHost, promise); return promise; } catch (Exception e) { return promise.setFailure(e); @@ -219,16 +86,14 @@ public abstract class SimpleNameResolver implements Nam } /** - * Invoked by {@link #resolve(SocketAddress)} and {@link #resolve(String, int)} to perform the actual name - * resolution. + * Invoked by {@link #resolve(String)} to perform the actual name resolution. */ - protected abstract void doResolve(T unresolvedAddress, Promise promise) throws Exception; + protected abstract void doResolve(String inetHost, Promise promise) throws Exception; /** - * Invoked by {@link #resolveAll(SocketAddress)} and {@link #resolveAll(String, int)} to perform the actual name - * resolution. + * Invoked by {@link #resolveAll(String)} to perform the actual name resolution. */ - protected abstract void doResolveAll(T unresolvedAddress, Promise> promise) throws Exception; + protected abstract void doResolveAll(String inetHost, Promise> promise) throws Exception; @Override public void close() { } diff --git a/resolver/src/main/java/io/netty/resolver/package-info.java b/resolver/src/main/java/io/netty/resolver/package-info.java index 33c69307b5..a92459842a 100644 --- a/resolver/src/main/java/io/netty/resolver/package-info.java +++ b/resolver/src/main/java/io/netty/resolver/package-info.java @@ -15,6 +15,6 @@ */ /** - * Resolves an arbitrary string that represents the name of an endpoint into a {@link java.net.SocketAddress}. + * Resolves an arbitrary string that represents the name of an endpoint into an address. */ package io.netty.resolver; diff --git a/transport/src/main/java/io/netty/bootstrap/Bootstrap.java b/transport/src/main/java/io/netty/bootstrap/Bootstrap.java index 7317d8cfb7..0805b91d38 100644 --- a/transport/src/main/java/io/netty/bootstrap/Bootstrap.java +++ b/transport/src/main/java/io/netty/bootstrap/Bootstrap.java @@ -23,9 +23,10 @@ import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPromise; import io.netty.channel.EventLoop; import io.netty.channel.EventLoopGroup; -import io.netty.resolver.DefaultNameResolverGroup; +import io.netty.resolver.AddressResolver; +import io.netty.resolver.DefaultAddressResolverGroup; import io.netty.resolver.NameResolver; -import io.netty.resolver.NameResolverGroup; +import io.netty.resolver.AddressResolverGroup; import io.netty.util.AttributeKey; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.FutureListener; @@ -50,10 +51,11 @@ public class Bootstrap extends AbstractBootstrap { private static final InternalLogger logger = InternalLoggerFactory.getInstance(Bootstrap.class); - private static final NameResolverGroup DEFAULT_RESOLVER = DefaultNameResolverGroup.INSTANCE; + private static final AddressResolverGroup DEFAULT_RESOLVER = DefaultAddressResolverGroup.INSTANCE; @SuppressWarnings("unchecked") - private volatile NameResolverGroup resolver = (NameResolverGroup) DEFAULT_RESOLVER; + private volatile AddressResolverGroup resolver = + (AddressResolverGroup) DEFAULT_RESOLVER; private volatile SocketAddress remoteAddress; public Bootstrap() { } @@ -68,11 +70,11 @@ public class Bootstrap extends AbstractBootstrap { * Sets the {@link NameResolver} which will resolve the address of the unresolved named address. */ @SuppressWarnings("unchecked") - public Bootstrap resolver(NameResolverGroup resolver) { + public Bootstrap resolver(AddressResolverGroup resolver) { if (resolver == null) { throw new NullPointerException("resolver"); } - this.resolver = (NameResolverGroup) resolver; + this.resolver = (AddressResolverGroup) resolver; return this; } @@ -162,7 +164,7 @@ public class Bootstrap extends AbstractBootstrap { final Channel channel = regFuture.channel(); final EventLoop eventLoop = channel.eventLoop(); - final NameResolver resolver = this.resolver.getResolver(eventLoop); + final AddressResolver resolver = this.resolver.getResolver(eventLoop); if (!resolver.isSupported(remoteAddress) || resolver.isResolved(remoteAddress)) { // Resolver has no idea about what to do with the specified remote address or it's resolved already. diff --git a/transport/src/test/java/io/netty/bootstrap/BootstrapTest.java b/transport/src/test/java/io/netty/bootstrap/BootstrapTest.java index 230ea5e3ae..24b5a7754b 100644 --- a/transport/src/test/java/io/netty/bootstrap/BootstrapTest.java +++ b/transport/src/test/java/io/netty/bootstrap/BootstrapTest.java @@ -30,9 +30,9 @@ import io.netty.channel.ServerChannel; import io.netty.channel.local.LocalAddress; import io.netty.channel.local.LocalChannel; import io.netty.channel.local.LocalServerChannel; -import io.netty.resolver.NameResolver; -import io.netty.resolver.NameResolverGroup; -import io.netty.resolver.SimpleNameResolver; +import io.netty.resolver.AddressResolver; +import io.netty.resolver.AddressResolverGroup; +import io.netty.resolver.AbstractAddressResolver; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; @@ -221,7 +221,7 @@ public class BootstrapTest { final Bootstrap bootstrapA = new Bootstrap(); bootstrapA.group(groupA); bootstrapA.channel(LocalChannel.class); - bootstrapA.resolver(new TestNameResolverGroup(true)); + bootstrapA.resolver(new TestAddressResolverGroup(true)); bootstrapA.handler(dummyHandler); final ServerBootstrap bootstrapB = new ServerBootstrap(); @@ -240,7 +240,7 @@ public class BootstrapTest { final Bootstrap bootstrapA = new Bootstrap(); bootstrapA.group(groupA); bootstrapA.channel(LocalChannel.class); - bootstrapA.resolver(new TestNameResolverGroup(false)); + bootstrapA.resolver(new TestAddressResolverGroup(false)); bootstrapA.handler(dummyHandler); final ServerBootstrap bootstrapB = new ServerBootstrap(); @@ -282,17 +282,17 @@ public class BootstrapTest { @Sharable private static final class DummyHandler extends ChannelHandlerAdapter { } - private static final class TestNameResolverGroup extends NameResolverGroup { + private static final class TestAddressResolverGroup extends AddressResolverGroup { private final boolean success; - TestNameResolverGroup(boolean success) { + TestAddressResolverGroup(boolean success) { this.success = success; } @Override - protected NameResolver newResolver(EventExecutor executor) throws Exception { - return new SimpleNameResolver(executor) { + protected AddressResolver newResolver(EventExecutor executor) throws Exception { + return new AbstractAddressResolver(executor) { @Override protected boolean doIsResolved(SocketAddress address) {