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 javax.faces.convert;
20  
21  import java.text.DateFormat;
22  import java.text.ParseException;
23  import java.text.SimpleDateFormat;
24  import java.util.Date;
25  import java.util.Locale;
26  import java.util.TimeZone;
27  
28  import javax.faces.component.PartialStateHolder;
29  import javax.faces.component.UIComponent;
30  import javax.faces.context.FacesContext;
31  
32  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
33  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
34  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
35  
36  /**
37   * This tag associates a date time converter with the nearest parent UIComponent.
38   * 
39   * Unless otherwise specified, all attributes accept static values or EL expressions.
40   * 
41   * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
42   *
43   * @author Thomas Spiegl (latest modification by $Author: struberg $)
44   * @version $Revision: 1188415 $ $Date: 2011-10-24 17:13:21 -0500 (Mon, 24 Oct 2011) $
45   */
46  @JSFConverter(
47      name="f:convertDateTime",
48      bodyContent="empty",
49      tagClass="org.apache.myfaces.taglib.core.ConvertDateTimeTag")
50  @JSFJspProperty(
51      name="binding", 
52      returnType = "javax.faces.convert.DateTimeConverter",
53      longDesc = "A ValueExpression that evaluates to a DateTimeConverter.")
54  public class DateTimeConverter
55          implements Converter, PartialStateHolder
56  {
57  
58      // API field
59      public static final String CONVERTER_ID = "javax.faces.DateTime";
60      public static final String DATE_ID = "javax.faces.converter.DateTimeConverter.DATE";
61      public static final String DATETIME_ID = "javax.faces.converter.DateTimeConverter.DATETIME";
62      public static final String STRING_ID = "javax.faces.converter.STRING";
63      public static final String TIME_ID = "javax.faces.converter.DateTimeConverter.TIME";
64  
65      // internal constants
66      private static final String TYPE_DATE = "date";
67      private static final String TYPE_TIME = "time";
68      private static final String TYPE_BOTH = "both";
69      private static final String STYLE_DEFAULT = "default";
70      private static final String STYLE_MEDIUM = "medium";
71      private static final String STYLE_SHORT = "short";
72      private static final String STYLE_LONG = "long";
73      private static final String STYLE_FULL = "full";
74      private static final TimeZone TIMEZONE_DEFAULT = TimeZone.getTimeZone("GMT");
75  
76      private String _dateStyle;
77      private Locale _locale;
78      private String _pattern;
79      private String _timeStyle;
80      private TimeZone _timeZone;
81      private String _type;
82      private boolean _transient;
83  
84      // CONSTRUCTORS
85      public DateTimeConverter()
86      {
87      }
88  
89      // METHODS
90      public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
91      {
92          if (facesContext == null)
93          {
94              throw new NullPointerException("facesContext");
95          }
96          if (uiComponent == null)
97          {
98              throw new NullPointerException("uiComponent");
99          }
100 
101         if (value != null)
102         {
103             value = value.trim();
104             if (value.length() > 0)
105             {
106                 DateFormat format = getDateFormat();
107                 TimeZone tz = getTimeZone();
108                 if( tz != null )
109                 {
110                     format.setTimeZone(tz);
111                 }
112                 try
113                 {
114                     return format.parse(value);
115                 }
116                 catch (ParseException e)
117                 {
118                     String type = getType();
119                     Object[] args = new Object[]{value,
120                             format.format(new Date()),_MessageUtils.getLabel(facesContext, uiComponent)};
121                     
122                     if(type.equals(TYPE_DATE))
123                     {
124                         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, DATE_ID, args));
125                     }
126                     else if (type.equals(TYPE_TIME))
127                     {
128                         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, TIME_ID, args));
129                     }
130                     else if (type.equals(TYPE_BOTH))
131                     {
132                         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, DATETIME_ID, args));
133                     }
134                     else
135                     {
136                         throw new ConverterException("invalid type '" + _type + "'");
137                     }
138                 }
139             }
140         }
141         return null;
142     }
143 
144     public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
145     {
146         if (facesContext == null)
147         {
148             throw new NullPointerException("facesContext");
149         }
150         if (uiComponent == null)
151         {
152             throw new NullPointerException("uiComponent");
153         }
154 
155         if (value == null)
156         {
157             return "";
158         }
159         if (value instanceof String)
160         {
161             return (String)value;
162         }
163 
164         DateFormat format = getDateFormat();
165         TimeZone tz = getTimeZone(); 
166         if (tz != null)
167         {
168             format.setTimeZone(tz);
169         }
170         try
171         {
172             return format.format(value);
173         }
174         catch (Exception e)
175         {
176             throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, STRING_ID,
177                     new Object[]{value,_MessageUtils.getLabel(facesContext, uiComponent)}),e);
178         }
179     }
180 
181     private DateFormat getDateFormat()
182     {
183         String type = getType();
184         DateFormat format;
185         if (_pattern != null)
186         {
187             try 
188             {
189                 format = new SimpleDateFormat(_pattern, getLocale());
190             } 
191                 catch (IllegalArgumentException iae)
192             {
193                 throw new ConverterException("Invalid pattern", iae);    
194             }
195         }
196         else if (type.equals(TYPE_DATE))
197         {
198             format = DateFormat.getDateInstance(calcStyle(getDateStyle()), getLocale());
199         }
200         else if (type.equals(TYPE_TIME))
201         {
202             format = DateFormat.getTimeInstance(calcStyle(getTimeStyle()), getLocale());
203         }
204         else if (type.equals(TYPE_BOTH))
205         {
206             format = DateFormat.getDateTimeInstance(calcStyle(getDateStyle()),
207                                                     calcStyle(getTimeStyle()),
208                                                     getLocale());
209         }
210         else
211         {
212             throw new ConverterException("invalid type '" + _type + "'");
213         }
214         
215         // format cannot be lenient (JSR-127)
216         format.setLenient(false);
217         return format;
218     }
219 
220     private int calcStyle(String name)
221     {
222         if (name.equals(STYLE_DEFAULT))
223         {
224             return DateFormat.DEFAULT;
225         }
226         if (name.equals(STYLE_MEDIUM))
227         {
228             return DateFormat.MEDIUM;
229         }
230         if (name.equals(STYLE_SHORT))
231         {
232             return DateFormat.SHORT;
233         }
234         if (name.equals(STYLE_LONG))
235         {
236             return DateFormat.LONG;
237         }
238         if (name.equals(STYLE_FULL))
239         {
240             return DateFormat.FULL;
241         }
242 
243         throw new ConverterException("invalid style '" + name + "'");
244     }
245 
246     // STATE SAVE/RESTORE
247     public void restoreState(FacesContext facesContext, Object state)
248     {
249         if (state != null)
250         {
251             Object[] values = (Object[])state;
252             _dateStyle = (String)values[0];
253             _locale = (Locale)values[1];
254             _pattern = (String)values[2];
255             _timeStyle = (String)values[3];
256             _timeZone = (TimeZone)values[4];
257             _type = (String)values[5];
258         }
259     }
260 
261     public Object saveState(FacesContext facesContext)
262     {
263         if (!initialStateMarked())
264         {
265             Object[] values = new Object[6];
266             values[0] = _dateStyle;
267             values[1] = _locale;
268             values[2] = _pattern;
269             values[3] = _timeStyle;
270             values[4] = _timeZone;
271             values[5] = _type;
272             return values;
273         }
274         return null;
275     }
276 
277     // GETTER & SETTER
278     
279     /**
280      * The style of the date.  Values include: default, short, medium, 
281      * long, and full.
282      * 
283      */
284     @JSFProperty
285     public String getDateStyle()
286     {
287         return _dateStyle != null ? _dateStyle : STYLE_DEFAULT;
288     }
289 
290     public void setDateStyle(String dateStyle)
291     {
292         //TODO: validate timeStyle
293         _dateStyle = dateStyle;
294         clearInitialState();
295     }
296 
297     /**
298      * The name of the locale to be used, instead of the default.
299      * 
300      */
301     @JSFProperty
302     public Locale getLocale()
303     {
304         if (_locale != null)
305         {
306             return _locale;
307         }
308         FacesContext context = FacesContext.getCurrentInstance();
309         return context.getViewRoot().getLocale();
310     }
311 
312     public void setLocale(Locale locale)
313     {
314         _locale = locale;
315         clearInitialState();
316     }
317 
318     /**
319      * A custom Date formatting pattern, in the format used by java.text.SimpleDateFormat.
320      * 
321      */
322     @JSFProperty
323     public String getPattern()
324     {
325         return _pattern;
326     }
327 
328     public void setPattern(String pattern)
329     {
330         _pattern = pattern;
331         clearInitialState();
332     }
333 
334     /**
335      * The style of the time.  Values include:  default, short, medium, long, 
336      * and full.
337      * 
338      */
339     @JSFProperty
340     public String getTimeStyle()
341     {
342         return _timeStyle != null ? _timeStyle : STYLE_DEFAULT;
343     }
344 
345     public void setTimeStyle(String timeStyle)
346     {
347         //TODO: validate timeStyle
348         _timeStyle = timeStyle;
349         clearInitialState();
350     }
351 
352     /**
353      * The time zone to use instead of GMT (the default timezone). When
354      * this value is a value-binding to a TimeZone instance, that
355      * timezone is used. Otherwise this value is treated as a String
356      * containing a timezone id, ie as the ID parameter of method
357      * java.util.TimeZone.getTimeZone(String).
358      * 
359      */
360     @JSFProperty
361     public TimeZone getTimeZone()
362     {
363         return _timeZone != null ? _timeZone : TIMEZONE_DEFAULT;
364     }
365 
366     public void setTimeZone(TimeZone timeZone)
367     {
368         _timeZone = timeZone;
369         clearInitialState();
370     }
371 
372     public boolean isTransient()
373     {
374         return _transient;
375     }
376 
377     public void setTransient(boolean aTransient)
378     {
379         _transient = aTransient;
380     }
381 
382     /**
383      * Specifies whether the date, time, or both should be 
384      * parsed/formatted.  Values include:  date, time, and both.
385      * Default based on setting of timeStyle and dateStyle.
386      * 
387      */
388     @JSFProperty
389     public String getType()
390     {
391         return _type != null ? _type : TYPE_DATE;
392     }
393 
394     public void setType(String type)
395     {
396         //TODO: validate type
397         _type = type;
398         clearInitialState();
399     }
400     
401     private boolean _initialStateMarked = false;
402 
403     public void clearInitialState()
404     {
405         _initialStateMarked = false;
406     }
407 
408     public boolean initialStateMarked()
409     {
410         return _initialStateMarked;
411     }
412 
413     public void markInitialState()
414     {
415         _initialStateMarked = true;
416     }
417 }