1
2
3
4 package de.powerstat.validation.values;
5
6
7 import java.util.Locale;
8 import java.util.Objects;
9 import java.util.regex.Pattern;
10
11 import de.powerstat.validation.interfaces.IValueObject;
12
13
14
15
16
17
18
19
20
21
22 public final class EMail implements Comparable<EMail>, IValueObject
23 {
24
25
26
27
28
29
30
31
32 private static final Pattern LOCAL_REGEXP = Pattern.compile("^[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+$");
33
34
35
36
37 private final String email;
38
39
40
41
42 private final Hostname domainPart;
43
44
45
46
47 private final String localPart;
48
49
50
51
52
53
54
55
56
57
58
59 private EMail(final String email)
60 {
61 super();
62 Objects.requireNonNull(email, "email");
63 if ((email.length() < 6) || (email.length() > 254))
64 {
65 throw new IllegalArgumentException("To short or long for an email address");
66 }
67 final String[] parts = email.split("@");
68 if (parts.length != 2)
69 {
70 throw new IllegalArgumentException("Not an email address, missing or to much @");
71 }
72 if (parts[0].length() > 64)
73 {
74 throw new IllegalArgumentException("Local part greater than 64 characters");
75 }
76 if (parts[1].charAt(0) == '[')
77 {
78 parts[1] = (parts[1].toLowerCase(Locale.getDefault()).startsWith("[ipv6:")) ? parts[1].substring(6) : parts[1].substring(1);
79 if (!parts[1].endsWith("]"))
80 {
81 throw new IllegalArgumentException("Missing end of IPv4/IPv6 address");
82 }
83 parts[1] = parts[1].substring(0, parts[1].length() - 1);
84 }
85 this.domainPart = Hostname.of(parts[1]);
86 if ((parts[0].charAt(0) == '(') || (parts[0].charAt(parts[0].length() - 1) == ')'))
87 {
88 throw new IllegalArgumentException("Comments in email addresses are not supported");
89 }
90 if (parts[0].indexOf('"') > -1)
91 {
92 throw new IllegalArgumentException("Double quotes in email addresses are not supported");
93 }
94 if ((parts[0].charAt(0) == '.') || (parts[0].charAt(parts[0].length() - 1) == '.'))
95 {
96 throw new IllegalArgumentException("A dot is not allowed at start or end of an emails local part");
97 }
98 if (parts[0].contains(".."))
99 {
100 throw new IllegalArgumentException("Two or more dots behind each other are not allowed within an emails local part");
101 }
102 if (!EMail.LOCAL_REGEXP.matcher(parts[0]).matches())
103 {
104 throw new IllegalArgumentException("Illegal character found in emails local part or unsupported UTF-8 character");
105 }
106 this.localPart = parts[0];
107 this.email = email;
108 }
109
110
111
112
113
114
115
116
117 public static EMail of(final String email)
118 {
119
120
121
122
123
124
125
126
127
128
129
130
131
132 return new EMail(email);
133 }
134
135
136
137
138
139
140
141 @Override
142 public String stringValue()
143 {
144 return this.email;
145 }
146
147
148
149
150
151
152
153 public String getDomainPart()
154 {
155 return this.domainPart.stringValue();
156 }
157
158
159
160
161
162
163
164 public String getReverseDomainPart()
165 {
166 return this.domainPart.getReverseHostname();
167 }
168
169
170
171
172
173
174
175 public String getLocalPart()
176 {
177 return this.localPart;
178 }
179
180
181
182
183
184
185
186
187 @Override
188 public int hashCode()
189 {
190 return this.email.hashCode();
191 }
192
193
194
195
196
197
198
199
200
201 @Override
202 public boolean equals(final Object obj)
203 {
204 if (this == obj)
205 {
206 return true;
207 }
208 if (!(obj instanceof EMail))
209 {
210 return false;
211 }
212 final EMail other = (EMail)obj;
213 return this.email.equals(other.email);
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227 @Override
228 public String toString()
229 {
230 final var builder = new StringBuilder();
231 builder.append("EMail[email=").append(this.email).append(']');
232 return builder.toString();
233 }
234
235
236
237
238
239
240
241
242
243 @Override
244 public int compareTo(final EMail obj)
245 {
246 Objects.requireNonNull(obj, "obj");
247 return this.email.compareTo(obj.email);
248 }
249
250 }