Forum Controls
Spotlight Features

The Rich Engineering Heritage Behind Dependency Injection

Andrew McVeigh takes us on a tour of the rich heritage behind dependency injection, what it represents, and tells us why its here to stay.

NetBeans 6: Matisse Updates

NetBeans 6 delivers great updates to the Matisse GUI builder. Spend a few minutes with Roman Strobl and get an expert briefing on what's new and what has changed.

Introduction to Groovy Part 3

In this, the third and final installation of Andres' Introduction to Groovy series, you learn about how Groovy handles variable numbers of arguments, named parameters, currying, and more about Groovy operators. Including, some new operators.

Easier Custom Components with Swing Fuse

Swing Fuse (actually just Fuse), is a framework designed to make it easier to create your own custom desktop components. In this article, Daniel Spiewak shows you how to get started and provides sample source code you can download.

Benchmark Analysis: Guice vs Spring

Willam Louth shows how he uses JXInsight Probes to investigate probable performance issues with code bases that he is not familiar with. He also highlights possible pitfalls in creating a benchmark, as well as in the analysis of results.
Replies: 5 - Pages: 1  
  Click to reply to this thread Reply

Credit Card Validation with AbstractValidator

At 6:26 AM on Aug 4, 2005, Michael Urban wrote:

This is a followup to the AbstractValidator we created in Building a Swing Validation Package with InputVerifier that shows some examples of validators I built ontop of AbstractValidator. The main validator I want to show is a very powerful one which validates credit card numbers, even down to checking for mistyped digits. But lets start with something simpler just to show how easy it is to build a validator ontop of AbstractValidator.

The NotEmptyValidator

NotEmptyValidator is a very simple validator. All it does is make sure that the user entered something in the text field. It shows just how easy it is to write and use actual validators using the validation package we wrote earlier. Here is the short and simple code for NotEmptyValidator:

package org.javalobby.validation;
 
import javax.swing.JComponent;
import javax.swing.JTextField;
import javax.swing.JDialog;
 
/**
 * A class for performing basic validation on text fields. All it does is make 
 * sure that they are not null.
 * 
 * @author Michael Urban
 */
 
public class NotEmptyValidator extends AbstractValidator {
    public NotEmptyValidator(JDialog parent, JTextField c, String message) {
        super(parent, c, message);
    }
	
    protected boolean validationCriteria(JComponent c) {
        if (((JTextField)c).getText().equals(""))
            return false;
        return true;
    }
}

That's all there is too it. To use the validator on a text field in your application, all you have to to is something like this:

JTextField textField = new JTextField();
textField.setInputVerifier(new NotEmptyValidator(parent, textField, "Field cannot be null."));

Now lets takes a look at a more complex, but very powerful and useful validator.

The CreditCardValidator

CreditCardValidator does pre-validation of credit card numbers before actually sending them off for authrorization. It is a very powerful validator that uses the Luhn algorithm to catch mistakes in credit card number input, all the way down to the user simply mistyping a single digit in the card number. As you can see, validation criteria for a validator package can be arbitrarily complex. Let's look at the source code for CreditCardValidator:

package org.javalobby.validation;
 
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JTextField;
import java.util.regex.*;
 
/**
 * A class for performing pre-validation on credit cards.
 * 
 * @author Michael Urban
 */
 
public class CreditCardValidator extends AbstractValidator {
    public static final int MASTERCARD = 0, VISA = 1;
    public static final int AMEX = 2, DISCOVER = 3, DINERS = 4;
    private JDialog parent;
    private Object form;
	
    private static final String[] messages = {
        "Not a valid number for MasterCard.",
        "Not a valid number for Visa.",
        "Not a valid number for American Express.",
        "Not a valid number for Discover.",
        "Not a valid number for Diner's Club"
    };
	
    public CreditCardValidator(JDialog parent, Object form, JComponent c,
        String message) 
    {
        super(parent, c, message);
        this.parent = parent;
        this.form = form;
    }
 
    protected boolean validationCriteria(JComponent c) {
        String number = ((JTextField)c).getText();
		
        if (number.equals("")) {
            setMessage("Field cannnot be blank.");
            return false;
        }
		
        Matcher m = Pattern.compile("[^\\d\\s.-]").matcher(number);
        
        if (m.find()) {
            setMessage("Credit card number can only contain numbers, spaces, \"-\", and \".\"");
            return false;
        }
		
        int type = ((CreditCardValidation)form).validateCreditCardType();
        setMessage(messages[type]);
        Matcher matcher = Pattern.compile("[\\s.-]").matcher(number);
        number = matcher.replaceAll("");
        return validate(number, type);
    }
 
    // Check that cards start with proper digits for
    // selected card type and are also the right length.    
 
    private boolean validate(String number, int type) {
        switch(type) {
		
        case MASTERCARD:
            if (number.length() != 16 ||
                Integer.parseInt(number.substring(0, 2)) < 51 ||
                Integer.parseInt(number.substring(0, 2)) > 55)
            {
                return false;
            }
            break;
			
        case VISA:
            if ((number.length() != 13 && number.length() != 16) ||
                    Integer.parseInt(number.substring(0, 1)) != 4)
            {
                return false;
            }
            break;
			
        case AMEX:
            if (number.length() != 15 ||
                (Integer.parseInt(number.substring(0, 2)) != 34 &&
                    Integer.parseInt(number.substring(0, 2)) != 37))
            {
                return false;
            }
            break;
			
        case DISCOVER:
            if (number.length() != 16 ||
                Integer.parseInt(number.substring(0, 5)) != 6011)
            {
                return false;
            }
            break;
			
        case DINERS:
            if (number.length() != 14 ||
                ((Integer.parseInt(number.substring(0, 2)) != 36 &&
                    Integer.parseInt(number.substring(0, 2)) != 38) &&
                    Integer.parseInt(number.substring(0, 3)) < 300 ||
                        Integer.parseInt(number.substring(0, 3)) > 305))
            {
                return false;
            }
            break;
        }
        return luhnValidate(number);
    }
 
    // The Luhn algorithm is basically a CRC type
    // system for checking the validity of an entry.
    // All major credit cards use numbers that will
    // pass the Luhn check. Also, all of them are based
    // on MOD 10.
	
    private boolean luhnValidate(String numberString) {
        char[] charArray = numberString.toCharArray();
        int[] number = new int[charArray.length];
        int total = 0;
		
        for (int i=0; i < charArray.length; i++) {
            number[i] = Character.getNumericValue(charArray[i]);
        }
		
        for (int i = number.length-2; i > -1; i-=2) {
            number[i] *= 2;
			
            if (number[i] > 9)
                number[i] -= 9;
        }
		
        for (int i=0; i < number.length; i++)
            total += number[i];
		
            if (total % 10 != 0)
                return false;
		
        return true;
    }
}

Because we need to check the credit card type, notice that this validator requires an additional interface so that our validator can retrieve the credit card type from the form. That interface is CreditCardValidation:

package org.javalobby.validation;
 
public interface CreditCardValidation {
    int validateCreditCardType();
}

Notice that in this validator, we provide context sensitive pop help messages and check for three different possible problems: Whether the the user left the credit card field blank; whether the user entered illegal characters in the credit card field; and whether or not the credit card type could be a valid credit card number for the card type in question.

CreditCardValidator is mostly just algorithm programming, so I am not going to go into details about how it works. But suffice it to say, it shows that the validation criteria we implement can be arbitrarily complex, and that in CreditCardValidator, all we had to focus on was writing the logic for our validator. We didn't haven't to worry about presenting validation results to the user at all. AbstractValidator we wrote earlier takes care of all those details for us.

Message was edited by: Michael Urban
1 . At 12:29 AM on Aug 7, 2005, Ayman Hasan wrote:
  Click to reply to this thread Reply

Re: Credit Card Validation with AbstractValidator

That's pretty good. BUT, some newer card numbers are now 19 digits long. So tou may check for that length too.
2 . At 12:33 PM on Aug 10, 2005, Rastislav Komara wrote:
  Click to reply to this thread Reply

Re: Credit Card Validation with AbstractValidator

Well nice but why U dont use strategy pattern for validation algorithms? If it depends on card type it is the from my point of view the best sollution. Also it is very robust and expandable.
3 . At 3:21 PM on Sep 19, 2005, Jalal kiswani wrote:
  Click to reply to this thread Reply

Re: Credit Card Validation with AbstractValidator

It is really nice , thank you for the good work .
4 . At 2:42 PM on Oct 25, 2005, sean wrote:
  Click to reply to this thread Reply

Re: Credit Card Validation with AbstractValidator

Thanks for this.

I think there's a bug in the diners if statement. Looks like it blocks all cards not between 300 and 305.

case DINERS:
if (number.length() != 14 ||
((Integer.parseInt(number.substring(0, 2)) != 36 &&
Integer.parseInt(number.substring(0, 2)) != 38) &&
Integer.parseInt(number.substring(0, 3)) Integer.parseInt(number.substring(0, 3)) > 305))
{
return false;
}
break;
}
5 . At 4:45 PM on Dec 20, 2006, Misha wrote:
  Click to reply to this thread Reply

Re: Credit Card Validation with AbstractValidator

I'm looking for two bogus credit numbers, preferably 16 digits. One that is valid using CRC but not LUHN, and one that is valid using LUHN, but not CRC. Does anyone have any or know where I could find examples?

thread.rss_message