001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License version 2
011: * as published by the Free Software Foundation.
012: *
013: * Resin Open Source is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
016: * of NON-INFRINGEMENT. See the GNU General Public License for more
017: * details.
018: *
019: * You should have received a copy of the GNU General Public License
020: * along with Resin Open Source; if not, write to the
021: *
022: * Free Software Foundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package javax.faces.convert;
030:
031: import java.util.*;
032: import java.text.*;
033:
034: import javax.faces.application.*;
035: import javax.faces.context.*;
036: import javax.faces.component.*;
037:
038: public class NumberConverter implements Converter, StateHolder {
039: public static final String CONVERTER_ID = "javax.faces.Number";
040: public static final String CURRENCY_ID = "javax.faces.converter.NumberConverter.CURRENCY";
041: public static final String NUMBER_ID = "javax.faces.converter.NumberConverter.NUMBER";
042: public static final String PATTERN_ID = "javax.faces.converter.NumberConverter.PATTERN";
043: public static final String PERCENT_ID = "javax.faces.converter.NumberConverter.PERCENT";
044: public static final String STRING_ID = "javax.faces.converter.STRING";
045:
046: private String _currencyCode;
047: private String _currencySymbol;
048: private Locale _locale;
049:
050: private Integer _maxFractionDigits;
051: private Integer _minFractionDigits;
052:
053: private Integer _maxIntegerDigits;
054: private Integer _minIntegerDigits;
055:
056: private String _pattern;
057: private String _type = "number";
058: private boolean _isGroupingUsed = true;
059: private boolean _isIntegerOnly;
060: private boolean _isTransient;
061:
062: private NumberFormat _format;
063:
064: public String getCurrencyCode() {
065: return _currencyCode;
066: }
067:
068: public void setCurrencyCode(String value) {
069: _currencyCode = value;
070: _format = null;
071: }
072:
073: public String getCurrencySymbol() {
074: return _currencySymbol;
075: }
076:
077: public void setCurrencySymbol(String value) {
078: _currencySymbol = value;
079: _format = null;
080: }
081:
082: public Locale getLocale() {
083: if (_locale != null)
084: return _locale;
085:
086: FacesContext context = FacesContext.getCurrentInstance();
087:
088: return context.getViewRoot().getLocale();
089: }
090:
091: public void setLocale(Locale locale) {
092: _locale = locale;
093: _format = null;
094: }
095:
096: public int getMaxFractionDigits() {
097: if (_maxFractionDigits != null)
098: return _maxFractionDigits;
099: else
100: return 0;
101: }
102:
103: public void setMaxFractionDigits(int value) {
104: _maxFractionDigits = value;
105: _format = null;
106: }
107:
108: public int getMinFractionDigits() {
109: if (_minFractionDigits != null)
110: return _minFractionDigits;
111: else
112: return 0;
113: }
114:
115: public void setMinFractionDigits(int value) {
116: _minFractionDigits = value;
117: _format = null;
118: }
119:
120: public int getMaxIntegerDigits() {
121: if (_maxIntegerDigits != null)
122: return _maxIntegerDigits;
123: else
124: return 0;
125: }
126:
127: public void setMaxIntegerDigits(int value) {
128: _maxIntegerDigits = value;
129: _format = null;
130: }
131:
132: public int getMinIntegerDigits() {
133: if (_minIntegerDigits != null)
134: return _minIntegerDigits;
135: else
136: return 0;
137: }
138:
139: public void setMinIntegerDigits(int value) {
140: _minIntegerDigits = value;
141: _format = null;
142: }
143:
144: public void setIntegerOnly(boolean isIntegerOnly) {
145: _isIntegerOnly = isIntegerOnly;
146: }
147:
148: public boolean isIntegerOnly() {
149: return _isIntegerOnly;
150: }
151:
152: public String getPattern() {
153: return _pattern;
154: }
155:
156: public void setPattern(String value) {
157: _pattern = value;
158: _format = null;
159: }
160:
161: public String getType() {
162: return _type;
163: }
164:
165: public void setType(String value) {
166: _type = value;
167: _format = null;
168: }
169:
170: public boolean isGroupingUsed() {
171: return _isGroupingUsed;
172: }
173:
174: public void setGroupingUsed(boolean value) {
175: _isGroupingUsed = value;
176: _format = null;
177: }
178:
179: public boolean isTransient() {
180: return _isTransient;
181: }
182:
183: public void setTransient(boolean value) {
184: _isTransient = value;
185: }
186:
187: public void restoreState(FacesContext context, Object state) {
188: Object[] values = (Object[]) state;
189: _currencyCode = (String) values[0];
190: _currencySymbol = (String) values[1];
191: _locale = (Locale) values[2];
192: _maxFractionDigits = (Integer) values[3];
193: _minFractionDigits = (Integer) values[4];
194: _maxIntegerDigits = (Integer) values[5];
195: _minIntegerDigits = (Integer) values[6];
196: _pattern = (String) values[7];
197: _type = (String) values[8];
198: _isGroupingUsed = ((Boolean) values[9]).booleanValue();
199: _isIntegerOnly = ((Boolean) values[10]).booleanValue();
200: }
201:
202: public Object saveState(FacesContext context) {
203: Object[] state = new Object[11];
204: state[0] = _currencyCode;
205: state[1] = _currencySymbol;
206: state[2] = _locale;
207: state[3] = _maxFractionDigits;
208: state[4] = _minFractionDigits;
209: state[5] = _maxIntegerDigits;
210: state[6] = _minIntegerDigits;
211: state[7] = _pattern;
212: state[8] = _type;
213: state[9] = _isGroupingUsed ? Boolean.TRUE : Boolean.FALSE;
214: state[10] = _isIntegerOnly ? Boolean.TRUE : Boolean.FALSE;
215: return state;
216: }
217:
218: public Object getAsObject(FacesContext context,
219: UIComponent component, String value)
220: throws ConverterException {
221: if (context == null || component == null)
222: throw new NullPointerException();
223:
224: // XXX: incorrect
225: if (value == null)
226: return null;
227:
228: if (value.length() == 0)
229: return null;
230:
231: value = value.trim();
232:
233: UIViewRoot viewRoot = context.getViewRoot();
234: Locale locale = null;
235:
236: if (viewRoot != null)
237: locale = viewRoot.getLocale();
238:
239: NumberFormat format = getFormat(locale);
240:
241: try {
242: synchronized (format) {
243: return format.parse(value);
244: }
245: } catch (ParseException e) {
246: String summary;
247: String detail;
248:
249: if ("percent".equals(_type)) {
250: summary = Util
251: .l10n(
252: context,
253: PERCENT_ID,
254: "{2}: \"{0}\" could not be understood as a percentage.",
255: value, getExample(context), Util
256: .getLabel(context, component));
257:
258: detail = Util
259: .l10n(
260: context,
261: PERCENT_ID + "_detail",
262: "{2}: \"{0}\" could not be understood as a percentage. Example: {1}.",
263: value, getExample(context), Util
264: .getLabel(context, component));
265: } else if ("currency".equals(_type)) {
266: summary = Util
267: .l10n(
268: context,
269: CURRENCY_ID,
270: "{2}: \"{0}\" could not be understood as a currency value.",
271: value, getExample(context), Util
272: .getLabel(context, component));
273:
274: detail = Util
275: .l10n(
276: context,
277: CURRENCY_ID + "_detail",
278: "{2}: \"{0}\" could not be understood as a currency value. Example: {1}.",
279: value, getExample(context), Util
280: .getLabel(context, component));
281: } else {
282: summary = Util
283: .l10n(
284: context,
285: NUMBER_ID,
286: "{2}: \"{0}\" could not be understood as a number.",
287: value, getExample(context), Util
288: .getLabel(context, component));
289:
290: detail = Util
291: .l10n(
292: context,
293: NUMBER_ID + "_detail",
294: "{2}: \"{0}\" could not be understood as a number. Example: {1}.",
295: value, getExample(context), Util
296: .getLabel(context, component));
297: }
298:
299: FacesMessage msg = new FacesMessage(summary, detail);
300:
301: throw new ConverterException(msg, e);
302: }
303: }
304:
305: public String getAsString(FacesContext context,
306: UIComponent component, Object value)
307: throws ConverterException {
308: if (context == null || component == null)
309: throw new NullPointerException();
310:
311: if (value == null)
312: return "";
313: else if (value instanceof Number) {
314: NumberFormat format = getFormat(context.getViewRoot()
315: .getLocale());
316:
317: synchronized (format) {
318: return format.format((Number) value);
319: }
320: } else
321: return String.valueOf(value);
322: }
323:
324: private NumberFormat getFormat(Locale locale) {
325: synchronized (this ) {
326: if (_locale == null)
327: return createFormat(locale);
328: else if (_format == null) {
329: _format = createFormat(_locale);
330: }
331:
332: return _format;
333: }
334: }
335:
336: private NumberFormat createFormat(Locale locale) {
337: NumberFormat format;
338:
339: if (_type == null || "number".equals(_type)) {
340: if (locale != null)
341: format = NumberFormat.getNumberInstance(locale);
342: else
343: format = NumberFormat.getNumberInstance();
344: } else if ("currency".equals(_type)) {
345: if (locale != null)
346: format = NumberFormat.getCurrencyInstance(locale);
347: else
348: format = NumberFormat.getCurrencyInstance();
349:
350: if (_currencyCode != null)
351: format.setCurrency(Currency.getInstance(_currencyCode));
352: else if (_currencySymbol != null) {
353: if (format instanceof DecimalFormat) {
354: DecimalFormat decimalFormat = (DecimalFormat) format;
355: DecimalFormatSymbols symbols = decimalFormat
356: .getDecimalFormatSymbols();
357:
358: symbols.setCurrencySymbol(_currencySymbol);
359: decimalFormat.setDecimalFormatSymbols(symbols);
360: }
361: }
362: } else if ("percent".equals(_type)) {
363: if (locale != null)
364: format = NumberFormat.getPercentInstance(locale);
365: else
366: format = NumberFormat.getPercentInstance();
367: } else {
368: throw new ConverterException("'" + _type
369: + "' is an illegal converter type.");
370: }
371:
372: format.setGroupingUsed(_isGroupingUsed);
373: format.setParseIntegerOnly(_isIntegerOnly);
374:
375: if (_maxFractionDigits != null)
376: format.setMaximumFractionDigits(_maxFractionDigits);
377: if (_minFractionDigits != null)
378: format.setMinimumFractionDigits(_minFractionDigits);
379: if (_maxIntegerDigits != null)
380: format.setMaximumIntegerDigits(_maxIntegerDigits);
381: if (_minIntegerDigits != null)
382: format.setMinimumIntegerDigits(_minIntegerDigits);
383:
384: if (_pattern != null && format instanceof DecimalFormat)
385: ((DecimalFormat) format).applyPattern(_pattern);
386:
387: return format;
388: }
389:
390: private String getExample(FacesContext context) {
391: UIViewRoot viewRoot = context.getViewRoot();
392: Locale locale = null;
393:
394: if (viewRoot != null)
395: locale = viewRoot.getLocale();
396:
397: NumberFormat format = getFormat(locale);
398:
399: synchronized (format) {
400: if ("percentage".equals(_type))
401: return format.format(new Double(0.75));
402: else
403: return format.format(new Double(10125.25));
404: }
405: }
406:
407: public String toString() {
408: return "NumberConverter[]";
409: }
410: }
|