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