001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.forms.datatype.convertor;
018:
019: import java.text.ParseException;
020: import java.util.Date;
021: import java.util.Locale;
022:
023: import org.apache.cocoon.forms.FormsConstants;
024: import org.apache.cocoon.xml.AttributesImpl;
025: import org.xml.sax.ContentHandler;
026: import org.xml.sax.SAXException;
027:
028: import com.ibm.icu.text.DateFormat;
029: import com.ibm.icu.text.SimpleDateFormat;
030:
031: /**
032: * A Convertor for {@link java.util.Date Date} objects backed by ICU4J's
033: * {@link com.ibm.icu.text.SimpleDateFormat} class.
034: *
035: * <p>It can be configured to use one of three <strong>variants</strong>: date,
036: * time or datetime and one of four <strong>styles</strong>: long, full, medium or short.
037: *
038: * <p>Alternatively, a <strong>formatting pattern</strong> can be used. This can either be a locale-dependent
039: * or locale-independent formatting pattern. When looking up a formatting pattern, a mechansim
040: * similar to resource bundle lookup is used. Suppose the locale is nl-BE, then first a formatting
041: * pattern for nl-BE will be sought, then one for nl, and if that is not
042: * found, finally the locale-independent formatting pattern will be used.
043: *
044: * <p>Date parsing can be configured to be lenient or not by specifying a <code>lenient</code>
045: * boolean attribute. By default, parsing is lenient.
046: *
047: * @version $Id: Icu4jDateConvertor.java 449149 2006-09-23 03:58:05Z crossley $
048: */
049: public class Icu4jDateConvertor implements Convertor {
050: //FIXME: the only difference of this class with FormattingDateConvertor is the use of com.ibm.icu.text.SimpleDateFormat
051: // --> refactor to have it extend FormattingDateConvertor
052:
053: /** See {@link #setStyle}. */
054: private int style;
055: /** See {@link #setVariant}. */
056: private String variant;
057: /** Locale-specific formatting patterns. */
058: private LocaleMap localizedPatterns;
059: /** Non-locale specific formatting pattern. */
060: private String nonLocalizedPattern;
061: /** Should date parsing be lenient or not? */
062: private boolean lenient;
063:
064: public static final String DATE = "date";
065: public static final String TIME = "time";
066: public static final String DATE_TIME = "datetime";
067:
068: public Icu4jDateConvertor() {
069: this .style = DateFormat.SHORT;
070: this .variant = DATE;
071: this .localizedPatterns = new LocaleMap();
072: this .lenient = true;
073: }
074:
075: public ConversionResult convertFromString(String value,
076: Locale locale, Convertor.FormatCache formatCache) {
077: SimpleDateFormat dateFormat = getDateFormat(locale, formatCache);
078: try {
079: return new ConversionResult(dateFormat.parse(value));
080: } catch (ParseException e) {
081: return ConversionResult.create("date." + this .variant);
082: }
083: }
084:
085: public String convertToString(Object value, Locale locale,
086: Convertor.FormatCache formatCache) {
087: SimpleDateFormat dateFormat = getDateFormat(locale, formatCache);
088: return dateFormat.format((Date) value);
089: }
090:
091: private final SimpleDateFormat getDateFormat(Locale locale,
092: Convertor.FormatCache formatCache) {
093: SimpleDateFormat dateFormat = null;
094: if (formatCache != null)
095: dateFormat = (SimpleDateFormat) formatCache.get();
096: if (dateFormat == null) {
097: dateFormat = getDateFormat(locale);
098: if (formatCache != null)
099: formatCache.store(dateFormat);
100: }
101: dateFormat.setLenient(lenient);
102: return dateFormat;
103: }
104:
105: protected SimpleDateFormat getDateFormat(Locale locale) {
106: SimpleDateFormat dateFormat = null;
107:
108: if (this .variant.equals(DATE)) {
109: //dateFormat = I18nSupport.getInstance().getDateFormat(style, locale);
110: dateFormat = (SimpleDateFormat) DateFormat.getDateInstance(
111: style, locale);
112: } else if (this .variant.equals(TIME)) {
113: //dateFormat = I18nSupport.getInstance().getTimeFormat(style, locale);
114: dateFormat = (SimpleDateFormat) DateFormat.getTimeInstance(
115: style, locale);
116: } else if (this .variant.equals(DATE_TIME)) {
117: //dateFormat = I18nSupport.getInstance().getDateTimeFormat(style, style, locale);
118: dateFormat = (SimpleDateFormat) DateFormat
119: .getDateTimeInstance(style, style, locale);
120: }
121:
122: String pattern = (String) localizedPatterns.get(locale);
123:
124: if (pattern != null)
125: // Note: this was previously using applyLocalizedPattern() which allows to use
126: // a locale-specific pattern syntax, e.g. in french "j" (jour) for "d" and
127: // "a" (annee) for "y". But the localized pattern syntax is very little known and thus
128: // led to some weird pattern syntax error messages.
129: dateFormat.applyPattern(pattern);
130: else if (nonLocalizedPattern != null)
131: dateFormat.applyPattern(nonLocalizedPattern);
132:
133: dateFormat.setLenient(lenient);
134: return dateFormat;
135: }
136:
137: public Class getTypeClass() {
138: return Date.class;
139: }
140:
141: /**
142: *
143: * @param style one of the constants FULL, LONG, MEDIUM or SHORT defined in the {@link Date} class.
144: */
145: public void setStyle(int style) {
146: this .style = style;
147: }
148:
149: public void setVariant(String variant) {
150: if (DATE.equals(variant) || TIME.equals(variant)
151: || DATE_TIME.equals(variant)) {
152: this .variant = variant;
153: } else {
154: throw new IllegalArgumentException(
155: "Invalid value for variant parameter.");
156: }
157: }
158:
159: public void addFormattingPattern(Locale locale, String pattern) {
160: localizedPatterns.put(locale, pattern);
161: }
162:
163: public void setNonLocalizedPattern(String pattern) {
164: this .nonLocalizedPattern = pattern;
165: }
166:
167: public void setLenient(boolean lenient) {
168: this .lenient = lenient;
169: }
170:
171: private static final String CONVERTOR_EL = "convertor";
172:
173: public void generateSaxFragment(ContentHandler contentHandler,
174: Locale locale) throws SAXException {
175: String pattern = getDateFormat(locale).toPattern();
176:
177: if (pattern != null) {
178: AttributesImpl attrs = new AttributesImpl();
179: attrs.addCDATAAttribute("pattern", pattern);
180: attrs.addCDATAAttribute("variant", this.variant);
181: contentHandler.startElement(FormsConstants.INSTANCE_NS,
182: CONVERTOR_EL, FormsConstants.INSTANCE_PREFIX_COLON
183: + CONVERTOR_EL, attrs);
184: contentHandler.endElement(FormsConstants.INSTANCE_NS,
185: CONVERTOR_EL, FormsConstants.INSTANCE_PREFIX_COLON
186: + CONVERTOR_EL);
187: }
188: }
189: }
|