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