Import atomix/{storage,utils}
[controller.git] / third-party / atomix / utils / src / main / java / io / atomix / utils / net / Address.java
1 /*
2  * Copyright 2015-present Open Networking Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package io.atomix.utils.net;
17
18 import java.net.Inet6Address;
19 import java.net.InetAddress;
20 import java.net.UnknownHostException;
21 import java.util.Objects;
22
23 /**
24  * Representation of a network address.
25  */
26 public final class Address {
27   private static final int DEFAULT_PORT = 5679;
28
29   /**
30    * Address type.
31    */
32   public enum Type {
33     IPV4,
34     IPV6,
35   }
36
37   /**
38    * Returns an address that binds to all interfaces.
39    *
40    * @return the address
41    */
42   public static Address local() {
43     return from(DEFAULT_PORT);
44   }
45
46   /**
47    * Returns the address from the given host:port string.
48    *
49    * @param address the address string
50    * @return the address
51    */
52   public static Address from(String address) {
53     int lastColon = address.lastIndexOf(':');
54     int openBracket = address.indexOf('[');
55     int closeBracket = address.indexOf(']');
56
57     String host;
58     if (openBracket != -1 && closeBracket != -1) {
59       host = address.substring(openBracket + 1, closeBracket);
60     } else if (lastColon != -1) {
61       host = address.substring(0, lastColon);
62     } else {
63       host = address;
64     }
65
66     int port;
67     if (lastColon != -1) {
68       try {
69         port = Integer.parseInt(address.substring(lastColon + 1));
70       } catch (NumberFormatException e) {
71         throw new MalformedAddressException(address, e);
72       }
73     } else {
74       port = DEFAULT_PORT;
75     }
76     return new Address(host, port);
77   }
78
79   /**
80    * Returns an address for the given host/port.
81    *
82    * @param host the host name
83    * @param port the port
84    * @return a new address
85    */
86   public static Address from(String host, int port) {
87     return new Address(host, port);
88   }
89
90   /**
91    * Returns an address for the local host and the given port.
92    *
93    * @param port the port
94    * @return a new address
95    */
96   public static Address from(int port) {
97     try {
98       InetAddress address = getLocalAddress();
99       return new Address(address.getHostName(), port);
100     } catch (UnknownHostException e) {
101       throw new IllegalArgumentException("Failed to locate host", e);
102     }
103   }
104
105   /**
106    * Returns the local host.
107    */
108   private static InetAddress getLocalAddress() throws UnknownHostException {
109     try {
110       return InetAddress.getLocalHost();  // first NIC
111     } catch (Exception ignore) {
112       return InetAddress.getByName(null);
113     }
114   }
115
116   private final String host;
117   private final int port;
118   private transient volatile Type type;
119   private transient volatile InetAddress address;
120
121   public Address(String host, int port) {
122     this(host, port, null);
123   }
124
125   public Address(String host, int port, InetAddress address) {
126     this.host = host;
127     this.port = port;
128     this.address = address;
129     if (address != null) {
130       this.type = address instanceof Inet6Address ? Type.IPV6 : Type.IPV4;
131     }
132   }
133
134   /**
135    * Returns the host name.
136    *
137    * @return the host name
138    */
139   public String host() {
140     return host;
141   }
142
143   /**
144    * Returns the port.
145    *
146    * @return the port
147    */
148   public int port() {
149     return port;
150   }
151
152   /**
153    * Returns the IP address.
154    *
155    * @return the IP address
156    */
157   public InetAddress address() {
158     return address(false);
159   }
160
161   /**
162    * Returns the IP address.
163    *
164    * @param resolve whether to force resolve the hostname
165    * @return the IP address
166    */
167   public InetAddress address(boolean resolve) {
168     if (resolve) {
169       address = resolveAddress();
170       return address;
171     }
172
173     if (address == null) {
174       synchronized (this) {
175         if (address == null) {
176           address = resolveAddress();
177         }
178       }
179     }
180     return address;
181   }
182
183   /**
184    * Resolves the IP address from the hostname.
185    *
186    * @return the resolved IP address or {@code null} if the IP could not be resolved
187    */
188   private InetAddress resolveAddress() {
189     try {
190       return InetAddress.getByName(host);
191     } catch (UnknownHostException e) {
192       return null;
193     }
194   }
195
196   /**
197    * Returns the address type.
198    *
199    * @return the address type
200    */
201   public Type type() {
202     if (type == null) {
203       synchronized (this) {
204         if (type == null) {
205           type = address() instanceof Inet6Address ? Type.IPV6 : Type.IPV4;
206         }
207       }
208     }
209     return type;
210   }
211
212   @Override
213   public String toString() {
214     String host = host();
215     int port = port();
216     if (host.matches("([0-9a-f]{1,4}:){7}([0-9a-f]){1,4}")) {
217       return String.format("[%s]:%d", host, port);
218     } else {
219       return String.format("%s:%d", host, port);
220     }
221   }
222
223   @Override
224   public int hashCode() {
225     return Objects.hash(host, port);
226   }
227
228   @Override
229   public boolean equals(Object obj) {
230     if (this == obj) {
231       return true;
232     }
233     if (!(obj instanceof Address)) {
234       return false;
235     }
236     Address that = (Address) obj;
237     return this.host.equals(that.host)
238         && this.port == that.port;
239   }
240 }