Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
CreditCardValidator |
|
| 3.4;3.4 | ||||
CreditCardValidator$1 |
|
| 3.4;3.4 | ||||
CreditCardValidator$Amex |
|
| 3.4;3.4 | ||||
CreditCardValidator$CreditCardType |
|
| 3.4;3.4 | ||||
CreditCardValidator$Discover |
|
| 3.4;3.4 | ||||
CreditCardValidator$Mastercard |
|
| 3.4;3.4 | ||||
CreditCardValidator$Visa |
|
| 3.4;3.4 |
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; | |
18 | ||
19 | import java.util.ArrayList; | |
20 | import java.util.Collection; | |
21 | ||
22 | import org.apache.commons.validator.util.Flags; | |
23 | ||
24 | /** | |
25 | * Perform credit card validations. | |
26 | * | |
27 | * <p> | |
28 | * By default, all supported card types are allowed. You can specify which | |
29 | * cards should pass validation by configuring the validation options. For | |
30 | * example, | |
31 | * </p> | |
32 | * | |
33 | * <pre> | |
34 | * <code>CreditCardValidator ccv = new CreditCardValidator(CreditCardValidator.AMEX + CreditCardValidator.VISA);</code> | |
35 | * </pre> | |
36 | * | |
37 | * <p> | |
38 | * configures the validator to only pass American Express and Visa cards. | |
39 | * If a card type is not directly supported by this class, you can implement | |
40 | * the CreditCardType interface and pass an instance into the | |
41 | * <code>addAllowedCardType</code> method. | |
42 | * </p> | |
43 | * | |
44 | * <p> | |
45 | * For a similar implementation in Perl, reference Sean M. Burke's | |
46 | * <a href="http://www.speech.cs.cmu.edu/~sburke/pub/luhn_lib.html">script</a>. | |
47 | * More information is also available | |
48 | * <a href="http://www.merriampark.com/anatomycc.htm">here</a>. | |
49 | * </p> | |
50 | * | |
51 | * @version $Revision: 1739358 $ | |
52 | * @since Validator 1.1 | |
53 | * @deprecated Use the new CreditCardValidator in the routines package. This class | |
54 | * will be removed in a future release. | |
55 | */ | |
56 | // CHECKSTYLE:OFF (deprecated code) | |
57 | @Deprecated | |
58 | public class CreditCardValidator { | |
59 | ||
60 | /** | |
61 | * Option specifying that no cards are allowed. This is useful if | |
62 | * you want only custom card types to validate so you turn off the | |
63 | * default cards with this option. | |
64 | * <pre> | |
65 | * <code> | |
66 | * CreditCardValidator v = new CreditCardValidator(CreditCardValidator.NONE); | |
67 | * v.addAllowedCardType(customType); | |
68 | * v.isValid(aCardNumber); | |
69 | * </code> | |
70 | * </pre> | |
71 | * @since Validator 1.1.2 | |
72 | */ | |
73 | public static final int NONE = 0; | |
74 | ||
75 | /** | |
76 | * Option specifying that American Express cards are allowed. | |
77 | */ | |
78 | public static final int AMEX = 1 << 0; | |
79 | ||
80 | /** | |
81 | * Option specifying that Visa cards are allowed. | |
82 | */ | |
83 | public static final int VISA = 1 << 1; | |
84 | ||
85 | /** | |
86 | * Option specifying that Mastercard cards are allowed. | |
87 | */ | |
88 | public static final int MASTERCARD = 1 << 2; | |
89 | ||
90 | /** | |
91 | * Option specifying that Discover cards are allowed. | |
92 | */ | |
93 | public static final int DISCOVER = 1 << 3; | |
94 | ||
95 | /** | |
96 | * The CreditCardTypes that are allowed to pass validation. | |
97 | */ | |
98 | 3 | private final Collection<CreditCardType> cardTypes = new ArrayList<CreditCardType>(); |
99 | ||
100 | /** | |
101 | * Create a new CreditCardValidator with default options. | |
102 | */ | |
103 | public CreditCardValidator() { | |
104 | 1 | this(AMEX + VISA + MASTERCARD + DISCOVER); |
105 | 1 | } |
106 | ||
107 | /** | |
108 | * Creates a new CreditCardValidator with the specified options. | |
109 | * @param options Pass in | |
110 | * CreditCardValidator.VISA + CreditCardValidator.AMEX to specify that | |
111 | * those are the only valid card types. | |
112 | */ | |
113 | public CreditCardValidator(int options) { | |
114 | 3 | super(); |
115 | ||
116 | 3 | Flags f = new Flags(options); |
117 | 3 | if (f.isOn(VISA)) { |
118 | 1 | this.cardTypes.add(new Visa()); |
119 | } | |
120 | ||
121 | 3 | if (f.isOn(AMEX)) { |
122 | 2 | this.cardTypes.add(new Amex()); |
123 | } | |
124 | ||
125 | 3 | if (f.isOn(MASTERCARD)) { |
126 | 1 | this.cardTypes.add(new Mastercard()); |
127 | } | |
128 | ||
129 | 3 | if (f.isOn(DISCOVER)) { |
130 | 1 | this.cardTypes.add(new Discover()); |
131 | } | |
132 | 3 | } |
133 | ||
134 | /** | |
135 | * Checks if the field is a valid credit card number. | |
136 | * @param card The card number to validate. | |
137 | * @return Whether the card number is valid. | |
138 | */ | |
139 | public boolean isValid(String card) { | |
140 | 17 | if ((card == null) || (card.length() < 13) || (card.length() > 19)) { |
141 | 4 | return false; |
142 | } | |
143 | ||
144 | 13 | if (!this.luhnCheck(card)) { |
145 | 2 | return false; |
146 | } | |
147 | ||
148 | 11 | for (Object cardType : this.cardTypes) { |
149 | 13 | CreditCardType type = (CreditCardType) cardType; |
150 | 13 | if (type.matches(card)) { |
151 | 6 | return true; |
152 | } | |
153 | 7 | } |
154 | ||
155 | 5 | return false; |
156 | } | |
157 | ||
158 | /** | |
159 | * Adds an allowed CreditCardType that participates in the card | |
160 | * validation algorithm. | |
161 | * @param type The type that is now allowed to pass validation. | |
162 | * @since Validator 1.1.2 | |
163 | */ | |
164 | public void addAllowedCardType(CreditCardType type){ | |
165 | 1 | this.cardTypes.add(type); |
166 | 1 | } |
167 | ||
168 | /** | |
169 | * Checks for a valid credit card number. | |
170 | * @param cardNumber Credit Card Number. | |
171 | * @return Whether the card number passes the luhnCheck. | |
172 | */ | |
173 | protected boolean luhnCheck(String cardNumber) { | |
174 | // number must be validated as 0..9 numeric first!! | |
175 | 13 | int digits = cardNumber.length(); |
176 | 13 | int oddOrEven = digits & 1; |
177 | 13 | long sum = 0; |
178 | 202 | for (int count = 0; count < digits; count++) { |
179 | 190 | int digit = 0; |
180 | try { | |
181 | 190 | digit = Integer.parseInt(cardNumber.charAt(count) + ""); |
182 | 1 | } catch(NumberFormatException e) { |
183 | 1 | return false; |
184 | 189 | } |
185 | ||
186 | 189 | if (((count & 1) ^ oddOrEven) == 0) { // not |
187 | 93 | digit *= 2; |
188 | 93 | if (digit > 9) { |
189 | 29 | digit -= 9; |
190 | } | |
191 | } | |
192 | 189 | sum += digit; |
193 | } | |
194 | ||
195 | 12 | return (sum == 0) ? false : (sum % 10 == 0); |
196 | } | |
197 | ||
198 | /** | |
199 | * CreditCardType implementations define how validation is performed | |
200 | * for one type/brand of credit card. | |
201 | * @since Validator 1.1.2 | |
202 | */ | |
203 | public interface CreditCardType { | |
204 | ||
205 | /** | |
206 | * Returns true if the card number matches this type of credit | |
207 | * card. Note that this method is <strong>not</strong> responsible | |
208 | * for analyzing the general form of the card number because | |
209 | * <code>CreditCardValidator</code> performs those checks before | |
210 | * calling this method. It is generally only required to valid the | |
211 | * length and prefix of the number to determine if it's the correct | |
212 | * type. | |
213 | * @param card The card number, never null. | |
214 | * @return true if the number matches. | |
215 | */ | |
216 | boolean matches(String card); | |
217 | ||
218 | } | |
219 | ||
220 | /** | |
221 | * Change to support Visa Carte Blue used in France | |
222 | * has been removed - see Bug 35926 | |
223 | */ | |
224 | 2 | private static class Visa implements CreditCardType { |
225 | private static final String PREFIX = "4"; | |
226 | @Override | |
227 | public boolean matches(String card) { | |
228 | 5 | return ( |
229 | card.substring(0, 1).equals(PREFIX) | |
230 | && (card.length() == 13 || card.length() == 16)); | |
231 | } | |
232 | } | |
233 | ||
234 | 4 | private static class Amex implements CreditCardType { |
235 | private static final String PREFIX = "34,37,"; | |
236 | @Override | |
237 | public boolean matches(String card) { | |
238 | 4 | String prefix2 = card.substring(0, 2) + ","; |
239 | 4 | return ((PREFIX.contains(prefix2)) && (card.length() == 15)); |
240 | } | |
241 | } | |
242 | ||
243 | 2 | private static class Discover implements CreditCardType { |
244 | private static final String PREFIX = "6011"; | |
245 | @Override | |
246 | public boolean matches(String card) { | |
247 | 1 | return (card.substring(0, 4).equals(PREFIX) && (card.length() == 16)); |
248 | } | |
249 | } | |
250 | ||
251 | 2 | private static class Mastercard implements CreditCardType { |
252 | private static final String PREFIX = "51,52,53,54,55,"; | |
253 | @Override | |
254 | public boolean matches(String card) { | |
255 | 2 | String prefix2 = card.substring(0, 2) + ","; |
256 | 2 | return ((PREFIX.contains(prefix2)) && (card.length() == 16)); |
257 | } | |
258 | } | |
259 | ||
260 | } |