001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.validator.routines; 018 019import java.io.Serializable; 020 021import org.apache.commons.validator.routines.checkdigit.CheckDigit; 022 023/** 024 * Generic <b>Code Validation</b> providing format, minimum/maximum 025 * length and {@link CheckDigit} validations. 026 * <p> 027 * Performs the following validations on a code: 028 * <ul> 029 * <li>if the code is null, return null/false as appropriate</li> 030 * <li>trim the input. If the resulting code is empty, return null/false as appropriate</li> 031 * <li>Check the <i>format</i> of the code using a <i>regular expression.</i> (if specified)</li> 032 * <li>Check the <i>minimum</i> and <i>maximum</i> length (if specified) of the <i>parsed</i> code 033 * (i.e. parsed by the <i>regular expression</i>).</li> 034 * <li>Performs {@link CheckDigit} validation on the parsed code (if specified).</li> 035 * <li>The {@link #validate(String)} method returns the trimmed, parsed input (or null if validation failed)</li> 036 * </ul> 037 * <p> 038 * <b>Note</b> 039 * The {@link #isValid(String)} method will return true if the input passes validation. 040 * Since this includes trimming as well as potentially dropping parts of the input, 041 * it is possible for a String to pass validation 042 * but fail the checkdigit test if passed directly to it (the check digit routines generally don't trim input 043 * nor do they generally check the format/length). 044 * To be sure that you are passing valid input to a method use {@link #validate(String)} as follows: 045 * <pre> 046 * Object valid = validator.validate(input); 047 * if (valid != null) { 048 * some_method(valid.toString()); 049 * } 050 * </pre> 051 * <p> 052 * Configure the validator with the appropriate regular expression, minimum/maximum length 053 * and {@link CheckDigit} validator and then call one of the two validation 054 * methods provided:</p> 055 * <ul> 056 * <li><code>boolean isValid(code)</code></li> 057 * <li><code>String validate(code)</code></li> 058 * </ul> 059 * <p> 060 * Codes often include <i>format</i> characters - such as hyphens - to make them 061 * more easily human readable. These can be removed prior to length and check digit 062 * validation by specifying them as a <i>non-capturing</i> group in the regular 063 * expression (i.e. use the <code>(?: )</code> notation). 064 * <br> 065 * Or just avoid using parentheses except for the parts you want to capture 066 * 067 * @version $Revision$ 068 * @since Validator 1.4 069 */ 070public final class CodeValidator implements Serializable { 071 072 private static final long serialVersionUID = 446960910870938233L; 073 074 private final RegexValidator regexValidator; 075 private final int minLength; 076 private final int maxLength; 077 private final CheckDigit checkdigit; 078 079 /** 080 * Construct a code validator with a specified regular 081 * expression and {@link CheckDigit}. 082 * The RegexValidator validator is created to be case-sensitive 083 * 084 * @param regex The format regular expression 085 * @param checkdigit The check digit validation routine 086 */ 087 public CodeValidator(String regex, CheckDigit checkdigit) { 088 this(regex, -1, -1, checkdigit); 089 } 090 091 /** 092 * Construct a code validator with a specified regular 093 * expression, length and {@link CheckDigit}. 094 * The RegexValidator validator is created to be case-sensitive 095 * 096 * @param regex The format regular expression. 097 * @param length The length of the code 098 * (sets the mimimum/maximum to the same) 099 * @param checkdigit The check digit validation routine 100 */ 101 public CodeValidator(String regex, int length, CheckDigit checkdigit) { 102 this(regex, length, length, checkdigit); 103 } 104 105 /** 106 * Construct a code validator with a specified regular 107 * expression, minimum/maximum length and {@link CheckDigit} validation. 108 * The RegexValidator validator is created to be case-sensitive 109 * 110 * @param regex The regular expression 111 * @param minLength The minimum length of the code 112 * @param maxLength The maximum length of the code 113 * @param checkdigit The check digit validation routine 114 */ 115 public CodeValidator(String regex, int minLength, int maxLength, 116 CheckDigit checkdigit) { 117 if (regex != null && regex.length() > 0) { 118 this.regexValidator = new RegexValidator(regex); 119 } else { 120 this.regexValidator = null; 121 } 122 this.minLength = minLength; 123 this.maxLength = maxLength; 124 this.checkdigit = checkdigit; 125 } 126 127 /** 128 * Construct a code validator with a specified regular expression, 129 * validator and {@link CheckDigit} validation. 130 * 131 * @param regexValidator The format regular expression validator 132 * @param checkdigit The check digit validation routine. 133 */ 134 public CodeValidator(RegexValidator regexValidator, CheckDigit checkdigit) { 135 this(regexValidator, -1, -1, checkdigit); 136 } 137 138 /** 139 * Construct a code validator with a specified regular expression, 140 * validator, length and {@link CheckDigit} validation. 141 * 142 * @param regexValidator The format regular expression validator 143 * @param length The length of the code 144 * (sets the mimimum/maximum to the same value) 145 * @param checkdigit The check digit validation routine 146 */ 147 public CodeValidator(RegexValidator regexValidator, int length, CheckDigit checkdigit) { 148 this(regexValidator, length, length, checkdigit); 149 } 150 151 /** 152 * Construct a code validator with a specified regular expression 153 * validator, minimum/maximum length and {@link CheckDigit} validation. 154 * 155 * @param regexValidator The format regular expression validator 156 * @param minLength The minimum length of the code 157 * @param maxLength The maximum length of the code 158 * @param checkdigit The check digit validation routine 159 */ 160 public CodeValidator(RegexValidator regexValidator, int minLength, int maxLength, 161 CheckDigit checkdigit) { 162 this.regexValidator = regexValidator; 163 this.minLength = minLength; 164 this.maxLength = maxLength; 165 this.checkdigit = checkdigit; 166 } 167 168 /** 169 * Return the check digit validation routine. 170 * <p> 171 * <b>N.B.</b> Optional, if not set no Check Digit 172 * validation will be performed on the code. 173 * 174 * @return The check digit validation routine 175 */ 176 public CheckDigit getCheckDigit() { 177 return checkdigit; 178 } 179 180 /** 181 * Return the minimum length of the code. 182 * <p> 183 * <b>N.B.</b> Optional, if less than zero the 184 * minimum length will not be checked. 185 * 186 * @return The minimum length of the code or 187 * <code>-1</code> if the code has no minimum length 188 */ 189 public int getMinLength() { 190 return minLength; 191 } 192 193 /** 194 * Return the maximum length of the code. 195 * <p> 196 * <b>N.B.</b> Optional, if less than zero the 197 * maximum length will not be checked. 198 * 199 * @return The maximum length of the code or 200 * <code>-1</code> if the code has no maximum length 201 */ 202 public int getMaxLength() { 203 return maxLength; 204 } 205 206 /** 207 * Return the <i>regular expression</i> validator. 208 * <p> 209 * <b>N.B.</b> Optional, if not set no regular 210 * expression validation will be performed on the code. 211 * 212 * @return The regular expression validator 213 */ 214 public RegexValidator getRegexValidator() { 215 return regexValidator; 216 } 217 218 /** 219 * Validate the code returning either <code>true</code> 220 * or <code>false</code>. 221 * <p> 222 * This calls {@link #validate(String)} and returns false 223 * if the return value is null, true otherwise. 224 * <p> 225 * Note that {@link #validate(String)} trims the input 226 * and if there is a {@link RegexValidator} it may also 227 * change the input as part of the validation. 228 * 229 * @param input The code to validate 230 * @return <code>true</code> if valid, otherwise 231 * <code>false</code> 232 */ 233 public boolean isValid(String input) { 234 return (validate(input) != null); 235 } 236 237 /** 238 * Validate the code returning either the valid code or 239 * <code>null</code> if invalid. 240 * <p> 241 * Note that this method trims the input 242 * and if there is a {@link RegexValidator} it may also 243 * change the input as part of the validation. 244 * 245 * @param input The code to validate 246 * @return The code if valid, otherwise <code>null</code> 247 * if invalid 248 */ 249 public Object validate(String input) { 250 251 if (input == null) { 252 return null; 253 } 254 255 String code = input.trim(); 256 if (code.length() == 0) { 257 return null; 258 } 259 260 // validate/reformat using regular expression 261 if (regexValidator != null) { 262 code = regexValidator.validate(code); 263 if (code == null) { 264 return null; 265 } 266 } 267 268 // check the length (must be done after validate as that can change the code) 269 if ((minLength >= 0 && code.length() < minLength) || 270 (maxLength >= 0 && code.length() > maxLength)) { 271 return null; 272 } 273 274 // validate the check digit 275 if (checkdigit != null && !checkdigit.isValid(code)) { 276 return null; 277 } 278 279 return code; 280 281 } 282 283}