View Javadoc

1   /*
2    * $Header: /home/cvs/jakarta-commons/validator/src/share/org/apache/commons/validator/EmailValidator.java,v 1.12 2004/02/21 17:10:29 rleland Exp $
3    * $Revision: 1.12 $
4    * $Date: 2004/02/21 17:10:29 $
5    *
6    * ====================================================================
7    * Copyright 2001-2004 The Apache Software Foundation
8    *
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   *
13   *     http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   */
21  
22  package org.apache.commons.validator;
23  
24  import org.apache.oro.text.perl.Perl5Util;
25  
26  /***
27   * <p>Perform email validations.</p>
28   * <p>
29   * This class is a Singleton; you can retrieve the instance via the getInstance() method.
30   * </p>
31   * <p>
32   * Based on a script by <a href="mailto:stamhankar@hotmail.com">Sandeep V. Tamhankar</a>
33   * http://javascript.internet.com
34   * </p>
35   *
36   * @since Validator 1.1
37   */
38  public class EmailValidator {
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      // Each pattern must be surrounded by /
47      private static final String LEGAL_ASCII_PATTERN = "/^[//000-//177]+$/";
48      private static final String EMAIL_PATTERN = "/^(.+)@(.+)$/";
49      private static final String IP_DOMAIN_PATTERN =
50              "/^(//d{1,3})[.](//d{1,3})[.](//d{1,3})[.](//d{1,3})$/";
51  
52      private static final String USER_PATTERN = "/^" + WORD + "(//." + WORD + ")*$/";
53      private static final String DOMAIN_PATTERN = "/^" + ATOM + "(//." + ATOM + ")*$/";
54      private static final String ATOM_PATTERN = "/(" + ATOM + ")/";
55  
56      /***
57       * Singleton instance of this class.
58       */
59      private static final EmailValidator instance = new EmailValidator();
60  
61      /***
62       * Returns the Singleton instance of this validator.
63       */
64      public static EmailValidator getInstance() {
65          return instance;
66      }
67  
68      /***
69       * Protected constructor for subclasses to use.
70       */
71      protected EmailValidator() {
72          super();
73      }
74  
75      /***
76       * <p>Checks if a field has a valid e-mail address.</p>
77       *
78       * @param email The value validation is being performed on.  A <code>null</code>
79       * value is considered invalid.
80       */
81      public boolean isValid(String email) {
82          if (email == null) {
83              return false;
84          }
85  
86          Perl5Util matchAsciiPat = new Perl5Util();
87          if (!matchAsciiPat.match(LEGAL_ASCII_PATTERN, email)) {
88              return false;
89          }
90  
91          // Check the whole email address structure
92          Perl5Util emailMatcher = new Perl5Util();
93          if (!emailMatcher.match(EMAIL_PATTERN, email)) {
94              return false;
95          }
96  
97          if (email.endsWith(".")) {
98              return false;
99          }
100 
101         if (!isValidUser(emailMatcher.group(1))) {
102             return false;
103         }
104 
105         if (!isValidDomain(emailMatcher.group(2))) {
106             return false;
107         }
108 
109         return true;
110     }
111 
112     /***
113      * Returns true if the domain component of an email address is valid.
114      * @param domain being validatied.
115      */
116     protected boolean isValidDomain(String domain) {
117         boolean symbolic = false;
118         Perl5Util ipAddressMatcher = new Perl5Util();
119 
120         if (ipAddressMatcher.match(IP_DOMAIN_PATTERN, domain)) {
121             if (!isValidIpAddress(ipAddressMatcher)) {
122                 return false;
123             }
124         } else {
125             // Domain is symbolic name
126             Perl5Util domainMatcher = new Perl5Util();
127             symbolic = domainMatcher.match(DOMAIN_PATTERN, domain);
128         }
129 
130         if (symbolic) {
131             if (!isValidSymbolicDomain(domain)) {
132                 return false;
133             }
134         } else {
135             return false;
136         }
137 
138         return true;
139     }
140 
141     /***
142      * Returns true if the user component of an email address is valid.
143      * @param user being validated
144      */
145     protected boolean isValidUser(String user) {
146         Perl5Util userMatcher = new Perl5Util();
147         return userMatcher.match(USER_PATTERN, user);
148     }
149 
150     /***
151      * Validates an IP address. Returns true if valid.
152      * @param ipAddressMatcher Pattren matcher
153      */
154     protected boolean isValidIpAddress(Perl5Util ipAddressMatcher) {
155         for (int i = 1; i <= 4; i++) {
156             String ipSegment = ipAddressMatcher.group(i);
157             if (ipSegment == null || ipSegment.length() <= 0) {
158                 return false;
159             }
160 
161             int iIpSegment = 0;
162 
163             try {
164                 iIpSegment = Integer.parseInt(ipSegment);
165             } catch(NumberFormatException e) {
166                 return false;
167             }
168 
169             if (iIpSegment > 255) {
170                 return false;
171             }
172 
173         }
174         return true;
175     }
176 
177     /***
178      * Validates a symbolic domain name.  Returns true if it's valid.
179      * @param domain symbolic domain name
180      */
181     protected boolean isValidSymbolicDomain(String domain) {
182         String[] domainSegment = new String[10];
183         boolean match = true;
184         int i = 0;
185         Perl5Util atomMatcher = new Perl5Util();
186 
187         while (match) {
188             match = atomMatcher.match(ATOM_PATTERN, domain);
189             if (match) {
190                 domainSegment[i] = atomMatcher.group(1);
191                 int l = domainSegment[i].length() + 1;
192                 domain =
193                         (l >= domain.length())
194                         ? ""
195                         : domain.substring(l);
196 
197                 i++;
198             }
199         }
200 
201         int len = i;
202         if (domainSegment[len - 1].length() < 2
203                 || domainSegment[len - 1].length() > 4) {
204 
205             return false;
206         }
207 
208         // Make sure there's a host name preceding the domain.
209         if (len < 2) {
210             return false;
211         }
212 
213         return true;
214     }
215 
216 }