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