org.apache.myfaces.trinidad.convert.DateTimeConverter Maven / Gradle / Ivy
Show all versions of trinidad-api Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.trinidad.convert;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.TimeZone;
import javax.el.ValueExpression;
import javax.faces.application.FacesMessage;
import javax.faces.component.StateHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.el.ValueBinding;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
import org.apache.myfaces.trinidad.bean.FacesBean;
import org.apache.myfaces.trinidad.bean.PropertyKey;
import org.apache.myfaces.trinidad.context.RequestContext;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
import org.apache.myfaces.trinidad.util.ComponentUtils;
import org.apache.myfaces.trinidad.util.MessageFactory;
/**
* {@link Converter} implementation for java.util.Date
* values. Converts an strings to and from java.util.Date objects.
*
* The converter has additonal features than standard JSF
* {@link javax.faces.convert.DateTimeConverter}.
*
* New dateStyle shortish
has been introduced. Shortish is identical
* to short
but forces the year to be a full four digits.
* If dateStyle is not set, then dateStyle
defaults to
* shortish
.
*
* Timezone can be set per web-app in trinidad-config.xml configuration file.
* If timeZone
is not set on the converter, then timezone will be defaulted to the
* value set in trinidad-config.xml configuration file. If it is not set in the
* configuration file, then it will be defaulted to GMT.
*
* The converter always allows a level of leniency
while converting
* user input value to date to the following extent.
*
* - A converter with associated pattern 'MMM' for month, when attached to any
* value holder, will accept values with month specified in the form 'MM' or 'M'
* as valid.
* - Allows use of separators '-' or '.' or '/' irrespective of the separator
* specified in the associated pattern.
* - The leniency is applicable to both 'pattern' and 'secondaryPattern'.
*
*
* For example:
* When pattern on the converter is set to "MMM/d/yyyy" the following inputs
* are tolerated as valid by the converter.
*
* - Jan/4/2004
* - Jan-4-2004
* - Jan.4.2004
* - 01/4/2004
* - 01-4-2004
* - 01.4.2004
* - 1/4/2004
* - 1-4-2004
* - 1.4.2004
*
*
*
* The detail part of faces message,for conversion errors can be customized
* by overriding the message associated with each CONVERT_[TYPE]_MESSAGE_ID.
*
* The methods used for customizing the detail message associated with each id
* is given below:
*
* - {@link #CONVERT_DATE_MESSAGE_ID} - {@link #setMessageDetailConvertDate(String)}
* - {@link #CONVERT_TIME_MESSAGE_ID} - {@link #setMessageDetailConvertTime(String) }
* - {@link #CONVERT_BOTH_MESSAGE_ID} - {@link #setMessageDetailConvertBoth(String) }
*
The custom messages can contain placeholders, which will be replaced with
* values as specified in its corresponding message id.
*
* The getAsObject()
method parses a String into a
* java.util.Date
, according to the following algorithm:
*
* - If the specified String is null, return
* a
null
. Otherwise, trim leading and trailing
* whitespace before proceeding.
* - If the specified String - after trimming - has a zero length,
* return
null
.
* - If the
locale
property is not null,
* use that Locale
for managing parsing. Otherwise, use the
* Locale
from the UIViewRoot
.
* - If a
pattern
has been specified, its syntax must conform
* the rules specified by java.text.SimpleDateFormat
. Such
* a pattern will be used to parse, and the type
,
* dateStyle
, and timeStyle
properties
* will be ignored.
* - If a
pattern
has not been specified, parsing will be based
* on the type
property, which expects a date value, a time
* value, or both. Any date and time values included will be parsed in
* accordance to the styles specified by dateStyle
and
* timeStyle
, respectively.
* - If conversion fails with
pattern
or style
* and if secondaryPattern
is set, re parsers based on the
* secondaryPattern
. Syntax for secondaryPattern
* must conform to the rules specified by
* java.text.SimpleDateFormat
.
* - Parsing is lenient as outlined earlier and is not the same as setting
* leniency on
java.text.DateFormat
*
*
* The getAsString()
method expects a value of type
* java.util.Date
(or a subclass), and creates a formatted
* String according to the following algorithm:
*
* - If the specified value is null, return a zero-length String.
* - If the specified value is a String, return it unmodified.
* - If the
locale
property is not null,
* use that Locale
for managing formatting. Otherwise, use the
* Locale
from the UIViewRoot
.
* - If a
pattern
has been specified, its syntax must conform
* the rules specified by java.text.SimpleDateFormat
. Such
* a pattern will be used to format, and the type
,
* dateStyle
, and timeStyle
properties
* will be ignored.
* - If a
pattern
has not been specified, formatting will be
* based on the type
property, which includes a date value,
* a time value, or both into the formatted String. Any date and time
* values included will be formatted in accordance to the styles specified
* by dateStyle
and timeStyle
, respectively.
* secondaryPattern
even if set is never used for formatting
* to a String
*
*
* @see #CONVERT_DATE_MESSAGE_ID
* @see #CONVERT_TIME_MESSAGE_ID
* @see #CONVERT_BOTH_MESSAGE_ID
* @see java.text.DateFormat
* @see java.text.SimpleDateFormat
*
* @version $Name: $ ($Revision: adfrt/faces/adf-faces-api/src/main/java/oracle/adf/view/faces/convert/DateTimeConverter.java#0 $) $Date: 10-nov-2005.19:09:11 $
*/
@JSFConverter(configExcluded=true)
public class DateTimeConverter extends javax.faces.convert.DateTimeConverter
implements Converter, StateHolder
{
/**
* Standard converter id for this converter.
*/
public static final String CONVERTER_ID = "org.apache.myfaces.trinidad.DateTime";
/**
* The message identifier of the FacesMessage to be created if
* the value cannot be converted to a date, when pattern
* is null or not set and type
is set to 'date'
.
* Or when failures occurs when value cannot be converted to a date
* based on the pattern set. The message format string for this message
* may optionally include {0}
, {1}
, {4}
* placeholdes, which will be replaced by input value, component label
* and example date based on the pattern
or based on the
* style
when type
is set to 'date'
.
*/
public static final String CONVERT_DATE_MESSAGE_ID =
"org.apache.myfaces.trinidad.convert.DateTimeConverter.CONVERT_DATE";
/**
* The message identifier of the FacesMessage to be created if
* the value cannot be converted date time object, when type
* is set to 'time'
and pattern is null or not set.
* The message format string for this message may optionally include
* {0}
, {1}
, {4}
* placeholdes, which will be replaced by input value, component label
* and a time example, based on the timeStyle
* set in the converter.
*/
public static final String CONVERT_TIME_MESSAGE_ID =
"org.apache.myfaces.trinidad.convert.DateTimeConverter.CONVERT_TIME";
/**
* The message identifier of the FacesMessage to be created if
* the value cannot be converted to a date when type
* is set to 'both'
and pattern is either null or not set. The
* message format string for this message may optionally include
* {0}
, {1}
, {4}
* placeholdes, which will be replaced by input value, component label
* and a date-time example, based on the dateStyle
and
* timeStyle
set in the converter.
*/
public static final String CONVERT_BOTH_MESSAGE_ID =
"org.apache.myfaces.trinidad.convert.DateTimeConverter.CONVERT_BOTH";
/**
* Creates a DateTimeConverter
*/
public DateTimeConverter()
{
}
/**
* Creates a DateTimeConverter with the specified SimpleDateFormat format
* pattern
* @param pattern a primary pattern; this will be used to format
* and parser strings.
*/
public DateTimeConverter(String pattern)
{
this();
setPattern(pattern);
}
/**
* Creates a DateTimeConverter with the specified SimpleDateFormat format
* pattern and a secondary pattern.
* @param pattern a primary pattern; this will be used to format
* and parser strings.
* @param secondaryPattern a second pattern, which will be used
* as a second attempt to parse a string if the primary pattern or
* styles fail, but is never used for formatting strings.
*/
public DateTimeConverter(String pattern, String secondaryPattern)
{
this(pattern);
setSecondaryPattern(secondaryPattern);
}
/**
* Convert the specified string value, which is associated with
* the specified {@link UIComponent}, into a java.util.Date object
* based on the values set.
*
* @param context {@link FacesContext} for the request being processed
* @param component {@link UIComponent} with which this model object
* value is associated
* @param value String value to be converted (may be null
)
*
* @return null
if the value to convert is null
,
* otherwise return a java.util.Date object.
*
* @exception ConverterException if conversion cannot be successfully
* performed
* @exception NullPointerException if context
or
* component
is null
*
* @exception IllegalArgumentException if the value
is of
* type other than {@link java.util.Date}, {@link java.lang.String}. The
* value
can be null.
*/
@Override
public Object getAsObject(
FacesContext context,
UIComponent component,
String value)
{
if (isDisabled())
return value;
Date date = _getParsedDate(context, component, value);
if (date != null)
{
_fillTimePortion(context, component, date);
}
return date;
}
/**
* Convert the model Date object value, into a String based on the pattern
* or styles.
* @param context {@link FacesContext} for the request being processed
* @param component {@link UIComponent} with which this model object
* value is associated
* @param value Model object value to be converted
* (may be null
)
*
* @return a zero-length String if value is null
,
* otherwise the result of the conversion
*
* @exception ConverterException if conversion cannot be successfully
* performed
* @exception NullPointerException if context
or
* component
is null
*/
@Override
public String getAsString(
FacesContext context,
UIComponent component,
Object value
)
{
if (context == null || component == null)
throw new NullPointerException(_LOG.getMessage(
"NULL_FACESCONTEXT_OR_UICOMPONENT"));
if (null == value)
return "";
if (value instanceof String)
return (String)value;
if (isDisabled())
return value.toString();
if (!(value instanceof Date))
throw new ClassCastException(_LOG.getMessage(
"VALUE_IS_NOT_DATE_TYPE_IT_IS", new Object[]{value,value.getClass()}));
DateFormat format = _getDateFormat(context, getPattern(), false, (Date)value);
return format.format(value);
}
/**
* Custom error message to be used, for creating detail part of the {@link FacesMessage},
* for values that cannot be converted to {@link java.util.Date} when the
* pattern / secondary pattern
is set or when type
* is set to 'date'
.
* Overrides detail message identified by message id {@link #CONVERT_DATE_MESSAGE_ID}
* @param convertDateMessageDetail custom error message.
*
*/
public void setMessageDetailConvertDate(String convertDateMessageDetail)
{
_facesBean.setProperty(_CONVERT_DATE_MESSAGE_DETAIL_KEY, convertDateMessageDetail);
}
/**
* Return custom detail error message that was set for creating {@link FacesMessage},
* for values that cannot be converted to {@link java.util.Date} when
* pattern / secondary pattern
is set or
* when type
is set to 'date'
.
* @return custom error message that was set.
* @see #setMessageDetailConvertDate(String)
*/
@JSFProperty
public String getMessageDetailConvertDate()
{
Object msg = _facesBean.getProperty(_CONVERT_DATE_MESSAGE_DETAIL_KEY);
return ComponentUtils.resolveString(msg);
}
/**
* Custom error message to be used, for creating detail part of the {@link FacesMessage},
* for time based value that cannot be converted to date
* when type
is set to 'time'
.
* Overrides detail message identified by message id {@link #CONVERT_TIME_MESSAGE_ID}
* @param convertTimeMessageDetail custom error message.
*/
public void setMessageDetailConvertTime(String convertTimeMessageDetail)
{
_facesBean.setProperty(_CONVERT_TIME_MESSAGE_DETAIL_KEY, convertTimeMessageDetail);
}
/**
* Return custom detail error message that was set for creating {@link FacesMessage},
* for values that cannot be converted to {@link java.util.Date}
* when type
is set to 'time'
.
* @return custom error message that was set.
* @see #setMessageDetailConvertTime(java.lang.String)
*/
@JSFProperty
public String getMessageDetailConvertTime()
{
Object msg =_facesBean.getProperty(_CONVERT_TIME_MESSAGE_DETAIL_KEY);
return ComponentUtils.resolveString(msg);
}
/**
* Custom error message to be used, for creating detail part of the {@link FacesMessage},
* for date-time based value that cannot be converted to {@link java.util.Date}
* when type
is set to 'both'
.
* Overrides detail message identified by message id {@link #CONVERT_BOTH_MESSAGE_ID}
* @param convertBothMessageDetail custom error message.
* @see #CONVERT_BOTH_MESSAGE_ID
*/
public void setMessageDetailConvertBoth(String convertBothMessageDetail)
{
_facesBean.setProperty(_CONVERT_BOTH_MESSAGE_DETAIL_KEY, convertBothMessageDetail);
}
/**
* Return custom detail error message that was set for creating {@link FacesMessage},
* for values that cannot be converted to {@link java.util.Date}
* when type
is set to 'both'
.
* @return custom error message that was set.
* @see #setMessageDetailConvertBoth(java.lang.String)
*/
@JSFProperty
public String getMessageDetailConvertBoth()
{
Object msg = _facesBean.getProperty(_CONVERT_BOTH_MESSAGE_DETAIL_KEY);
return ComponentUtils.resolveString(msg);
}
/**
* Custom hintDate message.
* Overrides default hint message
* @param hintDate Custom hint message.
*/
public void setHintDate(String hintDate)
{
_facesBean.setProperty(_HINT_DATE_KEY, hintDate);
}
/**
* Return custom hintDate message.
* @return Custom hint message.
* @see #setHintDate(String)
*/
public String getHintDate()
{
Object obj = _facesBean.getProperty(_HINT_DATE_KEY);
return ComponentUtils.resolveString(obj);
}
/**
* Custom hintTime message.
* Overrides default hint message
* @param hintTime Custom hint message.
*/
public void setHintTime(String hintTime)
{
_facesBean.setProperty(_HINT_TIME_KEY, hintTime);
}
/**
* Return custom hintTime message.
* @return Custom hint message.
* @see #setHintTime(String)
*/
public String getHintTime()
{
Object obj = _facesBean.getProperty(_HINT_TIME_KEY);
return ComponentUtils.resolveString(obj);
}
/**
* Custom hintBoth message.
* Overrides default hint message
* @param hintBoth Custom hint message.
*/
public void setHintBoth(String hintBoth)
{
_facesBean.setProperty(_HINT_BOTH_KEY, hintBoth);
}
/**
* Return custom hintBoth message.
* @return Custom hint message.
* @see #setHintBoth(String)
*/
public String getHintBoth()
{
Object obj = _facesBean.getProperty(_HINT_BOTH_KEY);
return ComponentUtils.resolveString(obj);
}
/**
* Gets the existing date from the component.
* This date will be used to fill in missing portions of the new date.
* For example, if the new date is missing the time, the time portion
* from the existing date will be used.
*
* This implementation checks to see if the component is a ValueHolder, and
* calls getValue() and returns the result if it is a Date instance.
* @param component The component to get the existing date from.
* @return null if there is no existing date.
*/
protected Date getDate(FacesContext context, UIComponent component)
{
if (component instanceof ValueHolder)
{
Object value = ((ValueHolder)component).getValue();
if(value instanceof Date)
{
return (Date)value;
}
}
return null;
}
private Locale _extractConverterLocale(
FacesContext context)
{
Locale locale = getLocale();
if (null == locale)
{
RequestContext reqContext = RequestContext.getCurrentInstance();
if (reqContext != null)
{
locale = reqContext.getFormattingLocale();
}
if (locale == null)
{
locale = context.getViewRoot().getLocale();
}
}
return locale;
}
private Date _getParsedDate(FacesContext context,
UIComponent component,
String value)
{
if (context == null || component == null)
throw new NullPointerException(_LOG.getMessage(
"NULL_FACESCONTEXT_OR_UICOMPONENT"));
if (null == value)
return null;
value = value.trim();
if ( 1 > value.length() )
return null;
try
{
String pattern = getPattern();
if (pattern == null)
{
// get the pattern based on the style and type that has been set.
DateFormat format = getDateFormat(context, null, true, null);
if (format instanceof SimpleDateFormat)
{
pattern = ((SimpleDateFormat)format).toPattern();
}
}
if (pattern != null)
{
return _doLenientParse(context, component, value, pattern);
}
else
{
// more unlikely that we will get null pattern here but just to be safe
return _parse(context, component, value, null);
}
}
catch (ConverterException ce)
{
try
{
// If the parsing fails with primary pattern or with the styles
// then we try with the secondary pattern.
String secPattern = getSecondaryPattern();
if ( secPattern != null)
{
return _doLenientParse(context, component, value, secPattern);
}
}
catch(ConverterException secondaryCe)
{
// either way we throw the first exception.
;
}
throw ce;
}
}
// for fixing bug 4469819.
/**
* Fill in the time portion of the new date with the time from the previous
* date value if the converter displays only date. For now, we are not
* bothered about filling all the missing parts of the pattern. But in
* future we would consider that.
*/
private void _fillTimePortion(
FacesContext context,
UIComponent component,
Date newDate)
{
// get the previous date value
Date prevDate = getDate(context, component);
// if the component doesn't have any date value before, return
if (prevDate == null)
{
return;
}
// if the converter uses timePortion, then we need not do anything
String pattern = getPattern();
if (pattern == null && !"date".equals(getType()))
{
return;
}
// find out the missing time components from the pattern
boolean fillMilliSeconds = true;
boolean fillSeconds = true;
boolean fillMinutes = true;
boolean fillHour = true;
if (pattern != null)
{
int patternLen = pattern.length();
for (int currCharIndex = 0; currCharIndex < patternLen; currCharIndex++)
{
switch (pattern.charAt(currCharIndex))
{
case 'S':
fillMilliSeconds = false;
break;
case 's':
fillSeconds = false;
break;
case 'm':
fillMinutes = false;
break;
case 'h':
case 'H':
case 'k':
case 'K':
fillHour = false;
break;
}
}
}
// fill only if any of the time components are missing
if ( fillMilliSeconds || fillSeconds || fillMinutes || fillHour )
{
TimeZone timeZone = _getTimeZone();
// convert the previous date value wrt client's timeZone
Calendar prevCal = Calendar.getInstance(timeZone);
prevCal.setTime(prevDate);
// convert the new date value wrt client's timeZone
Calendar newCal = Calendar.getInstance(timeZone);
newCal.setTime(newDate);
// extract all the missing time portions from the previous date value
// and set it to the new date value.
if (fillMilliSeconds)
{
newCal.set(Calendar.MILLISECOND, prevCal.get(Calendar.MILLISECOND));
}
if (fillSeconds)
{
newCal.set(Calendar.SECOND, prevCal.get(Calendar.SECOND));
}
if(fillMinutes)
{
newCal.set(Calendar.MINUTE, prevCal.get(Calendar.MINUTE));
}
if(fillHour)
{
newCal.set(Calendar.HOUR_OF_DAY, prevCal.get(Calendar.HOUR_OF_DAY));
}
// modify the new date value.
newDate.setTime(newCal.getTimeInMillis());
}
}
private Date _parse(
FacesContext context,
UIComponent component,
String value,
String pattern
)
{
DateFormat fmt = getDateFormat(context, pattern, true, null);
try
{
return fmt.parse(value);
} catch (ConverterException ce)
{
throw ce;
}
catch (ParseException pe)
{
Object[] params = _getPlaceHolderParameters(context, component, value);
throw new ConverterException(getParseErrorMessage(context, component,
pattern, params),
pe);
}
}
/**
* Does some more lenient parsing than the stric JSF standard wants.
*/
private Date _doLenientParse(
FacesContext context,
UIComponent component,
String value,
String pattern
)
{
// When a pattern (e.g. dd.MM.yyyy HH:mm' Uhr ') requires a whitespace
// at the end, we should honor that. As the JSF spec (see http://bit.ly/kTelf)
// wants the converter to trim leading/trailing whitespace, we have to append
// one, if the pattern requires it at the end...
// TODO at the beginning as well ?
if(pattern.endsWith(" '"))
{
value += " ";
}
// do lenient parsing for the pattern supplied.
// accept derived patterns during
// parsing, allowing:
// 01/13/99 --> 13-Jan-99
// 03/Oct/99 --> 03-Oct-99
// 03.Oct.99 --> 03-Oct-99
ConverterException ce;
try
{
return _parse(context, component, value, pattern);
}
catch (ConverterException convException)
{
// Let us save this exception to throw, if in case we have exhausted
// all possible patterns
ce = convException;
List patterns = new ArrayList();
patterns.add(pattern);
Locale locale = _extractConverterLocale(context);
// we apply some patterns for convenience reasons (see TRINIDAD-859, 1262)
if (_CONVENIENCE_PATTERNS.containsKey(locale))
{
patterns.addAll(_CONVENIENCE_PATTERNS.get(locale));
}
List lenientPatterns = new ArrayList();
for (String tmpPattern : patterns)
{
lenientPatterns.addAll(_getLenientPatterns(tmpPattern));
}
for (String lenientPattern : lenientPatterns)
{
try
{
return _parse(context, component, value, lenientPattern);
}
catch (ConverterException e)
{
// Just do nothing with the excpetion - we still need to evaluate
// for other possible patterns, and we will throw the initially caught
// exception, which will convey to the user the appropriate message.
continue;
}
}
throw ce;
}
}
/**
* Set the Locale
to be used when parsing or formatting
* dates and times. If set to null
, the Locale
* stored in the {@link javax.faces.component.UIViewRoot} for the current
* request will be utilized.
*
* @param locale The new Locale
(or null
)
*/
@Override
public void setLocale(Locale locale)
{
_facesBean.setProperty(_LOCALE_KEY, locale);
}
/**
* Return the Locale
that was set.
* If not explicitly set, the Locale
stored
* in the {@link javax.faces.component.UIViewRoot} for the current
* request is used during call to getAsObject
and
* getAsString
.
*/
@JSFProperty
@Override
public Locale getLocale()
{
Object locale = _facesBean.getProperty(_LOCALE_KEY);
return ComponentUtils.resolveLocale(locale);
}
/**
* Set the format pattern to be used when formatting and parsing
* dates and times. Valid values are those supported by
* java.text.SimpleDateFormat
.
* An invalid value will cause a {@link ConverterException} when
* getAsObject()
or getAsString()
is called.
*
* @param pattern The new format pattern
*/
@Override
public void setPattern(String pattern)
{
_facesBean.setProperty(_PATTERN_KEY, pattern);
}
/**
* Return the format pattern to be used when formatting and
* parsing dates and times.
*/
@JSFProperty
@Override
public String getPattern()
{
Object patternObj = _facesBean.getProperty(_PATTERN_KEY);
String pattern = ComponentUtils.resolveString(patternObj);
if (pattern != null && pattern.trim().isEmpty())
{
return null;
}
return pattern;
}
/**
* Set the TimeZone
used to interpret a time value.
*
* @param timeZone The new time zone
*/
@Override
public void setTimeZone(TimeZone timeZone)
{
_facesBean.setProperty(_TIME_ZONE_KEY, timeZone);
}
/**
* Return the TimeZone
that is used to interpret a time value.
* If not explicitly set or if a null value is set, then during call to
* getAsObject
and getAsString
, the time zone set
* for the web-app is used. If time zone is not set for the web-app then
* the default time zone of GMT
is used.
*/
@JSFProperty
@Override
public TimeZone getTimeZone()
{
Object timeZone = _facesBean.getProperty(_TIME_ZONE_KEY);
return ComponentUtils.resolveTimeZone(timeZone);
}
/**
* Set the type of value to be formatted or parsed.
* Valid values are both
, date
, or
* time
.
* An invalid value will cause a {@link IllegalStateException} when
* getAsObject()
or getAsString()
is called.
*
* @param type The new date style
*/
@Override
public void setType(String type)
{
_facesBean.setProperty(_TYPE_KEY, type);
}
/**
* Return the type of value to be formatted or parsed.
* If not explicitly set, the default type, date
* is returned.
*/
@JSFProperty(defaultValue="date")
@Override
public String getType()
{
Object type = _facesBean.getProperty(_TYPE_KEY);
return ComponentUtils.resolveString(type, "date");
}
/**
* Set the style to be used to format or parse dates. Valid values
* are default
, shortish
* short
, medium
,
* long
, and full
.
* An invalid value will cause a {@link IllegalStateException} when
* getAsObject()
or getAsString()
is called.
*
* @param dateStyle The new style code
*/
@Override
public void setDateStyle(String dateStyle)
{
_facesBean.setProperty(_DATE_STYLE_KEY, dateStyle);
}
/**
* Return the style to be used to format or parse dates. If not set,
* the default value, shortish
, is returned.
* @see #setDateStyle(java.lang.String)
* @return date style
*/
@JSFProperty(defaultValue="shortish")
@Override
public String getDateStyle()
{
Object dateStyle = _facesBean.getProperty(_DATE_STYLE_KEY);
return ComponentUtils.resolveString(dateStyle, "shortish");
}
/**
* Set the style to be used to format or parse times. Valid values
* are default
, short
,
* medium
, long
, and full
.
* An invalid value will cause a {@link IllegalStateException} when
* getAsObject()
or getAsString()
is called.
*
* @param timeStyle The new style code
*/
@Override
public void setTimeStyle(String timeStyle)
{
_facesBean.setProperty(_TIME_STYLE_KEY, timeStyle);
}
/**
* Return the style to be used to format or parse times. If not set,
* the default value, short
, is returned.
*/
@JSFProperty(defaultValue="short")
@Override
public String getTimeStyle()
{
Object timeStyle = _facesBean.getProperty(_TIME_STYLE_KEY);
return ComponentUtils.resolveString(timeStyle, "short");
}
/**
* Second pattern which will be used to parse string in
* getAsObject
if pattern or styles fail. But is never
* used for formatting to string in getAsString()
.
* @param secondaryPattern a second pattern which will be used
* as a second attempt to parse a string if the primary pattern or
* styles fail, but is never used for formatting strings.
*/
public void setSecondaryPattern(String secondaryPattern)
{
_facesBean.setProperty(_SECONDARY_PATTERN_KEY, secondaryPattern);
}
/**
* Return the secondary pattern used to parse string when parsing by
* pattern or style fails.
*/
@JSFProperty
public String getSecondaryPattern()
{
Object secPattern = _facesBean.getProperty(_SECONDARY_PATTERN_KEY);
return ComponentUtils.resolveString(secPattern);
}
@Override
public boolean isTransient()
{
return _isTransient;
}
@Override
public void setTransient(boolean isTransient)
{
_isTransient = isTransient;
}
@Override
public Object saveState(FacesContext context)
{
return _facesBean.saveState(context);
}
@Override
public void restoreState(FacesContext context, Object state)
{
_facesBean.restoreState(context, state);
}
/**
* Set the {@link ValueExpression} used to calculate the value for the
* specified attribute if any.
*
* @param name Name of the attribute for which to set a {@link ValueExpression}
* @param expression The {@link ValueExpression} to set, or null
* to remove any currently set {@link ValueExpression}
*
* @exception NullPointerException if name
* is null
* @exception IllegalArgumentException if name
is not a valid
* attribute of this converter
*/
public void setValueExpression(String name, ValueExpression expression)
{
ConverterUtils.setValueExpression(_facesBean, name, expression) ;
}
/**
* Return the {@link ValueExpression} used to calculate the value for the
* specified attribute name, if any.
*
* @param name Name of the attribute or property for which to retrieve a
* {@link ValueExpression}
*
* @exception NullPointerException if name
* is null
* @exception IllegalArgumentException if name
is not a valid
* attribute of this converter
*/
public ValueExpression getValueExpression(String name)
{
return ConverterUtils.getValueExpression(_facesBean, name);
}
/**
* Set the {@link ValueBinding} used to calculate the value for the
* specified attribute if any.
*
* @param name Name of the attribute for which to set a {@link ValueBinding}
* @param binding The {@link ValueBinding} to set, or null
* to remove any currently set {@link ValueBinding}
*
* @exception NullPointerException if name
* is null
* @exception IllegalArgumentException if name
is not a valid
* attribute of this converter
* @deprecated
*/
public void setValueBinding(String name, ValueBinding binding)
{
ConverterUtils.setValueBinding(_facesBean, name, binding) ;
}
/**
* Return the {@link ValueBinding} used to calculate the value for the
* specified attribute name, if any.
*
* @param name Name of the attribute or property for which to retrieve a
* {@link ValueBinding}
*
* @exception NullPointerException if name
* is null
* @exception IllegalArgumentException if name
is not a valid
* attribute of this converter
* @deprecated
*/
public ValueBinding getValueBinding(String name)
{
return ConverterUtils.getValueBinding(_facesBean, name);
}
/**
* Compares this DateTimeConverter with the specified Object for
* equality.
* @param object Object to which this DateTimeConverter is to be compared.
* @return true if and only if the specified Object is a DateTimeConverter
* and if all parameters are equal.
*/
@Override
public boolean equals(Object object)
{
if (this == object)
return true;
if(object instanceof DateTimeConverter)
{
DateTimeConverter other = (DateTimeConverter)object;
if ( (isDisabled() == other.isDisabled())
&& (isTransient() == other.isTransient())
&& ConverterUtils.equals(getDateStyle(), other.getDateStyle())
&& ConverterUtils.equals(getLocale(), other.getLocale())
&& ConverterUtils.equals(getPattern(), other.getPattern())
&& ConverterUtils.equals(getTimeStyle(), other.getTimeStyle())
&& ConverterUtils.equals(getTimeZone(), other.getTimeZone())
&& ConverterUtils.equals(getType(), other.getType())
&& ConverterUtils.equals(getSecondaryPattern(), other.getSecondaryPattern())
&& ConverterUtils.equals(getMessageDetailConvertDate(),
other.getMessageDetailConvertDate())
&& ConverterUtils.equals(getMessageDetailConvertTime(),
other.getMessageDetailConvertTime())
&& ConverterUtils.equals(getMessageDetailConvertBoth(),
other.getMessageDetailConvertBoth())
)
{
return true;
}
}
return false;
}
/**
* Returns the hash code for this Converter.
* @return a hash code value for this object.
*/
@Override
public int hashCode()
{
int result = 17;
result = result * 37 + (isDisabled() ? 1 : 0);
result = result * 37 + (isTransient()? 1 : 0);
result = result * 37 + _getHashValue(getDateStyle());
result = result * 37 + _getHashValue(getLocale());
result = result * 37 + _getHashValue(getPattern());
result = result * 37 + _getHashValue(getTimeStyle());
result = result * 37 + _getHashValue(getTimeZone());
result = result * 37 + _getHashValue(getType());
result = result * 37 + _getHashValue(getSecondaryPattern());
result = result * 37 + _getHashValue(getMessageDetailConvertDate());
result = result * 37 + _getHashValue(getMessageDetailConvertTime());
result = result * 37 + _getHashValue(getMessageDetailConvertBoth());
return result;
}
/**
* Set the value to property disabled
. Default value is false.
* @param isDisabled true
if it's disabled, false
otherwise.
*/
public void setDisabled(boolean isDisabled)
{
_facesBean.setProperty(_DISABLED_KEY, Boolean.valueOf(isDisabled));
}
/**
* Return whether it is disabled.
* @return true if it's disabled and false if it's enabled.
*/
public boolean isDisabled()
{
Boolean disabled = (Boolean) _facesBean.getProperty(_DISABLED_KEY);
return (disabled != null) ? disabled.booleanValue() : false;
}
protected final DateFormat getDateFormat(
FacesContext context,
String pattern,
boolean forParsing,
Date targetDate
) throws ConverterException
{
ConverterException exception = null;
try
{
DateFormat format = _getDateFormat(context, pattern, forParsing, targetDate);
return format;
}
catch (ConverterException ce)
{
exception = ce;
}
catch (Exception e)
{
exception = new ConverterException(e);
}
throw exception;
}
/**
* Returns the TimeZone that will be set on DateFormat for formatting
* and parsing the dates. By default, this just returns the specified
* time zone, the one that is set on the DateTimeConverter or in the
* Adf-Faces config.
*/
protected TimeZone getFormattingTimeZone(TimeZone tZone)
{
return getFormattingTimeZone (tZone, null);
}
/**
* Returns the timeZone for formatting and parsing the date.
* TRINIDAD-1512: In some cases,timezone varies depending on the targetDate,
* e.g. daylight savings.
*/
protected TimeZone getFormattingTimeZone(TimeZone tZone, Date targetDate)
{
return tZone;
}
// This is used while displaying error message at the client side.
// Identifies the pattern expected to be matched.
private String[] _getExpectedPatterns(FacesContext context)
{
String pattern = getPattern();
if ( pattern != null )
{
return _getAllowedPatterns(context, pattern, getSecondaryPattern());
}
else
{
String datePattern = null;
try
{
DateFormat format = getDateFormat(context, null,false, null);
if ((format != null) && (format instanceof SimpleDateFormat))
{
datePattern = ((SimpleDateFormat)format).toPattern();
}
}
catch (ConverterException ce)
{
// Do nothing here. Check to see if secondary pattern is available.
;
}
return _getAllowedPatterns(context, datePattern, getSecondaryPattern());
}
}
protected final FacesMessage getParseErrorMessage(
FacesContext context,
UIComponent component,
String pattern,
Object[] params
)
{
// if pattern is set then - conversion would have been carried out using
// the pattern or secondary pattern.
String key = getViolationMessageKey(pattern);
return _getConvertErrorFacesMessage(context, key, params, component);
}
protected final String getExample(FacesContext context)
{
String[] expectedPatterns = _getExpectedPatterns(context);
assert((expectedPatterns != null) && (expectedPatterns.length >= 1));
String example = expectedPatterns[0];
return example;
}
private String[] _getAllowedPatterns(
FacesContext context,
String mainPattern,
String secondaryPattern
)
{
String[] patterns;
if (mainPattern != null)
{
if (secondaryPattern != null)
{
patterns = new String[]{mainPattern, secondaryPattern};
}
else
{
patterns = new String[]{mainPattern};
}
}
else
{
patterns = new String[]{secondaryPattern};
}
// Convert each pattern into an example
for (int i = 0; i < patterns.length; i++)
{
patterns[i] = _getExample(context, patterns[i]);
}
return patterns;
}
/**
* Return the style constant for the specified style name.
* If invalid throw IllegalStateException.
*
* @param dateStyle Name of the date style for which to return a constant
*
*/
private static final int _getDateStyle(String dateStyle)
{
if (dateStyle.equals("shortish"))
{
return _SHORTISH;
}
else if (dateStyle.equals("default"))
{
return (DateFormat.DEFAULT);
}
else if (dateStyle.equals("short"))
{
return (DateFormat.SHORT);
}
else if (dateStyle.equals("medium"))
{
return (DateFormat.MEDIUM);
}
else if (dateStyle.equals("long"))
{
return (DateFormat.LONG);
}
else if (dateStyle.equals("full"))
{
return (DateFormat.FULL);
}
else
throw new IllegalStateException(_LOG.getMessage(
"INVALID_DATE_STYLE", dateStyle));
}
private static final int _getTimeStyle(String timeStyle)
{
if ("default".equals(timeStyle))
{
return (DateFormat.DEFAULT);
}
else if ("short".equals(timeStyle))
{
return (DateFormat.SHORT);
}
else if ("medium".equals(timeStyle))
{
return (DateFormat.MEDIUM);
}
else if ("long".equals(timeStyle))
{
return (DateFormat.LONG);
}
else if ("full".equals(timeStyle))
{
return (DateFormat.FULL);
}
else
throw new IllegalStateException(_LOG.getMessage(
"INVALID_TIME_STYLE", timeStyle));
}
/**
* The valid values for type are date,time and both. Any value other than this
* would result in a ConverterException.
* @return type
*/
private static int _getType(String type)
{
if ("date".equals(type))
return _TYPE_DATE;
else if ("time".equals(type))
return _TYPE_TIME;
else if ("both".equals(type))
return _TYPE_BOTH;
else
throw new IllegalStateException(_LOG.getMessage(
"INVALID_TYPE", type));
}
// Don't use this for Array Object and other objects which don't implement
// their hashCode()
private static int _getHashValue(Object obj)
{
return obj == null? 0 : obj.hashCode();
}
private static List _getLenientPatterns(String pattern)
{
//Create patterns so as to be lenient.
// allow for
// 01/13/99 --> 13-Jan-99 [MMM -> MM], [MMM -> M]
// Apply the below conversion to the above obtained patterns and the actual
// patern
// 03/Oct/99 --> 03-Oct-99
// 03.Oct.99 --> 03-Oct-99
List patterns = new ArrayList();
// Don't forget to add the actual pattern.
patterns.add(pattern);
String[] leniencyApplicablePatterns = new String[1];
leniencyApplicablePatterns[0] = pattern;
if (pattern.indexOf("MMM") != -1)
{
leniencyApplicablePatterns = new String[3];
leniencyApplicablePatterns[0] = pattern;
String str1 = pattern.replaceAll("MMM", "MM");
patterns.add(str1);
leniencyApplicablePatterns[1] = str1;
String str2 = pattern.replaceAll("MMM", "M");
leniencyApplicablePatterns[2] = str2;
patterns.add(str2);
}
// Apply the leninecy (German for leniency?) to the above obtained patterns which was obtained
// after replacing MMM -> MM and MMM -> M and the actual pattern
int len = leniencyApplicablePatterns.length;
if (pattern.indexOf('/') != -1)
{
for (int i = 0; i < len; i++)
patterns.add(leniencyApplicablePatterns[i].replaceAll("/", "-"));
for (int i = 0; i < len; i++)
patterns.add(leniencyApplicablePatterns[i].replaceAll("/", "."));
}
else if (pattern.indexOf('-') != -1)
{
for (int i = 0; i < len; i++)
patterns.add(leniencyApplicablePatterns[i].replaceAll("-", "/"));
for (int i = 0; i < len; i++)
patterns.add(leniencyApplicablePatterns[i].replaceAll("-", "."));
}
else if (pattern.indexOf('.') != -1)
{
for (int i = 0; i < len; i++)
patterns.add(leniencyApplicablePatterns[i].replaceAll("\\.", "/"));
for (int i = 0; i < len; i++)
patterns.add(leniencyApplicablePatterns[i].replaceAll("\\.", "-"));
}
return patterns;
}
private Object[] _getPlaceHolderParameters(
FacesContext context,
UIComponent component,
String value)
{
Object label = ConverterUtils.getComponentLabel(component);
String example = getExample(context);
Object[] params = {label, value, example};
return params;
}
private Object _getRawConvertBothMessageDetail()
{
return _facesBean.getRawProperty(_CONVERT_BOTH_MESSAGE_DETAIL_KEY);
}
private Object _getRawConvertDateMessageDetail()
{
return _facesBean.getRawProperty(_CONVERT_DATE_MESSAGE_DETAIL_KEY);
}
private Object _getRawConvertTimeMessageDetail()
{
return _facesBean.getRawProperty(_CONVERT_TIME_MESSAGE_DETAIL_KEY);
}
private FacesMessage _getConvertErrorFacesMessage(
FacesContext context,
String key,
Object[] params,
UIComponent component
)
{
Object msgPattern = getMessagePattern(context, key, params, component);
return MessageFactory.getMessage(context, key, msgPattern,
params, component);
}
private String _getExample(FacesContext context, String pattern)
{
DateFormat format = _getDateFormat(context, pattern, false, _EXAMPLE_DATE);
return format.format(_EXAMPLE_DATE);
}
protected Object getMessagePattern(
FacesContext context,
String key,
Object[] params,
UIComponent component
)
{
Object msgPattern;
if (CONVERT_DATE_MESSAGE_ID.equals(key))
{
msgPattern = _getRawConvertDateMessageDetail();
}
else if (CONVERT_TIME_MESSAGE_ID.equals(key))
{
msgPattern = _getRawConvertTimeMessageDetail();
}
else if (CONVERT_BOTH_MESSAGE_ID.equals(key))
{
msgPattern = _getRawConvertBothMessageDetail();
}
else
{
// THIS CAN NEVER HAPPEN!
throw new IllegalArgumentException(_LOG.getMessage(
"ILLEGAL_MESSAGE_ID", key));
}
return msgPattern;
}
protected String getViolationMessageKey(String pattern)
{
String key = null;
// if pattern is null, then use ViolationMessage based on type specified
if (getPattern() == null || pattern == null)
{
String type = getType();
if("date".equals(type))
{
key = CONVERT_DATE_MESSAGE_ID;
}
else if ("time".equals(type))
{
key = CONVERT_TIME_MESSAGE_ID;
}
else if ("both".equals(type))
{
key = CONVERT_BOTH_MESSAGE_ID;
}
else if (pattern == null)
{
// The chances of this happening is remote. If this was the case..
// it should have happend during early stages of processing.
throw new IllegalArgumentException(_LOG.getMessage(
"ILLEGAL_ATTRIBUTE_TYPE_VALUE", type));
}
}
if (key == null)
{
// if pattern is specified explicitly, then use this key
key = CONVERT_DATE_MESSAGE_ID;
}
return key;
}
private SimpleDateFormat _getSimpleDateFormat(String pattern, Locale locale)
{
String variant = locale.getVariant();
SimpleDateFormat sdf = null;
if ((variant != null) && (variant.toUpperCase().startsWith("ORACLE")))
{
// This is a special Oracle format, we have to build a special formatter
// using Oracle style resources.
try
{
ResourceBundle oraElementsData =
ResourceBundle.getBundle(_ORA_LOCALE_ELEMENTS_BASE, locale);
DateFormatSymbols syms = new DateFormatSymbols(locale);
String[] res = oraElementsData.getStringArray("AmPmMarkers");
if (res != null)
syms.setAmPmStrings(res);
res = oraElementsData.getStringArray("Eras");
if (res != null)
syms.setEras(res);
res = oraElementsData.getStringArray("MonthNames");
if (res != null)
syms.setMonths(res);
res = oraElementsData.getStringArray("MonthAbbreviations");
if (res != null)
syms.setShortMonths(res);
res = oraElementsData.getStringArray("DayAbbreviations");
if (res != null)
syms.setShortWeekdays(res);
res = oraElementsData.getStringArray("DayNames");
if (res != null)
syms.setWeekdays(res);
sdf = new SimpleDateFormat(pattern, syms);
}
catch (MissingResourceException e)
{
// the Oracle resource bundle must be screwed up, just use the default
sdf = new SimpleDateFormat(pattern, locale);
}
}
else
sdf = new SimpleDateFormat(pattern, locale);
return sdf;
}
/**
* Returns a SimpleDateFormat based on the passed in SimpleDateFormat that
* uses at least 4 digit years if it uses years at all.
*
* If format
already uses at least 4 digit years, then
* the format
instance will be returned from this function
* unchanged.
*/
private SimpleDateFormat _get4YearFormat(
SimpleDateFormat format,
Locale loc
)
{
String formatPattern = format.toPattern();
//
// search through the formatPattern for a less than 4 year pattern
//
int patternLen = formatPattern.length();
int firstYIndex = -1;
int yCount = 0;
boolean inQuotes = false;
int currCharIndex = 0;
for (; currCharIndex < patternLen; currCharIndex++)
{
char currChar = formatPattern.charAt(currCharIndex);
switch (currChar)
{
case 'y':
if (!inQuotes)
{
// save the location of the first y
if (firstYIndex < 0)
firstYIndex = currCharIndex;
yCount++;
}
break;
case '\'':
if (inQuotes)
{
int nextCharIndex = currCharIndex + 1;
if ((nextCharIndex < patternLen) &&
('\'' == formatPattern.charAt(nextCharIndex)))
{
// this is just an escaped quote, so ignore
currCharIndex++;
}
else
{
// no longer quoted
inQuotes = false;
}
}
else
{
// we're now in quotes
inQuotes = true;
}
// fall through
default:
{
// we only replace the first set of years
// FIXME: this break does nothing, so commenting out; is
// it really logic that needs to be fixed?
/*
if ((yCount > 0) && (yCount < 4))
{
break;
}
*/
}
}
}
// we have some years, but not enough, so add enough y's to the current
// y's to get us to 4
// =-= bts should we actually be guaranteeing 4 digit years? Maybe we
// should guarantee that we use the same year format as the
// MEDIUM format.
if ((yCount > 0) && (yCount < 4))
{
StringBuffer newFormatPattern = new StringBuffer(patternLen + 4 - yCount);
// append everything from the orginal string before the first y
if (firstYIndex > 0)
{
newFormatPattern.append(formatPattern.substring(0, firstYIndex));
}
// add in the correct number of y's
for (; yCount < 4; yCount++)
{
newFormatPattern.append('y');
}
// append everything from the orginal string after the last y
if (firstYIndex < patternLen)
{
newFormatPattern.append(formatPattern.substring(firstYIndex,
patternLen));
}
// create the new format
//format = new SimpleDateFormat(newFormatPattern.toString(), loc);
format = _getSimpleDateFormat(newFormatPattern.toString(), loc);
}
return format;
}
private DateFormat _getDateFormat(
FacesContext context,
String pattern,
boolean forParsing,
Date targetDate
)
{
Locale locale = _extractConverterLocale(context);
TimeZone tZone = _getTimeZone();
DateFormat format = _getCachedFormat(locale, tZone, pattern);
if (format != null)
{
format.setTimeZone(tZone);
}
else
{
// create a format off of the styles.
// We will change shortish to short only at place where it is required.
// Otherwise we may end up throwing convert exception for case where
// dateStyle is invalid. So evaluating only at the required place.
if ( null == pattern || "".equals(pattern))
{
int type = _getType(getType());
if (type == _TYPE_DATE || type == _TYPE_BOTH)
{
int actualDateStyle = _getDateStyle(getDateStyle());
int dateStyle = _changeShortishAsShortIfNeeded(actualDateStyle);
if (type == _TYPE_DATE)
{
format = DateFormat.getDateInstance(dateStyle, locale);
}
else
{
int timeStyle = _getTimeStyle(getTimeStyle());
format = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
}
}
if (type == _TYPE_TIME)
{
int timeStyle = _getTimeStyle(getTimeStyle());
format = DateFormat.getTimeInstance(timeStyle, locale);
}
}
else
{
// create a format off of the pattern
format = _getSimpleDateFormat(pattern, locale);
}
if (format instanceof SimpleDateFormat)
{
SimpleDateFormat simpleFormat = (SimpleDateFormat)format;
if (!forParsing)
{
// make sure that we have a 4 digit year for "shortish"
// dates
// DO NOT CHANGE THE FOLLOWING LINE to "dateStyle"; this
// must be retrieved from the instance variable! (See above)
// and we need to apply shortish only if it is of date type or
// type is date and time.
if (null == pattern && "shortish".equals(getDateStyle()) )
{
int type = _getType(getType());
if (type == _TYPE_DATE || type == _TYPE_BOTH )
{
simpleFormat = _get4YearFormat(simpleFormat, locale);
format = simpleFormat;
}
}
}//end-if for formatting
else
{
Calendar cal;
RequestContext reqContext = RequestContext.getCurrentInstance();
if (reqContext == null)
{
cal = null;
if(_LOG.isWarning())
{
_LOG.warning("NO_REQUESTCONTEXT_TWO_DIGIT_YEAR_START_DEFAULT");
}
}
else
{
cal = new GregorianCalendar(reqContext.getTwoDigitYearStart(), 0, 0);
}
if (cal != null)
simpleFormat.set2DigitYearStart(cal.getTime());
}//end-if for parsing
}//end-if using SimpleDateFormat
// Bug 2002065
format.setLenient(false);
// Bug 2317641
// include timezone in date format
if (tZone != null)
{
TimeZone formatTZone = getFormattingTimeZone(tZone, targetDate);
format.setTimeZone(formatTZone);
}
// cache the format
_cacheFormat(format, locale, tZone, pattern);
}
return format;
}
private int _changeShortishAsShortIfNeeded(int dateStyle)
{
if (dateStyle == _SHORTISH)
dateStyle = DateFormat.SHORT;
return dateStyle;
}
// 1. For the given locale get the timeZone map
// 2. For the given timeZone get the pattern,type map
// 3. For the given pattern and type, dateStyle, timeStyle from the
// InfoHolderMap- get the date format.
private DateFormat _getCachedFormat(
Locale locale,
TimeZone tZone,
String pattern
)
{
// See _cacheFormat()
return null;
}
// caching is based on pattern, type, dateStyle and timeStyle
private void _cacheFormat(
DateFormat format,
Locale locale,
TimeZone tZone,
String pattern
)
{
// We formerly attempted to cache the SimpleDateFormat in
// a global, static HashMap. However, this is invalid: SimpleDateFormats
// are not threadsafe, and can only be cached within a thread. This
// architecture must be revisited and implemented in a thread-safe fashion.
}
private TimeZone _getTimeZone()
{
TimeZone tZone = getTimeZone();
if (tZone == null)
{
RequestContext context = RequestContext.getCurrentInstance();
if (context == null)
{
_LOG.warning("NO_REQUESTCONTEXT_TIMEZONE_DEFAULT");
}
else
{
tZone = context.getTimeZone();
}
// If RequestContext is null or if it returns a null,
// then set it to the default time zone which is GMT time zone
if (tZone == null)
{
tZone = _DEFAULT_TIME_ZONE;
}
}
return tZone;
}
private static final FacesBean.Type _TYPE = new FacesBean.Type();
private static final PropertyKey _DATE_STYLE_KEY
= _TYPE.registerKey("dateStyle", String.class, "shortish");
private static final PropertyKey _LOCALE_KEY
= _TYPE.registerKey("locale", Locale.class);
private static final PropertyKey _PATTERN_KEY
= _TYPE.registerKey("pattern", String.class);
private static final PropertyKey _SECONDARY_PATTERN_KEY
= _TYPE.registerKey("secondaryPattern", String.class);
private static final PropertyKey _TIME_STYLE_KEY
= _TYPE.registerKey("timeStyle", String.class, "short");
private static final PropertyKey _TIME_ZONE_KEY
= _TYPE.registerKey("timeZone", TimeZone.class);
private static final PropertyKey _TYPE_KEY
= _TYPE.registerKey("type", String.class, "date");
private static final PropertyKey _CONVERT_DATE_MESSAGE_DETAIL_KEY
= _TYPE.registerKey("messageDetailConvertDate", String.class);
private static final PropertyKey _CONVERT_TIME_MESSAGE_DETAIL_KEY
= _TYPE.registerKey("messageDetailConvertTime", String.class);
private static final PropertyKey _CONVERT_BOTH_MESSAGE_DETAIL_KEY
= _TYPE.registerKey("messageDetailConvertBoth", String.class);
private static final PropertyKey _HINT_DATE_KEY =
_TYPE.registerKey("hintDate", String.class);
private static final PropertyKey _HINT_TIME_KEY =
_TYPE.registerKey("hintTime", String.class);
private static final PropertyKey _HINT_BOTH_KEY =
_TYPE.registerKey("hintBoth", String.class);
// Default is false
private static final PropertyKey _DISABLED_KEY =
_TYPE.registerKey("disabled", Boolean.class, Boolean.FALSE);
private FacesBean _facesBean = ConverterUtils.getFacesBean(_TYPE);
private boolean _isTransient;
private static final TimeZone _DEFAULT_TIME_ZONE = TimeZone.getTimeZone("GMT");
private static final int _SHORTISH = -2;
private static final int _TYPE_DATE = 0;
private static final int _TYPE_TIME = 2;
private static final int _TYPE_BOTH = 4;
private static final String _ORA_LOCALE_ELEMENTS_BASE =
"org.apache.myfaces.trinidad.resource.LocaleElements";
private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(DateTimeConverter.class);
private static final Date _EXAMPLE_DATE;
/**
* All entries added to this map MUST also be added to the client map:
* trinidad-impl\src\main\javascript\META-INF\adf\jsLibs\DateFormat.js->_CONVENIENCE_PATTERNS
* (in TrDateTimeConverter.prototype._initConveniencePatterns)
*/
private static final Map> _CONVENIENCE_PATTERNS =
new HashMap>();
private static final List _US_CONVENIENCE_PATTERNS =
Arrays.asList("MMMM dd, yy", "MMMM/dd/yy", "dd-MMMM-yy");
static
{
Calendar dateFactory = Calendar.getInstance(Locale.US);
dateFactory.set(1998, 10, 29, 15, 45);
_EXAMPLE_DATE = dateFactory.getTime();
// All entries added to this map MUST also be added to the client map:
// trinidad-impl\src\main\javascript\META-INF\adf\jsLibs\DateFormat.js->_CONVENIENCE_PATTERNS
// (in TrDateTimeConverter.prototype._initConveniencePatterns)
_CONVENIENCE_PATTERNS.put(Locale.US, _US_CONVENIENCE_PATTERNS);
}
}