001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package org.apache.taglibs.datetime;
020
021import java.text.DateFormatSymbols;
022import java.text.SimpleDateFormat;
023import java.util.Date;
024import java.util.Locale;
025import java.util.TimeZone;
026
027import javax.servlet.jsp.JspException;
028import javax.servlet.jsp.JspTagException;
029import javax.servlet.jsp.PageContext;
030import javax.servlet.jsp.tagext.BodyContent;
031import javax.servlet.jsp.tagext.BodyTagSupport;
032
033public final class FormatTag extends BodyTagSupport     {
034
035    // format tag attributes
036
037    // Optional attribute, use users locale if known when formatting date
038    private boolean locale_flag = false;
039    // Optional attribute, time pattern string to use when formatting date
040    private String pattern = null;
041    // Optional attribute, name of script variable to use as pattern
042    private String patternid = null;
043    // Optional attribute, timeZone script variable id to use when formatting date
044    private String timeZone_string;
045    // Optional attribute, date object from rtexprvalue
046    private Date date = null;
047    // Optional attribute, the default text if the tag body or date given is invalid/null
048    private String default_text = "Invalid Date";
049    // Optional attribute, the name of an attribute which contains the Locale
050    private String localeRef = null;
051    // Optional attribute, name of script variable to use as date symbols source
052    private String symbolsRef = null;
053
054    // format tag invocation variables
055
056    // The symbols object
057    private DateFormatSymbols symbols = null;
058    // The date to be formatted an output by tag
059    private Date output_date = null;
060
061    /**
062     * Method called at start of tag, always returns EVAL_BODY_TAG
063     *
064     * @return EVAL_BODY_TAG
065     */
066    public final int doStartTag() throws JspException
067    {
068        output_date = date;
069        return EVAL_BODY_TAG;
070    }
071
072    /**
073     * Method called at end of format tag body.
074     *
075     * @return SKIP_BODY
076     */
077    public final int doAfterBody() throws JspException
078    {
079        // Use the body of the tag as input for the date
080        BodyContent body = getBodyContent();
081        String s = body.getString().trim();  
082        // Clear the body since we will output only the formatted date
083        body.clearBody();
084        if( output_date == null ) {
085            long time;
086            try {
087                time = Long.valueOf(s).longValue();
088                output_date = new Date(time);
089            } catch(NumberFormatException nfe) {
090            }
091        }
092
093        return SKIP_BODY;
094    }
095
096    /**
097     * Method called at end of Tag
098     *
099     * @return EVAL_PAGE
100     */
101    public final int doEndTag() throws JspException
102    {
103        String date_formatted = default_text;
104
105        if (output_date != null) {
106            // Get the pattern to use
107            SimpleDateFormat sdf;
108            String pat = pattern;
109
110            if (pat == null && patternid != null) {
111                Object attr = pageContext.findAttribute(patternid);
112                if (attr != null)
113                    pat = attr.toString();
114            }
115
116            if (pat == null) {
117                sdf = new SimpleDateFormat();
118                pat = sdf.toPattern();
119            }
120
121            // Get a DateFormatSymbols
122            if (symbolsRef != null) {
123                symbols = (DateFormatSymbols) pageContext.findAttribute(symbolsRef);
124                if (symbols == null) {
125                    throw new JspException(
126                            "datetime format tag could not find dateFormatSymbols for symbolsRef \"" +
127                            symbolsRef + "\".");
128                }
129            }
130
131            // Get a SimpleDateFormat using locale if necessary
132            if (localeRef != null) {
133                Locale locale = (Locale) pageContext.findAttribute(localeRef);
134                if (locale == null) {
135                    throw new JspException(
136                            "datetime format tag could not find locale for localeRef \"" +
137                            localeRef + "\".");
138                }
139
140                sdf = new SimpleDateFormat(pat, locale);
141            } else if (locale_flag) {
142                sdf = new SimpleDateFormat(pat,
143                         pageContext.getRequest().getLocale());
144            } else if (symbols != null) {
145                sdf = new SimpleDateFormat(pat,
146                        symbols);
147            } else {
148                sdf = new SimpleDateFormat(pat);
149            }
150
151            // See if there is a timeZone
152            if (timeZone_string != null) {
153                TimeZone timeZone =
154                        (TimeZone) pageContext.getAttribute(timeZone_string,
155                                PageContext.SESSION_SCOPE);
156                if (timeZone == null) {
157                    throw new JspTagException("Datetime format tag timeZone " +
158                            "script variable \"" + timeZone_string +
159                            " \" does not exist");
160                }
161                sdf.setTimeZone(timeZone);
162            }
163
164            // Format the date for display
165            date_formatted = sdf.format(output_date);
166        }
167
168        try {
169            pageContext.getOut().write(date_formatted);
170        } catch (Exception e) {
171            throw new JspException("IO Error: " + e.getMessage());
172        }
173
174        return EVAL_PAGE;
175    }
176
177    public void release()
178    {
179        //lucee.print.ln("release FormatTag");
180        super.release();
181        locale_flag = false;
182        pattern = null;
183        patternid = null;
184        date = null;
185        localeRef = null;
186        symbolsRef = null;
187        symbols = null;
188    }
189
190    /**
191     * Locale flag, if set to true, format date
192     * for client's preferred locale if known.
193     *
194     * @param boolean use users locale, true or false
195     */
196    public final void setLocale(short flag)
197    { 
198        //locale_flag = flag; 
199    }
200
201    /**
202     * Set the time zone to use when formatting date.
203     *
204     * Value must be the name of a <b>timeZone</b> tag script
205     * variable ID.
206     *
207     * @param String name of timeZone to use
208     */
209    public final void setTimeZone(String tz)
210    {
211        timeZone_string = tz;
212    }
213
214    /**
215     * Set the pattern to use when formatting Date.
216     *
217     * @param String SimpleDateFormat style time pattern format string
218     */
219    public final void setPattern(String str)
220    {
221        pattern = str;
222    }
223
224    /**
225     * Set the pattern to use when parsing Date using a script variable
226     * attribute.
227     * 
228     * @param String name of script variable attribute id
229     */
230    public final void setPatternId(String str)
231    {   
232        patternid = str;
233    }
234
235    /**
236     * Set the date to use (overrides tag body) for formatting
237     *
238     * @param Date to use for formatting (could be null)
239     */
240    public final void setDate(Date date)
241    {
242        this.date = date;
243    }
244
245    /**
246     * Set the default text if an invalid date or no tag body is given
247     *
248     * @param String to use as default text
249     */
250    public final void setDefault(String default_text)
251    {
252        this.default_text = default_text;
253    }
254
255    /**
256     * Provides a key to search the page context for in order to get the
257     * java.util.Locale to use.
258     *
259     * @param String name of locale attribute to use
260     */
261    public void setLocaleRef(String value)
262    {
263        localeRef = value;
264    }
265
266    /**
267     * Provides a key to search the page context for in order to get the
268     * java.text.DateFormatSymbols to use
269     *
270     * @param symbolsRef
271     */
272    public void setSymbolsRef(String symbolsRef) {
273        this.symbolsRef = symbolsRef;
274    }
275    
276}