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