View Javadoc

1   /*
2    * Copyright 2004-2008 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
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   * Eメールアドレスに対する検証を行います。
30   * <p>
31   * デフォルトエラーメッセージキー:valid.email
32   * </p>
33   * 
34   * @author agata
35   * @author baba
36   */
37  public class EmailValidator implements ScalarFieldValidator {
38  
39  	private static final String SPECIAL_CHARS = "\\(\\)<>@,;:\\\\\\\"\\.\\[\\]";
40  	private static final String VALID_CHARS = "[^\\s" + SPECIAL_CHARS + "]";
41  	private static final String QUOTED_USER = "(\"[^\"]*\")";
42  	private static final String ATOM = VALID_CHARS + '+';
43  	private static final String WORD = "(" + ATOM + "|" + QUOTED_USER + ")";
44  
45  	private static final String LEGAL_ASCII_PATTERN = "^[\\x00-\\x7F]+$";
46  	private static final String EMAIL_PATTERN = "^(.+)@(.+)$";
47  	private static final String IP_DOMAIN_PATTERN = "^(\\d{1,3})[.](\\d{1,3})[.](\\d{1,3})[.](\\d{1,3})$";
48  
49  	private static final String USER_PATTERN = "^" + WORD + "(\\." + WORD
50  			+ ")*$";
51  	private static final String DOMAIN_PATTERN = "^" + ATOM + "(\\." + ATOM
52  			+ ")*$";
53  	private static final String ATOM_PATTERN = "(" + ATOM + ")";
54  
55  	/**
56  	 * メッセージヘルパ。
57  	 */
58  	private final MessageHelper messageHelper;
59  
60  	/**
61  	 * コンストラクタ
62  	 */
63  	public EmailValidator() {
64  		this("valid.email");
65  	}
66  
67  	/**
68  	 * メッセージキーを指定するコンストラクタ
69  	 * 
70  	 * @param messageKey
71  	 */
72  	public EmailValidator(final String messageKey) {
73  		this.messageHelper = new MessageHelper(messageKey);
74  	}
75  
76  	public void validate(final ValidationContext context, final Object value) {
77  		if (value == null) {
78  			return;
79  		}
80  		if (value instanceof String) {
81  			final String email = (String) value;
82  			if (StringUtil.isEmpty(email)) {
83  				return;
84  			}
85  
86  			boolean match = !email.endsWith(".");
87  			if (match) {
88  				final Pattern pattern = Pattern.compile(LEGAL_ASCII_PATTERN);
89  				final Matcher matchAsciiPat = pattern.matcher(email);
90  				match = matchAsciiPat.matches();
91  			}
92  
93  			if (match) {
94  				final Pattern pattern = Pattern.compile(EMAIL_PATTERN);
95  				final Matcher matcher = pattern.matcher(email);
96  				match = matcher.find();
97  				if (match) {
98  					if (isValidUser(matcher.group(1))
99  							&& isValidDomain(matcher.group(2))) {
100 						return;
101 					}
102 				}
103 			}
104 		}
105 
106 		context.addMessageInfo(this.messageHelper.createMessageInfo());
107 	}
108 
109 	private boolean isValidDomain(final String domain) {
110 		Pattern pattern = Pattern.compile(IP_DOMAIN_PATTERN);
111 		final Matcher ipAddressMatcher = pattern.matcher(domain);
112 
113 		if (ipAddressMatcher.find()) {
114 			if (isValidIpAddress(ipAddressMatcher)) {
115 				return true;
116 			}
117 		} else {
118 			pattern = Pattern.compile(DOMAIN_PATTERN);
119 			final Matcher domainMatcher = pattern.matcher(domain);
120 			if (domainMatcher.matches()) {
121 				if (isValidSymbolicDomain(domain)) {
122 					return true;
123 				}
124 			}
125 		}
126 		return false;
127 	}
128 
129 	private boolean isValidUser(final String user) {
130 		final Pattern pattern = Pattern.compile(USER_PATTERN);
131 		final Matcher userMatcher = pattern.matcher(user);
132 		return userMatcher.matches();
133 	}
134 
135 	private boolean isValidIpAddress(final Matcher ipAddressMatcher) {
136 		for (int i = 1; i <= 4; i++) {
137 			final String ipSegment = ipAddressMatcher.group(i);
138 			if (ipSegment == null || ipSegment.length() <= 0) {
139 				return false;
140 			}
141 
142 			int iIpSegment = 0;
143 
144 			try {
145 				iIpSegment = Integer.parseInt(ipSegment);
146 			} catch (final NumberFormatException e) {
147 				return false;
148 			}
149 
150 			if (iIpSegment > 255) {
151 				return false;
152 			}
153 
154 		}
155 		return true;
156 	}
157 
158 	private boolean isValidSymbolicDomain(String domain) {
159 		final List<String> domainSegments = new ArrayList<String>();
160 		boolean match = true;
161 		int i = 0;
162 
163 		final Pattern pattern = Pattern.compile(ATOM_PATTERN);
164 		Matcher atomMatcher;
165 		String ds;
166 		while (match) {
167 			atomMatcher = pattern.matcher(domain);
168 			match = atomMatcher.find();
169 			if (match) {
170 				ds = atomMatcher.group(1);
171 				domainSegments.add(ds);
172 				final int l = ds.length() + 1;
173 				domain = l >= domain.length() ? "" : domain.substring(l);
174 
175 				i++;
176 			}
177 		}
178 
179 		final int size = domainSegments.size();
180 		if (size > 0) {
181 			final String end = domainSegments.get(size - 1);
182 			if (end.length() < 2 || end.length() > 4) {
183 				return false;
184 			}
185 		}
186 
187 		if (domainSegments.size() < 2) {
188 			return false;
189 		}
190 
191 		return true;
192 	}
193 
194 }