This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 7.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 661f583a14dd509e39d084dc50c7c94ffc7993fd Author: Mark Thomas <ma...@apache.org> AuthorDate: Fri Nov 8 22:10:46 2019 +0000 Align with 8.5.x/9.0.x --- .../apache/catalina/tribes/util/StringManager.java | 177 +++++++++++++++++---- 1 file changed, 145 insertions(+), 32 deletions(-) diff --git a/java/org/apache/catalina/tribes/util/StringManager.java b/java/org/apache/catalina/tribes/util/StringManager.java index 2204245..53caf03 100644 --- a/java/org/apache/catalina/tribes/util/StringManager.java +++ b/java/org/apache/catalina/tribes/util/StringManager.java @@ -18,11 +18,15 @@ package org.apache.catalina.tribes.util; import java.text.MessageFormat; +import java.util.Enumeration; import java.util.Hashtable; +import java.util.LinkedHashMap; import java.util.Locale; +import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; + /** * An internationalization / localization helper class which reduces * the bother of handling ResourceBundles and takes care of the @@ -49,11 +53,14 @@ import java.util.ResourceBundle; */ public class StringManager { + private static int LOCALE_CACHE_SIZE = 10; + /** * The ResourceBundle for this StringManager. */ - private ResourceBundle bundle; - private Locale locale; + private final ResourceBundle bundle; + private final Locale locale; + /** * Creates a new StringManager for a given package. This is a @@ -63,53 +70,67 @@ public class StringManager { * * @param packageName Name of package to create StringManager for. */ - private StringManager(String packageName) { + private StringManager(String packageName, Locale locale) { String bundleName = packageName + ".LocalStrings"; + ResourceBundle bnd = null; try { - bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); - } catch( MissingResourceException ex ) { + bnd = ResourceBundle.getBundle(bundleName, locale); + } catch (MissingResourceException ex) { // Try from the current loader (that's the case for trusted apps) // Should only be required if using a TC5 style classloader structure // where common != shared != server ClassLoader cl = Thread.currentThread().getContextClassLoader(); - if( cl != null ) { + if (cl != null) { try { - bundle = ResourceBundle.getBundle( - bundleName, Locale.getDefault(), cl); - } catch(MissingResourceException ex2) { + bnd = ResourceBundle.getBundle(bundleName, locale, cl); + } catch (MissingResourceException ex2) { // Ignore } } } + bundle = bnd; // Get the actual locale, which may be different from the requested one if (bundle != null) { - locale = bundle.getLocale(); + Locale bundleLocale = bundle.getLocale(); + if (bundleLocale.equals(Locale.ROOT)) { + this.locale = Locale.ENGLISH; + } else { + this.locale = bundleLocale; + } + } else { + this.locale = null; } } - /** - Get a string from the underlying resource bundle or return - null if the String is not found. - @param key to desired resource String - @return resource String matching <i>key</i> from underlying - bundle or null if not found. - @throws IllegalArgumentException if <i>key</i> is null. + /** + * Get a string from the underlying resource bundle or return null if the + * String is not found. + * + * @param key to desired resource String + * + * @return resource String matching <i>key</i> from underlying bundle or + * null if not found. + * + * @throws IllegalArgumentException if <i>key</i> is null */ public String getString(String key) { - if(key == null){ + if (key == null){ String msg = "key may not have a null value"; - throw new IllegalArgumentException(msg); } String str = null; try { - str = bundle.getString(key); - } catch(MissingResourceException mre) { + // Avoid NPE if bundle is null and treat it like an MRE + if (bundle != null) { + str = bundle.getString(key); + } + } catch (MissingResourceException mre) { //bad: shouldn't mask an exception the following way: - // str = "[cannot find message associated with key '" + key + "' due to " + mre + "]"; + // str = "[cannot find message associated with key '" + key + + // "' due to " + mre + "]"; // because it hides the fact that the String was missing // from the calling code. //good: could just throw the exception (or wrap it in another) @@ -124,12 +145,15 @@ public class StringManager { return str; } + /** * Get a string from the underlying resource bundle and format * it with the given set of arguments. * - * @param key - * @param args + * @param key The key for the required message + * @param args The values to insert into the message + * + * @return The requested string formatted with the provided arguments */ public String getString(final String key, final Object... args) { String value = getString(key); @@ -142,27 +166,116 @@ public class StringManager { return mf.format(args, new StringBuffer(), null).toString(); } + + /** + * Identify the Locale this StringManager is associated with + * + * @return The Locale associated with this instance + */ + public Locale getLocale() { + return locale; + } + + // -------------------------------------------------------------- // STATIC SUPPORT METHODS // -------------------------------------------------------------- - private static Hashtable<String, StringManager> managers = - new Hashtable<String, StringManager>(); + private static final Map<String, Map<Locale,StringManager>> managers = + new Hashtable<String, Map<Locale, StringManager>>(); + /** - * Get the StringManager for a particular package. If a manager for - * a package already exists, it will be reused, else a new + * The StringManager will be returned for the package in which the class is + * located. If a manager for that package already exists, it will be reused, + * else a new StringManager will be created and returned. + * + * @param clazz The class for which to retrieve the StringManager + * + * @return The StringManager for the given class. + */ + public static final StringManager getManager(Class<?> clazz) { + return getManager(clazz.getPackage().getName()); + } + + + /** + * If a manager for a package already exists, it will be reused, else a new * StringManager will be created and returned. * * @param packageName The package name + * + * @return The StringManager for the given package. + */ + public static final StringManager getManager(String packageName) { + return getManager(packageName, Locale.getDefault()); + } + + + /** + * If a manager for a package/Locale combination already exists, it will be + * reused, else a new StringManager will be created and returned. + * + * @param packageName The package name + * @param locale The Locale + * + * @return The StringManager for a particular package and Locale */ - public static final synchronized StringManager getManager(String packageName) { - StringManager mgr = managers.get(packageName); + public static final synchronized StringManager getManager( + String packageName, Locale locale) { + + Map<Locale,StringManager> map = managers.get(packageName); + if (map == null) { + /* + * Don't want the HashMap to be expanded beyond LOCALE_CACHE_SIZE. + * Expansion occurs when size() exceeds capacity. Therefore keep + * size at or below capacity. + * removeEldestEntry() executes after insertion therefore the test + * for removal needs to use one less than the maximum desired size + * + */ + map = new LinkedHashMap<Locale,StringManager>(LOCALE_CACHE_SIZE, 1, true) { + private static final long serialVersionUID = 1L; + @Override + protected boolean removeEldestEntry( + Map.Entry<Locale,StringManager> eldest) { + if (size() > (LOCALE_CACHE_SIZE - 1)) { + return true; + } + return false; + } + }; + managers.put(packageName, map); + } + + StringManager mgr = map.get(locale); if (mgr == null) { - mgr = new StringManager(packageName); - managers.put(packageName, mgr); + mgr = new StringManager(packageName, locale); + map.put(locale, mgr); } return mgr; } + + /** + * Retrieve the StringManager for a list of Locales. The first StringManager + * found will be returned. + * + * @param packageName The package for which the StringManager is required + * @param requestedLocales the list of Locales + * + * @return the found StringManager or the default StringManager + */ + public static StringManager getManager(String packageName, + Enumeration<Locale> requestedLocales) { + while (requestedLocales.hasMoreElements()) { + Locale locale = requestedLocales.nextElement(); + StringManager result = getManager(packageName, locale); + if (result.getLocale().equals(locale)) { + return result; + } + } + // Return the default + return getManager(packageName); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org