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     */
017    package org.apache.commons.validator.routines;
018    
019    import java.io.Serializable;
020    
021    import 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>Check the <i>format</i> of the code using a <i>regular expression.</i> (if specified)</li>
030     *   <li>Check the <i>minimum</i> and <i>maximum</i> length  (if specified) of the <i>parsed</i> code
031     *      (i.e. parsed by the <i>regular expression</i>).</li>
032     *   <li>Performs {@link CheckDigit} validation on the parsed code (if specified).</li>
033     * </ul>
034     * <p>
035     * Configure the validator with the appropriate regular expression, minimum/maximum length
036     * and {@link CheckDigit} validator and then call one of the two validation
037     * methods provided:</p>
038     *    <ul>
039     *       <li><code>boolean isValid(code)</code></li>
040     *       <li><code>String validate(code)</code></li>
041     *    </ul>
042     * <p>
043     * Codes often include <i>format</i> characters - such as hyphens - to make them
044     * more easily human readable. These can be removed prior to length and check digit
045     * validation by  specifying them as a <i>non-capturing</i> group in the regular
046     * expression (i.e. use the <code>(?:   )</code> notation).
047     *
048     * @version $Revision: 591497 $ $Date: 2007-11-02 23:25:16 +0100 (Fr, 02. Nov 2007) $
049     * @since Validator 1.4
050     */
051    public final class CodeValidator implements Serializable {
052    
053        private final RegexValidator regexValidator;
054        private final int minLength;
055        private final int maxLength;
056        private final CheckDigit checkdigit;
057    
058        /**
059         * Construct a code validator with a specified regular
060         * expression and {@link CheckDigit}.
061         *
062         * @param regex The format regular expression
063         * @param checkdigit The check digit validation routine
064         */
065        public CodeValidator(String regex, CheckDigit checkdigit) {
066            this(regex, -1, -1, checkdigit);
067        }
068    
069        /**
070         * Construct a code validator with a specified regular
071         * expression, length and {@link CheckDigit}.
072         *
073         * @param regex The format regular expression.
074         * @param length The length of the code
075         *  (sets the mimimum/maximum to the same)
076         * @param checkdigit The check digit validation routine
077         */
078        public CodeValidator(String regex, int length, CheckDigit checkdigit) {
079            this(regex, length, length, checkdigit);
080        }
081    
082        /**
083         * Construct a code validator with a specified regular
084         * expression, minimum/maximum length and {@link CheckDigit} validation.
085         *
086         * @param regex The regular expression validator
087         * @param minLength The minimum length of the code
088         * @param maxLength The maximum length of the code
089         * @param checkdigit The check digit validation routine
090         */
091        public CodeValidator(String regex, int minLength, int maxLength,
092                CheckDigit checkdigit) {
093            if (regex != null && regex.length() > 0) {
094                this.regexValidator = new RegexValidator(regex);
095            } else {
096                this.regexValidator = null;
097            }
098            this.minLength = minLength;
099            this.maxLength = maxLength;
100            this.checkdigit = checkdigit;
101        }
102    
103        /**
104         * Construct a code validator with a specified regular expression,
105         * validator and {@link CheckDigit} validation.
106         *
107         * @param regexValidator The format regular expression validator
108         * @param checkdigit The check digit validation routine.
109         */
110        public CodeValidator(RegexValidator regexValidator, CheckDigit checkdigit) {
111            this(regexValidator, -1, -1, checkdigit);
112        }
113    
114        /**
115         * Construct a code validator with a specified regular expression,
116         * validator, length and {@link CheckDigit} validation.
117         *
118         * @param regexValidator The format regular expression validator
119         * @param length The length of the code
120         *  (sets the mimimum/maximum to the same value)
121         * @param checkdigit The check digit validation routine
122         */
123        public CodeValidator(RegexValidator regexValidator, int length, CheckDigit checkdigit) {
124            this(regexValidator, length, length, checkdigit);
125        }
126    
127        /**
128         * Construct a code validator with a specified regular expression
129         * validator, minimum/maximum length and {@link CheckDigit} validation.
130         *
131         * @param regexValidator The format regular expression validator
132         * @param minLength The minimum length of the code
133         * @param maxLength The maximum length of the code
134         * @param checkdigit The check digit validation routine
135         */
136        public CodeValidator(RegexValidator regexValidator, int minLength, int maxLength,
137                CheckDigit checkdigit) {
138            this.regexValidator = regexValidator;
139            this.minLength = minLength;
140            this.maxLength = maxLength;
141            this.checkdigit = checkdigit;
142        }
143    
144        /**
145         * Return the check digit validation routine.
146         * <p>
147         * <b>N.B.</b> Optional, if not set no Check Digit
148         * validation will be performed on the code.
149         *
150         * @return The check digit validation routine
151         */
152        public CheckDigit getCheckDigit() {
153            return checkdigit;
154        }
155    
156        /**
157         * Return the minimum length of the code.
158         * <p>
159         * <b>N.B.</b> Optional, if less than zero the
160         * minimum length will not be checked.
161         *
162         * @return The minimum length of the code or
163         * <code>-1</code> if the code has no minimum length
164         */
165        public int getMinLength() {
166            return minLength;
167        }
168    
169        /**
170         * Return the maximum length of the code.
171         * <p>
172         * <b>N.B.</b> Optional, if less than zero the
173         * maximum length will not be checked.
174         *
175         * @return The maximum length of the code or
176         * <code>-1</code> if the code has no maximum length
177         */
178        public int getMaxLength() {
179            return maxLength;
180        }
181    
182        /**
183         * Return the <i>regular expression</i> validator.
184         * <p>
185         * <b>N.B.</b> Optional, if not set no regular
186         * expression validation will be performed on the code.
187         *
188         * @return The regular expression validator
189         */
190        public RegexValidator getRegexValidator() {
191            return regexValidator;
192        }
193    
194        /**
195         * Validate the code returning either <code>true</code>
196         * or <code>false</code>.
197         *
198         * @param input The code to validate
199         * @return <code>true</code> if valid, otherwise
200         * <code>false</code>
201         */
202        public boolean isValid(String input) {
203            return (validate(input) != null);
204        }
205    
206        /**
207         * Validate the code returning either the valid code or
208         * <code>null</code> if invalid.
209         *
210         * @param input The code to validate
211         * @return The code if valid, otherwise <code>null</code>
212         * if invalid
213         */
214        public Object validate(String input) {
215    
216            String code = (input == null ? null : input.trim());
217            if (code != null && code.length() == 0) {
218                return null;
219            }
220    
221            // validate/reformat using regular expression
222            if (regexValidator != null) {
223                code = regexValidator.validate(code);
224                if (code == null) {
225                    return null;
226                }
227            }
228    
229            // check the length
230            if ((minLength >= 0 && code.length() < minLength) ||
231                (maxLength >= 0 && code.length() > maxLength)) {
232                return null;
233            }
234    
235            // validate the check digit
236            if (checkdigit != null && !checkdigit.isValid(code)) {
237                return null;
238            }
239    
240            return code;
241    
242        }
243    
244    }