Name resolver API + implementations

(This is a work in progress)

This pull request adds a new interface called `NameResolver`, which is designed to perform an asynchronous name resolusion such as DNS loopkup.

Currently, there's only one implementation - `JdkDomainNameResolver`, which simply delegates the resolution request to `InetAddress.getByName()`.  Eventually, I'm going to add a fully working asynchronous DNS resolver on top of netty-codec-dns in a separate package.

`Bootstrap` now has a new option that allows you to specify the resolver to use.  Right before a connection attempt is made, `Bootstrap` resolves the remote address using the resolver:

```java
EventLoopGroup group = ...;
EventLoop loop = group.next();
AsyncDomainNameResolver resolver = new AsyncDomainNameResolver(loop);
Bootstrap b = ...;
b.group(loop); // Make sure to use the same event loop for resolver and the actual connection.
b.resolver(resolver);
// Internally, Bootstrap.connect(inetHost, inetPort) uses InetSocketAddress.createUnresolved(...)
// instead of `new InetSocketAddress(...)` to avoid immediate name lookup via JDK.
b.connect("host", port);
```

The caveat with the current API is that a `NameResolver` is tied to an `EventLoop`, because otherwise there's no way to tell the resolver to use the same event loop with the actual connection attempt.  We could probably add `EventExecutor` or `EventLoop` to `NameResolver.resolve()` as a parameter instead, so that `Bootstrap` can simply tell the resolver to use the same event loop.  However, it should be noted that 1) not all resolvers do resolution using Netty API and 2) an OIO event loop is supposed to handle only one single channel.

Besides fully asynchronous DNS resolution, this feature has a lot of potential; imagine you implement:

* fully configurable name cache that works for all resolver types
* resolver that uses other protocols than DNS, such as Zookeeper


Because Java generics suck? :-)
Initially, NameResolver had a type parameter as you suggested and thus we
didn't have this casting problem.  Maybe I'll add it back when the API
settles down.
2014. 9. 20. 오전 3:06에 "Norman Maurer" <notifications@github.com>님이 작성:

> In transport/src/main/java/io/netty/resolver/JdkDomainNameResolver.java:
>
> > +            throw new NullPointerException("unresolvedAddress");
> > +        }
> > +
> > +        if (!(unresolvedAddress instanceof InetSocketAddress)) {
> > +            return executor().newFailedFuture(new UnsupportedAddressTypeException());
> > +        }
> > +
> > +        final InetSocketAddress unresolvedInetAddress = (InetSocketAddress) unresolvedAddress;
> > +        if (!unresolvedInetAddress.isUnresolved()) {
> > +            // Resolved already.  No need to perform a lookup.
> > +            return executor().newSucceededFuture(unresolvedAddress);
> > +        }
> > +
> > +        try {
> > +            return executor().newSucceededFuture(
> > +                    (SocketAddress) new InetSocketAddress(
>
> why is this cast even necessary ?
>
> —
> Reply to this email directly or view it on GitHub
> <https://github.com/netty/netty/pull/2917/files#r17799337>.
>