KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > validator > CreditCardValidator


1 /*
2  * $Id: CreditCardValidator.java 155434 2005-02-26 13:16:41Z dirkv $
3  * $Rev$
4  * $Date: 2005-02-26 05:16:41 -0800 (Sat, 26 Feb 2005) $
5  *
6  * ====================================================================
7  * Copyright 2001-2005 The Apache Software Foundation
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */

21
22 package org.apache.commons.validator;
23
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Iterator JavaDoc;
27
28 import org.apache.commons.validator.util.Flags;
29
30 /**
31  * <p>Perform credit card validations.</p>
32  * <p>
33  * By default, all supported card types are allowed. You can specify which
34  * cards should pass validation by configuring the validation options. For
35  * example,<br/><code>CreditCardValidator ccv = new CreditCardValidator(CreditCardValidator.AMEX + CreditCardValidator.VISA);</code>
36  * configures the validator to only pass American Express and Visa cards.
37  * If a card type is not directly supported by this class, you can implement
38  * the CreditCardType interface and pass an instance into the
39  * <code>addAllowedCardType</code> method.
40  * </p>
41  * For a similar implementation in Perl, reference Sean M. Burke's
42  * <a HREF="http://www.speech.cs.cmu.edu/~sburke/pub/luhn_lib.html">script</a>.
43  * More information is also available
44  * <a HREF="http://www.merriampark.com/anatomycc.htm">here</a>.
45  *
46  * @since Validator 1.1
47  */

48 public class CreditCardValidator {
49
50     /**
51      * Option specifying that no cards are allowed. This is useful if
52      * you want only custom card types to validate so you turn off the
53      * default cards with this option.
54      * <br/>
55      * <pre>
56      * CreditCardValidator v = new CreditCardValidator(CreditCardValidator.NONE);
57      * v.addAllowedCardType(customType);
58      * v.isValid(aCardNumber);
59      * </pre>
60      * @since Validator 1.1.2
61      */

62     public static final int NONE = 0;
63
64     /**
65      * Option specifying that American Express cards are allowed.
66      */

67     public static final int AMEX = 1 << 0;
68
69     /**
70      * Option specifying that Visa cards are allowed.
71      */

72     public static final int VISA = 1 << 1;
73
74     /**
75      * Option specifying that Mastercard cards are allowed.
76      */

77     public static final int MASTERCARD = 1 << 2;
78
79     /**
80      * Option specifying that Discover cards are allowed.
81      */

82     public static final int DISCOVER = 1 << 3;
83     
84     /**
85      * The CreditCardTypes that are allowed to pass validation.
86      */

87     private Collection JavaDoc cardTypes = new ArrayList JavaDoc();
88
89     /**
90      * Create a new CreditCardValidator with default options.
91      */

92     public CreditCardValidator() {
93         this(AMEX + VISA + MASTERCARD + DISCOVER);
94     }
95
96     /**
97      * Create a new CreditCardValidator with the specified options.
98      * @param options Pass in
99      * CreditCardValidator.VISA + CreditCardValidator.AMEX to specify that
100      * those are the only valid card types.
101      */

102     public CreditCardValidator(int options) {
103         super();
104
105         Flags f = new Flags(options);
106         if (f.isOn(VISA)) {
107             this.cardTypes.add(new Visa());
108         }
109
110         if (f.isOn(AMEX)) {
111             this.cardTypes.add(new Amex());
112         }
113
114         if (f.isOn(MASTERCARD)) {
115             this.cardTypes.add(new Mastercard());
116         }
117
118         if (f.isOn(DISCOVER)) {
119             this.cardTypes.add(new Discover());
120         }
121     }
122
123     /**
124      * Checks if the field is a valid credit card number.
125      * @param card The card number to validate.
126      */

127     public boolean isValid(String JavaDoc card) {
128         if ((card == null) || (card.length() < 13) || (card.length() > 19)) {
129             return false;
130         }
131
132         if (!this.luhnCheck(card)) {
133             return false;
134         }
135         
136         Iterator JavaDoc types = this.cardTypes.iterator();
137         while (types.hasNext()) {
138             CreditCardType type = (CreditCardType) types.next();
139             if (type.matches(card)) {
140                 return true;
141             }
142         }
143
144         return false;
145     }
146     
147     /**
148      * Add an allowed CreditCardType that participates in the card
149      * validation algorithm.
150      * @param type The type that is now allowed to pass validation.
151      * @since Validator 1.1.2
152      */

153     public void addAllowedCardType(CreditCardType type){
154         this.cardTypes.add(type);
155     }
156
157     /**
158      * Checks for a valid credit card number.
159      * @param cardNumber Credit Card Number.
160      */

161     protected boolean luhnCheck(String JavaDoc cardNumber) {
162         // number must be validated as 0..9 numeric first!!
163
int digits = cardNumber.length();
164         int oddOrEven = digits & 1;
165         long sum = 0;
166         for (int count = 0; count < digits; count++) {
167             int digit = 0;
168             try {
169                 digit = Integer.parseInt(cardNumber.charAt(count) + "");
170             } catch(NumberFormatException JavaDoc e) {
171                 return false;
172             }
173
174             if (((count & 1) ^ oddOrEven) == 0) { // not
175
digit *= 2;
176                 if (digit > 9) {
177                     digit -= 9;
178                 }
179             }
180             sum += digit;
181         }
182
183         return (sum == 0) ? false : (sum % 10 == 0);
184     }
185     
186     /**
187      * CreditCardType implementations define how validation is performed
188      * for one type/brand of credit card.
189      * @since Validator 1.1.2
190      */

191     public interface CreditCardType {
192         
193         /**
194          * Returns true if the card number matches this type of credit
195          * card. Note that this method is <strong>not</strong> responsible
196          * for analyzing the general form of the card number because
197          * <code>CreditCardValidator</code> performs those checks before
198          * calling this method. It is generally only required to valid the
199          * length and prefix of the number to determine if it's the correct
200          * type.
201          * @param card The card number, never null.
202          * @return true if the number matches.
203          */

204         boolean matches(String JavaDoc card);
205         
206     }
207     
208     private class Visa implements CreditCardType {
209         private static final String JavaDoc PREFIX = "4";
210         public boolean matches(String JavaDoc card) {
211             return (
212                 card.substring(0, 1).equals(PREFIX)
213                     && (card.length() == 13 || card.length() == 16));
214         }
215     }
216     
217     private class Amex implements CreditCardType {
218         private static final String JavaDoc PREFIX = "34,37,";
219         public boolean matches(String JavaDoc card) {
220             String JavaDoc prefix2 = card.substring(0, 2) + ",";
221             return ((PREFIX.indexOf(prefix2) != -1) && (card.length() == 15));
222         }
223     }
224     
225     private class Discover implements CreditCardType {
226         private static final String JavaDoc PREFIX = "6011";
227         public boolean matches(String JavaDoc card) {
228             return (card.substring(0, 4).equals(PREFIX) && (card.length() == 16));
229         }
230     }
231     
232     private class Mastercard implements CreditCardType {
233         private static final String JavaDoc PREFIX = "51,52,53,54,55,";
234         public boolean matches(String JavaDoc card) {
235             String JavaDoc prefix2 = card.substring(0, 2) + ",";
236             return ((PREFIX.indexOf(prefix2) != -1) && (card.length() == 16));
237         }
238     }
239
240 }
241
Popular Tags