2 // ========================================================================
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.util;
21 import java.net.InetSocketAddress;
22 import java.net.SocketAddress;
23 import java.nio.channels.UnresolvedAddressException;
24 import java.util.concurrent.Executor;
25 import java.util.concurrent.TimeUnit;
26 import java.util.concurrent.TimeoutException;
27 import java.util.concurrent.atomic.AtomicBoolean;
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.log.Logger;
31 import org.eclipse.jetty.util.thread.Scheduler;
34 * Creates asynchronously {@link SocketAddress} instances, returning them through a {@link Promise},
35 * in order to avoid blocking on DNS lookup.
37 * {@link InetSocketAddress#InetSocketAddress(String, int)} attempts to perform a DNS resolution of
38 * the host name, and this may block for several seconds.
39 * This class creates the {@link InetSocketAddress} in a separate thread and provides the result
40 * through a {@link Promise}, with the possibility to specify a timeout for the operation.
44 * SocketAddressResolver resolver = new SocketAddressResolver(executor, scheduler);
45 * resolver.resolve("www.google.com", 80, new Promise<SocketAddress>()
47 * public void succeeded(SocketAddress result)
49 * // The address was resolved
52 * public void failed(Throwable failure)
54 * // The address resolution failed
59 public class SocketAddressResolver
61 private static final Logger LOG = Log.getLogger(SocketAddressResolver.class);
63 private final Executor executor;
64 private final Scheduler scheduler;
65 private final long timeout;
68 * Creates a new instance with the given executor (to perform DNS resolution in a separate thread),
69 * the given scheduler (to cancel the operation if it takes too long) and the given timeout, in milliseconds.
71 * @param executor the thread pool to use to perform DNS resolution in pooled threads
72 * @param scheduler the scheduler to schedule tasks to cancel DNS resolution if it takes too long
73 * @param timeout the timeout, in milliseconds, for the DNS resolution to complete
75 public SocketAddressResolver(Executor executor, Scheduler scheduler, long timeout)
77 this.executor = executor;
78 this.scheduler = scheduler;
79 this.timeout = timeout;
82 public Executor getExecutor()
87 public Scheduler getScheduler()
92 public long getTimeout()
98 * Resolves the given host and port, returning a {@link SocketAddress} through the given {@link Promise}
99 * with the default timeout.
101 * @param host the host to resolve
102 * @param port the port of the resulting socket address
103 * @param promise the callback invoked when the resolution succeeds or fails
104 * @see #resolve(String, int, long, Promise)
106 public void resolve(String host, int port, Promise<SocketAddress> promise)
108 resolve(host, port, timeout, promise);
112 * Resolves the given host and port, returning a {@link SocketAddress} through the given {@link Promise}
113 * with the given timeout.
115 * @param host the host to resolve
116 * @param port the port of the resulting socket address
117 * @param timeout the timeout, in milliseconds, for the DNS resolution to complete
118 * @param promise the callback invoked when the resolution succeeds or fails
120 protected void resolve(final String host, final int port, final long timeout, final Promise<SocketAddress> promise)
122 executor.execute(new Runnable()
127 Scheduler.Task task = null;
128 final AtomicBoolean complete = new AtomicBoolean();
131 final Thread thread = Thread.currentThread();
132 task = scheduler.schedule(new Runnable()
137 if (complete.compareAndSet(false, true))
139 promise.failed(new TimeoutException());
143 }, timeout, TimeUnit.MILLISECONDS);
148 long start = System.nanoTime();
149 InetSocketAddress result = new InetSocketAddress(host, port);
150 long elapsed = System.nanoTime() - start;
151 LOG.debug("Resolved {} in {} ms", host, TimeUnit.NANOSECONDS.toMillis(elapsed));
152 if (complete.compareAndSet(false, true))
154 if (result.isUnresolved())
155 promise.failed(new UnresolvedAddressException());
157 promise.succeeded(result);
162 if (complete.compareAndSet(false, true))
169 // Reset the interrupted status before releasing the thread to the pool
170 Thread.interrupted();