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