com.riversoforion.yukon.bankcard.Issuer.java Source code

Java tutorial

Introduction

Here is the source code for com.riversoforion.yukon.bankcard.Issuer.java

Source

/*
 * Copyright (c) 2011, Eric McIntyre
 * All rights reserved.
 *
 * This software is under the BSD license.
 * http://www.opensource.org/licenses/bsd-license.php
 */
package com.riversoforion.yukon.bankcard;

import static org.apache.commons.lang3.Range.between;
import static org.apache.commons.lang3.Range.is;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.lang3.Range;

/**
 * @author macdaddy
 */
@SuppressWarnings("unchecked")
public enum Issuer {

    /**
     * Luhn algorithm, 15 digits, valid prefixes: 34, 37
     */
    AmericanExpress("American Express", LuhnAlgorithm.instance(), 15, between(340000, 349999),
            between(370000, 379999)),
    /**
     * Luhn algorithm, 14 digits, valid prefixes: 300-305
     */
    DinersClubCarteBlanche("Diners Club Carte Blanche", LuhnAlgorithm.instance(), 14, between(300000, 305999)),
    /**
     * Luhn algorithm, 14 digits, valid prefixes: 36
     */
    DinersClubInternational("Diners Club International", LuhnAlgorithm.instance(), 14, between(360000, 369999)),
    /**
     * Luhn algorithm, 16 digits, valid prefixes: 54, 55
     */
    DinersClubUsCa("Diners Club (US and Canada)", LuhnAlgorithm.instance(), 16, between(540000, 559999)),
    /**
     * Luhn algorithm, 16 digits, valid prefixes: 6011, 622126-622925, 644-649,
     * 65
     */
    Discover("Discover", LuhnAlgorithm.instance(), 16, between(601100, 601199), between(622126, 622925),
            between(644000, 649999), between(650000, 659999)),
    /**
     * Luhn algorithm, 16 digits, valid prefixes: 3528-3589
     */
    JapanCreditBureau("JCB", LuhnAlgorithm.instance(), 16, between(352800, 358999)),
    /**
     * Luhn algorithm, 16-19 digits, valid prefixes: 6304, 6706, 6771, 6709
     */
    Laser("Laser", LuhnAlgorithm.instance(), Arrays.asList(16, 17, 18, 19), between(630400, 630499),
            between(670600, 670699), between(670900, 670999), between(677100, 677199)),
    /**
     * Luhn algorithm, 12-19 digits, valid prefixes: 5018, 5020, 5038, 6304,
     * 6759, 6761, 6762, 6763
     */
    Maestro("Maestro", LuhnAlgorithm.instance(), Arrays.asList(12, 13, 14, 15, 16, 17, 18, 19),
            between(501800, 501899), between(502000, 502099), between(503800, 503899), between(630400, 630499),
            between(675900, 675999), between(676100, 676199), between(676200, 676299), between(676300, 676399)),
    /**
     * Luhn algorithm, 16 digits, valid prefixes: 51-55
     */
    MasterCard("Master Card", LuhnAlgorithm.instance(), 16, between(510000, 559999)),
    /**
     * Luhn algorithm, 16, 18, or 19 digits, valid prefixes: 6334, 6767
     */
    Solo("Solo", LuhnAlgorithm.instance(), Arrays.asList(16, 18, 19), between(633400, 633499),
            between(676700, 676799)),
    /**
     * Luhn algorithm, 16, 18, or 19 digits, valid prefixes: 4903, 4905, 4911,
     * 4936, 564182, 633110, 6333, 6759
     */
    Switch("Switch", LuhnAlgorithm.instance(), Arrays.asList(16, 18, 19), between(490300, 490399),
            between(490500, 490599), between(491100, 491199), between(493600, 493699), is(564182), is(633110),
            between(633300, 633399), between(675900, 675999)),
    /**
     * Luhn algorithm, 16 digits, valid prefixes: 4
     */
    Visa("Visa", LuhnAlgorithm.instance(), 16, between(400000, 499999));

    private static final int IIN_LENGTH = 6;

    private String description;
    private CheckDigit checkDigitAlgorithm;
    private List<Integer> validLengths = new ArrayList<Integer>();
    private Set<Range<Integer>> validIinRanges = new TreeSet<Range<Integer>>();

    private Issuer(String description, CheckDigit checkDigitAlgorithm, List<Integer> validLengths,
            Range<Integer>... validIinRanges) {

        this.description = description;
        this.checkDigitAlgorithm = checkDigitAlgorithm;
        this.validLengths.addAll(validLengths);
        this.validIinRanges.addAll(Arrays.asList(validIinRanges));
    }

    private Issuer(String description, CheckDigit checkDigitAlgorithm, int validLength,
            Range<Integer>... validIinRanges) {

        this(description, checkDigitAlgorithm, Arrays.asList(validLength), validIinRanges);
    }

    public String getDescription() {

        return this.description;
    }

    public CheckDigit getCheckDigitAlgorithm() {

        return this.checkDigitAlgorithm;
    }

    public List<Integer> getValidLengths() {

        return this.validLengths;
    }

    public Set<Range<Integer>> getValidIinRanges() {

        return this.validIinRanges;
    }

    public void validate(String bankCardNumber) {

        validateLength(bankCardNumber);
        validateIin(bankCardNumber);
        validateCheckDigit(bankCardNumber);
    }

    public void validateLength(String bankCardNumber) {

        int length = bankCardNumber.length();
        for (int validLength : this.validLengths) {
            if (length == validLength) {
                return;
            }
        }
        throw new BankCardException(String.format("Invalid length for issuer %s: %d", this.name(), length));
    }

    public void validateIin(String bankCardNumber) {

        String prefix = bankCardNumber.substring(0, IIN_LENGTH);
        int iin = Integer.parseInt(prefix);
        for (Range<Integer> range : this.validIinRanges) {
            if (range.contains(iin)) {
                return;
            }
        }
        throw new BankCardException(String.format("Invalid prefix for issuer %s: %s", this.name(), prefix));
    }

    public void validateCheckDigit(String bankCardNumber) {

        this.checkDigitAlgorithm.verify(bankCardNumber);
    }
}