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}