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         Object[] values = (Object[])state;
229         _dateStyle = (String)values[0];
230         _locale = (Locale)values[1];
231         _pattern = (String)values[2];
232         _timeStyle = (String)values[3];
233         _timeZone = (TimeZone)values[4];
234         _type = (String)values[5];
235         restoreValueExpressionMap(facesContext, values[6]);
236         
237     }
238 
239     public Object saveState(FacesContext facesContext)
240     {
241         Object[] values = new Object[7];
242         values[0] = _dateStyle;
243         values[1] = _locale;
244         values[2] = _pattern;
245         values[3] = _timeStyle;
246         values[4] = _timeZone;
247         values[5] = _type;
248         values[6] = saveValueExpressionMap(facesContext);
249         return values;
250     }
251     
252     // --------------------- borrowed from UIComponentBase ------------
253 
254     private Map _valueExpressionMap = null;
255 
256     public ValueExpression getValueExpression(String name)
257     {
258         if (name == null) throw new NullPointerException("name");
259         if (_valueExpressionMap == null)
260         {
261             return null;
262         }
263         else
264         {
265             return (ValueExpression)_valueExpressionMap.get(name);
266         }
267     }
268 
269     public void setValueExpression(String name,
270                                 ValueExpression binding)
271     {
272         if (name == null) throw new NullPointerException("name");
273         if (_valueExpressionMap == null)
274         {
275             _valueExpressionMap = new HashMap();
276         }
277         _valueExpressionMap.put(name, binding);
278     }
279 
280     private Object saveValueExpressionMap(FacesContext context)
281     {
282         if (_valueExpressionMap != null)
283         {
284             int initCapacity = (_valueExpressionMap.size() * 4 + 3) / 3;
285             HashMap stateMap = new HashMap(initCapacity);
286             for (Iterator it = _valueExpressionMap.entrySet().iterator(); it.hasNext(); )
287             {
288                 Map.Entry entry = (Map.Entry)it.next();
289                 stateMap.put(entry.getKey(),
290                              ConverterBase.saveAttachedState(context, entry.getValue()));
291             }
292             return stateMap;
293         }
294         else
295         {
296             return null;
297         }
298     }
299 
300     private void restoreValueExpressionMap(FacesContext context, Object stateObj)
301     {
302         if (stateObj != null)
303         {
304             Map stateMap = (Map)stateObj;
305             int initCapacity = (stateMap.size() * 4 + 3) / 3;
306             _valueExpressionMap = new HashMap(initCapacity);
307             for (Iterator it = stateMap.entrySet().iterator(); it.hasNext(); )
308             {
309                 Map.Entry entry = (Map.Entry)it.next();
310                 _valueExpressionMap.put(entry.getKey(),
311                         ConverterBase.restoreAttachedState(context, entry.getValue()));
312             }
313         }
314         else
315         {
316             _valueExpressionMap = null;
317         }
318     }
319     protected FacesContext getFacesContext()
320     {
321         if (_facesContext == null)
322         {
323             return FacesContext.getCurrentInstance();
324         }
325         else
326         {
327             return _facesContext;
328         }
329     }
330     
331     boolean isCachedFacesContext()
332     {
333         return _facesContext != null;
334     }
335     
336     void setCachedFacesContext(FacesContext facesContext)
337     {
338         _facesContext = facesContext;
339     }
340     
341 
342     // GETTER & SETTER
343     
344     /**
345      * The style of the date.  Values include: default, short, medium, 
346      * long, and full.
347      * 
348      */
349     @JSFProperty(inheritedTag = false)
350     public String getDateStyle()
351     {
352         if (_dateStyle != null)
353         {
354             return _dateStyle;
355         }
356         ValueExpression vb = getValueExpression("dateStyle");
357         if (vb != null)
358         {
359             return (String) vb.getValue(getFacesContext().getELContext());
360         }
361         return STYLE_DEFAULT;
362     }
363 
364     public void setDateStyle(String dateStyle)
365     {
366         _dateStyle = dateStyle;
367     }
368 
369     /**
370      * The name of the locale to be used, instead of the default.
371      * 
372      */
373     @JSFProperty(inheritedTag = false,deferredValueType="java.lang.Object")
374     public Locale getLocale()
375     {        
376         if (_locale != null)
377         {
378             return _locale;
379         }
380         ValueExpression vb = getValueExpression("locale");
381         if (vb != null)
382         {
383             Object _localeValue = vb.getValue(getFacesContext().getELContext());
384             if (_localeValue instanceof String)
385             {
386                 _localeValue = org.apache.myfaces.commons.util.TagUtils.getLocale((String)_localeValue);
387             }
388             return (java.util.Locale)_localeValue;
389         }
390         FacesContext context = FacesContext.getCurrentInstance();
391         return context.getViewRoot().getLocale();
392     }
393 
394     public void setLocale(Locale locale)
395     {
396         _locale = locale;
397     }
398 
399     /**
400      * A custom Date formatting pattern, in the format used by java.text.SimpleDateFormat.
401      * 
402      */
403     @JSFProperty(inheritedTag = false)
404     public String getPattern()
405     {
406         if (_pattern != null)
407         {
408             return _pattern;
409         }
410         ValueExpression vb = getValueExpression("pattern");
411         if (vb != null)
412         {
413             return (String) vb.getValue(getFacesContext().getELContext()).toString();
414         }
415         return null;
416     }
417 
418     public void setPattern(String pattern)
419     {
420         _pattern = pattern;
421     }
422 
423     /**
424      * The style of the time.  Values include:  default, short, medium, long, 
425      * and full.
426      * 
427      */
428     @JSFProperty(inheritedTag = false)
429     public String getTimeStyle()
430     {
431         if (_timeStyle != null)
432         {
433             return _timeStyle;
434         }
435         ValueExpression vb = getValueExpression("timeStyle");
436         if (vb != null)
437         {
438             return (String) vb.getValue(getFacesContext().getELContext()).toString();
439         }
440         return STYLE_DEFAULT;
441     }
442 
443     public void setTimeStyle(String timeStyle)
444     {
445         _timeStyle = timeStyle;
446     }
447 
448     /**
449      * The time zone to use instead of GMT (the default timezone). When
450      * this value is a value-binding to a TimeZone instance, that
451      * timezone is used. Otherwise this value is treated as a String
452      * containing a timezone id, ie as the ID parameter of method
453      * java.util.TimeZone.getTimeZone(String).
454      * 
455      */
456     @JSFProperty(inheritedTag = false,deferredValueType="java.lang.Object")
457     public TimeZone getTimeZone()
458     {
459         //return _timeZone != null ? _timeZone : TIMEZONE_DEFAULT;
460         if (_timeZone != null)
461         {
462             return _timeZone;
463         }
464         ValueExpression vb = getValueExpression("timeZone");
465         if (vb != null)
466         {
467             Object _timeZoneValue = vb.getValue(getFacesContext().getELContext());
468             if(_timeZoneValue instanceof java.util.TimeZone)
469             {
470                 return (java.util.TimeZone) _timeZoneValue;
471             }
472             else
473             {
474                 return java.util.TimeZone.getTimeZone(_timeZoneValue.toString());
475             }
476         }
477         return TimeZone.getDefault(); //TIMEZONE_DEFAULT
478     }
479 
480     public void setTimeZone(TimeZone timeZone)
481     {
482         _timeZone = timeZone;
483     }
484 
485     /**
486      * Specifies whether the date, time, or both should be 
487      * parsed/formatted.  Values include:  date, time, and both.
488      * Default based on setting of timeStyle and dateStyle.
489      * 
490      */
491     @JSFProperty(inheritedTag = false)
492     public String getType()
493     {
494         if (_type != null)
495         {
496             return _type;
497         }
498         ValueExpression vb = getValueExpression("type");
499         if (vb != null)
500         {
501             return (String) vb.getValue(getFacesContext().getELContext()).toString();
502         }
503         return TYPE_DATE;
504     }
505 
506     public void setType(String type)
507     {
508         _type = type;
509     }
510 }