1
2
3
4 package de.powerstat.validation.values;
5
6
7 import java.io.IOException;
8 import java.net.InetAddress;
9 import java.net.UnknownHostException;
10 import java.util.Objects;
11 import java.util.regex.Pattern;
12
13 import org.apache.logging.log4j.LogManager;
14 import org.apache.logging.log4j.Logger;
15
16 import de.powerstat.validation.generated.GeneratedTlds;
17 import de.powerstat.validation.interfaces.IValueObject;
18
19
20
21
22
23
24
25
26
27
28 public final class Hostname implements Comparable<Hostname>, IValueObject
29 {
30
31
32
33 private static final Logger LOGGER = LogManager.getLogger(Hostname.class);
34
35
36
37
38
39
40
41
42
43 private static final Pattern HOSTNAME_REGEXP = Pattern.compile("^[.0-9a-zA-Z-]+$");
44
45
46
47
48 private static final String ESC_DOT = "\\.";
49
50
51
52
53 private static final Pattern HOSTNAME_BY_DOTS = Pattern.compile(Hostname.ESC_DOT);
54
55
56
57
58 private final String hostname;
59
60
61
62
63 @SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
64 private final String reverseHostname;
65
66
67
68
69
70
71
72
73
74 private Hostname(final String hostname)
75 {
76 super();
77 Objects.requireNonNull(hostname, "hostname");
78 if ((hostname.length() < 2) || (hostname.length() > 253))
79 {
80 throw new IllegalArgumentException("To short or long for a hostname");
81 }
82 var tempHostname = "";
83 try
84 {
85 tempHostname = IPV4Address.of(hostname).stringValue();
86 }
87 catch (final IllegalArgumentException ignored)
88 {
89
90 }
91 try
92 {
93 if (tempHostname.isEmpty())
94 {
95 tempHostname = IPV6Address.of(hostname).stringValue();
96 }
97 }
98 catch (final IllegalArgumentException ignored)
99 {
100
101 }
102 if (tempHostname.isEmpty())
103 {
104 tempHostname = checkHostname(hostname);
105 this.reverseHostname = reverseHostname(tempHostname);
106 }
107 else
108 {
109 this.reverseHostname = tempHostname;
110 }
111 this.hostname = tempHostname;
112 }
113
114
115
116
117
118
119
120
121 private static String checkHostname(final String hostname)
122 {
123 if (!Hostname.HOSTNAME_REGEXP.matcher(hostname).matches())
124 {
125 throw new IllegalArgumentException("Hostname contains illegal character");
126 }
127 final String[] parts = HOSTNAME_BY_DOTS.split(hostname, 0);
128
129 if (parts.length < 2)
130 {
131 throw new IllegalArgumentException("Hostname must be at a minimum consist of subdomain.topleveldomain");
132 }
133 for (final String part : parts)
134 {
135 if (part.isEmpty() || (part.length() > 63))
136 {
137 throw new IllegalArgumentException("Hostname part empty or to long");
138 }
139 if ((part.charAt(0) == '-') || (part.charAt(part.length() - 1) == '-'))
140 {
141 throw new IllegalArgumentException("Illegal character '-' at name start or end");
142 }
143 }
144 if (!GeneratedTlds.contains(parts[parts.length - 1]))
145 {
146 throw new IllegalArgumentException("Unknown top level domain in hostname");
147 }
148 return hostname;
149 }
150
151
152
153
154
155
156
157
158 private static String reverseHostname(final String hostname)
159 {
160 final String[] parts = HOSTNAME_BY_DOTS.split(hostname, 0);
161
162 final var buffer = new StringBuilder(hostname.length());
163 for (int i = parts.length - 1; i >= 0; --i)
164 {
165 if (buffer.length() != 0)
166 {
167 buffer.append('.');
168 }
169 buffer.append(parts[i]);
170 }
171 return buffer.toString();
172 }
173
174
175
176
177
178
179
180
181 public static Hostname of(final String hostname)
182 {
183
184
185
186
187
188
189
190
191
192
193
194
195
196 return new Hostname(hostname);
197 }
198
199
200
201
202
203
204
205 @Override
206 public String stringValue()
207 {
208 return this.hostname;
209 }
210
211
212
213
214
215
216
217 public String getReverseHostname()
218 {
219 return this.reverseHostname;
220 }
221
222
223
224
225
226
227
228 public boolean exist()
229 {
230 try
231 {
232 InetAddress.getByName(this.hostname);
233 }
234 catch (final UnknownHostException ignored)
235 {
236
237 return false;
238 }
239 return true;
240 }
241
242
243
244
245
246
247
248
249 public boolean isReachable(final int timeout)
250 {
251 try
252 {
253 final var address = InetAddress.getByName(this.hostname);
254 return address.isReachable(timeout);
255 }
256 catch (final IOException ignored)
257 {
258
259 return false;
260 }
261 }
262
263
264
265
266
267
268
269
270 @Override
271 public int hashCode()
272 {
273 return this.hostname.hashCode();
274 }
275
276
277
278
279
280
281
282
283
284 @Override
285 public boolean equals(final Object obj)
286 {
287 if (this == obj)
288 {
289 return true;
290 }
291 if (!(obj instanceof Hostname))
292 {
293 return false;
294 }
295 final Hostname other = (Hostname)obj;
296 return this.hostname.equals(other.hostname);
297 }
298
299
300
301
302
303
304
305
306
307
308
309
310 @Override
311 public String toString()
312 {
313 final var builder = new StringBuilder(19);
314 builder.append("Hostname[hostname=").append(this.hostname).append(']');
315 return builder.toString();
316 }
317
318
319
320
321
322
323
324
325
326 @Override
327 public int compareTo(final Hostname obj)
328 {
329 Objects.requireNonNull(obj, "obj");
330 return this.hostname.compareTo(obj.hostname);
331 }
332
333 }