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