8134720: Lazy initialization support for currency names in DecimalFormatSymbols
authornaoto
Thu, 22 Oct 2015 21:44:39 -0700
changeset 33310 2701a9854bb5
parent 33309 3aecb54196d9
child 33311 b606aa2b32d1
8134720: Lazy initialization support for currency names in DecimalFormatSymbols Reviewed-by: okutsu
jdk/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java
jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java
jdk/src/java.base/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java
jdk/src/java.base/share/classes/sun/util/locale/provider/CalendarDataUtility.java
jdk/src/java.base/share/classes/sun/util/locale/provider/CalendarProviderImpl.java
jdk/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java
jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java
jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java
jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java
jdk/src/java.base/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java
jdk/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java
jdk/src/java.base/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java
--- a/jdk/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Thu Oct 22 21:44:39 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,13 +57,13 @@
 public class HostLocaleProviderAdapterImpl {
 
     // per supported locale instances
-    private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatPatternsMap =
+    private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatPatternsMap =
         new ConcurrentHashMap<>(2);
-    private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatPatternsMap =
+    private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatPatternsMap =
         new ConcurrentHashMap<>(2);
-    private static ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsMap =
+    private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsMap =
         new ConcurrentHashMap<>(2);
-    private static ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsMap =
+    private static final ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsMap =
         new ConcurrentHashMap<>(2);
 
     // locale categories
--- a/jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java	Thu Oct 22 21:44:39 2015 -0700
@@ -384,6 +384,7 @@
      */
     public String getCurrencySymbol()
     {
+        initializeCurrency(locale);
         return currencySymbol;
     }
 
@@ -396,6 +397,7 @@
      */
     public void setCurrencySymbol(String currency)
     {
+        initializeCurrency(locale);
         currencySymbol = currency;
     }
 
@@ -408,6 +410,7 @@
      */
     public String getInternationalCurrencySymbol()
     {
+        initializeCurrency(locale);
         return intlCurrencySymbol;
     }
 
@@ -429,6 +432,7 @@
      */
     public void setInternationalCurrencySymbol(String currencyCode)
     {
+        initializeCurrency(locale);
         intlCurrencySymbol = currencyCode;
         currency = null;
         if (currencyCode != null) {
@@ -449,6 +453,7 @@
      * @since 1.4
      */
     public Currency getCurrency() {
+        initializeCurrency(locale);
         return currency;
     }
 
@@ -468,6 +473,7 @@
         if (currency == null) {
             throw new NullPointerException();
         }
+        initializeCurrency(locale);
         this.currency = currency;
         intlCurrencySymbol = currency.getCurrencyCode();
         currencySymbol = currency.getSymbol(locale);
@@ -507,14 +513,15 @@
     {
         return exponential;
     }
-  /**
-   * Returns the string used to separate the mantissa from the exponent.
-   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
-   *
-   * @return the exponent separator string
-   * @see #setExponentSeparator(java.lang.String)
-   * @since 1.6
-   */
+
+    /**
+     * Returns the string used to separate the mantissa from the exponent.
+     * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
+     *
+     * @return the exponent separator string
+     * @see #setExponentSeparator(java.lang.String)
+     * @since 1.6
+     */
     public String getExponentSeparator()
     {
         return exponentialSeparator;
@@ -528,22 +535,22 @@
         exponential = exp;
     }
 
-  /**
-   * Sets the string used to separate the mantissa from the exponent.
-   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
-   *
-   * @param exp the exponent separator string
-   * @exception NullPointerException if <code>exp</code> is null
-   * @see #getExponentSeparator()
-   * @since 1.6
-   */
+    /**
+     * Sets the string used to separate the mantissa from the exponent.
+     * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
+     *
+     * @param exp the exponent separator string
+     * @exception NullPointerException if <code>exp</code> is null
+     * @see #getExponentSeparator()
+     * @since 1.6
+     */
     public void setExponentSeparator(String exp)
     {
         if (exp == null) {
             throw new NullPointerException();
         }
         exponentialSeparator = exp;
-     }
+    }
 
 
     //------------------------------------------------------------
@@ -582,7 +589,7 @@
         patternSeparator == other.patternSeparator &&
         infinity.equals(other.infinity) &&
         NaN.equals(other.NaN) &&
-        currencySymbol.equals(other.currencySymbol) &&
+        getCurrencySymbol().equals(other.getCurrencySymbol()) && // possible currency init occurs here
         intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
         currency == other.currency &&
         monetarySeparator == other.monetarySeparator &&
@@ -629,6 +636,24 @@
         infinity  = numberElements[9];
         NaN = numberElements[10];
 
+        // maybe filled with previously cached values, or null.
+        intlCurrencySymbol = (String) data[1];
+        currencySymbol = (String) data[2];
+
+        // Currently the monetary decimal separator is the same as the
+        // standard decimal separator for all locales that we support.
+        // If that changes, add a new entry to NumberElements.
+        monetarySeparator = decimalSeparator;
+    }
+
+    /**
+     * Lazy initialization for currency related fields
+     */
+    private void initializeCurrency(Locale locale) {
+        if (currencyInitialized) {
+            return;
+        }
+
         // Try to obtain the currency used in the locale's country.
         // Check for empty country string separately because it's a valid
         // country ID for Locale (and used for the C locale), but not a valid
@@ -640,7 +665,16 @@
                 // use default values below for compatibility
             }
         }
+
         if (currency != null) {
+            // get resource bundle data
+            LocaleProviderAdapter adapter =
+                LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
+            // Avoid potential recursions
+            if (!(adapter instanceof ResourceBundleBasedAdapter)) {
+                adapter = LocaleProviderAdapter.getResourceBundleBased();
+            }
+            Object[] data = adapter.getLocaleResources(locale).getDecimalFormatSymbolsData();
             intlCurrencySymbol = currency.getCurrencyCode();
             if (data[1] != null && data[1] == intlCurrencySymbol) {
                 currencySymbol = (String) data[2];
@@ -658,10 +692,8 @@
             }
             currencySymbol = "\u00A4";
         }
-        // Currently the monetary decimal separator is the same as the
-        // standard decimal separator for all locales that we support.
-        // If that changes, add a new entry to NumberElements.
-        monetarySeparator = decimalSeparator;
+
+        currencyInitialized = true;
     }
 
     /**
@@ -705,6 +737,7 @@
                  currency = Currency.getInstance(intlCurrencySymbol);
             } catch (IllegalArgumentException e) {
             }
+            currencyInitialized = true;
         }
     }
 
@@ -820,16 +853,16 @@
      */
     private  char    exponential;       // Field new in JDK 1.1.6
 
-  /**
-   * The string used to separate the mantissa from the exponent.
-   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
-   * <p>
-   * If both <code>exponential</code> and <code>exponentialSeparator</code>
-   * exist, this <code>exponentialSeparator</code> has the precedence.
-   *
-   * @serial
-   * @since 1.6
-   */
+    /**
+     * The string used to separate the mantissa from the exponent.
+     * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
+     * <p>
+     * If both <code>exponential</code> and <code>exponentialSeparator</code>
+     * exist, this <code>exponentialSeparator</code> has the precedence.
+     *
+     * @serial
+     * @since 1.6
+     */
     private  String    exponentialSeparator;       // Field new in JDK 1.6
 
     /**
@@ -842,6 +875,7 @@
 
     // currency; only the ISO code is serialized.
     private transient Currency currency;
+    private transient volatile boolean currencyInitialized = false;
 
     // Proclaim JDK 1.1 FCS compatibility
     static final long serialVersionUID = 5772796243397350300L;
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/AuxLocaleProviderAdapter.java	Thu Oct 22 21:44:39 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,10 +33,10 @@
 import java.text.spi.DateFormatSymbolsProvider;
 import java.text.spi.DecimalFormatSymbolsProvider;
 import java.text.spi.NumberFormatProvider;
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
-import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.spi.CalendarDataProvider;
@@ -161,7 +161,7 @@
     @Override
     public Locale[] getAvailableLocales() {
         if (availableLocales == null) {
-            Set<Locale> avail = new HashSet<>();
+            List<Locale> avail = new ArrayList<>();
             for (Class<? extends LocaleServiceProvider> c :
                     LocaleServiceProviderPool.spiClasses) {
                 LocaleServiceProvider lsp = getLocaleServiceProvider(c);
@@ -169,6 +169,7 @@
                     avail.addAll(Arrays.asList(lsp.getAvailableLocales()));
                 }
             }
+            availableLocales = avail.toArray(new Locale[0]);
         }
 
         // assuming caller won't mutate the array.
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/CalendarDataUtility.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/CalendarDataUtility.java	Thu Oct 22 21:44:39 2015 -0700
@@ -50,7 +50,7 @@
         LocaleServiceProviderPool pool =
                 LocaleServiceProviderPool.getPool(CalendarDataProvider.class);
         Integer value = pool.getLocalizedObject(CalendarWeekParameterGetter.INSTANCE,
-                                                locale, FIRST_DAY_OF_WEEK);
+                                                locale, true, FIRST_DAY_OF_WEEK);
         return (value != null && (value >= SUNDAY && value <= SATURDAY)) ? value : SUNDAY;
     }
 
@@ -58,7 +58,7 @@
         LocaleServiceProviderPool pool =
                 LocaleServiceProviderPool.getPool(CalendarDataProvider.class);
         Integer value = pool.getLocalizedObject(CalendarWeekParameterGetter.INSTANCE,
-                                                locale, MINIMAL_DAYS_IN_FIRST_WEEK);
+                                                locale, true, MINIMAL_DAYS_IN_FIRST_WEEK);
         return (value != null && (value >= 1 && value <= 7)) ? value : 1;
     }
 
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/CalendarProviderImpl.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/CalendarProviderImpl.java	Thu Oct 22 21:44:39 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@
 package sun.util.locale.provider;
 
 import java.util.Calendar;
-import java.util.Calendar.Builder;
 import java.util.Locale;
 import java.util.Set;
 import java.util.TimeZone;
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java	Thu Oct 22 21:44:39 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@
 package sun.util.locale.provider;
 
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
 
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java	Thu Oct 22 21:44:39 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,6 @@
 import java.util.spi.LocaleNameProvider;
 import java.util.spi.LocaleServiceProvider;
 import java.util.spi.TimeZoneNameProvider;
-import sun.util.cldr.CLDRLocaleProviderAdapter;
 import sun.util.spi.CalendarProvider;
 
 /**
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java	Thu Oct 22 21:44:39 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,8 +71,8 @@
     private final LocaleProviderAdapter.Type type;
 
     // Resource cache
-    private ConcurrentMap<String, ResourceReference> cache = new ConcurrentHashMap<>();
-    private ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
+    private final ConcurrentMap<String, ResourceReference> cache = new ConcurrentHashMap<>();
+    private final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
 
     // cache key prefixes
     private static final String BREAK_ITERATOR_INFO = "BII.";
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java	Thu Oct 22 21:44:39 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,20 +53,13 @@
      * A Map that holds singleton instances of this class.  Each instance holds a
      * set of provider implementations of a particular locale sensitive service.
      */
-    private static ConcurrentMap<Class<? extends LocaleServiceProvider>, LocaleServiceProviderPool> poolOfPools =
-        new ConcurrentHashMap<>();
-
-    /**
-     * A Map containing locale service providers that implement the
-     * specified provider SPI, keyed by a LocaleProviderAdapter.Type
-     */
-    private ConcurrentMap<LocaleProviderAdapter.Type, LocaleServiceProvider> providers =
+    private static final ConcurrentMap<Class<? extends LocaleServiceProvider>, LocaleServiceProviderPool> poolOfPools =
         new ConcurrentHashMap<>();
 
     /**
      * A Map that retains Locale->provider mapping
      */
-    private ConcurrentMap<Locale, List<LocaleProviderAdapter.Type>> providersCache =
+    private final ConcurrentMap<Locale, List<LocaleServiceProvider>> providersCache =
         new ConcurrentHashMap<>();
 
     /**
@@ -78,7 +71,7 @@
     /**
      * Provider class
      */
-    private Class<? extends LocaleServiceProvider> providerClass;
+    private final Class<? extends LocaleServiceProvider> providerClass;
 
     /**
      * Array of all Locale Sensitive SPI classes.
@@ -126,16 +119,6 @@
      */
     private LocaleServiceProviderPool (final Class<? extends LocaleServiceProvider> c) {
         providerClass = c;
-
-        for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
-            LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
-            if (lda != null) {
-                LocaleServiceProvider provider = lda.getLocaleServiceProvider(c);
-                if (provider != null) {
-                    providers.putIfAbsent(type, provider);
-                }
-            }
-        }
     }
 
     static void config(Class<? extends Object> caller, String message) {
@@ -208,10 +191,16 @@
     private synchronized Set<Locale> getAvailableLocaleSet() {
         if (availableLocales == null) {
             availableLocales = new HashSet<>();
-            for (LocaleServiceProvider lsp : providers.values()) {
-                Locale[] locales = lsp.getAvailableLocales();
-                for (Locale locale: locales) {
-                    availableLocales.add(getLookupLocale(locale));
+            for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
+                LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
+                if (lda != null) {
+                    LocaleServiceProvider lsp = lda.getLocaleServiceProvider(providerClass);
+                    if (lsp != null) {
+                        Locale[] locales = lsp.getAvailableLocales();
+                        for (Locale locale: locales) {
+                            availableLocales.add(getLookupLocale(locale));
+                        }
+                    }
                 }
             }
         }
@@ -220,17 +209,6 @@
     }
 
     /**
-     * Returns whether any provider for this locale sensitive
-     * service is available or not, excluding JRE/CLDR's one.
-     *
-     * @return true if any provider (other than JRE/CLDR) is available
-     */
-    boolean hasProviders() {
-        return providers.size() != 1 ||
-               providers.get(LocaleProviderAdapter.defaultLocaleProviderAdapter) == null;
-    }
-
-    /**
      * Returns the provider's localized object for the specified
      * locale.
      *
@@ -264,6 +242,26 @@
         return getLocalizedObjectImpl(getter, locale, false, key, params);
     }
 
+    /**
+     * Returns the provider's localized name for the specified
+     * locale.
+     *
+     * @param getter an object on which getObject() method
+     *     is called to obtain the provider's instance.
+     * @param locale the given locale that is used as the starting one
+     * @param isObjectProvider flag designating object provder or not
+     * @param key the key string for name providers
+     * @param params provider specific parameters
+     * @return provider's instance, or null.
+     */
+    public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter,
+                                     Locale locale,
+                                     Boolean isObjectProvider,
+                                     String key,
+                                     Object... params) {
+        return getLocalizedObjectImpl(getter, locale, isObjectProvider, key, params);
+    }
+
     @SuppressWarnings("unchecked")
     private <P extends LocaleServiceProvider, S> S getLocalizedObjectImpl(LocalizedObjectGetter<P, S> getter,
                                      Locale locale,
@@ -274,30 +272,19 @@
             throw new NullPointerException();
         }
 
-        // Check whether JRE/CLDR is the sole locale data provider or not,
-        // and directly call it if it is.
-        if (!hasProviders()) {
-            return getter.getObject((P)providers.get(LocaleProviderAdapter.defaultLocaleProviderAdapter),
-                                    locale, key, params);
-        }
-
         List<Locale> lookupLocales = getLookupLocales(locale);
 
-        Set<Locale> available = getAvailableLocaleSet();
         for (Locale current : lookupLocales) {
-            if (available.contains(current)) {
-                S providersObj;
+            S providersObj;
 
-                for (LocaleProviderAdapter.Type type: findProviders(current)) {
-                    LocaleServiceProvider lsp = providers.get(type);
-                    providersObj = getter.getObject((P)lsp, locale, key, params);
-                    if (providersObj != null) {
-                        return providersObj;
-                    } else if (isObjectProvider) {
-                        config(LocaleServiceProviderPool.class,
-                            "A locale sensitive service provider returned null for a localized objects,  which should not happen.  provider: "
-                                + lsp + " locale: " + locale);
-                    }
+            for (LocaleServiceProvider lsp: findProviders(current, isObjectProvider)) {
+                providersObj = getter.getObject((P)lsp, locale, key, params);
+                if (providersObj != null) {
+                    return providersObj;
+                } else if (isObjectProvider) {
+                    config(LocaleServiceProviderPool.class,
+                        "A locale sensitive service provider returned null for a localized objects,  which should not happen.  provider: "
+                            + lsp + " locale: " + locale);
                 }
             }
         }
@@ -313,31 +300,36 @@
      * @param locale the given locale
      * @return the list of locale data adapter types
      */
-    private List<LocaleProviderAdapter.Type> findProviders(Locale locale) {
-        List<LocaleProviderAdapter.Type> providersList = providersCache.get(locale);
+    private List<LocaleServiceProvider> findProviders(Locale locale, boolean isObjectProvider) {
+        List<LocaleServiceProvider> providersList = providersCache.get(locale);
         if (providersList == null) {
             for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
-                LocaleServiceProvider lsp = providers.get(type);
-                if (lsp != null) {
-                    if (lsp.isSupportedLocale(locale)) {
-                        if (providersList == null) {
-                            providersList = new ArrayList<>(2);
+                LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
+                if (lda != null) {
+                    LocaleServiceProvider lsp = lda.getLocaleServiceProvider(providerClass);
+                    if (lsp != null) {
+                        if (lsp.isSupportedLocale(locale)) {
+                            if (providersList == null) {
+                                providersList = new ArrayList<>(2);
+                            }
+                            providersList.add(lsp);
+                            if (isObjectProvider) {
+                                break;
+                            }
                         }
-                        providersList.add(type);
-
                     }
                 }
             }
             if (providersList == null) {
                 providersList = NULL_LIST;
             }
-            List<LocaleProviderAdapter.Type> val = providersCache.putIfAbsent(locale, providersList);
+            List<LocaleServiceProvider> val = providersCache.putIfAbsent(locale, providersList);
             if (val != null) {
                 providersList = val;
             }
         }
-            return providersList;
-        }
+        return providersList;
+    }
 
     /**
      * Returns a list of candidate locales for service look up.
@@ -392,7 +384,7 @@
      * A dummy locale service provider list that indicates there is no
      * provider available
      */
-    private static List<LocaleProviderAdapter.Type> NULL_LIST =
+    private static final List<LocaleServiceProvider> NULL_LIST =
         Collections.emptyList();
 
     /**
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java	Thu Oct 22 21:44:39 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -133,7 +133,7 @@
      */
     static class BreakIteratorProviderDelegate extends BreakIteratorProvider
                                         implements Delegate<BreakIteratorProvider> {
-        private ConcurrentMap<Locale, BreakIteratorProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, BreakIteratorProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(BreakIteratorProvider impl) {
@@ -188,7 +188,7 @@
     }
 
     static class CollatorProviderDelegate extends CollatorProvider implements Delegate<CollatorProvider> {
-        private ConcurrentMap<Locale, CollatorProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, CollatorProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(CollatorProvider impl) {
@@ -222,7 +222,7 @@
 
     static class DateFormatProviderDelegate extends DateFormatProvider
                                      implements Delegate<DateFormatProvider> {
-        private ConcurrentMap<Locale, DateFormatProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, DateFormatProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(DateFormatProvider impl) {
@@ -270,7 +270,7 @@
 
     static class DateFormatSymbolsProviderDelegate extends DateFormatSymbolsProvider
                                             implements Delegate<DateFormatSymbolsProvider> {
-        private ConcurrentMap<Locale, DateFormatSymbolsProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, DateFormatSymbolsProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(DateFormatSymbolsProvider impl) {
@@ -304,7 +304,7 @@
 
     static class DecimalFormatSymbolsProviderDelegate extends DecimalFormatSymbolsProvider
                                                implements Delegate<DecimalFormatSymbolsProvider> {
-        private ConcurrentMap<Locale, DecimalFormatSymbolsProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, DecimalFormatSymbolsProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(DecimalFormatSymbolsProvider impl) {
@@ -338,7 +338,7 @@
 
     static class NumberFormatProviderDelegate extends NumberFormatProvider
                                        implements Delegate<NumberFormatProvider> {
-        private ConcurrentMap<Locale, NumberFormatProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, NumberFormatProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(NumberFormatProvider impl) {
@@ -393,7 +393,7 @@
 
     static class CalendarDataProviderDelegate extends CalendarDataProvider
                                        implements Delegate<CalendarDataProvider> {
-        private ConcurrentMap<Locale, CalendarDataProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, CalendarDataProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(CalendarDataProvider impl) {
@@ -434,7 +434,7 @@
 
     static class CalendarNameProviderDelegate extends CalendarNameProvider
                                        implements Delegate<CalendarNameProvider> {
-        private ConcurrentMap<Locale, CalendarNameProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, CalendarNameProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(CalendarNameProvider impl) {
@@ -479,7 +479,7 @@
 
     static class CurrencyNameProviderDelegate extends CurrencyNameProvider
                                        implements Delegate<CurrencyNameProvider> {
-        private ConcurrentMap<Locale, CurrencyNameProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, CurrencyNameProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(CurrencyNameProvider impl) {
@@ -520,7 +520,7 @@
 
     static class LocaleNameProviderDelegate extends LocaleNameProvider
                                      implements Delegate<LocaleNameProvider> {
-        private ConcurrentMap<Locale, LocaleNameProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, LocaleNameProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(LocaleNameProvider impl) {
@@ -575,7 +575,7 @@
 
     static class TimeZoneNameProviderDelegate extends TimeZoneNameProvider
                                      implements Delegate<TimeZoneNameProvider> {
-        private ConcurrentMap<Locale, TimeZoneNameProvider> map = new ConcurrentHashMap<>();
+        private final ConcurrentMap<Locale, TimeZoneNameProvider> map = new ConcurrentHashMap<>();
 
         @Override
         public void addImpl(TimeZoneNameProvider impl) {
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java	Thu Oct 22 21:44:39 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,7 @@
     /**
      * cache to hold time zone localized strings. Keyed by Locale
      */
-    private static ConcurrentHashMap<Locale, SoftReference<String[][]>> cachedZoneData =
+    private static final ConcurrentHashMap<Locale, SoftReference<String[][]>> cachedZoneData =
         new ConcurrentHashMap<>();
 
     /**
--- a/jdk/src/java.base/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Thu Oct 22 21:41:57 2015 -0700
+++ b/jdk/src/java.base/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Thu Oct 22 21:44:39 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,6 @@
 import java.util.Currency;
 import java.util.HashSet;
 import java.util.Locale;
-import java.util.Map;
 import java.util.ResourceBundle.Control;
 import java.util.Set;
 import java.util.TimeZone;
@@ -100,10 +99,10 @@
     };
 
     // Caches
-    private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatCache = new ConcurrentHashMap<>();
-    private static ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsCache = new ConcurrentHashMap<>();
-    private static ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatCache = new ConcurrentHashMap<>();
-    private static ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsCache = new ConcurrentHashMap<>();
+    private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> dateFormatCache = new ConcurrentHashMap<>();
+    private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> dateFormatSymbolsCache = new ConcurrentHashMap<>();
+    private static final ConcurrentMap<Locale, SoftReference<AtomicReferenceArray<String>>> numberFormatCache = new ConcurrentHashMap<>();
+    private static final ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsCache = new ConcurrentHashMap<>();
 
     private static final Set<Locale> supportedLocaleSet;
     private static final String nativeDisplayLanguage;