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: 1649191 $
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.
241     *
242     * <p>
243     * This in conjunction with the page property of
244     * a {@code Field} can control the processing of fields. If the field's
245     * page is less than or equal to this page value, it will be processed.
246     * </p>
247     *
248     * @return the page number.
249     */
250    public int getPage() {
251        return page;
252    }
253
254    /**
255     * Sets the page.
256     * <p>
257     * This in conjunction with the page property of
258     * a {@code Field} can control the processing of fields. If the field's page
259     * is less than or equal to this page value, it will be processed.
260     * </p>
261     *
262     * @param page the page number.
263     */
264    public void setPage(int page) {
265        this.page = page;
266    }
267
268    /**
269     * Clears the form name, resources that were added, and the page that was
270     * set (if any).  This can be called to reinitialize the Validator instance
271     * so it can be reused.  The form name (key to set of validation rules) and any
272     * resources needed, like the JavaBean being validated, will need to
273     * set and/or added to this instance again.  The
274     * <code>ValidatorResources</code> will not be removed since it can be used
275     * again and is thread safe.
276     */
277    public void clear() {
278        this.formName = null;
279        this.fieldName = null;
280        this.parameters = new HashMap();
281        this.page = 0;
282    }
283
284    /**
285     * Return the boolean as to whether the context classloader should be used.
286     * @return whether the context classloader should be used.
287     */
288    public boolean getUseContextClassLoader() {
289        return this.useContextClassLoader;
290    }
291
292    /**
293     * Determine whether to use the Context ClassLoader (the one found by
294     * calling <code>Thread.currentThread().getContextClassLoader()</code>)
295     * to resolve/load classes that are defined in various rules.  If not
296     * using Context ClassLoader, then the class-loading defaults to
297     * using the calling-class' ClassLoader.
298     *
299     * @param use determines whether to use Context ClassLoader.
300     */
301    public void setUseContextClassLoader(boolean use) {
302        this.useContextClassLoader = use;
303    }
304
305    /**
306     * Return the class loader to be used for instantiating application objects
307     * when required.  This is determined based upon the following rules:
308     * <ul>
309     * <li>The class loader set by <code>setClassLoader()</code>, if any</li>
310     * <li>The thread context class loader, if it exists and the
311     *     <code>useContextClassLoader</code> property is set to true</li>
312     * <li>The class loader used to load the Digester class itself.
313     * </ul>
314     * @return the class loader.
315     */
316    public ClassLoader getClassLoader() {
317        if (this.classLoader != null) {
318            return this.classLoader;
319        }
320
321        if (this.useContextClassLoader) {
322            ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
323            if (contextLoader != null) {
324                return contextLoader;
325            }
326        }
327
328        return this.getClass().getClassLoader();
329    }
330
331    /**
332     * Set the class loader to be used for instantiating application objects
333     * when required.
334     *
335     * @param classLoader The new class loader to use, or <code>null</code>
336     *  to revert to the standard rules
337     */
338    public void setClassLoader(ClassLoader classLoader) {
339        this.classLoader = classLoader;
340    }
341
342    /**
343     * Performs validations based on the configured resources.
344     *
345     * @return The <code>Map</code> returned uses the property of the
346     * <code>Field</code> for the key and the value is the number of error the
347     * field had.
348     * @throws ValidatorException If an error occurs during validation
349     */
350    public ValidatorResults validate() throws ValidatorException {
351        Locale locale = (Locale) this.getParameterValue(LOCALE_PARAM);
352
353        if (locale == null) {
354            locale = Locale.getDefault();
355        }
356
357        this.setParameter(VALIDATOR_PARAM, this);
358
359        Form form = this.resources.getForm(locale, this.formName);
360        if (form != null) {
361            this.setParameter(FORM_PARAM, form);
362            return form.validate(
363                this.parameters,
364                this.resources.getValidatorActions(),
365                this.page,
366                this.fieldName);
367        }
368
369        return new ValidatorResults();
370    }
371
372    /**
373     * Returns true if the Validator is only returning Fields that fail validation.
374     * @return whether only failed fields are returned.
375     */
376    public boolean getOnlyReturnErrors() {
377        return onlyReturnErrors;
378    }
379
380    /**
381     * Configures which Fields the Validator returns from the validate() method.  Set this
382     * to true to only return Fields that failed validation.  By default, validate() returns
383     * all fields.
384     * @param onlyReturnErrors whether only failed fields are returned.
385     */
386    public void setOnlyReturnErrors(boolean onlyReturnErrors) {
387        this.onlyReturnErrors = onlyReturnErrors;
388    }
389
390}