1 /* 2 * Copyright (c) 1996, 2013, 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 sun.util.locale.provider.LocaleDataMetaInfo; 52 import sun.util.locale.provider.LocaleProviderAdapter; 53 import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE; 54 55 /** 56 * Provides information about and access to resource bundles in the 57 * sun.text.resources and sun.util.resources packages or in their corresponding 58 * packages for CLDR. 59 * 60 * @author Asmus Freytag 61 * @author Mark Davis 62 */ 63 64 public class LocaleData { 65 private final LocaleProviderAdapter.Type type; 66 67 public LocaleData(LocaleProviderAdapter.Type type) { 68 this.type = type; 69 } 70 71 /** 72 * Gets a calendar data resource bundle, using privileges 73 * to allow accessing a sun.* package. 74 */ 75 public ResourceBundle getCalendarData(Locale locale) { 76 return getBundle(type.getUtilResourcesPackage() + ".CalendarData", locale); 77 } 78 79 /** 80 * Gets a currency names resource bundle, using privileges 81 * to allow accessing a sun.* package. 82 */ 83 public OpenListResourceBundle getCurrencyNames(Locale locale) { 84 return (OpenListResourceBundle) getBundle(type.getUtilResourcesPackage() + ".CurrencyNames", locale); 85 } 86 87 /** 88 * Gets a locale names resource bundle, using privileges 89 * to allow accessing a sun.* package. 90 */ 91 public OpenListResourceBundle getLocaleNames(Locale locale) { 92 return (OpenListResourceBundle) getBundle(type.getUtilResourcesPackage() + ".LocaleNames", locale); 93 } 94 95 /** 96 * Gets a time zone names resource bundle, using privileges 97 * to allow accessing a sun.* package. 98 */ 99 public TimeZoneNamesBundle getTimeZoneNames(Locale locale) { 100 return (TimeZoneNamesBundle) getBundle(type.getUtilResourcesPackage() + ".TimeZoneNames", locale); 101 } 102 103 /** 104 * Gets a break iterator info resource bundle, using privileges 105 * to allow accessing a sun.* package. 106 */ 107 public ResourceBundle getBreakIteratorInfo(Locale locale) { 108 return getBundle(type.getTextResourcesPackage() + ".BreakIteratorInfo", locale); 109 } 110 111 /** 112 * Gets a collation data resource bundle, using privileges 113 * to allow accessing a sun.* package. 114 */ 115 public ResourceBundle getCollationData(Locale locale) { 116 return getBundle(type.getTextResourcesPackage() + ".CollationData", locale); 117 } 118 119 /** 120 * Gets a date format data resource bundle, using privileges 121 * to allow accessing a sun.* package. 122 */ 123 public ResourceBundle getDateFormatData(Locale locale) { 124 return getBundle(type.getTextResourcesPackage() + ".FormatData", locale); 125 } 126 127 public void setSupplementary(ParallelListResourceBundle formatData) { 128 if (!formatData.areParallelContentsComplete()) { 129 String suppName = type.getTextResourcesPackage() + ".JavaTimeSupplementary"; 130 setSupplementary(suppName, formatData); 131 } 132 } 133 134 private boolean setSupplementary(String suppName, ParallelListResourceBundle formatData) { 135 ParallelListResourceBundle parent = (ParallelListResourceBundle) formatData.getParent(); 136 boolean resetKeySet = false; 137 if (parent != null) { 138 resetKeySet = setSupplementary(suppName, parent); 139 } 140 OpenListResourceBundle supp = getSupplementary(suppName, formatData.getLocale()); 141 formatData.setParallelContents(supp); 142 resetKeySet |= supp != null; 143 // If any parents or this bundle has parallel data, reset keyset to create 144 // a new keyset with the data. 145 if (resetKeySet) { 146 formatData.resetKeySet(); 147 } 148 return resetKeySet; 149 } 150 151 /** 152 * Gets a number format data resource bundle, using privileges 153 * to allow accessing a sun.* package. 154 */ 155 public ResourceBundle getNumberFormatData(Locale locale) { 156 return getBundle(type.getTextResourcesPackage() + ".FormatData", locale); 157 } 158 159 public static ResourceBundle getBundle(final String baseName, final Locale locale) { 160 return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() { 161 @Override 162 public ResourceBundle run() { 163 return ResourceBundle 164 .getBundle(baseName, locale, LocaleDataResourceBundleControl.INSTANCE); 165 } 166 }); 167 } 168 169 private static OpenListResourceBundle getSupplementary(final String baseName, final Locale locale) { 170 return AccessController.doPrivileged(new PrivilegedAction<OpenListResourceBundle>() { 171 @Override 172 public OpenListResourceBundle run() { 173 OpenListResourceBundle rb = null; 174 try { 175 rb = (OpenListResourceBundle) ResourceBundle.getBundle(baseName, 176 locale, SupplementaryResourceBundleControl.INSTANCE); 177 178 } catch (MissingResourceException e) { 179 // return null if no supplementary is available 180 } 181 return rb; 182 } 183 }); 184 } 185 186 private static class LocaleDataResourceBundleControl extends ResourceBundle.Control { 187 /* Singlton instance of ResourceBundle.Control. */ 188 private static final LocaleDataResourceBundleControl INSTANCE = 189 new LocaleDataResourceBundleControl(); 190 191 private LocaleDataResourceBundleControl() { 192 } 193 194 /* 195 * This method overrides the default implementation to search 196 * from a prebaked locale string list to determin the candidate 197 * locale list. 198 * 199 * @param baseName the resource bundle base name. 200 * locale the requested locale for the resource bundle. 201 * @returns a list of candidate locales to search from. 202 * @exception NullPointerException if baseName or locale is null. 203 */ 204 @Override 205 public List<Locale> getCandidateLocales(String baseName, Locale locale) { 206 List<Locale> candidates = super.getCandidateLocales(baseName, locale); 207 /* Get the locale string list from LocaleDataMetaInfo class. */ 208 String localeString = LocaleDataMetaInfo.getSupportedLocaleString(baseName); 209 210 if (localeString != null && localeString.length() != 0) { 211 for (Iterator<Locale> l = candidates.iterator(); l.hasNext();) { 212 Locale loc = l.next(); 213 String lstr; 214 if (loc.getScript().length() > 0) { 215 lstr = loc.toLanguageTag().replace('-', '_'); 216 } else { 217 lstr = loc.toString(); 218 int idx = lstr.indexOf("_#"); 219 if (idx >= 0) { 220 lstr = lstr.substring(0, idx); 221 } 222 } 223 /* Every locale string in the locale string list returned from 224 the above getSupportedLocaleString is enclosed 225 within two white spaces so that we could check some locale 226 such as "en". 227 */ 228 if (lstr.length() != 0 && localeString.indexOf(" " + lstr + " ") == -1) { 229 l.remove(); 230 } 231 } 232 } 233 // Force fallback to Locale.ENGLISH for CLDR time zone names support 234 if (locale.getLanguage() != "en" 235 && baseName.contains(CLDR) && baseName.endsWith("TimeZoneNames")) { 236 candidates.add(candidates.size() - 1, Locale.ENGLISH); 237 } 238 return candidates; 239 } 240 241 /* 242 * Overrides "getFallbackLocale" to return null so 243 * that the fallback locale will be null. 244 * @param baseName the resource bundle base name. 245 * locale the requested locale for the resource bundle. 246 * @return null for the fallback locale. 247 * @exception NullPointerException if baseName or locale is null. 248 */ 249 @Override 250 public Locale getFallbackLocale(String baseName, Locale locale) { 251 if (baseName == null || locale == null) { 252 throw new NullPointerException(); 253 } 254 return null; 255 } 256 257 private static final String CLDR = ".cldr"; 258 259 /** 260 * Changes baseName to its per-language package name and 261 * calls the super class implementation. For example, 262 * if the baseName is "sun.text.resources.FormatData" and locale is ja_JP, 263 * the baseName is changed to "sun.text.resources.ja.FormatData". If 264 * baseName contains "cldr", such as "sun.text.resources.cldr.FormatData", 265 * the name is changed to "sun.text.resources.cldr.jp.FormatData". 266 */ 267 @Override 268 public String toBundleName(String baseName, Locale locale) { 269 String newBaseName = baseName; 270 String lang = locale.getLanguage(); 271 if (lang.length() > 0) { 272 if (baseName.startsWith(JRE.getUtilResourcesPackage()) 273 || baseName.startsWith(JRE.getTextResourcesPackage())) { 274 // Assume the lengths are the same. 275 assert JRE.getUtilResourcesPackage().length() 276 == JRE.getTextResourcesPackage().length(); 277 int index = JRE.getUtilResourcesPackage().length(); 278 if (baseName.indexOf(CLDR, index) > 0) { 279 index += CLDR.length(); 280 } 281 newBaseName = baseName.substring(0, index + 1) + lang 282 + baseName.substring(index); 283 } 284 } 285 return super.toBundleName(newBaseName, locale); 286 } 287 } 288 289 private static class SupplementaryResourceBundleControl extends LocaleDataResourceBundleControl { 290 private static final SupplementaryResourceBundleControl INSTANCE = 291 new SupplementaryResourceBundleControl(); 292 293 private SupplementaryResourceBundleControl() { 294 } 295 296 @Override 297 public List<Locale> getCandidateLocales(String baseName, Locale locale) { 298 // Specifiy only the given locale 299 return Arrays.asList(locale); 300 } 301 302 @Override 303 public long getTimeToLive(String baseName, Locale locale) { 304 assert baseName.contains("JavaTimeSupplementary"); 305 return TTL_DONT_CACHE; 306 } 307 } 308 }