    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 *      https://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;
    018
    019import java.io.Serializable;
    020import java.util.HashMap;
    021import java.util.Locale;
    022import java.util.Map;
    023
    024/**
    025 * Validations are processed by the validate method. An instance of
    026 * {@code ValidatorResources} is used to define the validators
    027 * (validation methods) and the validation rules for a JavaBean.
    028 */
    029// TODO mutable fields should be made private and accessed via suitable methods only
    030public class Validator implements Serializable {
    031
    032    /**
    033     * Resources key the JavaBean is stored to perform validation on.
    034     */
    035    public static final String BEAN_PARAM = "java.lang.Object";
    036
    037    /**
    038     * Resources key the {@code Field} is stored under.
    039     * This will be automatically passed into a validation method
    040     * with the current {@code Field} if it is
    041     * specified in the method signature.
    042     */
    043    public static final String FIELD_PARAM = "org.apache.commons.validator.Field";
    044
    045    /**
    046     * Resources key the {@code Form} is stored under.
    047     * This will be automatically passed into a validation method
    048     * with the current {@code Form} if it is
    049     * specified in the method signature.
    050     */
    051    public static final String FORM_PARAM = "org.apache.commons.validator.Form";
    052
    053    /**
    054     * Resources key the {@link Locale} is stored.
    055     * This will be used to retrieve the appropriate
    056     * {@code FormSet} and {@code Form} to be
    057     * processed.
    058     */
    059    public static final String LOCALE_PARAM = "java.util.Locale";
    060
    061    private static final long serialVersionUID = -7119418755208731611L;
    062
    063    /**
    064     * Resources key the {@code ValidatorAction} is stored under.
    065     * This will be automatically passed into a validation method
    066     * with the current {@code ValidatorAction} if it is
    067     * specified in the method signature.
    068     */
    069    public static final String VALIDATOR_ACTION_PARAM =
    070            "org.apache.commons.validator.ValidatorAction";
    071
    072    /**
    073     * Resources key the {@code Validator} is stored under.
    074     * This will be automatically passed into a validation method
    075     * with the current {@code Validator} if it is
    076     * specified in the method signature.
    077     */
    078    public static final String VALIDATOR_PARAM =
    079            "org.apache.commons.validator.Validator";
    080
    081    /**
    082     * Resources key the {@code ValidatorResults} is stored under.
    083     * This will be automatically passed into a validation method
    084     * with the current {@code ValidatorResults} if it is
    085     * specified in the method signature.
    086     */
    087    public static final String VALIDATOR_RESULTS_PARAM =
    088            "org.apache.commons.validator.ValidatorResults";
    089
    090    static Locale toLocale(final Locale locale) {
    091        return locale != null ? locale : Locale.getDefault();
    092    }
    093
    094    /**
    095     * The class loader to use for instantiating application objects.
    096     * If not specified, the context class loader, or the class loader
    097     * used to load Digester itself, is used, based on the value of the
    098     * {@code useContextClassLoader} variable.
    099     *
    100     * @deprecated Use {@link #getClassLoader()}, will be private in the next major version.
    101     */
    102    @Deprecated
    103    protected transient ClassLoader classLoader;
    104
    105    /**
    106     * The name of the field on the form to validate
    107     *
    108     * @since 1.2.0
    109     *
    110     * @deprecated Use {@link #getFieldName()}, will be private in the next major version.
    111     */
    112    @Deprecated
    113    protected String fieldName;
    114
    115    /**
    116     * The name of the form to validate
    117     *
    118     * @deprecated Use {@link #getFormName()}, will be private in the next major version.
    119     */
    120    @Deprecated
    121    protected String formName;
    122
    123    /**
    124     * Sets this to true to not return Fields that pass validation.  Only return failures.
    125     *
    126     * @deprecated Use {@link #getOnlyReturnErrors()}, will be private in the next major version.
    127     */
    128    @Deprecated
    129    protected boolean onlyReturnErrors;
    130
    131    /**
    132     * The current page number to validate.
    133     *
    134     * @deprecated Use {@link #getPage()}, will be private in the next major version.
    135     */
    136    @Deprecated
    137    protected int page;
    138
    139    /**
    140     * Maps validation method parameter class names to the objects to be passed
    141     * into the method.
    142     *
    143     * @deprecated Use {@link #getParameters()}, will be private in the next major version.
    144     */
    145    @Deprecated
    146    protected Map<String, Object> parameters = new HashMap<>();
    147
    148    /**
    149     * The Validator Resources.
    150     *
    151     * @deprecated Use {@link #getResources()}, will be private in the next major version.
    152     */
    153    @Deprecated
    154    protected ValidatorResources resources;
    155
    156    /**
    157     * Whether or not to use the Context ClassLoader when loading classes
    158     * for instantiating new objects.  Default is {@code false}.
    159     *
    160     * @deprecated Use {@link #getUseContextClassLoader()}, will be private in the next major version.
    161     */
    162    @Deprecated
    163    protected boolean useContextClassLoader;
    164
    165    /**
    166     * Constructs a {@code Validator} that will
    167     * use the {@code ValidatorResources}
    168     * passed in to retrieve pluggable validators
    169     * the different sets of validation rules.
    170     *
    171     * @param resources {@code ValidatorResources} to use during validation.
    172     */
    173    public Validator(final ValidatorResources resources) {
    174        this(resources, null);
    175    }
    176
    177    /**
    178     * Constructs a {@code Validator} that will
    179     * use the {@code ValidatorResources}
    180     * passed in to retrieve pluggable validators
    181     * the different sets of validation rules.
    182     *
    183     * @param resources {@code ValidatorResources} to use during validation.
    184     * @param formName Key used for retrieving the set of validation rules.
    185     */
    186    public Validator(final ValidatorResources resources, final String formName) {
    187        if (resources == null) {
    188            throw new IllegalArgumentException("Resources cannot be null.");
    189        }
    190
    191        this.resources = resources;
    192        this.formName = formName;
    193    }
    194
    195    /**
    196     * Constructs a {@code Validator} that will
    197     * use the {@code ValidatorResources}
    198     * passed in to retrieve pluggable validators
    199     * the different sets of validation rules.
    200     *
    201     * @param resources {@code ValidatorResources} to use during validation.
    202     * @param formName Key used for retrieving the set of validation rules.
    203     * @param fieldName Key used for retrieving the set of validation rules for a field
    204     * @since 1.2.0
    205     */
    206    public Validator(final ValidatorResources resources, final String formName, final String fieldName) {
    207        if (resources == null) {
    208            throw new IllegalArgumentException("Resources cannot be null.");
    209        }
    210
    211        this.resources = resources;
    212        this.formName = formName;
    213        this.fieldName = fieldName;
    214    }
    215
    216    /**
    217     * Clears the form name, resources that were added, and the page that was
    218     * set (if any).  This can be called to reinitialize the Validator instance
    219     * so it can be reused.  The form name (key to set of validation rules) and any
    220     * resources needed, like the JavaBean being validated, will need to
    221     * set and/or added to this instance again.  The
    222     * {@code ValidatorResources} will not be removed since it can be used
    223     * again and is thread safe.
    224     */
    225    public void clear() {
    226        formName = null;
    227        fieldName = null;
    228        parameters.clear();
    229        page = 0;
    230    }
    231
    232    /**
    233     * Gets the class loader to be used for instantiating application objects
    234     * when required.  This is determined based upon the following rules:
    235     * <ul>
    236     * <li>The class loader set by {@code setClassLoader()}, if any</li>
    237     * <li>The thread context class loader, if it exists and the
    238     *     {@code useContextClassLoader} property is set to true</li>
    239     * <li>The class loader used to load the Digester class itself.</li>
    240     * </ul>
    241     *
    242     * @return The class loader.
    243     */
    244    public ClassLoader getClassLoader() {
    245        if (classLoader != null) {
    246            return classLoader;
    247        }
    248
    249        if (useContextClassLoader) {
    250            final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
    251            if (contextLoader != null) {
    252                return contextLoader;
    253            }
    254        }
    255
    256        return this.getClass().getClassLoader();
    257    }
    258
    259    /**
    260     * Gets the field name.
    261     *
    262     * @return The field name.
    263     * @since 1.10.0
    264     */
    265    public String getFieldName() {
    266        return fieldName;
    267    }
    268
    269    /**
    270     * Gets the form name which is the key to a set of validation rules.
    271     *
    272     * @return The name of the form.
    273     */
    274    public String getFormName() {
    275        return formName;
    276    }
    277
    278    /**
    279     * Returns true if the Validator is only returning Fields that fail validation.
    280     *
    281     * @return whether only failed fields are returned.
    282     */
    283    public boolean getOnlyReturnErrors() {
    284        return onlyReturnErrors;
    285    }
    286
    287    /**
    288     * Gets the page.
    289     *
    290     * <p>
    291     * This in conjunction with the page property of
    292     * a {@code Field} can control the processing of fields. If the field's
    293     * page is less than or equal to this page value, it will be processed.
    294     * </p>
    295     *
    296     * @return The page number.
    297     */
    298    public int getPage() {
    299        return page;
    300    }
    301
    302    /**
    303     * Gets the parameter map.
    304     *
    305     * @return The parameter map.
    306     * @since 1.10.0
    307     */
    308    public Map<String, Object> getParameters() {
    309        return parameters;
    310    }
    311
    312    /**
    313     * Returns the value of the specified parameter that will be used during the
    314     * processing of validations.
    315     *
    316     * @param parameterClassName The full class name of the parameter of the
    317     * validation method that corresponds to the value/instance passed in with it.
    318     * @return value of the specified parameter.
    319     */
    320    public Object getParameterValue(final String parameterClassName) {
    321        return parameters.get(parameterClassName);
    322    }
    323
    324    /**
    325     * Gets the validator resource.
    326     *
    327     * @return The validator resource.
    328     * @since 1.10.0
    329     */
    330    public ValidatorResources getResources() {
    331        return resources;
    332    }
    333
    334    /**
    335     * Gets the boolean as to whether the context classloader should be used.
    336     *
    337     * @return whether the context classloader should be used.
    338     */
    339    public boolean getUseContextClassLoader() {
    340        return useContextClassLoader;
    341    }
    342
    343    /**
    344     * Sets the class loader to be used for instantiating application objects
    345     * when required.
    346     *
    347     * @param classLoader The new class loader to use, or {@code null}
    348     *  to revert to the standard rules
    349     */
    350    public void setClassLoader(final ClassLoader classLoader) {
    351        this.classLoader = classLoader;
    352    }
    353
    354    /**
    355     * Sets the name of the field to validate in a form (optional)
    356     *
    357     * @param fieldName The name of the field in a form set
    358     * @since 1.2.0
    359     */
    360    public void setFieldName(final String fieldName) {
    361        this.fieldName = fieldName;
    362    }
    363
    364    /**
    365     * Sets the form name which is the key to a set of validation rules.
    366     *
    367     * @param formName The name of the form.
    368     */
    369    public void setFormName(final String formName) {
    370        this.formName = formName;
    371    }
    372
    373    /**
    374     * Configures which Fields the Validator returns from the validate() method.  Set this
    375     * to true to only return Fields that failed validation.  By default, validate() returns
    376     * all fields.
    377     *
    378     * @param onlyReturnErrors whether only failed fields are returned.
    379     */
    380    public void setOnlyReturnErrors(final boolean onlyReturnErrors) {
    381        this.onlyReturnErrors = onlyReturnErrors;
    382    }
    383
    384    /**
    385     * Sets the page.
    386     * <p>
    387     * This in conjunction with the page property of
    388     * a {@code Field} can control the processing of fields. If the field's page
    389     * is less than or equal to this page value, it will be processed.
    390     * </p>
    391     *
    392     * @param page The page number.
    393     */
    394    public void setPage(final int page) {
    395        this.page = page;
    396    }
    397
    398    /**
    399     * Sets a parameter of a pluggable validation method.
    400     *
    401     * @param parameterClassName The full class name of the parameter of the
    402     * validation method that corresponds to the value/instance passed in with it.
    403     *
    404     * @param parameterValue The instance that will be passed into the
    405     * validation method.
    406     */
    407    public void setParameter(final String parameterClassName, final Object parameterValue) {
    408        parameters.put(parameterClassName, parameterValue);
    409    }
    410
    411    /**
    412     * Sets whether to use the Context ClassLoader (the one found by
    413     * calling {@code Thread.currentThread().getContextClassLoader()})
    414     * to resolve/load classes that are defined in various rules.  If not
    415     * using Context ClassLoader, then the class-loading defaults to
    416     * using the calling-class' ClassLoader.
    417     *
    418     * @param useContextClassLoader determines whether to use Context ClassLoader.
    419     */
    420    public void setUseContextClassLoader(final boolean useContextClassLoader) {
    421        this.useContextClassLoader = useContextClassLoader;
    422    }
    423
    424    /**
    425     * Performs validations based on the configured resources.
    426     *
    427     * @return The {@link Map} returned uses the property of the
    428     * {@code Field} for the key and the value is the number of error the
    429     * field had.
    430     * @throws ValidatorException If an error occurs during validation
    431     */
    432    public ValidatorResults validate() throws ValidatorException {
    433        Locale locale = (Locale) getParameterValue(LOCALE_PARAM);
    434        locale = toLocale(locale);
    435        setParameter(VALIDATOR_PARAM, this);
    436        final Form form = resources.getForm(locale, formName);
    437        if (form != null) {
    438            setParameter(FORM_PARAM, form);
    439            return form.validate(parameters, resources.getValidatorActions(), page, fieldName);
    440        }
    441        return new ValidatorResults();
    442    }
    443
    444}