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