Coverage report

  %line %branch
org.apache.commons.validator.CreditCardValidator$Discover
100% 
100% 

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

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.