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:


   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 package sun.util.locale.provider;
  27 
  28 import java.io.File;
  29 import java.security.AccessController;
  30 import java.security.PrivilegedAction;

  31 import java.text.spi.BreakIteratorProvider;
  32 import java.text.spi.CollatorProvider;
  33 import java.text.spi.DateFormatProvider;
  34 import java.text.spi.DateFormatSymbolsProvider;
  35 import java.text.spi.DecimalFormatSymbolsProvider;
  36 import java.text.spi.NumberFormatProvider;
  37 import java.util.Collections;
  38 import java.util.HashSet;
  39 import java.util.Locale;

  40 import java.util.Set;
  41 import java.util.StringTokenizer;
  42 import java.util.concurrent.ConcurrentHashMap;
  43 import java.util.concurrent.ConcurrentMap;
  44 import java.util.spi.CalendarDataProvider;
  45 import java.util.spi.CalendarNameProvider;
  46 import java.util.spi.CurrencyNameProvider;
  47 import java.util.spi.LocaleNameProvider;
  48 import java.util.spi.LocaleServiceProvider;
  49 import java.util.spi.TimeZoneNameProvider;
  50 import sun.util.resources.LocaleData;
  51 import sun.util.spi.CalendarProvider;
  52 
  53 /**
  54  * LocaleProviderAdapter implementation for the legacy JRE locale data.
  55  *
  56  * @author Naoto Sato
  57  * @author Masayoshi Okutsu
  58  */
  59 public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements ResourceBundleBasedAdapter {
  60 
  61     private static final String LOCALE_DATA_JAR_NAME = "localedata.jar";
  62 
  63     private final ConcurrentMap<String, Set<String>> langtagSets
  64         = new ConcurrentHashMap<>();
  65 
  66     private final ConcurrentMap<Locale, LocaleResources> localeResourcesMap
  67         = new ConcurrentHashMap<>();
  68 
  69     // LocaleData specific to this LocaleProviderAdapter.
  70     private volatile LocaleData localeData;
  71 
  72     /**
  73      * Returns the type of this LocaleProviderAdapter
  74      */
  75     @Override
  76     public LocaleProviderAdapter.Type getAdapterType() {
  77         return Type.JRE;
  78     }
  79 
  80     /**
  81      * Getter method for Locale Service Providers
  82      */


 117     private volatile CollatorProvider collatorProvider = null;
 118     private volatile DateFormatProvider dateFormatProvider = null;
 119     private volatile DateFormatSymbolsProvider dateFormatSymbolsProvider = null;
 120     private volatile DecimalFormatSymbolsProvider decimalFormatSymbolsProvider = null;
 121     private volatile NumberFormatProvider numberFormatProvider = null;
 122 
 123     private volatile CurrencyNameProvider currencyNameProvider = null;
 124     private volatile LocaleNameProvider localeNameProvider = null;
 125     private volatile TimeZoneNameProvider timeZoneNameProvider = null;
 126     private volatile CalendarDataProvider calendarDataProvider = null;
 127     private volatile CalendarNameProvider calendarNameProvider = null;
 128 
 129     private volatile CalendarProvider calendarProvider = null;
 130 
 131     /*
 132      * Getter methods for java.text.spi.* providers
 133      */
 134     @Override
 135     public BreakIteratorProvider getBreakIteratorProvider() {
 136         if (breakIteratorProvider == null) {
 137             BreakIteratorProvider provider = new BreakIteratorProviderImpl(getAdapterType(),
 138                                                             getLanguageTagSet("FormatData"));
 139             synchronized (this) {
 140                 if (breakIteratorProvider == null) {
 141                     breakIteratorProvider = provider;
 142                 }
 143             }
 144         }
 145         return breakIteratorProvider;
 146     }
 147 
 148     @Override
 149     public CollatorProvider getCollatorProvider() {
 150         if (collatorProvider == null) {
 151             CollatorProvider provider = new CollatorProviderImpl(getAdapterType(),
 152                                                 getLanguageTagSet("CollationData"));
 153             synchronized (this) {
 154                 if (collatorProvider == null) {
 155                     collatorProvider = provider;
 156                 }
 157             }
 158         }
 159         return collatorProvider;
 160     }
 161 
 162     @Override
 163     public DateFormatProvider getDateFormatProvider() {
 164         if (dateFormatProvider == null) {
 165             DateFormatProvider provider = new DateFormatProviderImpl(getAdapterType(),
 166                                                     getLanguageTagSet("FormatData"));
 167             synchronized (this) {
 168                 if (dateFormatProvider == null) {
 169                     dateFormatProvider = provider;
 170                 }
 171             }
 172         }
 173         return dateFormatProvider;
 174     }
 175 
 176     @Override
 177     public DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
 178         if (dateFormatSymbolsProvider == null) {
 179             DateFormatSymbolsProvider provider = new DateFormatSymbolsProviderImpl(getAdapterType(),
 180                                                                 getLanguageTagSet("FormatData"));
 181             synchronized (this) {
 182                 if (dateFormatSymbolsProvider == null) {
 183                     dateFormatSymbolsProvider = provider;
 184                 }
 185             }
 186         }
 187         return dateFormatSymbolsProvider;
 188     }
 189 
 190     @Override
 191     public DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
 192         if (decimalFormatSymbolsProvider == null) {
 193             DecimalFormatSymbolsProvider provider = new DecimalFormatSymbolsProviderImpl(getAdapterType(), getLanguageTagSet("FormatData"));
 194             synchronized (this) {
 195                 if (decimalFormatSymbolsProvider == null) {
 196                     decimalFormatSymbolsProvider = provider;
 197                 }
 198             }
 199         }
 200         return decimalFormatSymbolsProvider;
 201     }
 202 
 203     @Override
 204     public NumberFormatProvider getNumberFormatProvider() {
 205         if (numberFormatProvider == null) {
 206             NumberFormatProvider provider = new NumberFormatProviderImpl(getAdapterType(),
 207                                                         getLanguageTagSet("FormatData"));
 208             synchronized (this) {
 209                 if (numberFormatProvider == null) {
 210                     numberFormatProvider = provider;
 211                 }
 212             }
 213         }
 214         return numberFormatProvider;
 215     }
 216 
 217     /**
 218      * Getter methods for java.util.spi.* providers
 219      */
 220     @Override
 221     public CurrencyNameProvider getCurrencyNameProvider() {
 222         if (currencyNameProvider == null) {
 223             CurrencyNameProvider provider = new CurrencyNameProviderImpl(getAdapterType(),
 224                                             getLanguageTagSet("CurrencyNames"));
 225             synchronized (this) {
 226                 if (currencyNameProvider == null) {
 227                     currencyNameProvider = provider;
 228                 }
 229             }
 230         }
 231         return currencyNameProvider;
 232     }
 233 
 234     @Override
 235     public LocaleNameProvider getLocaleNameProvider() {
 236         if (localeNameProvider == null) {
 237             LocaleNameProvider provider = new LocaleNameProviderImpl(getAdapterType(),
 238                                                     getLanguageTagSet("LocaleNames"));
 239             synchronized (this) {
 240                 if (localeNameProvider == null) {
 241                     localeNameProvider = provider;
 242                 }
 243             }
 244         }
 245         return localeNameProvider;
 246     }
 247 
 248     @Override
 249     public TimeZoneNameProvider getTimeZoneNameProvider() {
 250         if (timeZoneNameProvider == null) {
 251             TimeZoneNameProvider provider = new TimeZoneNameProviderImpl(getAdapterType(),
 252                                                     getLanguageTagSet("TimeZoneNames"));
 253             synchronized (this) {
 254                 if (timeZoneNameProvider == null) {
 255                     timeZoneNameProvider = provider;
 256                 }
 257             }
 258         }
 259         return timeZoneNameProvider;
 260     }
 261 
 262     @Override
 263     public CalendarDataProvider getCalendarDataProvider() {
 264         if (calendarDataProvider == null) {
 265             CalendarDataProvider provider;
 266             provider = new CalendarDataProviderImpl(getAdapterType(),
 267                                                     getLanguageTagSet("CalendarData"));
 268             synchronized (this) {
 269                 if (calendarDataProvider == null) {
 270                     calendarDataProvider = provider;
 271                 }
 272             }
 273         }
 274         return calendarDataProvider;
 275     }
 276 
 277     @Override
 278     public CalendarNameProvider getCalendarNameProvider() {
 279         if (calendarNameProvider == null) {
 280             CalendarNameProvider provider;
 281             provider = new CalendarNameProviderImpl(getAdapterType(),
 282                                                     getLanguageTagSet("FormatData"));
 283             synchronized (this) {
 284                 if (calendarNameProvider == null) {
 285                     calendarNameProvider = provider;
 286                 }
 287             }
 288         }
 289         return calendarNameProvider;
 290     }
 291 
 292     /**
 293      * Getter methods for sun.util.spi.* providers
 294      */
 295     @Override
 296     public CalendarProvider getCalendarProvider() {
 297         if (calendarProvider == null) {
 298             CalendarProvider provider = new CalendarProviderImpl(getAdapterType(),
 299                                                     getLanguageTagSet("CalendarData"));
 300             synchronized (this) {
 301                 if (calendarProvider == null) {
 302                     calendarProvider = provider;
 303                 }
 304             }
 305         }
 306         return calendarProvider;
 307     }
 308 
 309     @Override
 310     public LocaleResources getLocaleResources(Locale locale) {
 311         LocaleResources lr = localeResourcesMap.get(locale);
 312         if (lr == null) {
 313             lr = new LocaleResources(this, locale);
 314             LocaleResources lrc = localeResourcesMap.putIfAbsent(locale, lr);
 315             if (lrc != null) {
 316                 lr = lrc;
 317             }
 318         }
 319         return lr;


 339      * locale coverage in the JRE.
 340      */
 341     @Override
 342     public Locale[] getAvailableLocales() {
 343         return AvailableJRELocales.localeList.clone();
 344     }
 345 
 346     public Set<String> getLanguageTagSet(String category) {
 347         Set<String> tagset = langtagSets.get(category);
 348         if (tagset == null) {
 349             tagset = createLanguageTagSet(category);
 350             Set<String> ts = langtagSets.putIfAbsent(category, tagset);
 351             if (ts != null) {
 352                 tagset = ts;
 353             }
 354         }
 355         return tagset;
 356     }
 357 
 358     protected Set<String> createLanguageTagSet(String category) {
 359         String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString(category);
 360         if (supportedLocaleString == null) {
 361             return Collections.emptySet();
 362         }
 363         Set<String> tagset = new HashSet<>();
 364         StringTokenizer tokens = new StringTokenizer(supportedLocaleString);
 365         while (tokens.hasMoreTokens()) {
 366             String token = tokens.nextToken();
 367             if (token.equals("|")) {
 368                 if (isNonENLangSupported()) {
 369                     continue;






















 370                 }
 371                 break;
 372             }
 373             tagset.add(token);
 374         }



 375 
 376         return tagset;







 377     }
 378 
 379     /**
 380      * Lazy load available locales.
 381      */
 382     private static class AvailableJRELocales {
 383         private static final Locale[] localeList = createAvailableLocales();
 384         private AvailableJRELocales() {
 385         }
 386     }
 387 
 388     private static Locale[] createAvailableLocales() {
 389         /*
 390          * Gets the locale string list from LocaleDataMetaInfo class and then
 391          * contructs the Locale array and a set of language tags based on the
 392          * locale string returned above.
 393          */
 394         String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString("AvailableLocales");
 395 
 396         if (supportedLocaleString.length() == 0) {
 397             throw new InternalError("No available locales for JRE");
 398         }
 399 
 400         /*
 401          * Look for "|" and construct a new locale string list.
 402          */
 403         int barIndex = supportedLocaleString.indexOf('|');
 404         StringTokenizer localeStringTokenizer;
 405         if (isNonENLangSupported()) {
 406             localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex)
 407                     + supportedLocaleString.substring(barIndex + 1));
 408         } else {
 409             localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex));
 410         }
 411 
 412         int length = localeStringTokenizer.countTokens();
 413         Locale[] locales = new Locale[length + 1];
 414         locales[0] = Locale.ROOT;
 415         for (int i = 1; i <= length; i++) {
 416             String currentToken = localeStringTokenizer.nextToken();
 417             switch (currentToken) {
 418                 case "ja-JP-JP":
 419                     locales[i] = JRELocaleConstants.JA_JP_JP;
 420                     break;
 421                 case "no-NO-NY":
 422                     locales[i] = JRELocaleConstants.NO_NO_NY;
 423                     break;
 424                 case "th-TH-TH":
 425                     locales[i] = JRELocaleConstants.TH_TH_TH;
 426                     break;
 427                 default:
 428                     locales[i] = Locale.forLanguageTag(currentToken);
 429             }
 430         }
 431         return locales;
 432     }
 433 
 434     private static volatile Boolean isNonENSupported = null;
 435 
 436     /*
 437      * Returns true if the non EN resources jar file exists in jre
 438      * extension directory. @returns true if the jar file is there. Otherwise,
 439      * returns false.
 440      */
 441     private static boolean isNonENLangSupported() {
 442         if (isNonENSupported == null) {
 443             synchronized (JRELocaleProviderAdapter.class) {
 444                 if (isNonENSupported == null) {
 445                     final String sep = File.separator;
 446                     String localeDataJar =
 447                             java.security.AccessController.doPrivileged(
 448                             new sun.security.action.GetPropertyAction("java.home"))
 449                             + sep + "lib" + sep + "ext" + sep + LOCALE_DATA_JAR_NAME;
 450 
 451                     /*
 452                      * Peek at the installed extension directory to see if
 453                      * localedata.jar is installed or not.
 454                      */
 455                     final File f = new File(localeDataJar);
 456                     isNonENSupported =
 457                         AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
 458                             @Override
 459                             public Boolean run() {
 460                                 return f.exists();
 461                             }
 462                         });
 463                }
 464             }
 465         }
 466         return isNonENSupported;
 467     }
 468 }


   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 package sun.util.locale.provider;
  27 

  28 import java.security.AccessController;
  29 import java.security.PrivilegedActionException;
  30 import java.security.PrivilegedExceptionAction;
  31 import java.text.spi.BreakIteratorProvider;
  32 import java.text.spi.CollatorProvider;
  33 import java.text.spi.DateFormatProvider;
  34 import java.text.spi.DateFormatSymbolsProvider;
  35 import java.text.spi.DecimalFormatSymbolsProvider;
  36 import java.text.spi.NumberFormatProvider;
  37 import java.util.Collections;
  38 import java.util.HashSet;
  39 import java.util.Locale;
  40 import java.util.ServiceLoader;
  41 import java.util.Set;
  42 import java.util.StringTokenizer;
  43 import java.util.concurrent.ConcurrentHashMap;
  44 import java.util.concurrent.ConcurrentMap;
  45 import java.util.spi.CalendarDataProvider;
  46 import java.util.spi.CalendarNameProvider;
  47 import java.util.spi.CurrencyNameProvider;
  48 import java.util.spi.LocaleNameProvider;
  49 import java.util.spi.LocaleServiceProvider;
  50 import java.util.spi.TimeZoneNameProvider;
  51 import sun.util.resources.LocaleData;
  52 import sun.util.spi.CalendarProvider;
  53 
  54 /**
  55  * LocaleProviderAdapter implementation for the legacy JRE locale data.
  56  *
  57  * @author Naoto Sato
  58  * @author Masayoshi Okutsu
  59  */
  60 public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements ResourceBundleBasedAdapter {
  61 


  62     private final ConcurrentMap<String, Set<String>> langtagSets
  63         = new ConcurrentHashMap<>();
  64 
  65     private final ConcurrentMap<Locale, LocaleResources> localeResourcesMap
  66         = new ConcurrentHashMap<>();
  67 
  68     // LocaleData specific to this LocaleProviderAdapter.
  69     private volatile LocaleData localeData;
  70 
  71     /**
  72      * Returns the type of this LocaleProviderAdapter
  73      */
  74     @Override
  75     public LocaleProviderAdapter.Type getAdapterType() {
  76         return Type.JRE;
  77     }
  78 
  79     /**
  80      * Getter method for Locale Service Providers
  81      */


 116     private volatile CollatorProvider collatorProvider = null;
 117     private volatile DateFormatProvider dateFormatProvider = null;
 118     private volatile DateFormatSymbolsProvider dateFormatSymbolsProvider = null;
 119     private volatile DecimalFormatSymbolsProvider decimalFormatSymbolsProvider = null;
 120     private volatile NumberFormatProvider numberFormatProvider = null;
 121 
 122     private volatile CurrencyNameProvider currencyNameProvider = null;
 123     private volatile LocaleNameProvider localeNameProvider = null;
 124     private volatile TimeZoneNameProvider timeZoneNameProvider = null;
 125     private volatile CalendarDataProvider calendarDataProvider = null;
 126     private volatile CalendarNameProvider calendarNameProvider = null;
 127 
 128     private volatile CalendarProvider calendarProvider = null;
 129 
 130     /*
 131      * Getter methods for java.text.spi.* providers
 132      */
 133     @Override
 134     public BreakIteratorProvider getBreakIteratorProvider() {
 135         if (breakIteratorProvider == null) {
 136             BreakIteratorProvider provider = new BreakIteratorProviderImpl(getAdapterType());

 137             synchronized (this) {
 138                 if (breakIteratorProvider == null) {
 139                     breakIteratorProvider = provider;
 140                 }
 141             }
 142         }
 143         return breakIteratorProvider;
 144     }
 145 
 146     @Override
 147     public CollatorProvider getCollatorProvider() {
 148         if (collatorProvider == null) {
 149             CollatorProvider provider = new CollatorProviderImpl(getAdapterType());

 150             synchronized (this) {
 151                 if (collatorProvider == null) {
 152                     collatorProvider = provider;
 153                 }
 154             }
 155         }
 156         return collatorProvider;
 157     }
 158 
 159     @Override
 160     public DateFormatProvider getDateFormatProvider() {
 161         if (dateFormatProvider == null) {
 162             DateFormatProvider provider = new DateFormatProviderImpl(getAdapterType());

 163             synchronized (this) {
 164                 if (dateFormatProvider == null) {
 165                     dateFormatProvider = provider;
 166                 }
 167             }
 168         }
 169         return dateFormatProvider;
 170     }
 171 
 172     @Override
 173     public DateFormatSymbolsProvider getDateFormatSymbolsProvider() {
 174         if (dateFormatSymbolsProvider == null) {
 175             DateFormatSymbolsProvider provider = new DateFormatSymbolsProviderImpl(getAdapterType());

 176             synchronized (this) {
 177                 if (dateFormatSymbolsProvider == null) {
 178                     dateFormatSymbolsProvider = provider;
 179                 }
 180             }
 181         }
 182         return dateFormatSymbolsProvider;
 183     }
 184 
 185     @Override
 186     public DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() {
 187         if (decimalFormatSymbolsProvider == null) {
 188             DecimalFormatSymbolsProvider provider = new DecimalFormatSymbolsProviderImpl(getAdapterType());
 189             synchronized (this) {
 190                 if (decimalFormatSymbolsProvider == null) {
 191                     decimalFormatSymbolsProvider = provider;
 192                 }
 193             }
 194         }
 195         return decimalFormatSymbolsProvider;
 196     }
 197 
 198     @Override
 199     public NumberFormatProvider getNumberFormatProvider() {
 200         if (numberFormatProvider == null) {
 201             NumberFormatProvider provider = new NumberFormatProviderImpl(getAdapterType());

 202             synchronized (this) {
 203                 if (numberFormatProvider == null) {
 204                     numberFormatProvider = provider;
 205                 }
 206             }
 207         }
 208         return numberFormatProvider;
 209     }
 210 
 211     /**
 212      * Getter methods for java.util.spi.* providers
 213      */
 214     @Override
 215     public CurrencyNameProvider getCurrencyNameProvider() {
 216         if (currencyNameProvider == null) {
 217             CurrencyNameProvider provider = new CurrencyNameProviderImpl(getAdapterType());

 218             synchronized (this) {
 219                 if (currencyNameProvider == null) {
 220                     currencyNameProvider = provider;
 221                 }
 222             }
 223         }
 224         return currencyNameProvider;
 225     }
 226 
 227     @Override
 228     public LocaleNameProvider getLocaleNameProvider() {
 229         if (localeNameProvider == null) {
 230             LocaleNameProvider provider = new LocaleNameProviderImpl(getAdapterType());

 231             synchronized (this) {
 232                 if (localeNameProvider == null) {
 233                     localeNameProvider = provider;
 234                 }
 235             }
 236         }
 237         return localeNameProvider;
 238     }
 239 
 240     @Override
 241     public TimeZoneNameProvider getTimeZoneNameProvider() {
 242         if (timeZoneNameProvider == null) {
 243             TimeZoneNameProvider provider = new TimeZoneNameProviderImpl(getAdapterType());

 244             synchronized (this) {
 245                 if (timeZoneNameProvider == null) {
 246                     timeZoneNameProvider = provider;
 247                 }
 248             }
 249         }
 250         return timeZoneNameProvider;
 251     }
 252 
 253     @Override
 254     public CalendarDataProvider getCalendarDataProvider() {
 255         if (calendarDataProvider == null) {
 256             CalendarDataProvider provider;
 257             provider = new CalendarDataProviderImpl(getAdapterType());

 258             synchronized (this) {
 259                 if (calendarDataProvider == null) {
 260                     calendarDataProvider = provider;
 261                 }
 262             }
 263         }
 264         return calendarDataProvider;
 265     }
 266 
 267     @Override
 268     public CalendarNameProvider getCalendarNameProvider() {
 269         if (calendarNameProvider == null) {
 270             CalendarNameProvider provider;
 271             provider = new CalendarNameProviderImpl(getAdapterType());

 272             synchronized (this) {
 273                 if (calendarNameProvider == null) {
 274                     calendarNameProvider = provider;
 275                 }
 276             }
 277         }
 278         return calendarNameProvider;
 279     }
 280 
 281     /**
 282      * Getter methods for sun.util.spi.* providers
 283      */
 284     @Override
 285     public CalendarProvider getCalendarProvider() {
 286         if (calendarProvider == null) {
 287             CalendarProvider provider = new CalendarProviderImpl(getAdapterType());

 288             synchronized (this) {
 289                 if (calendarProvider == null) {
 290                     calendarProvider = provider;
 291                 }
 292             }
 293         }
 294         return calendarProvider;
 295     }
 296 
 297     @Override
 298     public LocaleResources getLocaleResources(Locale locale) {
 299         LocaleResources lr = localeResourcesMap.get(locale);
 300         if (lr == null) {
 301             lr = new LocaleResources(this, locale);
 302             LocaleResources lrc = localeResourcesMap.putIfAbsent(locale, lr);
 303             if (lrc != null) {
 304                 lr = lrc;
 305             }
 306         }
 307         return lr;


 327      * locale coverage in the JRE.
 328      */
 329     @Override
 330     public Locale[] getAvailableLocales() {
 331         return AvailableJRELocales.localeList.clone();
 332     }
 333 
 334     public Set<String> getLanguageTagSet(String category) {
 335         Set<String> tagset = langtagSets.get(category);
 336         if (tagset == null) {
 337             tagset = createLanguageTagSet(category);
 338             Set<String> ts = langtagSets.putIfAbsent(category, tagset);
 339             if (ts != null) {
 340                 tagset = ts;
 341             }
 342         }
 343         return tagset;
 344     }
 345 
 346     protected Set<String> createLanguageTagSet(String category) {
 347         String supportedLocaleString = createSupportedLocaleString(category);
 348         if (supportedLocaleString == null) {
 349             return Collections.emptySet();
 350         }
 351         Set<String> tagset = new HashSet<>();
 352         StringTokenizer tokens = new StringTokenizer(supportedLocaleString);
 353         while (tokens.hasMoreTokens()) {
 354             tagset.add(tokens.nextToken());
 355         }
 356 
 357         return tagset;
 358     }
 359 
 360     private static String createSupportedLocaleString(String category) {
 361         // Directly call English tags, as we know it's in the base module.
 362         String supportedLocaleString = JREENLocaleDataMetaInfo.getSupportedLocaleString(category);
 363 
 364         // Use ServiceLoader to dynamically acquire installede locales' tags.
 365         try {
 366             String nonENTags = AccessController.doPrivileged(new PrivilegedExceptionAction<String>() {
 367                 @Override
 368                 public String run() {
 369                     String tags = null;
 370                     for (LocaleDataMetaInfo ldmi :
 371                          ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) {
 372                         if (ldmi.getType() == LocaleProviderAdapter.Type.JRE) {
 373                             String t = ldmi.availableLanguageTags(category);
 374                             if (t != null) {
 375                                 if (tags == null) {
 376                                     tags = t;
 377                                 } else {
 378                                     tags += " " + t;
 379                                 }
 380                             }

 381                         }

 382                     }
 383                     return tags;
 384                 }
 385             });
 386 
 387             if (nonENTags != null) {
 388                 supportedLocaleString += " " + nonENTags;
 389             }
 390         }  catch (Exception e) {
 391             // catch any exception, and ignore them as if non-EN locales do not exist.
 392         }
 393 
 394         return supportedLocaleString;
 395     }
 396 
 397     /**
 398      * Lazy load available locales.
 399      */
 400     private static class AvailableJRELocales {
 401         private static final Locale[] localeList = createAvailableLocales();
 402         private AvailableJRELocales() {
 403         }
 404     }
 405 
 406     private static Locale[] createAvailableLocales() {
 407         /*
 408          * Gets the locale string list from LocaleDataMetaInfo classes and then
 409          * contructs the Locale array and a set of language tags based on the
 410          * locale string returned above.
 411          */
 412         String supportedLocaleString = createSupportedLocaleString("AvailableLocales");
 413 
 414         if (supportedLocaleString.length() == 0) {
 415             throw new InternalError("No available locales for JRE");
 416         }
 417 
 418         StringTokenizer localeStringTokenizer = new StringTokenizer(supportedLocaleString);










 419 
 420         int length = localeStringTokenizer.countTokens();
 421         Locale[] locales = new Locale[length + 1];
 422         locales[0] = Locale.ROOT;
 423         for (int i = 1; i <= length; i++) {
 424             String currentToken = localeStringTokenizer.nextToken();
 425             switch (currentToken) {
 426                 case "ja-JP-JP":
 427                     locales[i] = JRELocaleConstants.JA_JP_JP;
 428                     break;
 429                 case "no-NO-NY":
 430                     locales[i] = JRELocaleConstants.NO_NO_NY;
 431                     break;
 432                 case "th-TH-TH":
 433                     locales[i] = JRELocaleConstants.TH_TH_TH;
 434                     break;
 435                 default:
 436                     locales[i] = Locale.forLanguageTag(currentToken);
 437             }
 438         }
 439         return locales;
 440     }



































 441 }