View Javadoc
1   package org.andromda.cartridges.jsf.validator;
2   
3   import java.io.Serializable;
4   import java.net.URL;
5   import java.text.DateFormat;
6   import java.text.SimpleDateFormat;
7   import java.util.Calendar;
8   import java.util.Collection;
9   import java.util.Date;
10  import java.util.Iterator;
11  import java.util.Locale;
12  import java.util.Map;
13  
14  import javax.faces.component.EditableValueHolder;
15  import javax.faces.component.UIComponent;
16  import javax.faces.context.FacesContext;
17  
18  import org.apache.commons.lang.ObjectUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.apache.commons.validator.Field;
21  import org.apache.commons.validator.GenericTypeValidator;
22  import org.apache.commons.validator.GenericValidator;
23  import org.apache.commons.validator.ValidatorAction;
24  import org.apache.commons.validator.ValidatorException;
25  
26  /**
27   * <p>
28   * This class contains the default validations that are used in the
29   * validator-rules.xml file.
30   * </p>
31   * <p>
32   * In general passing in a null or blank will return a null Object or a false
33   * boolean. However, nulls and blanks do not result in an error being added to
34   * the errors.
35   * </p>
36   */
37  public class ParameterChecks
38      implements Serializable
39  {
40      /**
41       *
42       */
43      private static final long serialVersionUID = 1L;
44      /** NULL */
45      public static final String FIELD_TEST_NULL = "NULL";
46      /** NOTNULL */
47      public static final String FIELD_TEST_NOTNULL = "NOTNULL";
48      /** EQUAL */
49      public static final String FIELD_TEST_EQUAL = "EQUAL";
50  
51      /**
52       * Checks if the field isn't null and length of the field is greater than
53       * zero not including whitespace.
54       *
55       * @param context the faces context
56       * @param object the value of the field being validated.
57       * @param parameters Any field parameters from the validation.xml.
58       * @param errors The <code>Map</code> object to add errors to if any
59       *        validation errors occur.
60       * @param action The <code>ValidatorAction</code> that is currently being
61       *        performed.
62       * @param field The <code>Field</code> object associated with the current
63       *        field being validated.
64       */
65      public static void validateRequired(
66          FacesContext context,
67          Object object,
68          Map parameters,
69          Collection errors,
70          ValidatorAction action,
71          Field field)
72      {
73          String value = null;
74          if (object instanceof String)
75          {
76              value = (String)object;
77          }
78          else
79          {
80              value = ObjectUtils.toString(object);
81          }
82          if (StringUtils.isBlank(value))
83          {
84              errors.add(ValidatorMessages.getMessage(
85                      action,
86                      field,
87                      context));
88          }
89      }
90  
91      /**
92       * Checks if the parameter isn't null based on the values of other fields.
93       *
94       * @param context the faces context
95       * @param object the value of the field being validated.
96       * @param parameters Any field parameters from the validation.xml.
97       * @param errors The <code>Map</code> object to add errors to if any
98       *        validation errors occur.
99       * @param action The <code>ValidatorAction</code> that is currently being
100      *        performed.
101      * @param field The <code>Field</code> object associated with the current
102      *        field being validated.
103      */
104     public static void validateRequiredIf(
105         FacesContext context,
106         Object object,
107         Map parameters,
108         Collection errors,
109         ValidatorAction action,
110         Field field)
111     {
112         boolean required = false;
113 
114         final String value = ObjectUtils.toString(object);
115 
116         int ctr = 0;
117         String fieldJoin = "AND";
118         if (!StringUtils.isBlank(field.getVarValue("fieldJoin")))
119         {
120             fieldJoin = field.getVarValue("fieldJoin");
121         }
122 
123         if ("AND".equalsIgnoreCase(fieldJoin))
124         {
125             required = true;
126         }
127 
128         while (!StringUtils.isBlank(field.getVarValue("field[" + ctr + ']')))
129         {
130             String dependProp = field.getVarValue("field[" + ctr + ']');
131             String dependTest = field.getVarValue("fieldTest[" + ctr + ']');
132             String dependTestValue = field.getVarValue("fieldValue[" + ctr + ']');
133             String dependIndexed = field.getVarValue("fieldIndexed[" + ctr + ']');
134 
135             if (dependIndexed == null)
136             {
137                 dependIndexed = "false";
138             }
139 
140             String dependVal = null;
141             boolean thisRequired = false;
142             if (field.isIndexed() && "true".equalsIgnoreCase(dependIndexed))
143             {
144                 String key = field.getKey();
145                 if ((key.indexOf('[') > -1) && (key.indexOf(']') > -1))
146                 {
147                     String ind = key.substring(
148                             0,
149                             key.indexOf('.') + 1);
150                     dependProp = ind + dependProp;
151                 }
152             }
153 
154             dependVal = (String)parameters.get(dependProp);
155             if (dependTest.equals(FIELD_TEST_NULL))
156             {
157                 if ((dependVal != null) && (dependVal.length() > 0))
158                 {
159                     thisRequired = false;
160                 }
161                 else
162                 {
163                     thisRequired = true;
164                 }
165             }
166 
167             if (dependTest.equals(FIELD_TEST_NOTNULL))
168             {
169                 if ((dependVal != null) && (dependVal.length() > 0))
170                 {
171                     thisRequired = true;
172                 }
173                 else
174                 {
175                     thisRequired = false;
176                 }
177             }
178 
179             if (dependTest.equals(FIELD_TEST_EQUAL))
180             {
181                 thisRequired = dependTestValue.equalsIgnoreCase(dependVal);
182             }
183 
184             if ("AND".equalsIgnoreCase(fieldJoin))
185             {
186                 required = required && thisRequired;
187             }
188             else
189             {
190                 required = required || thisRequired;
191             }
192 
193             ctr++;
194         }
195 
196         if (required)
197         {
198             if (StringUtils.isBlank(value))
199             {
200                 errors.add(ValidatorMessages.getMessage(
201                         action,
202                         field,
203                         context));
204             }
205         }
206     }
207 
208     /**
209      * Checks if the parameter matches the regular expression in the field's
210      * mask attribute.
211      *
212      * @param context the faces context
213      * @param object the value of the field being validated.
214      * @param parameters Any field parameters from the validation.xml.
215      * @param errors The <code>Map</code> object to add errors to if any
216      *        validation errors occur.
217      * @param action The <code>ValidatorAction</code> that is currently being
218      *        performed.
219      * @param field The <code>Field</code> object associated with the current
220      *        field being validated.
221      */
222     public static void validateMask(
223         FacesContext context,
224         Object object,
225         Map parameters,
226         Collection errors,
227         ValidatorAction action,
228         Field field)
229     {
230         final String mask = field.getVarValue("mask");
231         final String value = ObjectUtils.toString(object);
232         if (StringUtils.isNotBlank(value) && !GenericValidator.matchRegexp(
233                 value,
234                 mask))
235         {
236             errors.add(ValidatorMessages.getMessage(
237                     action,
238                     field,
239                     context));
240         }
241     }
242 
243     /**
244      * Checks if the field can safely be converted to a byte primitive.
245      *
246      * @param context the faces context
247      * @param object the value of the field being validated.
248      * @param parameters Any field parameters from the validation.xml.
249      * @param errors The <code>Map</code> object to add errors to if any
250      *        validation errors occur.
251      * @param action The <code>ValidatorAction</code> that is currently being
252      *        performed.
253      * @param field The <code>Field</code> object associated with the current
254      *        field being validated.
255      */
256     public static void validateByte(
257         FacesContext context,
258         Object object,
259         Map parameters,
260         Collection errors,
261         ValidatorAction action,
262         Field field)
263     {
264         Byte result = null;
265         String value = ObjectUtils.toString(object);
266         if (StringUtils.isNotBlank(value))
267         {
268             result = GenericTypeValidator.formatByte(value);
269 
270             if (result == null)
271             {
272                 errors.add(ValidatorMessages.getMessage(
273                         action,
274                         field,
275                         context));
276             }
277         }
278     }
279 
280     /**
281      * Checks if the field can safely be converted to a short primitive.
282      *
283      * @param context the faces context
284      * @param object the value of the field being validated.
285      * @param parameters Any field parameters from the validation.xml.
286      * @param errors The <code>Map</code> object to add errors to if any
287      *        validation errors occur.
288      * @param action The <code>ValidatorAction</code> that is currently being
289      *        performed.
290      * @param field The <code>Field</code> object associated with the current
291      *        field being validated.
292      */
293     public static void validateShort(
294         FacesContext context,
295         Object object,
296         Map parameters,
297         Collection errors,
298         ValidatorAction action,
299         Field field)
300     {
301         Short result = null;
302         String value = ObjectUtils.toString(object);
303         if (StringUtils.isNotBlank(value))
304         {
305             result = GenericTypeValidator.formatShort(value);
306 
307             if (result == null)
308             {
309                 errors.add(ValidatorMessages.getMessage(
310                         action,
311                         field,
312                         context));
313             }
314         }
315     }
316 
317     /**
318      * Checks if the field can safely be converted to an int primitive.
319      *
320      * @param context the faces context
321      * @param object the value of the field being validated.
322      * @param parameters Any field parameters from the validation.xml.
323      * @param errors The <code>Map</code> object to add errors to if any
324      *        validation errors occur.
325      * @param action The <code>ValidatorAction</code> that is currently being
326      *        performed.
327      * @param field The <code>Field</code> object associated with the current
328      *        field being validated.
329      */
330     public static void validateInteger(
331         FacesContext context,
332         Object object,
333         Map parameters,
334         Collection errors,
335         ValidatorAction action,
336         Field field)
337     {
338         Integer result = null;
339         String value = ObjectUtils.toString(object);
340         if (StringUtils.isNotBlank(value))
341         {
342             result = GenericTypeValidator.formatInt(value);
343             if (result == null)
344             {
345                 errors.add(ValidatorMessages.getMessage(
346                         action,
347                         field,
348                         context));
349             }
350         }
351     }
352 
353     /**
354      * Checks if the field can safely be converted to a long primitive.
355      *
356      * @param context the faces context
357      * @param object the value of the field being validated.
358      * @param parameters Any field parameters from the validation.xml.
359      * @param errors The <code>Map</code> object to add errors to if any
360      *        validation errors occur.
361      * @param action The <code>ValidatorAction</code> that is currently being
362      *        performed.
363      * @param field The <code>Field</code> object associated with the current
364      *        field being validated.
365      */
366     public static void validateLong(
367         FacesContext context,
368         Object object,
369         Map parameters,
370         Collection errors,
371         ValidatorAction action,
372         Field field)
373     {
374         Long result = null;
375         String value = ObjectUtils.toString(object);
376         if (StringUtils.isNotBlank(value))
377         {
378             result = GenericTypeValidator.formatLong(value);
379             if (result == null)
380             {
381                 errors.add(ValidatorMessages.getMessage(
382                         action,
383                         field,
384                         context));
385             }
386         }
387     }
388 
389     /**
390      * Checks if the field can safely be converted to a float primitive.
391      *
392      * @param context the faces context
393      * @param object the value of the field being validated.
394      * @param parameters Any field parameters from the validation.xml.
395      * @param errors The <code>Map</code> object to add errors to if any
396      *        validation errors occur.
397      * @param action The <code>ValidatorAction</code> that is currently being
398      *        performed.
399      * @param field The <code>Field</code> object associated with the current
400      *        field being validated.
401      */
402     public static void validateFloat(
403         FacesContext context,
404         Object object,
405         Map parameters,
406         Collection errors,
407         ValidatorAction action,
408         Field field)
409     {
410         Float result = null;
411         String value = ObjectUtils.toString(object);
412         if (StringUtils.isNotBlank(value))
413         {
414             result = GenericTypeValidator.formatFloat(value);
415 
416             if (result == null)
417             {
418                 errors.add(ValidatorMessages.getMessage(
419                         action,
420                         field,
421                         context));
422             }
423         }
424     }
425 
426     /**
427      * Checks if the field can safely be converted to a double primitive.
428      *
429      * @param context the faces context
430      * @param object the value of the field being validated.
431      * @param parameters Any field parameters from the validation.xml.
432      * @param errors The <code>Map</code> object to add errors to if any
433      *        validation errors occur.
434      * @param action The <code>ValidatorAction</code> that is currently being
435      *        performed.
436      * @param field The <code>Field</code> object associated with the current
437      *        field being validated.
438      */
439     public static void validateDouble(
440         FacesContext context,
441         Object object,
442         Map parameters,
443         Collection errors,
444         ValidatorAction action,
445         Field field)
446     {
447         Double result = null;
448         String value = ObjectUtils.toString(object);
449         if (StringUtils.isNotBlank(value))
450         {
451             result = GenericTypeValidator.formatDouble(value);
452 
453             if (result == null)
454             {
455                 errors.add(ValidatorMessages.getMessage(
456                         action,
457                         field,
458                         context));
459             }
460         }
461     }
462 
463     /**
464      * Checks if the field is a valid date. If the field has a datePattern
465      * variable, that will be used to format
466      * <code>java.text.SimpleDateFormat</code>. If the field has a
467      * datePatternStrict variable, that will be used to format
468      * <code>java.text.SimpleDateFormat</code> and the length will be checked
469      * so '2/12/1999' will not pass validation with the format 'MM/dd/yyyy'
470      * because the month isn't two digits. If no datePattern variable is
471      * specified, then the field gets the DateFormat.SHORT format for the
472      * locale. The setLenient method is set to <code>false</code> for all
473      * variations.  If the <code>object</code> is a date instance, then validation is not performed.
474      *
475      * @param context the faces context
476      * @param object the value of the field being validated.
477      * @param parameters Any field parameters from the validation.xml.
478      * @param errors The <code>Map</code> object to add errors to if any
479      *        validation errors occur.
480      * @param action The <code>ValidatorAction</code> that is currently being
481      *        performed.
482      * @param field The <code>Field</code> object associated with the current
483      *        field being validated.
484      */
485     public static void validateDate(
486         FacesContext context,
487         Object object,
488         Map parameters,
489         Collection errors,
490         ValidatorAction action,
491         Field field)
492     {
493         // - only validate if the object is not already a date or calendar
494         if (!(object instanceof Date) && ! (object instanceof Calendar))
495         {
496             Date result = null;
497             String value = ObjectUtils.toString(object);
498             String datePattern = field.getVarValue("datePattern");
499             String datePatternStrict = field.getVarValue("datePatternStrict");
500             Locale locale = Locale.getDefault();
501 
502             if (StringUtils.isNotBlank(value))
503             {
504                 if (StringUtils.isNotBlank(datePattern))
505                 {
506                     result = GenericTypeValidator.formatDate(
507                             value,
508                             datePattern,
509                             false);
510                 }
511                 else if (StringUtils.isNotBlank(datePatternStrict))
512                 {
513                     result = GenericTypeValidator.formatDate(
514                             value,
515                             datePatternStrict,
516                             true);
517                 }
518                 else
519                 {
520                     result = GenericTypeValidator.formatDate(
521                             value,
522                             locale);
523                 }
524                 if (result == null)
525                 {
526                     errors.add(ValidatorMessages.getMessage(
527                             action,
528                             field,
529                             context));
530                 }
531             }
532         }
533     }
534 
535     /**
536      * Checks if a fields value is within a range (min &amp; max specified in
537      * the vars attribute).
538      *
539      * @param context the faces context
540      * @param object the value of the field being validated.
541      * @param parameters Any field parameters from the validation.xml.
542      * @param errors The <code>Map</code> object to add errors to if any
543      *        validation errors occur.
544      * @param action The <code>ValidatorAction</code> that is currently being
545      *        performed.
546      * @param field The <code>Field</code> object associated with the current
547      *        field being validated.
548      */
549     public static void validateLongRange(
550         FacesContext context,
551         Object object,
552         Map parameters,
553         Collection errors,
554         ValidatorAction action,
555         Field field)
556     {
557         final String value = ObjectUtils.toString(object);
558         if (StringUtils.isNotBlank(value))
559         {
560             try
561             {
562                 long intValue = Long.parseLong(value);
563                 long min = Long.parseLong(field.getVarValue("min"));
564                 long max = Long.parseLong(field.getVarValue("max"));
565 
566                 if (!GenericValidator.isInRange(
567                         intValue,
568                         min,
569                         max))
570                 {
571                     errors.add(ValidatorMessages.getMessage(
572                             action,
573                             field,
574                             context));
575                 }
576             }
577             catch (Exception exception)
578             {
579                 errors.add(ValidatorMessages.getMessage(
580                         action,
581                         field,
582                         context));
583             }
584         }
585     }
586 
587     /**
588      * Checks if a fields value is within a range (min &amp; max specified in
589      * the vars attribute).
590      *
591      * @param context the faces context
592      * @param object the value of the field being validated.
593      * @param parameters Any field parameters from the validation.xml.
594      * @param errors The <code>Map</code> object to add errors to if any
595      *        validation errors occur.
596      * @param action The <code>ValidatorAction</code> that is currently being
597      *        performed.
598      * @param field The <code>Field</code> object associated with the current
599      *        field being validated.
600      */
601     public static void validateDoubleRange(
602         FacesContext context,
603         Object object,
604         Map parameters,
605         Collection errors,
606         ValidatorAction action,
607         Field field)
608     {
609         final String value = ObjectUtils.toString(object);
610         if (StringUtils.isNotBlank(value))
611         {
612             try
613             {
614                 double doubleValue = Double.parseDouble(value);
615                 double min = Double.parseDouble(field.getVarValue("min"));
616                 double max = Double.parseDouble(field.getVarValue("max"));
617 
618                 if (!GenericValidator.isInRange(
619                         doubleValue,
620                         min,
621                         max))
622                 {
623                     errors.add(ValidatorMessages.getMessage(
624                             action,
625                             field,
626                             context));
627                 }
628             }
629             catch (Exception exception)
630             {
631                 errors.add(ValidatorMessages.getMessage(
632                         action,
633                         field,
634                         context));
635             }
636         }
637     }
638 
639     /**
640      * Checks if a fields value is within a range (min &amp; max specified in
641      * the vars attribute).
642      *
643      * @param context the faces context
644      * @param object the value of the field being validated.
645      * @param parameters Any field parameters from the validation.xml.
646      * @param errors The <code>Map</code> object to add errors to if any
647      *        validation errors occur.
648      * @param action The <code>ValidatorAction</code> that is currently being
649      *        performed.
650      * @param field The <code>Field</code> object associated with the current
651      *        field being validated.
652      */
653     public static void validateFloatRange(
654         FacesContext context,
655         Object object,
656         Map parameters,
657         Collection errors,
658         ValidatorAction action,
659         Field field)
660     {
661         final String value = ObjectUtils.toString(object);
662         if (StringUtils.isNotBlank(value))
663         {
664             try
665             {
666                 float floatValue = Float.parseFloat(value);
667                 float min = Float.parseFloat(field.getVarValue("min"));
668                 float max = Float.parseFloat(field.getVarValue("max"));
669 
670                 if (!GenericValidator.isInRange(
671                         floatValue,
672                         min,
673                         max))
674                 {
675                     errors.add(ValidatorMessages.getMessage(
676                             action,
677                             field,
678                             context));
679                 }
680             }
681             catch (Exception exception)
682             {
683                 errors.add(ValidatorMessages.getMessage(
684                         action,
685                         field,
686                         context));
687             }
688         }
689     }
690 
691     /**
692      * Checks if the field is a valid credit card number.
693      *
694      * @param context the faces context
695      * @param object the value of the field being validated.
696      * @param parameters Any field parameters from the validation.xml.
697      * @param errors The <code>Map</code> object to add errors to if any
698      *        validation errors occur.
699      * @param action The <code>ValidatorAction</code> that is currently being
700      *        performed.
701      * @param field The <code>Field</code> object associated with the current
702      *        field being validated.
703      */
704     public static void validateCreditCard(
705         FacesContext context,
706         Object object,
707         Map parameters,
708         Collection errors,
709         ValidatorAction action,
710         Field field)
711     {
712         Long result = null;
713         final String value = ObjectUtils.toString(object);
714         if (StringUtils.isNotBlank(value))
715         {
716             result = GenericTypeValidator.formatCreditCard(value);
717 
718             if (result == null)
719             {
720                 errors.add(ValidatorMessages.getMessage(
721                         action,
722                         field,
723                         context));
724             }
725         }
726     }
727 
728     /**
729      * Checks if a field has a valid exception-mail address.
730      *
731      * @param context the faces context
732      * @param object the value of the field being validated.
733      * @param parameters Any field parameters from the validation.xml.
734      * @param errors The <code>Map</code> object to add errors to if any
735      *        validation errors occur.
736      * @param action The <code>ValidatorAction</code> that is currently being
737      *        performed.
738      * @param field The <code>Field</code> object associated with the current
739      *        field being validated.
740      */
741     public static void validateEmail(
742         FacesContext context,
743         Object object,
744         Map parameters,
745         Collection errors,
746         ValidatorAction action,
747         Field field)
748     {
749         final String value = ObjectUtils.toString(object);
750         if (StringUtils.isNotBlank(value) && !GenericValidator.isEmail(value))
751         {
752             errors.add(ValidatorMessages.getMessage(
753                     action,
754                     field,
755                     context));
756         }
757     }
758 
759     /**
760      * Checks if the field's length is less than or equal to the maximum value.
761      * A <code>Null</code> will be considered an error.
762      *
763      * @param context the faces context
764      * @param object the value of the field being validated.
765      * @param parameters Any field parameters from the validation.xml.
766      * @param errors The <code>Map</code> object to add errors to if any
767      *        validation errors occur.
768      * @param action The <code>ValidatorAction</code> that is currently being
769      *        performed.
770      * @param field The <code>Field</code> object associated with the current
771      *        field being validated.
772      */
773     public static void validateMaxLength(
774         FacesContext context,
775         Object object,
776         Map parameters,
777         Collection errors,
778         ValidatorAction action,
779         Field field)
780     {
781         final String value = ObjectUtils.toString(object);
782         if (StringUtils.isNotBlank(value))
783         {
784             try
785             {
786                 int max = Integer.parseInt(field.getVarValue("maxlength"));
787 
788                 if (!GenericValidator.maxLength(
789                         value,
790                         max))
791                 {
792                     errors.add(ValidatorMessages.getMessage(
793                             action,
794                             field,
795                             context));
796                 }
797             }
798             catch (Exception exception)
799             {
800                 errors.add(ValidatorMessages.getMessage(
801                         action,
802                         field,
803                         context));
804             }
805         }
806     }
807 
808     /**
809      * Checks if the field's length is greater than or equal to the minimum
810      * value. A <code>Null</code> will be considered an error.
811      *
812      * @param context the faces context
813      * @param object the value of the field being validated.
814      * @param parameters Any field parameters from the validation.xml.
815      * @param errors The <code>Map</code> object to add errors to if any
816      *        validation errors occur.
817      * @param action The <code>ValidatorAction</code> that is currently being
818      *        performed.
819      * @param field The <code>Field</code> object associated with the current
820      *        field being validated.
821      */
822     public static void validateMinLength(
823         FacesContext context,
824         Object object,
825         Map parameters,
826         Collection errors,
827         ValidatorAction action,
828         Field field)
829     {
830         String value = ObjectUtils.toString(object);
831         if (!StringUtils.isBlank(value))
832         {
833             try
834             {
835                 int min = Integer.parseInt(field.getVarValue("minlength"));
836                 if (!GenericValidator.minLength(
837                         value,
838                         min))
839                 {
840                     errors.add(ValidatorMessages.getMessage(
841                             action,
842                             field,
843                             context));
844                 }
845             }
846             catch (Exception exception)
847             {
848                 errors.add(ValidatorMessages.getMessage(
849                         action,
850                         field,
851                         context));
852             }
853         }
854     }
855 
856     /**
857      * <p>
858      * Validates whether the URL string passed in is a valid URL or not. Does
859      * this by attempting to construct a java.net.URL instance and checking
860      * whether or not, it's valid.
861      * </p>
862      *
863      * @param context the faces context
864      * @param object the value of the field being validated.
865      * @param parameters Any field parameters from the validation.xml.
866      * @param errors The <code>Map</code> object to add errors to if any
867      *        validation errors occur.
868      * @param action The <code>ValidatorAction</code> that is currently being
869      *        performed.
870      * @param field The <code>Field</code> object associated with the current
871      *        field being validated.
872      */
873     @SuppressWarnings("unused")
874     public static void validateUrl(
875         FacesContext context,
876         Object object,
877         Map parameters,
878         Collection errors,
879         ValidatorAction action,
880         Field field)
881     {
882         boolean valid = true;
883         String urlString = ObjectUtils.toString(object);
884         try
885         {
886             new URL(urlString);
887         }
888         catch (Exception exception)
889         {
890             valid = false;
891         }
892         if (!valid)
893         {
894             errors.add(ValidatorMessages.getMessage(
895                     action,
896                     field,
897                     context));
898         }
899     }
900 
901     /**
902      *  Checks if the field is a valid time. If the field has a timePattern variable,
903      *  that will be used to format <code>java.text.SimpleDateFormat</code>.
904      *
905      * @param context the faces context
906      * @param object the value of the field being validated.
907      * @param parameters Any field parameters from the validation.xml.
908      * @param errors The <code>Map</code> object to add errors to if any
909      *        validation errors occur.
910      * @param action The <code>ValidatorAction</code> that is currently being
911      *        performed.
912      * @param field The <code>Field</code> object associated with the current
913      *        field being validated.
914      */
915     public static void validateTime(
916         FacesContext context,
917         Object object,
918         Map parameters,
919         Collection errors,
920         ValidatorAction action,
921         Field field)
922     {
923         // - only validate if the object is not already a date
924         if (!(object instanceof Date) && !(object instanceof Calendar))
925         {
926             final String value = ObjectUtils.toString(object);
927             final String timePattern = field.getVarValue("timePattern");
928 
929             if (StringUtils.isNotBlank(value))
930             {
931                 try
932                 {
933                     if (StringUtils.isNotBlank(timePattern))
934                     {
935                         final java.text.DateFormat timeFormatter = new SimpleDateFormat(timePattern);
936                         timeFormatter.parse(value);
937                     }
938                     else
939                     {
940                         DateFormat.getTimeInstance().parse(value);
941                     }
942                 }
943                 catch (Exception exception)
944                 {
945                     errors.add(ValidatorMessages.getMessage(
946                             action,
947                             field,
948                             context));
949                 }
950             }
951         }
952     }
953 
954     /**
955      *  Checks if the field's value is equal to another field's value on the same form.
956      *
957      * @param context the faces context
958      * @param object the value of the field being validated.
959      * @param parameters Any field parameters from the validation.xml.
960      * @param errors The <code>Map</code> object to add errors to if any
961      *        validation errors occur.
962      * @param action The <code>ValidatorAction</code> that is currently being
963      *        performed.
964      * @param field The <code>Field</code> object associated with the current
965      *        field being validated.
966      * @throws Exception
967      */
968     public static void validateEqual(
969         FacesContext context,
970         Object object,
971         Map parameters,
972         Collection errors,
973         ValidatorAction action,
974         Field field) throws Exception
975     {
976         final String value = ObjectUtils.toString(object);
977         if (StringUtils.isNotBlank(value))
978         {
979             final String equalFieldName = field.getVarValue("fieldName");
980             final EditableValueHolder equalField = (EditableValueHolder)findComponent(context, equalFieldName);
981             final Object equalFieldValue = equalField.getSubmittedValue() != null ? equalField.getSubmittedValue() : equalField.getValue();
982 
983             if (equalFieldValue != null && !equalFieldValue.equals(value))
984             {
985                 errors.add(ValidatorMessages.getMessage(
986                     action,
987                     field,
988                     context));
989             }
990 
991         }
992     }
993 
994     /**
995      * @param context
996      * @param componentId
997      * @return component
998      * @throws ValidatorException
999      */
1000     public static UIComponent findComponent(final FacesContext context, final String componentId)
1001         throws ValidatorException
1002     {
1003         UIComponent component = null;
1004         final int index = componentId.indexOf(':');
1005         if (index != -1)
1006         {
1007             final String parentId = componentId.substring(0, index);
1008             UIComponent parent = context.getViewRoot().findComponent(parentId);
1009             if (parent == null)
1010             {
1011                 throw new ValidatorException("No component with id: " + parentId + " could be found on view!");
1012             }
1013             final String restOfId = componentId.substring(index + 1, componentId.length());
1014             component = findComponent(context, parent, restOfId);
1015         }
1016         return component;
1017     }
1018 
1019     private static final char COMPONENT_NAME_SEPARATOR = ':';
1020 
1021     /**
1022      * @param context
1023      * @param parent
1024      * @param componentId
1025      * @return component
1026      */
1027     public static UIComponent findComponent(final FacesContext context, final UIComponent parent, String componentId)
1028     {
1029         UIComponent component = null;
1030         final int index = componentId.indexOf(COMPONENT_NAME_SEPARATOR);
1031         if (index != -1)
1032         {
1033             final String firstId = componentId.substring(0, index);
1034             component = findChildComponent(parent, firstId);
1035             componentId = componentId.substring(index + 1, componentId.length());
1036         }
1037         else if (StringUtils.isNotBlank(componentId))
1038         {
1039             component = findChildComponent(parent, componentId);
1040         }
1041         if (component != null && componentId.indexOf(COMPONENT_NAME_SEPARATOR) != -1)
1042         {
1043             component = findComponent(context, component, componentId);
1044         }
1045         return component;
1046     }
1047 
1048     /**
1049      * @param component
1050      * @param id
1051      * @return child
1052      */
1053     public static UIComponent findChildComponent(final UIComponent component, final String id)
1054     {
1055         UIComponent child = null;
1056         if (component != null)
1057         {
1058             if (component.getId().equals(id))
1059             {
1060                 child = component;
1061             }
1062             else
1063             {
1064                 for (final Iterator iterator = component.getFacetsAndChildren(); iterator.hasNext();)
1065                 {
1066                     child = findChildComponent((UIComponent)iterator.next(), id);
1067                     if (child != null)
1068                     {
1069                         break;
1070                     }
1071                 }
1072             }
1073         }
1074         return child;
1075     }
1076 }