View Javadoc

1   /*
2    * $Id: FieldChecks.java 421119 2006-07-12 04:49:11Z wsmoak $
3    *
4    * Copyright 2000-2006 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.struts.validator;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.apache.commons.validator.Field;
23  import org.apache.commons.validator.GenericTypeValidator;
24  import org.apache.commons.validator.GenericValidator;
25  import org.apache.commons.validator.UrlValidator;
26  import org.apache.commons.validator.Validator;
27  import org.apache.commons.validator.ValidatorAction;
28  import org.apache.commons.validator.util.ValidatorUtils;
29  import org.apache.struts.action.ActionMessage;
30  import org.apache.struts.action.ActionMessages;
31  import org.apache.struts.util.MessageResources;
32  import org.apache.struts.util.RequestUtils;
33  
34  import javax.servlet.http.HttpServletRequest;
35  
36  import java.io.Serializable;
37  
38  import java.util.Locale;
39  import java.util.StringTokenizer;
40  
41  /***
42   * <p> This class contains the default validations that are used in the
43   * validator-rules.xml file. </p> <p> In general passing in a null or blank
44   * will return a null Object or a false boolean. However, nulls and blanks do
45   * not result in an error being added to the errors. </p>
46   *
47   * @since Struts 1.1
48   */
49  public class FieldChecks implements Serializable {
50      /***
51       * Commons Logging instance.
52       */
53      private static final Log log = LogFactory.getLog(FieldChecks.class);
54  
55      /***
56       * The message resources for this package.
57       */
58      private static MessageResources sysmsgs =
59          MessageResources.getMessageResources(
60              "org.apache.struts.validator.LocalStrings");
61      public static final String FIELD_TEST_NULL = "NULL";
62      public static final String FIELD_TEST_NOTNULL = "NOTNULL";
63      public static final String FIELD_TEST_EQUAL = "EQUAL";
64  
65      /***
66       * Checks if the field isn't null and length of the field is greater than
67       * zero not including whitespace.
68       *
69       * @param bean      The bean validation is being performed on.
70       * @param va        The <code>ValidatorAction</code> that is currently
71       *                  being performed.
72       * @param field     The <code>Field</code> object associated with the
73       *                  current field being validated.
74       * @param errors    The <code>ActionMessages</code> object to add errors
75       *                  to if any validation errors occur.
76       * @param validator The <code>Validator</code> instance, used to access
77       *                  other field values.
78       * @param request   Current request object.
79       * @return true if meets stated requirements, false otherwise.
80       */
81      public static boolean validateRequired(Object bean, ValidatorAction va,
82          Field field, ActionMessages errors, Validator validator,
83          HttpServletRequest request) {
84          String value = null;
85  
86          value = evaluateBean(bean, field);
87  
88          if (GenericValidator.isBlankOrNull(value)) {
89              errors.add(field.getKey(),
90                  Resources.getActionMessage(validator, request, va, field));
91  
92              return false;
93          } else {
94              return true;
95          }
96      }
97  
98      /***
99       * Checks if the field isn't null based on the values of other fields.
100      *
101      * @param bean      The bean validation is being performed on.
102      * @param va        The <code>ValidatorAction</code> that is currently
103      *                  being performed.
104      * @param field     The <code>Field</code> object associated with the
105      *                  current field being validated.
106      * @param errors    The <code>ActionMessages</code> object to add errors
107      *                  to if any validation errors occur.
108      * @param validator The <code>Validator</code> instance, used to access
109      *                  other field values.
110      * @param request   Current request object.
111      * @return true if meets stated requirements, false otherwise.
112      */
113     public static boolean validateRequiredIf(Object bean, ValidatorAction va,
114         Field field, ActionMessages errors, Validator validator,
115         HttpServletRequest request) {
116         Object form =
117             validator.getParameterValue(org.apache.commons.validator.Validator.BEAN_PARAM);
118         String value = null;
119         boolean required = false;
120 
121         value = evaluateBean(bean, field);
122 
123         int i = 0;
124         String fieldJoin = "AND";
125 
126         if (!GenericValidator.isBlankOrNull(field.getVarValue("fieldJoin"))) {
127             fieldJoin = field.getVarValue("fieldJoin");
128         }
129 
130         if (fieldJoin.equalsIgnoreCase("AND")) {
131             required = true;
132         }
133 
134         while (!GenericValidator.isBlankOrNull(field.getVarValue("field[" + i
135                     + "]"))) {
136             String dependProp = field.getVarValue("field[" + i + "]");
137             String dependTest = field.getVarValue("fieldTest[" + i + "]");
138             String dependTestValue = field.getVarValue("fieldValue[" + i + "]");
139             String dependIndexed = field.getVarValue("fieldIndexed[" + i + "]");
140 
141             if (dependIndexed == null) {
142                 dependIndexed = "false";
143             }
144 
145             String dependVal = null;
146             boolean thisRequired = false;
147 
148             if (field.isIndexed() && dependIndexed.equalsIgnoreCase("true")) {
149                 String key = field.getKey();
150 
151                 if ((key.indexOf("[") > -1) && (key.indexOf("]") > -1)) {
152                     String ind = key.substring(0, key.indexOf(".") + 1);
153 
154                     dependProp = ind + dependProp;
155                 }
156             }
157 
158             dependVal = ValidatorUtils.getValueAsString(form, dependProp);
159 
160             if (dependTest.equals(FIELD_TEST_NULL)) {
161                 if ((dependVal != null) && (dependVal.length() > 0)) {
162                     thisRequired = false;
163                 } else {
164                     thisRequired = true;
165                 }
166             }
167 
168             if (dependTest.equals(FIELD_TEST_NOTNULL)) {
169                 if ((dependVal != null) && (dependVal.length() > 0)) {
170                     thisRequired = true;
171                 } else {
172                     thisRequired = false;
173                 }
174             }
175 
176             if (dependTest.equals(FIELD_TEST_EQUAL)) {
177                 thisRequired = dependTestValue.equalsIgnoreCase(dependVal);
178             }
179 
180             if (fieldJoin.equalsIgnoreCase("AND")) {
181                 required = required && thisRequired;
182             } else {
183                 required = required || thisRequired;
184             }
185 
186             i++;
187         }
188 
189         if (required) {
190             if (GenericValidator.isBlankOrNull(value)) {
191                 errors.add(field.getKey(),
192                     Resources.getActionMessage(validator, request, va, field));
193 
194                 return false;
195             } else {
196                 return true;
197             }
198         }
199 
200         return true;
201     }
202 
203     /***
204      * Checks if the field matches the regular expression in the field's mask
205      * attribute.
206      *
207      * @param bean      The bean validation is being performed on.
208      * @param va        The <code>ValidatorAction</code> that is currently
209      *                  being performed.
210      * @param field     The <code>Field</code> object associated with the
211      *                  current field being validated.
212      * @param errors    The <code>ActionMessages</code> object to add errors
213      *                  to if any validation errors occur.
214      * @param validator The <code>Validator</code> instance, used to access
215      *                  other field values.
216      * @param request   Current request object.
217      * @return true if field matches mask, false otherwise.
218      */
219     public static boolean validateMask(Object bean, ValidatorAction va,
220         Field field, ActionMessages errors, Validator validator,
221         HttpServletRequest request) {
222         String value = null;
223 
224         value = evaluateBean(bean, field);
225 
226         try {
227             String mask =
228                 Resources.getVarValue("mask", field, validator, request, true);
229 
230             if (value != null && value.length()>0
231                 && !GenericValidator.matchRegexp(value, mask)) {
232                 errors.add(field.getKey(),
233                     Resources.getActionMessage(validator, request, va, field));
234 
235                 return false;
236             } else {
237                 return true;
238             }
239         } catch (Exception e) {
240             processFailure(errors, field, "mask", e);
241 
242             return false;
243         }
244     }
245 
246     /***
247      * Checks if the field can safely be converted to a byte primitive.
248      *
249      * @param bean      The bean validation is being performed on.
250      * @param va        The <code>ValidatorAction</code> that is currently
251      *                  being performed.
252      * @param field     The <code>Field</code> object associated with the
253      *                  current field being validated.
254      * @param errors    The <code>ActionMessages</code> object to add errors
255      *                  to if any validation errors occur.
256      * @param validator The <code>Validator</code> instance, used to access
257      *                  other field values.
258      * @param request   Current request object.
259      * @return true if valid, false otherwise.
260      */
261     public static Object validateByte(Object bean, ValidatorAction va,
262         Field field, ActionMessages errors, Validator validator,
263         HttpServletRequest request) {
264         Object result = null;
265         String value = null;
266 
267         value = evaluateBean(bean, field);
268 
269         if (GenericValidator.isBlankOrNull(value)) {
270             return Boolean.TRUE;
271         }
272 
273         result = GenericTypeValidator.formatByte(value);
274 
275         if (result == null) {
276             errors.add(field.getKey(),
277                 Resources.getActionMessage(validator, request, va, field));
278         }
279 
280         return (result == null) ? Boolean.FALSE : result;
281     }
282 
283     /***
284      * Checks if the field can safely be converted to a byte primitive.
285      *
286      * @param bean      The bean validation is being performed on.
287      * @param va        The <code>ValidatorAction</code> that is currently
288      *                  being performed.
289      * @param field     The <code>Field</code> object associated with the
290      *                  current field being validated.
291      * @param errors    The <code>ActionMessages</code> object to add errors
292      *                  to if any validation errors occur.
293      * @param validator The <code>Validator</code> instance, used to access
294      *                  other field values.
295      * @param request   Current request object.
296      * @return true if valid, false otherwise.
297      */
298     public static Object validateByteLocale(Object bean, ValidatorAction va,
299         Field field, ActionMessages errors, Validator validator,
300         HttpServletRequest request) {
301         Object result = null;
302         String value = null;
303 
304         value = evaluateBean(bean, field);
305 
306         if (GenericValidator.isBlankOrNull(value)) {
307             return Boolean.TRUE;
308         }
309 
310         Locale locale = RequestUtils.getUserLocale(request, null);
311 
312         result = GenericTypeValidator.formatByte(value, locale);
313 
314         if (result == null) {
315             errors.add(field.getKey(),
316                 Resources.getActionMessage(validator, request, va, field));
317         }
318 
319         return (result == null) ? Boolean.FALSE : result;
320     }
321 
322     /***
323      * @param bean
324      * @param field
325      * @return
326      */
327     private static String evaluateBean(Object bean, Field field) {
328         String value;
329 
330         if (isString(bean)) {
331             value = (String) bean;
332         } else {
333             value = ValidatorUtils.getValueAsString(bean, field.getProperty());
334         }
335 
336         return value;
337     }
338 
339     /***
340      * Checks if the field can safely be converted to a short primitive.
341      *
342      * @param bean      The bean validation is being performed on.
343      * @param va        The <code>ValidatorAction</code> that is currently
344      *                  being performed.
345      * @param field     The <code>Field</code> object associated with the
346      *                  current field being validated.
347      * @param errors    The <code>ActionMessages</code> object to add errors
348      *                  to if any validation errors occur.
349      * @param validator The <code>Validator</code> instance, used to access
350      *                  other field values.
351      * @param request   Current request object.
352      * @return true if valid, false otherwise.
353      */
354     public static Object validateShort(Object bean, ValidatorAction va,
355         Field field, ActionMessages errors, Validator validator,
356         HttpServletRequest request) {
357         Object result = null;
358         String value = null;
359 
360         value = evaluateBean(bean, field);
361 
362         if (GenericValidator.isBlankOrNull(value)) {
363             return Boolean.TRUE;
364         }
365 
366         result = GenericTypeValidator.formatShort(value);
367 
368         if (result == null) {
369             errors.add(field.getKey(),
370                 Resources.getActionMessage(validator, request, va, field));
371         }
372 
373         return (result == null) ? Boolean.FALSE : result;
374     }
375 
376     /***
377      * Checks if the field can safely be converted to a short primitive.
378      *
379      * @param bean      The bean validation is being performed on.
380      * @param va        The <code>ValidatorAction</code> that is currently
381      *                  being performed.
382      * @param field     The <code>Field</code> object associated with the
383      *                  current field being validated.
384      * @param errors    The <code>ActionMessages</code> object to add errors
385      *                  to if any validation errors occur.
386      * @param validator The <code>Validator</code> instance, used to access
387      *                  other field values.
388      * @param request   Current request object.
389      * @return true if valid, false otherwise.
390      */
391     public static Object validateShortLocale(Object bean, ValidatorAction va,
392         Field field, ActionMessages errors, Validator validator,
393         HttpServletRequest request) {
394         Object result = null;
395         String value = null;
396 
397         value = evaluateBean(bean, field);
398 
399         if (GenericValidator.isBlankOrNull(value)) {
400             return Boolean.TRUE;
401         }
402 
403         Locale locale = RequestUtils.getUserLocale(request, null);
404 
405         result = GenericTypeValidator.formatShort(value, locale);
406 
407         if (result == null) {
408             errors.add(field.getKey(),
409                 Resources.getActionMessage(validator, request, va, field));
410         }
411 
412         return (result == null) ? Boolean.FALSE : result;
413     }
414 
415     /***
416      * Checks if the field can safely be converted to an int primitive.
417      *
418      * @param bean      The bean validation is being performed on.
419      * @param va        The <code>ValidatorAction</code> that is currently
420      *                  being performed.
421      * @param field     The <code>Field</code> object associated with the
422      *                  current field being validated.
423      * @param errors    The <code>ActionMessages</code> object to add errors
424      *                  to if any validation errors occur.
425      * @param validator The <code>Validator</code> instance, used to access
426      *                  other field values.
427      * @param request   Current request object.
428      * @return true if valid, false otherwise.
429      */
430     public static Object validateInteger(Object bean, ValidatorAction va,
431         Field field, ActionMessages errors, Validator validator,
432         HttpServletRequest request) {
433         Object result = null;
434         String value = null;
435 
436         value = evaluateBean(bean, field);
437 
438         if (GenericValidator.isBlankOrNull(value)) {
439             return Boolean.TRUE;
440         }
441 
442         result = GenericTypeValidator.formatInt(value);
443 
444         if (result == null) {
445             errors.add(field.getKey(),
446                 Resources.getActionMessage(validator, request, va, field));
447         }
448 
449         return (result == null) ? Boolean.FALSE : result;
450     }
451 
452     /***
453      * Checks if the field can safely be converted to an int primitive.
454      *
455      * @param bean      The bean validation is being performed on.
456      * @param va        The <code>ValidatorAction</code> that is currently
457      *                  being performed.
458      * @param field     The <code>Field</code> object associated with the
459      *                  current field being validated.
460      * @param errors    The <code>ActionMessages</code> object to add errors
461      *                  to if any validation errors occur.
462      * @param validator The <code>Validator</code> instance, used to access
463      *                  other field values.
464      * @param request   Current request object.
465      * @return true if valid, false otherwise.
466      */
467     public static Object validateIntegerLocale(Object bean, ValidatorAction va,
468         Field field, ActionMessages errors, Validator validator,
469         HttpServletRequest request) {
470         Object result = null;
471         String value = null;
472 
473         value = evaluateBean(bean, field);
474 
475         if (GenericValidator.isBlankOrNull(value)) {
476             return Boolean.TRUE;
477         }
478 
479         Locale locale = RequestUtils.getUserLocale(request, null);
480 
481         result = GenericTypeValidator.formatInt(value, locale);
482 
483         if (result == null) {
484             errors.add(field.getKey(),
485                 Resources.getActionMessage(validator, request, va, field));
486         }
487 
488         return (result == null) ? Boolean.FALSE : result;
489     }
490 
491     /***
492      * Checks if the field can safely be converted to a long primitive.
493      *
494      * @param bean      The bean validation is being performed on.
495      * @param va        The <code>ValidatorAction</code> that is currently
496      *                  being performed.
497      * @param field     The <code>Field</code> object associated with the
498      *                  current field being validated.
499      * @param errors    The <code>ActionMessages</code> object to add errors
500      *                  to if any validation errors occur.
501      * @param validator The <code>Validator</code> instance, used to access
502      *                  other field values.
503      * @param request   Current request object.
504      * @return true if valid, false otherwise.
505      */
506     public static Object validateLong(Object bean, ValidatorAction va,
507         Field field, ActionMessages errors, Validator validator,
508         HttpServletRequest request) {
509         Object result = null;
510         String value = null;
511 
512         value = evaluateBean(bean, field);
513 
514         if (GenericValidator.isBlankOrNull(value)) {
515             return Boolean.TRUE;
516         }
517 
518         result = GenericTypeValidator.formatLong(value);
519 
520         if (result == null) {
521             errors.add(field.getKey(),
522                 Resources.getActionMessage(validator, request, va, field));
523         }
524 
525         return (result == null) ? Boolean.FALSE : result;
526     }
527 
528     /***
529      * Checks if the field can safely be converted to a long primitive.
530      *
531      * @param bean      The bean validation is being performed on.
532      * @param va        The <code>ValidatorAction</code> that is currently
533      *                  being performed.
534      * @param field     The <code>Field</code> object associated with the
535      *                  current field being validated.
536      * @param errors    The <code>ActionMessages</code> object to add errors
537      *                  to if any validation errors occur.
538      * @param validator The <code>Validator</code> instance, used to access
539      *                  other field values.
540      * @param request   Current request object.
541      * @return true if valid, false otherwise.
542      */
543     public static Object validateLongLocale(Object bean, ValidatorAction va,
544         Field field, ActionMessages errors, Validator validator,
545         HttpServletRequest request) {
546         Object result = null;
547         String value = null;
548 
549         value = evaluateBean(bean, field);
550 
551         if (GenericValidator.isBlankOrNull(value)) {
552             return Boolean.TRUE;
553         }
554 
555         Locale locale = RequestUtils.getUserLocale(request, null);
556 
557         result = GenericTypeValidator.formatLong(value, locale);
558 
559         if (result == null) {
560             errors.add(field.getKey(),
561                 Resources.getActionMessage(validator, request, va, field));
562         }
563 
564         return (result == null) ? Boolean.FALSE : result;
565     }
566 
567     /***
568      * Checks if the field can safely be converted to a float primitive.
569      *
570      * @param bean      The bean validation is being performed on.
571      * @param va        The <code>ValidatorAction</code> that is currently
572      *                  being performed.
573      * @param field     The <code>Field</code> object associated with the
574      *                  current field being validated.
575      * @param errors    The <code>ActionMessages</code> object to add errors
576      *                  to if any validation errors occur.
577      * @param validator The <code>Validator</code> instance, used to access
578      *                  other field values.
579      * @param request   Current request object.
580      * @return true if valid, false otherwise.
581      */
582     public static Object validateFloat(Object bean, ValidatorAction va,
583         Field field, ActionMessages errors, Validator validator,
584         HttpServletRequest request) {
585         Object result = null;
586         String value = null;
587 
588         value = evaluateBean(bean, field);
589 
590         if (GenericValidator.isBlankOrNull(value)) {
591             return Boolean.TRUE;
592         }
593 
594         result = GenericTypeValidator.formatFloat(value);
595 
596         if (result == null) {
597             errors.add(field.getKey(),
598                 Resources.getActionMessage(validator, request, va, field));
599         }
600 
601         return (result == null) ? Boolean.FALSE : result;
602     }
603 
604     /***
605      * Checks if the field can safely be converted to a float primitive.
606      *
607      * @param bean      The bean validation is being performed on.
608      * @param va        The <code>ValidatorAction</code> that is currently
609      *                  being performed.
610      * @param field     The <code>Field</code> object associated with the
611      *                  current field being validated.
612      * @param errors    The <code>ActionMessages</code> object to add errors
613      *                  to if any validation errors occur.
614      * @param validator The <code>Validator</code> instance, used to access
615      *                  other field values.
616      * @param request   Current request object.
617      * @return true if valid, false otherwise.
618      */
619     public static Object validateFloatLocale(Object bean, ValidatorAction va,
620         Field field, ActionMessages errors, Validator validator,
621         HttpServletRequest request) {
622         Object result = null;
623         String value = null;
624 
625         value = evaluateBean(bean, field);
626 
627         if (GenericValidator.isBlankOrNull(value)) {
628             return Boolean.TRUE;
629         }
630 
631         Locale locale = RequestUtils.getUserLocale(request, null);
632 
633         result = GenericTypeValidator.formatFloat(value, locale);
634 
635         if (result == null) {
636             errors.add(field.getKey(),
637                 Resources.getActionMessage(validator, request, va, field));
638         }
639 
640         return (result == null) ? Boolean.FALSE : result;
641     }
642 
643     /***
644      * Checks if the field can safely be converted to a double primitive.
645      *
646      * @param bean      The bean validation is being performed on.
647      * @param va        The <code>ValidatorAction</code> that is currently
648      *                  being performed.
649      * @param field     The <code>Field</code> object associated with the
650      *                  current field being validated.
651      * @param errors    The <code>ActionMessages</code> object to add errors
652      *                  to if any validation errors occur.
653      * @param validator The <code>Validator</code> instance, used to access
654      *                  other field values.
655      * @param request   Current request object.
656      * @return true if valid, false otherwise.
657      */
658     public static Object validateDouble(Object bean, ValidatorAction va,
659         Field field, ActionMessages errors, Validator validator,
660         HttpServletRequest request) {
661         Object result = null;
662         String value = null;
663 
664         value = evaluateBean(bean, field);
665 
666         if (GenericValidator.isBlankOrNull(value)) {
667             return Boolean.TRUE;
668         }
669 
670         result = GenericTypeValidator.formatDouble(value);
671 
672         if (result == null) {
673             errors.add(field.getKey(),
674                 Resources.getActionMessage(validator, request, va, field));
675         }
676 
677         return (result == null) ? Boolean.FALSE : result;
678     }
679 
680     /***
681      * Checks if the field can safely be converted to a double primitive.
682      *
683      * @param bean      The bean validation is being performed on.
684      * @param va        The <code>ValidatorAction</code> that is currently
685      *                  being performed.
686      * @param field     The <code>Field</code> object associated with the
687      *                  current field being validated.
688      * @param errors    The <code>ActionMessages</code> object to add errors
689      *                  to if any validation errors occur.
690      * @param validator The <code>Validator</code> instance, used to access
691      *                  other field values.
692      * @param request   Current request object.
693      * @return true if valid, false otherwise.
694      */
695     public static Object validateDoubleLocale(Object bean, ValidatorAction va,
696         Field field, ActionMessages errors, Validator validator,
697         HttpServletRequest request) {
698         Object result = null;
699         String value = null;
700 
701         value = evaluateBean(bean, field);
702 
703         if (GenericValidator.isBlankOrNull(value)) {
704             return Boolean.TRUE;
705         }
706 
707         Locale locale = RequestUtils.getUserLocale(request, null);
708 
709         result = GenericTypeValidator.formatDouble(value, locale);
710 
711         if (result == null) {
712             errors.add(field.getKey(),
713                 Resources.getActionMessage(validator, request, va, field));
714         }
715 
716         return (result == null) ? Boolean.FALSE : result;
717     }
718 
719     /***
720      * Checks if the field is a valid date. If the field has a datePattern
721      * variable, that will be used to format <code>java.text.SimpleDateFormat</code>.
722      * If the field has a datePatternStrict variable, that will be used to
723      * format <code>java.text.SimpleDateFormat</code> and the length will be
724      * checked so '2/12/1999' will not pass validation with the format
725      * 'MM/dd/yyyy' because the month isn't two digits. If no datePattern
726      * variable is specified, then the field gets the DateFormat.SHORT format
727      * for the locale. The setLenient method is set to <code>false</code> for
728      * all variations.
729      *
730      * @param bean      The bean validation is being performed on.
731      * @param va        The <code>ValidatorAction</code> that is currently
732      *                  being performed.
733      * @param field     The <code>Field</code> object associated with the
734      *                  current field being validated.
735      * @param errors    The <code>ActionMessages</code> object to add errors
736      *                  to if any validation errors occur.
737      * @param validator The <code>Validator</code> instance, used to access
738      *                  other field values.
739      * @param request   Current request object.
740      * @return true if valid, false otherwise.
741      */
742     public static Object validateDate(Object bean, ValidatorAction va,
743         Field field, ActionMessages errors, Validator validator,
744         HttpServletRequest request) {
745         Object result = null;
746         String value = null;
747 
748         value = evaluateBean(bean, field);
749 
750         boolean isStrict = false;
751         String datePattern =
752             Resources.getVarValue("datePattern", field, validator, request,
753                 false);
754 
755         if (GenericValidator.isBlankOrNull(datePattern)) {
756             datePattern =
757                 Resources.getVarValue("datePatternStrict", field, validator,
758                     request, false);
759 
760             if (!GenericValidator.isBlankOrNull(datePattern)) {
761                 isStrict = true;
762             }
763         }
764 
765         Locale locale = RequestUtils.getUserLocale(request, null);
766 
767         if (GenericValidator.isBlankOrNull(value)) {
768             return Boolean.TRUE;
769         }
770 
771         try {
772             if (GenericValidator.isBlankOrNull(datePattern)) {
773                 result = GenericTypeValidator.formatDate(value, locale);
774             } else {
775                 result =
776                     GenericTypeValidator.formatDate(value, datePattern, isStrict);
777             }
778         } catch (Exception e) {
779             log.error(e.getMessage(), e);
780         }
781 
782         if (result == null) {
783             errors.add(field.getKey(),
784                 Resources.getActionMessage(validator, request, va, field));
785         }
786 
787         return (result == null) ? Boolean.FALSE : result;
788     }
789 
790     /***
791      * Checks if a fields value is within a range (min &amp; max specified in
792      * the vars attribute).
793      *
794      * @param bean      The bean validation is being performed on.
795      * @param va        The <code>ValidatorAction</code> that is currently
796      *                  being performed.
797      * @param field     The <code>Field</code> object associated with the
798      *                  current field being validated.
799      * @param errors    The <code>ActionMessages</code> object to add errors
800      *                  to if any validation errors occur.
801      * @param validator The <code>Validator</code> instance, used to access
802      *                  other field values.
803      * @param request   Current request object.
804      * @return True if in range, false otherwise.
805      */
806     public static boolean validateLongRange(Object bean, ValidatorAction va,
807         Field field, ActionMessages errors, Validator validator,
808         HttpServletRequest request) {
809         String value = null;
810 
811         value = evaluateBean(bean, field);
812 
813         if (!GenericValidator.isBlankOrNull(value)) {
814             try {
815                 String minVar =
816                     Resources.getVarValue("min", field, validator, request, true);
817                 String maxVar =
818                     Resources.getVarValue("max", field, validator, request, true);
819                 long longValue = Long.parseLong(value);
820                 long min = Long.parseLong(minVar);
821                 long max = Long.parseLong(maxVar);
822 
823                 if (min > max) {
824                     throw new IllegalArgumentException(sysmsgs.getMessage(
825                             "invalid.range", minVar, maxVar));
826                 }
827 
828                 if (!GenericValidator.isInRange(longValue, min, max)) {
829                     errors.add(field.getKey(),
830                         Resources.getActionMessage(validator, request, va, field));
831 
832                     return false;
833                 }
834             } catch (Exception e) {
835                 processFailure(errors, field, "longRange", e);
836 
837                 return false;
838             }
839         }
840 
841         return true;
842     }
843 
844     /***
845      * Checks if a fields value is within a range (min &amp; max specified in
846      * the vars attribute).
847      *
848      * @param bean      The bean validation is being performed on.
849      * @param va        The <code>ValidatorAction</code> that is currently
850      *                  being performed.
851      * @param field     The <code>Field</code> object associated with the
852      *                  current field being validated.
853      * @param errors    The <code>ActionMessages</code> object to add errors
854      *                  to if any validation errors occur.
855      * @param validator The <code>Validator</code> instance, used to access
856      *                  other field values.
857      * @param request   Current request object.
858      * @return True if in range, false otherwise.
859      */
860     public static boolean validateIntRange(Object bean, ValidatorAction va,
861         Field field, ActionMessages errors, Validator validator,
862         HttpServletRequest request) {
863         String value = null;
864 
865         value = evaluateBean(bean, field);
866 
867         if (!GenericValidator.isBlankOrNull(value)) {
868             try {
869                 String minVar =
870                     Resources.getVarValue("min", field, validator, request, true);
871                 String maxVar =
872                     Resources.getVarValue("max", field, validator, request, true);
873                 int min = Integer.parseInt(minVar);
874                 int max = Integer.parseInt(maxVar);
875                 int intValue = Integer.parseInt(value);
876 
877                 if (min > max) {
878                     throw new IllegalArgumentException(sysmsgs.getMessage(
879                             "invalid.range", minVar, maxVar));
880                 }
881 
882                 if (!GenericValidator.isInRange(intValue, min, max)) {
883                     errors.add(field.getKey(),
884                         Resources.getActionMessage(validator, request, va, field));
885 
886                     return false;
887                 }
888             } catch (Exception e) {
889                 processFailure(errors, field, "intRange", e);
890 
891                 return false;
892             }
893         }
894 
895         return true;
896     }
897 
898     /***
899      * Checks if a fields value is within a range (min &amp; max specified in
900      * the vars attribute).
901      *
902      * @param bean      The bean validation is being performed on.
903      * @param va        The <code>ValidatorAction</code> that is currently
904      *                  being performed.
905      * @param field     The <code>Field</code> object associated with the
906      *                  current field being validated.
907      * @param errors    The <code>ActionMessages</code> object to add errors
908      *                  to if any validation errors occur.
909      * @param validator The <code>Validator</code> instance, used to access
910      *                  other field values.
911      * @param request   Current request object.
912      * @return True if in range, false otherwise.
913      */
914     public static boolean validateDoubleRange(Object bean, ValidatorAction va,
915         Field field, ActionMessages errors, Validator validator,
916         HttpServletRequest request) {
917         String value = null;
918 
919         value = evaluateBean(bean, field);
920 
921         if (!GenericValidator.isBlankOrNull(value)) {
922             try {
923                 String minVar =
924                     Resources.getVarValue("min", field, validator, request, true);
925                 String maxVar =
926                     Resources.getVarValue("max", field, validator, request, true);
927                 double doubleValue = Double.parseDouble(value);
928                 double min = Double.parseDouble(minVar);
929                 double max = Double.parseDouble(maxVar);
930 
931                 if (min > max) {
932                     throw new IllegalArgumentException(sysmsgs.getMessage(
933                             "invalid.range", minVar, maxVar));
934                 }
935 
936                 if (!GenericValidator.isInRange(doubleValue, min, max)) {
937                     errors.add(field.getKey(),
938                         Resources.getActionMessage(validator, request, va, field));
939 
940                     return false;
941                 }
942             } catch (Exception e) {
943                 processFailure(errors, field, "doubleRange", e);
944 
945                 return false;
946             }
947         }
948 
949         return true;
950     }
951 
952     /***
953      * Checks if a fields value is within a range (min &amp; max specified in
954      * the vars attribute).
955      *
956      * @param bean      The bean validation is being performed on.
957      * @param va        The <code>ValidatorAction</code> that is currently
958      *                  being performed.
959      * @param field     The <code>Field</code> object associated with the
960      *                  current field being validated.
961      * @param errors    The <code>ActionMessages</code> object to add errors
962      *                  to if any validation errors occur.
963      * @param validator The <code>Validator</code> instance, used to access
964      *                  other field values.
965      * @param request   Current request object.
966      * @return True if in range, false otherwise.
967      */
968     public static boolean validateFloatRange(Object bean, ValidatorAction va,
969         Field field, ActionMessages errors, Validator validator,
970         HttpServletRequest request) {
971         String value = null;
972 
973         value = evaluateBean(bean, field);
974 
975         if (!GenericValidator.isBlankOrNull(value)) {
976             try {
977                 String minVar =
978                     Resources.getVarValue("min", field, validator, request, true);
979                 String maxVar =
980                     Resources.getVarValue("max", field, validator, request, true);
981                 float floatValue = Float.parseFloat(value);
982                 float min = Float.parseFloat(minVar);
983                 float max = Float.parseFloat(maxVar);
984 
985                 if (min > max) {
986                     throw new IllegalArgumentException(sysmsgs.getMessage(
987                             "invalid.range", minVar, maxVar));
988                 }
989 
990                 if (!GenericValidator.isInRange(floatValue, min, max)) {
991                     errors.add(field.getKey(),
992                         Resources.getActionMessage(validator, request, va, field));
993 
994                     return false;
995                 }
996             } catch (Exception e) {
997                 processFailure(errors, field, "floatRange", e);
998 
999                 return false;
1000             }
1001         }
1002 
1003         return true;
1004     }
1005 
1006     /***
1007      * Checks if the field is a valid credit card number.
1008      *
1009      * @param bean      The bean validation is being performed on.
1010      * @param va        The <code>ValidatorAction</code> that is currently
1011      *                  being performed.
1012      * @param field     The <code>Field</code> object associated with the
1013      *                  current field being validated.
1014      * @param errors    The <code>ActionMessages</code> object to add errors
1015      *                  to if any validation errors occur.
1016      * @param validator The <code>Validator</code> instance, used to access
1017      *                  other field values.
1018      * @param request   Current request object.
1019      * @return true if valid, false otherwise.
1020      */
1021     public static Object validateCreditCard(Object bean, ValidatorAction va,
1022         Field field, ActionMessages errors, Validator validator,
1023         HttpServletRequest request) {
1024         Object result = null;
1025         String value = null;
1026 
1027         value = evaluateBean(bean, field);
1028 
1029         if (GenericValidator.isBlankOrNull(value)) {
1030             return Boolean.TRUE;
1031         }
1032 
1033         result = GenericTypeValidator.formatCreditCard(value);
1034 
1035         if (result == null) {
1036             errors.add(field.getKey(),
1037                 Resources.getActionMessage(validator, request, va, field));
1038         }
1039 
1040         return (result == null) ? Boolean.FALSE : result;
1041     }
1042 
1043     /***
1044      * Checks if a field has a valid e-mail address.
1045      *
1046      * @param bean      The bean validation is being performed on.
1047      * @param va        The <code>ValidatorAction</code> that is currently
1048      *                  being performed.
1049      * @param field     The <code>Field</code> object associated with the
1050      *                  current field being validated.
1051      * @param errors    The <code>ActionMessages</code> object to add errors
1052      *                  to if any validation errors occur.
1053      * @param validator The <code>Validator</code> instance, used to access
1054      *                  other field values.
1055      * @param request   Current request object.
1056      * @return True if valid, false otherwise.
1057      */
1058     public static boolean validateEmail(Object bean, ValidatorAction va,
1059         Field field, ActionMessages errors, Validator validator,
1060         HttpServletRequest request) {
1061         String value = null;
1062 
1063         value = evaluateBean(bean, field);
1064 
1065         if (!GenericValidator.isBlankOrNull(value)
1066             && !GenericValidator.isEmail(value)) {
1067             errors.add(field.getKey(),
1068                 Resources.getActionMessage(validator, request, va, field));
1069 
1070             return false;
1071         } else {
1072             return true;
1073         }
1074     }
1075 
1076     /***
1077      * Checks if the field's length is less than or equal to the maximum
1078      * value. A <code>Null</code> will be considered an error.
1079      *
1080      * @param bean      The bean validation is being performed on.
1081      * @param va        The <code>ValidatorAction</code> that is currently
1082      *                  being performed.
1083      * @param field     The <code>Field</code> object associated with the
1084      *                  current field being validated.
1085      * @param errors    The <code>ActionMessages</code> object to add errors
1086      *                  to if any validation errors occur.
1087      * @param validator The <code>Validator</code> instance, used to access
1088      *                  other field values.
1089      * @param request   Current request object.
1090      * @return True if stated conditions met.
1091      */
1092     public static boolean validateMaxLength(Object bean, ValidatorAction va,
1093         Field field, ActionMessages errors, Validator validator,
1094         HttpServletRequest request) {
1095         String value = null;
1096 
1097         value = evaluateBean(bean, field);
1098 
1099         if (value != null) {
1100             try {
1101                 String maxVar =
1102                     Resources.getVarValue("maxlength", field, validator,
1103                         request, true);
1104                 int max = Integer.parseInt(maxVar);
1105 
1106                 boolean isValid = false;
1107                 String endLth = Resources.getVarValue("lineEndLength", field,
1108                     validator, request, false);
1109                 if (GenericValidator.isBlankOrNull(endLth)) {
1110                     isValid = GenericValidator.maxLength(value, max);
1111                 } else {
1112                     isValid = GenericValidator.maxLength(value, max,
1113                         Integer.parseInt(endLth));
1114                 }
1115 
1116                 if (!isValid) {
1117                     errors.add(field.getKey(),
1118                         Resources.getActionMessage(validator, request, va, field));
1119 
1120                     return false;
1121                 }
1122             } catch (Exception e) {
1123                 processFailure(errors, field, "floatRange", e);
1124 
1125                 return false;
1126             }
1127         }
1128 
1129         return true;
1130     }
1131 
1132     /***
1133      * Checks if the field's length is greater than or equal to the minimum
1134      * value. A <code>Null</code> will be considered an error.
1135      *
1136      * @param bean      The bean validation is being performed on.
1137      * @param va        The <code>ValidatorAction</code> that is currently
1138      *                  being performed.
1139      * @param field     The <code>Field</code> object associated with the
1140      *                  current field being validated.
1141      * @param errors    The <code>ActionMessages</code> object to add errors
1142      *                  to if any validation errors occur.
1143      * @param validator The <code>Validator</code> instance, used to access
1144      *                  other field values.
1145      * @param request   Current request object.
1146      * @return True if stated conditions met.
1147      */
1148     public static boolean validateMinLength(Object bean, ValidatorAction va,
1149         Field field, ActionMessages errors, Validator validator,
1150         HttpServletRequest request) {
1151         String value = null;
1152 
1153         value = evaluateBean(bean, field);
1154 
1155         if (!GenericValidator.isBlankOrNull(value)) {
1156             try {
1157                 String minVar =
1158                     Resources.getVarValue("minlength", field, validator,
1159                         request, true);
1160                 int min = Integer.parseInt(minVar);
1161 
1162                 boolean isValid = false;
1163                 String endLth = Resources.getVarValue("lineEndLength", field,
1164                     validator, request, false);
1165                 if (GenericValidator.isBlankOrNull(endLth)) {
1166                     isValid = GenericValidator.minLength(value, min);
1167                 } else {
1168                     isValid = GenericValidator.minLength(value, min,
1169                         Integer.parseInt(endLth));
1170                 }
1171 
1172                 if (!isValid) {
1173                     errors.add(field.getKey(),
1174                         Resources.getActionMessage(validator, request, va, field));
1175 
1176                     return false;
1177                 }
1178             } catch (Exception e) {
1179                 processFailure(errors, field, "minlength", e);
1180 
1181                 return false;
1182             }
1183         }
1184 
1185         return true;
1186     }
1187 
1188     /***
1189      * Checks if a field has a valid url. Four optional variables can be
1190      * specified to configure url validation.
1191      *
1192      * <ul>
1193      *
1194      * <li>Variable <code>allow2slashes</code> can be set to <code>true</code>
1195      * or <code>false</code> to control whether two slashes are allowed -
1196      * default is <code>false</code> (i.e. two slashes are NOT allowed).</li>
1197      *
1198      * <li>Variable <code>nofragments</code> can be set to <code>true</code>
1199      * or <code>false</code> to control whether fragments are allowed -
1200      * default is <code>false</code> (i.e. fragments ARE allowed).</li>
1201      *
1202      * <li>Variable <code>allowallschemes</code> can be set to
1203      * <code>true</code> or <code>false</code> to control if all schemes are
1204      * allowed - default is <code>false</code> (i.e. all schemes are NOT
1205      * allowed).</li>
1206      *
1207      * <li>Variable <code>schemes</code> can be set to a comma delimited list
1208      * of valid schemes. This value is ignored if <code>allowallschemes</code>
1209      * is set to <code>true</code>. Default schemes allowed are "http",
1210      * "https" and "ftp" if this variable is not specified.</li>
1211      *
1212      * </ul>
1213      *
1214      * @param bean      The bean validation is being performed on.
1215      * @param va        The <code>ValidatorAction</code> that is currently
1216      *                  being performed.
1217      * @param field     The <code>Field</code> object associated with the
1218      *                  current field being validated.
1219      * @param errors    The <code>ActionMessages</code> object to add errors
1220      *                  to if any validation errors occur.
1221      * @param validator The <code>Validator</code> instance, used to access
1222      *                  other field values.
1223      * @param request   Current request object.
1224      * @return True if valid, false otherwise.
1225      */
1226     public static boolean validateUrl(Object bean, ValidatorAction va,
1227         Field field, ActionMessages errors, Validator validator,
1228         HttpServletRequest request) {
1229         String value = null;
1230 
1231         value = evaluateBean(bean, field);
1232 
1233         if (GenericValidator.isBlankOrNull(value)) {
1234             return true;
1235         }
1236 
1237         // Get the options and schemes Vars
1238         String allowallschemesVar =
1239             Resources.getVarValue("allowallschemes", field, validator, request,
1240                 false);
1241         boolean allowallschemes = "true".equalsIgnoreCase(allowallschemesVar);
1242         int options = allowallschemes ? UrlValidator.ALLOW_ALL_SCHEMES : 0;
1243 
1244         String allow2slashesVar =
1245             Resources.getVarValue("allow2slashes", field, validator, request,
1246                 false);
1247 
1248         if ("true".equalsIgnoreCase(allow2slashesVar)) {
1249             options += UrlValidator.ALLOW_2_SLASHES;
1250         }
1251 
1252         String nofragmentsVar =
1253             Resources.getVarValue("nofragments", field, validator, request,
1254                 false);
1255 
1256         if ("true".equalsIgnoreCase(nofragmentsVar)) {
1257             options += UrlValidator.NO_FRAGMENTS;
1258         }
1259 
1260         String schemesVar =
1261             allowallschemes ? null
1262                             : Resources.getVarValue("schemes", field,
1263                 validator, request, false);
1264 
1265         // No options or schemes - use GenericValidator as default
1266         if ((options == 0) && (schemesVar == null)) {
1267             if (GenericValidator.isUrl(value)) {
1268                 return true;
1269             } else {
1270                 errors.add(field.getKey(),
1271                     Resources.getActionMessage(validator, request, va, field));
1272 
1273                 return false;
1274             }
1275         }
1276 
1277         // Parse comma delimited list of schemes into a String[]
1278         String[] schemes = null;
1279 
1280         if (schemesVar != null) {
1281             StringTokenizer st = new StringTokenizer(schemesVar, ",");
1282 
1283             schemes = new String[st.countTokens()];
1284 
1285             int i = 0;
1286 
1287             while (st.hasMoreTokens()) {
1288                 schemes[i++] = st.nextToken().trim();
1289             }
1290         }
1291 
1292         // Create UrlValidator and validate with options/schemes
1293         UrlValidator urlValidator = new UrlValidator(schemes, options);
1294 
1295         if (urlValidator.isValid(value)) {
1296             return true;
1297         } else {
1298             errors.add(field.getKey(),
1299                 Resources.getActionMessage(validator, request, va, field));
1300 
1301             return false;
1302         }
1303     }
1304 
1305     /***
1306      * Process a validation failure.
1307      */
1308     private static void processFailure(ActionMessages errors, Field field,
1309         String validator, Throwable t) {
1310         // Log the error
1311         String logErrorMsg =
1312             sysmsgs.getMessage("validation.failed", validator,
1313                 field.getProperty(), t.toString());
1314 
1315         log.error(logErrorMsg);
1316 
1317         // Add general "system error" message to show to the user
1318         String userErrorMsg = sysmsgs.getMessage("system.error");
1319 
1320         errors.add(field.getKey(), new ActionMessage(userErrorMsg, false));
1321     }
1322 
1323     /***
1324      * Return <code>true</code> if the specified object is a String or a
1325      * <code>null</code> value.
1326      *
1327      * @param o Object to be tested
1328      * @return The string value
1329      */
1330     protected static boolean isString(Object o) {
1331         return (o == null) ? true : String.class.isInstance(o);
1332     }
1333 }