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.woody.datatype.convertor;
018:
019: import java.util.Locale;
020: import java.util.Date;
021: import java.text.DateFormat;
022: import java.text.ParseException;
023: import java.text.SimpleDateFormat;
024:
025: /**
026: * A Convertor for {@link java.util.Date Date} objects backed by the
027: * {@link java.text.SimpleDateFormat SimpleDateFormat} class.
028: *
029: * <p>It can be configured to use one of three <strong>variants</strong>: date,
030: * time or datetime and one of four <strong>styles</strong>: long, full, medium or short.
031: *
032: * <p>Alternatively, a <strong>formatting pattern</strong> can be used. This can either be a locale-dependent
033: * or locale-independent formatting pattern. When looking up a formatting pattern, a mechansim
034: * similar to resource bundle lookup is used. Suppose the locale is nl-BE, then first a formatting
035: * pattern for nl-BE will be sought, then one for nl, and if that is not
036: * found, finally the locale-independent formatting pattern will be used.
037: *
038: * <p><strong>NOTE:</strong> the earlier statement about the fact that this class uses java.text.SimpleDateFormat
039: * is not entirely correct. In fact, it uses a small wrapper class that will either delegate to
040: * java.text.SimpleDateFormat or com.ibm.icu.text.SimpleDateFormat. The com.ibm version will automatically
041: * be used if it is present on the classpath, otherwise the java.text version will be used.
042: *
043: * @version CVS $Id: FormattingDateConvertor.java 503643 2007-02-05 11:27:11Z cziegeler $
044: */
045: public class FormattingDateConvertor implements Convertor {
046: /** See {@link #setStyle}. */
047: private int style;
048: /** See {@link #setVariant}. */
049: private int variant;
050: /** Locale-specific formatting patterns. */
051: private LocaleMap localizedPatterns;
052: /** Non-locale specific formatting pattern. */
053: private String nonLocalizedPattern;
054:
055: public static final int DATE = 1;
056: public static final int TIME = 2;
057: public static final int DATE_TIME = 3;
058:
059: public FormattingDateConvertor() {
060: this .style = java.text.DateFormat.SHORT;
061: this .variant = DATE;
062: this .localizedPatterns = new LocaleMap();
063: }
064:
065: public Object convertFromString(String value, Locale locale,
066: Convertor.FormatCache formatCache) {
067: DateFormat dateFormat = getDateFormat(locale, formatCache);
068: try {
069: return dateFormat.parse(value);
070: } catch (ParseException e) {
071: return null;
072: }
073: }
074:
075: public String convertToString(Object value, Locale locale,
076: Convertor.FormatCache formatCache) {
077: DateFormat dateFormat = getDateFormat(locale, formatCache);
078: return dateFormat.format((Date) value);
079: }
080:
081: private final DateFormat getDateFormat(Locale locale,
082: Convertor.FormatCache formatCache) {
083: DateFormat dateFormat = null;
084: if (formatCache != null)
085: dateFormat = (DateFormat) formatCache.get();
086: if (dateFormat == null) {
087: dateFormat = getDateFormat(locale);
088: if (formatCache != null)
089: formatCache.store(dateFormat);
090: }
091: return dateFormat;
092: }
093:
094: protected DateFormat getDateFormat(Locale locale) {
095: SimpleDateFormat dateFormat = null;
096:
097: switch (variant) {
098: case DATE:
099: dateFormat = (SimpleDateFormat) DateFormat.getDateInstance(
100: style, locale);
101: break;
102: case TIME:
103: dateFormat = (SimpleDateFormat) DateFormat.getTimeInstance(
104: style, locale);
105: break;
106: case DATE_TIME:
107: dateFormat = (SimpleDateFormat) DateFormat
108: .getDateTimeInstance(style, style, locale);
109: break;
110: }
111:
112: String pattern = (String) localizedPatterns.get(locale);
113:
114: if (pattern != null)
115: // Note: this was previously using applyLocalizedPattern() which allows to use
116: // a locale-specific pattern syntax, e.g. in french "j" (jour) for "d" and
117: // "a" (annee) for "y". But the localized pattern syntax is very little known and thus
118: // led to some weird pattern syntax error messages.
119: dateFormat.applyPattern(pattern);
120: else if (nonLocalizedPattern != null)
121: dateFormat.applyPattern(nonLocalizedPattern);
122:
123: return dateFormat;
124: }
125:
126: public Class getTypeClass() {
127: return Date.class;
128: }
129:
130: /**
131: *
132: * @param style one of the constants FULL, LONG, MEDIUM or SHORT defined in the {@link Date} class.
133: */
134: public void setStyle(int style) {
135: this .style = style;
136: }
137:
138: public void setVariant(int variant) {
139: if (variant != DATE && variant != TIME && variant != DATE_TIME)
140: throw new IllegalArgumentException(
141: "Invalid value for variant parameter.");
142: this .variant = variant;
143: }
144:
145: public void addFormattingPattern(Locale locale, String pattern) {
146: localizedPatterns.put(locale, pattern);
147: }
148:
149: public void setNonLocalizedPattern(String pattern) {
150: this.nonLocalizedPattern = pattern;
151: }
152: }
|