Author: markt
Date: Wed Jan 8 14:10:38 2014
New Revision: 1556539
URL: http://svn.apache.org/r1556539
Log:
Fix issue with Manager app and other apps that use i18n in the UI when a
request that specifies an Accept-Language of English ahead of French, Spanish
or Japanese.
Port all the other improvements to the StringManager from trunk as well
Modified:
tomcat/tc6.0.x/trunk/STATUS.txt
tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/res/StringManager.java
tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
Modified: tomcat/tc6.0.x/trunk/STATUS.txt
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=1556539&r1=1556538&r2=1556539&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/STATUS.txt (original)
+++ tomcat/tc6.0.x/trunk/STATUS.txt Wed Jan 8 14:10:38 2014
@@ -32,15 +32,6 @@ PATCHES PROPOSED TO BACKPORT:
[ New proposals should be added at the end of the list ]
-* Fix issue with Manager app and other apps that use i18n in the UI when a
- request that specifies an Accept-Language of English ahead of French, Spanish
- or Japanese.
- Port all the other improvements to the StringManager from trunk as well
- http://people.apache.org/~markt/patches/2013-12-17-webapp-locale-tc6.patch
- +1: markt, remm, jboynes
- +1: kkolinko (a typo in changelog: s/associated/associate/)
- -1:
-
* Add support for limiting the size of chunk extensions when using chunked
encoding.
http://people.apache.org/~markt/patches/2013-12-17-chunk-extensions-tc6-v2.patch
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/res/StringManager.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/res/StringManager.java?rev=1556539&r1=1556538&r2=1556539&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/res/StringManager.java
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/res/StringManager.java Wed
Jan 8 14:10:38 2014
@@ -18,8 +18,11 @@
package org.apache.tomcat.util.res;
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;
@@ -52,12 +55,16 @@ import java.util.ResourceBundle;
public class StringManager {
+ // Locale.ROOT isn't available until Java 6
+ private static final Locale LOCALE_ROOT = new Locale("", "", "");
+
+ 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
@@ -67,22 +74,36 @@ public class StringManager {
*
* @param packageName Name of package to create StringManager for.
*/
-
- private StringManager(String packageName) {
- this( packageName, Locale.getDefault() );
- }
-
- private StringManager(String packageName, Locale loc) {
+ private StringManager(String packageName, Locale locale) {
String bundleName = packageName + ".LocalStrings";
- bundle = ResourceBundle.getBundle(bundleName, loc);
+ ResourceBundle bnd = null;
+ try {
+ 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 ) {
+ try {
+ bnd = ResourceBundle.getBundle(bundleName, locale, cl);
+ } catch(MissingResourceException ex2) {
+ // Ignore
+ }
+ }
+ }
+ bundle = bnd;
// Get the actual locale, which may be different from the requested one
- locale = bundle.getLocale();
- }
-
- private StringManager(ResourceBundle bundle )
- {
- this.bundle=bundle;
- locale = bundle.getLocale();
+ if (bundle != null) {
+ Locale bundleLocale = bundle.getLocale();
+ if (bundleLocale.equals(LOCALE_ROOT)) {
+ this.locale = Locale.ENGLISH;
+ } else {
+ this.locale = bundleLocale;
+ }
+ } else {
+ this.locale = null;
+ }
}
/**
@@ -94,7 +115,6 @@ public class StringManager {
bundle or null if not found.
@throws IllegalArgumentException if <i>key</i> is null.
*/
-
public String getString(String key) {
if(key == null){
String msg = "key may not have a null value";
@@ -104,11 +124,15 @@ public class StringManager {
String str = null;
- try{
- str = bundle.getString(key);
- }catch(MissingResourceException mre){
+ try {
+ // 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)
@@ -130,7 +154,6 @@ public class StringManager {
* @param key
* @param args
*/
-
public String getString(final String key, final Object... args) {
String value = getString(key);
if (value == null) {
@@ -142,11 +165,19 @@ public class StringManager {
return mf.format(args, new StringBuffer(), null).toString();
}
+ /**
+ * Identify the Locale this StringManager is associated with
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
// --------------------------------------------------------------
// STATIC SUPPORT METHODS
// --------------------------------------------------------------
- private static Hashtable managers = new Hashtable();
+ 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
@@ -155,42 +186,87 @@ public class StringManager {
*
* @param packageName The package name
*/
- public synchronized static StringManager getManager(String packageName) {
- StringManager mgr = (StringManager)managers.get(packageName);
- if (mgr == null) {
- mgr = new StringManager(packageName);
- managers.put(packageName, mgr);
- }
- return mgr;
+ public static final synchronized StringManager getManager(
+ String packageName) {
+ return getManager(packageName, Locale.getDefault());
+ }
+
+ /**
+ * Get the StringManager for a particular package and Locale. 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
+ */
+ 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, locale);
+ map.put(locale, mgr);
+ }
+ return mgr;
}
/**
- * Get the StringManager for a particular package. If a manager for
- * a package already exists, it will be reused, else a new
- * StringManager will be created and returned.
+ * Retrieve the StringManager for a list of Locales. The first
StringManager
+ * found will be returned.
*
- * @param bundle The resource bundle
+ * @param requestedLocales the list of Locales
+ *
+ * @return the found StringManager or the default StringManager
*/
- public synchronized static StringManager getManager(ResourceBundle bundle)
{
- return new StringManager( bundle );
+ 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);
}
-
+
/**
- * Get the StringManager for a particular package and Locale. If a manager
for
- * a package already exists, it will be reused, else a new
- * StringManager will be created for that Locale and returned.
+ * Always returns null.
*
- * @param packageName The package name
- * @param loc The locale
- */
-
- public synchronized static StringManager getManager(String
packageName,Locale loc) {
- StringManager mgr =
(StringManager)managers.get(packageName+"_"+loc.toString());
- if (mgr == null) {
- mgr = new StringManager(packageName,loc);
- managers.put(packageName+"_"+loc.toString(), mgr);
- }
- return mgr;
+ * @param bundle The resource bundle
+ *
+ * @return Always <code>null</code>
+ *
+ * @deprecated This is unused in Tomcat 6 and will be removed in Tomcat 7
+ */
+ @Deprecated
+ public static final synchronized StringManager getManager(
+ ResourceBundle bundle) {
+ return null;
}
-
}
Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=1556539&r1=1556538&r2=1556539&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Wed Jan 8 14:10:38 2014
@@ -74,6 +74,12 @@
command-line option to change service start wait time from default
of 10 seconds. (schultz)
</fix>
+ <fix>
+ Correctly associate the default resource bundle with the English locale
+ so that requests that specify an Accept-Language of English ahead of
+ French, Spanish or Japanese get the English messages they asked for.
+ (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Coyote">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]