CodeValidator.java

  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.routines;

  18. import java.io.Serializable;

  19. import org.apache.commons.validator.GenericValidator;
  20. import org.apache.commons.validator.routines.checkdigit.CheckDigit;

  21. /**
  22.  * Generic <b>Code Validation</b> providing format, minimum/maximum
  23.  * length and {@link CheckDigit} validations.
  24.  * <p>
  25.  * Performs the following validations on a code:
  26.  * <ul>
  27.  *   <li>if the code is null, return null/false as appropriate</li>
  28.  *   <li>trim the input. If the resulting code is empty, return null/false as appropriate</li>
  29.  *   <li>Check the <i>format</i> of the code using a <i>regular expression.</i> (if specified)</li>
  30.  *   <li>Check the <i>minimum</i> and <i>maximum</i> length  (if specified) of the <i>parsed</i> code
  31.  *      (i.e. parsed by the <i>regular expression</i>).</li>
  32.  *   <li>Performs {@link CheckDigit} validation on the parsed code (if specified).</li>
  33.  *   <li>The {@link #validate(String)} method returns the trimmed, parsed input (or null if validation failed)</li>
  34.  * </ul>
  35.  * <p>
  36.  * <b>Note</b>
  37.  * The {@link #isValid(String)} method will return true if the input passes validation.
  38.  * Since this includes trimming as well as potentially dropping parts of the input,
  39.  * it is possible for a String to pass validation
  40.  * but fail the checkdigit test if passed directly to it (the check digit routines generally don't trim input
  41.  * nor do they generally check the format/length).
  42.  * To be sure that you are passing valid input to a method use {@link #validate(String)} as follows:
  43.  * <pre>
  44.  * Object valid = validator.validate(input);
  45.  * if (valid != null) {
  46.  *    some_method(valid.toString());
  47.  * }
  48.  * </pre>
  49.  * <p>
  50.  * Configure the validator with the appropriate regular expression, minimum/maximum length
  51.  * and {@link CheckDigit} validator and then call one of the two validation
  52.  * methods provided:</p>
  53.  *    <ul>
  54.  *       <li><code>boolean isValid(code)</code></li>
  55.  *       <li><code>String validate(code)</code></li>
  56.  *    </ul>
  57.  * <p>
  58.  * Codes often include <i>format</i> characters - such as hyphens - to make them
  59.  * more easily human readable. These can be removed prior to length and check digit
  60.  * validation by  specifying them as a <i>non-capturing</i> group in the regular
  61.  * expression (i.e. use the <code>(?:   )</code> notation).
  62.  * <br>
  63.  * Or just avoid using parentheses except for the parts you want to capture
  64.  *
  65.  * @since 1.4
  66.  */
  67. public final class CodeValidator implements Serializable {

  68.     private static final long serialVersionUID = 446960910870938233L;

  69.     /** The format regular expression validator. */
  70.     private final RegexValidator regexValidator;

  71.     /** The minimum length of the code. */
  72.     private final int minLength;

  73.     /** The maximum length of the code. */
  74.     private final int maxLength;

  75.     /** The check digit validation routine. */
  76.     private final CheckDigit checkdigit;

  77.     /**
  78.      * Constructs a code validator with a specified regular expression,
  79.      * validator and {@link CheckDigit} validation.
  80.      *
  81.      * @param regexValidator The format regular expression validator
  82.      * @param checkdigit The check digit validation routine.
  83.      */
  84.     public CodeValidator(final RegexValidator regexValidator, final CheckDigit checkdigit) {
  85.         this(regexValidator, -1, -1, checkdigit);
  86.     }

  87.     /**
  88.      * Constructs a code validator with a specified regular expression,
  89.      * validator, length and {@link CheckDigit} validation.
  90.      *
  91.      * @param regexValidator The format regular expression validator
  92.      * @param length The length of the code
  93.      *  (sets the mimimum/maximum to the same value)
  94.      * @param checkdigit The check digit validation routine
  95.      */
  96.     public CodeValidator(final RegexValidator regexValidator, final int length, final CheckDigit checkdigit) {
  97.         this(regexValidator, length, length, checkdigit);
  98.     }

  99.     /**
  100.      * Constructs a code validator with a specified regular expression
  101.      * validator, minimum/maximum length and {@link CheckDigit} validation.
  102.      *
  103.      * @param regexValidator The format regular expression validator
  104.      * @param minLength The minimum length of the code
  105.      * @param maxLength The maximum length of the code
  106.      * @param checkdigit The check digit validation routine
  107.      */
  108.     public CodeValidator(final RegexValidator regexValidator, final int minLength, final int maxLength,
  109.             final CheckDigit checkdigit) {
  110.         this.regexValidator = regexValidator;
  111.         this.minLength = minLength;
  112.         this.maxLength = maxLength;
  113.         this.checkdigit = checkdigit;
  114.     }

  115.     /**
  116.      * Constructs a code validator with a specified regular
  117.      * expression and {@link CheckDigit}.
  118.      * The RegexValidator validator is created to be case-sensitive
  119.      *
  120.      * @param regex The format regular expression
  121.      * @param checkdigit The check digit validation routine
  122.      */
  123.     public CodeValidator(final String regex, final CheckDigit checkdigit) {
  124.         this(regex, -1, -1, checkdigit);
  125.     }

  126.     /**
  127.      * Constructs a code validator with a specified regular
  128.      * expression, length and {@link CheckDigit}.
  129.      * The RegexValidator validator is created to be case-sensitive
  130.      *
  131.      * @param regex The format regular expression.
  132.      * @param length The length of the code
  133.      *  (sets the mimimum/maximum to the same)
  134.      * @param checkdigit The check digit validation routine
  135.      */
  136.     public CodeValidator(final String regex, final int length, final CheckDigit checkdigit) {
  137.         this(regex, length, length, checkdigit);
  138.     }

  139.     /**
  140.      * Constructs a code validator with a specified regular
  141.      * expression, minimum/maximum length and {@link CheckDigit} validation.
  142.      * The RegexValidator validator is created to be case-sensitive
  143.      *
  144.      * @param regex The regular expression
  145.      * @param minLength The minimum length of the code
  146.      * @param maxLength The maximum length of the code
  147.      * @param checkdigit The check digit validation routine
  148.      */
  149.     public CodeValidator(final String regex, final int minLength, final int maxLength,
  150.             final CheckDigit checkdigit) {
  151.         if (!GenericValidator.isBlankOrNull(regex)) {
  152.             this.regexValidator = new RegexValidator(regex);
  153.         } else {
  154.             this.regexValidator = null;
  155.         }
  156.         this.minLength = minLength;
  157.         this.maxLength = maxLength;
  158.         this.checkdigit = checkdigit;
  159.     }

  160.     /**
  161.      * Gets the check digit validation routine.
  162.      * <p>
  163.      * <b>N.B.</b> Optional, if not set no Check Digit
  164.      * validation will be performed on the code.
  165.      *
  166.      * @return The check digit validation routine
  167.      */
  168.     public CheckDigit getCheckDigit() {
  169.         return checkdigit;
  170.     }

  171.     /**
  172.      * Gets the maximum length of the code.
  173.      * <p>
  174.      * <b>N.B.</b> Optional, if less than zero the
  175.      * maximum length will not be checked.
  176.      *
  177.      * @return The maximum length of the code or
  178.      * <code>-1</code> if the code has no maximum length
  179.      */
  180.     public int getMaxLength() {
  181.         return maxLength;
  182.     }

  183.     /**
  184.      * Gets the minimum length of the code.
  185.      * <p>
  186.      * <b>N.B.</b> Optional, if less than zero the
  187.      * minimum length will not be checked.
  188.      *
  189.      * @return The minimum length of the code or
  190.      * <code>-1</code> if the code has no minimum length
  191.      */
  192.     public int getMinLength() {
  193.         return minLength;
  194.     }

  195.     /**
  196.      * Gets the <i>regular expression</i> validator.
  197.      * <p>
  198.      * <b>N.B.</b> Optional, if not set no regular
  199.      * expression validation will be performed on the code.
  200.      *
  201.      * @return The regular expression validator
  202.      */
  203.     public RegexValidator getRegexValidator() {
  204.         return regexValidator;
  205.     }

  206.     /**
  207.      * Validate the code returning either {@code true}
  208.      * or {@code false}.
  209.      * <p>
  210.      * This calls {@link #validate(String)} and returns false
  211.      * if the return value is null, true otherwise.
  212.      * <p>
  213.      * Note that {@link #validate(String)} trims the input
  214.      * and if there is a {@link RegexValidator} it may also
  215.      * change the input as part of the validation.
  216.      *
  217.      * @param input The code to validate
  218.      * @return {@code true} if valid, otherwise
  219.      * {@code false}
  220.      */
  221.     public boolean isValid(final String input) {
  222.         return validate(input) != null;
  223.     }

  224.     /**
  225.      * Validate the code returning either the valid code or
  226.      * {@code null} if invalid.
  227.      * <p>
  228.      * Note that this method trims the input
  229.      * and if there is a {@link RegexValidator} it may also
  230.      * change the input as part of the validation.
  231.      *
  232.      * @param input The code to validate
  233.      * @return The code if valid, otherwise {@code null}
  234.      * if invalid
  235.      */
  236.     public Object validate(final String input) {
  237.         if (input == null) {
  238.             return null;
  239.         }
  240.         String code = input.trim();
  241.         if (code.isEmpty()) {
  242.             return null;
  243.         }
  244.         // validate/reformat using regular expression
  245.         if (regexValidator != null) {
  246.             code = regexValidator.validate(code);
  247.             if (code == null) {
  248.                 return null;
  249.             }
  250.         }
  251.         // check the length (must be done after validate as that can change the code)
  252.         if (minLength >= 0 && code.length() < minLength ||
  253.             maxLength >= 0 && code.length() > maxLength) {
  254.             return null;
  255.         }
  256.         // validate the check digit
  257.         if (checkdigit != null && !checkdigit.isValid(code)) {
  258.             return null;
  259.         }
  260.         return code;
  261.     }

  262. }