View Javadoc
1   /* ---------------------------------------------------------------------------------------
2    * Class:  com.cardatechnologies.utils.validators.abaroutevalidator.AbaRouteValidator.java
3    * Date:   2015/02/11
4    * ---------------------------------------------------------------------------------------
5    * Copyright:  Daniel Carda
6    *             All Rights Reserved
7    * ---------------------------------------------------------------------------------------
8    *
9    *  License: MIT license
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12   * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANT ABILITY, FITNESS FOR A
13   * PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14   * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15   * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16   * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17   */
18  
19  package com.cardatechnologies.utils.validators.abaroutevalidator;
20  
21  //~--- non-JDK imports --------------------------------------------------------
22  
23  import com.cardatechnologies.utils.validators.abaroutevalidator.exceptions.AbaRouteValidationException;
24  
25  /**
26   * <b>Description:</b><br>
27   *     This class is used to validate a ABA Routing Transit Number.
28   *
29   * @author     Daniel Carda
30   * <br>
31   * <br><b>Maintenance History:</b>
32   * <br>
33  <pre>
34      yyyy mm dd  Who                       Description
35      ----------  ------------------------  ----------------------------------------------------
36      2015/02/11  Daniel Carda              Initial Module Creation...
37      2020/12/23  Daniel Carda              Started using and ENum for error content.
38      2020/12/24  Daniel Carda              Optimized algorithms.
39      2021/08/01  Daniel Carda              Improved Class Javadocs
40  </pre>
41   * <hr>
42   */
43  public class AbaRouteValidator {
44  
45      /**
46       * Method description
47       *
48       * @param  paramAbaRouteNumber
49       *         The incoming ABA Number.
50       *
51       * @return boolean
52       *         True if all the characters were digits.
53       *         False if there was a problem.
54       *
55       * @throws AbaRouteValidationException
56       *         There was a problem somewhere not related to checking the ABA number.
57       */
58      private static boolean breakdownAbaNumber( final String paramAbaRouteNumber )
59              throws AbaRouteValidationException {
60  
61          // Check first two digits.
62          validateFedNumber( paramAbaRouteNumber );
63  
64          // Alright, now see if the number holds up to scrutiny!
65          boolean returnBool;
66  
67          returnBool = validateAbaNumberChecksum( paramAbaRouteNumber );
68  
69          // Return the result
70          return( returnBool );
71      }
72  
73      /**
74       * This method is the starting point to validate whether a incoming string is
75       * a valid ABA Routing Transit Number.
76       *
77       * @param   paramAbaRouteNumber The ABA number to be tested.
78       *
79       * @return boolean
80       *         True if all the characters were digits.
81       *         False if there was a problem.
82       *
83       * @throws AbaRouteValidationException
84       *         A error occurred when parsing the suspect
85       *         ABA Routing Transit Number.
86       */
87      static public boolean validate( final String paramAbaRouteNumber )
88              throws AbaRouteValidationException {
89  
90          // http://en.wikipedia.org/wiki/Routing_transit_number
91          //
92          // See FRB Regulation CC, Appendix A, which available online here:
93          // <http://www.bankersonline.com/regs/229/a229a.html>
94          // Quick Check
95          // Is the parameter null
96          if( paramAbaRouteNumber == null ) {
97              throw new AbaRouteValidationException( ErrorCodes.ABA_1000.getErrorCode(),
98                                                     ErrorCodes.ABA_1000.getErrorMnemonic() );
99          }
100 
101         // Quick Check
102         // Is the parameter empty/blank
103         if( paramAbaRouteNumber.trim().equals( "" ) ) {
104             throw new AbaRouteValidationException( ErrorCodes.ABA_1001.getErrorCode(),
105                                                    ErrorCodes.ABA_1001.getErrorMnemonic() );
106         }
107 
108         // Quick Check
109         // Make sure the string length is right
110         int _strLen;
111 
112         _strLen = paramAbaRouteNumber.length();
113 
114         // See if it's the right length
115         if( _strLen != 9 ) {
116 
117             // Is it to short?
118             if( _strLen < 9 ) {
119                 throw new AbaRouteValidationException( ErrorCodes.ABA_1002.getErrorCode(),
120                                                        ErrorCodes.ABA_1002.getErrorMnemonic() );
121             }
122             else {
123 
124                 // Must be to long.
125                 throw new AbaRouteValidationException( ErrorCodes.ABA_1003.getErrorCode(),
126                                                        ErrorCodes.ABA_1003.getErrorMnemonic() );
127             }
128         }
129 
130         // Quick Check
131         // Finally, let's just do a scan and make sure it's a number
132         if( !isNumeric( paramAbaRouteNumber ) ) {
133             throw new AbaRouteValidationException( ErrorCodes.ABA_1004.getErrorCode(),
134                                                    ErrorCodes.ABA_1004.getErrorMnemonic() );
135         }
136 
137         // -----------------------------------------------------------------------------
138         // -----------------------------------------------------------------------------
139         // So we got this far, lets start breaking it down.
140         boolean returnBool;
141 
142         returnBool = breakdownAbaNumber( paramAbaRouteNumber );
143 
144         // Must be good!
145         return( returnBool );
146     }
147 
148     /**
149      * Method: validateAbaNumberChecksum
150      *
151      * @param  paramAbaRouteNumber
152      *         The target ABA number to test.
153      *
154      * @return boolean
155      *         True if all the characters were digits.
156      *         False if there was a problem.
157      */
158     static private boolean validateAbaNumberChecksum( final String paramAbaRouteNumber ) {
159 
160         // Even thought initializing this to zero is redundant, performance tests
161         // were slightly improved.
162         int checksumTotal = 0;
163 
164         // Set up all the ints
165         int i1, i2, i3, i4, i5, i6, i7, i8, i9;
166 
167         // Break up the string so we can look at the numbers.
168         // Although this is a bit simplistic, doing it this way (as opposed to
169         // to a loop) produced much faster results.
170         i1 = Character.getNumericValue( paramAbaRouteNumber.charAt( 0 ) );
171         i2 = Character.getNumericValue( paramAbaRouteNumber.charAt( 1 ) );
172         i3 = Character.getNumericValue( paramAbaRouteNumber.charAt( 2 ) );
173         i4 = Character.getNumericValue( paramAbaRouteNumber.charAt( 3 ) );
174         i5 = Character.getNumericValue( paramAbaRouteNumber.charAt( 4 ) );
175         i6 = Character.getNumericValue( paramAbaRouteNumber.charAt( 5 ) );
176         i7 = Character.getNumericValue( paramAbaRouteNumber.charAt( 6 ) );
177         i8 = Character.getNumericValue( paramAbaRouteNumber.charAt( 7 ) );
178         i9 = Character.getNumericValue( paramAbaRouteNumber.charAt( 8 ) );
179 
180         // Okay, lets crank it through the formula
181         checksumTotal = ( ( i3 + i6 + i9 ) + ( 3 * ( i1 + i4 + i7 ) ) + ( 7 * ( i2 + i5 + i8 ) ) );
182 
183         // Check the modulus and we're done!
184         if( ( checksumTotal % 10 ) != 0 ) {
185 
186             // Checksum has failed
187             return( false );
188         }
189         else {
190 
191             // Checksum is good!
192             return( true );
193         }
194     }
195 
196     /**
197      * This method will test to see if the first two characters, when combined to create a
198      * number, are within an acceptable range.
199      *
200      * @param  paramAbaRouteNumber The target string to test.
201      *
202      * @throws AbaRouteValidationException
203      *         There was a problem in converting the ABA number.
204      */
205     static private void validateFedNumber( final String paramAbaRouteNumber )
206             throws AbaRouteValidationException {
207 
208         // String off the first 2 numbers and see if they validate.
209         String _tempStr;
210 
211         _tempStr = paramAbaRouteNumber.substring( 0, 2 );
212 
213         // Now, convert the substring to an int
214         int _fedNumb;
215 
216         _fedNumb = Integer.parseInt( _tempStr );
217 
218         // Okay, let's see if it works!
219         if( !( ( ( _fedNumb >= 0 ) && ( _fedNumb <= 12 ) )
220                 || ( ( _fedNumb >= 21 ) && ( _fedNumb <= 32 ) )
221                 || ( ( _fedNumb >= 61 ) && ( _fedNumb <= 72 ) )
222                 || ( ( _fedNumb == 80 ) ) ) ) {
223             throw new AbaRouteValidationException( ErrorCodes.ABA_1005.getErrorCode(),
224                                                    ErrorCodes.ABA_1005.getErrorMnemonic() );
225         }
226     }
227 
228     /**
229      * Method: isNumeric
230      *
231      * Description:
232      *         This method will scan the individual numbers in the ABA number
233      *         and makre sure they are numeric digits.
234      *
235      * @param  paramStr
236      *         The string which needs to be made up of all numbers.
237      *
238      * @return boolean
239      *         True if all the characters were digits.
240      *         False if there was a problem.
241      */
242     static private boolean isNumeric( final String paramStr ) {
243 
244           // Cycle through the character array
245           int size = paramStr.length();
246           for( int i = 0; i < size; i++ ) {
247               if( !Character.isDigit( paramStr.charAt(i) ) ) {
248 
249                   // This is bad!
250                   return( false );
251               }
252           }
253 
254           // All is well!
255         return( true );
256     }
257 }
258 
259 /* ---------------------------------------------------------------------------------------
260  * Class:  com.cardatechnologies.utils.validators.abaroutevalidator.AbaRouteValidator.java
261  * Date:   2015/02/11
262  * --------------------------------------------------------------------------------------- */