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    *   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.dns;
18  
19  import io.netty.util.internal.UnstableApi;
20  
21  import java.net.InetSocketAddress;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.List;
25  
26  import static io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider.defaultAddressArray;
27  
28  /**
29   * Provides an infinite sequence of DNS server addresses to {@link DnsNameResolver}.
30   */
31  @UnstableApi
32  @SuppressWarnings("IteratorNextCanNotThrowNoSuchElementException")
33  public abstract class DnsServerAddresses {
34      /**
35       * @deprecated Use {@link DefaultDnsServerAddressStreamProvider#defaultAddressList()}.
36       * <p>
37       * Returns the list of the system DNS server addresses. If it failed to retrieve the list of the system DNS server
38       * addresses from the environment, it will return {@code "8.8.8.8"} and {@code "8.8.4.4"}, the addresses of the
39       * Google public DNS servers.
40       */
41      @Deprecated
42      public static List<InetSocketAddress> defaultAddressList() {
43          return DefaultDnsServerAddressStreamProvider.defaultAddressList();
44      }
45  
46      /**
47       * @deprecated Use {@link DefaultDnsServerAddressStreamProvider#defaultAddresses()}.
48       * <p>
49       * Returns the {@link DnsServerAddresses} that yields the system DNS server addresses sequentially. If it failed to
50       * retrieve the list of the system DNS server addresses from the environment, it will use {@code "8.8.8.8"} and
51       * {@code "8.8.4.4"}, the addresses of the Google public DNS servers.
52       * <p>
53       * This method has the same effect with the following code:
54       * <pre>
55       * DnsServerAddresses.sequential(DnsServerAddresses.defaultAddressList());
56       * </pre>
57       * </p>
58       */
59      @Deprecated
60      public static DnsServerAddresses defaultAddresses() {
61          return DefaultDnsServerAddressStreamProvider.defaultAddresses();
62      }
63  
64      /**
65       * Returns the {@link DnsServerAddresses} that yields the specified {@code addresses} sequentially. Once the
66       * last address is yielded, it will start again from the first address.
67       */
68      public static DnsServerAddresses sequential(Iterable<? extends InetSocketAddress> addresses) {
69          return sequential0(sanitize(addresses));
70      }
71  
72      /**
73       * Returns the {@link DnsServerAddresses} that yields the specified {@code addresses} sequentially. Once the
74       * last address is yielded, it will start again from the first address.
75       */
76      public static DnsServerAddresses sequential(InetSocketAddress... addresses) {
77          return sequential0(sanitize(addresses));
78      }
79  
80      private static DnsServerAddresses sequential0(final InetSocketAddress... addresses) {
81          if (addresses.length == 1) {
82              return singleton(addresses[0]);
83          }
84  
85          return new DefaultDnsServerAddresses("sequential", addresses) {
86              @Override
87              public DnsServerAddressStream stream() {
88                  return new SequentialDnsServerAddressStream(addresses, 0);
89              }
90          };
91      }
92  
93      /**
94       * Returns the {@link DnsServerAddresses} that yields the specified {@code address} in a shuffled order. Once all
95       * addresses are yielded, the addresses are shuffled again.
96       */
97      public static DnsServerAddresses shuffled(Iterable<? extends InetSocketAddress> addresses) {
98          return shuffled0(sanitize(addresses));
99      }
100 
101     /**
102      * Returns the {@link DnsServerAddresses} that yields the specified {@code addresses} in a shuffled order. Once all
103      * addresses are yielded, the addresses are shuffled again.
104      */
105     public static DnsServerAddresses shuffled(InetSocketAddress... addresses) {
106         return shuffled0(sanitize(addresses));
107     }
108 
109     private static DnsServerAddresses shuffled0(final InetSocketAddress[] addresses) {
110         if (addresses.length == 1) {
111             return singleton(addresses[0]);
112         }
113 
114         return new DefaultDnsServerAddresses("shuffled", addresses) {
115             @Override
116             public DnsServerAddressStream stream() {
117                 return new ShuffledDnsServerAddressStream(addresses);
118             }
119         };
120     }
121 
122     /**
123      * Returns the {@link DnsServerAddresses} that yields the specified {@code addresses} in a rotational sequential
124      * order. It is similar to {@link #sequential(Iterable)}, but each {@link DnsServerAddressStream} starts from
125      * a different starting point.  For example, the first {@link #stream()} will start from the first address, the
126      * second one will start from the second address, and so on.
127      */
128     public static DnsServerAddresses rotational(Iterable<? extends InetSocketAddress> addresses) {
129         return rotational0(sanitize(addresses));
130     }
131 
132     /**
133      * Returns the {@link DnsServerAddresses} that yields the specified {@code addresses} in a rotational sequential
134      * order. It is similar to {@link #sequential(Iterable)}, but each {@link DnsServerAddressStream} starts from
135      * a different starting point.  For example, the first {@link #stream()} will start from the first address, the
136      * second one will start from the second address, and so on.
137      */
138     public static DnsServerAddresses rotational(InetSocketAddress... addresses) {
139         return rotational0(sanitize(addresses));
140     }
141 
142     private static DnsServerAddresses rotational0(final InetSocketAddress[] addresses) {
143         if (addresses.length == 1) {
144             return singleton(addresses[0]);
145         }
146 
147         return new RotationalDnsServerAddresses(addresses);
148     }
149 
150     /**
151      * Returns the {@link DnsServerAddresses} that yields only a single {@code address}.
152      */
153     public static DnsServerAddresses singleton(final InetSocketAddress address) {
154         if (address == null) {
155             throw new NullPointerException("address");
156         }
157         if (address.isUnresolved()) {
158             throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + address);
159         }
160 
161         return new SingletonDnsServerAddresses(address);
162     }
163 
164     private static InetSocketAddress[] sanitize(Iterable<? extends InetSocketAddress> addresses) {
165         if (addresses == null) {
166             throw new NullPointerException("addresses");
167         }
168 
169         final List<InetSocketAddress> list;
170         if (addresses instanceof Collection) {
171             list = new ArrayList<InetSocketAddress>(((Collection<?>) addresses).size());
172         } else {
173             list = new ArrayList<InetSocketAddress>(4);
174         }
175 
176         for (InetSocketAddress a : addresses) {
177             if (a == null) {
178                 break;
179             }
180             if (a.isUnresolved()) {
181                 throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + a);
182             }
183             list.add(a);
184         }
185 
186         if (list.isEmpty()) {
187             throw new IllegalArgumentException("empty addresses");
188         }
189 
190         return list.toArray(new InetSocketAddress[list.size()]);
191     }
192 
193     private static InetSocketAddress[] sanitize(InetSocketAddress[] addresses) {
194         if (addresses == null) {
195             throw new NullPointerException("addresses");
196         }
197 
198         List<InetSocketAddress> list = new ArrayList<InetSocketAddress>(addresses.length);
199         for (InetSocketAddress a: addresses) {
200             if (a == null) {
201                 break;
202             }
203             if (a.isUnresolved()) {
204                 throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + a);
205             }
206             list.add(a);
207         }
208 
209         if (list.isEmpty()) {
210             return defaultAddressArray();
211         }
212 
213         return list.toArray(new InetSocketAddress[list.size()]);
214     }
215 
216     /**
217      * Starts a new infinite stream of DNS server addresses. This method is invoked by {@link DnsNameResolver} on every
218      * uncached {@link DnsNameResolver#resolve(String)}or {@link DnsNameResolver#resolveAll(String)}.
219      */
220     public abstract DnsServerAddressStream stream();
221 }