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<InetAddress>.
This commit is contained in:
Stephane Landelle 2015-12-13 00:11:59 +01:00 committed by Norman Maurer
parent 89ff831a67
commit 6393506b97
18 changed files with 602 additions and 400 deletions

View File

@ -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.DefaultThreadFactory;
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<SocketChannel>() {
@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<SocketChannel>() {
@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<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {

View File

@ -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<InetSocketAddress> {
public class DnsAddressResolverGroup extends AddressResolverGroup<InetSocketAddress> {
private final ChannelFactory<? extends DatagramChannel> channelFactory;
private final InetSocketAddress localAddress;
private final DnsServerAddresses nameServerAddresses;
public DnsNameResolverGroup(
public DnsAddressResolverGroup(
Class<? extends DatagramChannel> channelType, DnsServerAddresses nameServerAddresses) {
this(channelType, ANY_LOCAL_ADDR, nameServerAddresses);
}
public DnsNameResolverGroup(
public DnsAddressResolverGroup(
Class<? extends DatagramChannel> channelType,
InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) {
this(new ReflectiveChannelFactory<DatagramChannel>(channelType), localAddress, nameServerAddresses);
}
public DnsNameResolverGroup(
public DnsAddressResolverGroup(
ChannelFactory<? extends DatagramChannel> channelFactory, DnsServerAddresses nameServerAddresses) {
this(channelFactory, ANY_LOCAL_ADDR, nameServerAddresses);
}
public DnsNameResolverGroup(
public DnsAddressResolverGroup(
ChannelFactory<? extends DatagramChannel> channelFactory,
InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) {
this.channelFactory = channelFactory;
@ -63,7 +63,7 @@ public class DnsNameResolverGroup extends NameResolverGroup<InetSocketAddress> {
}
@Override
protected final NameResolver<InetSocketAddress> newResolver(EventExecutor executor) throws Exception {
protected final AddressResolver<InetSocketAddress> 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<InetSocketAddress> {
* 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<InetSocketAddress> newResolver(
EventLoop eventLoop, ChannelFactory<? extends DatagramChannel> channelFactory,
InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) throws Exception {
return new DnsNameResolver(
eventLoop, channelFactory, localAddress, nameServerAddresses);
return new DnsNameResolver(eventLoop, channelFactory, localAddress, nameServerAddresses)
.asAddressResolver();
}
}

View File

@ -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<InetSocketAddress> {
public class DnsNameResolver extends InetNameResolver {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(DnsNameResolver.class);
@ -74,7 +71,7 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
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<InetSocketAddress> {
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<String, List<DnsCacheEntry>> resolveCache = PlatformDependent.newConcurrentHashMap();
@ -329,7 +326,7 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
}
/**
* 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<InetSocketAddress> {
}
/**
* 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<InetSocketAddress> {
}
/**
* 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<InetSocketAddress> {
}
@Override
protected boolean doIsResolved(InetSocketAddress address) {
return !address.isUnresolved();
}
@Override
protected void doResolve(InetSocketAddress unresolvedAddress, Promise<InetSocketAddress> promise) throws Exception {
final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(unresolvedAddress.getHostName());
protected void doResolve(String inetHost, Promise<InetAddress> 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<InetSocketAddress> promise) {
private boolean doResolveCached(String hostname, Promise<InetAddress> promise) {
final List<DnsCacheEntry> cachedEntries = resolveCache.get(hostname);
if (cachedEntries == null) {
return false;
@ -644,7 +635,7 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
}
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<InetSocketAddress> {
return true;
}
private static void setSuccess(Promise<InetSocketAddress> promise, InetSocketAddress result) {
private static void setSuccess(Promise<InetAddress> 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<InetSocketAddress> promise) {
final DnsNameResolverContext<InetSocketAddress> ctx =
new DnsNameResolverContext<InetSocketAddress>(this, hostname, promise) {
private void doResolveUncached(String hostname, Promise<InetAddress> promise) {
final DnsNameResolverContext<InetAddress> ctx =
new DnsNameResolverContext<InetAddress>(this, hostname, promise) {
@Override
protected boolean finishResolve(
Class<? extends InetAddress> addressType, List<DnsCacheEntry> resolvedEntries) {
@ -673,7 +664,7 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
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<InetSocketAddress> {
}
@Override
protected void doResolveAll(
InetSocketAddress unresolvedAddress, Promise<List<InetSocketAddress>> promise) throws Exception {
protected void doResolveAll(String inetHost, Promise<List<InetAddress>> 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<List<InetSocketAddress>> promise) {
private boolean doResolveAllCached(String hostname, Promise<List<InetAddress>> promise) {
final List<DnsCacheEntry> cachedEntries = resolveCache.get(hostname);
if (cachedEntries == null) {
return false;
}
List<InetSocketAddress> result = null;
List<InetAddress> result = null;
Throwable cause = null;
synchronized (cachedEntries) {
final int numEntries = cachedEntries.size();
@ -724,9 +712,9 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
final DnsCacheEntry e = cachedEntries.get(i);
if (f.addressType().isInstance(e.address())) {
if (result == null) {
result = new ArrayList<InetSocketAddress>(numEntries);
result = new ArrayList<InetAddress>(numEntries);
}
result.add(new InetSocketAddress(e.address(), port));
result.add(e.address());
}
}
}
@ -744,23 +732,22 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
return true;
}
private void doResolveAllUncached(final String hostname, final int port,
final Promise<List<InetSocketAddress>> promise) {
final DnsNameResolverContext<List<InetSocketAddress>> ctx =
new DnsNameResolverContext<List<InetSocketAddress>>(this, hostname, promise) {
private void doResolveAllUncached(final String hostname, final Promise<List<InetAddress>> promise) {
final DnsNameResolverContext<List<InetAddress>> ctx =
new DnsNameResolverContext<List<InetAddress>>(this, hostname, promise) {
@Override
protected boolean finishResolve(
Class<? extends InetAddress> addressType, List<DnsCacheEntry> resolvedEntries) {
List<InetSocketAddress> result = null;
List<InetAddress> 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<InetSocketAddress>(numEntries);
result = new ArrayList<InetAddress>(numEntries);
}
result.add(new InetSocketAddress(a, port));
result.add(a);
}
}
@ -775,16 +762,8 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
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) {

View File

@ -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<String, InetAddress> results = new HashMap<String, InetAddress>();
try {
final Map<InetSocketAddress, Future<InetSocketAddress>> futures =
new LinkedHashMap<InetSocketAddress, Future<InetSocketAddress>>();
final Map<String, Future<InetAddress>> futures =
new LinkedHashMap<String, Future<InetAddress>>();
for (String name : DOMAINS) {
if (excludedDomains.contains(name)) {
@ -358,19 +358,17 @@ public class DnsNameResolverTest {
resolve(futures, name);
}
for (Entry<InetSocketAddress, Future<InetSocketAddress>> e : futures.entrySet()) {
InetSocketAddress unresolved = e.getKey();
InetSocketAddress resolved = e.getValue().sync().getNow();
for (Entry<String, Future<InetAddress>> 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<InetSocketAddress, Future<InetSocketAddress>> futures, String hostname) {
InetSocketAddress unresolved =
InetSocketAddress.createUnresolved(hostname, ThreadLocalRandom.current().nextInt(65536));
private static void resolve(Map<String, Future<InetAddress>> futures, String hostname) {
futures.put(unresolved, resolver.resolve(unresolved));
futures.put(hostname, resolver.resolve(hostname));
}
private static void queryMx(

View File

@ -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<T extends SocketAddress> implements AddressResolver<T> {
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<? extends T> 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<T> 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<T> promise = executor().newPromise();
doResolve(cast, promise);
return promise;
} catch (Exception e) {
return executor().newFailedFuture(e);
}
}
@Override
public final Future<T> resolve(SocketAddress address, Promise<T> 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<List<T>> 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<List<T>> promise = executor().newPromise();
doResolveAll(cast, promise);
return promise;
} catch (Exception e) {
return executor().newFailedFuture(e);
}
}
@Override
public final Future<List<T>> resolveAll(SocketAddress address, Promise<List<T>> 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<T> promise) throws Exception;
/**
* Invoked by {@link #resolveAll(SocketAddress)} to perform the actual name
* resolution.
*/
protected abstract void doResolveAll(T unresolvedAddress, Promise<List<T>> promise) throws Exception;
@Override
public void close() { }
}

View File

@ -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<T extends SocketAddress> 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<T> 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<T> resolve(SocketAddress address, Promise<T> 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<List<T>> 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<List<T>> resolveAll(SocketAddress address, Promise<List<T>> promise);
/**
* Closes all the resources allocated and used by this resolver.
*/
@Override
void close();
}

View File

@ -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<T extends SocketAddress> implements Closeable {
public abstract class AddressResolverGroup<T extends SocketAddress> 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<EventExecutor, NameResolver<T>> resolvers =
new IdentityHashMap<EventExecutor, NameResolver<T>>();
private final Map<EventExecutor, AddressResolver<T>> resolvers =
new IdentityHashMap<EventExecutor, AddressResolver<T>>();
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<T> getResolver(final EventExecutor executor) {
public AddressResolver<T> getResolver(final EventExecutor executor) {
if (executor == null) {
throw new NullPointerException("executor");
}
@ -58,11 +58,11 @@ public abstract class NameResolverGroup<T extends SocketAddress> implements Clos
throw new IllegalStateException("executor not accepting a task");
}
NameResolver<T> r;
AddressResolver<T> r;
synchronized (resolvers) {
r = resolvers.get(executor);
if (r == null) {
final NameResolver<T> newResolver;
final AddressResolver<T> newResolver;
try {
newResolver = newResolver(executor);
} catch (Exception e) {
@ -86,9 +86,9 @@ public abstract class NameResolverGroup<T extends SocketAddress> 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<T> newResolver(EventExecutor executor) throws Exception;
protected abstract AddressResolver<T> newResolver(EventExecutor executor) throws Exception;
/**
* Closes all {@link NameResolver}s created by this group.
@ -96,13 +96,13 @@ public abstract class NameResolverGroup<T extends SocketAddress> implements Clos
@Override
@SuppressWarnings({ "unchecked", "SuspiciousToArrayCall" })
public void close() {
final NameResolver<T>[] rArray;
final AddressResolver<T>[] rArray;
synchronized (resolvers) {
rArray = (NameResolver<T>[]) resolvers.values().toArray(new NameResolver[resolvers.size()]);
rArray = (AddressResolver<T>[]) resolvers.values().toArray(new AddressResolver[resolvers.size()]);
resolvers.clear();
}
for (NameResolver<T> r: rArray) {
for (AddressResolver<T> r: rArray) {
try {
r.close();
} catch (Throwable t) {

View File

@ -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<InetSocketAddress> {
public final class DefaultAddressResolverGroup extends AddressResolverGroup<InetSocketAddress> {
public static final DefaultNameResolverGroup INSTANCE = new DefaultNameResolverGroup();
public static final DefaultAddressResolverGroup INSTANCE = new DefaultAddressResolverGroup();
private DefaultNameResolverGroup() { }
private DefaultAddressResolverGroup() { }
@Override
protected NameResolver<InetSocketAddress> newResolver(EventExecutor executor) throws Exception {
return new DefaultNameResolver(executor);
protected AddressResolver<InetSocketAddress> newResolver(EventExecutor executor) throws Exception {
return new DefaultNameResolver(executor).asAddressResolver();
}
}

View File

@ -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<InetSocketAddress> {
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<InetSocketAddress> promise) throws Exception {
protected void doResolve(String inetHost, Promise<InetAddress> 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<List<InetSocketAddress>> promise) throws Exception {
protected void doResolveAll(String inetHost, Promise<List<InetAddress>> 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<InetSocketAddress> result = new ArrayList<InetSocketAddress>(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);
}

View File

@ -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<InetAddress> {
private volatile AddressResolver<InetSocketAddress> 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<InetSocketAddress> asAddressResolver() {
AddressResolver<InetSocketAddress> result = addressResolver;
if (result == null) {
synchronized (this) {
result = addressResolver;
if (result == null) {
addressResolver = result = new InetSocketAddressResolver(executor(), this);
}
}
}
return result;
}
}

View File

@ -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<InetSocketAddress> {
private final NameResolver<InetAddress> 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<InetAddress> 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<InetSocketAddress> 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<Future<InetAddress>>() {
@Override
public void operationComplete(Future<InetAddress> 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<List<InetSocketAddress>> 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<Future<List<InetAddress>>>() {
@Override
public void operationComplete(Future<List<InetAddress>> future) throws Exception {
if (future.isSuccess()) {
List<InetAddress> inetAddresses = future.getNow();
List<InetSocketAddress> socketAddresses =
new ArrayList<InetSocketAddress>(inetAddresses.size());
for (InetAddress inetAddress : inetAddresses) {
socketAddresses.add(new InetSocketAddress(inetAddress, unresolvedAddress.getPort()));
}
promise.setSuccess(socketAddresses);
} else {
promise.setFailure(future.cause());
}
}
});
}
}

View File

@ -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<T extends SocketAddress> extends Closeable {
public interface NameResolver<T> 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<T> resolve(String inetHost, int inetPort);
Future<T> 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<T> resolve(String inetHost, int inetPort, Promise<T> promise);
Future<T> resolve(String inetHost, Promise<T> 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<T> 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<T> resolve(SocketAddress address, Promise<T> 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<List<T>> resolveAll(String inetHost, int inetPort);
Future<List<T>> 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<List<T>> resolveAll(String inetHost, int inetPort, Promise<List<T>> 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<List<T>> 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<List<T>> resolveAll(SocketAddress address, Promise<List<T>> promise);
Future<List<T>> resolveAll(String inetHost, Promise<List<T>> promise);
/**
* Closes all the resources allocated and used by this resolver.

View File

@ -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<SocketAddress> {
public class NoopAddressResolver extends AbstractAddressResolver<SocketAddress> {
public NoopNameResolver(EventExecutor executor) {
public NoopAddressResolver(EventExecutor executor) {
super(executor);
}

View File

@ -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<SocketAddress> {
public final class NoopAddressResolverGroup extends AddressResolverGroup<SocketAddress> {
public static final NoopNameResolverGroup INSTANCE = new NoopNameResolverGroup();
public static final NoopAddressResolverGroup INSTANCE = new NoopAddressResolverGroup();
private NoopNameResolverGroup() { }
private NoopAddressResolverGroup() { }
@Override
protected NameResolver<SocketAddress> newResolver(EventExecutor executor) throws Exception {
return new NoopNameResolver(executor);
protected AddressResolver<SocketAddress> newResolver(EventExecutor executor) throws Exception {
return new NoopAddressResolver(executor);
}
}

View File

@ -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<T extends SocketAddress> implements NameResolver<T> {
public abstract class SimpleNameResolver<T> implements NameResolver<T> {
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<? extends T> 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<T> resolve(String inetHost) {
final Promise<T> 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<T> resolve(String inetHost, int inetPort) {
return resolve(InetSocketAddress.createUnresolved(checkNotNull(inetHost, "inetHost"), inetPort));
}
@Override
public Future<T> resolve(String inetHost, int inetPort, Promise<T> promise) {
return resolve(InetSocketAddress.createUnresolved(checkNotNull(inetHost, "inetHost"), inetPort), promise);
}
@Override
public final Future<T> 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<T> promise = executor().newPromise();
doResolve(cast, promise);
return promise;
} catch (Exception e) {
return executor().newFailedFuture(e);
}
}
@Override
public final Future<T> resolve(SocketAddress address, Promise<T> promise) {
checkNotNull(address, "address");
public Future<T> resolve(String inetHost, Promise<T> 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<T extends SocketAddress> implements Nam
}
@Override
public final Future<List<T>> resolveAll(String inetHost, int inetPort) {
return resolveAll(InetSocketAddress.createUnresolved(checkNotNull(inetHost, "inetHost"), inetPort));
public final Future<List<T>> resolveAll(String inetHost) {
final Promise<List<T>> promise = executor().newPromise();
return resolveAll(inetHost, promise);
}
@Override
public Future<List<T>> resolveAll(String inetHost, int inetPort, Promise<List<T>> promise) {
return resolveAll(InetSocketAddress.createUnresolved(checkNotNull(inetHost, "inetHost"), inetPort), promise);
}
@Override
public final Future<List<T>> 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<List<T>> promise = executor().newPromise();
doResolveAll(cast, promise);
return promise;
} catch (Exception e) {
return executor().newFailedFuture(e);
}
}
@Override
public final Future<List<T>> resolveAll(SocketAddress address, Promise<List<T>> promise) {
checkNotNull(address, "address");
public Future<List<T>> resolveAll(String inetHost, Promise<List<T>> 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<T extends SocketAddress> 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<T> promise) throws Exception;
protected abstract void doResolve(String inetHost, Promise<T> 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<List<T>> promise) throws Exception;
protected abstract void doResolveAll(String inetHost, Promise<List<T>> promise) throws Exception;
@Override
public void close() { }

View File

@ -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;

View File

@ -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<Bootstrap, Channel> {
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<SocketAddress> resolver = (NameResolverGroup<SocketAddress>) DEFAULT_RESOLVER;
private volatile AddressResolverGroup<SocketAddress> resolver =
(AddressResolverGroup<SocketAddress>) DEFAULT_RESOLVER;
private volatile SocketAddress remoteAddress;
public Bootstrap() { }
@ -68,11 +70,11 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
* 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<SocketAddress>) resolver;
this.resolver = (AddressResolverGroup<SocketAddress>) resolver;
return this;
}
@ -162,7 +164,7 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
final Channel channel = regFuture.channel();
final EventLoop eventLoop = channel.eventLoop();
final NameResolver<SocketAddress> resolver = this.resolver.getResolver(eventLoop);
final AddressResolver<SocketAddress> 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.

View File

@ -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;
@ -223,7 +223,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();
@ -242,7 +242,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();
@ -284,17 +284,17 @@ public class BootstrapTest {
@Sharable
private static final class DummyHandler extends ChannelInboundHandlerAdapter { }
private static final class TestNameResolverGroup extends NameResolverGroup<SocketAddress> {
private static final class TestAddressResolverGroup extends AddressResolverGroup<SocketAddress> {
private final boolean success;
TestNameResolverGroup(boolean success) {
TestAddressResolverGroup(boolean success) {
this.success = success;
}
@Override
protected NameResolver<SocketAddress> newResolver(EventExecutor executor) throws Exception {
return new SimpleNameResolver<SocketAddress>(executor) {
protected AddressResolver<SocketAddress> newResolver(EventExecutor executor) throws Exception {
return new AbstractAddressResolver<SocketAddress>(executor) {
@Override
protected boolean doIsResolved(SocketAddress address) {