View Javadoc
1   package org.andromda.cartridges.jsf.converters;
2   
3   import java.text.DateFormat;
4   import java.text.SimpleDateFormat;
5   import java.util.Calendar;
6   import java.util.Date;
7   import java.util.TimeZone;
8   import javax.faces.component.UIComponent;
9   import javax.faces.context.FacesContext;
10  import javax.faces.convert.ConverterException;
11  import javax.faces.el.ValueBinding;
12  import org.apache.myfaces.custom.calendar.HtmlCalendarRenderer.DateConverter;
13  
14  /**
15   * Overrides the default DateTimeConverter to include conversion of Calendar
16   * instances as well as Date instances.
17   *
18   * <p>
19   * Unfortunately because of poor design in myfaces's calendar component, we have to implement
20   * DateConverter so that we can correctly convert to a date in the inputCalendar implementation.
21   * </p>
22   *
23   * @author Chad Brandon
24   */
25  public class JSFDateTimeConverter
26      extends javax.faces.convert.DateTimeConverter
27      implements DateConverter
28  {
29      /**
30       * @see javax.faces.convert.DateTimeConverter#getAsString(javax.faces.context.FacesContext, javax.faces.component.UIComponent, java.lang.Object)
31       * @throws ConverterException
32       */
33      @Override
34      public String getAsString(
35          FacesContext context,
36          UIComponent component,
37          Object value)
38      {
39          if (value instanceof Calendar)
40          {
41              // - if the time zone is not explicitly set, use the one from the calendar
42              if (!this.timeZoneIsSet)
43              {
44                  // - use the time zone from the calendar
45                  this.setTimeZone(((Calendar)value).getTimeZone());
46              }
47              value = ((Calendar)value).getTime();
48          }
49          final String pattern = this.getPattern();
50          String result = null;
51          if (value != null && pattern != null && pattern.trim().length() > 0)
52          {
53              DateFormat format = new SimpleDateFormat(pattern);
54              format.setTimeZone(this.getTimeZone());
55              result = format.format((Date)value);
56          }
57          return result;
58      }
59  
60      /**
61       * @see javax.faces.convert.DateTimeConverter#getAsObject(javax.faces.context.FacesContext, javax.faces.component.UIComponent, String)
62       */
63      @Override
64      public Object getAsObject(
65          FacesContext context,
66          UIComponent component,
67          String value)
68          throws ConverterException
69      {
70          Object asObject = null;
71          final Class componentType = this.getComponentType(
72                  context,
73                  component);
74          if (componentType != null)
75          {
76              asObject = super.getAsObject(
77                      context,
78                      component,
79                      value);
80              if (Calendar.class.isAssignableFrom(componentType) && asObject instanceof Date)
81              {
82                  final Calendar calendar = Calendar.getInstance();
83                  calendar.setTimeZone(this.getTimeZone());
84                  calendar.setTime((Date)asObject);
85                  asObject = calendar;
86              }
87          }
88          return asObject;
89      }
90  
91      /**
92       * Gets the component type for the given <code>component</code>.
93       * @param context the current faces context.
94       * @param component the component from which to retrieve the type.
95       * @return true/false
96       */
97      protected Class getComponentType(
98          final FacesContext context,
99          final UIComponent component)
100     {
101         Class type = null;
102         final ValueBinding binding = component.getValueBinding("value");
103         if (binding != null)
104         {
105             type = binding.getType(context);
106         }
107         return type;
108     }
109 
110     /**
111      * Gets the component Value for the given <code>component</code>.
112      * @param context the current faces context.
113      * @param component the component from which to retrieve the value.
114      * @return true/false
115      */
116     protected Object getComponentValue(
117         final FacesContext context,
118         final UIComponent component)
119     {
120         Object value = null;
121         final ValueBinding binding = component.getValueBinding("value");
122         if (binding != null)
123         {
124             value = binding.getValue(context);
125         }
126         return value;
127     }
128 
129     private TimeZone timeZone;
130 
131     /**
132      * @see #getTimeZone()
133      */
134     @Override
135     public void restoreState(FacesContext facesContext, Object state)
136     {
137         super.restoreState(facesContext, state);
138         Object[] values = (Object[])state;
139         this.timeZone = (TimeZone)values[4];
140     }
141 
142     /**
143      * @see #getTimeZone()
144      */
145     @Override
146     public Object saveState(FacesContext facesContext)
147     {
148         Object[] values = (Object[])super.saveState(facesContext);
149         values[4] = this.timeZone;
150         return values;
151     }
152 
153     /**
154      * Keeps track of whether or not the time zone was explicitly set.
155      */
156     private boolean timeZoneIsSet;
157 
158     /**
159      * @see #getTimeZone()
160      */
161     @Override
162     public void setTimeZone(TimeZone timeZone)
163     {
164         this.timeZone = timeZone;
165         this.timeZoneIsSet = true;
166     }
167 
168     /**
169      * Overridden because the default timeZone is set as GMT, whereas it should be the default
170      * for the operating system.
171      */
172     @Override
173     public TimeZone getTimeZone()
174     {
175         return this.timeZone == null ? TimeZone.getDefault() : this.timeZone;
176     }
177 
178     /**
179      * andromda.faces.DateTime
180      */
181     public static final String CONVERTER_ID = "andromda.faces.DateTime";
182 
183     /**
184      * @see org.apache.myfaces.custom.calendar.HtmlCalendarRenderer.DateConverter
185      * #getAsDate(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
186      */
187     @Override
188     public Date getAsDate(
189         FacesContext context,
190         UIComponent component)
191     {
192         Object value = this.getComponentValue(
193                 context,
194                 component);
195         if (value instanceof Calendar)
196         {
197             value = ((Calendar)value).getTime();
198         }
199         return (Date)value;
200     }
201 }