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
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 }
207