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