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  package io.netty.resolver;
17  
18  import io.netty.util.concurrent.EventExecutor;
19  import io.netty.util.concurrent.Future;
20  import io.netty.util.concurrent.FutureListener;
21  import io.netty.util.concurrent.Promise;
22  import io.netty.util.internal.ObjectUtil;
23  
24  import java.util.Arrays;
25  import java.util.List;
26  
27  import static io.netty.util.internal.ObjectUtil.checkNotNull;
28  
29  /**
30   * A composite {@link SimpleNameResolver} that resolves a host name against a sequence of {@link NameResolver}s.
31   *
32   * In case of a failure, only the last one will be reported.
33   */
34  public final class CompositeNameResolver<T> extends SimpleNameResolver<T> {
35  
36      private final NameResolver<T>[] resolvers;
37  
38      /**
39       * @param executor the {@link EventExecutor} which is used to notify the listeners of the {@link Future} returned
40       *                 by {@link #resolve(String)}
41       * @param resolvers the {@link NameResolver}s to be tried sequentially
42       */
43      public CompositeNameResolver(EventExecutor executor, NameResolver<T>... resolvers) {
44          super(executor);
45          checkNotNull(resolvers, "resolvers");
46          for (int i = 0; i < resolvers.length; i++) {
47              ObjectUtil.checkNotNull(resolvers[i], "resolvers[" + i + ']');
48          }
49          if (resolvers.length < 2) {
50              throw new IllegalArgumentException("resolvers: " + Arrays.asList(resolvers) +
51                      " (expected: at least 2 resolvers)");
52          }
53          this.resolvers = resolvers.clone();
54      }
55  
56      @Override
57      protected void doResolve(String inetHost, Promise<T> promise) throws Exception {
58          doResolveRec(inetHost, promise, 0, null);
59      }
60  
61      private void doResolveRec(final String inetHost,
62                                final Promise<T> promise,
63                                final int resolverIndex,
64                                Throwable lastFailure) throws Exception {
65          if (resolverIndex >= resolvers.length) {
66              promise.setFailure(lastFailure);
67          } else {
68              NameResolver<T> resolver = resolvers[resolverIndex];
69              resolver.resolve(inetHost).addListener(new FutureListener<T>() {
70                  @Override
71                  public void operationComplete(Future<T> future) throws Exception {
72                      if (future.isSuccess()) {
73                          promise.setSuccess(future.getNow());
74                      } else {
75                          doResolveRec(inetHost, promise, resolverIndex + 1, future.cause());
76                      }
77                  }
78              });
79          }
80      }
81  
82      @Override
83      protected void doResolveAll(String inetHost, Promise<List<T>> promise) throws Exception {
84          doResolveAllRec(inetHost, promise, 0, null);
85      }
86  
87      private void doResolveAllRec(final String inetHost,
88                                final Promise<List<T>> promise,
89                                final int resolverIndex,
90                                Throwable lastFailure) throws Exception {
91          if (resolverIndex >= resolvers.length) {
92              promise.setFailure(lastFailure);
93          } else {
94              NameResolver<T> resolver = resolvers[resolverIndex];
95              resolver.resolveAll(inetHost).addListener(new FutureListener<List<T>>() {
96                  @Override
97                  public void operationComplete(Future<List<T>> future) throws Exception {
98                      if (future.isSuccess()) {
99                          promise.setSuccess(future.getNow());
100                     } else {
101                         doResolveAllRec(inetHost, promise, resolverIndex + 1, future.cause());
102                     }
103                 }
104             });
105         }
106     }
107 }