1
2
3
4 package de.powerstat.validation.values;
5
6
7 import java.math.BigInteger;
8 import java.util.Objects;
9 import java.util.regex.Pattern;
10
11 import de.powerstat.validation.interfaces.IValueObject;
12 import de.powerstat.validation.values.impl.IBANVerifierAbstractFactory;
13
14
15
16
17
18
19
20
21
22
23 public final class IBAN implements Comparable<IBAN>, IValueObject
24 {
25
26
27
28
29
30
31
32
33 @SuppressWarnings("java:S5867")
34 private static final Pattern IBAN_REGEXP = Pattern.compile("^[A-Z]{2}\\d{2}[0-9A-Z]{11,30}$");
35
36
37
38
39 private final String iban;
40
41
42
43
44
45
46
47
48
49 private IBAN(final String iban)
50 {
51 super();
52 Objects.requireNonNull(iban, "iban");
53 if ((iban.length() < 15) || (iban.length() > 34))
54 {
55 throw new IllegalArgumentException("IBAN with wrong length");
56 }
57 if (!IBAN.IBAN_REGEXP.matcher(iban).matches())
58 {
59 throw new IllegalArgumentException("IBAN with wrong format");
60 }
61 final var checksum = iban.substring(2, 4);
62 if ("00".equals(checksum) || "01".equals(checksum) || "99".equals(checksum))
63 {
64 throw new IllegalArgumentException("IBAN with illegal checksum");
65 }
66 if (!verifyChecksum(iban))
67 {
68 throw new IllegalArgumentException("IBAN with wrong checksum");
69 }
70 final var country = Country.of(iban.substring(0, 2));
71 if (!IBANVerifierAbstractFactory.createIBANVerifier(country).verify(iban))
72 {
73 throw new IllegalArgumentException("IBAN not correct in country context: " + iban);
74 }
75 this.iban = iban;
76 }
77
78
79
80
81
82
83
84
85 private static boolean verifyChecksum(final String iban)
86 {
87 final String reordered = iban.substring(4) + iban.substring(0, 2) + iban.substring(2, 4);
88 final String replacement = reordered.replace("A", "10").replace("B", "11").replace("C", "12").replace("D", "13").replace("E", "14").replace("F", "15").replace("G", "16").replace("H", "17").replace("I", "18").replace("J", "19").replace("K", "20").replace("L", "21").replace("M", "22").replace("N", "23").replace("O", "24").replace("P", "25").replace("Q", "26").replace("R", "27").replace("S", "28").replace("T", "29").replace("U", "30").replace("V", "31").replace("W", "32").replace("X", "33").replace("Y", "34").replace("Z", "35");
89 final var num = new BigInteger(replacement);
90 final BigInteger result = num.remainder(BigInteger.valueOf(97));
91 return result.longValue() == 1;
92 }
93
94
95
96
97
98
99
100
101 public static IBAN of(final String iban)
102 {
103
104
105
106
107
108
109
110
111
112
113
114
115
116 return new IBAN(iban);
117 }
118
119
120
121
122
123
124
125 @Override
126 public String stringValue()
127 {
128 return this.iban;
129 }
130
131
132
133
134
135
136
137
138 @Override
139 public int hashCode()
140 {
141 return this.iban.hashCode();
142 }
143
144
145
146
147
148
149
150
151
152 @Override
153 public boolean equals(final Object obj)
154 {
155 if (this == obj)
156 {
157 return true;
158 }
159 if (!(obj instanceof IBAN))
160 {
161 return false;
162 }
163 final IBAN other = (IBAN)obj;
164 return this.iban.equals(other.iban);
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178 @Override
179 public String toString()
180 {
181 final var builder = new StringBuilder();
182 builder.append("IBAN[iban=").append(this.iban).append(']');
183 return builder.toString();
184 }
185
186
187
188
189
190
191
192
193
194 @Override
195 public int compareTo(final IBAN obj)
196 {
197 Objects.requireNonNull(obj, "obj");
198 return this.iban.compareTo(obj.iban);
199 }
200
201 }