Source code: com/clra/member/Email.java
1 /*
2 * Copyright (c) Carnegie Lake Rowing Association 2002. All rights reserved.
3 * Distributed under the GPL license. See doc/COPYING.
4 * $RCSfile: Email.java,v $
5 * $Date: 2003/03/01 00:45:14 $
6 * $Revision: 1.5 $
7 */
8
9 package com.clra.member;
10
11 import java.io.Serializable;
12
13 /**
14 * Encapsulates the email address of a member. This class performs
15 * rough validation of email addresses, in the spirit of RFC 821, but not
16 * to the letter of that specification. An email address is considered valid
17 * if it is of the form:<pre>
18 * "local" "@" "domain"
19 * </pre>
20 * where the "local" part can be any combination of [a-zA-Z0-9.] that does not
21 * start with a digit or dot nor ends with a dot. (To be rigorous, the local
22 * part should exclude doubled dot sequences, and it should allow all escaped
23 * ASCII characters.) The "domain" part can be any combination of [-a-zA-Z09.]
24 * that does not start with a digit, hyphen or dot, and that does not end with
25 * a hyphen or dot. (To be rigorous, the domain part should exclude doubled
26 * dot or hyphen sequences, and it should allow dotted numeric addresses.)</p>
27 *
28 * @version $Id: Email.java,v 1.5 2003/03/01 00:45:14 rphall Exp $
29 * @author <a href="mailto:rphall@pluto.njcc.com">Rick Hall</a>
30 */
31 public class Email implements Serializable {
32
33 public static boolean isValidStart( char c ) {
34 boolean retVal = ( 'a' <= c && c <= 'z' );
35 retVal = retVal || ( 'A' <= c && c <= 'Z' );
36
37 return retVal;
38 }
39
40 public static boolean isValidEnd( char c ) {
41 boolean retVal = isValidStart( c );
42 retVal = retVal || ( '0' <= c && c <= '9' );
43
44 return retVal;
45 }
46
47 public static boolean isValidLocalChar( char c ) {
48 boolean retVal = isValidEnd( c );
49 retVal = retVal || c == '.' || c == '_' || c == '-' ;
50
51 return retVal;
52 }
53
54 public static boolean isValidDomainChar( char c ) {
55 boolean retVal = isValidEnd( c );
56 retVal = retVal || c == '.' || c == '-' ;
57
58 return retVal;
59 }
60
61 public static boolean isValidEmail( String s ) {
62
63 // Not null, and no leading or trailing whitespace
64 boolean retVal = s != null;
65 retVal = retVal && s.trim().length() == s.length();
66
67 // An '@' sign in the middle
68 if ( retVal ) {
69
70 final int idxAtSign = s.indexOf( '@' );
71 retVal = ( 0 < idxAtSign ) && ( idxAtSign < s.length() - 1 );
72
73 // A valid local part
74 final int idxLastLocal = idxAtSign - 1;
75 retVal = retVal && isValidStart( s.charAt(0) );
76 retVal = retVal && isValidEnd( s.charAt(idxLastLocal) );
77 for ( int i=1; retVal && i<idxLastLocal; i++ ) {
78 retVal = isValidLocalChar( s.charAt(i) );
79 }
80
81 // A valid domain
82 final int idxFirstDomain = idxAtSign + 1;
83 retVal = retVal && isValidStart( s.charAt(idxFirstDomain) );
84 retVal = retVal && isValidEnd( s.charAt(s.length()-1) );
85 for ( int i=idxFirstDomain+1; retVal && i<s.length()-1; i++ ) {
86 retVal = isValidDomainChar( s.charAt(i) );
87 }
88
89 } // if s non-null
90
91 return retVal;
92 } // isValidEmail
93
94 private final String email;
95
96 public Email( String s ) {
97
98 this.email = s;
99
100 if ( s == null ) {
101 throw new IllegalArgumentException( "null email address" );
102 }
103 s = s.trim();
104 if ( !isValidEmail(s) ) {
105 throw new IllegalArgumentException( "invalid email == '" +s+ "'" );
106 }
107
108 } // ctor
109
110 public String toString() {
111 return this.email;
112 }
113
114 public boolean equals( Object o ) {
115 boolean retVal;
116 if ( o == null ) {
117 retVal = false;
118 }
119 else if ( o instanceof String ) {
120 String s = ((String)o).trim();
121 retVal = this.email.equalsIgnoreCase(s);
122 }
123 else if ( o instanceof Email ) {
124 Email that = (Email) o;
125 retVal = this.email.equalsIgnoreCase(that.email);
126 }
127 else {
128 retVal = false;
129 }
130
131 return retVal;
132 } // equals(Object)
133
134 public int hashCode() {
135 int retVal = this.email.toUpperCase().hashCode();
136 return retVal;
137 }
138
139 } // Email
140
141 /*
142 * $Log: Email.java,v $
143 * Revision 1.5 2003/03/01 00:45:14 rphall
144 * Removed no-param default constructor
145 *
146 * Revision 1.4 2003/02/28 14:05:49 rphall
147 * Added default constructor so that class could be used as a Java bean
148 *
149 * Revision 1.3 2003/02/26 03:38:45 rphall
150 * Added copyright and GPL license
151 *
152 * Revision 1.2 2003/02/19 22:23:05 rphall
153 * Removed gratuitous use of CLRA acronym
154 *
155 * Revision 1.1 2003/02/19 03:41:40 rphall
156 * Working with unit tests
157 *
158 */
159