alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (LocaleServiceProviderPool.java)

This example Java source code file (LocaleServiceProviderPool.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

allavailablelocales, class, concurrenthashmap, concurrentmap, hashset, list, locale, localeserviceprovider, localeserviceproviderpool, object, set, string, suppresswarnings, threading, threads, util

The LocaleServiceProviderPool.java Java example source code

/*
 * Copyright (c) 2005, 2013, 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.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.IllformedLocaleException;
import java.util.List;
import java.util.Locale;
import java.util.Locale.Builder;
import java.util.ResourceBundle.Control;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.spi.LocaleServiceProvider;
import sun.util.logging.PlatformLogger;

/**
 * An instance of this class holds a set of the third party implementations of a particular
 * locale sensitive service, such as {@link java.util.spi.LocaleNameProvider}.
 *
 * @author Naoto Sato
 * @author Masayoshi Okutsu
 */
public final class LocaleServiceProviderPool {

    /**
     * A Map that holds singleton instances of this class.  Each instance holds a
     * set of provider implementations of a particular locale sensitive service.
     */
    private static ConcurrentMap<Class poolOfPools =
        new ConcurrentHashMap<>();

    /**
     * A Map containing locale service providers that implement the
     * specified provider SPI, keyed by a LocaleProviderAdapter.Type
     */
    private ConcurrentMap<LocaleProviderAdapter.Type, LocaleServiceProvider> providers =
        new ConcurrentHashMap<>();

    /**
     * A Map that retains Locale->provider mapping
     */
    private ConcurrentMap<Locale, List providersCache =
        new ConcurrentHashMap<>();

    /**
     * Available locales for this locale sensitive service.  This also contains
     * JRE's available locales
     */
    private Set<Locale> availableLocales = null;

    /**
     * Provider class
     */
    private Class<? extends LocaleServiceProvider> providerClass;

    /**
     * Array of all Locale Sensitive SPI classes.
     *
     * We know "spiClasses" contains classes that extends LocaleServiceProvider,
     * but generic array creation is not allowed, thus the "unchecked" warning
     * is suppressed here.
     */
    @SuppressWarnings("unchecked")
    static final Class<LocaleServiceProvider>[] spiClasses =
                (Class<LocaleServiceProvider>[]) new Class[] {
        java.text.spi.BreakIteratorProvider.class,
        java.text.spi.CollatorProvider.class,
        java.text.spi.DateFormatProvider.class,
        java.text.spi.DateFormatSymbolsProvider.class,
        java.text.spi.DecimalFormatSymbolsProvider.class,
        java.text.spi.NumberFormatProvider.class,
        java.util.spi.CurrencyNameProvider.class,
        java.util.spi.LocaleNameProvider.class,
        java.util.spi.TimeZoneNameProvider.class,
        java.util.spi.CalendarDataProvider.class
    };

    /**
     * A factory method that returns a singleton instance
     */
    public static LocaleServiceProviderPool getPool(Class<? extends LocaleServiceProvider> providerClass) {
        LocaleServiceProviderPool pool = poolOfPools.get(providerClass);
        if (pool == null) {
            LocaleServiceProviderPool newPool =
                new LocaleServiceProviderPool(providerClass);
            pool = poolOfPools.putIfAbsent(providerClass, newPool);
            if (pool == null) {
                pool = newPool;
            }
        }

        return pool;
    }

    /**
     * The sole constructor.
     *
     * @param c class of the locale sensitive service
     */
    private LocaleServiceProviderPool (final Class<? extends LocaleServiceProvider> c) {
        providerClass = c;

        for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
            LocaleProviderAdapter lda = LocaleProviderAdapter.forType(type);
            if (lda != null) {
                LocaleServiceProvider provider = lda.getLocaleServiceProvider(c);
                if (provider != null) {
                    providers.putIfAbsent(type, provider);
                }
            }
        }
    }

    static void config(Class<? extends Object> caller, String message) {
        PlatformLogger logger = PlatformLogger.getLogger(caller.getCanonicalName());
        logger.config(message);
    }

    /**
     * Lazy loaded set of available locales.
     * Loading all locales is a very long operation.
     */
    private static class AllAvailableLocales {
        /**
         * Available locales for all locale sensitive services.
         * This also contains JRE's available locales
         */
        static final Locale[] allAvailableLocales;

        static {
            Set<Locale> all = new HashSet<>();
            for (Class<? extends LocaleServiceProvider> c : spiClasses) {
                LocaleServiceProviderPool pool =
                    LocaleServiceProviderPool.getPool(c);
                all.addAll(pool.getAvailableLocaleSet());
            }

            allAvailableLocales = all.toArray(new Locale[0]);
        }

        // No instantiation
        private AllAvailableLocales() {
        }
    }

    /**
     * Returns an array of available locales for all the provider classes.
     * This array is a merged array of all the locales that are provided by each
     * provider, including the JRE.
     *
     * @return an array of the available locales for all provider classes
     */
    public static Locale[] getAllAvailableLocales() {
        return AllAvailableLocales.allAvailableLocales.clone();
    }

    /**
     * Returns an array of available locales.  This array is a
     * merged array of all the locales that are provided by each
     * provider, including the JRE.
     *
     * @return an array of the available locales
     */
    public Locale[] getAvailableLocales() {
        Set<Locale> locList = new HashSet<>();
        locList.addAll(getAvailableLocaleSet());
        // Make sure it all contains JRE's locales for compatibility.
        locList.addAll(Arrays.asList(LocaleProviderAdapter.forJRE().getAvailableLocales()));
        Locale[] tmp = new Locale[locList.size()];
        locList.toArray(tmp);
        return tmp;
    }

    /**
     * Returns the union of locale sets that are available from
     * each service provider. This method does NOT return the
     * defensive copy.
     *
     * @return a set of available locales
     */
    private synchronized Set<Locale> getAvailableLocaleSet() {
        if (availableLocales == null) {
            availableLocales = new HashSet<>();
            for (LocaleServiceProvider lsp : providers.values()) {
                Locale[] locales = lsp.getAvailableLocales();
                for (Locale locale: locales) {
                    availableLocales.add(getLookupLocale(locale));
                }
            }
        }

        return availableLocales;
    }

    /**
     * Returns whether any provider for this locale sensitive
     * service is available or not, excluding JRE's one.
     *
     * @return true if any provider (other than JRE) is available
     */
    boolean hasProviders() {
        return providers.size() != 1 ||
               (providers.get(LocaleProviderAdapter.Type.JRE) == null &&
                providers.get(LocaleProviderAdapter.Type.FALLBACK) == null);
    }

    /**
     * Returns the provider's localized object for the specified
     * locale.
     *
     * @param getter an object on which getObject() method
     *     is called to obtain the provider's instance.
     * @param locale the given locale that is used as the starting one
     * @param params provider specific parameters
     * @return provider's instance, or null.
     */
    public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter getter,
                                     Locale locale,
                                     Object... params) {
        return getLocalizedObjectImpl(getter, locale, true, null, params);
    }

    /**
     * Returns the provider's localized name for the specified
     * locale.
     *
     * @param getter an object on which getObject() method
     *     is called to obtain the provider's instance.
     * @param locale the given locale that is used as the starting one
     * @param key the key string for name providers
     * @param params provider specific parameters
     * @return provider's instance, or null.
     */
    public <P extends LocaleServiceProvider, S> S getLocalizedObject(LocalizedObjectGetter getter,
                                     Locale locale,
                                     String key,
                                     Object... params) {
        return getLocalizedObjectImpl(getter, locale, false, key, params);
    }

    @SuppressWarnings("unchecked")
    private <P extends LocaleServiceProvider, S> S getLocalizedObjectImpl(LocalizedObjectGetter getter,
                                     Locale locale,
                                     boolean isObjectProvider,
                                     String key,
                                     Object... params) {
        if (locale == null) {
            throw new NullPointerException();
        }

        // Check whether JRE is the sole locale data provider or not,
        // and directly call it if it is.
        if (!hasProviders()) {
            return getter.getObject((P)providers.get(LocaleProviderAdapter.defaultLocaleProviderAdapter),
                                    locale, key, params);
        }

        List<Locale> lookupLocales = getLookupLocales(locale);

        Set<Locale> available = getAvailableLocaleSet();
        for (Locale current : lookupLocales) {
            if (available.contains(current)) {
                S providersObj;

                for (LocaleProviderAdapter.Type type: findProviders(current)) {
                    LocaleServiceProvider lsp = providers.get(type);
                    providersObj = getter.getObject((P)lsp, locale, key, params);
                    if (providersObj != null) {
                        return providersObj;
                    } else if (isObjectProvider) {
                        config(LocaleServiceProviderPool.class,
                            "A locale sensitive service provider returned null for a localized objects,  which should not happen.  provider: "
                                + lsp + " locale: " + locale);
                    }
                }
            }
        }

        // not found.
        return null;
    }

    /**
     * Returns the list of locale service provider instances that support
     * the specified locale.
     *
     * @param locale the given locale
     * @return the list of locale data adapter types
     */
    private List<LocaleProviderAdapter.Type> findProviders(Locale locale) {
        List<LocaleProviderAdapter.Type> providersList = providersCache.get(locale);
        if (providersList == null) {
            for (LocaleProviderAdapter.Type type : LocaleProviderAdapter.getAdapterPreference()) {
                LocaleServiceProvider lsp = providers.get(type);
                if (lsp != null) {
                    if (lsp.isSupportedLocale(locale)) {
                        if (providersList == null) {
                            providersList = new ArrayList<>(2);
                        }
                        providersList.add(type);

                    }
                }
            }
            if (providersList == null) {
                providersList = NULL_LIST;
            }
            List<LocaleProviderAdapter.Type> val = providersCache.putIfAbsent(locale, providersList);
            if (val != null) {
                providersList = val;
            }
        }
            return providersList;
        }

    /**
     * Returns a list of candidate locales for service look up.
     * @param locale the input locale
     * @return the list of candidate locales for the given locale
     */
    static List<Locale> getLookupLocales(Locale locale) {
        // Note: We currently use the default implementation of
        // ResourceBundle.Control.getCandidateLocales. The result
        // returned by getCandidateLocales are already normalized
        // (no extensions) for service look up.
        List<Locale> lookupLocales = Control.getNoFallbackControl(Control.FORMAT_DEFAULT)
                                            .getCandidateLocales("", locale);
        return lookupLocales;
    }

    /**
     * Returns an instance of Locale used for service look up.
     * The result Locale has no extensions except for ja_JP_JP
     * and th_TH_TH
     *
     * @param locale the locale
     * @return the locale used for service look up
     */
    static Locale getLookupLocale(Locale locale) {
        Locale lookupLocale = locale;
        if (locale.hasExtensions()
                && !locale.equals(JRELocaleConstants.JA_JP_JP)
                && !locale.equals(JRELocaleConstants.TH_TH_TH)) {
            // remove extensions
            Builder locbld = new Builder();
            try {
                locbld.setLocale(locale);
                locbld.clearExtensions();
                lookupLocale = locbld.build();
            } catch (IllformedLocaleException e) {
                // A Locale with non-empty extensions
                // should have well-formed fields except
                // for ja_JP_JP and th_TH_TH. Therefore,
                // it should never enter in this catch clause.
                config(LocaleServiceProviderPool.class,
                       "A locale(" + locale + ") has non-empty extensions, but has illformed fields.");

                // Fallback - script field will be lost.
                lookupLocale = new Locale(locale.getLanguage(), locale.getCountry(), locale.getVariant());
            }
        }
        return lookupLocale;
    }

    /**
     * A dummy locale service provider list that indicates there is no
     * provider available
     */
    private static List<LocaleProviderAdapter.Type> NULL_LIST =
        Collections.emptyList();

    /**
     * An interface to get a localized object for each locale sensitive
     * service class.
     */
    public interface LocalizedObjectGetter<P extends LocaleServiceProvider, S> {
        /**
         * Returns an object from the provider
         *
         * @param lsp the provider
         * @param locale the locale
         * @param key key string to localize, or null if the provider is not
         *     a name provider
         * @param params provider specific params
         * @return localized object from the provider
         */
        public S getObject(P lsp,
                           Locale locale,
                           String key,
                           Object... params);
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java LocaleServiceProviderPool.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.