View Javadoc

1   /*
2    * Copyright 2006 Christian Kalkhoff <me@ninan.info>
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package net.sf.plausj.bank.german;
18  
19  import net.sf.plausj.bank.german.strategy.Strategy;
20  import net.sf.plausj.bank.german.util.StrategyHelper;
21  import net.sf.plausj.bank.german.util.StrategyHelperImpl;
22  
23  /**
24   * This is a german bank account object.
25   * 
26   * @author ninan
27   * 
28   */
29  public class BankAccount {
30  
31  	/** Used internally to represent default value */
32  	private static final int UNSET = 0;
33  
34  	/** No strategy is responsible for this bank account */
35  	public static final int NOCHECK = 2;
36  
37  	/** All strategies said this bank account is valid */
38  	public static final int VALID = 4;
39  
40  	/** All strategies said this bank account is invalid */
41  	public static final int INVALID = 8;
42  
43  	/** Used to signal that the bank code was not found */
44  	public static final int BANK_CODE_NOT_FOUND = 256;
45  
46  	/**
47  	 * Used to signal that the strategy referenced by the bank code is not
48  	 * implemented
49  	 */
50  	public static final int NOT_IMPLEMENTED = 512;
51  
52  	/** Some strategies said this bank account is valid, some said it is invalid */
53  	public static final int AMBIGUOUS1 = VALID | INVALID;
54  
55  	/**
56  	 * Some strategies said this bank account is valid, some said they are not
57  	 * responsible
58  	 */
59  	public static final int AMBIGUOUS2 = VALID | NOCHECK;
60  
61  	/**
62  	 * Some strategies said this bank account is invalid, some said they are not
63  	 * responsible
64  	 */
65  	public static final int AMBIGUOUS3 = INVALID | NOCHECK;
66  
67  	/**
68  	 * Some strategies said this bank account is valid, some said it is invalid
69  	 * and some said they are not responsible
70  	 */
71  	public static final int AMBIGUOUS4 = VALID | INVALID | NOCHECK;
72  
73  	/** Stores the instance of the bank code */
74  	private final BankCode bankCode;
75  
76  	/** Stores the instance of the account code */
77  	private final AccountCode accountCode;
78  
79  	/** Stores the validity of the bank account */
80  	private int validity = UNSET;
81  
82  	private final StrategyHelper sh = new StrategyHelperImpl();
83  
84  	/**
85  	 * The default CTOR for a bank account.
86  	 * 
87  	 * @param bankCode
88  	 *            The bank code of the account
89  	 * @param accountCode
90  	 *            The account code
91  	 * @throws IllegalArgumentException
92  	 *             If bank account or bank code are invalid this exception is
93  	 *             thrown
94  	 */
95  	public BankAccount(final BankCode bankCode, final AccountCode accountCode)
96  			throws IllegalArgumentException {
97  
98  		if (null == bankCode) {
99  			throw new IllegalArgumentException(
100 					"Null pointer supplied as bank code.");
101 		}
102 
103 		if (null == accountCode) {
104 			throw new IllegalArgumentException(
105 					"Null pointer supplied as account code.");
106 		}
107 
108 		this.bankCode = bankCode;
109 		this.accountCode = accountCode;
110 
111 		calculateValidity();
112 
113 	}
114 
115 	/**
116 	 * An comfort CTOR using strings instead of objects for bank code and
117 	 * account code
118 	 * 
119 	 * @param bankCode
120 	 *            The bank code of the account
121 	 * @param accountCode
122 	 *            The account code
123 	 * @throws IllegalArgumentException
124 	 *             If bank account or bank code are invalid this exception is
125 	 *             thrown
126 	 */
127 	public BankAccount(final String bankCode, final String accountCode)
128 			throws IllegalArgumentException {
129 
130 		this(new BankCode(bankCode), new AccountCode(accountCode));
131 
132 	}
133 
134 	/**
135 	 * Returns the validity of this bank account. It returns an integer from the
136 	 * range of the MAGICs in this class
137 	 * 
138 	 * @return The validity of the bank account
139 	 * 
140 	 * @see BankAccount#NOCHECK
141 	 * @see BankAccount#VALID
142 	 * @see BankAccount#INVALID
143 	 * @see BankAccount#BLZ_NOT_FOUND
144 	 * @see BankAccount#NOT_IMPLEMENTED
145 	 * @see BankAccount#AMBIGUOUS1
146 	 * @see BankAccount#AMBIGUOUS2
147 	 * @see BankAccount#AMBIGUOUS3
148 	 * @see BankAccount#AMBIGUOUS4
149 	 */
150 	public int getValidity() {
151 		return validity;
152 	}
153 
154 	/**
155 	 * Return the validity as string constant
156 	 * 
157 	 * @return The validity as string
158 	 */
159 	public String getValidityAsString() {
160 
161 		if (UNSET == validity)
162 			return "UNSET";
163 
164 		if (VALID == validity)
165 			return "VALID";
166 
167 		if (INVALID == validity)
168 			return "INVALID";
169 
170 		if (NOCHECK == validity)
171 			return "NOCHECK";
172 
173 		if (BANK_CODE_NOT_FOUND == validity)
174 			return "BANK_CODE_NOT_FOUND";
175 
176 		if (NOT_IMPLEMENTED == validity)
177 			return "NOT_IMPLEMENTED";
178 
179 		if (AMBIGUOUS1 == validity)
180 			return "AMBIGUOUS1";
181 
182 		if (AMBIGUOUS2 == validity)
183 			return "AMBIGUOUS2";
184 
185 		if (AMBIGUOUS3 == validity)
186 			return "AMBIGUOUS3";
187 
188 		if (AMBIGUOUS4 == validity)
189 			return "AMBIGUOUS4";
190 
191 		return "UNKNOWN";
192 
193 	}
194 
195 	/**
196 	 * @return Returns the accountCode.
197 	 */
198 	public AccountCode getAccountCode() {
199 		return accountCode;
200 	}
201 
202 	/**
203 	 * @return Returns the bankCode.
204 	 */
205 	public BankCode getBankCode() {
206 		return bankCode;
207 	}
208 
209 	/**
210 	 * Calculates the validity of the bank account
211 	 * 
212 	 */
213 	private void calculateValidity() {
214 
215 		final Strategy[] strategies = sh.getStrategiesByBankCode(bankCode);
216 
217 		// There are no strategies for this bank code
218 		if (null == strategies) {
219 			validity = NOCHECK;
220 			return;
221 		}
222 
223 		for (int i = 0; i < strategies.length; ++i) {
224 			Strategy s = strategies[i];
225 			CheckDigit cd = s.calculateCheckDigit(bankCode, accountCode);
226 
227 			// The following lines set bits on the validity integer
228 			if (null == cd) {
229 				validity |= NOCHECK;
230 				continue;
231 			}
232 
233 			if (cd.isAlwaysValid()) {
234 				validity |= VALID;
235 				continue;
236 			}
237 
238 			if (cd.isAlwaysInvalid()) {
239 				validity |= INVALID;
240 				continue;
241 			}
242 
243 			if (cd.isBankCodeNotFound()) {
244 				// Not an error, if bank code not found, there may be no other
245 				// checks
246 				validity = BANK_CODE_NOT_FOUND;
247 				return;
248 			}
249 
250 			if (cd.isNotImplemented()) {
251 				// That míght be an bug or something, so we do an absolute thing
252 				validity = NOT_IMPLEMENTED;
253 				return;
254 			}
255 
256 			if (accountCode.matchesCheckDigit(cd)) {
257 				validity |= VALID;
258 				continue;
259 			} else {
260 				validity |= INVALID;
261 				continue;
262 			}
263 		}
264 	}
265 
266 	/**
267 	 * @see java.lang.Object#toString()
268 	 */
269 	public String toString() {
270 		return "[BankCode='" + bankCode + "'; AccountCode='" + accountCode
271 				+ "'; validity='" + getValidityAsString() + "(" + getValidity()
272 				+ ")']";
273 	}
274 
275 }