001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.tags.html;
020:
021: import org.apache.beehive.netui.util.internal.InternalStringBuilder;
022:
023: import org.apache.beehive.netui.util.Bundle;
024: import org.apache.beehive.netui.util.logging.Logger;
025:
026: import javax.servlet.jsp.JspException;
027: import javax.servlet.jsp.tagext.JspTag;
028: import javax.servlet.jsp.tagext.SimpleTagSupport;
029: import java.text.DateFormat;
030: import java.text.ParsePosition;
031: import java.text.SimpleDateFormat;
032: import java.util.Locale;
033:
034: //external imports
035:
036: /**
037: * A formatter used to format dates. This formatter uses patterns that conform to
038: * <code>java.text.SimpleDateFormat</code> pattern syntax. Valid types for formatting are:
039: * <ul>
040: * <li>String</li>
041: * <li>java.sql.Date</li>
042: * <li>java.util.Date</li>
043: * <li>java.util.Calendar</li>
044: * </ul>
045: *
046: * <p>
047: * If the type is a String, we attempt to create a date out of the String. The
048: * String must be defined by a common format list below. If the string is
049: * equal the the empty string, it will be returned as the empty string. See
050: * java.text.SimpleDateFormat for more information.
051: * <p>
052: * The valid formats are:
053: * <ul>
054: * <li>MM/dd/yy</li>
055: * <li>yyyy-MM-dd</li>
056: * <li>MMddyy</li>
057: * <li>and the local default</li>
058: * </ul>
059: * @jsptagref.tagdescription A formatter used to format dates. This formatter uses patterns that conform to
060: * {@link java.text.SimpleDateFormat java.text.SimpleDateFormat} pattern syntax.
061: * Valid types for formatting are:
062: * <blockquote>
063: * <ul>
064: * <li>String</li>
065: * <li>java.sql.Date</li>
066: * <li>java.util.Date</li>
067: * <li>java.util.Calendar</li>
068: * </ul>
069: * </blockquote>
070: *
071: * <p>The <netui:formatDate> tag formats the output of its parent tag. For example:
072: *
073: * <pre> <netui:content value="${pageScope.euroDate}">
074: * <netui:formatDate pattern="dd-MM-yyyy" />
075: * </netui:content></pre>
076: *
077: * <p>
078: * The following table summarizes the pattern letters that can be used.
079: * <table border=0 cellspacing=3 cellpadding=0>
080: * <tr bgcolor="#ccccff">
081: * <th align=left>Letter
082: * <th align=left>Date or Time Component
083: * <th align=left>Examples
084: * <tr>
085: * <td><code>G</code>
086: * <td>Era designator
087: * <td><code>AD</code>
088: * <tr bgcolor="#eeeeff">
089: * <td><code>y</code>
090: * <td>Year
091: * <td><code>1996</code>; <code>96</code>
092: * <tr>
093: * <td><code>M</code>
094: * <td>Month in year
095: * <td><code>July</code>; <code>Jul</code>; <code>07</code>
096: * <tr bgcolor="#eeeeff">
097: * <td><code>w</code>
098: * <td>Week in year
099: * <td><code>27</code>
100: * <tr>
101: * <td><code>W</code>
102: * <td>Week in month
103: * <td><code>2</code>
104: * <tr bgcolor="#eeeeff">
105: * <td><code>D</code>
106: * <td>Day in year
107: * <td><code>189</code>
108: * <tr>
109: * <td><code>d</code>
110: * <td>Day in month
111: * <td><code>10</code>
112: * <tr bgcolor="#eeeeff">
113: * <td><code>F</code>
114: * <td>Day of week in month
115: * <td><code>2</code>
116: * <tr>
117: * <td><code>E</code>
118: * <td>Day in week
119: * <td><code>Tuesday</code>; <code>Tue</code>
120: * <tr bgcolor="#eeeeff">
121: * <td><code>a</code>
122: * <td>Am/pm marker
123: * <td><code>PM</code>
124: * <tr>
125: * <td><code>H</code>
126: * <td>Hour in day (0-23)
127: * <td><code>0</code>
128: * <tr bgcolor="#eeeeff">
129: * <td><code>k</code>
130: * <td>Hour in day (1-24)
131: * <td><code>24</code>
132: * <tr>
133: * <td><code>K</code>
134: * <td>Hour in am/pm (0-11)
135: * <td><code>0</code>
136: * <tr bgcolor="#eeeeff">
137: * <td><code>h</code>
138: * <td>Hour in am/pm (1-12)
139: * <td><code>12</code>
140: * <tr>
141: * <td><code>m</code>
142: * <td>Minute in hour
143: * <td><code>30</code>
144: * <tr bgcolor="#eeeeff">
145: * <td><code>s</code>
146: * <td>Second in minute
147: * <td><code>55</code>
148: * <tr>
149: * <td><code>S</code>
150: * <td>Millisecond
151: * <td><code>978</code>
152: * <tr bgcolor="#eeeeff">
153: * <td><code>z</code>
154: * <td>Time zone
155: * <td><code>Pacific Standard Time</code>; <code>PST</code>; <code>GMT-08:00</code>
156: * <tr>
157: * <td><code>Z</code>
158: * <td>Time zone
159: * <td><code>-0800</code>
160: * </table>
161: * </p>
162: *
163: * The number of pattern letters used determines the final presentation. For example,
164: * yy specifies a 2 digit year, while yyyy specifies a four digit year. For detailed information see
165: * {@link java.text.SimpleDateFormat java.text.SimpleDateFormat}.
166: *
167: * <p>
168: * If the input type is a String, <netui:formatDate> attempts to
169: * convert the String into a java.util.Date object before formatting.
170: * For the conversion to succeed, the
171: * String must conform to a format listed below.
172: * <p>
173: * The valid formats are:
174: * <blockquote>
175: * <ul>
176: * <li>MM/dd/yy</li>
177: * <li>yyyy-MM-dd</li>
178: * <li>MMddyy</li>
179: * <li>the local default</li>
180: * </ul>
181: * </blockquote>
182: * @example In this sample, the <netui:span> tag's output will be formatted to something like 08/29/1957.
183: * <pre> <netui:span value="${pageScope.today}">
184: * <netui:formatDate pattern="MM/dd/yyyy" />
185: * </netui:span></pre>
186: * @netui:tag name="formatDate" body-content="empty" description="A formatter used to format dates."
187: */
188: public class FormatDate extends FormatTag {
189: private static final Logger logger = Logger
190: .getInstance(FormatDate.class);
191:
192: private static final String[] commonFormats = { "MM/dd/yy",
193: "yyyy-MM-dd", "MMddyy", null };
194:
195: private String _stringInput;
196:
197: /**
198: * Return the name of the Tag.
199: */
200: public String getTagName() {
201: return "FormatDate";
202: }
203:
204: /**
205: * Set the pattern to use to convert a String value into a date. This
206: * will be used before the common formats.
207: * @param inputPattern the pattern representing the string input
208: * @jsptagref.attributedescription The pattern used to convert a String value into a date.
209: * @jsptagref.databindable Read Only
210: * @jsptagref.attributesyntaxvalue <i>string_stringInputPattern</i>
211: * @netui:attribute required="false" rtexprvalue="true"
212: * description="The pattern used to convert a String value into a date."
213: */
214: public void setStringInputPattern(String inputPattern)
215: throws JspException {
216: _stringInput = setRequiredValueAttribute(inputPattern,
217: "stringInputPattern");
218: }
219:
220: /**
221: * Create the internal Formatter instance and perform the formatting.
222: * @throws JspException if a JSP exception has occurred
223: */
224: public void doTag() throws JspException {
225: JspTag parentTag = SimpleTagSupport.findAncestorWithClass(this ,
226: IFormattable.class);
227:
228: // if there are errors we need to either add these to the parent AbstractBastTag or report an error.
229: if (hasErrors()) {
230: if (parentTag instanceof IFormattable) {
231: IFormattable parent = (IFormattable) parentTag;
232: parent.formatterHasError();
233: }
234: reportErrors();
235: return;
236: }
237:
238: if (parentTag instanceof IFormattable) {
239: IFormattable parent = (IFormattable) parentTag;
240: DateFormatter dateFmt = new DateFormatter();
241: dateFmt.setPattern(_pattern);
242: dateFmt.setLocale(getLocale());
243: dateFmt.setInputPattern(_stringInput);
244: parent.addFormatter(dateFmt);
245: } else {
246: String s = Bundle
247: .getString("Tags_FormattableParentRequired");
248: registerTagError(s, null);
249: reportErrors();
250: }
251: }
252:
253: /**
254: * Internal FormatTag.Formatter which uses SimpleDateFormat.
255: */
256: public static class DateFormatter extends FormatTag.Formatter {
257: private Locale locale;
258: private String inputPattern;
259:
260: public void setLocale(Locale locale) {
261: this .locale = locale;
262: }
263:
264: public void setInputPattern(String pattern) {
265: inputPattern = pattern;
266: }
267:
268: public String format(Object dataToFormat) throws JspException {
269: if (dataToFormat == null) {
270: return null;
271: }
272: InternalStringBuilder formattedString = new InternalStringBuilder(
273: 32);
274:
275: SimpleDateFormat dateFormat = null;
276: if (getPattern() != null) {
277: try {
278: if (locale != null) {
279: dateFormat = new SimpleDateFormat(getPattern(),
280: locale);
281: } else {
282: dateFormat = new SimpleDateFormat(getPattern());
283: }
284: } catch (IllegalArgumentException e) {
285: String s = Bundle.getString(
286: "Tags_DateFormatPatternException",
287: new Object[] { e.getMessage() });
288: logger.warn(s);
289: throw new JspException(s);
290: }
291: } else {
292: dateFormat = new SimpleDateFormat();
293: }
294:
295: if (dataToFormat instanceof java.sql.Date) {
296:
297: java.sql.Date date = (java.sql.Date) dataToFormat;
298: formattedString.append(dateFormat.format(date));
299: } else if (dataToFormat instanceof java.util.Date) {
300:
301: java.util.Date date = (java.util.Date) dataToFormat;
302: formattedString.append(dateFormat.format(date));
303: } else if (dataToFormat instanceof java.util.Calendar) {
304: java.util.Calendar c = (java.util.Calendar) dataToFormat;
305: java.util.Date date = new java.util.Date(c
306: .getTimeInMillis());
307: formattedString.append(dateFormat.format(date));
308: } else if (dataToFormat instanceof String) {
309: if (dataToFormat.equals("")) {
310: return "";
311: }
312:
313: DateFormat df = null;
314: if (inputPattern != null) {
315: try {
316: df = new SimpleDateFormat(inputPattern);
317: } catch (IllegalArgumentException e) {
318: String s = Bundle.getString(
319: "Tags_formatDate_StringPatternError",
320: new Object[] { inputPattern,
321: e.getMessage() });
322: logger.warn(s);
323: throw new JspException(s);
324: }
325:
326: // let try and convert this to some type of date
327: java.util.Date date = df
328: .parse((String) dataToFormat,
329: new ParsePosition(0));
330: if (date != null) {
331: formattedString.append(dateFormat.format(date));
332: return formattedString.toString();
333: }
334: }
335:
336: // this will loop through all of the formats and
337: // try to convert the date to one of them.
338: int i;
339: for (i = 0; i < commonFormats.length; i++) {
340:
341: if (commonFormats[i] != null) {
342: df = new SimpleDateFormat(commonFormats[i]);
343: } else {
344: df = new SimpleDateFormat();
345:
346: }
347:
348: // let try and convert this to some type of date
349: java.util.Date date = df
350: .parse((String) dataToFormat,
351: new ParsePosition(0));
352: if (date != null) {
353: formattedString.append(dateFormat.format(date));
354: break;
355: }
356: }
357: if (i == commonFormats.length) {
358: String s = Bundle.getString(
359: "Tags_formatDate_String_Error",
360: new Object[] { dataToFormat });
361: logger.error(s);
362: throw new JspException(s);
363: }
364: } else {
365: String s = Bundle.getString(
366: "Tags_formatDate_Type_Error",
367: new Object[] { dataToFormat.getClass()
368: .getName() });
369: logger.error(s);
370: throw new JspException(s);
371: }
372:
373: return formattedString.toString();
374: }
375: }
376: }
|