View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package io.netty.resolver;
18  
19  import io.netty.util.concurrent.EventExecutor;
20  import io.netty.util.concurrent.Future;
21  import io.netty.util.concurrent.Promise;
22  import io.netty.util.internal.TypeParameterMatcher;
23  
24  import java.net.InetSocketAddress;
25  import java.net.SocketAddress;
26  import java.nio.channels.UnsupportedAddressTypeException;
27  
28  /**
29   * A skeletal {@link NameResolver} implementation.
30   */
31  public abstract class SimpleNameResolver<T extends SocketAddress> implements NameResolver<T> {
32  
33      private final EventExecutor executor;
34      private final TypeParameterMatcher matcher;
35  
36      /**
37       * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned
38       *                 by {@link #resolve(SocketAddress)}
39       */
40      protected SimpleNameResolver(EventExecutor executor) {
41          if (executor == null) {
42              throw new NullPointerException("executor");
43          }
44  
45          this.executor = executor;
46          matcher = TypeParameterMatcher.find(this, SimpleNameResolver.class, "T");
47      }
48  
49      /**
50       * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned
51       *                 by {@link #resolve(SocketAddress)}
52       * @param addressType the type of the {@link SocketAddress} supported by this resolver
53       */
54      protected SimpleNameResolver(EventExecutor executor, Class<? extends T> addressType) {
55          if (executor == null) {
56              throw new NullPointerException("executor");
57          }
58  
59          this.executor = executor;
60          matcher = TypeParameterMatcher.get(addressType);
61      }
62  
63      /**
64       * Returns the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned
65       * by {@link #resolve(SocketAddress)}.
66       */
67      protected EventExecutor executor() {
68          return executor;
69      }
70  
71      @Override
72      public boolean isSupported(SocketAddress address) {
73          return matcher.match(address);
74      }
75  
76      @Override
77      public final boolean isResolved(SocketAddress address) {
78          if (!isSupported(address)) {
79              throw new UnsupportedAddressTypeException();
80          }
81  
82          @SuppressWarnings("unchecked")
83          final T castAddress = (T) address;
84          return doIsResolved(castAddress);
85      }
86  
87      /**
88       * Invoked by {@link #isResolved(SocketAddress)} to check if the specified {@code address} has been resolved
89       * already.
90       */
91      protected abstract boolean doIsResolved(T address);
92  
93      @Override
94      public final Future<T> resolve(String inetHost, int inetPort) {
95          if (inetHost == null) {
96              throw new NullPointerException("inetHost");
97          }
98  
99          return resolve(InetSocketAddress.createUnresolved(inetHost, inetPort));
100     }
101 
102     @Override
103     public Future<T> resolve(String inetHost, int inetPort, Promise<T> promise) {
104         if (inetHost == null) {
105             throw new NullPointerException("inetHost");
106         }
107 
108         return resolve(InetSocketAddress.createUnresolved(inetHost, inetPort), promise);
109     }
110 
111     @Override
112     public final Future<T> resolve(SocketAddress address) {
113         if (address == null) {
114             throw new NullPointerException("unresolvedAddress");
115         }
116 
117         if (!isSupported(address)) {
118             // Address type not supported by the resolver
119             return executor().newFailedFuture(new UnsupportedAddressTypeException());
120         }
121 
122         if (isResolved(address)) {
123             // Resolved already; no need to perform a lookup
124             @SuppressWarnings("unchecked")
125             final T cast = (T) address;
126             return executor.newSucceededFuture(cast);
127         }
128 
129         try {
130             @SuppressWarnings("unchecked")
131             final T cast = (T) address;
132             final Promise<T> promise = executor().newPromise();
133             doResolve(cast, promise);
134             return promise;
135         } catch (Exception e) {
136             return executor().newFailedFuture(e);
137         }
138     }
139 
140     @Override
141     public final Future<T> resolve(SocketAddress address, Promise<T> promise) {
142         if (address == null) {
143             throw new NullPointerException("unresolvedAddress");
144         }
145         if (promise == null) {
146             throw new NullPointerException("promise");
147         }
148 
149         if (!isSupported(address)) {
150             // Address type not supported by the resolver
151             return promise.setFailure(new UnsupportedAddressTypeException());
152         }
153 
154         if (isResolved(address)) {
155             // Resolved already; no need to perform a lookup
156             @SuppressWarnings("unchecked")
157             final T cast = (T) address;
158             return promise.setSuccess(cast);
159         }
160 
161         try {
162             @SuppressWarnings("unchecked")
163             final T cast = (T) address;
164             doResolve(cast, promise);
165             return promise;
166         } catch (Exception e) {
167             return promise.setFailure(e);
168         }
169     }
170 
171     /**
172      * Invoked by {@link #resolve(SocketAddress)} and {@link #resolve(String, int)} to perform the actual name
173      * resolution.
174      */
175     protected abstract void doResolve(T unresolvedAddress, Promise<T> promise) throws Exception;
176 
177     @Override
178     public void close() { }
179 }