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 19 import java.io.Serializable; 20 21 import org.apache.commons.validator.GenericValidator; 22 import org.apache.commons.validator.routines.checkdigit.CheckDigit; 23 24 /** 25 * Generic <b>Code Validation</b> providing format, minimum/maximum 26 * length and {@link CheckDigit} validations. 27 * <p> 28 * Performs the following validations on a code: 29 * <ul> 30 * <li>if the code is null, return null/false as appropriate</li> 31 * <li>trim the input. If the resulting code is empty, return null/false as appropriate</li> 32 * <li>Check the <i>format</i> of the code using a <i>regular expression.</i> (if specified)</li> 33 * <li>Check the <i>minimum</i> and <i>maximum</i> length (if specified) of the <i>parsed</i> code 34 * (i.e. parsed by the <i>regular expression</i>).</li> 35 * <li>Performs {@link CheckDigit} validation on the parsed code (if specified).</li> 36 * <li>The {@link #validate(String)} method returns the trimmed, parsed input (or null if validation failed)</li> 37 * </ul> 38 * <p> 39 * <b>Note</b> 40 * The {@link #isValid(String)} method will return true if the input passes validation. 41 * Since this includes trimming as well as potentially dropping parts of the input, 42 * it is possible for a String to pass validation 43 * but fail the checkdigit test if passed directly to it (the check digit routines generally don't trim input 44 * nor do they generally check the format/length). 45 * To be sure that you are passing valid input to a method use {@link #validate(String)} as follows: 46 * <pre> 47 * Object valid = validator.validate(input); 48 * if (valid != null) { 49 * some_method(valid.toString()); 50 * } 51 * </pre> 52 * <p> 53 * Configure the validator with the appropriate regular expression, minimum/maximum length 54 * and {@link CheckDigit} validator and then call one of the two validation 55 * methods provided:</p> 56 * <ul> 57 * <li><code>boolean isValid(code)</code></li> 58 * <li><code>String validate(code)</code></li> 59 * </ul> 60 * <p> 61 * Codes often include <i>format</i> characters - such as hyphens - to make them 62 * more easily human readable. These can be removed prior to length and check digit 63 * validation by specifying them as a <i>non-capturing</i> group in the regular 64 * expression (i.e. use the <code>(?: )</code> notation). 65 * <br> 66 * Or just avoid using parentheses except for the parts you want to capture 67 * 68 * @since 1.4 69 */ 70 public final class CodeValidator implements Serializable { 71 72 private static final long serialVersionUID = 446960910870938233L; 73 74 /** The format regular expression validator. */ 75 private final RegexValidator regexValidator; 76 77 /** The minimum length of the code. */ 78 private final int minLength; 79 80 /** The maximum length of the code. */ 81 private final int maxLength; 82 83 /** The check digit validation routine. */ 84 private final CheckDigit checkdigit; 85 86 /** 87 * Constructs a code validator with a specified regular expression, 88 * validator and {@link CheckDigit} validation. 89 * 90 * @param regexValidator The format regular expression validator 91 * @param checkdigit The check digit validation routine. 92 */ 93 public CodeValidator(final RegexValidator regexValidator, final CheckDigit checkdigit) { 94 this(regexValidator, -1, -1, checkdigit); 95 } 96 97 /** 98 * Constructs a code validator with a specified regular expression, 99 * validator, length and {@link CheckDigit} validation. 100 * 101 * @param regexValidator The format regular expression validator 102 * @param length The length of the code 103 * (sets the mimimum/maximum to the same value) 104 * @param checkdigit The check digit validation routine 105 */ 106 public CodeValidator(final RegexValidator regexValidator, final int length, final CheckDigit checkdigit) { 107 this(regexValidator, length, length, checkdigit); 108 } 109 110 /** 111 * Constructs a code validator with a specified regular expression 112 * validator, minimum/maximum length and {@link CheckDigit} validation. 113 * 114 * @param regexValidator The format regular expression validator 115 * @param minLength The minimum length of the code 116 * @param maxLength The maximum length of the code 117 * @param checkdigit The check digit validation routine 118 */ 119 public CodeValidator(final RegexValidator regexValidator, final int minLength, final int maxLength, 120 final CheckDigit checkdigit) { 121 this.regexValidator = regexValidator; 122 this.minLength = minLength; 123 this.maxLength = maxLength; 124 this.checkdigit = checkdigit; 125 } 126 127 /** 128 * Constructs a code validator with a specified regular 129 * expression and {@link CheckDigit}. 130 * The RegexValidator validator is created to be case-sensitive 131 * 132 * @param regex The format regular expression 133 * @param checkdigit The check digit validation routine 134 */ 135 public CodeValidator(final String regex, final CheckDigit checkdigit) { 136 this(regex, -1, -1, checkdigit); 137 } 138 139 /** 140 * Constructs a code validator with a specified regular 141 * expression, length and {@link CheckDigit}. 142 * The RegexValidator validator is created to be case-sensitive 143 * 144 * @param regex The format regular expression. 145 * @param length The length of the code 146 * (sets the mimimum/maximum to the same) 147 * @param checkdigit The check digit validation routine 148 */ 149 public CodeValidator(final String regex, final int length, final CheckDigit checkdigit) { 150 this(regex, length, length, checkdigit); 151 } 152 153 /** 154 * Constructs a code validator with a specified regular 155 * expression, minimum/maximum length and {@link CheckDigit} validation. 156 * The RegexValidator validator is created to be case-sensitive 157 * 158 * @param regex The regular expression 159 * @param minLength The minimum length of the code 160 * @param maxLength The maximum length of the code 161 * @param checkdigit The check digit validation routine 162 */ 163 public CodeValidator(final String regex, final int minLength, final int maxLength, 164 final CheckDigit checkdigit) { 165 if (!GenericValidator.isBlankOrNull(regex)) { 166 this.regexValidator = new RegexValidator(regex); 167 } else { 168 this.regexValidator = null; 169 } 170 this.minLength = minLength; 171 this.maxLength = maxLength; 172 this.checkdigit = checkdigit; 173 } 174 175 /** 176 * Gets the check digit validation routine. 177 * <p> 178 * <b>N.B.</b> Optional, if not set no Check Digit 179 * validation will be performed on the code. 180 * 181 * @return The check digit validation routine 182 */ 183 public CheckDigit getCheckDigit() { 184 return checkdigit; 185 } 186 187 /** 188 * Gets the maximum length of the code. 189 * <p> 190 * <b>N.B.</b> Optional, if less than zero the 191 * maximum length will not be checked. 192 * 193 * @return The maximum length of the code or 194 * <code>-1</code> if the code has no maximum length 195 */ 196 public int getMaxLength() { 197 return maxLength; 198 } 199 200 /** 201 * Gets the minimum length of the code. 202 * <p> 203 * <b>N.B.</b> Optional, if less than zero the 204 * minimum length will not be checked. 205 * 206 * @return The minimum length of the code or 207 * <code>-1</code> if the code has no minimum length 208 */ 209 public int getMinLength() { 210 return minLength; 211 } 212 213 /** 214 * Gets the <i>regular expression</i> validator. 215 * <p> 216 * <b>N.B.</b> Optional, if not set no regular 217 * expression validation will be performed on the code. 218 * 219 * @return The regular expression validator 220 */ 221 public RegexValidator getRegexValidator() { 222 return regexValidator; 223 } 224 225 /** 226 * Validate the code returning either {@code true} 227 * or {@code false}. 228 * <p> 229 * This calls {@link #validate(String)} and returns false 230 * if the return value is null, true otherwise. 231 * <p> 232 * Note that {@link #validate(String)} trims the input 233 * and if there is a {@link RegexValidator} it may also 234 * change the input as part of the validation. 235 * 236 * @param input The code to validate 237 * @return {@code true} if valid, otherwise 238 * {@code false} 239 */ 240 public boolean isValid(final String input) { 241 return validate(input) != null; 242 } 243 244 /** 245 * Validate the code returning either the valid code or 246 * {@code null} if invalid. 247 * <p> 248 * Note that this method trims the input 249 * and if there is a {@link RegexValidator} it may also 250 * change the input as part of the validation. 251 * 252 * @param input The code to validate 253 * @return The code if valid, otherwise {@code null} 254 * if invalid 255 */ 256 public Object validate(final String input) { 257 if (input == null) { 258 return null; 259 } 260 String code = input.trim(); 261 if (code.isEmpty()) { 262 return null; 263 } 264 // validate/reformat using regular expression 265 if (regexValidator != null) { 266 code = regexValidator.validate(code); 267 if (code == null) { 268 return null; 269 } 270 } 271 // check the length (must be done after validate as that can change the code) 272 if (minLength >= 0 && code.length() < minLength || 273 maxLength >= 0 && code.length() > maxLength) { 274 return null; 275 } 276 // validate the check digit 277 if (checkdigit != null && !checkdigit.isValid(code)) { 278 return null; 279 } 280 return code; 281 } 282 283 }