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 org.xml.sax.ContentHandler;
020: import org.xml.sax.SAXException;
021:
022: import java.util.Locale;
023: import java.text.DecimalFormat;
024: import java.text.NumberFormat;
025: import java.text.ParseException;
026: import java.math.BigDecimal;
027: import java.math.BigInteger;
028:
029: /**
030: * A Convertor for {@link BigDecimal}s backed by the
031: * {@link java.text.DecimalFormat DecimalFormat} class.
032: *
033: * <p>It can be configured to use one of these variants: integer,
034: * number, currency or percent.
035: *
036: * <p>Alternatively, a <strong>formatting pattern</strong> can be used. This can either be a locale-dependent
037: * or locale-independent formatting pattern. When looking up a formatting pattern, a mechansim
038: * similar to resource bundle lookup is used. Suppose the locale is nl-BE, then first a formatting
039: * pattern for nl-BE will be sought, then one for nl, and if that is not
040: * found, finally the locale-independent formatting pattern will be used.
041: *
042: * @version $Id: FormattingDecimalConvertor.java 479296 2006-11-26 06:28:51Z antonio $
043: */
044: public class FormattingDecimalConvertor implements Convertor {
045: private int variant;
046: /** Locale-specific formatting patterns. */
047: private LocaleMap localizedPatterns;
048: /** Non-locale specific formatting pattern. */
049: private String nonLocalizedPattern;
050:
051: public static final int INTEGER = 0;
052: public static final int NUMBER = 1;
053: public static final int CURRENCY = 2;
054: public static final int PERCENT = 3;
055:
056: public FormattingDecimalConvertor() {
057: this .variant = getDefaultVariant();
058: this .localizedPatterns = new LocaleMap();
059: }
060:
061: protected int getDefaultVariant() {
062: return NUMBER;
063: }
064:
065: public ConversionResult convertFromString(String value,
066: Locale locale, Convertor.FormatCache formatCache) {
067: // Some locales (e.g. "fr") produce non-breaking spaces sent back as space by the browser
068: value = value.replace(' ', (char) 160);
069: DecimalFormat decimalFormat = getDecimalFormat(locale,
070: formatCache);
071:
072: Number decimalValue;
073: try {
074: decimalValue = decimalFormat.parse(value);
075: } catch (ParseException e) {
076: return ConversionResult.create("decimal");
077: }
078:
079: if (decimalValue instanceof BigDecimal) {
080: // no need for conversion
081: } else if (decimalValue instanceof Integer) {
082: decimalValue = new BigDecimal(decimalValue.intValue());
083: } else if (decimalValue instanceof Long) {
084: decimalValue = new BigDecimal(decimalValue.longValue());
085: } else if (decimalValue instanceof Double) {
086: decimalValue = new BigDecimal(decimalValue.doubleValue());
087: } else if (decimalValue instanceof BigInteger) {
088: decimalValue = new BigDecimal((BigInteger) decimalValue);
089: } else {
090: return ConversionResult.create("decimal");
091: }
092: return new ConversionResult(decimalValue);
093: }
094:
095: public String convertToString(Object value, Locale locale,
096: Convertor.FormatCache formatCache) {
097: DecimalFormat decimalFormat = getDecimalFormat(locale,
098: formatCache);
099: return decimalFormat.format(value);
100: }
101:
102: protected final DecimalFormat getDecimalFormat(Locale locale,
103: Convertor.FormatCache formatCache) {
104: DecimalFormat decimalFormat = null;
105: if (formatCache != null)
106: decimalFormat = (DecimalFormat) formatCache.get();
107: if (decimalFormat == null) {
108: decimalFormat = getDecimalFormat(locale);
109: if (formatCache != null)
110: formatCache.store(decimalFormat);
111: }
112: return decimalFormat;
113: }
114:
115: private DecimalFormat getDecimalFormat(Locale locale) {
116: DecimalFormat decimalFormat = null;
117:
118: switch (variant) {
119: case INTEGER:
120: decimalFormat = (DecimalFormat) NumberFormat
121: .getNumberInstance(locale);
122: decimalFormat.setMaximumFractionDigits(0);
123: decimalFormat.setDecimalSeparatorAlwaysShown(false);
124: decimalFormat.setParseIntegerOnly(true);
125: break;
126: case NUMBER:
127: decimalFormat = (DecimalFormat) NumberFormat
128: .getNumberInstance(locale);
129: break;
130: case CURRENCY:
131: decimalFormat = (DecimalFormat) NumberFormat
132: .getCurrencyInstance(locale);
133: break;
134: case PERCENT:
135: decimalFormat = (DecimalFormat) NumberFormat
136: .getPercentInstance(locale);
137: break;
138: }
139:
140: String pattern = (String) localizedPatterns.get(locale);
141:
142: if (pattern != null) {
143: decimalFormat.applyPattern(pattern);
144: } else if (nonLocalizedPattern != null) {
145: decimalFormat.applyPattern(nonLocalizedPattern);
146: }
147: return decimalFormat;
148: }
149:
150: public void setVariant(int variant) {
151: if (variant != INTEGER && variant != NUMBER
152: && variant != CURRENCY && variant != PERCENT)
153: throw new IllegalArgumentException(
154: "Invalid value for variant parameter.");
155: this .variant = variant;
156: }
157:
158: public void addFormattingPattern(Locale locale, String pattern) {
159: localizedPatterns.put(locale, pattern);
160: }
161:
162: public void setNonLocalizedPattern(String pattern) {
163: this .nonLocalizedPattern = pattern;
164: }
165:
166: public Class getTypeClass() {
167: return java.math.BigDecimal.class;
168: }
169:
170: public void generateSaxFragment(ContentHandler contentHandler,
171: Locale locale) throws SAXException {
172: // intentionally empty
173: }
174: }
|