1 /* 2 * Copyright (c) 1996, 2014, 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 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved 28 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved 29 * 30 * The original version of this source code and documentation 31 * is copyrighted and owned by Taligent, Inc., a wholly-owned 32 * subsidiary of IBM. These materials are provided under terms 33 * of a License Agreement between Taligent and Sun. This technology 34 * is protected by multiple US and International patents. 35 * 36 * This notice and attribution to Taligent may not be removed. 37 * Taligent is a registered trademark of Taligent, Inc. 38 * 39 */ 40 41 package sun.util.resources; 42 43 import java.security.AccessController; 44 import java.security.PrivilegedAction; 45 import java.util.Arrays; 46 import java.util.Iterator; 47 import java.util.List; 48 import java.util.Locale; 49 import java.util.MissingResourceException; 50 import java.util.ResourceBundle; 51 import java.util.Set; 52 import sun.util.locale.provider.JRELocaleProviderAdapter; 53 import sun.util.locale.provider.LocaleDataMetaInfo; 54 import sun.util.locale.provider.LocaleProviderAdapter; 55 import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR; 56 import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE; 57 58 /** 59 * Provides information about and access to resource bundles in the 60 * sun.text.resources and sun.util.resources packages or in their corresponding 61 * packages for CLDR. 62 * 63 * @author Asmus Freytag 64 * @author Mark Davis 65 */ 66 67 public class LocaleData { 68 private final LocaleProviderAdapter.Type type; 69 70 public LocaleData(LocaleProviderAdapter.Type type) { 71 this.type = type; 72 } 73 74 /** 75 * Gets a calendar data resource bundle, using privileges 76 * to allow accessing a sun.* package. 77 */ 78 public ResourceBundle getCalendarData(Locale locale) { 79 return getBundle(type.getUtilResourcesPackage() + ".CalendarData", locale); 80 } 81 82 /** 83 * Gets a currency names resource bundle, using privileges 84 * to allow accessing a sun.* package. 85 */ 86 public OpenListResourceBundle getCurrencyNames(Locale locale) { 87 return (OpenListResourceBundle) getBundle(type.getUtilResourcesPackage() + ".CurrencyNames", locale); 88 } 89 90 /** 91 * Gets a locale names resource bundle, using privileges 92 * to allow accessing a sun.* package. 93 */ 94 public OpenListResourceBundle getLocaleNames(Locale locale) { 95 return (OpenListResourceBundle) getBundle(type.getUtilResourcesPackage() + ".LocaleNames", locale); 96 } 97 98 /** 99 * Gets a time zone names resource bundle, using privileges 100 * to allow accessing a sun.* package. 101 */ 102 public TimeZoneNamesBundle getTimeZoneNames(Locale locale) { 103 return (TimeZoneNamesBundle) getBundle(type.getUtilResourcesPackage() + ".TimeZoneNames", locale); 104 } 105 106 /** 107 * Gets a break iterator info resource bundle, using privileges 108 * to allow accessing a sun.* package. 109 */ 110 public ResourceBundle getBreakIteratorInfo(Locale locale) { 111 return getBundle(type.getTextResourcesPackage() + ".BreakIteratorInfo", locale); 112 } 113 114 /** 115 * Gets a collation data resource bundle, using privileges 116 * to allow accessing a sun.* package. 117 */ 118 public ResourceBundle getCollationData(Locale locale) { 119 return getBundle(type.getTextResourcesPackage() + ".CollationData", locale); 120 } 121 122 /** 123 * Gets a date format data resource bundle, using privileges 124 * to allow accessing a sun.* package. 125 */ 126 public ResourceBundle getDateFormatData(Locale locale) { 127 return getBundle(type.getTextResourcesPackage() + ".FormatData", locale); 128 } 129 130 public void setSupplementary(ParallelListResourceBundle formatData) { 131 if (!formatData.areParallelContentsComplete()) { 132 String suppName = type.getTextResourcesPackage() + ".JavaTimeSupplementary"; 133 setSupplementary(suppName, formatData); 134 } 135 } 136 137 private boolean setSupplementary(String suppName, ParallelListResourceBundle formatData) { 138 ParallelListResourceBundle parent = (ParallelListResourceBundle) formatData.getParent(); 139 boolean resetKeySet = false; 140 if (parent != null) { 141 resetKeySet = setSupplementary(suppName, parent); 142 } 143 OpenListResourceBundle supp = getSupplementary(suppName, formatData.getLocale()); 144 formatData.setParallelContents(supp); 145 resetKeySet |= supp != null; 146 // If any parents or this bundle has parallel data, reset keyset to create 147 // a new keyset with the data. 148 if (resetKeySet) { 149 formatData.resetKeySet(); 150 } 151 return resetKeySet; 152 } 153 154 /** 155 * Gets a number format data resource bundle, using privileges 156 * to allow accessing a sun.* package. 157 */ 158 public ResourceBundle getNumberFormatData(Locale locale) { 159 return getBundle(type.getTextResourcesPackage() + ".FormatData", locale); 160 } 161 162 public static ResourceBundle getBundle(final String baseName, final Locale locale) { 163 return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() { 164 @Override 165 public ResourceBundle run() { 166 return ResourceBundle 167 .getBundle(baseName, locale, LocaleDataResourceBundleControl.INSTANCE); 168 } 169 }); 170 } 171 172 private static OpenListResourceBundle getSupplementary(final String baseName, final Locale locale) { 173 return AccessController.doPrivileged(new PrivilegedAction<OpenListResourceBundle>() { 174 @Override 175 public OpenListResourceBundle run() { 176 OpenListResourceBundle rb = null; 177 try { 178 rb = (OpenListResourceBundle) ResourceBundle.getBundle(baseName, 179 locale, SupplementaryResourceBundleControl.INSTANCE); 180 181 } catch (MissingResourceException e) { 182 // return null if no supplementary is available 183 } 184 return rb; 185 } 186 }); 187 } 188 189 private static class LocaleDataResourceBundleControl extends ResourceBundle.Control { 190 /* Singlton instance of ResourceBundle.Control. */ 191 private static final LocaleDataResourceBundleControl INSTANCE = 192 new LocaleDataResourceBundleControl(); 193 194 private LocaleDataResourceBundleControl() { 195 } 196 197 /* 198 * This method overrides the default implementation to search 199 * from a prebaked locale string list to determin the candidate 200 * locale list. 201 * 202 * @param baseName the resource bundle base name. 203 * locale the requested locale for the resource bundle. 204 * @returns a list of candidate locales to search from. 205 * @exception NullPointerException if baseName or locale is null. 206 */ 207 @Override 208 public List<Locale> getCandidateLocales(String baseName, Locale locale) { 209 List<Locale> candidates = super.getCandidateLocales(baseName, locale); 210 // Weed out Locales which are known to have no resource bundles 211 int lastDot = baseName.lastIndexOf('.'); 212 String category = (lastDot >= 0) ? baseName.substring(lastDot + 1) : baseName; 213 LocaleProviderAdapter.Type type = baseName.contains(DOTCLDR) ? CLDR : JRE; 214 LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); 215 Set<String> langtags = ((JRELocaleProviderAdapter)adapter).getLanguageTagSet(category); 216 if (!langtags.isEmpty()) { 217 for (Iterator<Locale> itr = candidates.iterator(); itr.hasNext();) { 218 if (!LocaleProviderAdapter.isSupportedLocale(itr.next(), type, langtags)) { 219 itr.remove(); 220 } 221 } 222 } 223 224 // Force fallback to Locale.ENGLISH for CLDR time zone names support 225 if (locale.getLanguage() != "en" 226 && type == CLDR && category.equals("TimeZoneNames")) { 227 candidates.add(candidates.size() - 1, Locale.ENGLISH); 228 } 229 return candidates; 230 } 231 232 /* 233 * Overrides "getFallbackLocale" to return null so 234 * that the fallback locale will be null. 235 * @param baseName the resource bundle base name. 236 * locale the requested locale for the resource bundle. 237 * @return null for the fallback locale. 238 * @exception NullPointerException if baseName or locale is null. 239 */ 240 @Override 241 public Locale getFallbackLocale(String baseName, Locale locale) { 242 if (baseName == null || locale == null) { 243 throw new NullPointerException(); 244 } 245 return null; 246 } 247 248 private static final String DOTCLDR = ".cldr"; 249 250 /** 251 * Changes baseName to its per-language package name and 252 * calls the super class implementation. For example, 253 * if the baseName is "sun.text.resources.FormatData" and locale is ja_JP, 254 * the baseName is changed to "sun.text.resources.ja.FormatData". If 255 * baseName contains "cldr", such as "sun.text.resources.cldr.FormatData", 256 * the name is changed to "sun.text.resources.cldr.jp.FormatData". 257 */ 258 @Override 259 public String toBundleName(String baseName, Locale locale) { 260 String newBaseName = baseName; 261 String lang = locale.getLanguage(); 262 if (lang.length() > 0) { 263 if (baseName.startsWith(JRE.getUtilResourcesPackage()) 264 || baseName.startsWith(JRE.getTextResourcesPackage())) { 265 // Assume the lengths are the same. 266 assert JRE.getUtilResourcesPackage().length() 267 == JRE.getTextResourcesPackage().length(); 268 int index = JRE.getUtilResourcesPackage().length(); 269 if (baseName.indexOf(DOTCLDR, index) > 0) { 270 index += DOTCLDR.length(); 271 } 272 newBaseName = baseName.substring(0, index + 1) + lang 273 + baseName.substring(index); 274 } 275 } 276 return super.toBundleName(newBaseName, locale); 277 } 278 } 279 280 private static class SupplementaryResourceBundleControl extends LocaleDataResourceBundleControl { 281 private static final SupplementaryResourceBundleControl INSTANCE = 282 new SupplementaryResourceBundleControl(); 283 284 private SupplementaryResourceBundleControl() { 285 } 286 287 @Override 288 public List<Locale> getCandidateLocales(String baseName, Locale locale) { 289 // Specifiy only the given locale 290 return Arrays.asList(locale); 291 } 292 293 @Override 294 public long getTimeToLive(String baseName, Locale locale) { 295 assert baseName.contains("JavaTimeSupplementary"); 296 return TTL_DONT_CACHE; 297 } 298 } 299 }