151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/* 22c87ad3a45cecf9e344487cad1abfdebe79f2c7cNarayan Kamath * Copyright (C) 2014 The Android Open Source Project 351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it 751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as 851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation. Oracle designates this 951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided 1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code. 1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT 1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that 1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code). 1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version 1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation, 2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any 2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions. 2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.util; 2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.AccessController; 3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.PrivilegedActionException; 3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.PrivilegedExceptionAction; 3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.ArrayList; 3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.HashSet; 3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.IllformedLocaleException; 3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.LinkedHashSet; 3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.List; 3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Locale; 3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Locale.Builder; 3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Map; 4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.ResourceBundle.Control; 4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.ServiceLoader; 4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Set; 4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.concurrent.ConcurrentHashMap; 4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.concurrent.ConcurrentMap; 4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.spi.LocaleServiceProvider; 469c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebskiimport libcore.icu.ICU; 4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.util.logging.PlatformLogger; 4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.util.resources.OpenListResourceBundle; 5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/** 5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * An instance of this class holds a set of the third party implementations of a particular 5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * locale sensitive service, such as {@link java.util.spi.LocaleNameProvider}. 5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic final class LocaleServiceProviderPool { 5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * A Map that holds singleton instances of this class. Each instance holds a 6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * set of provider implementations of a particular locale sensitive service. 6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static ConcurrentMap<Class<? extends LocaleServiceProvider>, LocaleServiceProviderPool> poolOfPools = 6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski new ConcurrentHashMap<>(); 6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * A Set containing locale service providers that implement the 6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * specified provider SPI 6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private Set<LocaleServiceProvider> providers = 7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski new LinkedHashSet<LocaleServiceProvider>(); 7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * A Map that retains Locale->provider mapping 7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private Map<Locale, LocaleServiceProvider> providersCache = 7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski new ConcurrentHashMap<Locale, LocaleServiceProvider>(); 7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Available locales for this locale sensitive service. This also contains 8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * JRE's available locales 8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private Set<Locale> availableLocales = null; 8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Available locales within this JRE. Currently this is declared as 8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * static. This could be non-static later, so that they could have 8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * different sets for each locale sensitive services. 8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static volatile List<Locale> availableJRELocales = null; 9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Provider locales for this locale sensitive service. 9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private Set<Locale> providerLocales = null; 9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Special locale for ja_JP with Japanese calendar 9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static Locale locale_ja_JP_JP = new Locale("ja", "JP", "JP"); 10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Special locale for th_TH with Thai numbering system 10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static Locale locale_th_TH_TH = new Locale("th", "TH", "TH"); 10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * A factory method that returns a singleton instance 10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public static LocaleServiceProviderPool getPool(Class<? extends LocaleServiceProvider> providerClass) { 11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski LocaleServiceProviderPool pool = poolOfPools.get(providerClass); 11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (pool == null) { 11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski LocaleServiceProviderPool newPool = 11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski new LocaleServiceProviderPool(providerClass); 11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski pool = poolOfPools.putIfAbsent(providerClass, newPool); 11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (pool == null) { 11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski pool = newPool; 11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return pool; 12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The sole constructor. 12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param c class of the locale sensitive service 12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private LocaleServiceProviderPool (final Class<? extends LocaleServiceProvider> c) { 12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Object run() { 13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (LocaleServiceProvider provider : ServiceLoader.loadInstalled(c)) { 13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski providers.add(provider); 13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski }); 13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (PrivilegedActionException e) { 13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski config(e.toString()); 14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static void config(String message) { 14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski PlatformLogger logger = PlatformLogger.getLogger("sun.util.LocaleServiceProviderPool"); 14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski logger.config(message); 14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Lazy loaded set of available locales. 15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Loading all locales is a very long operation. 15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * We know "providerClasses" contains classes that extends LocaleServiceProvider, 15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * but generic array creation is not allowed, thus the "unchecked" warning 15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * is suppressed here. 15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static class AllAvailableLocales { 15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Available locales for all locale sensitive services. 15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This also contains JRE's available locales 16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski static final Locale[] allAvailableLocales; 16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski static { 16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski @SuppressWarnings("unchecked") 16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Class<LocaleServiceProvider>[] providerClasses = 16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski (Class<LocaleServiceProvider>[]) new Class<?>[] { 16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski java.text.spi.BreakIteratorProvider.class, 16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski java.text.spi.CollatorProvider.class, 16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski java.text.spi.DateFormatProvider.class, 17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski java.text.spi.DateFormatSymbolsProvider.class, 17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski java.text.spi.DecimalFormatSymbolsProvider.class, 17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski java.text.spi.NumberFormatProvider.class, 173983b2c6ff9ea6d35adf7ab6398dccf870b7e180aPiotr Jastrzebski java.util.spi.CurrencyNameProvider.class, 17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski java.util.spi.LocaleNameProvider.class, 1759c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski java.util.spi.TimeZoneNameProvider.class, 1769c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski }; 17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Normalize locales for look up 1799c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski Locale[] allLocales = ICU.getAvailableLocales(); 18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Set<Locale> all = new HashSet<Locale>(allLocales.length); 18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (Locale locale : allLocales) { 18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski all.add(getLookupLocale(locale)); 18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (Class<LocaleServiceProvider> providerClass : providerClasses) { 18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski LocaleServiceProviderPool pool = 18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski LocaleServiceProviderPool.getPool(providerClass); 18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski all.addAll(pool.getProviderLocales()); 18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski allAvailableLocales = all.toArray(new Locale[0]); 19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns an array of available locales for all the provider classes. 19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This array is a merged array of all the locales that are provided by each 19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * provider, including the JRE. 19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return an array of the available locales for all provider classes 20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public static Locale[] getAllAvailableLocales() { 20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return AllAvailableLocales.allAvailableLocales.clone(); 20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns an array of available locales. This array is a 20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * merged array of all the locales that are provided by each 20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * provider, including the JRE. 21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return an array of the available locales 21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public synchronized Locale[] getAvailableLocales() { 21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (availableLocales == null) { 21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski availableLocales = new HashSet<Locale>(getJRELocales()); 21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (hasProviders()) { 21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski availableLocales.addAll(getProviderLocales()); 21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale[] tmp = new Locale[availableLocales.size()]; 22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski availableLocales.toArray(tmp); 22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return tmp; 22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns an array of available locales (already normalized 22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * for service lookup) from providers. 22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Note that this method does not return a defensive copy. 22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return list of the provider locales 23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private synchronized Set<Locale> getProviderLocales() { 23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (providerLocales == null) { 23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski providerLocales = new HashSet<Locale>(); 23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (hasProviders()) { 23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (LocaleServiceProvider lsp : providers) { 23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale[] locales = lsp.getAvailableLocales(); 23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (Locale locale: locales) { 23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski providerLocales.add(getLookupLocale(locale)); 24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return providerLocales; 24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns whether any provider for this locale sensitive 24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * service is available or not. 25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return true if any provider is available 25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public boolean hasProviders() { 25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return !providers.isEmpty(); 25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns an array of available locales (already normalized for 25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * service lookup) supported by the JRE. 26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Note that this method does not return a defensive copy. 26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return list of the available JRE locales 26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private List<Locale> getJRELocales() { 26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (availableJRELocales == null) { 26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski synchronized (LocaleServiceProviderPool.class) { 26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (availableJRELocales == null) { 2689c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski Locale[] allLocales = ICU.getAvailableLocales(); 26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski List<Locale> tmpList = new ArrayList<>(allLocales.length); 27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (Locale locale : allLocales) { 27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski tmpList.add(getLookupLocale(locale)); 27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski availableJRELocales = tmpList; 27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return availableJRELocales; 27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns whether the given locale is supported by the JRE. 28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param locale the locale to test. 28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return true, if the locale is supported by the JRE. false 28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * otherwise. 28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private boolean isJRESupported(Locale locale) { 28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski List<Locale> locales = getJRELocales(); 28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return locales.contains(getLookupLocale(locale)); 29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns the provider's localized object for the specified 29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * locale. 29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param getter an object on which getObject() method 29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * is called to obtain the provider's instance. 29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param locale the given locale that is used as the starting one 29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param params provider specific parameters 30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return provider's instance, or null. 30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public <P, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter, 30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale locale, 30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object... params) { 30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return getLocalizedObjectImpl(getter, locale, true, null, null, null, params); 30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns the provider's localized name for the specified 31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * locale. 31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param getter an object on which getObject() method 31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * is called to obtain the provider's instance. 31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param locale the given locale that is used as the starting one 31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param bundle JRE resource bundle that contains 31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the localized names, or null for localized objects. 31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param key the key string if bundle is supplied, otherwise null. 31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param params provider specific parameters 31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return provider's instance, or null. 32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public <P, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter, 32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale locale, 32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski OpenListResourceBundle bundle, 32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String key, 32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object... params) { 32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return getLocalizedObjectImpl(getter, locale, false, null, bundle, key, params); 32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns the provider's localized name for the specified 33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * locale. 33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param getter an object on which getObject() method 33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * is called to obtain the provider's instance. 33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param locale the given locale that is used as the starting one 33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param bundleKey JRE specific bundle key. e.g., "USD" is for currency 33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski symbol and "usd" is for currency display name in the JRE bundle. 33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param bundle JRE resource bundle that contains 33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the localized names, or null for localized objects. 34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param key the key string if bundle is supplied, otherwise null. 34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param params provider specific parameters 34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return provider's instance, or null. 34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public <P, S> S getLocalizedObject(LocalizedObjectGetter<P, S> getter, 34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale locale, 34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String bundleKey, 34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski OpenListResourceBundle bundle, 34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String key, 34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object... params) { 35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return getLocalizedObjectImpl(getter, locale, false, bundleKey, bundle, key, params); 35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private <P, S> S getLocalizedObjectImpl(LocalizedObjectGetter<P, S> getter, 35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale locale, 35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski boolean isObjectProvider, 35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String bundleKey, 35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski OpenListResourceBundle bundle, 35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String key, 35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object... params) { 36051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (hasProviders()) { 36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (bundleKey == null) { 36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski bundleKey = key; 36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale bundleLocale = (bundle != null ? bundle.getLocale() : null); 36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski List<Locale> lookupLocales = getLookupLocales(locale); 36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski S providersObj = null; 36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // check whether a provider has an implementation that's closer 36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // to the requested locale than the bundle we've found (for 37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // localized names), or Java runtime's supported locale 37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // (for localized objects) 37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Set<Locale> provLoc = getProviderLocales(); 37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int i = 0; i < lookupLocales.size(); i++) { 37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale current = lookupLocales.get(i); 37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (bundleLocale != null) { 37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (current.equals(bundleLocale)) { 37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski break; 37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (isJRESupported(current)) { 38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski break; 38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (provLoc.contains(current)) { 38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // It is safe to assume that findProvider() returns the instance of type P. 38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski @SuppressWarnings("unchecked") 38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski P lsp = (P)findProvider(current); 38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (lsp != null) { 38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski providersObj = getter.getObject(lsp, locale, key, params); 39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (providersObj != null) { 39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return providersObj; 39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else if (isObjectProvider) { 39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski config( 39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski "A locale sensitive service provider returned null for a localized objects, which should not happen. provider: " + lsp + " locale: " + locale); 39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // look up the JRE bundle and its parent chain. Only 40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // providers for localized names are checked hereafter. 40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (bundle != null) { 40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski bundleLocale = bundle.getLocale(); 40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (bundle.handleGetKeys().contains(bundleKey)) { 40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // JRE has it. 40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // It is safe to assume that findProvider() returns the instance of type P. 41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski @SuppressWarnings("unchecked") 41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski P lsp = (P)findProvider(bundleLocale); 41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (lsp != null) { 41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski providersObj = getter.getObject(lsp, locale, key, params); 41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (providersObj != null) { 41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return providersObj; 41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // try parent bundle 42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski bundle = bundle.getParent(); 42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // not found. 42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns a locale service provider instance that supports 43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the specified locale. 43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param locale the given locale 43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return the provider, or null if there is 43551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * no provider available. 43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private LocaleServiceProvider findProvider(Locale locale) { 43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (!hasProviders()) { 43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 44251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (providersCache.containsKey(locale)) { 44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski LocaleServiceProvider provider = providersCache.get(locale); 44451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (provider != NullProvider.INSTANCE) { 44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return provider; 44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (LocaleServiceProvider lsp : providers) { 44951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale[] locales = lsp.getAvailableLocales(); 45051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (Locale available: locales) { 45151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // normalize 45251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski available = getLookupLocale(available); 45351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (locale.equals(available)) { 45451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski LocaleServiceProvider providerInCache = 45551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski providersCache.put(locale, lsp); 45651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return (providerInCache != null ? 45751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski providerInCache : 45851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski lsp); 45951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 46051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 46151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 46251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski providersCache.put(locale, NullProvider.INSTANCE); 46351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 46451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 46551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 46651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 46751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 46851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns a list of candidate locales for service look up. 46951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param locale the input locale 47051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return the list of candiate locales for the given locale 47151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 47251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static List<Locale> getLookupLocales(Locale locale) { 47351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Note: We currently use the default implementation of 47451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // ResourceBundle.Control.getCandidateLocales. The result 47551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // returned by getCandidateLocales are already normalized 47651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // (no extensions) for service look up. 47751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski List<Locale> lookupLocales = new Control(){}.getCandidateLocales("", locale); 47851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return lookupLocales; 47951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 48051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 48151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 48251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns an instance of Locale used for service look up. 48351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The result Locale has no extensions except for ja_JP_JP 48451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * and th_TH_TH 48551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 48651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param locale the locale 48751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return the locale used for service look up 48851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 48951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static Locale getLookupLocale(Locale locale) { 49051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale lookupLocale = locale; 49151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Set<Character> extensions = locale.getExtensionKeys(); 49251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (!extensions.isEmpty() 49351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski && !locale.equals(locale_ja_JP_JP) 49451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski && !locale.equals(locale_th_TH_TH)) { 49551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // remove extensions 49651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Builder locbld = new Builder(); 49751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 49851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski locbld.setLocale(locale); 49951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski locbld.clearExtensions(); 50051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski lookupLocale = locbld.build(); 50151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (IllformedLocaleException e) { 50251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // A Locale with non-empty extensions 50351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // should have well-formed fields except 50451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // for ja_JP_JP and th_TH_TH. Therefore, 50551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // it should never enter in this catch clause. 50651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski config("A locale(" + locale + ") has non-empty extensions, but has illformed fields."); 50751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 50851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Fallback - script field will be lost. 50951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski lookupLocale = new Locale(locale.getLanguage(), locale.getCountry(), locale.getVariant()); 51051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 51151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 51251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return lookupLocale; 51351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 51451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 51551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 51651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * A dummy locale service provider that indicates there is no 51751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * provider available 51851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 51951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static class NullProvider extends LocaleServiceProvider { 52051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static final NullProvider INSTANCE = new NullProvider(); 52151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 52251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Locale[] getAvailableLocales() { 52351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new RuntimeException("Should not get called."); 52451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 52551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 52651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 52751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 52851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * An interface to get a localized object for each locale sensitve 52951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * service class. 53051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 53151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public interface LocalizedObjectGetter<P, S> { 53251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 53351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns an object from the provider 53451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 53551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param lsp the provider 53651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param locale the locale 53751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param key key string to localize, or null if the provider is not 53851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * a name provider 53951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param params provider specific params 54051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return localized object from the provider 54151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 54251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public S getObject(P lsp, 54351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Locale locale, 54451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String key, 54551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object... params); 54651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 54751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski} 548