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