View Javadoc
1   /*
2    * Copyright 2015 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    *   https://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.SocketAddress;
25  import java.nio.channels.UnsupportedAddressTypeException;
26  import java.util.Collections;
27  import java.util.List;
28  
29  import static io.netty.util.internal.ObjectUtil.checkNotNull;
30  
31  /**
32   * A skeletal {@link AddressResolver} implementation.
33   */
34  public abstract class AbstractAddressResolver<T extends SocketAddress> implements AddressResolver<T> {
35  
36      private final EventExecutor executor;
37      private final TypeParameterMatcher matcher;
38  
39      /**
40       * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned
41       *                 by {@link #resolve(SocketAddress)}
42       */
43      protected AbstractAddressResolver(EventExecutor executor) {
44          this.executor = checkNotNull(executor, "executor");
45          this.matcher = TypeParameterMatcher.find(this, AbstractAddressResolver.class, "T");
46      }
47  
48      /**
49       * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned
50       *                 by {@link #resolve(SocketAddress)}
51       * @param addressType the type of the {@link SocketAddress} supported by this resolver
52       */
53      protected AbstractAddressResolver(EventExecutor executor, Class<? extends T> addressType) {
54          this.executor = checkNotNull(executor, "executor");
55          this.matcher = TypeParameterMatcher.get(addressType);
56      }
57  
58      /**
59       * Returns the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned
60       * by {@link #resolve(SocketAddress)}.
61       */
62      protected EventExecutor executor() {
63          return executor;
64      }
65  
66      @Override
67      public boolean isSupported(SocketAddress address) {
68          return matcher.match(address);
69      }
70  
71      @Override
72      public final boolean isResolved(SocketAddress address) {
73          if (!isSupported(address)) {
74              throw new UnsupportedAddressTypeException();
75          }
76  
77          @SuppressWarnings("unchecked")
78          final T castAddress = (T) address;
79          return doIsResolved(castAddress);
80      }
81  
82      /**
83       * Invoked by {@link #isResolved(SocketAddress)} to check if the specified {@code address} has been resolved
84       * already.
85       */
86      protected abstract boolean doIsResolved(T address);
87  
88      @Override
89      public final Future<T> resolve(SocketAddress address) {
90          if (!isSupported(checkNotNull(address, "address"))) {
91              // Address type not supported by the resolver
92              return executor().newFailedFuture(new UnsupportedAddressTypeException());
93          }
94  
95          if (isResolved(address)) {
96              // Resolved already; no need to perform a lookup
97              @SuppressWarnings("unchecked")
98              final T cast = (T) address;
99              return executor.newSucceededFuture(cast);
100         }
101 
102         try {
103             @SuppressWarnings("unchecked")
104             final T cast = (T) address;
105             final Promise<T> promise = executor().newPromise();
106             doResolve(cast, promise);
107             return promise;
108         } catch (Exception e) {
109             return executor().newFailedFuture(e);
110         }
111     }
112 
113     @Override
114     public final Future<T> resolve(SocketAddress address, Promise<T> promise) {
115         checkNotNull(address, "address");
116         checkNotNull(promise, "promise");
117 
118         if (!isSupported(address)) {
119             // Address type not supported by the resolver
120             return promise.setFailure(new UnsupportedAddressTypeException());
121         }
122 
123         if (isResolved(address)) {
124             // Resolved already; no need to perform a lookup
125             @SuppressWarnings("unchecked")
126             final T cast = (T) address;
127             return promise.setSuccess(cast);
128         }
129 
130         try {
131             @SuppressWarnings("unchecked")
132             final T cast = (T) address;
133             doResolve(cast, promise);
134             return promise;
135         } catch (Exception e) {
136             return promise.setFailure(e);
137         }
138     }
139 
140     @Override
141     public final Future<List<T>> resolveAll(SocketAddress address) {
142         if (!isSupported(checkNotNull(address, "address"))) {
143             // Address type not supported by the resolver
144             return executor().newFailedFuture(new UnsupportedAddressTypeException());
145         }
146 
147         if (isResolved(address)) {
148             // Resolved already; no need to perform a lookup
149             @SuppressWarnings("unchecked")
150             final T cast = (T) address;
151             return executor.newSucceededFuture(Collections.singletonList(cast));
152         }
153 
154         try {
155             @SuppressWarnings("unchecked")
156             final T cast = (T) address;
157             final Promise<List<T>> promise = executor().newPromise();
158             doResolveAll(cast, promise);
159             return promise;
160         } catch (Exception e) {
161             return executor().newFailedFuture(e);
162         }
163     }
164 
165     @Override
166     public final Future<List<T>> resolveAll(SocketAddress address, Promise<List<T>> promise) {
167         checkNotNull(address, "address");
168         checkNotNull(promise, "promise");
169 
170         if (!isSupported(address)) {
171             // Address type not supported by the resolver
172             return promise.setFailure(new UnsupportedAddressTypeException());
173         }
174 
175         if (isResolved(address)) {
176             // Resolved already; no need to perform a lookup
177             @SuppressWarnings("unchecked")
178             final T cast = (T) address;
179             return promise.setSuccess(Collections.singletonList(cast));
180         }
181 
182         try {
183             @SuppressWarnings("unchecked")
184             final T cast = (T) address;
185             doResolveAll(cast, promise);
186             return promise;
187         } catch (Exception e) {
188             return promise.setFailure(e);
189         }
190     }
191 
192     /**
193      * Invoked by {@link #resolve(SocketAddress)} to perform the actual name
194      * resolution.
195      */
196     protected abstract void doResolve(T unresolvedAddress, Promise<T> promise) throws Exception;
197 
198     /**
199      * Invoked by {@link #resolveAll(SocketAddress)} to perform the actual name
200      * resolution.
201      */
202     protected abstract void doResolveAll(T unresolvedAddress, Promise<List<T>> promise) throws Exception;
203 
204     @Override
205     public void close() { }
206 }