View Javadoc
1   /*
2    * Copyright 2014 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.netty.resolver.dns;
18  
19  import io.netty.channel.ChannelFactory;
20  import io.netty.channel.EventLoop;
21  import io.netty.channel.socket.DatagramChannel;
22  import io.netty.resolver.AddressResolver;
23  import io.netty.resolver.AddressResolverGroup;
24  import io.netty.resolver.InetSocketAddressResolver;
25  import io.netty.resolver.NameResolver;
26  import io.netty.util.concurrent.EventExecutor;
27  import io.netty.util.concurrent.Promise;
28  import io.netty.util.internal.StringUtil;
29  
30  import java.net.InetAddress;
31  import java.net.InetSocketAddress;
32  import java.util.List;
33  import java.util.concurrent.ConcurrentHashMap;
34  import java.util.concurrent.ConcurrentMap;
35  
36  /**
37   * A {@link AddressResolverGroup} of {@link DnsNameResolver}s.
38   */
39  public class DnsAddressResolverGroup extends AddressResolverGroup<InetSocketAddress> {
40  
41      private final DnsNameResolverBuilder dnsResolverBuilder;
42  
43      private final ConcurrentMap<String, Promise<InetAddress>> resolvesInProgress = new ConcurrentHashMap<>();
44      private final ConcurrentMap<String, Promise<List<InetAddress>>> resolveAllsInProgress = new ConcurrentHashMap<>();
45  
46      public DnsAddressResolverGroup(DnsNameResolverBuilder dnsResolverBuilder) {
47          this.dnsResolverBuilder = withSharedCaches(dnsResolverBuilder.copy());
48      }
49  
50      public DnsAddressResolverGroup(
51              Class<? extends DatagramChannel> channelType,
52              DnsServerAddressStreamProvider nameServerProvider) {
53          this.dnsResolverBuilder = withSharedCaches(new DnsNameResolverBuilder());
54          dnsResolverBuilder.datagramChannelType(channelType).nameServerProvider(nameServerProvider);
55      }
56  
57      public DnsAddressResolverGroup(
58              ChannelFactory<? extends DatagramChannel> channelFactory,
59              DnsServerAddressStreamProvider nameServerProvider) {
60          this.dnsResolverBuilder = withSharedCaches(new DnsNameResolverBuilder());
61          dnsResolverBuilder.datagramChannelFactory(channelFactory).nameServerProvider(nameServerProvider);
62      }
63  
64      private static DnsNameResolverBuilder withSharedCaches(DnsNameResolverBuilder dnsResolverBuilder) {
65          /// To avoid each member of the group having its own cache we either use the configured cache
66          // or create a new one to share among the entire group.
67          return dnsResolverBuilder.resolveCache(dnsResolverBuilder.getOrNewCache())
68                  .cnameCache(dnsResolverBuilder.getOrNewCnameCache())
69                  .authoritativeDnsServerCache(dnsResolverBuilder.getOrNewAuthoritativeDnsServerCache());
70      }
71  
72      @SuppressWarnings("deprecation")
73      @Override
74      protected final AddressResolver<InetSocketAddress> newResolver(EventExecutor executor) throws Exception {
75          if (!(executor instanceof EventLoop)) {
76              throw new IllegalStateException(
77                      "unsupported executor type: " + StringUtil.simpleClassName(executor) +
78                      " (expected: " + StringUtil.simpleClassName(EventLoop.class));
79          }
80  
81          // we don't really need to pass channelFactory and nameServerProvider separately,
82          // but still keep this to ensure backward compatibility with (potentially) override methods
83          EventLoop loop = dnsResolverBuilder.eventLoop;
84          return newResolver(loop == null ? (EventLoop) executor : loop,
85                  dnsResolverBuilder.datagramChannelFactory(),
86                  dnsResolverBuilder.nameServerProvider());
87      }
88  
89      /**
90       * @deprecated Override {@link #newNameResolver(EventLoop, ChannelFactory, DnsServerAddressStreamProvider)}.
91       */
92      @Deprecated
93      protected AddressResolver<InetSocketAddress> newResolver(
94              EventLoop eventLoop, ChannelFactory<? extends DatagramChannel> channelFactory,
95              DnsServerAddressStreamProvider nameServerProvider) throws Exception {
96  
97          final NameResolver<InetAddress> resolver = new InflightNameResolver<InetAddress>(
98                  eventLoop,
99                  newNameResolver(eventLoop, channelFactory, nameServerProvider),
100                 resolvesInProgress,
101                 resolveAllsInProgress);
102 
103         return newAddressResolver(eventLoop, resolver);
104     }
105 
106     /**
107      * Creates a new {@link NameResolver}. Override this method to create an alternative {@link NameResolver}
108      * implementation or override the default configuration.
109      */
110     protected NameResolver<InetAddress> newNameResolver(EventLoop eventLoop,
111                                                         ChannelFactory<? extends DatagramChannel> channelFactory,
112                                                         DnsServerAddressStreamProvider nameServerProvider)
113             throws Exception {
114         DnsNameResolverBuilder builder = dnsResolverBuilder.copy();
115 
116         // once again, channelFactory and nameServerProvider are most probably set in builder already,
117         // but I do reassign them again to avoid corner cases with override methods
118         return builder.eventLoop(eventLoop)
119                 .datagramChannelFactory(channelFactory)
120                 .nameServerProvider(nameServerProvider)
121                 .build();
122     }
123 
124     /**
125      * Creates a new {@link AddressResolver}. Override this method to create an alternative {@link AddressResolver}
126      * implementation or override the default configuration.
127      */
128     protected AddressResolver<InetSocketAddress> newAddressResolver(EventLoop eventLoop,
129                                                                     NameResolver<InetAddress> resolver)
130             throws Exception {
131         return new InetSocketAddressResolver(eventLoop, resolver);
132     }
133 }