Coverage Report - org.apache.commons.validator.routines.checkdigit.IBANCheckDigit
 
Classes in this File Line Coverage Branch Coverage Complexity
IBANCheckDigit
93%
27/29
96%
29/30
6
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.validator.routines.checkdigit;
 18  
 
 19  
 import java.io.Serializable;
 20  
 
 21  
 /**
 22  
  * <b>IBAN</b> (International Bank Account Number) Check Digit calculation/validation.
 23  
  * <p>
 24  
  * This routine is based on the ISO 7064 Mod 97,10 check digit calculation routine.
 25  
  * <p>
 26  
  * The two check digit characters in a IBAN number are the third and fourth characters
 27  
  * in the code. For <i>check digit</i> calculation/validation the first four characters are moved
 28  
  * to the end of the code.
 29  
  *  So <code>CCDDnnnnnnn</code> becomes <code>nnnnnnnCCDD</code> (where
 30  
  *  <code>CC</code> is the country code and <code>DD</code> is the check digit). For
 31  
  *  check digit calculation the check digit value should be set to zero (i.e.
 32  
  *  <code>CC00nnnnnnn</code> in this example.
 33  
  * <p>
 34  
  * Note: the class does not check the format of the IBAN number, only the check digits.
 35  
  * <p>
 36  
  * For further information see
 37  
  *  <a href="http://en.wikipedia.org/wiki/International_Bank_Account_Number">Wikipedia -
 38  
  *  IBAN number</a>.
 39  
  *
 40  
  * @version $Revision: 1739357 $
 41  
  * @since Validator 1.4
 42  
  */
 43  
 public final class IBANCheckDigit implements CheckDigit, Serializable {
 44  
 
 45  
     private static final int MIN_CODE_LEN = 5;
 46  
 
 47  
     private static final long serialVersionUID = -3600191725934382801L;
 48  
 
 49  
     private static final int MAX_ALPHANUMERIC_VALUE = 35; // Character.getNumericValue('Z')
 50  
 
 51  
     /** Singleton IBAN Number Check Digit instance */
 52  1
     public static final CheckDigit IBAN_CHECK_DIGIT = new IBANCheckDigit();
 53  
 
 54  
     private static final long MAX = 999999999;
 55  
 
 56  
     private static final long MODULUS = 97;
 57  
 
 58  
     /**
 59  
      * Construct Check Digit routine for IBAN Numbers.
 60  
      */
 61  1
     public IBANCheckDigit() {
 62  1
     }
 63  
 
 64  
     /**
 65  
      * Validate the check digit of an IBAN code.
 66  
      *
 67  
      * @param code The code to validate
 68  
      * @return <code>true</code> if the check digit is valid, otherwise
 69  
      * <code>false</code>
 70  
      */
 71  
     @Override
 72  
     public boolean isValid(String code) {
 73  4131
         if (code == null || code.length() < MIN_CODE_LEN) {
 74  3
             return false;
 75  
         }
 76  4128
         String check = code.substring(2,4); // CHECKSTYLE IGNORE MagicNumber
 77  4128
         if ("00".equals(check) || "01".equals(check) || "99".equals(check)) {
 78  5
             return false;
 79  
         }
 80  
         try {
 81  4123
             int modulusResult = calculateModulus(code);
 82  4123
             return (modulusResult == 1);
 83  0
         } catch (CheckDigitException  ex) {
 84  0
             return false;
 85  
         }
 86  
     }
 87  
 
 88  
     /**
 89  
      * Calculate the <i>Check Digit</i> for an IBAN code.
 90  
      * <p>
 91  
      * <b>Note:</b> The check digit is the third and fourth
 92  
      * characters and is set to the value "<code>00</code>".
 93  
      *
 94  
      * @param code The code to calculate the Check Digit for
 95  
      * @return The calculated Check Digit as 2 numeric decimal characters, e.g. "42"
 96  
      * @throws CheckDigitException if an error occurs calculating
 97  
      * the check digit for the specified code
 98  
      */
 99  
     @Override
 100  
     public String calculate(String code) throws CheckDigitException {
 101  46
         if (code == null || code.length() < MIN_CODE_LEN) {
 102  2
             throw new CheckDigitException("Invalid Code length=" +
 103  
                     (code == null ? 0 : code.length()));
 104  
         }
 105  44
         code = code.substring(0, 2) + "00" + code.substring(4); // CHECKSTYLE IGNORE MagicNumber
 106  44
         int modulusResult = calculateModulus(code);
 107  43
         int charValue = (98 - modulusResult); // CHECKSTYLE IGNORE MagicNumber
 108  43
         String checkDigit = Integer.toString(charValue);
 109  43
         return (charValue > 9 ? checkDigit : "0" + checkDigit); // CHECKSTYLE IGNORE MagicNumber
 110  
     }
 111  
 
 112  
     /**
 113  
      * Calculate the modulus for a code.
 114  
      *
 115  
      * @param code The code to calculate the modulus for.
 116  
      * @return The modulus value
 117  
      * @throws CheckDigitException if an error occurs calculating the modulus
 118  
      * for the specified code
 119  
      */
 120  
     private int calculateModulus(String code) throws CheckDigitException {
 121  4167
         String reformattedCode = code.substring(4) + code.substring(0, 4); // CHECKSTYLE IGNORE MagicNumber
 122  4167
         long total = 0;
 123  98551
         for (int i = 0; i < reformattedCode.length(); i++) {
 124  94385
             int charValue = Character.getNumericValue(reformattedCode.charAt(i));
 125  94385
             if (charValue < 0 || charValue > MAX_ALPHANUMERIC_VALUE) {
 126  1
                 throw new CheckDigitException("Invalid Character[" +
 127  
                         i + "] = '" + charValue + "'");
 128  
             }
 129  94384
             total = (charValue > 9 ? total * 100 : total * 10) + charValue; // CHECKSTYLE IGNORE MagicNumber
 130  94384
             if (total > MAX) {
 131  10648
                 total = total % MODULUS;
 132  
             }
 133  
         }
 134  4166
         return (int)(total % MODULUS);
 135  
     }
 136  
 
 137  
 }