1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.seasar.cubby.validator.validators;
17
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22
23 import org.seasar.cubby.action.MessageInfo;
24 import org.seasar.cubby.internal.util.StringUtils;
25 import org.seasar.cubby.validator.ScalarFieldValidator;
26 import org.seasar.cubby.validator.ValidationContext;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class EmailValidator implements ScalarFieldValidator {
54
55 private static final String SPECIAL_CHARS = "\\(\\)<>@,;:\\\\\\\"\\.\\[\\]";
56 private static final String VALID_CHARS = "[^\\s" + SPECIAL_CHARS + "]";
57 private static final String QUOTED_USER = "(\"[^\"]*\")";
58 private static final String ATOM = VALID_CHARS + '+';
59 private static final String WORD = "(" + ATOM + "|" + QUOTED_USER + ")";
60
61 private static final String LEGAL_ASCII_PATTERN = "^[\\x00-\\x7F]+$";
62 private static final String EMAIL_PATTERN = "^(.+)@(.+)$";
63 private static final String IP_DOMAIN_PATTERN = "^(\\d{1,3})[.](\\d{1,3})[.](\\d{1,3})[.](\\d{1,3})$";
64
65 private static final String USER_PATTERN = "^" + WORD + "(\\." + WORD
66 + ")*$";
67 private static final String DOMAIN_PATTERN = "^" + ATOM + "(\\." + ATOM
68 + ")*$";
69 private static final String ATOM_PATTERN = "(" + ATOM + ")";
70
71
72
73
74 private final String messageKey;
75
76
77
78
79 public EmailValidator() {
80 this("valid.email");
81 }
82
83
84
85
86
87
88 public EmailValidator(final String messageKey) {
89 this.messageKey = messageKey;
90 }
91
92
93
94
95 public void validate(final ValidationContext context, final Object value) {
96 if (value == null) {
97 return;
98 }
99 if (value instanceof String) {
100 final String email = (String) value;
101 if (StringUtils.isEmpty(email)) {
102 return;
103 }
104
105 boolean match = !email.endsWith(".");
106 if (match) {
107 final Pattern pattern = Pattern.compile(LEGAL_ASCII_PATTERN);
108 final Matcher matchAsciiPat = pattern.matcher(email);
109 match = matchAsciiPat.matches();
110 }
111
112 if (match) {
113 final Pattern pattern = Pattern.compile(EMAIL_PATTERN);
114 final Matcher matcher = pattern.matcher(email);
115 match = matcher.find();
116 if (match) {
117 if (isValidUser(matcher.group(1))
118 && isValidDomain(matcher.group(2))) {
119 return;
120 }
121 }
122 }
123 }
124
125 final MessageInfo messageInfo = new MessageInfo();
126 messageInfo.setKey(this.messageKey);
127 context.addMessageInfo(messageInfo);
128 }
129
130 private boolean isValidDomain(final String domain) {
131 Pattern pattern = Pattern.compile(IP_DOMAIN_PATTERN);
132 final Matcher ipAddressMatcher = pattern.matcher(domain);
133
134 if (ipAddressMatcher.find()) {
135 if (isValidIpAddress(ipAddressMatcher)) {
136 return true;
137 }
138 } else {
139 pattern = Pattern.compile(DOMAIN_PATTERN);
140 final Matcher domainMatcher = pattern.matcher(domain);
141 if (domainMatcher.matches()) {
142 if (isValidSymbolicDomain(domain)) {
143 return true;
144 }
145 }
146 }
147 return false;
148 }
149
150 private boolean isValidUser(final String user) {
151 final Pattern pattern = Pattern.compile(USER_PATTERN);
152 final Matcher userMatcher = pattern.matcher(user);
153 return userMatcher.matches();
154 }
155
156 private boolean isValidIpAddress(final Matcher ipAddressMatcher) {
157 for (int i = 1; i <= 4; i++) {
158 final String ipSegment = ipAddressMatcher.group(i);
159 if (ipSegment == null || ipSegment.length() <= 0) {
160 return false;
161 }
162
163 int iIpSegment = 0;
164
165 try {
166 iIpSegment = Integer.parseInt(ipSegment);
167 } catch (final NumberFormatException e) {
168 return false;
169 }
170
171 if (iIpSegment > 255) {
172 return false;
173 }
174
175 }
176 return true;
177 }
178
179 private boolean isValidSymbolicDomain(final String domain) {
180 final List<String> domainSegments = new ArrayList<String>();
181 boolean match = true;
182
183 final Pattern pattern = Pattern.compile(ATOM_PATTERN);
184 String domainSegment;
185 String currentDomain = domain;
186 while (match) {
187 final Matcher atomMatcher = pattern.matcher(currentDomain);
188 match = atomMatcher.find();
189 if (match) {
190 domainSegment = atomMatcher.group(1);
191 domainSegments.add(domainSegment);
192 final int domainSegmentLength = domainSegment.length() + 1;
193 currentDomain = domainSegmentLength >= currentDomain.length() ? ""
194 : currentDomain.substring(domainSegmentLength);
195 }
196 }
197
198 final int size = domainSegments.size();
199 if (size > 0) {
200 final String end = domainSegments.get(size - 1);
201 if (end.length() < 2 || end.length() > 4) {
202 return false;
203 }
204 }
205
206 if (size < 2) {
207 return false;
208 }
209
210 return true;
211 }
212
213 }