View Javadoc
1   /*
2    * (c) Copyright 2006-2020 by rapiddweller GmbH & Volker Bergmann. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, is permitted under the terms of the
6    * GNU General Public License.
7    *
8    * For redistributing this software or a derivative work under a license other
9    * than the GPL-compatible Free Software License as defined by the Free
10   * Software Foundation or approved by OSI, you must first obtain a commercial
11   * license to this software product from rapiddweller GmbH & Volker Bergmann.
12   *
13   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14   * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
15   * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
17   * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24   * POSSIBILITY OF SUCH DAMAGE.
25   */
26  
27  package com.rapiddweller.domain.us;
28  
29  import com.rapiddweller.common.StringUtil;
30  import com.rapiddweller.common.Validator;
31  
32  import javax.validation.ConstraintValidator;
33  import javax.validation.ConstraintValidatorContext;
34  
35  /**
36   * Validates US Social Security Numbers.<br/>
37   * <br/>
38   * Created at 17.11.2008 07:08:34
39   *
40   * @author Volker Bergmann
41   * @see "http://en.wikipedia.org/wiki/Social_security_number"
42   * @see "http://www.socialsecurity.gov/history/ssn/geocard.html"
43   * @see "http://www.socialsecurity.gov/employer/stateweb.htm"
44   * @see "http://www.socialsecurity.gov/employer/ssnvhighgroup.htm"
45   * @since 0.5.6
46   */
47  public class SSNValidator
48      implements ConstraintValidator<SSN, String>, Validator<String> {
49  
50    private int maxAreaCode;
51  
52    /**
53     * Instantiates a new Ssn validator.
54     */
55    public SSNValidator() {
56      this(SSN.DEFAULT_MAX_AREA_CODE);
57    }
58  
59    /**
60     * Instantiates a new Ssn validator.
61     *
62     * @param maxAreaCode the max area code
63     */
64    public SSNValidator(int maxAreaCode) {
65      this.maxAreaCode = maxAreaCode;
66    }
67  
68    @Override
69    public void initialize(SSN parameters) {
70      this.maxAreaCode = parameters.maxAreaCode();
71    }
72  
73    @Override
74    public boolean isValid(String ssn, ConstraintValidatorContext context) {
75      return valid(ssn);
76    }
77  
78    @Override
79    public boolean valid(String ssn) {
80      if (ssn == null || ssn.length() != 11) {
81        return false;
82      }
83      String[] tokens = StringUtil.tokenize(ssn, '-');
84      if (tokens.length != 3) {
85        return false;
86      }
87      try {
88        // validate area number
89        if (tokens[0].length() != 3) {
90          return false;
91        }
92        int areaNumber = Integer.parseInt(tokens[0]);
93        // Currently, a valid SSN cannot have an area number between 734 and 749, or above 772,
94        // the highest area number which the Social Security Administration has allocated
95        if (areaNumber < 1 || areaNumber == 666 ||
96            areaNumber > maxAreaCode ||
97            (areaNumber > 733 && areaNumber < 750)) {
98          return false;
99        }
100 
101       // validate group number
102       if (tokens[1].length() != 2) {
103         return false;
104       }
105       int groupNumber = Integer.parseInt(tokens[1]);
106       if (groupNumber < 1) {
107         return false;
108       }
109 
110       // validate serial number
111       if (tokens[2].length() != 4) {
112         return false;
113       }
114       int serialNumber = Integer.parseInt(tokens[2]);
115       if (serialNumber < 1) {
116         return false;
117       }
118       // Numbers from 987-65-4320 to 987-65-4329 are reserved for use in advertisements
119       if (areaNumber == 987 && areaNumber == 65 &&
120           (serialNumber >= 4320 && serialNumber <= 4329)) {
121         return false;
122       }
123     } catch (NumberFormatException e) {
124       return false;
125     }
126     return true;
127   }
128 
129 }