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: bommel $)
44   * @version $Revision: 1187700 $ $Date: 2011-10-22 07:19:37 -0500 (Sat, 22 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) throw new NullPointerException("facesContext");
93          if (uiComponent == null) throw new NullPointerException("uiComponent");
94  
95          if (value != null)
96          {
97              value = value.trim();
98              if (value.length() > 0)
99              {
100                 DateFormat format = getDateFormat();
101                 TimeZone tz = getTimeZone();
102                 if( tz != null )
103                     format.setTimeZone( tz );
104                 try
105                 {
106                     return format.parse(value);
107                 }
108                 catch (ParseException e)
109                 {
110                     String type = getType();
111                     Object[] args = new Object[]{value,format.format(new Date()),_MessageUtils.getLabel(facesContext, uiComponent)};
112                     
113                     if(type.equals(TYPE_DATE))
114                         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,DATE_ID,args));
115                     else if (type.equals(TYPE_TIME))
116                         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,TIME_ID,args));
117                     else if (type.equals(TYPE_BOTH))
118                         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,DATETIME_ID,args));
119                     else
120                         throw new ConverterException("invalid type '" + _type + "'");
121                 }
122             }
123         }
124         return null;
125     }
126 
127     public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
128     {
129         if (facesContext == null) throw new NullPointerException("facesContext");
130         if (uiComponent == null) throw new NullPointerException("uiComponent");
131 
132         if (value == null)
133         {
134             return "";
135         }
136         if (value instanceof String)
137         {
138             return (String)value;
139         }
140 
141         DateFormat format = getDateFormat();
142         TimeZone tz = getTimeZone(); 
143         if (tz != null)
144         {
145             format.setTimeZone(tz);
146         }
147         try
148         {
149             return format.format(value);
150         }
151         catch (Exception e)
152         {
153             throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, STRING_ID, new Object[]{value,_MessageUtils.getLabel(facesContext, uiComponent)}),e);
154         }
155     }
156 
157     private DateFormat getDateFormat()
158     {
159         String type = getType();
160         DateFormat format;
161         if (_pattern != null)
162         {
163             try 
164             {
165                 format = new SimpleDateFormat(_pattern, getLocale());
166             } 
167                 catch (IllegalArgumentException iae)
168             {
169                 throw new ConverterException("Invalid pattern", iae);    
170             }
171         }
172         else if (type.equals(TYPE_DATE))
173         {
174             format = DateFormat.getDateInstance(calcStyle(getDateStyle()), getLocale());
175         }
176         else if (type.equals(TYPE_TIME))
177         {
178             format = DateFormat.getTimeInstance(calcStyle(getTimeStyle()), getLocale());
179         }
180         else if (type.equals(TYPE_BOTH))
181         {
182             format = DateFormat.getDateTimeInstance(calcStyle(getDateStyle()),
183                                                     calcStyle(getTimeStyle()),
184                                                     getLocale());
185         }
186         else
187         {
188             throw new ConverterException("invalid type '" + _type + "'");
189         }
190         
191         // format cannot be lenient (JSR-127)
192         format.setLenient(false);
193         return format;
194     }
195 
196     private int calcStyle(String name)
197     {
198         if (name.equals(STYLE_DEFAULT))
199         {
200             return DateFormat.DEFAULT;
201         }
202         if (name.equals(STYLE_MEDIUM))
203         {
204             return DateFormat.MEDIUM;
205         }
206         if (name.equals(STYLE_SHORT))
207         {
208             return DateFormat.SHORT;
209         }
210         if (name.equals(STYLE_LONG))
211         {
212             return DateFormat.LONG;
213         }
214         if (name.equals(STYLE_FULL))
215         {
216             return DateFormat.FULL;
217         }
218 
219         throw new ConverterException("invalid style '" + name + "'");
220     }
221 
222     // STATE SAVE/RESTORE
223     public void restoreState(FacesContext facesContext, Object state)
224     {
225         if (state != null)
226         {
227             Object[] values = (Object[])state;
228             _dateStyle = (String)values[0];
229             _locale = (Locale)values[1];
230             _pattern = (String)values[2];
231             _timeStyle = (String)values[3];
232             _timeZone = (TimeZone)values[4];
233             _type = (String)values[5];
234         }
235     }
236 
237     public Object saveState(FacesContext facesContext)
238     {
239         if (!initialStateMarked())
240         {
241             Object[] values = new Object[6];
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             return values;
249         }
250         return null;
251     }
252 
253     // GETTER & SETTER
254     
255     /**
256      * The style of the date.  Values include: default, short, medium, 
257      * long, and full.
258      * 
259      */
260     @JSFProperty
261     public String getDateStyle()
262     {
263         return _dateStyle != null ? _dateStyle : STYLE_DEFAULT;
264     }
265 
266     public void setDateStyle(String dateStyle)
267     {
268         //TODO: validate timeStyle
269         _dateStyle = dateStyle;
270         clearInitialState();
271     }
272 
273     /**
274      * The name of the locale to be used, instead of the default.
275      * 
276      */
277     @JSFProperty
278     public Locale getLocale()
279     {
280         if (_locale != null) return _locale;
281         FacesContext context = FacesContext.getCurrentInstance();
282         return context.getViewRoot().getLocale();
283     }
284 
285     public void setLocale(Locale locale)
286     {
287         _locale = locale;
288         clearInitialState();
289     }
290 
291     /**
292      * A custom Date formatting pattern, in the format used by java.text.SimpleDateFormat.
293      * 
294      */
295     @JSFProperty
296     public String getPattern()
297     {
298         return _pattern;
299     }
300 
301     public void setPattern(String pattern)
302     {
303         _pattern = pattern;
304         clearInitialState();
305     }
306 
307     /**
308      * The style of the time.  Values include:  default, short, medium, long, 
309      * and full.
310      * 
311      */
312     @JSFProperty
313     public String getTimeStyle()
314     {
315         return _timeStyle != null ? _timeStyle : STYLE_DEFAULT;
316     }
317 
318     public void setTimeStyle(String timeStyle)
319     {
320         //TODO: validate timeStyle
321         _timeStyle = timeStyle;
322         clearInitialState();
323     }
324 
325     /**
326      * The time zone to use instead of GMT (the default timezone). When
327      * this value is a value-binding to a TimeZone instance, that
328      * timezone is used. Otherwise this value is treated as a String
329      * containing a timezone id, ie as the ID parameter of method
330      * java.util.TimeZone.getTimeZone(String).
331      * 
332      */
333     @JSFProperty
334     public TimeZone getTimeZone()
335     {
336         return _timeZone != null ? _timeZone : TIMEZONE_DEFAULT;
337     }
338 
339     public void setTimeZone(TimeZone timeZone)
340     {
341         _timeZone = timeZone;
342         clearInitialState();
343     }
344 
345     public boolean isTransient()
346     {
347         return _transient;
348     }
349 
350     public void setTransient(boolean aTransient)
351     {
352         _transient = aTransient;
353     }
354 
355     /**
356      * Specifies whether the date, time, or both should be 
357      * parsed/formatted.  Values include:  date, time, and both.
358      * Default based on setting of timeStyle and dateStyle.
359      * 
360      */
361     @JSFProperty
362     public String getType()
363     {
364         return _type != null ? _type : TYPE_DATE;
365     }
366 
367     public void setType(String type)
368     {
369         //TODO: validate type
370         _type = type;
371         clearInitialState();
372     }
373     
374     private boolean _initialStateMarked = false;
375 
376     public void clearInitialState()
377     {
378         _initialStateMarked = false;
379     }
380 
381     public boolean initialStateMarked()
382     {
383         return _initialStateMarked;
384     }
385 
386     public void markInitialState()
387     {
388         _initialStateMarked = true;
389     }
390 }