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  
20  package org.apache.myfaces.commons.converter;
21  
22  import java.text.DateFormat;
23  import java.text.ParseException;
24  import java.text.SimpleDateFormat;
25  import java.util.Date;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.Locale;
29  import java.util.Map;
30  import java.util.TimeZone;
31  
32  import javax.el.ValueExpression;
33  import javax.faces.application.FacesMessage;
34  import javax.faces.component.UIComponent;
35  import javax.faces.context.FacesContext;
36  import javax.faces.convert.ConverterException;
37  
38  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
39  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
40  import org.apache.myfaces.commons.util.MessageUtils;
41  
42  /**
43   * Simple convert that overrides the spec DateTimeConverter and uses TimeZone.getDefault() as the 
44   * base timezone, rather than GMT.
45   *
46   * Convert date time using normal system timezone like it should
47   *
48   * User: treeder
49   * Date: Oct 28, 2005
50   * Time: 7:19:01 PM
51   */
52  @JSFConverter(
53     name = "mcc:convertDateTime",
54     tagClass = "org.apache.myfaces.commons.converter.ConvertDateTimeTag",
55     tagSuperclass = "org.apache.myfaces.commons.converter.ConverterTag",
56     tagHandler = "org.apache.myfaces.commons.converter.ConvertDateTimeTagHandler",
57     serialuidtag = "1542071733367150635L",
58     evaluateELOnExecution=true)
59  public class DateTimeConverter extends javax.faces.convert.DateTimeConverter
60  {
61      public static final String CONVERTER_ID = "org.apache.myfaces.custom.convertDateTime.DateTimeConverter";
62      
63      // internal constants
64      private static final String TYPE_DATE = "date";
65      private static final String TYPE_TIME = "time";
66      private static final String TYPE_BOTH = "both";
67      private static final String STYLE_DEFAULT = "default";
68      private static final String STYLE_MEDIUM = "medium";
69      private static final String STYLE_SHORT = "short";
70      private static final String STYLE_LONG = "long";
71      private static final String STYLE_FULL = "full";
72      private static final TimeZone TIMEZONE_DEFAULT = TimeZone.getTimeZone("GMT");
73  
74      // CONSTRUCTORS
75      public DateTimeConverter()
76      {
77          //setTimeZone(TimeZone.getDefault());
78      }
79      
80      private String _dateStyle;
81      private Locale _locale;
82      private String _pattern;
83      private String _timeStyle;
84      private TimeZone _timeZone;
85      private String _type;
86      private boolean _transient;
87      
88      private transient FacesContext _facesContext;
89  
90      // METHODS
91      public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
92      {
93          if (facesContext == null) throw new NullPointerException("facesContext");
94          if (uiComponent == null) throw new NullPointerException("uiComponent");
95  
96          if (value != null)
97          {
98              value = value.trim();
99              if (value.length() > 0)
100             {
101                 DateFormat format = getDateFormat();
102                 TimeZone tz = getTimeZone();
103                 if( tz != null )
104                     format.setTimeZone( tz );
105                 try
106                 {
107                     return format.parse(value);
108                 }
109                 catch (ParseException e)
110                 {
111                     String type = getType();
112                     Object[] args = new Object[]{value,format.format(new Date()),MessageUtils.getLabel(facesContext, uiComponent)};
113                     
114                     if(type.equals(TYPE_DATE))
115                         throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR, DATE_ID,args, facesContext));
116                     else if (type.equals(TYPE_TIME))
117                         throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR,TIME_ID,args, facesContext));
118                     else if (type.equals(TYPE_BOTH))
119                         throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR,DATETIME_ID,args, facesContext));
120                     else
121                         throw new ConverterException("invalid type '" + _type + "'");
122                 }
123             }
124         }
125         return null;
126     }
127 
128     public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
129     {
130         if (facesContext == null) throw new NullPointerException("facesContext");
131         if (uiComponent == null) throw new NullPointerException("uiComponent");
132 
133         if (value == null)
134         {
135             return "";
136         }
137         if (value instanceof String)
138         {
139             return (String)value;
140         }
141 
142         DateFormat format = getDateFormat();
143         TimeZone tz = getTimeZone(); 
144         if (tz != null)
145         {
146             format.setTimeZone(tz);
147         }
148         try
149         {
150             return format.format(value);
151         }
152         catch (Exception e)
153         {
154             throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR, STRING_ID, 
155                     new Object[]{value,MessageUtils.getLabel(facesContext, uiComponent)}, facesContext)
156                     ,e);
157         }
158     }
159 
160     private DateFormat getDateFormat()
161     {
162         String type = getType();
163         DateFormat format;
164         if (_pattern != null)
165         {
166             try 
167             {
168                 format = new SimpleDateFormat(_pattern, getLocale());
169             } 
170                 catch (IllegalArgumentException iae)
171             {
172                 throw new ConverterException("Invalid pattern", iae);    
173             }
174         }
175         else if (type.equals(TYPE_DATE))
176         {
177             format = DateFormat.getDateInstance(calcStyle(getDateStyle()), getLocale());
178         }
179         else if (type.equals(TYPE_TIME))
180         {
181             format = DateFormat.getTimeInstance(calcStyle(getTimeStyle()), getLocale());
182         }
183         else if (type.equals(TYPE_BOTH))
184         {
185             format = DateFormat.getDateTimeInstance(calcStyle(getDateStyle()),
186                                                     calcStyle(getTimeStyle()),
187                                                     getLocale());
188         }
189         else
190         {
191             throw new ConverterException("invalid type '" + _type + "'");
192         }
193         
194         // format cannot be lenient (JSR-127)
195         format.setLenient(false);
196         return format;
197     }
198 
199     private int calcStyle(String name)
200     {
201         if (name.equals(STYLE_DEFAULT))
202         {
203             return DateFormat.DEFAULT;
204         }
205         if (name.equals(STYLE_MEDIUM))
206         {
207             return DateFormat.MEDIUM;
208         }
209         if (name.equals(STYLE_SHORT))
210         {
211             return DateFormat.SHORT;
212         }
213         if (name.equals(STYLE_LONG))
214         {
215             return DateFormat.LONG;
216         }
217         if (name.equals(STYLE_FULL))
218         {
219             return DateFormat.FULL;
220         }
221 
222         throw new ConverterException("invalid style '" + name + "'");
223     }
224 
225     // STATE SAVE/RESTORE
226     public void restoreState(FacesContext facesContext, Object state)
227     {
228         if (state != null)
229         {
230             Object[] values = (Object[])state;
231             _dateStyle = (String)values[0];
232             _locale = (Locale)values[1];
233             _pattern = (String)values[2];
234             _timeStyle = (String)values[3];
235             _timeZone = (TimeZone)values[4];
236             _type = (String)values[5];
237             restoreValueExpressionMap(facesContext, values[6]);
238         }
239     }
240 
241     public Object saveState(FacesContext facesContext)
242     {
243         if (!initialStateMarked())
244         {
245             Object[] values = new Object[7];
246             values[0] = _dateStyle;
247             values[1] = _locale;
248             values[2] = _pattern;
249             values[3] = _timeStyle;
250             values[4] = _timeZone;
251             values[5] = _type;
252             values[6] = saveValueExpressionMap(facesContext);
253             return values;
254         }
255         return null;
256     }
257     
258     // --------------------- borrowed from UIComponentBase ------------
259 
260     private Map _valueExpressionMap = null;
261 
262     public ValueExpression getValueExpression(String name)
263     {
264         if (name == null) throw new NullPointerException("name");
265         if (_valueExpressionMap == null)
266         {
267             return null;
268         }
269         else
270         {
271             return (ValueExpression)_valueExpressionMap.get(name);
272         }
273     }
274 
275     public void setValueExpression(String name,
276                                 ValueExpression binding)
277     {
278         if (name == null) throw new NullPointerException("name");
279         if (_valueExpressionMap == null)
280         {
281             _valueExpressionMap = new HashMap();
282         }
283         _valueExpressionMap.put(name, binding);
284         clearInitialState();
285     }
286 
287     private Object saveValueExpressionMap(FacesContext context)
288     {
289         if (_valueExpressionMap != null)
290         {
291             int initCapacity = (_valueExpressionMap.size() * 4 + 3) / 3;
292             HashMap stateMap = new HashMap(initCapacity);
293             for (Iterator it = _valueExpressionMap.entrySet().iterator(); it.hasNext(); )
294             {
295                 Map.Entry entry = (Map.Entry)it.next();
296                 stateMap.put(entry.getKey(),
297                              ConverterBase.saveAttachedState(context, entry.getValue()));
298             }
299             return stateMap;
300         }
301         else
302         {
303             return null;
304         }
305     }
306 
307     private void restoreValueExpressionMap(FacesContext context, Object stateObj)
308     {
309         if (stateObj != null)
310         {
311             Map stateMap = (Map)stateObj;
312             int initCapacity = (stateMap.size() * 4 + 3) / 3;
313             _valueExpressionMap = new HashMap(initCapacity);
314             for (Iterator it = stateMap.entrySet().iterator(); it.hasNext(); )
315             {
316                 Map.Entry entry = (Map.Entry)it.next();
317                 _valueExpressionMap.put(entry.getKey(),
318                         ConverterBase.restoreAttachedState(context, entry.getValue()));
319             }
320         }
321         else
322         {
323             _valueExpressionMap = null;
324         }
325     }
326     protected FacesContext getFacesContext()
327     {
328         if (_facesContext == null)
329         {
330             return FacesContext.getCurrentInstance();
331         }
332         else
333         {
334             return _facesContext;
335         }
336     }
337     
338     boolean isCachedFacesContext()
339     {
340         return _facesContext != null;
341     }
342     
343     void setCachedFacesContext(FacesContext facesContext)
344     {
345         _facesContext = facesContext;
346     }
347     
348 
349     // GETTER & SETTER
350     
351     /**
352      * The style of the date.  Values include: default, short, medium, 
353      * long, and full.
354      * 
355      */
356     @JSFProperty(inheritedTag = false)
357     public String getDateStyle()
358     {
359         if (_dateStyle != null)
360         {
361             return _dateStyle;
362         }
363         ValueExpression vb = getValueExpression("dateStyle");
364         if (vb != null)
365         {
366             return (String) vb.getValue(getFacesContext().getELContext());
367         }
368         return STYLE_DEFAULT;
369     }
370 
371     public void setDateStyle(String dateStyle)
372     {
373         _dateStyle = dateStyle;
374         clearInitialState();
375     }
376 
377     /**
378      * The name of the locale to be used, instead of the default.
379      * 
380      */
381     @JSFProperty(inheritedTag = false,deferredValueType="java.lang.Object")
382     public Locale getLocale()
383     {        
384         if (_locale != null)
385         {
386             return _locale;
387         }
388         ValueExpression vb = getValueExpression("locale");
389         if (vb != null)
390         {
391             Object _localeValue = vb.getValue(getFacesContext().getELContext());
392             if (_localeValue instanceof String)
393             {
394                 _localeValue = org.apache.myfaces.commons.util.TagUtils.getLocale((String)_localeValue);
395             }
396             return (java.util.Locale)_localeValue;
397         }
398         FacesContext context = FacesContext.getCurrentInstance();
399         return context.getViewRoot().getLocale();
400     }
401 
402     public void setLocale(Locale locale)
403     {
404         _locale = locale;
405         clearInitialState();
406     }
407 
408     /**
409      * A custom Date formatting pattern, in the format used by java.text.SimpleDateFormat.
410      * 
411      */
412     @JSFProperty(inheritedTag = false)
413     public String getPattern()
414     {
415         if (_pattern != null)
416         {
417             return _pattern;
418         }
419         ValueExpression vb = getValueExpression("pattern");
420         if (vb != null)
421         {
422             return (String) vb.getValue(getFacesContext().getELContext()).toString();
423         }
424         return null;
425     }
426 
427     public void setPattern(String pattern)
428     {
429         _pattern = pattern;
430         clearInitialState();
431     }
432 
433     /**
434      * The style of the time.  Values include:  default, short, medium, long, 
435      * and full.
436      * 
437      */
438     @JSFProperty(inheritedTag = false)
439     public String getTimeStyle()
440     {
441         if (_timeStyle != null)
442         {
443             return _timeStyle;
444         }
445         ValueExpression vb = getValueExpression("timeStyle");
446         if (vb != null)
447         {
448             return (String) vb.getValue(getFacesContext().getELContext()).toString();
449         }
450         return STYLE_DEFAULT;
451     }
452 
453     public void setTimeStyle(String timeStyle)
454     {
455         _timeStyle = timeStyle;
456         clearInitialState();
457     }
458 
459     /**
460      * The time zone to use instead of GMT (the default timezone). When
461      * this value is a value-binding to a TimeZone instance, that
462      * timezone is used. Otherwise this value is treated as a String
463      * containing a timezone id, ie as the ID parameter of method
464      * java.util.TimeZone.getTimeZone(String).
465      * 
466      */
467     @JSFProperty(inheritedTag = false,deferredValueType="java.lang.Object")
468     public TimeZone getTimeZone()
469     {
470         //return _timeZone != null ? _timeZone : TIMEZONE_DEFAULT;
471         if (_timeZone != null)
472         {
473             return _timeZone;
474         }
475         ValueExpression vb = getValueExpression("timeZone");
476         if (vb != null)
477         {
478             Object _timeZoneValue = vb.getValue(getFacesContext().getELContext());
479             if(_timeZoneValue instanceof java.util.TimeZone)
480             {
481                 return (java.util.TimeZone) _timeZoneValue;
482             }
483             else
484             {
485                 return java.util.TimeZone.getTimeZone(_timeZoneValue.toString());
486             }
487         }
488         return TimeZone.getDefault(); //TIMEZONE_DEFAULT
489     }
490 
491     public void setTimeZone(TimeZone timeZone)
492     {
493         _timeZone = timeZone;
494         clearInitialState();
495     }
496 
497     /**
498      * Specifies whether the date, time, or both should be 
499      * parsed/formatted.  Values include:  date, time, and both.
500      * Default based on setting of timeStyle and dateStyle.
501      * 
502      */
503     @JSFProperty(inheritedTag = false)
504     public String getType()
505     {
506         if (_type != null)
507         {
508             return _type;
509         }
510         ValueExpression vb = getValueExpression("type");
511         if (vb != null)
512         {
513             return (String) vb.getValue(getFacesContext().getELContext()).toString();
514         }
515         return TYPE_DATE;
516     }
517 
518     public void setType(String type)
519     {
520         _type = type;
521         clearInitialState();
522     }
523 }