Coverage Report - org.apache.commons.validator.CreditCardValidator
 
Classes in this File Line Coverage Branch Coverage Complexity
CreditCardValidator
100%
41/41
96%
29/30
3.4
CreditCardValidator$1
N/A
N/A
3.4
CreditCardValidator$Amex
100%
3/3
75%
3/4
3.4
CreditCardValidator$CreditCardType
N/A
N/A
3.4
CreditCardValidator$Discover
100%
2/2
50%
2/4
3.4
CreditCardValidator$Mastercard
100%
3/3
75%
3/4
3.4
CreditCardValidator$Visa
100%
2/2
83%
5/6
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  
 }