1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
package org.apache.commons.validator.routines; |
18 | |
|
19 | |
import java.util.Arrays; |
20 | |
import java.util.Map; |
21 | |
import java.util.concurrent.ConcurrentHashMap; |
22 | |
|
23 | |
import org.apache.commons.validator.routines.RegexValidator; |
24 | |
import org.apache.commons.validator.routines.checkdigit.IBANCheckDigit; |
25 | |
|
26 | |
|
27 | |
|
28 | |
|
29 | |
|
30 | |
public class IBANValidator { |
31 | |
|
32 | |
private final Map<String, Validator> formatValidators; |
33 | |
|
34 | |
|
35 | |
|
36 | |
|
37 | |
public static class Validator { |
38 | |
|
39 | |
|
40 | |
|
41 | |
|
42 | |
|
43 | |
|
44 | |
|
45 | |
|
46 | |
|
47 | |
private static final int MIN_LEN = 8; |
48 | |
private static final int MAX_LEN = 34; |
49 | |
final String countryCode; |
50 | |
final RegexValidator validator; |
51 | |
final int lengthOfIBAN; |
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
|
58 | |
|
59 | 77 | public Validator(String cc, int len, String format) { |
60 | 77 | if (!(cc.length() == 2 && Character.isUpperCase(cc.charAt(0)) && Character.isUpperCase(cc.charAt(1)))) { |
61 | 1 | throw new IllegalArgumentException("Invalid country Code; must be exactly 2 upper-case characters"); |
62 | |
} |
63 | 76 | if (len > MAX_LEN || len < MIN_LEN) { |
64 | 2 | throw new IllegalArgumentException("Invalid length parameter, must be in range "+MIN_LEN+" to "+MAX_LEN+" inclusive: " +len); |
65 | |
} |
66 | 74 | if (!format.startsWith(cc)) { |
67 | 0 | throw new IllegalArgumentException("countryCode '"+cc+"' does not agree with format: " + format); |
68 | |
} |
69 | 74 | this.countryCode = cc; |
70 | 74 | this.lengthOfIBAN = len; |
71 | 74 | this.validator = new RegexValidator(format); |
72 | 74 | } |
73 | |
} |
74 | |
|
75 | |
|
76 | |
|
77 | |
|
78 | |
|
79 | |
|
80 | |
|
81 | |
|
82 | |
|
83 | |
|
84 | |
|
85 | |
|
86 | |
|
87 | |
|
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
|
94 | |
|
95 | |
|
96 | 1 | private static final Validator[] DEFAULT_FORMATS = { |
97 | |
new Validator("AD", 24, "AD\\d{10}[A-Z0-9]{12}" ), |
98 | |
new Validator("AE", 23, "AE\\d{21}" ), |
99 | |
new Validator("AL", 28, "AL\\d{10}[A-Z0-9]{16}" ), |
100 | |
new Validator("AT", 20, "AT\\d{18}" ), |
101 | |
new Validator("AZ", 28, "AZ\\d{2}[A-Z]{4}[A-Z0-9]{20}" ), |
102 | |
new Validator("BA", 20, "BA\\d{18}" ), |
103 | |
new Validator("BE", 16, "BE\\d{14}" ), |
104 | |
new Validator("BG", 22, "BG\\d{2}[A-Z]{4}\\d{6}[A-Z0-9]{8}" ), |
105 | |
new Validator("BH", 22, "BH\\d{2}[A-Z]{4}[A-Z0-9]{14}" ), |
106 | |
new Validator("BR", 29, "BR\\d{25}[A-Z]{1}[A-Z0-9]{1}" ), |
107 | |
new Validator("BY", 28, "BY\\d{2}[A-Z0-9]{4}\\d{4}[A-Z0-9]{16}" ), |
108 | |
new Validator("CH", 21, "CH\\d{7}[A-Z0-9]{12}" ), |
109 | |
new Validator("CR", 22, "CR\\d{20}" ), |
110 | |
new Validator("CY", 28, "CY\\d{10}[A-Z0-9]{16}" ), |
111 | |
new Validator("CZ", 24, "CZ\\d{22}" ), |
112 | |
new Validator("DE", 22, "DE\\d{20}" ), |
113 | |
new Validator("DK", 18, "DK\\d{16}" ), |
114 | |
new Validator("DO", 28, "DO\\d{2}[A-Z0-9]{4}\\d{20}" ), |
115 | |
new Validator("EE", 20, "EE\\d{18}" ), |
116 | |
new Validator("ES", 24, "ES\\d{22}" ), |
117 | |
new Validator("FI", 18, "FI\\d{16}" ), |
118 | |
new Validator("FO", 18, "FO\\d{16}" ), |
119 | |
new Validator("FR", 27, "FR\\d{12}[A-Z0-9]{11}\\d{2}" ), |
120 | |
new Validator("GB", 22, "GB\\d{2}[A-Z]{4}\\d{14}" ), |
121 | |
new Validator("GE", 22, "GE\\d{2}[A-Z]{2}\\d{16}" ), |
122 | |
new Validator("GI", 23, "GI\\d{2}[A-Z]{4}[A-Z0-9]{15}" ), |
123 | |
new Validator("GL", 18, "GL\\d{16}" ), |
124 | |
new Validator("GR", 27, "GR\\d{9}[A-Z0-9]{16}" ), |
125 | |
new Validator("GT", 28, "GT\\d{2}[A-Z0-9]{24}" ), |
126 | |
new Validator("HR", 21, "HR\\d{19}" ), |
127 | |
new Validator("HU", 28, "HU\\d{26}" ), |
128 | |
new Validator("IE", 22, "IE\\d{2}[A-Z]{4}\\d{14}" ), |
129 | |
new Validator("IL", 23, "IL\\d{21}" ), |
130 | |
new Validator("IS", 26, "IS\\d{24}" ), |
131 | |
new Validator("IT", 27, "IT\\d{2}[A-Z]{1}\\d{10}[A-Z0-9]{12}" ), |
132 | |
new Validator("IQ", 23, "IQ\\d{2}[A-Z]{4}\\d{15}" ), |
133 | |
new Validator("JO", 30, "JO\\d{2}[A-Z]{4}\\d{4}[A-Z0-9]{18}" ), |
134 | |
new Validator("KW", 30, "KW\\d{2}[A-Z]{4}[A-Z0-9]{22}" ), |
135 | |
new Validator("KZ", 20, "KZ\\d{5}[A-Z0-9]{13}" ), |
136 | |
new Validator("LB", 28, "LB\\d{6}[A-Z0-9]{20}" ), |
137 | |
new Validator("LC", 32, "LC\\d{2}[A-Z]{4}[A-Z0-9]{24}" ), |
138 | |
new Validator("LI", 21, "LI\\d{7}[A-Z0-9]{12}" ), |
139 | |
new Validator("LT", 20, "LT\\d{18}" ), |
140 | |
new Validator("LU", 20, "LU\\d{5}[A-Z0-9]{13}" ), |
141 | |
new Validator("LV", 21, "LV\\d{2}[A-Z]{4}[A-Z0-9]{13}" ), |
142 | |
new Validator("MC", 27, "MC\\d{12}[A-Z0-9]{11}\\d{2}" ), |
143 | |
new Validator("MD", 24, "MD\\d{2}[A-Z0-9]{20}" ), |
144 | |
new Validator("ME", 22, "ME\\d{20}" ), |
145 | |
new Validator("MK", 19, "MK\\d{5}[A-Z0-9]{10}\\d{2}" ), |
146 | |
new Validator("MR", 27, "MR\\d{25}" ), |
147 | |
new Validator("MT", 31, "MT\\d{2}[A-Z]{4}\\d{5}[A-Z0-9]{18}" ), |
148 | |
new Validator("MU", 30, "MU\\d{2}[A-Z]{4}\\d{19}[A-Z]{3}" ), |
149 | |
new Validator("NL", 18, "NL\\d{2}[A-Z]{4}\\d{10}" ), |
150 | |
new Validator("NO", 15, "NO\\d{13}" ), |
151 | |
new Validator("PK", 24, "PK\\d{2}[A-Z]{4}[A-Z0-9]{16}" ), |
152 | |
new Validator("PL", 28, "PL\\d{26}" ), |
153 | |
new Validator("PS", 29, "PS\\d{2}[A-Z]{4}[A-Z0-9]{21}" ), |
154 | |
new Validator("PT", 25, "PT\\d{23}" ), |
155 | |
new Validator("QA", 29, "QA\\d{2}[A-Z]{4}[A-Z0-9]{21}" ), |
156 | |
new Validator("RO", 24, "RO\\d{2}[A-Z]{4}[A-Z0-9]{16}" ), |
157 | |
new Validator("RS", 22, "RS\\d{20}" ), |
158 | |
new Validator("SA", 24, "SA\\d{4}[A-Z0-9]{18}" ), |
159 | |
new Validator("SC", 31, "SC\\d{2}[A-Z]{4}\\d{20}[A-Z]{3}" ), |
160 | |
new Validator("SE", 24, "SE\\d{22}" ), |
161 | |
new Validator("SI", 19, "SI\\d{17}" ), |
162 | |
new Validator("SK", 24, "SK\\d{22}" ), |
163 | |
new Validator("SM", 27, "SM\\d{2}[A-Z]{1}\\d{10}[A-Z0-9]{12}" ), |
164 | |
new Validator("ST", 25, "ST\\d{23}" ), |
165 | |
new Validator("TL", 23, "TL\\d{21}" ), |
166 | |
new Validator("TN", 24, "TN\\d{22}" ), |
167 | |
new Validator("TR", 26, "TR\\d{8}[A-Z0-9]{16}" ), |
168 | |
new Validator("UA", 29, "UA\\d{8}[A-Z0-9]{19}" ), |
169 | |
new Validator("VG", 24, "VG\\d{2}[A-Z]{4}\\d{16}" ), |
170 | |
new Validator("XK", 20, "XK\\d{18}" ), |
171 | |
}; |
172 | |
|
173 | |
|
174 | 1 | public static final IBANValidator DEFAULT_IBAN_VALIDATOR = new IBANValidator(); |
175 | |
|
176 | |
|
177 | |
|
178 | |
|
179 | |
|
180 | |
|
181 | |
public static IBANValidator getInstance() { |
182 | 1 | return DEFAULT_IBAN_VALIDATOR; |
183 | |
} |
184 | |
|
185 | |
|
186 | |
|
187 | |
|
188 | |
public IBANValidator() { |
189 | 5 | this(DEFAULT_FORMATS); |
190 | 5 | } |
191 | |
|
192 | |
|
193 | |
|
194 | |
|
195 | |
|
196 | |
|
197 | 5 | public IBANValidator(Validator[] formatMap) { |
198 | 5 | this.formatValidators = createValidators(formatMap); |
199 | 5 | } |
200 | |
|
201 | |
private Map<String, Validator> createValidators(Validator[] formatMap) { |
202 | 5 | Map<String, Validator> m = new ConcurrentHashMap<String, Validator>(); |
203 | 375 | for(Validator v : formatMap) { |
204 | 370 | m.put(v.countryCode, v); |
205 | |
} |
206 | 5 | return m; |
207 | |
} |
208 | |
|
209 | |
|
210 | |
|
211 | |
|
212 | |
|
213 | |
|
214 | |
|
215 | |
public boolean isValid(String code) { |
216 | 93 | Validator formatValidator = getValidator(code); |
217 | 93 | if (formatValidator == null || code.length() != formatValidator.lengthOfIBAN || !formatValidator.validator.isValid(code)) { |
218 | 11 | return false; |
219 | |
} |
220 | 82 | return IBANCheckDigit.IBAN_CHECK_DIGIT.isValid(code); |
221 | |
} |
222 | |
|
223 | |
|
224 | |
|
225 | |
|
226 | |
|
227 | |
|
228 | |
|
229 | |
public boolean hasValidator(String code) { |
230 | 81 | return getValidator(code) != null; |
231 | |
} |
232 | |
|
233 | |
|
234 | |
|
235 | |
|
236 | |
|
237 | |
|
238 | |
public Validator[] getDefaultValidators() { |
239 | 0 | return Arrays.copyOf(DEFAULT_FORMATS, DEFAULT_FORMATS.length); |
240 | |
} |
241 | |
|
242 | |
|
243 | |
|
244 | |
|
245 | |
|
246 | |
|
247 | |
|
248 | |
|
249 | |
public Validator getValidator(String code) { |
250 | 176 | if (code == null || code.length() < 2) { |
251 | 3 | return null; |
252 | |
} |
253 | 173 | String key = code.substring(0, 2); |
254 | 173 | return formatValidators.get(key); |
255 | |
} |
256 | |
|
257 | |
|
258 | |
|
259 | |
|
260 | |
|
261 | |
|
262 | |
|
263 | |
|
264 | |
|
265 | |
public Validator setValidator(Validator validator) { |
266 | 0 | if (this == DEFAULT_IBAN_VALIDATOR) { |
267 | 0 | throw new IllegalStateException("The singleton validator cannot be modified"); |
268 | |
} |
269 | 0 | return formatValidators.put(validator.countryCode, validator); |
270 | |
} |
271 | |
|
272 | |
|
273 | |
|
274 | |
|
275 | |
|
276 | |
|
277 | |
|
278 | |
|
279 | |
|
280 | |
|
281 | |
|
282 | |
|
283 | |
|
284 | |
public Validator setValidator(String countryCode, int length, String format) { |
285 | 7 | if (this == DEFAULT_IBAN_VALIDATOR) { |
286 | 2 | throw new IllegalStateException("The singleton validator cannot be modified"); |
287 | |
} |
288 | 5 | if (length < 0) { |
289 | 2 | return formatValidators.remove(countryCode); |
290 | |
} |
291 | 3 | return setValidator(new Validator(countryCode, length, format)); |
292 | |
} |
293 | |
} |