001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.validator.routines;
018
019 import java.io.Serializable;
020 import java.util.regex.Matcher;
021 import java.util.regex.Pattern;
022
023 /**
024 * <p>Perform email validations.</p>
025 * <p>
026 * This class is a Singleton; you can retrieve the instance via the getInstance() method.
027 * </p>
028 * <p>
029 * Based on a script by <a href="mailto:stamhankar@hotmail.com">Sandeep V. Tamhankar</a>
030 * http://javascript.internet.com
031 * </p>
032 * <p>
033 * This implementation is not guaranteed to catch all possible errors in an email address.
034 * For example, an address like nobody@noplace.somedog will pass validator, even though there
035 * is no TLD "somedog"
036 * </p>.
037 *
038 * @version $Revision: 594904 $ $Date: 2007-11-14 15:30:27 +0100 (Mi, 14. Nov 2007) $
039 * @since Validator 1.4
040 */
041 public class EmailValidator implements Serializable {
042
043 private static final String SPECIAL_CHARS = "\\p{Cntrl}\\(\\)<>@,;:'\\\\\\\"\\.\\[\\]";
044 private static final String VALID_CHARS = "[^\\s" + SPECIAL_CHARS + "]";
045 private static final String QUOTED_USER = "(\"[^\"]*\")";
046 private static final String WORD = "((" + VALID_CHARS + "|')+|" + QUOTED_USER + ")";
047
048 private static final String LEGAL_ASCII_REGEX = "^\\p{ASCII}+$";
049 private static final String EMAIL_REGEX = "^\\s*?(.+)@(.+?)\\s*$";
050 private static final String IP_DOMAIN_REGEX = "^\\[(.*)\\]$";
051 private static final String USER_REGEX = "^\\s*" + WORD + "(\\." + WORD + ")*$";
052
053 private static final Pattern MATCH_ASCII_PATTERN = Pattern.compile(LEGAL_ASCII_REGEX);
054 private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX);
055 private static final Pattern IP_DOMAIN_PATTERN = Pattern.compile(IP_DOMAIN_REGEX);
056 private static final Pattern USER_PATTERN = Pattern.compile(USER_REGEX);
057
058 /**
059 * Singleton instance of this class.
060 */
061 private static final EmailValidator EMAIL_VALIDATOR = new EmailValidator();
062
063 /**
064 * Returns the Singleton instance of this validator.
065 *
066 * @return singleton instance of this validator.
067 */
068 public static EmailValidator getInstance() {
069 return EMAIL_VALIDATOR;
070 }
071
072 /**
073 * Protected constructor for subclasses to use.
074 */
075 protected EmailValidator() {
076 super();
077 }
078
079 /**
080 * <p>Checks if a field has a valid e-mail address.</p>
081 *
082 * @param email The value validation is being performed on. A <code>null</code>
083 * value is considered invalid.
084 * @return true if the email address is valid.
085 */
086 public boolean isValid(String email) {
087 if (email == null) {
088 return false;
089 }
090
091 Matcher asciiMatcher = MATCH_ASCII_PATTERN.matcher(email);
092 if (!asciiMatcher.matches()) {
093 return false;
094 }
095
096 // Check the whole email address structure
097 Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
098 if (!emailMatcher.matches()) {
099 return false;
100 }
101
102 if (email.endsWith(".")) {
103 return false;
104 }
105
106 if (!isValidUser(emailMatcher.group(1))) {
107 return false;
108 }
109
110 if (!isValidDomain(emailMatcher.group(2))) {
111 return false;
112 }
113
114 return true;
115 }
116
117 /**
118 * Returns true if the domain component of an email address is valid.
119 *
120 * @param domain being validated.
121 * @return true if the email address's domain is valid.
122 */
123 protected boolean isValidDomain(String domain) {
124 // see if domain is an IP address in brackets
125 Matcher ipDomainMatcher = IP_DOMAIN_PATTERN.matcher(domain);
126
127 if (ipDomainMatcher.matches()) {
128 InetAddressValidator inetAddressValidator =
129 InetAddressValidator.getInstance();
130 return inetAddressValidator.isValid(ipDomainMatcher.group(1));
131 } else {
132 // Domain is symbolic name
133 DomainValidator domainValidator =
134 DomainValidator.getInstance();
135 return domainValidator.isValid(domain);
136 }
137 }
138
139 /**
140 * Returns true if the user component of an email address is valid.
141 *
142 * @param user being validated
143 * @return true if the user name is valid.
144 */
145 protected boolean isValidUser(String user) {
146 return USER_PATTERN.matcher(user).matches();
147 }
148
149 }