Author: niallp Date: Tue Dec 12 09:02:56 2006 New Revision: 486233 URL: http://svn.apache.org/viewvc?view=rev&rev=486233 Log: VALIDATOR-215 - add new generic code validator
Added: jakarta/commons/proper/validator/trunk/src/share/org/apache/commons/validator/routines/CodeValidator.java (with props) jakarta/commons/proper/validator/trunk/src/test/org/apache/commons/validator/routines/CodeValidatorTest.java (with props) Modified: jakarta/commons/proper/validator/trunk/xdocs/changes.xml Added: jakarta/commons/proper/validator/trunk/src/share/org/apache/commons/validator/routines/CodeValidator.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/validator/trunk/src/share/org/apache/commons/validator/routines/CodeValidator.java?view=auto&rev=486233 ============================================================================== --- jakarta/commons/proper/validator/trunk/src/share/org/apache/commons/validator/routines/CodeValidator.java (added) +++ jakarta/commons/proper/validator/trunk/src/share/org/apache/commons/validator/routines/CodeValidator.java Tue Dec 12 09:02:56 2006 @@ -0,0 +1,328 @@ +/* + * 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.commons.validator.routines; + +import java.io.Serializable; + +import org.apache.commons.validator.routines.checkdigit.CheckDigit; + +/** + * Generic <b>Code Validation</b> providing format, minimum/maximum + * length and [EMAIL PROTECTED] CheckDigit} validations. + * <p> + * Performs the following validations on a code: + * <ul> + * <li>Check the <i>format</i> of the code using a <i>regular expression.</i> (if specified)</li> + * <li>Check the <i>minimum</i> and <i>maximum</i> length (if specified) of the <i>parsed</i> code + * (i.e. parsed by the <i>regular expression</i>).</li> + * <li>Performs [EMAIL PROTECTED] CheckDigit} validation on the parsed code (if specified).</li> + * </ul> + * <p> + * Configure the validator with the appropriate regular expression, minimum/maximum length + * and [EMAIL PROTECTED] CheckDigit} validator and then call one of the two validation + * methods provided:</p> + * <ul> + * <li><code>boolean isValid(code)</code></li> + * <li><code>String validate(code)</code></li> + * </ul> + * <p> + * Codes often include <i>format</i> characters - such as hyphens - to make them + * more easily human readable. These can be removed prior to length and check digit + * validation by specifying them as a <i>non-capturing</i> group in the regular + * expression (i.e. use the <code>(?: )</code> notation). + * + * @version $Revision$ $Date$ + * @since Validator 1.4 + */ +public final class CodeValidator implements Serializable { + + private RegexValidator regexValidator; + private int minLength = -1; + private int maxLength = -1; + private CheckDigit checkdigit; + + /** + * Default Constructor. + */ + public CodeValidator() { + } + + /** + * Construct a code validator with a specified regular + * expression and [EMAIL PROTECTED] CheckDigit}. + * + * @param regex The format regular expression + * @param checkdigit The check digit validation routine + */ + public CodeValidator(String regex, CheckDigit checkdigit) { + this(regex, -1, -1, checkdigit); + } + + /** + * Construct a code validator with a specified regular + * expression, length and [EMAIL PROTECTED] CheckDigit}. + * + * @param regex The format regular expression. + * @param length The length of the code + * (sets the mimimum/maximum to the same) + * @param checkdigit The check digit validation routine + */ + public CodeValidator(String regex, int length, CheckDigit checkdigit) { + this(regex, length, length, checkdigit); + } + + /** + * Construct a code validator with a specified regular + * expression, minimum/maximum length and [EMAIL PROTECTED] CheckDigit} validation. + * + * @param regex The regular expression validator + * @param minLength The minimum length of the code + * @param maxLength The maximum length of the code + * @param checkdigit The check digit validation routine + */ + public CodeValidator(String regex, int minLength, int maxLength, + CheckDigit checkdigit) { + setRegex(regex); + setMinLength(minLength); + setMaxLength(maxLength); + setCheckDigit(checkdigit); + } + + /** + * Construct a code validator with a specified regular expression, + * validator and [EMAIL PROTECTED] CheckDigit} validation. + * + * @param regexValidator The format regular expression validator + * @param checkdigit The check digit validation routine. + */ + public CodeValidator(RegexValidator regexValidator, CheckDigit checkdigit) { + this(regexValidator, -1, -1, checkdigit); + } + + /** + * Construct a code validator with a specified regular expression, + * validator, length and [EMAIL PROTECTED] CheckDigit} validation. + * + * @param regexValidator The format regular expression validator + * @param length The length of the code + * (sets the mimimum/maximum to the same value) + * @param checkdigit The check digit validation routine + */ + public CodeValidator(RegexValidator regexValidator, int length, CheckDigit checkdigit) { + this(regexValidator, length, length, checkdigit); + } + + /** + * Construct a code validator with a specified regular expression + * validator, minimum/maximum length and [EMAIL PROTECTED] CheckDigit} validation. + * + * @param regexValidator The format regular expression validator + * @param minLength The minimum length of the code + * @param maxLength The maximum length of the code + * @param checkdigit The check digit validation routine + */ + public CodeValidator(RegexValidator regexValidator, int minLength, int maxLength, + CheckDigit checkdigit) { + setRegexValidator(regexValidator); + setMinLength(minLength); + setMaxLength(maxLength); + setCheckDigit(checkdigit); + } + + /** + * Return the check digit validation routine. + * <p> + * <b>N.B.</b> Optional, if not set no Check Digit + * validation will be performed on the code. + * + * @return The check digit validation routine + */ + public CheckDigit getCheckDigit() { + return checkdigit; + } + + /** + * Set the check digit validation routine. + * <p> + * <b>N.B.</b> Optional, if not set no Check Digit + * validation will be performed on the code. + * + * @param checkdigit The check digit validation routine + */ + public void setCheckDigit(CheckDigit checkdigit) { + this.checkdigit = checkdigit; + } + + /** + * Convenience method that sets the minimum and + * maximum length to the same value. + * + * @param length The length of the code + */ + public void setLength(int length) { + setMinLength(length); + setMaxLength(length); + } + + /** + * Return the minimum length of the code. + * <p> + * <b>N.B.</b> Optional, if less than zero the + * minimum length will not be checked. + * + * @return The minimum length of the code or + * <code>-1</code> if the code has no minimum length + */ + public int getMinLength() { + return minLength; + } + + /** + * Set the minimum length of the code. + * <p> + * <b>N.B.</b> Optional, if less than zero the + * minimum length will not be checked. + * + * @param minLength The minimum length of the code or + * <code>-1</code> if the code has no minimum length + */ + public void setMinLength(int minLength) { + this.minLength = minLength; + } + + /** + * Return the maximum length of the code. + * <p> + * <b>N.B.</b> Optional, if less than zero the + * maximum length will not be checked. + * + * @return The maximum length of the code or + * <code>-1</code> if the code has no maximum length + */ + public int getMaxLength() { + return maxLength; + } + + /** + * Set the maximum length of the code. + * <p> + * <b>N.B.</b> Optional, if less than zero the + * maximum length will not be checked. + * + * @param maxLength The maximum length of the code or + * <code>-1</code> if the code has no maximum length + */ + public void setMaxLength(int maxLength) { + this.maxLength = maxLength; + } + + /** + * Return the <i>regular expression</i> validator. + * <p> + * <b>N.B.</b> Optional, if not set no regular + * expression validation will be performed on the code. + * + * @return The regular expression validator + */ + public RegexValidator getRegexValidator() { + return regexValidator; + } + + /** + * Set the <i>regular expression</i> used to validate + * the <i>format</i> of the code. + * <p> + * This is a convenience method which creates a + * [EMAIL PROTECTED] RegexValidator} with the specified regular + * expression. + * <p> + * <b>N.B.</b> Optional, if not set no regular + * expression validation will be performed on the code. + * + * @param regex The format regular expression. + */ + public void setRegex(String regex) { + if (regex != null && regex.length() > 0) { + setRegexValidator(new RegexValidator(regex)); + } else { + setRegexValidator(null); + } + } + + /** + * Set the <i>regular expression</i> validator. + * <p> + * <b>N.B.</b> Optional, if not set no regular + * expression validation will be performed on the code. + * + * @param regexValidator The regular expression validator + */ + public void setRegexValidator(RegexValidator regexValidator) { + this.regexValidator = regexValidator; + } + + /** + * Validate the code returning either <code>true</code> + * or <code>false</code>. + * + * @param input The code to validate + * @return <code>true</code> if valid, otherwise + * <code>false</code> + */ + public boolean isValid(String input) { + return (validate(input) != null); + } + + /** + * Validate the code returning either the valid code or + * <code>null</code> if invalid. + * + * @param input The code to validate + * @return The code if valid, otherwise <code>null</code> + * if invalid + */ + public Object validate(String input) { + + String code = (input == null ? null : input.trim()); + if (code != null && code.length() == 0) { + return null; + } + + // validate/reformat using regular expression + if (regexValidator != null) { + code = regexValidator.validate(code); + if (code == null) { + return null; + } + } + + // check the length + if ((minLength >= 0 && code.length() < minLength) || + (maxLength >= 0 && code.length() > maxLength)) { + return null; + } + + // validate the check digit + if (checkdigit != null && !checkdigit.isValid(code)) { + return null; + } + + return code; + + } + +} Propchange: jakarta/commons/proper/validator/trunk/src/share/org/apache/commons/validator/routines/CodeValidator.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jakarta/commons/proper/validator/trunk/src/share/org/apache/commons/validator/routines/CodeValidator.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Added: jakarta/commons/proper/validator/trunk/src/test/org/apache/commons/validator/routines/CodeValidatorTest.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/validator/trunk/src/test/org/apache/commons/validator/routines/CodeValidatorTest.java?view=auto&rev=486233 ============================================================================== --- jakarta/commons/proper/validator/trunk/src/test/org/apache/commons/validator/routines/CodeValidatorTest.java (added) +++ jakarta/commons/proper/validator/trunk/src/test/org/apache/commons/validator/routines/CodeValidatorTest.java Tue Dec 12 09:02:56 2006 @@ -0,0 +1,249 @@ +/* + * 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.commons.validator.routines; + +import org.apache.commons.validator.routines.checkdigit.EAN13CheckDigit; + +import junit.framework.TestCase; + +/** + * CodeValidatorTest.java. + * + * @version $Revision$ $Date$ + * @since Validator 1.4 + */ +public class CodeValidatorTest extends TestCase { + + /** + * Construct a test with the specified name. + * @param name The name of the test + */ + public CodeValidatorTest(String name) { + super(name); + } + + /** + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Test Check Digit. + */ + public void testCheckDigit() { + CodeValidator validator = new CodeValidator(); + String invalidEAN = "9781930110992"; + String validEAN = "9781930110991"; + + // Test no CheckDigit (i.e. null) + assertNull("No CheckDigit", validator.getCheckDigit()); + assertEquals("No CheckDigit invalid", invalidEAN, validator.validate(invalidEAN)); + assertEquals("No CheckDigit valid", validEAN, validator.validate(validEAN)); + assertEquals("No CheckDigit (is) invalid", true, validator.isValid(invalidEAN)); + assertEquals("No CheckDigit (is) valid", true, validator.isValid(validEAN)); + + // Use the EAN-13 check digit routine + validator.setCheckDigit(EAN13CheckDigit.INSTANCE); + + assertNotNull("EAN CheckDigit", validator.getCheckDigit()); + assertEquals("EAN CheckDigit invalid", null, validator.validate(invalidEAN)); + assertEquals("EAN CheckDigit valid", validEAN, validator.validate(validEAN)); + assertEquals("EAN CheckDigit (is) invalid", false, validator.isValid(invalidEAN)); + assertEquals("EAN CheckDigit (is) valid", true, validator.isValid(validEAN)); + assertEquals("EAN CheckDigit ex", null, validator.validate("978193011099X")); + } + + /** + * Test the minimum/maximum length + */ + public void testLength() { + CodeValidator validator = new CodeValidator(); + String length_10 = "1234567890"; + String length_11 = "12345678901"; + String length_12 = "123456789012"; + String length_20 = "12345678901234567890"; + String length_21 = "123456789012345678901"; + String length_22 = "1234567890123456789012"; + + assertEquals("No min", -1, validator.getMinLength()); + assertEquals("No max", -1, validator.getMaxLength()); + + assertEquals("No Length 10", length_10, validator.validate(length_10)); + assertEquals("No Length 11", length_11, validator.validate(length_11)); + assertEquals("No Length 12", length_12, validator.validate(length_12)); + assertEquals("No Length 20", length_20, validator.validate(length_20)); + assertEquals("No Length 21", length_21, validator.validate(length_21)); + assertEquals("No Length 22", length_22, validator.validate(length_22)); + + validator.setMinLength(11); + + assertEquals("Min 11 - min", 11, validator.getMinLength()); + assertEquals("Min 11 - max", -1, validator.getMaxLength()); + assertEquals("Min 11 - 10", null, validator.validate(length_10)); + assertEquals("Min 11 - 11", length_11, validator.validate(length_11)); + assertEquals("Min 11 - 12", length_12, validator.validate(length_12)); + assertEquals("Min 11 - 20", length_20, validator.validate(length_20)); + assertEquals("Min 11 - 21", length_21, validator.validate(length_21)); + assertEquals("Min 11 - 22", length_22, validator.validate(length_22)); + + validator.setMinLength(-1); + validator.setMaxLength(21); + assertEquals("Max 21 - min", -1, validator.getMinLength()); + assertEquals("Max 21 - max", 21, validator.getMaxLength()); + assertEquals("Max 21 - 10", length_10, validator.validate(length_10)); + assertEquals("Max 21 - 11", length_11, validator.validate(length_11)); + assertEquals("Max 21 - 12", length_12, validator.validate(length_12)); + assertEquals("Max 21 - 20", length_20, validator.validate(length_20)); + assertEquals("Max 21 - 21", length_21, validator.validate(length_21)); + assertEquals("Max 21 - 22", null, validator.validate(length_22)); + + validator.setMinLength(11); + assertEquals("Min 11 / Max 21 - min", 11, validator.getMinLength()); + assertEquals("Min 11 / Max 21 - max", 21, validator.getMaxLength()); + assertEquals("Min 11 / Max 21 - 10", null, validator.validate(length_10)); + assertEquals("Min 11 / Max 21 - 11", length_11, validator.validate(length_11)); + assertEquals("Min 11 / Max 21 - 12", length_12, validator.validate(length_12)); + assertEquals("Min 11 / Max 21 - 20", length_20, validator.validate(length_20)); + assertEquals("Min 11 / Max 21 - 21", length_21, validator.validate(length_21)); + assertEquals("Min 11 / Max 21 - 22", null, validator.validate(length_22)); + + validator.setLength(11); + assertEquals("Exact 11 - min", 11, validator.getMinLength()); + assertEquals("Exact 11 - max", 11, validator.getMaxLength()); + assertEquals("Exact 11 - 10", null, validator.validate(length_10)); + assertEquals("Exact 11 - 11", length_11, validator.validate(length_11)); + assertEquals("Exact 11 - 12", null, validator.validate(length_12)); + } + + /** + * Test Regular Expression. + */ + public void testRegex() { + CodeValidator validator = new CodeValidator(); + + String value2 = "12"; + String value3 = "123"; + String value4 = "1234"; + String value5 = "12345"; + String invalid = "12a4"; + + // No Regular Expression + assertNull("No Regex", validator.getRegexValidator()); + assertEquals("No Regex 2", value2, validator.validate(value2)); + assertEquals("No Regex 3", value3, validator.validate(value3)); + assertEquals("No Regex 4", value4, validator.validate(value4)); + assertEquals("No Regex 5", value5, validator.validate(value5)); + assertEquals("No Regex invalid", invalid, validator.validate(invalid)); + + // Regular Expression + validator.setRegex("^([0-9]{3,4})$"); + assertNotNull("No Regex", validator.getRegexValidator()); + assertEquals("Regex 2", null, validator.validate(value2)); + assertEquals("Regex 3", value3, validator.validate(value3)); + assertEquals("Regex 4", value4, validator.validate(value4)); + assertEquals("Regex 5", null, validator.validate(value5)); + assertEquals("Regex invalid", null, validator.validate(invalid)); + + // Reformatted + validator.setRegexValidator(new RegexValidator("^([0-9]{3})(?:[-\\s])([0-9]{3})$")); + validator.setLength(6); + assertEquals("Reformat 123-456", "123456", validator.validate("123-456")); + assertEquals("Reformat 123 456", "123456", validator.validate("123 456")); + assertEquals("Reformat 123456", null, validator.validate("123456")); + assertEquals("Reformat 123.456", null, validator.validate("123.456")); + + String regex = "^(?:([0-9]{3})(?:[-\\s])([0-9]{3}))|([0-9]{6})$"; + validator.setRegex(regex); + assertEquals("Reformat 2 Regex", "RegexValidator{" + regex + "}", validator.getRegexValidator().toString()); + assertEquals("Reformat 2 123-456", "123456", validator.validate("123-456")); + assertEquals("Reformat 2 123 456", "123456", validator.validate("123 456")); + assertEquals("Reformat 2 123456", "123456", validator.validate("123456")); + validator.setRegex(null); + assertEquals("Reformat 2 Regex null", null, validator.getRegexValidator()); + } + + /** + * Test Regular Expression. + */ + public void testNoInput() { + CodeValidator validator = new CodeValidator(); + assertEquals("Null", null, validator.validate(null)); + assertEquals("Zero Length", null, validator.validate("")); + assertEquals("Spaces", null, validator.validate(" ")); + assertEquals("Trimmed", "A", validator.validate(" A ")); + } + + /** + * Test Regular Expression. + */ + public void testConstructors() { + CodeValidator validator = null; + RegexValidator regex = new RegexValidator("^[0-9]*$"); + + // Constructor 1 + validator = new CodeValidator(regex, EAN13CheckDigit.INSTANCE); + assertEquals("Constructor 1 - regex", regex, validator.getRegexValidator()); + assertEquals("Constructor 1 - min length", -1, validator.getMinLength()); + assertEquals("Constructor 1 - max length", -1, validator.getMaxLength()); + assertEquals("Constructor 1 - check digit", EAN13CheckDigit.INSTANCE, validator.getCheckDigit()); + + // Constructor 2 + validator = new CodeValidator(regex, 13, EAN13CheckDigit.INSTANCE); + assertEquals("Constructor 2 - regex", regex, validator.getRegexValidator()); + assertEquals("Constructor 2 - min length", 13, validator.getMinLength()); + assertEquals("Constructor 2 - max length", 13, validator.getMaxLength()); + assertEquals("Constructor 2 - check digit", EAN13CheckDigit.INSTANCE, validator.getCheckDigit()); + + // Constructor 3 + validator = new CodeValidator(regex, 10, 20, EAN13CheckDigit.INSTANCE); + assertEquals("Constructor 3 - regex", regex, validator.getRegexValidator()); + assertEquals("Constructor 3 - min length", 10, validator.getMinLength()); + assertEquals("Constructor 3 - max length", 20, validator.getMaxLength()); + assertEquals("Constructor 3 - check digit", EAN13CheckDigit.INSTANCE, validator.getCheckDigit()); + + // Constructor 4 + validator = new CodeValidator("^[0-9]*$", EAN13CheckDigit.INSTANCE); + assertEquals("Constructor 4 - regex", "RegexValidator{^[0-9]*$}", validator.getRegexValidator().toString()); + assertEquals("Constructor 4 - min length", -1, validator.getMinLength()); + assertEquals("Constructor 4 - max length", -1, validator.getMaxLength()); + assertEquals("Constructor 4 - check digit", EAN13CheckDigit.INSTANCE, validator.getCheckDigit()); + + // Constructor 5 + validator = new CodeValidator("^[0-9]*$", 13, EAN13CheckDigit.INSTANCE); + assertEquals("Constructor 5 - regex", "RegexValidator{^[0-9]*$}", validator.getRegexValidator().toString()); + assertEquals("Constructor 5 - min length", 13, validator.getMinLength()); + assertEquals("Constructor 5 - max length", 13, validator.getMaxLength()); + assertEquals("Constructor 5 - check digit", EAN13CheckDigit.INSTANCE, validator.getCheckDigit()); + + // Constructor 6 + validator = new CodeValidator("^[0-9]*$", 10, 20, EAN13CheckDigit.INSTANCE); + assertEquals("Constructor 6 - regex", "RegexValidator{^[0-9]*$}", validator.getRegexValidator().toString()); + assertEquals("Constructor 6 - min length", 10, validator.getMinLength()); + assertEquals("Constructor 6 - max length", 20, validator.getMaxLength()); + assertEquals("Constructor 6 - check digit", EAN13CheckDigit.INSTANCE, validator.getCheckDigit()); + } + +} Propchange: jakarta/commons/proper/validator/trunk/src/test/org/apache/commons/validator/routines/CodeValidatorTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jakarta/commons/proper/validator/trunk/src/test/org/apache/commons/validator/routines/CodeValidatorTest.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Modified: jakarta/commons/proper/validator/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/jakarta/commons/proper/validator/trunk/xdocs/changes.xml?view=diff&rev=486233&r1=486232&r2=486233 ============================================================================== --- jakarta/commons/proper/validator/trunk/xdocs/changes.xml (original) +++ jakarta/commons/proper/validator/trunk/xdocs/changes.xml Tue Dec 12 09:02:56 2006 @@ -40,6 +40,11 @@ <body> <release version="1.4-SNAPSHOT" date="in SVN" description="In progress"> + <action dev="niallp" type="add" issue="VALIDATOR-215"> + <b>Code Validator</b> - new generic code validator that validates format, + length and Check Digit for a code, see + <a href="apidocs/org/apache/commons/validator/routines/CodeValidator.html">CodeValidator</a>. + </action> <action dev="niallp" type="add" issue="VALIDATOR-214"> <b>Regular Expression Validator</b> - new Regular Expression validator using JDK 1.4's Regex, see <a href="apidocs/org/apache/commons/validator/routines/RegexValidator.html">RegexValidator</a>. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]