1 /* 2 * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * 28 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved 29 * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved 30 * 31 * The original version of this source code and documentation 32 * is copyrighted and owned by Taligent, Inc., a wholly-owned 33 * subsidiary of IBM. These materials are provided under terms 34 * of a License Agreement between Taligent and Sun. This technology 35 * is protected by multiple US and International patents. 36 * 37 * This notice and attribution to Taligent may not be removed. 38 * Taligent is a registered trademark of Taligent, Inc. 39 */ 40 41 package sun.util.locale.provider; 42 43 import java.text.DecimalFormat; 44 import java.text.DecimalFormatSymbols; 45 import java.text.NumberFormat; 46 import java.text.spi.NumberFormatProvider; 47 import java.util.Currency; 48 import java.util.Locale; 49 import java.util.Set; 50 51 /** 52 * Concrete implementation of the {@link java.text.spi.NumberFormatProvider 53 * NumberFormatProvider} class for the JRE LocaleProviderAdapter. 54 * 55 * @author Naoto Sato 56 * @author Masayoshi Okutsu 57 */ 58 public class NumberFormatProviderImpl extends NumberFormatProvider implements AvailableLanguageTags { 59 60 // Constants used by factory methods to specify a style of format. 61 private static final int NUMBERSTYLE = 0; 62 private static final int CURRENCYSTYLE = 1; 63 private static final int PERCENTSTYLE = 2; 64 private static final int SCIENTIFICSTYLE = 3; 65 private static final int INTEGERSTYLE = 4; 66 67 private final LocaleProviderAdapter.Type type; 68 private final Set<String> langtags; 69 70 public NumberFormatProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) { 71 this.type = type; 72 this.langtags = langtags; 73 } 74 75 /** 76 * Returns an array of all locales for which this locale service provider 77 * can provide localized objects or names. 78 * 79 * @return An array of all locales for which this locale service provider 80 * can provide localized objects or names. 81 */ 82 @Override 83 public Locale[] getAvailableLocales() { 84 return LocaleProviderAdapter.forType(type).getAvailableLocales(); 85 } 86 87 @Override 88 public boolean isSupportedLocale(Locale locale) { 89 return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags); 90 } 91 92 /** 93 * Returns a new <code>NumberFormat</code> instance which formats 94 * monetary values for the specified locale. 95 * 96 * @param locale the desired locale. 97 * @exception NullPointerException if <code>locale</code> is null 98 * @exception IllegalArgumentException if <code>locale</code> isn't 99 * one of the locales returned from 100 * {@link java.util.spi.LocaleServiceProvider#getAvailableLocales() 101 * getAvailableLocales()}. 102 * @return a currency formatter 103 * @see java.text.NumberFormat#getCurrencyInstance(java.util.Locale) 104 */ 105 @Override 106 public NumberFormat getCurrencyInstance(Locale locale) { 107 return getInstance(locale, CURRENCYSTYLE); 108 } 109 110 /** 111 * Returns a new <code>NumberFormat</code> instance which formats 112 * integer values for the specified locale. 113 * The returned number format is configured to 114 * round floating point numbers to the nearest integer using 115 * half-even rounding (see {@link java.math.RoundingMode#HALF_EVEN HALF_EVEN}) 116 * for formatting, and to parse only the integer part of 117 * an input string (see {@link 118 * java.text.NumberFormat#isParseIntegerOnly isParseIntegerOnly}). 119 * 120 * @param locale the desired locale 121 * @exception NullPointerException if <code>locale</code> is null 122 * @exception IllegalArgumentException if <code>locale</code> isn't 123 * one of the locales returned from 124 * {@link java.util.spi.LocaleServiceProvider#getAvailableLocales() 125 * getAvailableLocales()}. 126 * @return a number format for integer values 127 * @see java.text.NumberFormat#getIntegerInstance(java.util.Locale) 128 */ 129 @Override 130 public NumberFormat getIntegerInstance(Locale locale) { 131 return getInstance(locale, INTEGERSTYLE); 132 } 133 134 /** 135 * Returns a new general-purpose <code>NumberFormat</code> instance for 136 * the specified locale. 137 * 138 * @param locale the desired locale 139 * @exception NullPointerException if <code>locale</code> is null 140 * @exception IllegalArgumentException if <code>locale</code> isn't 141 * one of the locales returned from 142 * {@link java.util.spi.LocaleServiceProvider#getAvailableLocales() 143 * getAvailableLocales()}. 144 * @return a general-purpose number formatter 145 * @see java.text.NumberFormat#getNumberInstance(java.util.Locale) 146 */ 147 @Override 148 public NumberFormat getNumberInstance(Locale locale) { 149 return getInstance(locale, NUMBERSTYLE); 150 } 151 152 /** 153 * Returns a new <code>NumberFormat</code> instance which formats 154 * percentage values for the specified locale. 155 * 156 * @param locale the desired locale 157 * @exception NullPointerException if <code>locale</code> is null 158 * @exception IllegalArgumentException if <code>locale</code> isn't 159 * one of the locales returned from 160 * {@link java.util.spi.LocaleServiceProvider#getAvailableLocales() 161 * getAvailableLocales()}. 162 * @return a percent formatter 163 * @see java.text.NumberFormat#getPercentInstance(java.util.Locale) 164 */ 165 @Override 166 public NumberFormat getPercentInstance(Locale locale) { 167 return getInstance(locale, PERCENTSTYLE); 168 } 169 170 private NumberFormat getInstance(Locale locale, 171 int choice) { 172 if (locale == null) { 173 throw new NullPointerException(); 174 } 175 176 // Check for region override 177 Locale override = locale.getUnicodeLocaleType("nu") == null ? 178 CalendarDataUtility.findRegionOverride(locale).orElse(locale) : 179 locale; 180 181 LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); 182 String[] numberPatterns = adapter.getLocaleResources(override).getNumberPatterns(); 183 DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(override); 184 int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice; 185 DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols); 186 187 if (choice == INTEGERSTYLE) { 188 format.setMaximumFractionDigits(0); 189 format.setDecimalSeparatorAlwaysShown(false); 190 format.setParseIntegerOnly(true); 191 } else if (choice == CURRENCYSTYLE) { 192 adjustForCurrencyDefaultFractionDigits(format, symbols); 193 } 194 195 return format; 196 } 197 198 /** 199 * Adjusts the minimum and maximum fraction digits to values that 200 * are reasonable for the currency's default fraction digits. 201 */ 202 private static void adjustForCurrencyDefaultFractionDigits( 203 DecimalFormat format, DecimalFormatSymbols symbols) { 204 Currency currency = symbols.getCurrency(); 205 if (currency == null) { 206 try { 207 currency = Currency.getInstance(symbols.getInternationalCurrencySymbol()); 208 } catch (IllegalArgumentException e) { 209 } 210 } 211 if (currency != null) { 212 int digits = currency.getDefaultFractionDigits(); 213 if (digits != -1) { 214 int oldMinDigits = format.getMinimumFractionDigits(); 215 // Common patterns are "#.##", "#.00", "#". 216 // Try to adjust all of them in a reasonable way. 217 if (oldMinDigits == format.getMaximumFractionDigits()) { 218 format.setMinimumFractionDigits(digits); 219 format.setMaximumFractionDigits(digits); 220 } else { 221 format.setMinimumFractionDigits(Math.min(digits, oldMinDigits)); 222 format.setMaximumFractionDigits(digits); 223 } 224 } 225 } 226 } 227 228 @Override 229 public Set<String> getAvailableLanguageTags() { 230 return langtags; 231 } 232 }