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}