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