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.netty5.resolver;
18  
19  import io.netty5.util.concurrent.EventExecutor;
20  import io.netty5.util.concurrent.Future;
21  import io.netty5.util.concurrent.Promise;
22  import io.netty5.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 java.util.Objects.requireNonNull;
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 = requireNonNull(executor, "executor");
45          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 = requireNonNull(executor, "executor");
55          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(requireNonNull(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.asFuture();
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         requireNonNull(address, "address");
116         requireNonNull(promise, "promise");
117 
118         if (!isSupported(address)) {
119             // Address type not supported by the resolver
120             promise.setFailure(new UnsupportedAddressTypeException());
121             return promise.asFuture();
122         }
123 
124         if (isResolved(address)) {
125             // Resolved already; no need to perform a lookup
126             @SuppressWarnings("unchecked")
127             final T cast = (T) address;
128             promise.setSuccess(cast);
129             return promise.asFuture();
130         }
131 
132         try {
133             @SuppressWarnings("unchecked")
134             final T cast = (T) address;
135             doResolve(cast, promise);
136         } catch (Exception e) {
137             promise.setFailure(e);
138         }
139         return promise.asFuture();
140     }
141 
142     @Override
143     public final Future<List<T>> resolveAll(SocketAddress address) {
144         if (!isSupported(requireNonNull(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.asFuture();
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         requireNonNull(address, "address");
170         requireNonNull(promise, "promise");
171 
172         if (!isSupported(address)) {
173             // Address type not supported by the resolver
174             promise.setFailure(new UnsupportedAddressTypeException());
175             return promise.asFuture();
176         }
177 
178         if (isResolved(address)) {
179             // Resolved already; no need to perform a lookup
180             @SuppressWarnings("unchecked")
181             final T cast = (T) address;
182             promise.setSuccess(Collections.singletonList(cast));
183             return promise.asFuture();
184         }
185 
186         try {
187             @SuppressWarnings("unchecked")
188             final T cast = (T) address;
189             doResolveAll(cast, promise);
190         } catch (Exception e) {
191             promise.setFailure(e);
192         }
193         return promise.asFuture();
194     }
195 
196     /**
197      * Invoked by {@link #resolve(SocketAddress)} to perform the actual name
198      * resolution.
199      */
200     protected abstract void doResolve(T unresolvedAddress, Promise<T> promise) throws Exception;
201 
202     /**
203      * Invoked by {@link #resolveAll(SocketAddress)} to perform the actual name
204      * resolution.
205      */
206     protected abstract void doResolveAll(T unresolvedAddress, Promise<List<T>> promise) throws Exception;
207 
208     @Override
209     public void close() { }
210 }