All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lodsve.core.properties.message.DefaultResourceBundleMessageSource Maven / Gradle / Ivy

/*
 * Copyright (C) 2018  Sun.Hao
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */

package lodsve.core.properties.message;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.util.ClassUtils;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

/**
 * 扩展的资源绑定数据源.
 *
 * @author sunhao([email protected])
 * @date 13-4-17 下午9:02
 */
public class DefaultResourceBundleMessageSource extends AbstractMessageSource implements BeanClassLoaderAware {

    private ClassLoader bundleClassLoader;

    private ResourceBundleHolder resourceBundleHolder;

    private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

    /**
     * Cache to hold loaded ResourceBundles.
     * This Map is keyed with the bundle basename, which holds a Map that is
     * keyed with the Locale and in turn holds the ResourceBundle instances.
     * This allows for very efficient hash lookups, significantly faster
     * than the ResourceBundle class's own cache.
     */
    private final Map cachedResourceBundles = new HashMap();

    /**
     * Cache to hold already generated MessageFormats.
     * This Map is keyed with the ResourceBundle, which holds a Map that is
     * keyed with the message code, which in turn holds a Map that is keyed
     * with the Locale and holds the MessageFormat values. This allows for
     * very efficient hash lookups without concatenated keys.
     *
     * @see #getMessageFormat
     */
    private final Map>> cachedBundleMessageFormats =
            new HashMap>>();

    /**
     * Set the ClassLoader to load resource bundles with.
     * 

Default is the containing BeanFactory's * {@link org.springframework.beans.factory.BeanClassLoaderAware bean ClassLoader}, * or the default ClassLoader determined by * {@link org.springframework.util.ClassUtils#getDefaultClassLoader()} * if not running within a BeanFactory. */ public void setBundleClassLoader(ClassLoader classLoader) { this.bundleClassLoader = classLoader; } /** * Return the ClassLoader to load resource bundles with. *

Default is the containing BeanFactory's bean ClassLoader. * * @see #setBundleClassLoader */ protected ClassLoader getBundleClassLoader() { return (this.bundleClassLoader != null ? this.bundleClassLoader : this.beanClassLoader); } @Override public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); } /** * Resolves the given message code as key in the registered resource bundles, * returning the value found in the bundle as-is (without MessageFormat parsing). */ @Override protected String resolveCodeWithoutArguments(String code, Locale locale) { String result = null; ResourceBundle resourceBundle = getResourceBundle(locale); if (resourceBundle != null) { result = getStringOrNull(resourceBundle, code); } return result; } /** * Resolves the given message code as key in the registered resource bundles, * using a cached MessageFormat instance per message code. */ @Override protected MessageFormat resolveCode(String code, Locale locale) { MessageFormat messageFormat = null; ResourceBundle bundle = doGetBundle(locale); if (bundle != null) { messageFormat = getMessageFormat(bundle, code, locale); } return messageFormat; } /** * Return a ResourceBundle for the given basename and code, * fetching already generated MessageFormats from the cache. * * @param locale the Locale to find the ResourceBundle for * @return the resulting ResourceBundle, or null if none * found for the given basename and Locale */ @SuppressWarnings("unchecked") public ResourceBundle getResourceBundle(Locale locale) { synchronized (this.cachedResourceBundles) { ResourceBundle bundle = (ResourceBundle) this.cachedResourceBundles.get(locale); if (bundle != null) { return bundle; } bundle = doGetBundle(locale); if (bundle != null) { this.cachedResourceBundles.put(locale, bundle); } return bundle; } } /** * Obtain the resource bundle for the given Locale. * * @param locale the Locale to look for * @return the corresponding ResourceBundle * @throws java.util.MissingResourceException * if no matching bundle could be found * @see java.util.ResourceBundle#getBundle(String, java.util.Locale, ClassLoader) * @see #getBundleClassLoader() */ protected ResourceBundle doGetBundle(Locale locale) throws MissingResourceException { return resourceBundleHolder.getResourceBundle(locale); } /** * Return a MessageFormat for the given bundle and code, * fetching already generated MessageFormats from the cache. * * @param bundle the ResourceBundle to work on * @param code the message code to retrieve * @param locale the Locale to use to build the MessageFormat * @return the resulting MessageFormat, or null if no message * defined for the given code * @throws java.util.MissingResourceException * if thrown by the ResourceBundle */ protected MessageFormat getMessageFormat(ResourceBundle bundle, String code, Locale locale) throws MissingResourceException { synchronized (this.cachedBundleMessageFormats) { Map> codeMap = this.cachedBundleMessageFormats.get(bundle); Map localeMap = null; if (codeMap != null) { localeMap = codeMap.get(code); if (localeMap != null) { MessageFormat result = localeMap.get(locale); if (result != null) { return result; } } } String msg = getStringOrNull(bundle, code); if (msg != null) { if (codeMap == null) { codeMap = new HashMap<>(16); this.cachedBundleMessageFormats.put(bundle, codeMap); } if (localeMap == null) { localeMap = new HashMap<>(16); codeMap.put(code, localeMap); } MessageFormat result = createMessageFormat(msg, locale); localeMap.put(locale, result); return result; } return null; } } private String getStringOrNull(ResourceBundle bundle, String key) { try { return bundle.getString(key); } catch (MissingResourceException ex) { // Assume key not found // -> do NOT throw the exception to allow for checking parent message source. return null; } } public void setResourceBundleHolder(ResourceBundleHolder resourceBundleHolder) { this.resourceBundleHolder = resourceBundleHolder; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy