package com.anem.green.web.convert; import java.util.Map; import javax.el.ELContext; import javax.el.ValueExpression; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.convert.ConverterException; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.LocalDate; import org.joda.time.LocalTime; import org.joda.time.ReadableInstant; import org.joda.time.ReadablePartial; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import com.anem.green.web.SessionPreferences; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; /** */ public class DateTimeConverter implements Converter { private ValueExpression timeZoneExpression; /** * used to temporarily store the facesContext during the duration of a getAsString or getAsObject */ transient FacesContext facesContext; @Override public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value) { this.facesContext = facesContext; Class<?> type = ValueExpressionHelper.getValueType(facesContext, uiComponent, Lists.<Class<?>> newArrayList(DateTime.class, LocalDate.class, LocalTime.class)); Preconditions.checkArgument(type != null, "DateTimeConverter is not attached to a component bound to either a" + " DateTime, LocalDate, or LocalTime."); Object valueAsObject; if (type.isAssignableFrom(DateTime.class)) { valueAsObject = (DateTime) getAsObjectInstance(facesContext, uiComponent, value); } else if (type.isAssignableFrom(LocalDate.class)) { Object dateTime = getAsObjectInstance(facesContext, uiComponent, value); valueAsObject = dateTime == null ? null : new LocalDate(dateTime); } else if (type.isAssignableFrom(LocalTime.class)) { Object dateTime = getAsObjectInstance(facesContext, uiComponent, value); valueAsObject = dateTime == null ? null : new LocalTime(dateTime); } else { throw new AssertionError("ValueExpressionHelper.getValueType() broke its contract"); } this.facesContext = null; return valueAsObject; } @Override public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value) { this.facesContext = facesContext; Class<?> type = ValueExpressionHelper.getValueType(facesContext, uiComponent, Lists.<Class<?>> newArrayList(DateTime.class, LocalDate.class, LocalTime.class)); Preconditions.checkArgument(type != null, "DateTimeConverter is not attached to a component bound to either a" + " DateTime, LocalDate, or LocalTime."); if (value instanceof LocalDate) { LocalDate localDate = (LocalDate) value; return getAsStringValue(facesContext, uiComponent, localDate.toDateTimeAtStartOfDay(getTimeZone())); } if (value instanceof LocalTime) { LocalTime localTime = (LocalTime) value; return getAsStringValue(facesContext, uiComponent, localTime.toDateTimeToday(getTimeZone())); } if (value instanceof ReadablePartial) { ReadablePartial readablePartial = (ReadablePartial) value; return getAsStringValue(facesContext, uiComponent, readablePartial.toDateTime(new DateTime())); } this.facesContext = null; return getAsStringValue(facesContext, uiComponent, value); } private Object getAsObjectInstance(FacesContext facesContext, UIComponent uiComponent, String value) { if (facesContext == null) { throw new NullPointerException("facesContext"); } if (uiComponent == null) { throw new NullPointerException("uiComponent"); } if (value != null) { value = value.trim(); if (value.length() > 0) { DateTimeFormatter format = getDateFormat(uiComponent); try { return format.parseDateTime(value); } catch (IllegalArgumentException e) { throw new ConverterException(e); } } } return null; } private String getAsStringValue(FacesContext facesContext, UIComponent uiComponent, Object value) { if (facesContext == null) { throw new NullPointerException("facesContext"); } if (uiComponent == null) { throw new NullPointerException("uiComponent"); } if (value == null) { return ""; } if (value instanceof String) { return (String) value; } DateTimeFormatter format = getDateFormat(uiComponent); try { return format.print((ReadableInstant) value); } catch (Exception e) { throw new ConverterException("Cannot convert value '" + value + "'"); } } private DateTimeFormatter getDateFormat(UIComponent uiComponent) { DateTimeFormatter format = DateTimeFormat.forPattern(getPattern(uiComponent)); format = format.withLocale(SessionPreferences.getCurrentLocale()); format = format.withZone(getTimeZone()); return format; } public DateTimeZone getTimeZone() { if (timeZoneExpression == null) { return DateTimeZone.getDefault(); } else { ELContext context;// TODO: Need to know how to test this. if (facesContext == null) { context = FacesContext.getCurrentInstance().getELContext(); } else { context = facesContext.getELContext(); } return (DateTimeZone) timeZoneExpression.getValue(context); } } public static String getPattern(UIComponent component) { Map<String, Object> properties = component.getAttributes(); String pattern = (String) properties.get("dateFormat"); if (null == pattern) { pattern = (String) properties.get("pattern"); } if (null == pattern) { pattern = "MM/dd/yyyy"; } return pattern; } }