/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package javax.faces.convert; import java.util.*; import java.text.*; import javax.faces.application.*; import javax.faces.context.*; import javax.faces.component.*; public class NumberConverter implements Converter, StateHolder { public static final String CONVERTER_ID = "javax.faces.Number"; public static final String CURRENCY_ID = "javax.faces.converter.NumberConverter.CURRENCY"; public static final String NUMBER_ID = "javax.faces.converter.NumberConverter.NUMBER"; public static final String PATTERN_ID = "javax.faces.converter.NumberConverter.PATTERN"; public static final String PERCENT_ID = "javax.faces.converter.NumberConverter.PERCENT"; public static final String STRING_ID = "javax.faces.converter.STRING"; private String _currencyCode; private String _currencySymbol; private Locale _locale; private Integer _maxFractionDigits; private Integer _minFractionDigits; private Integer _maxIntegerDigits; private Integer _minIntegerDigits; private String _pattern; private String _type = "number"; private boolean _isGroupingUsed = true; private boolean _isIntegerOnly; private boolean _isTransient; private NumberFormat _format; public String getCurrencyCode() { return _currencyCode; } public void setCurrencyCode(String value) { _currencyCode = value; _format = null; } public String getCurrencySymbol() { return _currencySymbol; } public void setCurrencySymbol(String value) { _currencySymbol = value; _format = null; } public Locale getLocale() { if (_locale != null) return _locale; FacesContext context = FacesContext.getCurrentInstance(); return context.getViewRoot().getLocale(); } public void setLocale(Locale locale) { _locale = locale; _format = null; } public int getMaxFractionDigits() { if (_maxFractionDigits != null) return _maxFractionDigits; else return 0; } public void setMaxFractionDigits(int value) { _maxFractionDigits = value; _format = null; } public int getMinFractionDigits() { if (_minFractionDigits != null) return _minFractionDigits; else return 0; } public void setMinFractionDigits(int value) { _minFractionDigits = value; _format = null; } public int getMaxIntegerDigits() { if (_maxIntegerDigits != null) return _maxIntegerDigits; else return 0; } public void setMaxIntegerDigits(int value) { _maxIntegerDigits = value; _format = null; } public int getMinIntegerDigits() { if (_minIntegerDigits != null) return _minIntegerDigits; else return 0; } public void setMinIntegerDigits(int value) { _minIntegerDigits = value; _format = null; } public void setIntegerOnly(boolean isIntegerOnly) { _isIntegerOnly = isIntegerOnly; } public boolean isIntegerOnly() { return _isIntegerOnly; } public String getPattern() { return _pattern; } public void setPattern(String value) { _pattern = value; _format = null; } public String getType() { return _type; } public void setType(String value) { _type = value; _format = null; } public boolean isGroupingUsed() { return _isGroupingUsed; } public void setGroupingUsed(boolean value) { _isGroupingUsed = value; _format = null; } public boolean isTransient() { return _isTransient; } public void setTransient(boolean value) { _isTransient = value; } public void restoreState(FacesContext context, Object state) { Object []values = (Object []) state; _currencyCode = (String) values [0]; _currencySymbol = (String) values [1]; _locale = (Locale) values [2]; _maxFractionDigits = (Integer) values [3]; _minFractionDigits = (Integer) values [4]; _maxIntegerDigits = (Integer) values [5]; _minIntegerDigits = (Integer) values [6]; _pattern = (String) values [7]; _type = (String) values [8]; _isGroupingUsed = ((Boolean) values [9]).booleanValue(); _isIntegerOnly = ((Boolean) values [10]).booleanValue(); } public Object saveState(FacesContext context) { Object []state = new Object [11]; state [0] = _currencyCode; state [1] = _currencySymbol; state [2] = _locale; state [3] = _maxFractionDigits; state [4] = _minFractionDigits; state [5] = _maxIntegerDigits; state [6] = _minIntegerDigits; state [7] = _pattern; state [8] = _type; state [9] = _isGroupingUsed ? Boolean.TRUE : Boolean.FALSE; state [10] = _isIntegerOnly ? Boolean.TRUE : Boolean.FALSE; return state; } public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException { if (context == null || component == null) throw new NullPointerException(); // XXX: incorrect if (value == null) return null; if (value.length() == 0) return null; value = value.trim(); UIViewRoot viewRoot = context.getViewRoot(); Locale locale = null; if (viewRoot != null) locale = viewRoot.getLocale(); NumberFormat format = getFormat(locale); try { synchronized (format) { return format.parse(value); } } catch (ParseException e) { String summary; String detail; if ("percent".equals(_type)) { summary = Util.l10n(context, PERCENT_ID, "{2}: \"{0}\" could not be understood as a percentage.", value, getExample(context), Util.getLabel(context, component)); detail = Util.l10n(context, PERCENT_ID + "_detail", "{2}: \"{0}\" could not be understood as a percentage. Example: {1}.", value, getExample(context), Util.getLabel(context, component)); } else if ("currency".equals(_type)) { summary = Util.l10n(context, CURRENCY_ID, "{2}: \"{0}\" could not be understood as a currency value.", value, getExample(context), Util.getLabel(context, component)); detail = Util.l10n(context, CURRENCY_ID + "_detail", "{2}: \"{0}\" could not be understood as a currency value. Example: {1}.", value, getExample(context), Util.getLabel(context, component)); } else { summary = Util.l10n(context, NUMBER_ID, "{2}: \"{0}\" could not be understood as a number.", value, getExample(context), Util.getLabel(context, component)); detail = Util.l10n(context, NUMBER_ID + "_detail", "{2}: \"{0}\" could not be understood as a number. Example: {1}.", value, getExample(context), Util.getLabel(context, component)); } FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, detail); throw new ConverterException(msg, e); } } public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException { if (context == null || component == null) throw new NullPointerException(); if (value == null) return ""; else if (value instanceof Number) { NumberFormat format = getFormat(context.getViewRoot().getLocale()); synchronized (format) { return format.format((Number) value); } } else return String.valueOf(value); } private NumberFormat getFormat(Locale locale) { synchronized (this) { if (_locale == null) return createFormat(locale); else if (_format == null) { _format = createFormat(_locale); } return _format; } } private NumberFormat createFormat(Locale locale) { NumberFormat format; if (_type == null || "number".equals(_type)) { if (locale != null) format = NumberFormat.getNumberInstance(locale); else format = NumberFormat.getNumberInstance(); } else if ("currency".equals(_type)) { if (locale != null) format = NumberFormat.getCurrencyInstance(locale); else format = NumberFormat.getCurrencyInstance(); if (_currencyCode != null) format.setCurrency(Currency.getInstance(_currencyCode)); else if (_currencySymbol != null) { if (format instanceof DecimalFormat) { DecimalFormat decimalFormat = (DecimalFormat) format; DecimalFormatSymbols symbols = decimalFormat.getDecimalFormatSymbols(); symbols.setCurrencySymbol(_currencySymbol); decimalFormat.setDecimalFormatSymbols(symbols); } } } else if ("percent".equals(_type)) { if (locale != null) format = NumberFormat.getPercentInstance(locale); else format = NumberFormat.getPercentInstance(); } else { throw new ConverterException("'" + _type + "' is an illegal converter type."); } format.setGroupingUsed(_isGroupingUsed); format.setParseIntegerOnly(_isIntegerOnly); if (_maxFractionDigits != null) format.setMaximumFractionDigits(_maxFractionDigits); if (_minFractionDigits != null) format.setMinimumFractionDigits(_minFractionDigits); if (_maxIntegerDigits != null) format.setMaximumIntegerDigits(_maxIntegerDigits); if (_minIntegerDigits != null) format.setMinimumIntegerDigits(_minIntegerDigits); if (_pattern != null && format instanceof DecimalFormat) ((DecimalFormat) format).applyPattern(_pattern); return format; } private String getExample(FacesContext context) { UIViewRoot viewRoot = context.getViewRoot(); Locale locale = null; if (viewRoot != null) locale = viewRoot.getLocale(); NumberFormat format = getFormat(locale); synchronized (format) { if ("percentage".equals(_type)) return format.format(new Double(0.75)); else return format.format(new Double(10125.25)); } } public String toString() { return "NumberConverter[]"; } }