KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > acting > AbstractValidatorAction


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.acting;
17
18 import org.apache.avalon.framework.configuration.Configurable;
19 import org.apache.avalon.framework.configuration.Configuration;
20 import org.apache.avalon.framework.configuration.ConfigurationException;
21 import org.apache.avalon.framework.parameters.Parameters;
22
23 import org.apache.cocoon.Constants;
24 import org.apache.cocoon.ProcessingException;
25 import org.apache.cocoon.environment.SourceResolver;
26 import org.apache.cocoon.environment.ObjectModelHelper;
27 import org.apache.cocoon.environment.Redirector;
28 import org.apache.cocoon.sitemap.SitemapParameters;
29 import org.apache.commons.lang.BooleanUtils;
30 import org.apache.commons.lang.StringUtils;
31
32 import org.apache.regexp.RE;
33 import org.apache.regexp.RESyntaxException;
34
35 import java.util.Collection JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.HashSet JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.Set JavaDoc;
41 import java.util.Vector JavaDoc;
42
43 /**
44  * Abstract implementation of action that needs to perform validation of
45  * parameters (from session, from request, etc.). All `validator' actions
46  * share the same description xml file. In such file every parameter is
47  * described via its name, type and its constraints. One large description
48  * file can be used among all validator actions, because each action should
49  * explicitely specify which parameters to validate - through a sitemap
50  * parameter.
51  *
52  * <h3>Variant 1</h3>
53  * <pre>
54  * &lt;map:act type="validator"&gt;
55  * &lt;parameter name="descriptor" value="context://descriptor.xml"&gt;
56  * &lt;parameter name="validate" value="username,password"&gt;
57  * &lt;/map:act&gt;
58  * </pre>
59  *
60  * <p>The list of parameters to be validated is specified as a comma
61  * separated list of their names. descriptor.xml can therefore be used
62  * among many various actions. If the list contains only of <code>*</code>,
63  * all parameters in the file will be validated.</p>
64  *
65  * <h3>Variant 2</h3>
66  * <pre>
67  * &lt;map:act type="validator"&gt;
68  * &lt;parameter name="descriptor" value="context://descriptor.xml"&gt;
69  * &lt;parameter name="constraint-set" value="is-logged-in"&gt;
70  * &lt;/map:act&gt;
71  * </pre>
72  *
73  * <p>The parameter "constraint-set" tells to take a given
74  * "constraint-set" from description file and test all parameters
75  * against given criteria. This variant is more powerful, more aspect
76  * oriented and more flexibile than the previous one, because it
77  * allows comparsion constructs, etc. See AbstractValidatorAction
78  * documentation.</p>
79  *
80  * <p>For even more powerful validation, constraints can be grouped
81  * and used independently of the parameter name. If a validate element
82  * has a <code>rule</code> attribute, it uses the parameter with that
83  * name as a rule template and validates the parameter from the
84  * <code>name</code> attribute with that rule.</p>
85  *
86  * <p>This action returns null when validation fails, otherwise it
87  * provides all validated parameters to the sitemap via {name}
88  * expression.</p>
89  *
90  * <p>In addition a request attribute
91  * <code>org.apache.cocoon.acting.FormValidatorAction.results</code>
92  * contains the validation results in both cases and make it available
93  * to XSPs. The special parameter "*" contains either the validation
94  * result "OK", if all parameters were validated successfully, or
95  * "ERROR" otherwise. Mind you that redirections create new request
96  * objects and thus the result is not available for the target
97  * page.</p>
98  *
99  * <pre>
100  * &lt;root&gt;
101  * &lt;parameter name="username" type="string" nullable="no"/&gt;
102  * &lt;parameter name="role" type="string" nullable="no"/&gt;
103  * &lt;parameter name="oldpassword" type="string" nullable="no"/&gt;
104  * &lt;parameter name="newpassword" type="string" nullable="no"/&gt;
105  * &lt;parameter name="renewpassword" type="string" nullable="no"/&gt;
106  * &lt;parameter name="id" type="long" nullable="no"/&gt;
107  * &lt;parameter name="sallary" type="double" nullable="no"/&gt;
108  * &lt;parameter name="theme" type="string" nullable="yes" default="dflt"/&gt;
109  * &lt;constraint-set name="is-logged-in"&gt;
110  * &lt;validate name="username"/&gt;
111  * &lt;validate name="role"/&gt;
112  * &lt;/constraint-set&gt;
113  *
114  * &lt;constraint-set name="is-in-admin-role"&gt;
115  * &lt;validate name="username"/&gt;
116  * &lt;validate name="role" equals-to="admin"/&gt;
117  * &lt;/constraint-set&gt;
118  *
119  * &lt;constraint-set name="new-passwords-match"&gt;
120  * &lt;validate name="oldpassword"/&gt;
121  * &lt;validate name="newpassword"/&gt;
122  * &lt;validate name="renewpassword"
123  * equals-to-param="newpass"/&gt;
124  * &lt;/constraint-set&gt;
125  *
126  * &lt;constraint-set name="all"&gt;
127  * &lt;include name="is-logged-in"/&gt;
128  * &lt;include name="is-in-admin-role"/&gt;
129  * &lt;include name="new-passwords-match"/&gt;
130  * &lt;/constraint-set&gt;
131  * &lt;/root&gt;
132  * </pre>
133  *
134  * <h3>The types recognized by validator and their attributes</h3>
135  * <table border="1">
136  * <tr>
137  * <td><b>string</b></td><td>nullable="yes|no" default="str"</td>
138  * </tr>
139  * <tr>
140  * <td><b>long</b></td><td>nullable="yes|no" default="123123"</td>
141  * </tr>
142  * <tr>
143  * <td><b>double</b></td><td>nullable="yes|no" default="0.5"</td>
144  * </tr>
145  * </table>
146  *
147  * <p>Default value takes place only when specified parameter is
148  * nullable and really is null or empty. Long numbers may be specified
149  * in decimal, hex or octal values as accepted by java.Lang.decode
150  * (String s).</p>
151  *
152  * <h3>Constraints</h3>
153  * <table border="1">
154  * <tr>
155  * <td>matches-regex</td><td>POSIX regular expression</td>
156  * </tr>
157  * <tr>
158  * <td>min-len</td><td>positive integer</td>
159  * </tr>
160  * <tr>
161  * <td>max-len</td><td>positive integer</td>
162  * </tr>
163  * <tr>
164  * <td>min</td><td>Double / Long</td>
165  * </tr>
166  * <tr>
167  * <td>max</td><td>Double / Long</td>
168  * </tr>
169  * </table>
170  *
171  * <p>Constraints can be defined globally for a parameter and can be
172  * overridden by redefinition in a constraint-set. Thus if e.g. a
173  * database field can take at maximum 200 character, this property can
174  * be set globally.</p>
175  *
176  * <p>Values in parameter arrays are validated individually and the
177  * worst error is reported back.</p>
178  *
179  * <h3>The attributes recognized in "constraint-set"</h3>
180  * <table>
181  * <tr>
182  * <td>equals-to-param</td><td>parameter name</td>
183  * </tr>
184  * <tr>
185  * <td>equals-to</td><td>string constant</td>
186  * </tr>
187  * </table>
188  * @author <a HREF="mailto:Martin.Man@seznam.cz">Martin Man</a>
189  * @author <a HREF="mailto:haul@apache.org">Christian Haul</a>
190  * @version CVS $Id: AbstractValidatorAction.java 105794 2004-11-19 07:41:03Z antonio $
191  */

192 public abstract class AbstractValidatorAction
193     extends AbstractComplementaryConfigurableAction
194     implements Configurable {
195
196     /**
197      * Reads parameter values for all parameters that are contained in the active
198      * constraint list. If a parameter has multiple values, all are stored in the
199      * resulting map.
200      *
201      * @param objectModel the object model
202      * @param set a collection of parameter names
203      * @return HashMap
204      */

205     abstract protected HashMap JavaDoc createMapOfParameters(Map JavaDoc objectModel, Collection JavaDoc set);
206
207     /**
208      * Are parameters encoded as strings?
209      * @return boolean
210      */

211     abstract boolean isStringEncoded();
212
213     /*
214      * main method
215      */

216     public Map JavaDoc act(Redirector redirector,
217                    SourceResolver resolver,
218                    Map JavaDoc objectModel,
219                    String JavaDoc src,
220                    Parameters parameters) throws Exception JavaDoc {
221
222         Configuration conf = this.getDescriptor(resolver, objectModel, parameters);
223         if (conf == null)
224             return null;
225
226         String JavaDoc valStr =
227             parameters.getParameter("validate", (String JavaDoc)settings.get("validate", "")).trim();
228         String JavaDoc valSetStr =
229             parameters.getParameter("validate-set", (String JavaDoc)settings.get("validate-set", "")).trim();
230         String JavaDoc constraintSetStr =
231             parameters.getParameter("constraint-set", (String JavaDoc)settings.get("constraint-set", "")).trim();
232         if (!"".equals(valSetStr)) {
233             if (getLogger().isInfoEnabled()) {
234                 getLogger().info("Using sitemap parameter 'validate-set' for specifying "
235                                  + "the constraint-set for the ValidatorActions is deprecated in "
236                                  + "favor of 'constraint-set' due to consistency in the naming.");
237             }
238             if ("".equals(constraintSetStr)) {
239                 constraintSetStr = valSetStr;
240             }
241         }
242         Map JavaDoc desc = this.indexConfiguration(conf.getChildren("parameter"));
243
244         Map JavaDoc actionMap = new HashMap JavaDoc();
245         Map JavaDoc resultMap = new HashMap JavaDoc();
246         Collection JavaDoc params = null;
247         boolean allOK = false;
248
249         if (!"".equals(valStr)) {
250             if (getLogger().isDebugEnabled()) {
251                 getLogger().debug("Validating parameters as specified via 'validate' parameter");
252             }
253             params = this.getSetOfParameterNamesFromSitemap(valStr, desc);
254         } else if (!"".equals(constraintSetStr)) {
255             if (getLogger().isDebugEnabled()) {
256                 getLogger().debug("Validating parameters from given constraint-set " + constraintSetStr);
257             }
258             Map JavaDoc csets = this.indexConfiguration(conf.getChildren("constraint-set"));
259             params = this.resolveConstraints(constraintSetStr, csets);
260         }
261         
262         if (params == null) {
263             throw new ProcessingException("Neither a constraint-set nor parameters in the sitemap "
264                                           + "were specified for validating at "
265                                           + SitemapParameters.getStatementLocation(parameters));
266         }
267         HashMap JavaDoc values = this.createMapOfParameters(objectModel, params);
268         allOK = this.validateSetOfParameters(desc, actionMap, resultMap, params, values, this.isStringEncoded());
269
270         return this.setResult(objectModel, actionMap, resultMap, allOK);
271     }
272
273     /**
274      * Try to validate given parameter.
275      * @param name The name of the parameter to validate.
276      * @param constraints Configuration of all constraints for this
277      * parameter as taken from the description XML file.
278      * @param conf Configuration of all parameters as taken from the
279      * description XML file.
280      * @param params The map of parameters.
281      * @param isString Indicates wheter given param to validate is
282      * string (as taken from HTTP request for example) or wheteher it
283      * should be regular instance of java.lang.Double, java.lang.Long,
284      * etc.
285      * @return The validated parameter.
286      */

287     public ValidatorActionHelper validateParameter(
288         String JavaDoc name,
289         Configuration constraints,
290         Map JavaDoc conf,
291         Map JavaDoc params,
292         boolean isString) {
293
294         return validateParameter(name, name, constraints, conf, params, isString);
295     }
296
297     /**
298      * Try to validate given parameter.
299      * @param name The actual name of the parameter to validate.
300      * @param rule The name of the parameter element that contains the
301      * rule that should be used for validation.
302      * @param constraints Configuration of all constraints for this
303      * parameter as taken from the description XML file.
304      * @param conf Configuration of all parameters as taken from the
305      * description XML file.
306      * @param params The map of parameters.
307      * @param isString Indicates wheter given param to validate is
308      * string (as taken from HTTP request for example) or wheteher it
309      * should be regular instance of java.lang.Double, java.lang.Long,
310      * etc.
311      * @return The validated parameter.
312      */

313     public ValidatorActionHelper validateParameter(
314         String JavaDoc name,
315         String JavaDoc rule,
316         Configuration constraints,
317         Map JavaDoc conf,
318         Map JavaDoc params,
319         boolean isString) {
320         String JavaDoc type = null;
321
322         if (getLogger().isDebugEnabled())
323             getLogger().debug("Validating parameter: " + name + " using rule: " + rule);
324
325         /* try to find matching param description in conf tree */
326         try {
327             Configuration theConf = (Configuration) conf.get(rule);
328             type = theConf.getAttribute("type");
329
330             return validateValue(name, constraints, theConf, params, isString, type);
331
332         } catch (Exception JavaDoc e) {
333             if (getLogger().isDebugEnabled())
334                 getLogger().debug("No type specified for parameter " + name);
335             return null;
336         }
337     }
338
339     /**
340      * Validate a single parameter value.
341      *
342      * @param name String holding the name of the parameter
343      * @param constraints Configuration holding the constraint set configuration for the parameter
344      * @param conf Configuration holding the parameter configuration
345      * @param params Map of parameter values to be validated
346      * @param isString boolean indicating if the value is string encoded
347      * @param type string holding the name of the datatype to validate value
348      * @return ValidatorActionHelper
349      */

350     protected ValidatorActionHelper validateValue(
351         String JavaDoc name,
352         Configuration constraints,
353         Configuration conf,
354         Map JavaDoc params,
355         boolean isString,
356         String JavaDoc type) {
357         Object JavaDoc value = params.get(name);
358
359         if (value != null && value.getClass().isArray()) {
360             Object JavaDoc[] values = (Object JavaDoc[]) value;
361             ValidatorActionHelper vaH = null;
362             ValidatorActionResult vaR = ValidatorActionResult.OK;
363             for (int j = 0; j < values.length; j++) {
364                 value = values[j];
365                 if ("string".equals(type)) {
366                     vaH = validateString(name, constraints, conf, params, value);
367                 } else if ("long".equals(type)) {
368                     vaH = validateLong(name, constraints, conf, params, isString, value);
369                 } else if ("double".equals(type)) {
370                     vaH = validateDouble(name, constraints, conf, params, isString, value);
371                 } else {
372                     if (getLogger().isDebugEnabled())
373                         getLogger().debug(
374                             "Unknown type " + type + " specified for parameter " + name);
375                     return null;
376                 }
377                 vaR = (vaR.getPos() < vaH.getResult().getPos() ? vaH.getResult() : vaR);
378             }
379             return new ValidatorActionHelper(vaH.getObject(), vaR);
380         } else {
381             if ("string".equals(type)) {
382                 return validateString(name, constraints, conf, params, value);
383             } else if ("long".equals(type)) {
384                 return validateLong(name, constraints, conf, params, isString, value);
385             } else if ("double".equals(type)) {
386                 return validateDouble(name, constraints, conf, params, isString, value);
387             } else {
388                 if (getLogger().isDebugEnabled())
389                     getLogger().debug("Unknown type " + type + " specified for parameter " + name);
390             }
391             return null;
392         }
393     }
394
395     /**
396      * Validates nullability and default value for given parameter. If given
397      * constraints are not null they are validated as well.
398      */

399     private ValidatorActionHelper validateString(
400         String JavaDoc name,
401         Configuration constraints,
402         Configuration conf,
403         Map JavaDoc params,
404         Object JavaDoc param) {
405
406         String JavaDoc value = null;
407         String JavaDoc dflt = getDefault(conf, constraints);
408         boolean nullable = getNullable(conf, constraints);
409
410         if (getLogger().isDebugEnabled())
411             getLogger().debug("Validating string parameter " + name);
412         try {
413             value = getStringValue(param);
414         } catch (Exception JavaDoc e) {
415             // ClassCastException
416
return new ValidatorActionHelper(value, ValidatorActionResult.ERROR);
417         }
418         if (value == null) {
419             if (getLogger().isDebugEnabled())
420                 getLogger().debug("String parameter " + name + " is null");
421             if (!nullable) {
422                 return new ValidatorActionHelper(value, ValidatorActionResult.ISNULL);
423             } else {
424                 return new ValidatorActionHelper(dflt);
425             }
426         }
427         if (constraints != null) {
428             String JavaDoc eq = constraints.getAttribute("equals-to", "");
429             eq = conf.getAttribute("equals-to", eq);
430
431             String JavaDoc eqp = constraints.getAttribute("equals-to-param", "");
432             eqp = conf.getAttribute("equals-to-param", eqp);
433
434             String JavaDoc regex = conf.getAttribute("matches-regex", "");
435             regex = constraints.getAttribute("matches-regex", regex);
436
437             String JavaDoc oneOf = conf.getAttribute("one-of", "");
438             oneOf = constraints.getAttribute("one-of", oneOf);
439
440             Long JavaDoc minlen = getAttributeAsLong(conf, "min-len", null);
441             minlen = getAttributeAsLong(constraints, "min-len", minlen);
442
443             Long JavaDoc maxlen = getAttributeAsLong(conf, "max-len", null);
444             maxlen = getAttributeAsLong(constraints, "max-len", maxlen);
445
446             // Validate whether param is equal to constant
447
if (!"".equals(eq)) {
448                 if (getLogger().isDebugEnabled())
449                     getLogger().debug("String parameter " + name + " should be equal to " + eq);
450                 if (!value.equals(eq)) {
451                     if (getLogger().isDebugEnabled())
452                         getLogger().debug("and it is not");
453                     return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
454                 }
455             }
456
457             // Validate whether param is equal to another param
458
// FIXME: take default value of param being compared with into
459
// account?
460
if (!"".equals(eqp)) {
461                 if (getLogger().isDebugEnabled())
462                     getLogger().debug(
463                         "String parameter " + name + " should be equal to " + params.get(eqp));
464                 if (!value.equals(params.get(eqp))) {
465                     if (getLogger().isDebugEnabled())
466                         getLogger().debug("and it is not");
467                     return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
468                 }
469             }
470
471             // Validate whether param length is at least of minimum length
472
if (minlen != null) {
473                 if (getLogger().isDebugEnabled())
474                     getLogger().debug(
475                         "String parameter "
476                             + name
477                             + " should be at least "
478                             + minlen
479                             + " characters long");
480                 if (value.length() < minlen.longValue()) {
481                     if (getLogger().isDebugEnabled())
482                         getLogger().debug("and it is shorter (" + value.length() + ")");
483                     return new ValidatorActionHelper(value, ValidatorActionResult.TOOSMALL);
484                 }
485             }
486
487             // Validate whether param length is at most of maximum length
488
if (maxlen != null) {
489                 if (getLogger().isDebugEnabled())
490                     getLogger().debug(
491                         "String parameter "
492                             + name
493                             + " should be at most "
494                             + maxlen
495                             + " characters long");
496
497                 if (value.length() > maxlen.longValue()) {
498                     if (getLogger().isDebugEnabled())
499                         getLogger().debug("and it is longer (" + value.length() + ")");
500                     return new ValidatorActionHelper(value, ValidatorActionResult.TOOLARGE);
501                 }
502             }
503
504             // Validate wheter param matches regular expression
505
if (!"".equals(regex)) {
506                 if (getLogger().isDebugEnabled())
507                     getLogger().debug(
508                         "String parameter " + name + " should match regexp \"" + regex + "\"");
509                 try {
510                     RE r = new RE(regex);
511                     if (!r.match(value)) {
512                         if (getLogger().isDebugEnabled())
513                             getLogger().debug("and it does not match");
514                         return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
515                     }
516                 } catch (RESyntaxException rese) {
517                     if (getLogger().isDebugEnabled())
518                         getLogger().error("String parameter " + name + " regex error ", rese);
519                     return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
520                 }
521             }
522
523             // Validates against a set of possibilities
524
if (!"".equals(oneOf)) {
525                 if (getLogger().isDebugEnabled())
526                     getLogger().debug(
527                         "String parameter " + name + " should be one of \"" + oneOf + "\"");
528                 if (!oneOf.startsWith("|"))
529                     oneOf = "|" + oneOf;
530                 if (!oneOf.endsWith("|"))
531                     oneOf = oneOf + "|";
532                 if (value.indexOf("|") != -1) {
533                     if (getLogger().isDebugEnabled())
534                         getLogger().debug(
535                             "String parameter " + name + "contains \"|\" - can't validate that.");
536                     return new ValidatorActionHelper(value, ValidatorActionResult.ERROR);
537                 }
538                 if (oneOf.indexOf("|" + value + "|") == -1) {
539                     if (getLogger().isDebugEnabled())
540                         getLogger().debug("and it is not");
541                     return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
542                 }
543                 return new ValidatorActionHelper(value, ValidatorActionResult.OK);
544
545             }
546
547         }
548         return new ValidatorActionHelper(value);
549     }
550
551     /**
552      * Validates nullability and default value for given parameter. If given
553      * constraints are not null they are validated as well.
554      */

555     private ValidatorActionHelper validateLong(
556         String JavaDoc name,
557         Configuration constraints,
558         Configuration conf,
559         Map JavaDoc params,
560         boolean is_string,
561         Object JavaDoc param) {
562
563         boolean nullable = getNullable(conf, constraints);
564         Long JavaDoc value = null;
565         Long JavaDoc dflt = getLongValue(getDefault(conf, constraints), true);
566
567         if (getLogger().isDebugEnabled())
568             getLogger().debug(
569                 "Validating long parameter " + name + " (encoded in a string: " + is_string + ")");
570         try {
571             value = getLongValue(param, is_string);
572         } catch (Exception JavaDoc e) {
573             // Unable to parse long
574
return new ValidatorActionHelper(value, ValidatorActionResult.ERROR);
575         }
576         if (value == null) {
577             if (getLogger().isDebugEnabled())
578                 getLogger().debug("Long parameter " + name + " is null");
579             if (!nullable) {
580                 return new ValidatorActionHelper(value, ValidatorActionResult.ISNULL);
581             } else {
582                 return new ValidatorActionHelper(dflt);
583             }
584         }
585         if (constraints != null) {
586             Long JavaDoc eq = getAttributeAsLong(constraints, "equals-to", null);
587             String JavaDoc eqp = constraints.getAttribute("equals-to-param", "");
588
589             Long JavaDoc min = getAttributeAsLong(conf, "min", null);
590             min = getAttributeAsLong(constraints, "min", min);
591
592             Long JavaDoc max = getAttributeAsLong(conf, "max", null);
593             max = getAttributeAsLong(constraints, "max", max);
594
595             // Validate whether param is equal to constant
596
if (eq != null) {
597                 if (getLogger().isDebugEnabled())
598                     getLogger().debug("Long parameter " + name + " should be equal to " + eq);
599
600                 if (!value.equals(eq)) {
601                     if (getLogger().isDebugEnabled())
602                         getLogger().debug("and it is not");
603                     return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
604                 }
605             }
606
607             // Validate whether param is equal to another param
608
// FIXME: take default value of param being compared with into
609
// account?
610
if (!"".equals(eqp)) {
611                 if (getLogger().isDebugEnabled())
612                     getLogger().debug(
613                         "Long parameter " + name + " should be equal to " + params.get(eqp));
614                 // Request parameter is stored as string.
615
// Need to convert it beforehand.
616
try {
617                     Long JavaDoc _eqp = new Long JavaDoc(Long.parseLong((String JavaDoc) params.get(eqp)));
618                     if (!value.equals(_eqp)) {
619                         if (getLogger().isDebugEnabled())
620                             getLogger().debug("and it is not");
621                         return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
622                     }
623                 } catch (NumberFormatException JavaDoc nfe) {
624                     if (getLogger().isDebugEnabled())
625                         getLogger().debug(
626                             "Long parameter " + name + ": " + eqp + " is no long",
627                             nfe);
628                     return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
629                 }
630             }
631
632             // Validate wheter param is at least min
633
if (min != null) {
634                 if (getLogger().isDebugEnabled())
635                     getLogger().debug("Long parameter " + name + " should be at least " + min);
636
637                 if (min.compareTo(value) > 0) {
638                     if (getLogger().isDebugEnabled())
639                         getLogger().debug("and it is not");
640                     return new ValidatorActionHelper(value, ValidatorActionResult.TOOSMALL);
641                 }
642             }
643
644             // Validate wheter param is at most max
645
if (max != null) {
646                 if (getLogger().isDebugEnabled())
647                     getLogger().debug("Long parameter " + name + " should be at most " + max);
648                 if (max.compareTo(value) < 0) {
649                     if (getLogger().isDebugEnabled())
650                         getLogger().debug("and it is not");
651                     return new ValidatorActionHelper(value, ValidatorActionResult.TOOLARGE);
652                 }
653             }
654         }
655         return new ValidatorActionHelper(value);
656     }
657
658     /**
659      * Validates nullability and default value for given parameter. If given
660      * constraints are not null they are validated as well.
661      */

662     private ValidatorActionHelper validateDouble(
663         String JavaDoc name,
664         Configuration constraints,
665         Configuration conf,
666         Map JavaDoc params,
667         boolean is_string,
668         Object JavaDoc param) {
669
670         boolean nullable = getNullable(conf, constraints);
671         Double JavaDoc value = null;
672         Double JavaDoc dflt = getDoubleValue(getDefault(conf, constraints), true);
673
674         if (getLogger().isDebugEnabled())
675             getLogger().debug(
676                 "Validating double parameter "
677                     + name
678                     + " (encoded in a string: "
679                     + is_string
680                     + ")");
681         try {
682             value = getDoubleValue(param, is_string);
683         } catch (Exception JavaDoc e) {
684             // Unable to parse double
685
return new ValidatorActionHelper(value, ValidatorActionResult.ERROR);
686         }
687         if (value == null) {
688             if (getLogger().isDebugEnabled())
689                 getLogger().debug("double parameter " + name + " is null");
690             if (!nullable) {
691                 return new ValidatorActionHelper(value, ValidatorActionResult.ISNULL);
692             } else {
693                 return new ValidatorActionHelper(dflt);
694             }
695         }
696         if (constraints != null) {
697             Double JavaDoc eq = getAttributeAsDouble(constraints, "equals-to", null);
698             String JavaDoc eqp = constraints.getAttribute("equals-to-param", "");
699
700             Double JavaDoc min = getAttributeAsDouble(conf, "min", null);
701             min = getAttributeAsDouble(constraints, "min", min);
702
703             Double JavaDoc max = getAttributeAsDouble(conf, "max", null);
704             max = getAttributeAsDouble(constraints, "max", max);
705
706             // Validate whether param is equal to constant
707
if (eq != null) {
708                 if (getLogger().isDebugEnabled())
709                     getLogger().debug("Double parameter " + name + " should be equal to " + eq);
710
711                 if (!value.equals(eq)) {
712                     if (getLogger().isDebugEnabled())
713                         getLogger().debug("and it is not");
714                     return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
715                 }
716             }
717
718             // Validate whether param is equal to another param
719
// FIXME: take default value of param being compared with into
720
// account?
721
if (!"".equals(eqp)) {
722                 if (getLogger().isDebugEnabled())
723                     getLogger().debug(
724                         "Double parameter " + name + " should be equal to " + params.get(eqp));
725                 // Request parameter is stored as string.
726
// Need to convert it beforehand.
727
try {
728                     Double JavaDoc _eqp = new Double JavaDoc(Double.parseDouble((String JavaDoc) params.get(eqp)));
729                     if (!value.equals(_eqp)) {
730                         if (getLogger().isDebugEnabled())
731                             getLogger().debug("and it is not");
732                         return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
733                     }
734                 } catch (NumberFormatException JavaDoc nfe) {
735                     if (getLogger().isDebugEnabled())
736                         getLogger().debug(
737                             "Double parameter " + name + ": " + eqp + " is no double",
738                             nfe);
739                     return new ValidatorActionHelper(value, ValidatorActionResult.NOMATCH);
740                 }
741             }
742
743             // Validate wheter param is at least min
744
if (min != null) {
745                 if (getLogger().isDebugEnabled())
746                     getLogger().debug("Double parameter " + name + " should be at least " + min);
747                 if (0 > value.compareTo(min)) {
748                     if (getLogger().isDebugEnabled())
749                         getLogger().debug("and it is not");
750                     return new ValidatorActionHelper(value, ValidatorActionResult.TOOSMALL);
751                 }
752             }
753
754             // Validate wheter param is at most max
755
if (max != null) {
756                 if (getLogger().isDebugEnabled())
757                     getLogger().debug("Double parameter " + name + " should be at most " + max);
758                 if (0 < value.compareTo(max)) {
759                     if (getLogger().isDebugEnabled())
760                         getLogger().debug("and it is not");
761                     return new ValidatorActionHelper(value, ValidatorActionResult.TOOLARGE);
762                 }
763             }
764         }
765         return new ValidatorActionHelper(value);
766     }
767
768     /**
769      * Returns the parsed Double value.
770      */

771     private Double JavaDoc getDoubleValue(Object JavaDoc param, boolean is_string)
772         throws ClassCastException JavaDoc, NumberFormatException JavaDoc {
773
774         /* convert param to double */
775         if (is_string) {
776             String JavaDoc tmp = getStringValue(param);
777             if (tmp == null) {
778                 return null;
779             }
780             return new Double JavaDoc(tmp);
781         } else {
782             return (Double JavaDoc) param;
783         }
784     }
785
786     /**
787      * Returns the parsed Long value.
788      */

789     private Long JavaDoc getLongValue(Object JavaDoc param, boolean is_string)
790         throws ClassCastException JavaDoc, NumberFormatException JavaDoc {
791
792         /* convert param to long */
793         if (is_string) {
794             String JavaDoc tmp = getStringValue(param);
795             if (tmp == null) {
796                 return null;
797             }
798             return Long.decode(tmp);
799         } else {
800             return (Long JavaDoc) param;
801         }
802     }
803
804     /**
805      * Returns string
806      * @throws ClassCastException if param is not a String object
807      */

808     private String JavaDoc getStringValue(Object JavaDoc param) throws ClassCastException JavaDoc {
809
810         /* convert param to string */
811         String JavaDoc value = (String JavaDoc) param;
812         if (value != null && "".equals(value.trim())) {
813             value = null;
814         }
815         return value;
816     }
817
818     /**
819      * Returns the value of 'nullable' attribute from given configuration or
820      * from given constraints, value present in constraints takes precedence,
821      * false when attribute is not present in either of them.
822      */

823     private boolean getNullable(Configuration conf, Configuration cons) {
824         /* check nullability */
825         try {
826             String JavaDoc tmp = cons.getAttribute("nullable");
827             return BooleanUtils.toBoolean(tmp);
828         } catch (Exception JavaDoc e) {
829             String JavaDoc tmp = "no";
830             if (conf != null) {
831                 tmp = conf.getAttribute("nullable", "no");
832             }
833             return BooleanUtils.toBoolean(tmp);
834         }
835     }
836
837     /**
838      * Returns the default value from given configuration or constraints.
839      * Value present in constraints takes precedence, null is returned when no
840      * default attribute is present in eiher of them.
841      */

842     private String JavaDoc getDefault(Configuration conf, Configuration cons) {
843         String JavaDoc dflt = "";
844         try {
845             dflt = cons.getAttribute("default");
846         } catch (Exception JavaDoc e) {
847             if (conf != null)
848                 dflt = conf.getAttribute("default", "");
849         }
850         if ("".equals(dflt.trim())) {
851             dflt = null;
852         }
853         return dflt;
854     }
855
856     /**
857      * Replacement for Avalon's Configuration.getAttributeAsLong
858      * because that one doesn't take <code>Long</code> but long and
859      * thus won't take <code>null</code> as parameter value for
860      * default.
861      *
862      * @param conf Configuration
863      * @param name Parameter's name
864      * @param dflt Default value
865      * @return Parameter's value in <code>configuration</code> or
866      * <code>dflt</code> if parameter is not set or couldn't be
867      * converted to a <code>Long</code>
868      * @throws NumberFormatException if conversion fails
869      */

870     private Long JavaDoc getAttributeAsLong(Configuration conf, String JavaDoc name, Long JavaDoc dflt)
871         throws NumberFormatException JavaDoc {
872         try {
873             return new Long JavaDoc(conf.getAttribute(name));
874         } catch (ConfigurationException e) {
875             return dflt;
876         }
877     }
878
879     /**
880      * Addition to Avalon's Configuration.getAttributeAsFloat
881      * because that one does only deal with <code>float</code>.
882      *
883      * @param conf Configuration
884      * @param name Parameter's name
885      * @param dflt Default value
886      * @return Parameter's value in <code>configuration</code> or
887      * <code>dflt</code> if parameter is not set or couldn't be
888      * converted to a <code>Double</code>
889      * @throws NumberFormatException if conversion fails
890      */

891     private Double JavaDoc getAttributeAsDouble(Configuration conf, String JavaDoc name, Double JavaDoc dflt)
892         throws NumberFormatException JavaDoc {
893         try {
894             return new Double JavaDoc(conf.getAttribute(name));
895         } catch (ConfigurationException e) {
896             return dflt;
897         }
898     }
899
900     /**
901      * Create an index map to an array of configurations by their name
902      * attribute. An empty array results in an empty map.
903      *
904      * @param descriptor
905      * @return index map or empty map
906      */

907     protected Map JavaDoc indexConfiguration(Configuration[] descriptor) {
908         if (descriptor == null)
909             return new HashMap JavaDoc();
910         Map JavaDoc result = new HashMap JavaDoc((descriptor.length > 0) ? descriptor.length * 2 : 5);
911         for (int i = descriptor.length - 1; i >= 0; i--) {
912             String JavaDoc name = descriptor[i].getAttribute("name", "");
913             result.put(name, descriptor[i]);
914         }
915         return result;
916     }
917
918     /**
919      * Recursively resolve constraint sets that may "include" other constraint
920      * sets and return a collection of all parameters to validate.
921      *
922      * @param valsetstr
923      * @param consets
924      * @return collection of all parameters to validate
925      */

926     protected Collection JavaDoc resolveConstraints(String JavaDoc valsetstr, Map JavaDoc consets) {
927         /* get the list of params to be validated */
928         Vector JavaDoc rules = new Vector JavaDoc();
929         Configuration[] set = ((Configuration) consets.get(valsetstr)).getChildren("validate");
930         for (int j = 0; j < set.length; j++) {
931             rules.add(set[j]);
932         }
933         set = ((Configuration) consets.get(valsetstr)).getChildren("include");
934         for (int j = 0; j < set.length; j++) {
935             Collection JavaDoc tmp = resolveConstraints(set[j].getAttribute("name", ""), consets);
936             rules.addAll(tmp);
937         }
938         return rules;
939     }
940
941     /**
942      * Checks the default setting for reloading the descriptor file.
943      * @return boolean
944      */

945     protected boolean isDescriptorReloadable() {
946         // read global parameter settings
947
boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
948         if (this.settings.containsKey("reloadable")) {
949             reloadable = Boolean.valueOf((String JavaDoc) this.settings.get("reloadable")).booleanValue();
950         }
951         return reloadable;
952     }
953
954     /**
955      * Get list of params to be validated from sitemap parameter and
956      * isolates the parameter names from the comma separated list.
957      *
958      */

959     protected Collection JavaDoc getSetOfParameterNamesFromSitemap(String JavaDoc valstr, Map JavaDoc desc) {
960         String JavaDoc[] rparams = null;
961         Set JavaDoc set = new HashSet JavaDoc(20);
962         if (!"*".equals(valstr.trim())) {
963             rparams = StringUtils.split(valstr, ",");
964             if (rparams != null) {
965                 for (int i = rparams.length - 1; i >= 0; i--) {
966                     set.add(desc.get(rparams[i]));
967                 }
968             }
969         } else {
970             // validate _all_ parameters
971
set = desc.entrySet();
972         }
973         return set;
974     }
975
976     /**
977      * Validate all parameters in the set with the constraints contained in
978      * desc and the values from params. Validation details are in resultMap and
979      * successful validated parameters in resultMap.
980      *
981      * @param desc
982      * @param actionMap
983      * @param resultMap
984      * @param set
985      * @param params
986      * @param isString
987      * @return boolean all parameters ok or not
988      */

989     protected boolean validateSetOfParameters(
990         Map JavaDoc desc,
991         Map JavaDoc actionMap,
992         Map JavaDoc resultMap,
993         Collection JavaDoc set,
994         Map JavaDoc params,
995         boolean isString) {
996
997         boolean allOK = true;
998         ValidatorActionHelper result;
999         String JavaDoc name;
1000        String JavaDoc rule = null;
1001        for (Iterator JavaDoc i = set.iterator(); i.hasNext();) {
1002            Configuration constr = (Configuration) i.next();
1003            name = constr.getAttribute("name", null);
1004            rule = constr.getAttribute("rule", name);
1005            result = validateParameter(name, rule, constr, desc, params, isString);
1006            if (!result.isOK()) {
1007                if (getLogger().isDebugEnabled())
1008                    getLogger().debug("Validation failed for parameter " + name);
1009                allOK = false;
1010            }
1011            actionMap.put(name, result.getObject());
1012            resultMap.put(name, result.getResult());
1013        }
1014        return allOK;
1015    }
1016
1017    /**
1018     * Add success indicator to resulting maps and clear actionMap if unsuccessful.
1019     * Results are stored as request attributes.
1020     *
1021     * @param objectModel the object model
1022     * @param actionMap a Map containing validated parameters
1023     * @param resultMap a Map containing validation results
1024     * @param allOK a boolean indicating if all validations were successful
1025     * @return actionMap if allOK or null otherwise
1026     */

1027    protected Map JavaDoc setResult(Map JavaDoc objectModel, Map JavaDoc actionMap, Map JavaDoc resultMap, boolean allOK) {
1028        if (!allOK) {
1029            // if any validation failed return an empty map
1030
actionMap = null;
1031            resultMap.put("*", ValidatorActionResult.ERROR);
1032            if (getLogger().isDebugEnabled())
1033                getLogger().debug("All form params validated. An error occurred.");
1034        } else {
1035            resultMap.put("*", ValidatorActionResult.OK);
1036            if (getLogger().isDebugEnabled())
1037                getLogger().debug("All form params successfully validated");
1038        }
1039        // store validation results in request attribute
1040
ObjectModelHelper.getRequest(objectModel).setAttribute(
1041            Constants.XSP_FORMVALIDATOR_PATH,
1042            resultMap);
1043        //return Collections.unmodifiableMap (actionMap);
1044
return actionMap;
1045    }
1046
1047    /**
1048     * Load the descriptor containing the constraints.
1049     * @param resolver
1050     * @param parameters
1051     * @return a Configuration containing the constraints or null if a problem occurred.
1052     */

1053    protected Configuration getDescriptor(
1054        SourceResolver resolver,
1055        Map JavaDoc objectModel,
1056        Parameters parameters) {
1057        Configuration conf = null;
1058        try {
1059            conf =
1060                this.getConfiguration(
1061                    parameters.getParameter("descriptor", (String JavaDoc) this.settings.get("descriptor")),
1062                    resolver,
1063                    parameters.getParameterAsBoolean("reloadable", isDescriptorReloadable()));
1064        } catch (ConfigurationException e) {
1065            if (this.getLogger().isWarnEnabled())
1066                this.getLogger().warn("Exception reading descriptor: ", e);
1067        }
1068        return conf;
1069    }
1070
1071}
1072
Popular Tags