View Javadoc

1   /*
2    * Copyright 2002,2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.jelly.tags.fmt;
17  
18  import org.apache.commons.jelly.JellyTagException;
19  import org.apache.commons.jelly.XMLOutput;
20  import org.apache.commons.jelly.Tag;
21  import org.apache.commons.jelly.TagSupport;
22  import org.apache.commons.jelly.expression.Expression;
23  
24  import org.xml.sax.SAXException;
25  
26  import java.text.DateFormat;
27  import java.text.SimpleDateFormat;
28  import java.util.Date;
29  import java.util.Locale;
30  import java.util.TimeZone;
31  
32  
33  /***
34   * Support for tag handlers for <formatDate>, the date and time formatting
35   * tag in JSTL.
36   * @author <a href="mailto:willievu@yahoo.com">Willie Vu</a>
37   * @version $Revision: 155420 $
38   * @task i18n exception message
39   */
40  public class FormatDateTag extends TagSupport {
41  
42      private static final String DEFAULT = "default";
43      private static final String SHORT = "short";
44      private static final String MEDIUM = "medium";
45      private static final String LONG = "long";
46      private static final String FULL = "full";
47  
48      private static final String DATE = "date";
49      private static final String TIME = "time";
50      private static final String DATETIME = "both";
51  
52      /*** Holds value of property value. */
53      private Expression value;
54  
55      /*** Holds value of property type. */
56      private Expression type;
57  
58      /*** Holds value of property dataStyle. */
59      private Expression dateStyle;
60  
61      /*** Holds value of property timeStyle. */
62      private Expression timeStyle;
63  
64      /*** Holds value of property pattern. */
65      private Expression pattern;
66  
67      /*** Holds value of property timeZone. */
68      private Expression timeZone;
69  
70      /*** Holds value of property var. */
71      private String var;
72  
73      /*** Holds value of property scope. */
74      private String scope;
75  
76      /*** Evaluated type */
77      private String etype;
78      /*** Evaluated dateStyle */
79      private String edateStyle;
80      /*** Evaluated timeStyle */
81      private String etimeStyle;
82  
83      /*** Creates a new instance of FormatDateTag */
84      public FormatDateTag() {
85      }
86  
87      /***
88       * Evaluates this tag after all the tags properties have been initialized.
89       *
90       */
91      public void doTag(XMLOutput output) throws JellyTagException {
92  
93          if (scope != null && var == null) {
94              throw new JellyTagException(
95              "If 'scope' is specified, 'var' must be defined for this tag" );
96          }
97  
98          Object valueInput = null;
99          if (this.value != null) {
100             valueInput = this.value.evaluate(context);
101         }
102 
103         Date date = null;
104         if (valueInput != null && valueInput instanceof Date) {
105             date = (Date) valueInput;
106         }
107 
108         if (date == null && var != null) {
109             if (scope != null) {
110                 context.removeVariable(var, scope);
111             }
112             else {
113                 context.removeVariable(var);
114             }
115         }
116 
117         etype = DATE;
118         if (this.type != null) {
119             etype = (String) this.type.evaluate(context);
120         }
121 
122         edateStyle = DEFAULT;
123         if (this.dateStyle != null) {
124             edateStyle = (String) this.dateStyle.evaluate(context);
125         }
126 
127         etimeStyle = DEFAULT;
128         if (this.timeStyle != null) {
129             etimeStyle = (String) this.timeStyle.evaluate(context);
130         }
131 
132         String epattern = null;
133         if (this.pattern != null) {
134             epattern = (String) this.pattern.evaluate(context);
135         }
136 
137         Object etimeZone = null;
138         if (this.timeZone != null) {
139             etimeZone = this.timeZone.evaluate(context);
140         }
141 
142         // Create formatter
143         Locale locale = SetLocaleTag.getFormattingLocale(
144             context,
145             this,
146             true,
147             DateFormat.getAvailableLocales());
148 
149         String formatted = null;
150         if (locale != null) {
151             DateFormat formatter = createFormatter(locale);
152 
153             // Apply pattern, if present
154             if (pattern != null) {
155                 try {
156                     ((SimpleDateFormat) formatter).applyPattern(epattern);
157                 } catch (ClassCastException cce) {
158                     formatter = new SimpleDateFormat(epattern, locale);
159                 }
160             }
161 
162             // Set time zone
163             TimeZone tz = null;
164             if ((etimeZone instanceof String)
165             && ((String) etimeZone).equals("")) {
166                 etimeZone = null;
167             }
168             if (etimeZone != null) {
169                 if (etimeZone instanceof String) {
170                     tz = TimeZone.getTimeZone((String) etimeZone);
171                 } else if (etimeZone instanceof TimeZone) {
172                     tz = (TimeZone) etimeZone;
173                 } else {
174                     throw new JellyTagException("Bad time zone");
175                 }
176             } else {
177                 tz = TimeZoneTag.getTimeZone(context, this);
178             }
179             if (tz != null) {
180                 formatter.setTimeZone(tz);
181             }
182             formatted = formatter.format(date);
183         } else {
184             // no formatting locale available, use Date.toString()
185             formatted = date.toString();
186         }
187 
188         if (var != null) {
189             if (scope != null) {
190                 context.setVariable(var, scope, formatted);
191             }
192             else {
193                 context.setVariable(var, formatted);
194             }
195         }
196         else {
197             try {
198                 // write the formatted
199                 output.write(formatted);
200             } catch (SAXException e) {
201                 throw new JellyTagException("could not write formatted text",e);
202             }
203         }
204     }
205 
206     /*** Setter for property value.
207      * @param value New value of property value.
208      *
209      */
210     public void setValue(Expression value) {
211         this.value = value;
212     }
213 
214     /*** Setter for property type.
215      * @param type New value of property type.
216      *
217      */
218     public void setType(Expression type) {
219         this.type = type;
220     }
221 
222     /*** Setter for property dataStyle.
223      * @param dataStyle New value of property dataStyle.
224      *
225      */
226     public void setDateStyle(Expression dateStyle) {
227         this.dateStyle = dateStyle;
228     }
229 
230     /*** Setter for property timeStyle.
231      * @param timeStyle New value of property timeStyle.
232      *
233      */
234     public void setTimeStyle(Expression timeStyle) {
235         this.timeStyle = timeStyle;
236     }
237 
238     /*** Setter for property pattern.
239      * @param pattern New value of property pattern.
240      *
241      */
242     public void setPattern(Expression pattern) {
243         this.pattern = pattern;
244     }
245 
246     /*** Setter for property timeZone.
247      * @param timeZone New value of property timeZone.
248      *
249      */
250     public void setTimeZone(Expression timeZone) {
251         this.timeZone = timeZone;
252     }
253 
254     /*** Setter for property var.
255      * @param var New value of property var.
256      *
257      */
258     public void setVar(String var) {
259         this.var = var;
260     }
261 
262     /*** Setter for property scope.
263      * @param scope New value of property scope.
264      *
265      */
266     public void setScope(String scope) {
267         this.scope = scope;
268     }
269 
270     //**********************************************************************
271     // Private utility methods
272 
273     private DateFormat createFormatter(Locale loc) throws JellyTagException {
274         DateFormat formatter = null;
275 
276         if ((etype == null) || DATE.equalsIgnoreCase(etype)) {
277             formatter = DateFormat.getDateInstance(
278             getStyle(edateStyle, "FORMAT_DATE_INVALID_DATE_STYLE"),
279             loc);
280         } else if (TIME.equalsIgnoreCase(etype)) {
281             formatter = DateFormat.getTimeInstance(
282             getStyle(etimeStyle, "FORMAT_DATE_INVALID_TIME_STYLE"),
283             loc);
284         } else if (DATETIME.equalsIgnoreCase(etype)) {
285             formatter = DateFormat.getDateTimeInstance(
286             getStyle(edateStyle, "FORMAT_DATE_INVALID_DATE_STYLE"),
287             getStyle(etimeStyle, "FORMAT_DATE_INVALID_TIME_STYLE"),
288             loc);
289         } else {
290             throw new JellyTagException("Date format invalue");
291         }
292 
293         return formatter;
294     }
295 
296     /*
297      * Converts the given string description of a formatting style for
298      * dates and times to the corresponding java.util.DateFormat constant.
299      *
300      * @param style String description of formatting style for dates and times
301      * @param errCode Error code to throw if given style is invalid
302      *
303      * @return java.util.DateFormat constant corresponding to given style
304      *
305      * @throws JellyException if the given style is invalid
306      */
307     public static int getStyle(String style, String errCode)
308     throws JellyTagException {
309         int ret = DateFormat.DEFAULT;
310 
311         if (style != null) {
312             if (DEFAULT.equalsIgnoreCase(style)) {
313                 ret = DateFormat.DEFAULT;
314             } else if (SHORT.equalsIgnoreCase(style)) {
315                 ret = DateFormat.SHORT;
316             } else if (MEDIUM.equalsIgnoreCase(style)) {
317                 ret = DateFormat.MEDIUM;
318             } else if (LONG.equalsIgnoreCase(style)) {
319                 ret = DateFormat.LONG;
320             } else if (FULL.equalsIgnoreCase(style)) {
321                 ret = DateFormat.FULL;
322             } else {
323                 throw new JellyTagException("Invalid style " + errCode);
324             }
325         }
326 
327         return ret;
328     }
329 
330 }