Package org.apache.wicket.validation.validator

Source Code of org.apache.wicket.validation.validator.CreditCardValidator

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.wicket.validation.validator;

import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.IValidationError;
import org.apache.wicket.validation.IValidator;
import org.apache.wicket.validation.ValidationError;

/**
* Checks if a credit card number is valid. The number will be checked for "American Express",
* "China UnionPay", "Diners Club Carte Blanche", "Diners Club International",
* "Diners Club US & Canada", "Discover Card", "JCB", "Laser", "Maestro", "MasterCard", "Solo",
* "Switch", "Visa" and "Visa Electron". If none of those apply to the credit card number, the
* credit card number is considered invalid.
*
* <p>
* Card prefixes and lengths have been taken from <a
* href="http://en.wikipedia.org/w/index.php?title=Bank_card_number&oldid=322132931">Wikipedia</a>.
*
* @author Johan Compagner
* @author Joachim F. Rohde
* @since 1.2.6
*/
public class CreditCardValidator implements IValidator<String>
{
  private static final long serialVersionUID = 1L;

  /** */
  public static enum CreditCard {
    /** */
    INVALID(null),
    /** */
    AMERICAN_EXPRESS("American Express"),
    /** */
    CHINA_UNIONPAY("China UnionPay"),
    /** */
    DINERS_CLUB_CARTE_BLANCHE("Diners Club Carte Blanche"),
    /** */
    DINERS_CLUB_INTERNATIONAL("Diners Club International"),
    /** */
    DINERS_CLUB_US_AND_CANADA("Diners Club US & Canada"),
    /** */
    DISCOVER_CARD("Discover Card"),
    /** */
    JCB("JCB"),
    /** */
    LASER("Laser"),
    /** */
    MAESTRO("Maestro"),
    /** */
    MASTERCARD("MasterCard"),
    /** */
    SOLO("Solo"),
    /** */
    SWITCH("Switch"),
    /** */
    VISA("Visa"),
    /** */
    VISA_ELECTRON("Visa Electron");

    private final String name;

    CreditCard(String name)
    {
      this.name = name;
    }
  }

  /** The ID which represents the credit card institute. */
  private CreditCard cardId = CreditCard.INVALID;

  private boolean failOnUnknown = true;

  /**
   * Construct.
   */
  public CreditCardValidator()
  {
  }

  /**
   * Construct.
   *
   * @param failOnUnkown
   */
  public CreditCardValidator(final boolean failOnUnkown)
  {
    failOnUnknown = failOnUnkown;
  }

  /**
   *
   * @return Credit card issuer
   */
  public final CreditCard getCardId()
  {
    return cardId;
  }

  /**
   * Allow subclasses to set the card id
   *
   * @param cardId
   */
  protected void setCardId(final CreditCard cardId)
  {
    this.cardId = cardId;
  }

  @Override
  public void validate(final IValidatable<String> validatable)
  {
    final String value = validatable.getValue();

    try
    {
      if (!isLengthAndPrefixCorrect(value))
      {
        validatable.error(decorate(new ValidationError(this), validatable));
      }
    }
    catch (final NumberFormatException ex)
    {
      validatable.error(decorate(new ValidationError(this), validatable));
    }
  }

  /**
   * Allows subclasses to decorate reported errors
   *
   * @param error
   * @param validatable
   * @return decorated error
   */
  protected IValidationError decorate(IValidationError error, IValidatable<String> validatable)
  {
    return error;
  }

  /**
   * Checks if the credit card number can be determined as a valid number.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return <code>TRUE</code> if the credit card number could be determined as a valid number,
   *         else <code>FALSE</code> is returned
   */
  protected boolean isLengthAndPrefixCorrect(String creditCardNumber)
  {
    if (creditCardNumber == null)
    {
      return false;
    }

    // strip spaces and dashes
    creditCardNumber = creditCardNumber.replaceAll("[ -]", "");

    // the length of the credit card number has to be between 12 and 19.
    // else the number is invalid.
    if ((creditCardNumber.length() >= 12) && (creditCardNumber.length() <= 19) &&
      isChecksumCorrect(creditCardNumber))
    {
      if ((failOnUnknown == false) ||
        (determineCardId(creditCardNumber) != CreditCard.INVALID))
      {
        return true;
      }
    }

    return false;
  }

  /**
   * Checks if the credit card number can be determined as a valid number.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return <code>TRUE</code> if the credit card number could be determined as a valid number,
   *         else <code>FALSE</code> is returned
   */
  public final CreditCard determineCardId(String creditCardNumber)
  {
    if (creditCardNumber == null)
    {
      return CreditCard.INVALID;
    }

    // strip spaces and dashes
    creditCardNumber = creditCardNumber.replaceAll("[ -]", "");

    // the length of the credit card number has to be between 12 and 19.
    // else the number is invalid.
    if ((creditCardNumber.length() >= 12) && (creditCardNumber.length() <= 19) &&
      isChecksumCorrect(creditCardNumber))
    {
      cardId = CreditCard.INVALID;
      if (cardId == CreditCard.INVALID)
      {
        cardId = isAmericanExpress(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isChinaUnionPay(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isDinersClubCarteBlanche(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isDinersClubInternational(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isDinersClubUsAndCanada(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isDiscoverCard(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isJCB(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isLaser(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isMaestro(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isMastercard(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isSolo(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isSwitch(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isVisa(creditCardNumber);
      }
      if (cardId == CreditCard.INVALID)
      {
        cardId = isVisaElectron(creditCardNumber);
      }
    }
    else
    {
      cardId = isUnknown(creditCardNumber);
    }

    return cardId;
  }

  /**
   * Can be used (subclassed) to extend the test with a credit card not yet known by the
   * validator.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  protected CreditCard isUnknown(String creditCardNumber)
  {
    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is an American Express. An American Express number has to start with
   * 34 or 37 and has to have a length of 15. The number has to be validated with the Luhn
   * algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isAmericanExpress(String creditCardNumber)
  {
    if (creditCardNumber.length() == 15 &&
      (creditCardNumber.startsWith("34") || creditCardNumber.startsWith("37")))
    {
      return CreditCard.AMERICAN_EXPRESS;
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a China UnionPay. A China UnionPay number has to start with 622
   * (622126-622925) and has to have a length between 16 and 19. No further validation takes
   * place.<br/>
   * <br/>
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isChinaUnionPay(String creditCardNumber)
  {
    if ((creditCardNumber.length() >= 16 && creditCardNumber.length() <= 19) &&
      (creditCardNumber.startsWith("622")))
    {
      int firstDigits = Integer.parseInt(creditCardNumber.substring(0, 5));
      if (firstDigits >= 622126 && firstDigits <= 622925)
      {
        return CreditCard.CHINA_UNIONPAY;
      }
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Diners Club Carte Blanche. A Diners Club Carte Blanche number
   * has to start with a number between 300 and 305 and has to have a length of 14. The number has
   * to be validated with the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isDinersClubCarteBlanche(String creditCardNumber)
  {
    if (creditCardNumber.length() == 14 && creditCardNumber.startsWith("30"))
    {
      int firstDigits = Integer.parseInt(creditCardNumber.substring(0, 3));
      if (firstDigits >= 300 && firstDigits <= 305)
      {
        return CreditCard.DINERS_CLUB_CARTE_BLANCHE;
      }
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Diners Club International. A Diners Club International number
   * has to start with the number 36 and has to have a length of 14. The number has to be
   * validated with the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isDinersClubInternational(String creditCardNumber)
  {
    if (creditCardNumber.length() == 14 && creditCardNumber.startsWith("36"))
    {
      return CreditCard.DINERS_CLUB_INTERNATIONAL;
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Diners Club US & Canada. A Diners Club US & Canada number has
   * to start with the number 54 or 55 and has to have a length of 16. The number has to be
   * validated with the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isDinersClubUsAndCanada(String creditCardNumber)
  {
    if (creditCardNumber.length() == 16 &&
      (creditCardNumber.startsWith("54") || creditCardNumber.startsWith("55")))
    {
      return CreditCard.DINERS_CLUB_US_AND_CANADA;
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Discover Card. A Discover Card number has to start with 6011,
   * 622126-622925, 644-649 or 65 and has to have a length of 16. The number has to be validated
   * with the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isDiscoverCard(String creditCardNumber)
  {
    if (creditCardNumber.length() == 16 && creditCardNumber.startsWith("6"))
    {
      int firstThreeDigits = Integer.parseInt(creditCardNumber.substring(0, 3));
      int firstSixDigits = Integer.parseInt(creditCardNumber.substring(0, 6));
      if (creditCardNumber.startsWith("6011") || creditCardNumber.startsWith("65") ||
        (firstThreeDigits >= 644 && firstThreeDigits <= 649) ||
        (firstSixDigits >= 622126 && firstSixDigits <= 622925))
      {
        return CreditCard.DISCOVER_CARD;
      }
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a JCB. A JCB number has to start with a number between 3528 and
   * 3589 and has to have a length of 16. The number has to be validated with the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isJCB(String creditCardNumber)
  {
    if (creditCardNumber.length() == 16)
    {
      int firstFourDigits = Integer.parseInt(creditCardNumber.substring(0, 4));
      if (firstFourDigits >= 3528 && firstFourDigits <= 3589)
      {
        return CreditCard.JCB;
      }
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Laser. A Laser number has to start with 6304, 6706, 6771 or
   * 6709 and has to have a length between 16 and 19 digits. The number has to be validated with
   * the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isLaser(String creditCardNumber)
  {
    if (creditCardNumber.length() >= 16 && creditCardNumber.length() <= 19)
    {
      if (creditCardNumber.startsWith("6304") || creditCardNumber.startsWith("6706") ||
        creditCardNumber.startsWith("6771") || creditCardNumber.startsWith("6709"))
      {
        return CreditCard.LASER;
      }
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Maestro. A Maestro number has to start with
   * 5018,5020,5038,6304,6759,6761 or 6763 and has to have a length between 12 and 19 digits. The
   * number has to be validated with the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isMaestro(String creditCardNumber)
  {
    if (creditCardNumber.length() >= 12 && creditCardNumber.length() <= 19)
    {
      if (creditCardNumber.startsWith("5018") || creditCardNumber.startsWith("5020") ||
        creditCardNumber.startsWith("5038") || creditCardNumber.startsWith("6304") ||
        creditCardNumber.startsWith("6759") || creditCardNumber.startsWith("6761") ||
        creditCardNumber.startsWith("6763"))
      {
        return CreditCard.MAESTRO;
      }
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Solo. A Solo number has to start with 6334 or 6767 and has to
   * have a length of 16, 18 or 19 digits. The number has to be validated with the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isSolo(String creditCardNumber)
  {
    if ((creditCardNumber.length() == 16) || (creditCardNumber.length() == 18) ||
      (creditCardNumber.length() == 19))
    {
      if (creditCardNumber.startsWith("6334") || creditCardNumber.startsWith("6767"))
      {
        return CreditCard.SOLO;
      }
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Switch. A Switch number has to start with
   * 4903,4905,4911,4936,564182,633110,6333 or 6759 and has to have a length of 16, 18 or 19
   * digits. The number has to be validated with the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isSwitch(String creditCardNumber)
  {
    if ((creditCardNumber.length() == 16 || creditCardNumber.length() == 18 || creditCardNumber.length() == 19))
    {
      if (creditCardNumber.startsWith("4903") || creditCardNumber.startsWith("4905") ||
        creditCardNumber.startsWith("4911") || creditCardNumber.startsWith("4936") ||
        creditCardNumber.startsWith("564182") || creditCardNumber.startsWith("633110") ||
        creditCardNumber.startsWith("6333") || creditCardNumber.startsWith("6759"))
      {
        return CreditCard.SWITCH;
      }
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Visa. A Visa number has to start with a 4 and has to have a
   * length of 13 or 16 digits. The number has to be validated with the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isVisa(String creditCardNumber)
  {
    if (creditCardNumber.length() == 13 || creditCardNumber.length() == 16)
    {
      if (creditCardNumber.startsWith("4"))
      {
        return CreditCard.VISA;
      }
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Visa Electron. A Visa Electron number has to start with
   * 417500,4917,4913,4508 or 4844 and has to have a length of 16 digits. The number has to be
   * validated with the Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isVisaElectron(String creditCardNumber)
  {
    if (creditCardNumber.length() == 16 &&
      (creditCardNumber.startsWith("417500") || creditCardNumber.startsWith("4917") ||
        creditCardNumber.startsWith("4913") || creditCardNumber.startsWith("4508") || creditCardNumber.startsWith("4844")))
    {
      return CreditCard.VISA_ELECTRON;
    }

    return CreditCard.INVALID;
  }

  /**
   * Check if the credit card is a Mastercard. A Mastercard number has to start with a number
   * between 51 and 55 and has to have a length of 16. The number has to be validated with the
   * Luhn algorithm.
   *
   * @param creditCardNumber
   *            the credit card number as a string
   * @return The credit card id of the issuer
   */
  private CreditCard isMastercard(String creditCardNumber)
  {
    if (creditCardNumber.length() == 16)
    {
      int firstTwoDigits = Integer.parseInt(creditCardNumber.substring(0, 2));
      if (firstTwoDigits >= 51 && firstTwoDigits <= 55)
      {
        return CreditCard.MASTERCARD;
      }
    }

    return CreditCard.INVALID;
  }

  /**
   * Calculates the checksum of a credit card number using the Luhn algorithm (the so-called
   * "mod 10" algorithm).
   *
   * @param creditCardNumber
   *            the credit card number for which the checksum should be calculated
   * @return <code>TRUE</code> if the checksum for the given credit card number is valid, else
   *         return <code>FALSE</code>
   * @see <a href="http://en.wikipedia.org/wiki/Luhn_algorithm">Wikipedie - Luhn algorithm</a>
   */
  protected final boolean isChecksumCorrect(final String creditCardNumber)
  {
    int nulOffset = '0';
    int sum = 0;
    for (int i = 1; i <= creditCardNumber.length(); i++)
    {
      int currentDigit = creditCardNumber.charAt(creditCardNumber.length() - i) - nulOffset;
      if ((i % 2) == 0)
      {
        currentDigit *= 2;
        currentDigit = currentDigit > 9 ? currentDigit - 9 : currentDigit;
        sum += currentDigit;
      }
      else
      {
        sum += currentDigit;
      }
    }

    return (sum % 10) == 0;
  }
}
TOP

Related Classes of org.apache.wicket.validation.validator.CreditCardValidator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.