/*
 * 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
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.util.locale.provider;

import java.io.File;
import java.security.AccessController;
import java.security.PrivilegedAction;
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.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.spi.CalendarDataProvider;
import java.util.spi.CalendarNameProvider;
import java.util.spi.CurrencyNameProvider;
import java.util.spi.LocaleNameProvider;
import java.util.spi.LocaleServiceProvider;
import java.util.spi.TimeZoneNameProvider;
import sun.util.resources.LocaleData;
import sun.util.spi.CalendarProvider;

LocaleProviderAdapter implementation for the legacy JRE locale data.
Author:Naoto Sato, Masayoshi Okutsu
/** * LocaleProviderAdapter implementation for the legacy JRE locale data. * * @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<>(); // LocaleData specific to this LocaleProviderAdapter. private volatile LocaleData localeData;
Returns the type of this LocaleProviderAdapter
/** * Returns the type of this LocaleProviderAdapter */
@Override public LocaleProviderAdapter.Type getAdapterType() { return Type.JRE; }
Getter method for Locale Service Providers
/** * Getter method for Locale Service Providers */
@Override @SuppressWarnings("unchecked") public <P extends LocaleServiceProvider> P getLocaleServiceProvider(Class<P> c) { switch (c.getSimpleName()) { case "BreakIteratorProvider": return (P) getBreakIteratorProvider(); case "CollatorProvider": return (P) getCollatorProvider(); case "DateFormatProvider": return (P) getDateFormatProvider(); case "DateFormatSymbolsProvider": return (P) getDateFormatSymbolsProvider(); case "DecimalFormatSymbolsProvider": return (P) getDecimalFormatSymbolsProvider(); case "NumberFormatProvider": return (P) getNumberFormatProvider(); case "CurrencyNameProvider": return (P) getCurrencyNameProvider(); case "LocaleNameProvider": return (P) getLocaleNameProvider(); case "TimeZoneNameProvider": return (P) getTimeZoneNameProvider(); case "CalendarDataProvider": return (P) getCalendarDataProvider(); case "CalendarNameProvider": return (P) getCalendarNameProvider(); case "CalendarProvider": return (P) getCalendarProvider(); default: throw new InternalError("should not come down here"); } } private volatile BreakIteratorProvider breakIteratorProvider = null; private volatile CollatorProvider collatorProvider = null; private volatile DateFormatProvider dateFormatProvider = null; private volatile DateFormatSymbolsProvider dateFormatSymbolsProvider = null; private volatile DecimalFormatSymbolsProvider decimalFormatSymbolsProvider = null; private volatile NumberFormatProvider numberFormatProvider = null; private volatile CurrencyNameProvider currencyNameProvider = null; private volatile LocaleNameProvider localeNameProvider = null; private volatile TimeZoneNameProvider timeZoneNameProvider = null; private volatile CalendarDataProvider calendarDataProvider = null; private volatile CalendarNameProvider calendarNameProvider = null; private volatile CalendarProvider calendarProvider = null; /* * Getter methods for java.text.spi.* providers */ @Override public BreakIteratorProvider getBreakIteratorProvider() { if (breakIteratorProvider == null) { BreakIteratorProvider provider = new BreakIteratorProviderImpl(getAdapterType(), getLanguageTagSet("FormatData")); synchronized (this) { if (breakIteratorProvider == null) { breakIteratorProvider = provider; } } } return breakIteratorProvider; } @Override public CollatorProvider getCollatorProvider() { if (collatorProvider == null) { CollatorProvider provider = new CollatorProviderImpl(getAdapterType(), getLanguageTagSet("CollationData")); synchronized (this) { if (collatorProvider == null) { collatorProvider = provider; } } } return collatorProvider; } @Override public DateFormatProvider getDateFormatProvider() { if (dateFormatProvider == null) { DateFormatProvider provider = new DateFormatProviderImpl(getAdapterType(), getLanguageTagSet("FormatData")); synchronized (this) { if (dateFormatProvider == null) { dateFormatProvider = provider; } } } return dateFormatProvider; } @Override public DateFormatSymbolsProvider getDateFormatSymbolsProvider() { if (dateFormatSymbolsProvider == null) { DateFormatSymbolsProvider provider = new DateFormatSymbolsProviderImpl(getAdapterType(), getLanguageTagSet("FormatData")); synchronized (this) { if (dateFormatSymbolsProvider == null) { dateFormatSymbolsProvider = provider; } } } return dateFormatSymbolsProvider; } @Override public DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() { if (decimalFormatSymbolsProvider == null) { DecimalFormatSymbolsProvider provider = new DecimalFormatSymbolsProviderImpl(getAdapterType(), getLanguageTagSet("FormatData")); synchronized (this) { if (decimalFormatSymbolsProvider == null) { decimalFormatSymbolsProvider = provider; } } } return decimalFormatSymbolsProvider; } @Override public NumberFormatProvider getNumberFormatProvider() { if (numberFormatProvider == null) { NumberFormatProvider provider = new NumberFormatProviderImpl(getAdapterType(), getLanguageTagSet("FormatData")); synchronized (this) { if (numberFormatProvider == null) { numberFormatProvider = provider; } } } return numberFormatProvider; }
Getter methods for java.util.spi.* providers
/** * Getter methods for java.util.spi.* providers */
@Override public CurrencyNameProvider getCurrencyNameProvider() { if (currencyNameProvider == null) { CurrencyNameProvider provider = new CurrencyNameProviderImpl(getAdapterType(), getLanguageTagSet("CurrencyNames")); synchronized (this) { if (currencyNameProvider == null) { currencyNameProvider = provider; } } } return currencyNameProvider; } @Override public LocaleNameProvider getLocaleNameProvider() { if (localeNameProvider == null) { LocaleNameProvider provider = new LocaleNameProviderImpl(getAdapterType(), getLanguageTagSet("LocaleNames")); synchronized (this) { if (localeNameProvider == null) { localeNameProvider = provider; } } } return localeNameProvider; } @Override public TimeZoneNameProvider getTimeZoneNameProvider() { if (timeZoneNameProvider == null) { TimeZoneNameProvider provider = new TimeZoneNameProviderImpl(getAdapterType(), getLanguageTagSet("TimeZoneNames")); synchronized (this) { if (timeZoneNameProvider == null) { timeZoneNameProvider = provider; } } } return timeZoneNameProvider; } @Override public CalendarDataProvider getCalendarDataProvider() { if (calendarDataProvider == null) { CalendarDataProvider provider; provider = new CalendarDataProviderImpl(getAdapterType(), getLanguageTagSet("CalendarData")); synchronized (this) { if (calendarDataProvider == null) { calendarDataProvider = provider; } } } return calendarDataProvider; } @Override public CalendarNameProvider getCalendarNameProvider() { if (calendarNameProvider == null) { CalendarNameProvider provider; provider = new CalendarNameProviderImpl(getAdapterType(), getLanguageTagSet("FormatData")); synchronized (this) { if (calendarNameProvider == null) { calendarNameProvider = provider; } } } return calendarNameProvider; }
Getter methods for sun.util.spi.* providers
/** * Getter methods for sun.util.spi.* providers */
@Override public CalendarProvider getCalendarProvider() { if (calendarProvider == null) { CalendarProvider provider = new CalendarProviderImpl(getAdapterType(), getLanguageTagSet("CalendarData")); synchronized (this) { if (calendarProvider == null) { calendarProvider = provider; } } } return calendarProvider; } @Override public LocaleResources getLocaleResources(Locale locale) { LocaleResources lr = localeResourcesMap.get(locale); if (lr == null) { lr = new LocaleResources(this, locale); LocaleResources lrc = localeResourcesMap.putIfAbsent(locale, lr); if (lrc != null) { lr = lrc; } } return lr; } // ResourceBundleBasedAdapter method implementation @Override public LocaleData getLocaleData() { if (localeData == null) { synchronized (this) { if (localeData == null) { localeData = new LocaleData(getAdapterType()); } } } return localeData; }
Returns a list of the installed locales. Currently, this simply returns the list of locales for which a sun.text.resources.FormatData bundle exists. This bundle family happens to be the one with the broadest locale coverage in the JRE.
/** * Returns a list of the installed locales. Currently, this simply returns * the list of locales for which a sun.text.resources.FormatData bundle * exists. This bundle family happens to be the one with the broadest * locale coverage in the JRE. */
@Override public Locale[] getAvailableLocales() { return AvailableJRELocales.localeList.clone(); } public Set<String> getLanguageTagSet(String category) { Set<String> tagset = langtagSets.get(category); if (tagset == null) { tagset = createLanguageTagSet(category); Set<String> ts = langtagSets.putIfAbsent(category, tagset); if (ts != null) { tagset = ts; } } return tagset; } protected Set<String> createLanguageTagSet(String category) { String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString(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; } break; } tagset.add(token); } return tagset; }
Lazy load available locales.
/** * Lazy load available locales. */
private static class AvailableJRELocales { private static final Locale[] localeList = createAvailableLocales(); private AvailableJRELocales() { } } private static Locale[] createAvailableLocales() { /* * Gets the locale string list from LocaleDataMetaInfo class and then * contructs the Locale array and a set of language tags based on the * locale string returned above. */ String supportedLocaleString = LocaleDataMetaInfo.getSupportedLocaleString("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)); } int length = localeStringTokenizer.countTokens(); Locale[] locales = new Locale[length + 1]; locales[0] = Locale.ROOT; for (int i = 1; i <= length; i++) { String currentToken = localeStringTokenizer.nextToken(); switch (currentToken) { case "ja-JP-JP": locales[i] = JRELocaleConstants.JA_JP_JP; break; case "no-NO-NY": locales[i] = JRELocaleConstants.NO_NO_NY; break; case "th-TH-TH": locales[i] = JRELocaleConstants.TH_TH_TH; break; default: 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; } }