blob: 30a61c54f77dd94c8e47895a1cac15df764902c7 [file] [log] [blame]
/*
* 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.cocoon.forms.datatype.convertor;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.apache.cocoon.forms.FormsConstants;
import org.apache.cocoon.xml.AttributesImpl;
import java.util.Locale;
import java.util.Date;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/**
* A Convertor for {@link java.util.Date Date} objects backed by the
* {@link java.text.SimpleDateFormat SimpleDateFormat} class.
*
* <p>It can be configured to use one of three <strong>variants</strong>: date,
* time or datetime and one of four <strong>styles</strong>: long, full, medium or short.
*
* <p>Alternatively, a <strong>formatting pattern</strong> can be used. This can either be a locale-dependent
* or locale-independent formatting pattern. When looking up a formatting pattern, a mechansim
* similar to resource bundle lookup is used. Suppose the locale is nl-BE, then first a formatting
* pattern for nl-BE will be sought, then one for nl, and if that is not
* found, finally the locale-independent formatting pattern will be used.
*
* <p>Date parsing can be configured to be lenient or not by specifying a <code>lenient</code>
* boolean attribute. By default, parsing is lenient.
*
* @version $Id$
*/
public class FormattingDateConvertor implements Convertor {
/** See {@link #setStyle}. */
private int style;
private int timeStyle = -1;
/** See {@link #setVariant}. */
private String variant;
/** Locale-specific formatting patterns. */
private LocaleMap localizedPatterns;
/** Non-locale specific formatting pattern. */
private String nonLocalizedPattern;
/** Should date parsing be lenient or not? */
private boolean lenient;
public static final String DATE = "date";
public static final String TIME = "time";
public static final String DATE_TIME = "datetime";
public FormattingDateConvertor() {
this.style = DateFormat.SHORT;
this.variant = DATE;
this.localizedPatterns = new LocaleMap();
this.lenient = true;
}
public ConversionResult convertFromString(String value, Locale locale, Convertor.FormatCache formatCache) {
SimpleDateFormat dateFormat = getDateFormat(locale, formatCache);
try {
return new ConversionResult(dateFormat.parse(value));
} catch (ParseException e) {
return ConversionResult.create("date." + this.variant);
}
}
public String convertToString(Object value, Locale locale, Convertor.FormatCache formatCache) {
SimpleDateFormat dateFormat = getDateFormat(locale, formatCache);
return dateFormat.format((Date)value);
}
private final SimpleDateFormat getDateFormat(Locale locale, Convertor.FormatCache formatCache) {
SimpleDateFormat dateFormat = null;
if (formatCache != null)
dateFormat = (SimpleDateFormat)formatCache.get();
if (dateFormat == null) {
dateFormat = getDateFormat(locale);
if (formatCache != null)
formatCache.store(dateFormat);
}
dateFormat.setLenient(lenient);
return dateFormat;
}
protected SimpleDateFormat getDateFormat(Locale locale) {
SimpleDateFormat dateFormat = null;
int timeStyle = this.timeStyle != -1 ? this.timeStyle : style;
if (this.variant.equals(DATE)) {
//dateFormat = I18nSupport.getInstance().getDateFormat(style, locale);
dateFormat = (SimpleDateFormat)DateFormat.getDateInstance(style, locale);
} else if (this.variant.equals(TIME)) {
//dateFormat = I18nSupport.getInstance().getTimeFormat(style, locale);
dateFormat = (SimpleDateFormat)DateFormat.getTimeInstance(timeStyle, locale);
} else if (this.variant.equals(DATE_TIME)) {
//dateFormat = I18nSupport.getInstance().getDateTimeFormat(style, style, locale);
dateFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(style, timeStyle, locale);
}
String pattern = (String)localizedPatterns.get(locale);
if (pattern != null)
// Note: this was previously using applyLocalizedPattern() which allows to use
// a locale-specific pattern syntax, e.g. in french "j" (jour) for "d" and
// "a" (annee) for "y". But the localized pattern syntax is very little known and thus
// led to some weird pattern syntax error messages.
dateFormat.applyPattern(pattern);
else if (nonLocalizedPattern != null)
dateFormat.applyPattern(nonLocalizedPattern);
dateFormat.setLenient(lenient);
return dateFormat;
}
public Class getTypeClass() {
return Date.class;
}
/**
*
* @param style one of the constants FULL, LONG, MEDIUM or SHORT defined in the {@link Date} class.
*/
public void setStyle(int style) {
this.style = style;
}
/**
* Sets the style for times, if not specified it defaults to the same style as for dates.
*
* @param style one of the constants FULL, LONG, MEDIUM or SHORT defined in the {@link Date} class.
*/
public void setTimeStyle(int style) {
this.timeStyle = style;
}
public void setVariant(String variant) {
if (DATE.equals(variant) || TIME.equals(variant) || DATE_TIME.equals(variant)) {
this.variant = variant;
} else {
throw new IllegalArgumentException("Invalid value for variant parameter.");
}
}
public void addFormattingPattern(Locale locale, String pattern) {
localizedPatterns.put(locale, pattern);
}
public void setNonLocalizedPattern(String pattern) {
this.nonLocalizedPattern = pattern;
}
public void setLenient(boolean lenient) {
this.lenient = lenient;
}
private static final String CONVERTOR_EL = "convertor";
public void generateSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException {
String pattern = getDateFormat(locale).toPattern();
if (pattern != null) {
AttributesImpl attrs = new AttributesImpl();
attrs.addCDATAAttribute("pattern", pattern);
attrs.addCDATAAttribute("variant", this.variant);
contentHandler.startElement(FormsConstants.INSTANCE_NS, CONVERTOR_EL, FormsConstants.INSTANCE_PREFIX_COLON + CONVERTOR_EL, attrs);
contentHandler.endElement(FormsConstants.INSTANCE_NS, CONVERTOR_EL, FormsConstants.INSTANCE_PREFIX_COLON + CONVERTOR_EL);
}
}
}