< prev index next >

src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java

Print this page
rev 49854 : 8181157: CLDR Timezone name fallback implementation
Reviewed-by: sherman
   1 /*
   2  * Copyright (c) 2012, 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


  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.locale.provider;
  42 
  43 import java.lang.ref.ReferenceQueue;
  44 import java.lang.ref.SoftReference;
  45 import java.text.MessageFormat;
  46 import java.util.Calendar;
  47 import java.util.LinkedHashSet;
  48 import java.util.Locale;
  49 import java.util.Map;
  50 import java.util.Objects;
  51 import java.util.ResourceBundle;
  52 import java.util.Set;
  53 import java.util.concurrent.ConcurrentHashMap;
  54 import java.util.concurrent.ConcurrentMap;

  55 import sun.util.calendar.ZoneInfo;
  56 import sun.util.resources.LocaleData;
  57 import sun.util.resources.OpenListResourceBundle;
  58 import sun.util.resources.ParallelListResourceBundle;
  59 import sun.util.resources.TimeZoneNamesBundle;
  60 
  61 /**
  62  * Central accessor to locale-dependent resources for JRE/CLDR provider adapters.
  63  *
  64  * @author Masayoshi Okutsu
  65  * @author Naoto Sato
  66  */
  67 public class LocaleResources {
  68 
  69     private final Locale locale;
  70     private final LocaleData localeData;
  71     private final LocaleProviderAdapter.Type type;
  72 
  73     // Resource cache
  74     private final ConcurrentMap<String, ResourceReference> cache = new ConcurrentHashMap<>();
  75     private final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
  76 
  77     // cache key prefixes
  78     private static final String BREAK_ITERATOR_INFO = "BII.";
  79     private static final String CALENDAR_DATA = "CALD.";
  80     private static final String COLLATION_DATA_CACHEKEY = "COLD";
  81     private static final String DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY = "DFSD";
  82     private static final String CURRENCY_NAMES = "CN.";
  83     private static final String LOCALE_NAMES = "LN.";
  84     private static final String TIME_ZONE_NAMES = "TZN.";
  85     private static final String ZONE_IDS_CACHEKEY = "ZID";
  86     private static final String CALENDAR_NAMES = "CALN.";
  87     private static final String NUMBER_PATTERNS_CACHEKEY = "NP";
  88     private static final String DATE_TIME_PATTERN = "DTP.";
  89 



  90     // null singleton cache value
  91     private static final Object NULLOBJECT = new Object();
  92 
  93     LocaleResources(ResourceBundleBasedAdapter adapter, Locale locale) {
  94         this.locale = locale;
  95         this.localeData = adapter.getLocaleData();
  96         type = ((LocaleProviderAdapter)adapter).getAdapterType();
  97     }
  98 
  99     private void removeEmptyReferences() {
 100         Object ref;
 101         while ((ref = referenceQueue.poll()) != null) {
 102             cache.remove(((ResourceReference)ref).getCacheKey());
 103         }
 104     }
 105 
 106     Object getBreakIteratorInfo(String key) {
 107         Object biInfo;
 108         String cacheKey = BREAK_ITERATOR_INFO + key;
 109 


 237 
 238         if (data != null && ((localeName = data.get()) != null)) {
 239             if (localeName.equals(NULLOBJECT)) {
 240                 localeName = null;
 241             }
 242 
 243             return (String) localeName;
 244         }
 245 
 246         OpenListResourceBundle olrb = localeData.getLocaleNames(locale);
 247 
 248         if (olrb.containsKey(key)) {
 249             localeName = olrb.getObject(key);
 250             cache.put(cacheKey,
 251                       new ResourceReference(cacheKey, localeName, referenceQueue));
 252         }
 253 
 254         return (String) localeName;
 255     }
 256 
 257     String[] getTimeZoneNames(String key) {
 258         String[] names = null;
 259         String cacheKey = TIME_ZONE_NAMES + '.' + key;
 260 
 261         removeEmptyReferences();
 262         ResourceReference data = cache.get(cacheKey);
 263 
 264         if (Objects.isNull(data) || Objects.isNull((names = (String[]) data.get()))) {
 265             TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale);
 266             if (tznb.containsKey(key)) {
 267                 names = tznb.getStringArray(key);









 268                 cache.put(cacheKey,
 269                           new ResourceReference(cacheKey, (Object) names, referenceQueue));
 270             }
 271         }
 272 
 273         return names;
 274     }
 275 
 276     @SuppressWarnings("unchecked")
 277     Set<String> getZoneIDs() {
 278         Set<String> zoneIDs = null;
 279 
 280         removeEmptyReferences();
 281         ResourceReference data = cache.get(ZONE_IDS_CACHEKEY);
 282         if (data == null || ((zoneIDs = (Set<String>) data.get()) == null)) {
 283             TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale);
 284             zoneIDs = rb.keySet();
 285             cache.put(ZONE_IDS_CACHEKEY,
 286                       new ResourceReference(ZONE_IDS_CACHEKEY, (Object) zoneIDs, referenceQueue));
 287         }
 288 
 289         return zoneIDs;
 290     }
 291 
 292     // zoneStrings are cached separately in TimeZoneNameUtility.
 293     String[][] getZoneStrings() {
 294         TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale);
 295         Set<String> keyset = getZoneIDs();
 296         // Use a LinkedHashSet to preseve the order
 297         Set<String[]> value = new LinkedHashSet<>();
 298         for (String key : keyset) {

 299             value.add(rb.getStringArray(key));
 300         }

 301 
 302         // Add aliases data for CLDR
 303         if (type == LocaleProviderAdapter.Type.CLDR) {
 304             // Note: TimeZoneNamesBundle creates a String[] on each getStringArray call.
 305             Map<String, String> aliases = ZoneInfo.getAliasTable();
 306             for (String alias : aliases.keySet()) {
 307                 if (!keyset.contains(alias)) {
 308                     String tzid = aliases.get(alias);
 309                     if (keyset.contains(tzid)) {
 310                         String[] val = rb.getStringArray(tzid);
 311                         val[0] = alias;
 312                         value.add(val);
 313                     }
 314                 }
 315             }
 316         }
 317         return value.toArray(new String[0][]);
 318     }
 319 
 320     String[] getCalendarNames(String key) {


 497             return null;
 498         }
 499 
 500         // for DateTimePatterns. CLDR has multiple styles, while JRE has one.
 501         String[] styles = (String[])value;
 502         return (styles.length > 1 ? styles[styleIndex] : styles[0]);
 503     }
 504 
 505     private static class ResourceReference extends SoftReference<Object> {
 506         private final String cacheKey;
 507 
 508         ResourceReference(String cacheKey, Object o, ReferenceQueue<Object> q) {
 509             super(o, q);
 510             this.cacheKey = cacheKey;
 511         }
 512 
 513         String getCacheKey() {
 514             return cacheKey;
 515         }
 516     }









 517 }
   1 /*
   2  * Copyright (c) 2012, 2018, 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


  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.locale.provider;
  42 
  43 import java.lang.ref.ReferenceQueue;
  44 import java.lang.ref.SoftReference;
  45 import java.text.MessageFormat;
  46 import java.util.Calendar;
  47 import java.util.LinkedHashSet;
  48 import java.util.Locale;
  49 import java.util.Map;
  50 import java.util.Objects;
  51 import java.util.ResourceBundle;
  52 import java.util.Set;
  53 import java.util.concurrent.ConcurrentHashMap;
  54 import java.util.concurrent.ConcurrentMap;
  55 import sun.security.action.GetPropertyAction;
  56 import sun.util.calendar.ZoneInfo;
  57 import sun.util.resources.LocaleData;
  58 import sun.util.resources.OpenListResourceBundle;
  59 import sun.util.resources.ParallelListResourceBundle;
  60 import sun.util.resources.TimeZoneNamesBundle;
  61 
  62 /**
  63  * Central accessor to locale-dependent resources for JRE/CLDR provider adapters.
  64  *
  65  * @author Masayoshi Okutsu
  66  * @author Naoto Sato
  67  */
  68 public class LocaleResources {
  69 
  70     private final Locale locale;
  71     private final LocaleData localeData;
  72     private final LocaleProviderAdapter.Type type;
  73 
  74     // Resource cache
  75     private final ConcurrentMap<String, ResourceReference> cache = new ConcurrentHashMap<>();
  76     private final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
  77 
  78     // cache key prefixes
  79     private static final String BREAK_ITERATOR_INFO = "BII.";
  80     private static final String CALENDAR_DATA = "CALD.";
  81     private static final String COLLATION_DATA_CACHEKEY = "COLD";
  82     private static final String DECIMAL_FORMAT_SYMBOLS_DATA_CACHEKEY = "DFSD";
  83     private static final String CURRENCY_NAMES = "CN.";
  84     private static final String LOCALE_NAMES = "LN.";
  85     private static final String TIME_ZONE_NAMES = "TZN.";
  86     private static final String ZONE_IDS_CACHEKEY = "ZID";
  87     private static final String CALENDAR_NAMES = "CALN.";
  88     private static final String NUMBER_PATTERNS_CACHEKEY = "NP";
  89     private static final String DATE_TIME_PATTERN = "DTP.";
  90 
  91     // TimeZoneNamesBundle exemplar city prefix
  92     private static final String TZNB_EXCITY_PREFIX = "timezone.excity.";
  93 
  94     // null singleton cache value
  95     private static final Object NULLOBJECT = new Object();
  96 
  97     LocaleResources(ResourceBundleBasedAdapter adapter, Locale locale) {
  98         this.locale = locale;
  99         this.localeData = adapter.getLocaleData();
 100         type = ((LocaleProviderAdapter)adapter).getAdapterType();
 101     }
 102 
 103     private void removeEmptyReferences() {
 104         Object ref;
 105         while ((ref = referenceQueue.poll()) != null) {
 106             cache.remove(((ResourceReference)ref).getCacheKey());
 107         }
 108     }
 109 
 110     Object getBreakIteratorInfo(String key) {
 111         Object biInfo;
 112         String cacheKey = BREAK_ITERATOR_INFO + key;
 113 


 241 
 242         if (data != null && ((localeName = data.get()) != null)) {
 243             if (localeName.equals(NULLOBJECT)) {
 244                 localeName = null;
 245             }
 246 
 247             return (String) localeName;
 248         }
 249 
 250         OpenListResourceBundle olrb = localeData.getLocaleNames(locale);
 251 
 252         if (olrb.containsKey(key)) {
 253             localeName = olrb.getObject(key);
 254             cache.put(cacheKey,
 255                       new ResourceReference(cacheKey, localeName, referenceQueue));
 256         }
 257 
 258         return (String) localeName;
 259     }
 260 
 261     public Object getTimeZoneNames(String key) {
 262         Object val = null;
 263         String cacheKey = TIME_ZONE_NAMES + key;
 264 
 265         removeEmptyReferences();
 266         ResourceReference data = cache.get(cacheKey);
 267 
 268         if (Objects.isNull(data) || Objects.isNull(val = data.get())) {
 269             TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale);
 270             if (tznb.containsKey(key)) {
 271                 if (key.startsWith(TZNB_EXCITY_PREFIX)) {
 272                     val = tznb.getString(key);
 273                     assert val instanceof String;
 274                     trace("tznb: %s key: %s, val: %s\n", tznb, key, val);
 275                 } else {
 276                     String[] names = tznb.getStringArray(key);
 277                     trace("tznb: %s key: %s, names: %s, %s, %s, %s, %s, %s, %s\n", tznb, key,
 278                         names[0], names[1], names[2], names[3], names[4], names[5], names[6]);
 279                     val = names;
 280                 }
 281                 cache.put(cacheKey,
 282                           new ResourceReference(cacheKey, val, referenceQueue));
 283             }
 284         }
 285 
 286         return val;
 287     }
 288 
 289     @SuppressWarnings("unchecked")
 290     Set<String> getZoneIDs() {
 291         Set<String> zoneIDs = null;
 292 
 293         removeEmptyReferences();
 294         ResourceReference data = cache.get(ZONE_IDS_CACHEKEY);
 295         if (data == null || ((zoneIDs = (Set<String>) data.get()) == null)) {
 296             TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale);
 297             zoneIDs = rb.keySet();
 298             cache.put(ZONE_IDS_CACHEKEY,
 299                       new ResourceReference(ZONE_IDS_CACHEKEY, (Object) zoneIDs, referenceQueue));
 300         }
 301 
 302         return zoneIDs;
 303     }
 304 
 305     // zoneStrings are cached separately in TimeZoneNameUtility.
 306     String[][] getZoneStrings() {
 307         TimeZoneNamesBundle rb = localeData.getTimeZoneNames(locale);
 308         Set<String> keyset = getZoneIDs();
 309         // Use a LinkedHashSet to preseve the order
 310         Set<String[]> value = new LinkedHashSet<>();
 311         for (String key : keyset) {
 312             if (!key.startsWith(TZNB_EXCITY_PREFIX)) {
 313                 value.add(rb.getStringArray(key));
 314             }
 315         }
 316 
 317         // Add aliases data for CLDR
 318         if (type == LocaleProviderAdapter.Type.CLDR) {
 319             // Note: TimeZoneNamesBundle creates a String[] on each getStringArray call.
 320             Map<String, String> aliases = ZoneInfo.getAliasTable();
 321             for (String alias : aliases.keySet()) {
 322                 if (!keyset.contains(alias)) {
 323                     String tzid = aliases.get(alias);
 324                     if (keyset.contains(tzid)) {
 325                         String[] val = rb.getStringArray(tzid);
 326                         val[0] = alias;
 327                         value.add(val);
 328                     }
 329                 }
 330             }
 331         }
 332         return value.toArray(new String[0][]);
 333     }
 334 
 335     String[] getCalendarNames(String key) {


 512             return null;
 513         }
 514 
 515         // for DateTimePatterns. CLDR has multiple styles, while JRE has one.
 516         String[] styles = (String[])value;
 517         return (styles.length > 1 ? styles[styleIndex] : styles[0]);
 518     }
 519 
 520     private static class ResourceReference extends SoftReference<Object> {
 521         private final String cacheKey;
 522 
 523         ResourceReference(String cacheKey, Object o, ReferenceQueue<Object> q) {
 524             super(o, q);
 525             this.cacheKey = cacheKey;
 526         }
 527 
 528         String getCacheKey() {
 529             return cacheKey;
 530         }
 531     }
 532 
 533     private static final boolean TRACE_ON = Boolean.valueOf(
 534         GetPropertyAction.privilegedGetProperty("locale.resources.debug", "false"));
 535 
 536     public static void trace(String format, Object... params) {
 537         if (TRACE_ON) {
 538             System.out.format(format, params);
 539         }
 540     }
 541 }
< prev index next >