package org.jboss.seam.faces; import static org.jboss.seam.annotations.Install.BUILT_IN; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.convert.ConverterException; import org.jboss.seam.Component; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.faces.Converter; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.contexts.Contexts; import org.jboss.seam.log.Log; import org.jboss.seam.log.Logging; /** * Provides a default JSF converter for properties of type java.util.Date. * * <p>This converter is provided to save a developer from having to specify * a DateTimeConverter on an input field or page parameter. By default, it * assumes the type to be a date (as opposed to a time or date plus time) and * uses the short input style adjusted to the Locale of the user. For Locale.US, * the input pattern is mm/DD/yy. However, to comply with Y2K, the year is changed * from two digits to four (e.g., mm/DD/yyyy).</p> * <p>It's possible to override the input pattern globally using component configuration. * Here is an example of changing the style to both and setting the date and * time style to medium.</p> * <pre> * org.jboss.seam.faces.dateConverter.type=both * org.jboss.seam.faces.dateConverter.dateStyle=medium * org.jboss.seam.faces.dateConverter.timeStyle=medium * </pre> * <p>Alternatively, a fixed pattern can be specified.</p> * <pre> * org.jboss.seam.faces.dateConverter.pattern=yyyy-mm-DD * </pre> * * @author Dan Allen */ @Converter(forClass = Date.class) @Name("org.jboss.seam.faces.dateConverter") @Install(precedence = BUILT_IN, classDependencies = "javax.faces.context.FacesContext") @BypassInterceptors public class DateConverter extends javax.faces.convert.DateTimeConverter { private Log log = Logging.getLog(DateConverter.class); private static final String TYPE_DATE = "date"; private static final String STYLE_SHORT = "short"; private static final String TWO_DIGIT_YEAR_PATTERN = "yy"; private static final String FOUR_DIGIT_YEAR_PATTERN = "yyyy"; // constructor is used to initialize converter to allow these values to be overridden using component properties public DateConverter() { super(); setType(TYPE_DATE); setDateStyle(STYLE_SHORT); setTimeStyle(STYLE_SHORT); // default in case developer overrides type to be time or both } @Create public void create() { // TODO make this work if using "both" for type; requires more analysis of time style if (TYPE_DATE.equals(getType()) && STYLE_SHORT.equals(getDateStyle()) && getPattern() == null) { // attempt to make the pattern Y2K compliant, which it isn't by default DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, getLocale()); if (dateFormat instanceof SimpleDateFormat) { setPattern(((SimpleDateFormat) dateFormat).toPattern().replace(TWO_DIGIT_YEAR_PATTERN, FOUR_DIGIT_YEAR_PATTERN)); } } // required since the superclass may access the fields directly setTimeZone(getTimeZone()); setLocale(getLocale()); } @Override public TimeZone getTimeZone() { if (Contexts.isApplicationContextActive()) { return org.jboss.seam.international.TimeZone.instance(); } else { // we don't want to use JSF's braindead default (maybe in JSF 2) return TimeZone.getDefault(); } } @Override public Locale getLocale() { if (Contexts.isApplicationContextActive()) { return org.jboss.seam.international.Locale.instance(); } else { return super.getLocale(); } } @Override public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException { if (log.isDebugEnabled()) { log.debug("Converting string '#0' to date for clientId '#1' using Seam's built-in JSF date converter", value, component.getClientId(context)); } return super.getAsObject(context, component, value); } @Override public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException { if (log.isDebugEnabled()) { log.debug("Converting date '#0' to string for clientId '#1' using Seam's built-in JSF date converter", value, component.getClientId(context)); } return super.getAsString(context, component, value); } public static javax.faces.convert.Converter getInstance(){ return (javax.faces.convert.Converter) Component.getInstance("org.jboss.seam.faces.dateConverter"); } }