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.</li>
236     * </ul>
237     *
238     * @return the class loader.
239     */
240    public ClassLoader getClassLoader() {
241        if (classLoader != null) {
242            return classLoader;
243        }
244
245        if (useContextClassLoader) {
246            final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
247            if (contextLoader != null) {
248                return contextLoader;
249            }
250        }
251
252        return this.getClass().getClassLoader();
253    }
254
255    /**
256     * Gets the field name.
257     *
258     * @return the field name.
259     * @since 1.10.0
260     */
261    public String getFieldName() {
262        return fieldName;
263    }
264
265    /**
266     * Gets the form name which is the key to a set of validation rules.
267     *
268     * @return the name of the form.
269     */
270    public String getFormName() {
271        return formName;
272    }
273
274    /**
275     * Returns true if the Validator is only returning Fields that fail validation.
276     *
277     * @return whether only failed fields are returned.
278     */
279    public boolean getOnlyReturnErrors() {
280        return onlyReturnErrors;
281    }
282
283    /**
284     * Gets the page.
285     *
286     * <p>
287     * This in conjunction with the page property of
288     * a {@code Field} can control the processing of fields. If the field's
289     * page is less than or equal to this page value, it will be processed.
290     * </p>
291     *
292     * @return the page number.
293     */
294    public int getPage() {
295        return page;
296    }
297
298    /**
299     * Gets the parameter map.
300     *
301     * @return the parameter map.
302     * @since 1.10.0
303     */
304    public Map<String, Object> getParameters() {
305        return parameters;
306    }
307
308    /**
309     * Returns the value of the specified parameter that will be used during the
310     * processing of validations.
311     *
312     * @param parameterClassName The full class name of the parameter of the
313     * validation method that corresponds to the value/instance passed in with it.
314     * @return value of the specified parameter.
315     */
316    public Object getParameterValue(final String parameterClassName) {
317        return parameters.get(parameterClassName);
318    }
319
320    /**
321     * Gets the validator resource.
322     *
323     * @return the validator resource.
324     * @since 1.10.0
325     */
326    public ValidatorResources getResources() {
327        return resources;
328    }
329
330    /**
331     * Gets the boolean as to whether the context classloader should be used.
332     *
333     * @return whether the context classloader should be used.
334     */
335    public boolean getUseContextClassLoader() {
336        return useContextClassLoader;
337    }
338
339    /**
340     * Sets the class loader to be used for instantiating application objects
341     * when required.
342     *
343     * @param classLoader The new class loader to use, or {@code null}
344     *  to revert to the standard rules
345     */
346    public void setClassLoader(final ClassLoader classLoader) {
347        this.classLoader = classLoader;
348    }
349
350    /**
351     * Sets the name of the field to validate in a form (optional)
352     *
353     * @param fieldName The name of the field in a form set
354     * @since 1.2.0
355     */
356    public void setFieldName(final String fieldName) {
357        this.fieldName = fieldName;
358    }
359
360    /**
361     * Sets the form name which is the key to a set of validation rules.
362     *
363     * @param formName the name of the form.
364     */
365    public void setFormName(final String formName) {
366        this.formName = formName;
367    }
368
369    /**
370     * Configures which Fields the Validator returns from the validate() method.  Set this
371     * to true to only return Fields that failed validation.  By default, validate() returns
372     * all fields.
373     *
374     * @param onlyReturnErrors whether only failed fields are returned.
375     */
376    public void setOnlyReturnErrors(final boolean onlyReturnErrors) {
377        this.onlyReturnErrors = onlyReturnErrors;
378    }
379
380    /**
381     * Sets the page.
382     * <p>
383     * This in conjunction with the page property of
384     * a {@code Field} can control the processing of fields. If the field's page
385     * is less than or equal to this page value, it will be processed.
386     * </p>
387     *
388     * @param page the page number.
389     */
390    public void setPage(final int page) {
391        this.page = page;
392    }
393
394    /**
395     * Sets a parameter of a pluggable validation method.
396     *
397     * @param parameterClassName The full class name of the parameter of the
398     * validation method that corresponds to the value/instance passed in with it.
399     *
400     * @param parameterValue The instance that will be passed into the
401     * validation method.
402     */
403    public void setParameter(final String parameterClassName, final Object parameterValue) {
404        parameters.put(parameterClassName, parameterValue);
405    }
406
407    /**
408     * Sets whether to use the Context ClassLoader (the one found by
409     * calling {@code Thread.currentThread().getContextClassLoader()})
410     * to resolve/load classes that are defined in various rules.  If not
411     * using Context ClassLoader, then the class-loading defaults to
412     * using the calling-class' ClassLoader.
413     *
414     * @param useContextClassLoader determines whether to use Context ClassLoader.
415     */
416    public void setUseContextClassLoader(final boolean useContextClassLoader) {
417        this.useContextClassLoader = useContextClassLoader;
418    }
419
420    /**
421     * Performs validations based on the configured resources.
422     *
423     * @return The {@link Map} returned uses the property of the
424     * {@code Field} for the key and the value is the number of error the
425     * field had.
426     * @throws ValidatorException If an error occurs during validation
427     */
428    public ValidatorResults validate() throws ValidatorException {
429        Locale locale = (Locale) getParameterValue(LOCALE_PARAM);
430
431        if (locale == null) {
432            locale = Locale.getDefault();
433        }
434
435        setParameter(VALIDATOR_PARAM, this);
436
437        final Form form = resources.getForm(locale, formName);
438        if (form != null) {
439            setParameter(FORM_PARAM, form);
440            return form.validate(
441                parameters,
442                resources.getValidatorActions(),
443                page,
444                fieldName);
445        }
446
447        return new ValidatorResults();
448    }
449
450}