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