Save This Page
Home » mojarra-1.2_09-b02-FCS-source » javax.faces.convert » [javadoc | source]
    1   /*
    2    * $Id: DateTimeConverter.java,v 1.34.4.1 2007/09/26 19:02:55 rlubke Exp $
    3    */
    4   
    5   /*
    6    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    7    * 
    8    * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
    9    * 
   10    * The contents of this file are subject to the terms of either the GNU
   11    * General Public License Version 2 only ("GPL") or the Common Development
   12    * and Distribution License("CDDL") (collectively, the "License").  You
   13    * may not use this file except in compliance with the License. You can obtain
   14    * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
   15    * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
   16    * language governing permissions and limitations under the License.
   17    * 
   18    * When distributing the software, include this License Header Notice in each
   19    * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
   20    * Sun designates this particular file as subject to the "Classpath" exception
   21    * as provided by Sun in the GPL Version 2 section of the License file that
   22    * accompanied this code.  If applicable, add the following below the License
   23    * Header, with the fields enclosed by brackets [] replaced by your own
   24    * identifying information: "Portions Copyrighted [year]
   25    * [name of copyright owner]"
   26    * 
   27    * Contributor(s):
   28    * 
   29    * If you wish your version of this file to be governed by only the CDDL or
   30    * only the GPL Version 2, indicate your decision by adding "[Contributor]
   31    * elects to include this software in this distribution under the [CDDL or GPL
   32    * Version 2] license."  If you don't indicate a single choice of license, a
   33    * recipient has the option to distribute your version of this file under
   34    * either the CDDL, the GPL Version 2 or to extend the choice of license to
   35    * its licensees as provided above.  However, if you add GPL Version 2 code
   36    * and therefore, elected the GPL Version 2 license, then the option applies
   37    * only if the new code is made subject to such option by the copyright
   38    * holder.
   39    */
   40   
   41   package javax.faces.convert;
   42   
   43   
   44   import javax.faces.component.StateHolder;
   45   import javax.faces.component.UIComponent;
   46   import javax.faces.context.FacesContext;
   47   import java.text.DateFormat;
   48   import java.text.ParseException;
   49   import java.text.SimpleDateFormat;
   50   import java.util.Date;
   51   import java.util.Locale;
   52   import java.util.TimeZone;
   53   
   54   
   55   /**
   56    * <p>{@link Converter} implementation for <code>java.util.Date</code>
   57    * values.</p>
   58    * <p/>
   59    * <p>The <code>getAsObject()</code> method parses a String into a
   60    * <code>java.util.Date</code>, according to the following algorithm:</p>
   61    * <ul>
   62    * <li>If the specified String is null, return
   63    * a <code>null</code>.  Otherwise, trim leading and trailing
   64    * whitespace before proceeding.</li>
   65    * <li>If the specified String - after trimming - has a zero length,
   66    * return <code>null</code>.</li>
   67    * <li>If the <code>locale</code> property is not null,
   68    * use that <code>Locale</code> for managing parsing.  Otherwise, use the
   69    * <code>Locale</code> from the <code>UIViewRoot</code>.</li>
   70    * <li>If a <code>pattern</code> has been specified, its syntax must conform
   71    * the rules specified by <code>java.text.SimpleDateFormat</code>.  Such
   72    * a pattern will be used to parse, and the <code>type</code>,
   73    * <code>dateStyle</code>, and <code>timeStyle</code> properties
   74    * will be ignored.</li>
   75    * <li>If a <code>pattern</code> has not been specified, parsing will be based
   76    * on the <code>type</code> property, which expects a date value, a time
   77    * value, or both.  Any date and time values included will be parsed in
   78    * accordance to the styles specified by <code>dateStyle</code> and
   79    * <code>timeStyle</code>, respectively.</li>
   80    * <li>If a <code>timezone</code> has been specified, it must be passed
   81    * to the underlying <code>DateFormat</code> instance.  Otherwise
   82    * the "GMT" timezone is used.</li>
   83    * <li>In all cases, parsing must be non-lenient; the given string must
   84    * strictly adhere to the parsing format.</li>
   85    * </ul>
   86    * <p/>
   87    * <p>The <code>getAsString()</code> method expects a value of type
   88    * <code>java.util.Date</code> (or a subclass), and creates a formatted
   89    * String according to the following algorithm:</p>
   90    * <ul>
   91    * <li>If the specified value is null, return a zero-length String.</li>
   92    * <li>If the specified value is a String, return it unmodified.</li>
   93    * <li>If the <code>locale</code> property is not null,
   94    * use that <code>Locale</code> for managing formatting.  Otherwise, use the
   95    * <code>Locale</code> from the <code>UIViewRoot</code>.</li>
   96    * <li>If a <code>timezone</code> has been specified, it must be passed
   97    * to the underlying <code>DateFormat</code> instance.  Otherwise
   98    * the "GMT" timezone is used.</li>
   99    * <li>If a <code>pattern</code> has been specified, its syntax must conform
  100    * the rules specified by <code>java.text.SimpleDateFormat</code>.  Such
  101    * a pattern will be used to format, and the <code>type</code>,
  102    * <code>dateStyle</code>, and <code>timeStyle</code> properties
  103    * will be ignored.</li>
  104    * <li>If a <code>pattern</code> has not been specified, formatting will be
  105    * based on the <code>type</code> property, which includes a date value,
  106    * a time value, or both into the formatted String.  Any date and time
  107    * values included will be formatted in accordance to the styles specified
  108    * by <code>dateStyle</code> and <code>timeStyle</code>, respectively.</li>
  109    * </ul>
  110    */
  111   
  112   public class DateTimeConverter implements Converter, StateHolder {
  113   
  114       // ------------------------------------------------------ Manifest Constants
  115   
  116   
  117       /**
  118        * <p>The standard converter id for this converter.</p>
  119        */
  120       public static final String CONVERTER_ID = "javax.faces.DateTime";
  121   
  122       /**
  123        * <p>The message identifier of the {@link javax.faces.application.FacesMessage} to be created if
  124        * the conversion to <code>Date</code> fails.  The message format
  125        * string for this message may optionally include the following
  126        * placeholders:
  127        * <ul>
  128        * <li><code>{0}</code> replaced by the unconverted value.</li>
  129        * <li><code>{1}</code> replaced by an example value.</li>
  130        * <li><code>{2}</code> replaced by a <code>String</code> whose value
  131        * is the label of the input component that produced this message.</li>
  132        * </ul></p>
  133        */
  134       public static final String DATE_ID =
  135            "javax.faces.converter.DateTimeConverter.DATE";
  136   
  137       /**
  138        * <p>The message identifier of the {@link javax.faces.application.FacesMessage} to be created if
  139        * the conversion to <code>Time</code> fails.  The message format
  140        * string for this message may optionally include the following
  141        * placeholders:
  142        * <ul>
  143        * <li><code>{0}</code> replaced by the unconverted value.</li>
  144        * <li><code>{1}</code> replaced by an example value.</li>
  145        * <li><code>{2}</code> replaced by a <code>String</code> whose value
  146        * is the label of the input component that produced this message.</li>
  147        * </ul></p>
  148        */
  149       public static final String TIME_ID =
  150            "javax.faces.converter.DateTimeConverter.TIME";
  151   
  152       /**
  153        * <p>The message identifier of the {@link javax.faces.application.FacesMessage} to be created if
  154        * the conversion to <code>DateTime</code> fails.  The message format
  155        * string for this message may optionally include the following
  156        * placeholders:
  157        * <ul>
  158        * <li><code>{0}</code> replaced by the unconverted value.</li>
  159        * <li><code>{1}</code> replaced by an example value.</li>
  160        * <li><code>{2}</code> replaced by a <code>String</code> whose value
  161        * is the label of the input component that produced this message.</li>
  162        * </ul></p>
  163        */
  164       public static final String DATETIME_ID =
  165            "javax.faces.converter.DateTimeConverter.DATETIME";
  166   
  167       /**
  168        * <p>The message identifier of the {@link javax.faces.application.FacesMessage} to be created if
  169        * the conversion of the <code>DateTime</code> value to
  170        * <code>String</code> fails.   The message format string for this message
  171        * may optionally include the following placeholders:
  172        * <ul>
  173        * <li><code>{0}</code> relaced by the unconverted value.</li>
  174        * <li><code>{1}</code> replaced by a <code>String</code> whose value
  175        * is the label of the input component that produced this message.</li>
  176        * </ul></p>
  177        */
  178       public static final String STRING_ID =
  179            "javax.faces.converter.STRING";
  180   
  181   
  182       private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone("GMT");
  183   
  184       // ------------------------------------------------------ Instance Variables
  185   
  186   
  187       private String dateStyle = "default";
  188       private Locale locale = null;
  189       private String pattern = null;
  190       private String timeStyle = "default";
  191       private TimeZone timeZone = DEFAULT_TIME_ZONE;
  192       private String type = "date";
  193   
  194       // -------------------------------------------------------------- Properties
  195   
  196   
  197       /**
  198        * <p>Return the style to be used to format or parse dates.  If not set,
  199        * the default value, <code>default<code>, is returned.</p>
  200        */
  201       public String getDateStyle() {
  202   
  203           return (this.dateStyle);
  204   
  205       }
  206   
  207   
  208       /**
  209        * <p>Set the style to be used to format or parse dates.  Valid values
  210        * are <code>default</code>, <code>short</code>, <code>medium</code>,
  211        * <code>long</code>, and <code>full</code>.
  212        * An invalid value will cause a {@link ConverterException} when
  213        * <code>getAsObject()</code> or <code>getAsString()</code> is called.</p>
  214        *
  215        * @param dateStyle The new style code
  216        */
  217       public void setDateStyle(String dateStyle) {
  218   
  219           this.dateStyle = dateStyle;
  220   
  221       }
  222   
  223   
  224       /**
  225        * <p>Return the <code>Locale</code> to be used when parsing or formatting
  226        * dates and times. If not explicitly set, the <code>Locale</code> stored
  227        * in the {@link javax.faces.component.UIViewRoot} for the current
  228        * request is returned.</p>
  229        */
  230       public Locale getLocale() {
  231   
  232           if (this.locale == null) {
  233               this.locale =
  234                    getLocale(FacesContext.getCurrentInstance());
  235           }
  236           return (this.locale);
  237   
  238       }
  239   
  240   
  241       /**
  242        * <p>Set the <code>Locale</code> to be used when parsing or formatting
  243        * dates and times.  If set to <code>null</code>, the <code>Locale</code>
  244        * stored in the {@link javax.faces.component.UIViewRoot} for the current
  245        * request will be utilized.</p>
  246        *
  247        * @param locale The new <code>Locale</code> (or <code>null</code>)
  248        */
  249       public void setLocale(Locale locale) {
  250   
  251           this.locale = locale;
  252   
  253       }
  254   
  255   
  256       /**
  257        * <p>Return the format pattern to be used when formatting and
  258        * parsing dates and times.</p>
  259        */
  260       public String getPattern() {
  261   
  262           return (this.pattern);
  263   
  264       }
  265   
  266   
  267       /**
  268        * <p>Set the format pattern to be used when formatting and parsing
  269        * dates and times.  Valid values are those supported by
  270        * <code>java.text.SimpleDateFormat</code>.
  271        * An invalid value will cause a {@link ConverterException} when
  272        * <code>getAsObject()</code> or <code>getAsString()</code> is called.</p>
  273        *
  274        * @param pattern The new format pattern
  275        */
  276       public void setPattern(String pattern) {
  277   
  278           this.pattern = pattern;
  279   
  280       }
  281   
  282   
  283       /**
  284        * <p>Return the style to be used to format or parse times.  If not set,
  285        * the default value, <code>default</code>, is returned.</p>
  286        */
  287       public String getTimeStyle() {
  288   
  289           return (this.timeStyle);
  290   
  291       }
  292   
  293   
  294       /**
  295        * <p>Set the style to be used to format or parse times.  Valid values
  296        * are <code>default</code>, <code>short</code>, <code>medium</code>,
  297        * <code>long</code>, and <code>full</code>.
  298        * An invalid value will cause a {@link ConverterException} when
  299        * <code>getAsObject()</code> or <code>getAsString()</code> is called.</p>
  300        *
  301        * @param timeStyle The new style code
  302        */
  303       public void setTimeStyle(String timeStyle) {
  304   
  305           this.timeStyle = timeStyle;
  306   
  307       }
  308   
  309   
  310       /**
  311        * <p>Return the <code>TimeZone</code> used to interpret a time value.
  312        * If not explicitly set, the default time zone of <code>GMT</code>
  313        * returned.</p>
  314        */
  315       public TimeZone getTimeZone() {
  316   
  317           return (this.timeZone);
  318   
  319       }
  320   
  321   
  322       /**
  323        * <p>Set the <code>TimeZone</code> used to interpret a time value.</p>
  324        *
  325        * @param timeZone The new time zone
  326        */
  327       public void setTimeZone(TimeZone timeZone) {
  328   
  329           this.timeZone = timeZone;
  330   
  331       }
  332   
  333   
  334       /**
  335        * <p>Return the type of value to be formatted or parsed.
  336        * If not explicitly set, the default type, <code>date</code>
  337        * is returned.</p>
  338        */
  339       public String getType() {
  340   
  341           return (this.type);
  342   
  343       }
  344   
  345   
  346       /**
  347        * <p>Set the type of value to be formatted or parsed.
  348        * Valid values are <code>both</code>, <code>date</code>, or
  349        * <code>time</code>.
  350        * An invalid value will cause a {@link ConverterException} when
  351        * <code>getAsObject()</code> or <code>getAsString()</code> is called.</p>
  352        *
  353        * @param type The new date style
  354        */
  355       public void setType(String type) {
  356   
  357           this.type = type;
  358   
  359       }
  360   
  361       // ------------------------------------------------------- Converter Methods
  362   
  363       /**
  364        * @throws ConverterException   {@inheritDoc}
  365        * @throws NullPointerException {@inheritDoc}
  366        */
  367       public Object getAsObject(FacesContext context, UIComponent component,
  368                                 String value) {
  369   
  370           if (context == null || component == null) {
  371               throw new NullPointerException();
  372           }
  373   
  374           Object returnValue = null;
  375           DateFormat parser = null;
  376   
  377           try {
  378   
  379               // If the specified value is null or zero-length, return null
  380               if (value == null) {
  381                   return (null);
  382               }
  383               value = value.trim();
  384               if (value.length() < 1) {
  385                   return (null);
  386               }
  387   
  388               // Identify the Locale to use for parsing
  389               Locale locale = getLocale(context);
  390   
  391               // Create and configure the parser to be used
  392               parser = getDateFormat(locale);
  393               if (null != timeZone) {
  394                   parser.setTimeZone(timeZone);
  395               }
  396   
  397               // Perform the requested parsing
  398               returnValue = parser.parse(value);
  399           } catch (ParseException e) {
  400               if ("date".equals(type)) {
  401                   throw new ConverterException(MessageFactory.getMessage(
  402                        context, DATE_ID, value,
  403                        parser.format(new Date(System.currentTimeMillis())),
  404                        MessageFactory.getLabel(context, component)));
  405               } else if ("time".equals(type)) {
  406                   throw new ConverterException(MessageFactory.getMessage(
  407                        context, TIME_ID, value,
  408                        parser.format(new Date(System.currentTimeMillis())),
  409                        MessageFactory.getLabel(context, component)));
  410               } else if ("both".equals(type)) {
  411                   throw new ConverterException(MessageFactory.getMessage(
  412                        context, DATETIME_ID, value,
  413                        parser.format(new Date(System.currentTimeMillis())),
  414                        MessageFactory.getLabel(context, component)));
  415               }
  416           } catch (ConverterException e) {
  417               throw e;
  418           } catch (Exception e) {
  419               throw new ConverterException(e);
  420           }
  421           return returnValue;
  422       }
  423   
  424       /**
  425        * @throws ConverterException   {@inheritDoc}
  426        * @throws NullPointerException {@inheritDoc}
  427        */
  428       public String getAsString(FacesContext context, UIComponent component,
  429                                 Object value) {
  430   
  431           if (context == null || component == null) {
  432               throw new NullPointerException();
  433           }
  434   
  435           try {
  436   
  437               // If the specified value is null, return a zero-length String
  438               if (value == null) {
  439                   return "";
  440               }
  441   
  442               // If the incoming value is still a string, play nice
  443               // and return the value unmodified
  444               if (value instanceof String) {
  445                   return (String) value;
  446               }
  447   
  448               // Identify the Locale to use for formatting
  449               Locale locale = getLocale(context);
  450   
  451               // Create and configure the formatter to be used
  452               DateFormat formatter = getDateFormat(locale);
  453               if (null != timeZone) {
  454                   formatter.setTimeZone(timeZone);
  455               }
  456   
  457               // Perform the requested formatting
  458               return (formatter.format(value));
  459   
  460           } catch (ConverterException e) {
  461               throw new ConverterException(MessageFactory.getMessage(
  462                    context, STRING_ID, value,
  463                    MessageFactory.getLabel(context, component)), e);
  464           } catch (Exception e) {
  465               throw new ConverterException(MessageFactory.getMessage(
  466                    context, STRING_ID, value,
  467                    MessageFactory.getLabel(context, component)), e);
  468           }
  469       }
  470   
  471       // --------------------------------------------------------- Private Methods
  472   
  473   
  474       /**
  475        * <p>Return a <code>DateFormat</code> instance to use for formatting
  476        * and parsing in this {@link Converter}.</p>
  477        *
  478        * @param locale  The <code>Locale</code> used to select formatting
  479        *                and parsing conventions
  480        * @throws ConverterException if no instance can be created
  481        */
  482       private DateFormat getDateFormat(Locale locale) {
  483   
  484           // PENDING(craigmcc) - Implement pooling if needed for performance?
  485   
  486           if (pattern == null && type == null) {
  487               throw new IllegalArgumentException("Either pattern or type must" +
  488                    " be specified.");
  489           }
  490   
  491           DateFormat df;
  492           if (pattern != null) {
  493               df = new SimpleDateFormat(pattern, locale);
  494           } else if (type.equals("both")) {
  495               df = DateFormat.getDateTimeInstance
  496                    (getStyle(dateStyle), getStyle(timeStyle), locale);
  497           } else if (type.equals("date")) {
  498               df = DateFormat.getDateInstance(getStyle(dateStyle), locale);
  499           } else if (type.equals("time")) {
  500               df = DateFormat.getTimeInstance(getStyle(timeStyle), locale);
  501           } else {
  502               // PENDING(craigmcc) - i18n
  503               throw new IllegalArgumentException("Invalid type: " + type);
  504           }
  505           df.setLenient(false);
  506           return (df);
  507   
  508       }
  509   
  510   
  511       /**
  512        * <p>Return the <code>Locale</code> we will use for localizing our
  513        * formatting and parsing processing.</p>
  514        *
  515        * @param context The {@link FacesContext} for the current request
  516        */
  517       private Locale getLocale(FacesContext context) {
  518   
  519           // PENDING(craigmcc) - JSTL localization context?
  520           Locale locale = this.locale;
  521           if (locale == null) {
  522               locale = context.getViewRoot().getLocale();
  523           }
  524           return (locale);
  525   
  526       }
  527   
  528   
  529       /**
  530        * <p>Return the style constant for the specified style name.</p>
  531        *
  532        * @param name Name of the style for which to return a constant
  533        * @throws ConverterException if the style name is not valid
  534        */
  535       private static int getStyle(String name) {
  536   
  537           if ("default".equals(name)) {
  538               return (DateFormat.DEFAULT);
  539           } else if ("short".equals(name)) {
  540               return (DateFormat.SHORT);
  541           } else if ("medium".equals(name)) {
  542               return (DateFormat.MEDIUM);
  543           } else if ("long".equals(name)) {
  544               return (DateFormat.LONG);
  545           } else if ("full".equals(name)) {
  546               return (DateFormat.FULL);
  547           } else {
  548               // PENDING(craigmcc) - i18n
  549               throw new ConverterException("Invalid style '" + name + '\'');
  550           }
  551   
  552       }
  553   
  554       // ----------------------------------------------------- StateHolder Methods
  555   
  556   
  557       public Object saveState(FacesContext context) {
  558   
  559           Object values[] = new Object[6];
  560           values[0] = dateStyle;
  561           values[1] = locale;
  562           values[2] = pattern;
  563           values[3] = timeStyle;
  564           values[4] = timeZone;
  565           values[5] = type;
  566           return (values);
  567   
  568       }
  569   
  570   
  571       public void restoreState(FacesContext context, Object state) {
  572   
  573           Object values[] = (Object[]) state;
  574           dateStyle = (String) values[0];
  575           locale = (Locale) values[1];
  576           pattern = (String) values[2];
  577           timeStyle = (String) values[3];
  578           timeZone = (TimeZone) values[4];
  579           type = (String) values[5];
  580   
  581       }
  582   
  583   
  584       private boolean transientFlag = false;
  585   
  586   
  587       public boolean isTransient() {
  588           return (transientFlag);
  589       }
  590   
  591   
  592       public void setTransient(boolean transientFlag) {
  593           this.transientFlag = transientFlag;
  594       }
  595   
  596   }

Save This Page
Home » mojarra-1.2_09-b02-FCS-source » javax.faces.convert » [javadoc | source]