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

Print this page
rev 10528 : 8038436: Re-examine the mechanism to determine available localedata and cldrdata
Reviewed-by:

@@ -23,22 +23,23 @@
  * questions.
  */
 
 package sun.util.locale.provider;
 
-import java.io.File;
 import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.text.spi.BreakIteratorProvider;
 import java.text.spi.CollatorProvider;
 import java.text.spi.DateFormatProvider;
 import java.text.spi.DateFormatSymbolsProvider;
 import java.text.spi.DecimalFormatSymbolsProvider;
 import java.text.spi.NumberFormatProvider;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Locale;
+import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.spi.CalendarDataProvider;

@@ -56,12 +57,10 @@
  * @author Naoto Sato
  * @author Masayoshi Okutsu
  */
 public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements ResourceBundleBasedAdapter {
 
-    private static final String LOCALE_DATA_JAR_NAME = "localedata.jar";
-
     private final ConcurrentMap<String, Set<String>> langtagSets
         = new ConcurrentHashMap<>();
 
     private final ConcurrentMap<Locale, LocaleResources> localeResourcesMap
         = new ConcurrentHashMap<>();

@@ -132,12 +131,11 @@
      * Getter methods for java.text.spi.* providers
      */
     @Override
     public BreakIteratorProvider getBreakIteratorProvider() {
         if (breakIteratorProvider == null) {
-            BreakIteratorProvider provider = new BreakIteratorProviderImpl(getAdapterType(),
-                                                            getLanguageTagSet("FormatData"));
+            BreakIteratorProvider provider = new BreakIteratorProviderImpl(getAdapterType());
             synchronized (this) {
                 if (breakIteratorProvider == null) {
                     breakIteratorProvider = provider;
                 }
             }

@@ -146,12 +144,11 @@
     }
 
     @Override
     public CollatorProvider getCollatorProvider() {
         if (collatorProvider == null) {
-            CollatorProvider provider = new CollatorProviderImpl(getAdapterType(),
-                                                getLanguageTagSet("CollationData"));
+            CollatorProvider provider = new CollatorProviderImpl(getAdapterType());
             synchronized (this) {
                 if (collatorProvider == null) {
                     collatorProvider = provider;
                 }
             }

@@ -160,12 +157,11 @@
     }
 
     @Override
     public DateFormatProvider getDateFormatProvider() {
         if (dateFormatProvider == null) {
-            DateFormatProvider provider = new DateFormatProviderImpl(getAdapterType(),
-                                                    getLanguageTagSet("FormatData"));
+            DateFormatProvider provider = new DateFormatProviderImpl(getAdapterType());
             synchronized (this) {
                 if (dateFormatProvider == null) {
                     dateFormatProvider = provider;
                 }
             }

@@ -174,12 +170,11 @@
     }
 
     @Override
     public DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
         if (dateFormatSymbolsProvider == null) {
-            DateFormatSymbolsProvider provider = new DateFormatSymbolsProviderImpl(getAdapterType(),
-                                                                getLanguageTagSet("FormatData"));
+            DateFormatSymbolsProvider provider = new DateFormatSymbolsProviderImpl(getAdapterType());
             synchronized (this) {
                 if (dateFormatSymbolsProvider == null) {
                     dateFormatSymbolsProvider = provider;
                 }
             }

@@ -188,11 +183,11 @@
     }
 
     @Override
     public DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
         if (decimalFormatSymbolsProvider == null) {
-            DecimalFormatSymbolsProvider provider = new DecimalFormatSymbolsProviderImpl(getAdapterType(), getLanguageTagSet("FormatData"));
+            DecimalFormatSymbolsProvider provider = new DecimalFormatSymbolsProviderImpl(getAdapterType());
             synchronized (this) {
                 if (decimalFormatSymbolsProvider == null) {
                     decimalFormatSymbolsProvider = provider;
                 }
             }

@@ -201,12 +196,11 @@
     }
 
     @Override
     public NumberFormatProvider getNumberFormatProvider() {
         if (numberFormatProvider == null) {
-            NumberFormatProvider provider = new NumberFormatProviderImpl(getAdapterType(),
-                                                        getLanguageTagSet("FormatData"));
+            NumberFormatProvider provider = new NumberFormatProviderImpl(getAdapterType());
             synchronized (this) {
                 if (numberFormatProvider == null) {
                     numberFormatProvider = provider;
                 }
             }

@@ -218,12 +212,11 @@
      * Getter methods for java.util.spi.* providers
      */
     @Override
     public CurrencyNameProvider getCurrencyNameProvider() {
         if (currencyNameProvider == null) {
-            CurrencyNameProvider provider = new CurrencyNameProviderImpl(getAdapterType(),
-                                            getLanguageTagSet("CurrencyNames"));
+            CurrencyNameProvider provider = new CurrencyNameProviderImpl(getAdapterType());
             synchronized (this) {
                 if (currencyNameProvider == null) {
                     currencyNameProvider = provider;
                 }
             }

@@ -232,12 +225,11 @@
     }
 
     @Override
     public LocaleNameProvider getLocaleNameProvider() {
         if (localeNameProvider == null) {
-            LocaleNameProvider provider = new LocaleNameProviderImpl(getAdapterType(),
-                                                    getLanguageTagSet("LocaleNames"));
+            LocaleNameProvider provider = new LocaleNameProviderImpl(getAdapterType());
             synchronized (this) {
                 if (localeNameProvider == null) {
                     localeNameProvider = provider;
                 }
             }

@@ -246,12 +238,11 @@
     }
 
     @Override
     public TimeZoneNameProvider getTimeZoneNameProvider() {
         if (timeZoneNameProvider == null) {
-            TimeZoneNameProvider provider = new TimeZoneNameProviderImpl(getAdapterType(),
-                                                    getLanguageTagSet("TimeZoneNames"));
+            TimeZoneNameProvider provider = new TimeZoneNameProviderImpl(getAdapterType());
             synchronized (this) {
                 if (timeZoneNameProvider == null) {
                     timeZoneNameProvider = provider;
                 }
             }

@@ -261,12 +252,11 @@
 
     @Override
     public CalendarDataProvider getCalendarDataProvider() {
         if (calendarDataProvider == null) {
             CalendarDataProvider provider;
-            provider = new CalendarDataProviderImpl(getAdapterType(),
-                                                    getLanguageTagSet("CalendarData"));
+            provider = new CalendarDataProviderImpl(getAdapterType());
             synchronized (this) {
                 if (calendarDataProvider == null) {
                     calendarDataProvider = provider;
                 }
             }

@@ -276,12 +266,11 @@
 
     @Override
     public CalendarNameProvider getCalendarNameProvider() {
         if (calendarNameProvider == null) {
             CalendarNameProvider provider;
-            provider = new CalendarNameProviderImpl(getAdapterType(),
-                                                    getLanguageTagSet("FormatData"));
+            provider = new CalendarNameProviderImpl(getAdapterType());
             synchronized (this) {
                 if (calendarNameProvider == null) {
                     calendarNameProvider = provider;
                 }
             }

@@ -293,12 +282,11 @@
      * Getter methods for sun.util.spi.* providers
      */
     @Override
     public CalendarProvider getCalendarProvider() {
         if (calendarProvider == null) {
-            CalendarProvider provider = new CalendarProviderImpl(getAdapterType(),
-                                                    getLanguageTagSet("CalendarData"));
+            CalendarProvider provider = new CalendarProviderImpl(getAdapterType());
             synchronized (this) {
                 if (calendarProvider == null) {
                     calendarProvider = provider;
                 }
             }

@@ -354,28 +342,58 @@
         }
         return tagset;
     }
 
     protected Set<String> createLanguageTagSet(String category) {
-        String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString(category);
+        String supportedLocaleString = createSupportedLocaleString(category);
         if (supportedLocaleString == null) {
             return Collections.emptySet();
         }
         Set<String> tagset = new HashSet<>();
         StringTokenizer tokens = new StringTokenizer(supportedLocaleString);
         while (tokens.hasMoreTokens()) {
-            String token = tokens.nextToken();
-            if (token.equals("|")) {
-                if (isNonENLangSupported()) {
-                    continue;
+            tagset.add(tokens.nextToken());
+        }
+
+        return tagset;
+    }
+
+    private static String createSupportedLocaleString(String category) {
+        // Directly call English tags, as we know it's in the base module.
+        String supportedLocaleString = JREENLocaleDataMetaInfo.getSupportedLocaleString(category);
+
+        // Use ServiceLoader to dynamically acquire installede locales' tags.
+        try {
+            String nonENTags = AccessController.doPrivileged(new PrivilegedExceptionAction<String>() {
+                @Override
+                public String run() {
+                    String tags = null;
+                    for (LocaleDataMetaInfo ldmi :
+                         ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) {
+                        if (ldmi.getType() == LocaleProviderAdapter.Type.JRE) {
+                            String t = ldmi.availableLanguageTags(category);
+                            if (t != null) {
+                                if (tags == null) {
+                                    tags = t;
+                                } else {
+                                    tags += " " + t;
+                                }
                 }
-                break;
             }
-            tagset.add(token);
         }
+                    return tags;
+                }
+            });
 
-        return tagset;
+            if (nonENTags != null) {
+                supportedLocaleString += " " + nonENTags;
+            }
+        }  catch (Exception e) {
+            // catch any exception, and ignore them as if non-EN locales do not exist.
+        }
+
+        return supportedLocaleString;
     }
 
     /**
      * Lazy load available locales.
      */

@@ -385,31 +403,21 @@
         }
     }
 
     private static Locale[] createAvailableLocales() {
         /*
-         * Gets the locale string list from LocaleDataMetaInfo class and then
+         * Gets the locale string list from LocaleDataMetaInfo classes and then
          * contructs the Locale array and a set of language tags based on the
          * locale string returned above.
          */
-        String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString("AvailableLocales");
+        String supportedLocaleString = createSupportedLocaleString("AvailableLocales");
 
         if (supportedLocaleString.length() == 0) {
             throw new InternalError("No available locales for JRE");
         }
 
-        /*
-         * Look for "|" and construct a new locale string list.
-         */
-        int barIndex = supportedLocaleString.indexOf('|');
-        StringTokenizer localeStringTokenizer;
-        if (isNonENLangSupported()) {
-            localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex)
-                    + supportedLocaleString.substring(barIndex + 1));
-        } else {
-            localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex));
-        }
+        StringTokenizer localeStringTokenizer = new StringTokenizer(supportedLocaleString);
 
         int length = localeStringTokenizer.countTokens();
         Locale[] locales = new Locale[length + 1];
         locales[0] = Locale.ROOT;
         for (int i = 1; i <= length; i++) {

@@ -428,41 +436,6 @@
                     locales[i] = Locale.forLanguageTag(currentToken);
             }
         }
         return locales;
     }
-
-    private static volatile Boolean isNonENSupported = null;
-
-    /*
-     * Returns true if the non EN resources jar file exists in jre
-     * extension directory. @returns true if the jar file is there. Otherwise,
-     * returns false.
-     */
-    private static boolean isNonENLangSupported() {
-        if (isNonENSupported == null) {
-            synchronized (JRELocaleProviderAdapter.class) {
-                if (isNonENSupported == null) {
-                    final String sep = File.separator;
-                    String localeDataJar =
-                            java.security.AccessController.doPrivileged(
-                            new sun.security.action.GetPropertyAction("java.home"))
-                            + sep + "lib" + sep + "ext" + sep + LOCALE_DATA_JAR_NAME;
-
-                    /*
-                     * Peek at the installed extension directory to see if
-                     * localedata.jar is installed or not.
-                     */
-                    final File f = new File(localeDataJar);
-                    isNonENSupported =
-                        AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
-                            @Override
-                            public Boolean run() {
-                                return f.exists();
-                            }
-                        });
-               }
-            }
-        }
-        return isNonENSupported;
-    }
 }