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   * @since 1.0.0
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  	 * @param messageKey
72  	 */
73  	public EmailValidator(final String messageKey) {
74  		this.messageHelper = new MessageHelper(messageKey);
75  	}
76  
77  	/**
78  	 * {@inheritDoc}
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 }