You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2019/11/08 22:14:15 UTC

[tomcat] 01/02: Align with 8.5.x/9.0.x

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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org