commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject svn commit: r1713224 - in /commons/proper/validator/trunk/src: main/java/org/apache/commons/validator/routines/IBANValidator.java test/java/org/apache/commons/validator/routines/IBANValidatorTest.java
Date Sun, 08 Nov 2015 13:07:01 GMT
Author: sebb
Date: Sun Nov  8 13:07:01 2015
New Revision: 1713224

URL: http://svn.apache.org/viewvc?rev=1713224&view=rev
Log:
Allow formats to be updated
Disallow lower-case in IBAN as this is definitely not allowed.

Modified:
    commons/proper/validator/trunk/src/main/java/org/apache/commons/validator/routines/IBANValidator.java
    commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java

Modified: commons/proper/validator/trunk/src/main/java/org/apache/commons/validator/routines/IBANValidator.java
URL: http://svn.apache.org/viewvc/commons/proper/validator/trunk/src/main/java/org/apache/commons/validator/routines/IBANValidator.java?rev=1713224&r1=1713223&r2=1713224&view=diff
==============================================================================
--- commons/proper/validator/trunk/src/main/java/org/apache/commons/validator/routines/IBANValidator.java
(original)
+++ commons/proper/validator/trunk/src/main/java/org/apache/commons/validator/routines/IBANValidator.java
Sun Nov  8 13:07:01 2015
@@ -16,6 +16,7 @@
  */
 package org.apache.commons.validator.routines;
 
+import java.util.Arrays;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -24,22 +25,40 @@ import org.apache.commons.validator.rout
 
 /**
  * IBAN Validator.
+ * @since 1.5.0
  */
 public class IBANValidator {
 
     private final Map<String, Validator> formatValidators;
 
     public static class Validator {
+        /*
+         * The minimum length does not appear to be defined by the standard.
+         * Norway is currently the shortest at 15.
+         *
+         * There is no standard for BBANs; they vary between countries.
+         * But a BBAN must consist of a branch id and account number.
+         * Each of these must be at least 2 chars (generally more) so an absolute minimum
is
+         * 4 characters for the BBAN and 8 for the IBAN.
+         */
+        private static final int MIN_LEN = 8;
+        private static final int MAX_LEN = 34; // defined by [3]
         final String countryCode;
         final RegexValidator validator;
         final int lengthOfIBAN; // used to avoid unnecessary regex matching
         public Validator(String cc, int len, String format) {
-            this.countryCode = cc;
-            this.lengthOfIBAN = len;
-            this.validator = new RegexValidator(format);
+            if (!(cc.length() == 2 && Character.isUpperCase(cc.charAt(0)) &&
Character.isUpperCase(cc.charAt(1)))) {
+                throw new IllegalArgumentException("Invalid country Code; must be exactly
2 upper-case characters");
+            }
+            if (len > MAX_LEN || len < MIN_LEN) {
+                throw new IllegalArgumentException("Invalid length parameter, must be in
range "+MIN_LEN+" to "+MAX_LEN+" inclusive: " +len);
+            }
             if (!format.startsWith(cc)) {
                 throw new IllegalArgumentException("countryCode '"+cc+"' does not agree with
format: " + format);
             }
+            this.countryCode = cc;
+            this.lengthOfIBAN = len;
+            this.validator = new RegexValidator(format);
         }
     }
 
@@ -51,78 +70,87 @@ public class IBANValidator {
      * The IBANCheckDigit code treats upper and lower case the same,
      * so any case validation has to be done in this class.
      *
+     * Note: the European Payments council has a document [3] which includes a description
+     * of the IBAN. Section 5 clearly states that only upper case is allowed.
+     * Also the maximum length is 34 characters (including the country code),
+     * and the length is fixed for each country.
+     *
+     * It looks like lower-case is permitted in BBANs, but they must be converted to
+     * upper case for IBANs.
+     *
      * [1] https://en.wikipedia.org/wiki/International_Bank_Account_Number
      * [2] http://www.swift.com/dsp/resources/documents/IBAN_Registry.pdf
+     * [3] http://www.europeanpaymentscouncil.eu/documents/ECBS%20IBAN%20standard%20EBS204_V3.2.pdf
      */
     
     private static final Validator[] DEFAULT_FORMATS = {
-            new Validator("AL", 28, "AL\\d{10}[a-zA-Z0-9]{16}"              ), // Albania
-            new Validator("AD", 24, "AD\\d{10}[a-zA-Z0-9]{12}"              ), // Andorra
+            new Validator("AL", 28, "AL\\d{10}[A-Z0-9]{16}"                 ), // Albania
+            new Validator("AD", 24, "AD\\d{10}[A-Z0-9]{12}"                 ), // Andorra
             new Validator("AT", 20, "AT\\d{18}"                             ), // Austria
-            new Validator("AZ", 28, "AZ\\d{2}[A-Z]{4}[a-zA-Z0-9]{20}"       ), // Republic
of Azerbaijan
-            new Validator("BH", 22, "BH\\d{2}[A-Z]{4}[a-zA-Z0-9]{14}"       ), // Bahrain
(Kingdom of)
+            new Validator("AZ", 28, "AZ\\d{2}[A-Z]{4}[A-Z0-9]{20}"          ), // Republic
of Azerbaijan
+            new Validator("BH", 22, "BH\\d{2}[A-Z]{4}[A-Z0-9]{14}"          ), // Bahrain
(Kingdom of)
             new Validator("BE", 16, "BE\\d{14}"                             ), // Belgium
             new Validator("BA", 20, "BA\\d{18}"                             ), // Bosnia
and Herzegovina
-            new Validator("BR", 29, "BR\\d{25}[A-Z]{1}[a-zA-Z0-9]{1}"       ), // Brazil
-            new Validator("BG", 22, "BG\\d{2}[A-Z]{4}\\d{6}[a-zA-Z0-9]{8}"  ), // Bulgaria
+            new Validator("BR", 29, "BR\\d{25}[A-Z]{1}[A-Z0-9]{1}"          ), // Brazil
+            new Validator("BG", 22, "BG\\d{2}[A-Z]{4}\\d{6}[A-Z0-9]{8}"     ), // Bulgaria
             new Validator("CR", 21, "CR\\d{19}"                             ), // Costa Rica
             new Validator("HR", 21, "HR\\d{19}"                             ), // Croatia
-            new Validator("CY", 28, "CY\\d{10}[a-zA-Z0-9]{16}"              ), // Cyprus
+            new Validator("CY", 28, "CY\\d{10}[A-Z0-9]{16}"                 ), // Cyprus
             new Validator("CZ", 24, "CZ\\d{22}"                             ), // Czech Republic
             new Validator("DK", 18, "DK\\d{16}"                             ), // Denmark
             new Validator("FO", 18, "FO\\d{16}"                             ), // Denmark
(Faroes)
             new Validator("GL", 18, "GL\\d{16}"                             ), // Denmark
(Greenland)
-            new Validator("DO", 28, "DO\\d{2}[a-zA-Z0-9]{4}\\d{20}"         ), // Dominican
Republic
+            new Validator("DO", 28, "DO\\d{2}[A-Z0-9]{4}\\d{20}"            ), // Dominican
Republic
             new Validator("EE", 20, "EE\\d{18}"                             ), // Estonia
             new Validator("FI", 18, "FI\\d{16}"                             ), // Finland
-            new Validator("FR", 27, "FR\\d{12}[a-zA-Z0-9]{11}\\d{2}"        ), // France
+            new Validator("FR", 27, "FR\\d{12}[A-Z0-9]{11}\\d{2}"           ), // France
             new Validator("GE", 22, "GE\\d{2}[A-Z]{2}\\d{16}"               ), // Georgia
             new Validator("DE", 22, "DE\\d{20}"                             ), // Germany
-            new Validator("GI", 23, "GI\\d{2}[A-Z]{4}[a-zA-Z0-9]{15}"       ), // Gibraltar
-            new Validator("GR", 27, "GR\\d{9}[a-zA-Z0-9]{16}"               ), // Greece
-            new Validator("GT", 28, "GT\\d{2}[a-zA-Z0-9]{24}"               ), // Guatemala
+            new Validator("GI", 23, "GI\\d{2}[A-Z]{4}[A-Z0-9]{15}"          ), // Gibraltar
+            new Validator("GR", 27, "GR\\d{9}[A-Z0-9]{16}"                  ), // Greece
+            new Validator("GT", 28, "GT\\d{2}[A-Z0-9]{24}"                  ), // Guatemala
             new Validator("HU", 28, "HU\\d{26}"                             ), // Hungary
             new Validator("IS", 26, "IS\\d{24}"                             ), // Iceland
             new Validator("IE", 22, "IE\\d{2}[A-Z]{4}\\d{14}"               ), // Ireland
             new Validator("IL", 23, "IL\\d{21}"                             ), // Israel
-            new Validator("IT", 27, "IT\\d{2}[A-Z]{1}\\d{10}[a-zA-Z0-9]{12}"), // Italy
-            new Validator("JO", 30, "JO\\d{2}[A-Z]{4}\\d{4}[a-zA-Z0-9]{18}" ), // Jordan
-            new Validator("KZ", 20, "KZ\\d{5}[a-zA-Z0-9]{13}"               ), // Kazakhstan
+            new Validator("IT", 27, "IT\\d{2}[A-Z]{1}\\d{10}[A-Z0-9]{12}"   ), // Italy
+            new Validator("JO", 30, "JO\\d{2}[A-Z]{4}\\d{4}[A-Z0-9]{18}"    ), // Jordan
+            new Validator("KZ", 20, "KZ\\d{5}[A-Z0-9]{13}"                  ), // Kazakhstan
             new Validator("XK", 20, "XK\\d{18}"                             ), // Republic
of Kosovo
-            new Validator("KW", 30, "KW\\d{2}[A-Z]{4}[a-zA-Z0-9]{22}"       ), // Kuwait
-            new Validator("LV", 21, "LV\\d{2}[A-Z]{4}[a-zA-Z0-9]{13}"       ), // Latvia
-            new Validator("LB", 28, "LB\\d{6}[a-zA-Z0-9]{20}"               ), // Lebanon
-            new Validator("LI", 21, "LI\\d{7}[a-zA-Z0-9]{12}"               ), // Liechtenstein
(Principality of)
+            new Validator("KW", 30, "KW\\d{2}[A-Z]{4}[A-Z0-9]{22}"          ), // Kuwait
+            new Validator("LV", 21, "LV\\d{2}[A-Z]{4}[A-Z0-9]{13}"          ), // Latvia
+            new Validator("LB", 28, "LB\\d{6}[A-Z0-9]{20}"                  ), // Lebanon
+            new Validator("LI", 21, "LI\\d{7}[A-Z0-9]{12}"                  ), // Liechtenstein
(Principality of)
             new Validator("LT", 20, "LT\\d{18}"                             ), // Lithuania
-            new Validator("LU", 20, "LU\\d{5}[a-zA-Z0-9]{13}"               ), // Luxembourg
-            new Validator("MK", 19, "MK\\d{5}[a-zA-Z0-9]{10}\\d{2}"         ), // Macedonia,
Former Yugoslav Republic of
-            new Validator("MT", 31, "MT\\d{2}[A-Z]{4}\\d{5}[a-zA-Z0-9]{18}" ), // Malta
+            new Validator("LU", 20, "LU\\d{5}[A-Z0-9]{13}"                  ), // Luxembourg
+            new Validator("MK", 19, "MK\\d{5}[A-Z0-9]{10}\\d{2}"            ), // Macedonia,
Former Yugoslav Republic of
+            new Validator("MT", 31, "MT\\d{2}[A-Z]{4}\\d{5}[A-Z0-9]{18}"    ), // Malta
             new Validator("MR", 27, "MR13\\d{23}"                           ), // Mauritania
             new Validator("MU", 30, "MU\\d{2}[A-Z]{4}\\d{19}[A-Z]{3}"       ), // Mauritius
-            new Validator("MD", 24, "MD\\d{2}[a-zA-Z0-9]{20}"               ), // Moldova
-            new Validator("MC", 27, "MC\\d{12}[a-zA-Z0-9]{11}\\d{2}"        ), // Monaco
+            new Validator("MD", 24, "MD\\d{2}[A-Z0-9]{20}"                  ), // Moldova
+            new Validator("MC", 27, "MC\\d{12}[A-Z0-9]{11}\\d{2}"           ), // Monaco
             new Validator("ME", 22, "ME\\d{20}"                             ), // Montenegro
             new Validator("NL", 18, "NL\\d{2}[A-Z]{4}\\d{10}"               ), // The Netherlands
             new Validator("NO", 15, "NO\\d{13}"                             ), // Norway
-            new Validator("PK", 24, "PK\\d{2}[A-Z]{4}[a-zA-Z0-9]{16}"       ), // Pakistan
-            new Validator("PS", 29, "PS\\d{2}[A-Z]{4}[a-zA-Z0-9]{21}"       ), // Palestine,
State of
+            new Validator("PK", 24, "PK\\d{2}[A-Z]{4}[A-Z0-9]{16}"          ), // Pakistan
+            new Validator("PS", 29, "PS\\d{2}[A-Z]{4}[A-Z0-9]{21}"          ), // Palestine,
State of
             new Validator("PL", 28, "PL\\d{26}"                             ), // Poland
             new Validator("PT", 25, "PT\\d{23}"                             ), // Portugal
-            new Validator("QA", 29, "QA\\d{2}[A-Z]{4}[a-zA-Z0-9]{21}"       ), // Qatar
-            new Validator("RO", 24, "RO\\d{2}[A-Z]{4}[a-zA-Z0-9]{16}"       ), // Romania
+            new Validator("QA", 29, "QA\\d{2}[A-Z]{4}[A-Z0-9]{21}"          ), // Qatar
+            new Validator("RO", 24, "RO\\d{2}[A-Z]{4}[A-Z0-9]{16}"          ), // Romania
             new Validator("LC", 32, "LC\\d{2}[A-Z]{4}\\d{24}"               ), // Saint Lucia
-            new Validator("SM", 27, "SM\\d{2}[A-Z]{1}\\d{10}[a-zA-Z0-9]{12}"), // San Marino
+            new Validator("SM", 27, "SM\\d{2}[A-Z]{1}\\d{10}[A-Z0-9]{12}"   ), // San Marino
             new Validator("ST", 25, "ST\\d{23}"                             ), // Sao Tome
And Principe
-            new Validator("SA", 24, "SA\\d{4}[a-zA-Z0-9]{18}"               ), // Saudi Arabia
+            new Validator("SA", 24, "SA\\d{4}[A-Z0-9]{18}"                  ), // Saudi Arabia
             new Validator("RS", 22, "RS\\d{20}"                             ), // Serbia
             new Validator("SK", 24, "SK\\d{22}"                             ), // Slovak
Republic
             new Validator("SI", 19, "SI\\d{17}"                             ), // Slovenia
             new Validator("ES", 24, "ES\\d{22}"                             ), // Spain
             new Validator("SE", 24, "SE\\d{22}"                             ), // Sweden
-            new Validator("CH", 21, "CH\\d{7}[a-zA-Z0-9]{12}"               ), // Switzerland
+            new Validator("CH", 21, "CH\\d{7}[A-Z0-9]{12}"                  ), // Switzerland
             new Validator("TL", 23, "TL\\d{21}"                             ), // Timor-Leste
             new Validator("TN", 24, "TN59\\d{20}"                           ), // Tunisia
-            new Validator("TR", 26, "TR\\d{8}[a-zA-Z0-9]{16}"               ), // Turkey
+            new Validator("TR", 26, "TR\\d{8}[A-Z0-9]{16}"                  ), // Turkey
             new Validator("AE", 23, "AE\\d{21}"                             ), // United
Arab Emirates
             new Validator("GB", 22, "GB\\d{2}[A-Z]{4}\\d{14}"               ), // United
Kingdom
             new Validator("VG", 24, "VG\\d{2}[A-Z]{4}\\d{16}"               ), // Virgin
Islands, British
@@ -187,11 +215,64 @@ public class IBANValidator {
         return getValidator(code) != null;
     }
 
-    private Validator getValidator(String code) {
+    /**
+     * Gets a copy of the default Validators.
+     * 
+     * @return a copy of the default Validator array
+     */
+    public Validator[] getDefaultValidators() {
+        return Arrays.copyOf(DEFAULT_FORMATS, DEFAULT_FORMATS.length);
+    }
+
+    /**
+     * Get the Validator for a given IBAN
+     * 
+     * @param code a string starting with the ISO country code (e.g. an IBAN)
+     * 
+     * @return the validator or {@code null} if there is not one registered.
+     */
+    public Validator getValidator(String code) {
         if (code == null || code.length() < 2) { // ensure we can extract the code
             return null;
         }
         String key = code.substring(0, 2);
         return formatValidators.get(key);
     }
+
+    /**
+     * Installs a validator.
+     * Will replace any existing entry which has the same countryCode
+     * 
+     * @param validator the instance to install.
+     * @return the previous Validator, or {@code null} if there was none
+     * @throws IllegalStateException if an attempt is made to modify the singleton validator
+     */
+    public Validator setValidator(Validator validator) {
+        if (this == DEFAULT_IBAN_VALIDATOR) {
+            throw new IllegalStateException("The singleton validator cannot be modified");
+        }
+        return formatValidators.put(validator.countryCode, validator);
+    }
+
+    /**
+     * Installs a validator.
+     * Will replace any existing entry which has the same countryCode.
+     * 
+     * @param countryCode
+     * @param length the length of the IBAN. Must be &ge; 8 and &le; 32.
+     * If the length is &lt; 0, the validator is removed, and the format is not used.
+     * @param format the format of the IBAN (as a regular expression)
+     * @return the previous Validator, or {@code null} if there was none
+     * @throws IllegalArgumentException if there is a problem
+     * @throws IllegalStateException if an attempt is made to modify the singleton validator
+     */
+    public Validator setValidator(String countryCode, int length, String format) {
+        if (this == DEFAULT_IBAN_VALIDATOR) {
+            throw new IllegalStateException("The singleton validator cannot be modified");
+        }
+        if (length < 0) {
+            return formatValidators.remove(countryCode);
+        }
+        return setValidator(new Validator(countryCode, length, format));
+    }
 }

Modified: commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java?rev=1713224&r1=1713223&r2=1713224&view=diff
==============================================================================
--- commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java
(original)
+++ commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/IBANValidatorTest.java
Sun Nov  8 13:07:01 2015
@@ -16,14 +16,19 @@
  */
 package org.apache.commons.validator.routines;
 
-import org.apache.commons.validator.routines.checkdigit.IBANCheckDigit;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
-import junit.framework.TestCase;
+import org.apache.commons.validator.routines.checkdigit.IBANCheckDigit;
+import org.junit.Test;
 
 /**
  * IBANValidator Test Case.
+ * @since 1.5.0
  */
-public class IBANValidatorTest extends TestCase {
+public class IBANValidatorTest {
 
     // It's not clear whether IBANs can contain lower case characters
     // so we test for both where possible
@@ -52,7 +57,6 @@ public class IBANValidatorTest extends T
             "FI2112345600000785",
             "FI5542345670000081",
             "FR1420041010050500013M02606",
-            "FR1420041010050500013m02606", // lowercase version
             "GE29NB0000000101904917",
             "DE89370400440532013000",
             "GI75NWBK000000007099453",
@@ -70,12 +74,10 @@ public class IBANValidatorTest extends T
             "LV80BANK0000435195001",
             "LB62099900000001001901229114",
             "LI21088100002324013AA",
-            "LI21088100002324013aa", // lowercase version
             "LT121000011101001000",
             "LU280019400644750000",
             "MK07250120000058984",
             "MT84MALT011000012345MTLCAST001S",
-            "MT84MALT011000012345mtlcast001s", // lowercase version
             "MR1300020001010000123456753",
             "MU17BOMM0101101030300200000MUR",
             "MD24AG000225100013104168",
@@ -88,9 +90,7 @@ public class IBANValidatorTest extends T
             "PL61109010140000071219812874",
             "PT50000201231234567890154",
             "QA58DOHB00001234567890ABCDEFG",
-            "QA58DOHB00001234567890abcdefg", // lowercase version
             "RO49AAAA1B31007593840000",
-            "RO49AAAA1b31007593840000", // lowercase version
             "LC55HEMM000100010012001200023015", // the SWIFT docs have LC62...
             "SM86U0322509800000000270100",
             "ST68000100010051845310112",
@@ -114,39 +114,81 @@ public class IBANValidatorTest extends T
             "   ",                     // empty
             "A",                       // too short
             "AB",                      // too short
+            "FR1420041010050500013m02606", // lowercase version
+            "MT84MALT011000012345mtlcast001s", // lowercase version
+            "LI21088100002324013aa", // lowercase version
+            "QA58DOHB00001234567890abcdefg", // lowercase version
+            "RO49AAAA1b31007593840000", // lowercase version
+            "LC62HEMM000100010012001200023015", // wrong in SWIFT
             };
 
-    private IBANValidator validator;
-
-    @Override
-    protected void setUp() {
-        validator = IBANValidator.getInstance();
-    }
-
-    public IBANValidatorTest(String name) {
-        super(name);
-    }
+    private static final IBANValidator VALIDATOR = IBANValidator.getInstance();
 
+    @Test
     public void testValid() {
         for(String f : validIBANFormat) {
             assertTrue("Checksum fail: "+f, IBANCheckDigit.IBAN_CHECK_DIGIT.isValid(f));
-            assertTrue("Missing validator: "+f, validator.hasValidator(f));
-            assertTrue(f, validator.isValid(f));
+            assertTrue("Missing validator: "+f, VALIDATOR.hasValidator(f));
+            assertTrue(f, VALIDATOR.isValid(f));
         }
     }
 
+    @Test
     public void testInValid() {
         for(String f : invalidIBANFormat) {
-            assertFalse(f, validator.isValid(f));
+            assertFalse(f, VALIDATOR.isValid(f));
         }
     }
 
+    @Test
     public void testNull() {
-        assertFalse("isValid(null)",  validator.isValid(null));
+        assertFalse("isValid(null)",  VALIDATOR.isValid(null));
     }
 
+    @Test
     public void testHasValidator() {
-        assertTrue("GB", validator.hasValidator("GB"));
-        assertFalse("gb", validator.hasValidator("gb"));
+        assertTrue("GB", VALIDATOR.hasValidator("GB"));
+        assertFalse("gb", VALIDATOR.hasValidator("gb"));
+    }
+
+    @Test
+    public void testGetValidator() {
+        assertNotNull("GB", VALIDATOR.getValidator("GB"));
+        assertNull("gb", VALIDATOR.getValidator("gb"));        
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testSetDefaultValidator1() {
+        assertNotNull(VALIDATOR.setValidator("GB", 15, "GB"));
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testSetDefaultValidator2() {
+        assertNotNull(VALIDATOR.setValidator("GB", -1, "GB"));
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetValidatorLC() {
+        IBANValidator validator = new IBANValidator();
+        assertNotNull(validator.setValidator("gb", 15, "GB"));
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetValidatorLen7() {
+        IBANValidator validator = new IBANValidator();
+        assertNotNull(validator.setValidator("GB", 7, "GB"));
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetValidatorLen35() {
+        IBANValidator validator = new IBANValidator();
+        assertNotNull(validator.setValidator("GB", 35, "GB")); // valid params, but immutable
validator
+    }
+
+    @Test
+    public void testSetValidatorLen_1() {
+        IBANValidator validator = new IBANValidator();
+        assertNotNull("should be present",validator.setValidator("GB", -1, ""));
+        assertNull("no longer present",validator.setValidator("GB", -1, ""));
     }
 }



Mime
View raw message