diff --git a/source/java/org/alfresco/web/app/Application.java b/source/java/org/alfresco/web/app/Application.java index 7f8a82da98..a249b87ca6 100644 --- a/source/java/org/alfresco/web/app/Application.java +++ b/source/java/org/alfresco/web/app/Application.java @@ -33,7 +33,6 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.alfresco.config.ConfigService; -import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.importer.ImporterBootstrap; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.web.app.servlet.AuthenticationHelper; @@ -483,14 +482,7 @@ public class Application { locale = Locale.getDefault(); } - bundle = ResourceBundle.getBundle(MESSAGE_BUNDLE, locale); - if (bundle == null) - { - throw new AlfrescoRuntimeException("Unable to load Alfresco messages bundle: " + MESSAGE_BUNDLE); - } - - // apply our wrapper to catch MissingResourceException - bundle = new ResourceBundleWrapper(bundle); + bundle = ResourceBundleWrapper.findSharedResourceBundle(MESSAGE_BUNDLE, locale); session.setAttribute(MESSAGE_BUNDLE, bundle); } @@ -520,14 +512,7 @@ public class Application { locale = Locale.getDefault(); } - bundle = ResourceBundle.getBundle(MESSAGE_BUNDLE, locale); - if (bundle == null) - { - throw new AlfrescoRuntimeException("Unable to load Alfresco messages bundle: " + MESSAGE_BUNDLE); - } - - // apply our wrapper to catch MissingResourceException - bundle = new ResourceBundleWrapper(bundle); + bundle = ResourceBundleWrapper.findSharedResourceBundle(MESSAGE_BUNDLE, locale); session.put(MESSAGE_BUNDLE, bundle); } diff --git a/source/java/org/alfresco/web/app/ResourceBundleWrapper.java b/source/java/org/alfresco/web/app/ResourceBundleWrapper.java index 7bef0b82c9..f4b2c1f0bf 100644 --- a/source/java/org/alfresco/web/app/ResourceBundleWrapper.java +++ b/source/java/org/alfresco/web/app/ResourceBundleWrapper.java @@ -17,28 +17,39 @@ package org.alfresco.web.app; import java.util.Enumeration; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; + +import org.alfresco.error.AlfrescoRuntimeException; import org.apache.log4j.Logger; import org.apache.log4j.Priority; /** * Wrapper around Alfresco Resource Bundle objects. Used to catch and handle missing * resource exception to help identify missing I18N strings in client apps. + *

+ * Also provides a factory method to get/create a shared instance to a named resource + * bundle for a particular locale. * * @author Kevin Roast */ public final class ResourceBundleWrapper extends ResourceBundle { private static Logger logger = Logger.getLogger(ResourceBundleWrapper.class); + private ResourceBundle delegate; + private static Map cache = new HashMap(); + /** * Constructor * * @param bundle The ResourceBundle to route calls too */ - public ResourceBundleWrapper(ResourceBundle bundle) + private ResourceBundleWrapper(ResourceBundle bundle) { this.delegate = bundle; } @@ -68,4 +79,42 @@ public final class ResourceBundleWrapper extends ResourceBundle return "$$" + key + "$$"; } } + + /** + * Factory method to get/create a shared instance to a named resource bundle for a + * particular locale. A static cache of language bundles is used to save memory, as each + * bundle consumes >300K per user and they are read only objects. + * + * @param name Bundle name + * @param locale Locale to retrieve bundle for + * + * @return Shared ResourceBundle instance for specified locale + */ + public static ResourceBundle findSharedResourceBundle(String name, Locale locale) + { + String key = name + '_' + locale; + + ResourceBundle bundle = cache.get(key); + if (bundle == null) + { + // we can safely use a weak synchronization point here - i.e. it doesn't actually matter + // if more than one thread loads and caches the same bundle if a race condition occurs + synchronized (cache) + { + bundle = ResourceBundle.getBundle(name, locale); + if (bundle == null) + { + throw new AlfrescoRuntimeException("Unable to load Alfresco messages bundle: " + name); + } + + // apply our wrapper to catch MissingResourceException + bundle = new ResourceBundleWrapper(bundle); + + // cache the bundle for later use + cache.put(key, bundle); + } + } + + return bundle; + } }