View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  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,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.validator;
20  
21  import java.util.Date;
22  
23  import javax.el.ValueExpression;
24  
25  import javax.faces.application.FacesMessage;
26  import javax.faces.component.StateHolder;
27  import javax.faces.component.UIComponent;
28  import javax.faces.component.ValueHolder;
29  import javax.faces.context.FacesContext;
30  import javax.faces.convert.Converter;
31  import javax.faces.convert.DateTimeConverter;
32  import javax.faces.el.ValueBinding;
33  import javax.faces.validator.Validator;
34  import javax.faces.validator.ValidatorException;
35  
36  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
37  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFValidator;
38  import org.apache.myfaces.trinidad.bean.FacesBean;
39  import org.apache.myfaces.trinidad.bean.PropertyKey;
40  import org.apache.myfaces.trinidad.util.ComponentUtils;
41  import org.apache.myfaces.trinidad.util.MessageFactory;
42  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
43  
44  
45  /**
46   * <p><strong>DateTimeRangeValidator</strong> is a {@link Validator} that checks
47   * the value of the corresponding component against specified minimum and
48   * maximum dates.  The following algorithm is implemented:</p>
49   * <ul>
50   * <li>If the passed value is <code>null</code>, exit immediately.</li>
51   * <li>If both a <code>maximum</code> and <code>minimum</code> property
52   *     has been configured on this {@link Validator}, check the component
53   *     value against both limits.  If the component value is not within
54   *     this specified range, throw a {@link ValidatorException} containing a
55   *     {@link Validator#NOT_IN_RANGE_MESSAGE_ID} message.</li>
56   * <li>If a <code>maximum</code> property has been configured on this
57   *     {@link Validator}, check the component value against
58   *     this limit.  If the component value is greater than the
59   *     specified maximum, throw a {@link ValidatorException} containing a
60   *     MAXIMUM_MESSAGE_ID message.</li>
61   * <li>If a <code>minimum</code> property has been configured on this
62   *     {@link Validator}, check the component value against
63   *     this limit.  If the component value is less than the
64   *     specified minimum, throw a {@link ValidatorException} containing a
65   *     MINIMUM_MESSAGE_ID message.</li>
66   * </ul>
67   * <p>The detail part of faces message which arise during validation can be
68   * customised by overriding the message associated with each message id by calling
69   * appropriate setter methods.</p>
70   * <p>The methods used for customizing the detail message associated with each id
71   * is given below:</p>
72   * <ul>
73   * <li>{@link #MAXIMUM_MESSAGE_ID} - {@link #setMessageDetailMaximum(String)}</li>
74   * <li>{@link #MINIMUM_MESSAGE_ID} - {@link #setMessageDetailMinimum(String)}</li>
75   * <li>{@link #NOT_IN_RANGE_MESSAGE_ID} - {@link #setMessageDetailNotInRange(String)} - </li></ul>
76   *  Then this message will be used to construct faces message
77   *  when validation fails based on the above-mentioned algorithm
78  
79   * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-api/src/main/java/oracle/adf/view/faces/validator/DateTimeRangeValidator.java#0 $) $Date: 10-nov-2005.19:08:33 $
80   */
81  // TODO The error message date/time reads
82  // "Date cannot be before Mon Feb 16 16:11:13 PST 2004", but the
83  // date should probably be in the format of the converter....
84  @JSFValidator(configExcluded=true)
85  public class DateTimeRangeValidator implements Validator, StateHolder {
86  
87  
88    public static final String VALIDATOR_ID = "org.apache.myfaces.trinidad.DateTimeRange";
89  
90  
91    /**
92     * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
93     * to be created if the maximum value check fails.  The message format
94     * string for this message may optionally include <code>{0}</code>,
95     * <code>{1}</code> and <code>{3}</code> placeholders,
96     * which will be replaced by user input, component label and configured
97     * maximum value.</p>
98     */
99    public static final String MAXIMUM_MESSAGE_ID =
100       "org.apache.myfaces.trinidad.validator.DateTimeRangeValidator.MAXIMUM";
101 
102   /**
103    * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
104    * to be created if the minimum value check fails.  The message format
105    * string for this message may optionally include <code>{0}</code>,
106    * <code>{1}</code> and <code>{2}</code> placeholders, which will be replaced
107    * by user input, component label and configured minimum value.</p>
108    */
109   public static final String MINIMUM_MESSAGE_ID =
110       "org.apache.myfaces.trinidad.validator.DateTimeRangeValidator.MINIMUM";
111 
112 
113   /**
114    * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
115    * to be created if the maximum or minimum value check fails, and both
116    * the maximum and minimum values for this validator have been set.
117    * The message format string for this message may optionally include
118    * <code>{0}</code>, <code>{1}</code>, <code>{2}</code> and <code>{3}</code>
119    * placeholders, which will be replaced by user input, component label,
120    * configured minimum value and configured maximum value.</p>
121    */
122   public static final String NOT_IN_RANGE_MESSAGE_ID =
123       "org.apache.myfaces.trinidad.validator.DateTimeRangeValidator.NOT_IN_RANGE";
124 
125 
126   /**
127    * Construct a {@link Validator} with no preconfigured limits.
128    */
129   public DateTimeRangeValidator()
130   {
131     super();
132   }
133 
134   /**
135    * Construct a {@link Validator} with the specified preconfigured
136    * limit.
137    *
138    * @param maximum Maximum value to allow
139    */
140   public DateTimeRangeValidator(Date maximum)
141   {
142     super();
143     setMaximum(maximum);
144   }
145 
146   /**
147    * Construct a {@link Validator} with the specified preconfigured
148    * limits.
149    *
150    * @param maximum Maximum value to allow
151    * @param minimum Minimum value to allow
152    *
153    */
154   public DateTimeRangeValidator(Date maximum, Date minimum)
155   {
156     super();
157     setMaximum(maximum);
158     setMinimum(minimum);
159   }
160 
161   /**
162    * Return the maximum value to be enforced by this {@link
163    * Validator} or null if it has not been
164    * set.
165    */
166   @JSFProperty
167   public Date getMaximum()
168   {
169     Object maxDate = _facesBean.getProperty(_MAXIMUM_KEY);
170     return ComponentUtils.resolveDate(maxDate);
171   }
172 
173   /**
174    * Set the maximum value to be enforced by this {@link Validator}.
175    *
176    * @param maximum The new maximum value
177    *
178    */
179   public void setMaximum(Date maximum)
180   {
181     _facesBean.setProperty(_MAXIMUM_KEY, maximum);
182   }
183 
184 
185   /**
186    * Return the minimum value to be enforced by this {@link
187    * Validator}, or null if it has not been
188    * set.
189    */
190   @JSFProperty
191   public Date getMinimum()
192   {
193     Object minDate = _facesBean.getProperty(_MINIMUM_KEY);
194     return ComponentUtils.resolveDate(minDate);
195   }
196 
197   /**
198    * Set the minimum value to be enforced by this {@link Validator}.
199    *
200    * @param minimum The new minimum value
201    *
202    */
203   public void setMinimum(Date minimum)
204   {
205     _facesBean.setProperty(_MINIMUM_KEY, minimum);
206   }
207 
208   /**
209    * <p>Custom error message to be used, for creating detail part of the
210    * {@link FacesMessage}, when input value exceeds the maximum value set.</p>
211    * Overrides detail message identified by message id {@link #MAXIMUM_MESSAGE_ID}
212    * @param maximumMessageDetail Custom error message.
213    */
214   public void setMessageDetailMaximum(String maximumMessageDetail)
215   {
216     _facesBean.setProperty(_MAXIMUM_MESSAGE_DETAIL_KEY, maximumMessageDetail);
217   }
218 
219   /**
220    *  <p>Return custom detail error message that was set for creating {@link FacesMessage},
221    *  for cases where input value exceeds the <code>maximum</code> value set.</p>
222    * @return Custom error message.
223    * @see #setMessageDetailMaximum(String)
224    */
225   @JSFProperty
226   public String getMessageDetailMaximum()
227   {
228     Object maxMsgDet = _facesBean.getProperty(_MAXIMUM_MESSAGE_DETAIL_KEY);
229     return ComponentUtils.resolveString(maxMsgDet);
230   }
231 
232   /**
233    * <p>Custom error message to be used, for creating detail part of the
234    * {@link FacesMessage}, when input value is less the set
235    * <code>minimum</code> value.</p>
236    * Overrides detail message identified by message id {@link #MINIMUM_MESSAGE_ID}
237    * @param minimumMessageDetail Custom error message.
238    */
239   public void setMessageDetailMinimum(String minimumMessageDetail)
240   {
241     _facesBean.setProperty(_MINIMUM_MESSAGE_DETAIL_KEY, minimumMessageDetail);
242   }
243 
244   /**
245    * <p>Return custom detail error message that was set for creating {@link FacesMessage},
246    * for cases where, input value is less than the <code>minimum</code> value set.</p>
247    * @return Custom error message.
248    * @see #setMessageDetailMinimum(String)
249    */
250   @JSFProperty
251   public String getMessageDetailMinimum()
252   {
253     Object minMsgDet = _facesBean.getProperty(_MINIMUM_MESSAGE_DETAIL_KEY);
254     return ComponentUtils.resolveString(minMsgDet);
255   }
256 
257   /**
258    * <p>Custom error message to be used, for creating detail part of the
259    * {@link FacesMessage}, when input value is not with in the range,
260    * when <code>minimum</code> and <code>maximum</code> is set.</p>
261    * Overrides detail message identified by message id {@link #NOT_IN_RANGE_MESSAGE_ID}
262    * @param notInRangeMessageDetail Custom error message.
263    */
264   public void setMessageDetailNotInRange(String notInRangeMessageDetail)
265   {
266     _facesBean.setProperty(_NOT_IN_RANGE_MESSAGE_DETAIL_KEY, notInRangeMessageDetail);
267   }
268 
269   /**
270    * <p>Return custom detail error message that was set for creating {@link FacesMessage},
271    * for cases where, input value exceeds the <code>maximum</code> value and is
272    * less than the <code>minimum</code> value set.</p>
273    * @return Custom error message.
274    * @see #setMessageDetailNotInRange(String)
275    */
276   @JSFProperty
277   public String getMessageDetailNotInRange()
278   {
279     Object notInRngMsg = _facesBean.getProperty(_NOT_IN_RANGE_MESSAGE_DETAIL_KEY);
280     return ComponentUtils.resolveString(notInRngMsg);
281   }
282 
283   /**
284    * <p>Custom hint maximum message.</p>
285    * Overrides default hint message
286    * @param hintMaximum Custom hint message.
287    */
288   public void setHintMaximum(String hintMaximum)
289   {
290     _facesBean.setProperty(_HINT_MAXIMUM_KEY, hintMaximum);
291   }
292 
293   /**
294    * <p>Return custom hint maximum message.</p>
295    * @return Custom hint message.
296    * @see  #setHintMaximum(String)
297    */
298   @JSFProperty(tagExcluded=true)
299   public String getHintMaximum()
300   {
301     Object obj = _facesBean.getProperty(_HINT_MAXIMUM_KEY);
302     return ComponentUtils.resolveString(obj);
303   }
304 
305   /**
306    * <p>Custom hint minimum message.</p>
307    * Overrides default hint message
308    * @param hintMinimum Custom hint message.
309    */
310   public void setHintMinimum(String hintMinimum)
311   {
312     _facesBean.setProperty(_HINT_MINIMUM_KEY, hintMinimum);
313   }
314 
315   /**
316    * <p>Return custom hint minimum message.</p>
317    * @return Custom hint message.
318    * @see  #setHintMinimum(String)
319    */
320   @JSFProperty(tagExcluded=true)
321   public String getHintMinimum()
322   {
323     Object obj = _facesBean.getProperty(_HINT_MINIMUM_KEY);
324     return ComponentUtils.resolveString(obj);
325   }
326 
327   /**
328    * <p>Custom hint notInRange message.</p>
329    * Overrides default hint message
330    * @param hintNotInRange Custom hint message.
331    */
332   public void setHintNotInRange(String hintNotInRange)
333   {
334     _facesBean.setProperty(_HINT_NOT_IN_RANGE, hintNotInRange);
335   }
336 
337   /**
338    * <p>Return custom hint notInRange message.</p>
339    * @return Custom hint message.
340    * @see  #setHintNotInRange(String)
341    */
342   @JSFProperty(tagExcluded=true)
343   public String getHintNotInRange()
344   {
345     Object obj = _facesBean.getProperty(_HINT_NOT_IN_RANGE);
346     return ComponentUtils.resolveString(obj);
347   }
348 
349   /**
350    * @exception IllegalArgumentException if <code>value</code> is not of type
351    * {@link java.util.Date}
352    */
353   public void validate(
354     FacesContext context,
355     UIComponent  component,
356     Object       value) throws ValidatorException
357   {
358     if (isDisabled())
359       return;
360     
361     if ((context == null) || (component == null))
362     {
363       throw new NullPointerException(_LOG.getMessage(
364         "NULL_FACESCONTEXT_OR_UICOMPONENT"));
365     }
366 
367     if (value != null)
368     {
369 
370       Date converted = _getDateValue(value);
371 
372       // even after this values can change. But this should be very remote.
373       Date max = getMaximum();
374       Date min = getMinimum();
375       if (max != null && (converted.after(max)))
376       {
377         if (min != null)
378         {
379            throw new ValidatorException
380                       (_getNotInRangeMessage(context, component, value, min, max));
381         }
382         else
383         {
384            throw new ValidatorException
385                       (_getMaximumMessage(context, component, value, max));
386         }
387       }
388 
389       if (min != null && (converted.before(min)))
390       {
391         if (max != null)
392         {
393           throw new ValidatorException
394                       (_getNotInRangeMessage(context, component, value, min, max));
395         }
396         else
397         {
398           FacesMessage msg = _getMinimumMessage(context, component, value, min);
399           throw new ValidatorException(msg);
400         }
401       }
402     }
403   }
404 
405 
406 
407   //  StateHolder Methods
408 
409   public Object saveState(FacesContext context)
410   {
411     return _facesBean.saveState(context);
412   }
413 
414 
415   public void restoreState(FacesContext context, Object state)
416   {
417     _facesBean.restoreState(context, state);
418   }
419 
420 
421   /**
422    * <p>Set the {@link ValueExpression} used to calculate the value for the
423    * specified attribute if any.</p>
424    *
425    * @param name Name of the attribute for which to set a {@link ValueExpression}
426    * @param expression The {@link ValueExpression} to set, or <code>null</code>
427    *  to remove any currently set {@link ValueExpression}
428    *
429    * @exception NullPointerException if <code>name</code>
430    *  is <code>null</code>
431    * @exception IllegalArgumentException if <code>name</code> is not a valid
432    *            attribute of this converter
433    */
434   public void setValueExpression(String name, ValueExpression expression)
435   {
436     ValidatorUtils.setValueExpression(_facesBean, name, expression) ;
437   }
438 
439 
440   /**
441    * <p>Return the {@link ValueExpression} used to calculate the value for the
442    * specified attribute name, if any.</p>
443    *
444    * @param name Name of the attribute or property for which to retrieve a
445    *  {@link ValueExpression}
446    *
447    * @exception NullPointerException if <code>name</code>
448    *  is <code>null</code>
449    * @exception IllegalArgumentException if <code>name</code> is not a valid
450    * attribute of this converter
451    */
452   public ValueExpression getValueExpression(String name)
453   {
454     return ValidatorUtils.getValueExpression(_facesBean, name);
455   }
456 
457 
458   /**
459    * <p>Set the {@link ValueBinding} used to calculate the value for the
460    * specified attribute if any.</p>
461    *
462    * @param name Name of the attribute for which to set a {@link ValueBinding}
463    * @param binding The {@link ValueBinding} to set, or <code>null</code>
464    *  to remove any currently set {@link ValueBinding}
465    *
466    * @exception NullPointerException if <code>name</code>
467    *  is <code>null</code>
468    * @exception IllegalArgumentException if <code>name</code> is not a valid
469    *            attribute of this validator
470    * @deprecated
471    */
472   public void setValueBinding(String name, ValueBinding binding)
473   {
474     ValidatorUtils.setValueBinding(_facesBean, name, binding) ;
475   }
476 
477   /**
478    * <p>Return the {@link ValueBinding} used to calculate the value for the
479    * specified attribute name, if any.</p>
480    *
481    * @param name Name of the attribute or property for which to retrieve a
482    *  {@link ValueBinding}
483    *
484    * @exception NullPointerException if <code>name</code>
485    *  is <code>null</code>
486    * @exception IllegalArgumentException if <code>name</code> is not a valid
487    * attribute of this validator
488    * @deprecated
489    */
490   public ValueBinding getValueBinding(String name)
491   {
492     return ValidatorUtils.getValueBinding(_facesBean, name);
493   }
494 
495   @Override
496   public boolean equals(Object o)
497   {
498     if ( o instanceof DateTimeRangeValidator)
499     {
500       DateTimeRangeValidator that = (DateTimeRangeValidator)o;
501 
502       if ( _transientValue == that._transientValue &&
503            isDisabled() == that.isDisabled() &&
504            (ValidatorUtils.equals(getMinimum(), that.getMinimum())) &&
505            (ValidatorUtils.equals(getMaximum(), that.getMaximum())) &&
506            (ValidatorUtils.equals(getMessageDetailMaximum(),
507                                    that.getMessageDetailMaximum())) &&
508            (ValidatorUtils.equals(getMessageDetailMinimum(),
509                                    that.getMessageDetailMinimum())) &&
510            (ValidatorUtils.equals(getMessageDetailNotInRange(),
511                                    that.getMessageDetailNotInRange()))
512           )
513       {
514         return true;
515       }
516     }
517     return false;
518   }
519 
520   @Override
521   public int hashCode()
522   {
523     int result = 17;
524     Object max = getMaximum();
525     Object min = getMinimum();
526     Object maxMsgDet        =  getMessageDetailMaximum();
527     Object minMsgDet        =  getMessageDetailMinimum();
528     Object notInRangeMsgDet =  getMessageDetailNotInRange();
529 
530     result = 37 * result + ( max == null ? 0 : max.hashCode());
531     result = 37 * result + ( min == null ? 0 : min.hashCode());
532     result = 37 * result + ( _transientValue ? 0 : 1);
533     result = 37 * result + (isDisabled() ? 1 : 0);
534     result = 37 * result + ( maxMsgDet == null ? 0: maxMsgDet.hashCode());
535     result = 37 * result + ( minMsgDet == null ? 0: minMsgDet.hashCode());
536     result = 37 * result + ( notInRangeMsgDet == null ? 0: notInRangeMsgDet.hashCode());
537     return result;
538   }
539 
540   @JSFProperty(istransient=true,tagExcluded=true)
541   public boolean isTransient()
542   {
543     return (_transientValue);
544   }
545 
546   public void setTransient(boolean transientValue)
547   {
548     _transientValue = transientValue;
549   }
550   
551   /**
552     * Return whether it is disabled.
553     * @return true if it's disabled and false if it's enabled. 
554     */ 
555   public void setDisabled(boolean isDisabled)
556   {
557     _facesBean.setProperty(_DISABLED_KEY, Boolean.valueOf(isDisabled));
558   }
559 
560   /**
561     * Return whether it is disabled.
562     * @return true if it's disabled and false if it's enabled. 
563     */  
564   public boolean isDisabled()
565   {
566     Boolean disabled = (Boolean) _facesBean.getProperty(_DISABLED_KEY);
567     
568     return (disabled != null) ? disabled.booleanValue() : false;
569   }    
570 
571   private static Date _getDateValue(
572     Object value) throws IllegalArgumentException
573   {
574     if (value instanceof Date)
575     {
576       return ( (Date)value );
577     }
578 
579     throw new IllegalArgumentException(_LOG.getMessage(
580       "VALUE_IS_NOT_DATE_TYPE"));
581   }
582 
583   private FacesMessage _getNotInRangeMessage(
584     FacesContext context,
585     UIComponent component,
586     Object value,
587     Object min,
588     Object max)
589   { 
590     Converter converter = _getConverter(context, component);
591 
592     Object cValue = _getConvertedValue(context, component, converter, value);
593     Object cMin   = _getConvertedValue(context, component, converter, min);
594     Object cMax   = _getConvertedValue(context, component, converter, max);
595 
596     Object msg   = _getRawNotInRangeMessageDetail();
597     Object label = ValidatorUtils.getComponentLabel(component);
598 
599     Object[] params = {label, cValue, cMin, cMax};
600 
601     return MessageFactory.getMessage(context, NOT_IN_RANGE_MESSAGE_ID,
602                                       msg, params, component);
603   }
604 
605 
606   
607   private Object _getRawNotInRangeMessageDetail()
608   {
609     return _facesBean.getRawProperty(_NOT_IN_RANGE_MESSAGE_DETAIL_KEY);
610   }
611 
612 
613   private FacesMessage _getMaximumMessage(
614     FacesContext context,
615     UIComponent component,
616     Object value,
617     Object max)
618   {
619     Converter converter = _getConverter(context, component);
620 
621     Object cValue = _getConvertedValue(context, component, converter, value);
622     Object cMax   = _getConvertedValue(context, component, converter, max);
623 
624     Object msg   = _getRawMaximumMessageDetail();
625     Object label = ValidatorUtils.getComponentLabel(component);
626 
627     Object[] params = {label, cValue, cMax};
628 
629     return MessageFactory.getMessage(context,
630                                      MAXIMUM_MESSAGE_ID,
631                                      msg,
632                                      params,
633                                      component);
634   }
635 
636   private Object _getRawMaximumMessageDetail()
637   {
638     return _facesBean.getRawProperty(_MAXIMUM_MESSAGE_DETAIL_KEY);
639   }
640 
641   private FacesMessage _getMinimumMessage(
642     FacesContext context,
643     UIComponent component,
644     Object value,
645     Object min)
646   {
647     Converter converter = _getConverter(context, component);
648 
649     Object cValue = _getConvertedValue(context, component, converter, value);
650     Object cMin   = _getConvertedValue(context, component, converter, min);
651 
652 
653     Object msg      = _getRawMinimumMessageDetail();
654     Object label    = ValidatorUtils.getComponentLabel(component);
655 
656     Object[] params = {label, cValue, cMin};
657 
658     return MessageFactory.getMessage(context, MINIMUM_MESSAGE_ID,
659                                      msg, params, component);
660   }
661 
662   private Object _getRawMinimumMessageDetail()
663   {
664     return _facesBean.getRawProperty(_MINIMUM_MESSAGE_DETAIL_KEY);
665   }
666 
667   private Converter _getConverter(
668     FacesContext context,
669     UIComponent component)
670   {
671     Converter converter = null;
672     if (component instanceof ValueHolder)
673     {
674       converter = ((ValueHolder) component).getConverter();
675     }
676 
677     if (converter == null)
678     {
679       // Use the DateTimeConverter's CONVERTER_ID, not Date.class,
680       // because there is in fact not usually a converter registered
681       // at Date.class
682       converter = context.getApplication().createConverter(
683                       DateTimeConverter.CONVERTER_ID);
684     }
685 
686     assert(converter != null);
687 
688     return converter;
689   }
690 
691 
692   private Object _getConvertedValue(
693     FacesContext context,
694     UIComponent  component,
695     Converter    converter,
696     Object       value)
697   {
698     return converter.getAsString(context, component, value);
699   }
700 
701   private static final FacesBean.Type _TYPE = new FacesBean.Type();
702 
703   private static final PropertyKey _MINIMUM_KEY =
704     _TYPE.registerKey("minimum", Date.class);
705 
706   private static final PropertyKey _MAXIMUM_KEY =
707     _TYPE.registerKey("maximum", Date.class );
708 
709   private static final PropertyKey _MAXIMUM_MESSAGE_DETAIL_KEY =
710     _TYPE.registerKey("messageDetailMaximum", String.class);
711 
712   private static final PropertyKey _MINIMUM_MESSAGE_DETAIL_KEY =
713     _TYPE.registerKey("messageDetailMinimum", String.class);
714 
715   private static final PropertyKey _NOT_IN_RANGE_MESSAGE_DETAIL_KEY =
716     _TYPE.registerKey("messageDetailNotInRange", String.class);
717 
718   private static final PropertyKey  _HINT_MAXIMUM_KEY =
719     _TYPE.registerKey("hintMaximum", String.class);
720 
721   private static final PropertyKey  _HINT_MINIMUM_KEY =
722     _TYPE.registerKey("hintMinimum", String.class);
723 
724   private static final PropertyKey  _HINT_NOT_IN_RANGE =
725     _TYPE.registerKey("hintNotInRange", String.class);
726   
727   // Default is false
728   private static final PropertyKey _DISABLED_KEY =
729     _TYPE.registerKey("disabled", Boolean.class, Boolean.FALSE);
730 
731   private FacesBean _facesBean = ValidatorUtils.getFacesBean(_TYPE);
732 
733   private boolean _transientValue = false;
734 
735   private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
736     DateTimeRangeValidator.class);
737 }