Merged V2.2 to HEAD 8290: Merged V2.1-A to V2.2 8229: AWC-1149: Resource bundles in AMP files

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8323 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2008-02-19 12:52:48 +00:00
parent f45bccdbd8
commit 12656d59b8
5 changed files with 286 additions and 145 deletions

View File

@@ -688,7 +688,7 @@ public class Application
{ {
locale = Locale.getDefault(); locale = Locale.getDefault();
} }
bundle = ResourceBundleWrapper.getResourceBundleWrapper(session.getServletContext()).getResourceBundle(MESSAGE_BUNDLE, locale); bundle = ResourceBundleWrapper.getResourceBundle(session.getServletContext(), MESSAGE_BUNDLE, locale);
session.setAttribute(MESSAGE_BUNDLE, bundle); session.setAttribute(MESSAGE_BUNDLE, bundle);
} }
@@ -719,7 +719,7 @@ public class Application
{ {
locale = Locale.getDefault(); locale = Locale.getDefault();
} }
bundle = ResourceBundleWrapper.getResourceBundleWrapper(FacesContextUtils.getRequiredWebApplicationContext(context).getServletContext()).getResourceBundle(MESSAGE_BUNDLE, locale); bundle = ResourceBundleWrapper.getResourceBundle(FacesContextUtils.getRequiredWebApplicationContext(context).getServletContext(), MESSAGE_BUNDLE, locale);
session.put(MESSAGE_BUNDLE, bundle); session.put(MESSAGE_BUNDLE, bundle);
} }

View File

@@ -0,0 +1,28 @@
/**
*
*/
package org.alfresco.web.app;
import java.util.List;
/**
* Resource bundle bootstrap bean
*
* @author Roy Wetherall
*/
public class ResourceBundleBootstrap
{
/**
* Set the resource bundles to be registered. This should be a list of resource
* bundle base names whose content will be made available to the web client.
*
* @param resourceBundles the resource bundles
*/
public void setResourceBundles(List<String> resourceBundles)
{
for (String resourceBundle : resourceBundles)
{
ResourceBundleWrapper.addResourceBundle(resourceBundle);
}
}
}

View File

@@ -25,7 +25,9 @@
package org.alfresco.web.app; package org.alfresco.web.app;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@@ -52,107 +54,25 @@ import org.springframework.web.context.support.WebApplicationContextUtils;
public final class ResourceBundleWrapper extends ResourceBundle implements Serializable public final class ResourceBundleWrapper extends ResourceBundle implements Serializable
{ {
private static final long serialVersionUID = -3230653664902689948L; private static final long serialVersionUID = -3230653664902689948L;
private static Log logger = LogFactory.getLog(ResourceBundleWrapper.class);
private static Log logger = LogFactory.getLog(ResourceBundleWrapper.class); /** List of custom bundle names */
private static List<String> addedBundleNames = new ArrayList<String>(10);
private String name; /** List of delegate resource bundles */
private Locale locale; transient private List<ResourceBundle> delegates;
transient private ResourceBundle delegate;
transient private ResourceBundle delegateCustom;
private MessageService messageService;
public static final String BEAN_RESOURCE_BUNDLE_WRAPPER = "resourceBundleWrapper";
public static final String BEAN_RESOURCE_MESSAGE_SERVICE = "messageService";
public static final String PATH = "app:company_home/app:dictionary/app:webclient_extension"; public static final String PATH = "app:company_home/app:dictionary/app:webclient_extension";
public ResourceBundleWrapper(MessageService messageService)
{
this.messageService = messageService;
}
// Helper to get the ResourceBundleWrapper instance with access to the repository
public static ResourceBundleWrapper getResourceBundleWrapper(ServletContext context)
{
return (ResourceBundleWrapper)WebApplicationContextUtils.getRequiredWebApplicationContext(context).getBean(
BEAN_RESOURCE_BUNDLE_WRAPPER);
}
/** /**
* Constructor * Constructor
* *
* @param bundle The ResourceBundle to route calls too * @param bundles the resource bundles including the default, custom and any added
* @param customBundle A custom version of bundle to look in if the string is
* not found in bundle
*/ */
private ResourceBundleWrapper(String name, Locale locale) private ResourceBundleWrapper(List<ResourceBundle> bundles)
{ {
this.name = name; this.delegates = bundles;
this.locale = locale;
retreiveBundles();
}
private void retreiveBundles()
{
ResourceBundle bundle = ResourceBundle.getBundle(name, locale);
if (bundle == null)
{
throw new AlfrescoRuntimeException("Unable to load Alfresco messages bundle: " + name);
}
// also look up the custom version of the bundle in the extension package
ResourceBundle customBundle = null;
// first try in the repo otherwise try the classpath
StoreRef storeRef = null;
String path = null;
try
{
String customName = null;
int idx = name.lastIndexOf(".");
if (idx != -1)
{
customName = name.substring(idx+1, name.length());
}
else
{
customName = name;
}
storeRef = Repository.getStoreRef();
// TODO - make path configurable in one place ...
// Note: path here is XPath for selectNodes query
path = PATH + "/cm:" + customName;
customBundle = messageService.getRepoResourceBundle(Repository.getStoreRef(), path, locale);
}
catch (Throwable t)
{
// for now ... ignore the error, cannot be found or read from repo
logger.debug("Custom Web Client properties not found: " + storeRef + path);
}
if (customBundle == null)
{
// classpath
String customName = determineCustomBundleName(name);
try
{
customBundle = ResourceBundle.getBundle(customName, locale);
if (logger.isDebugEnabled())
logger.debug("Located and loaded custom bundle: " + customName);
}
catch (MissingResourceException mre)
{
// ignore the error, just leave custom bundle as null
}
}
this.delegate = bundle;
this.delegateCustom = customBundle;
} }
/** /**
@@ -160,31 +80,20 @@ public final class ResourceBundleWrapper extends ResourceBundle implements Seria
*/ */
public Enumeration<String> getKeys() public Enumeration<String> getKeys()
{ {
if (this.delegate == null) if (this.delegates.size() == 1)
{ {
// restore if the session was [de]serialised - as bundles themselves are not serialised return this.delegates.get(0).getKeys();
retreiveBundles();
}
if (this.delegateCustom == null)
{
return this.delegate.getKeys();
} }
else else
{ {
// get existing keys
Enumeration<String> keys = this.delegate.getKeys();
Enumeration<String> customKeys = this.delegateCustom.getKeys();
// combine keys into one list
Vector<String> allKeys = new Vector<String>(100, 2); Vector<String> allKeys = new Vector<String>(100, 2);
while (keys.hasMoreElements()) for (ResourceBundle delegate : this.delegates)
{ {
allKeys.add(keys.nextElement()); Enumeration<String> keys = delegate.getKeys();
} while(keys.hasMoreElements() == true)
while (customKeys.hasMoreElements()) {
{ allKeys.add(keys.nextElement());
allKeys.add(customKeys.nextElement()); }
} }
return allKeys.elements(); return allKeys.elements();
@@ -198,40 +107,32 @@ public final class ResourceBundleWrapper extends ResourceBundle implements Seria
{ {
Object result = null; Object result = null;
if (this.delegate == null) for (ResourceBundle delegate : this.delegates)
{ {
// restore if the session was [de]serialised - as bundles themselves are not serialised
retreiveBundles();
}
try
{
result = this.delegate.getObject(key);
}
catch (MissingResourceException err)
{
// if the string wasn't found in the normal bundle
// try the custom bundle if there is one
try try
{ {
if (this.delegateCustom != null) // Try and lookup the key from the resource bundle
result = delegate.getObject(key);
if (result != null)
{ {
result = this.delegateCustom.getObject(key); break;
} }
} }
catch (MissingResourceException mre) catch (MissingResourceException mre)
{ {
// don't do anything here, dealt with below // ignore as this means the key was not present
} }
}
// if the key was not found return a default string // if the key was not found return a default string
if (result == null) if (result == null)
{
if (logger.isWarnEnabled() == true)
{ {
if (logger.isWarnEnabled()) logger.warn("Failed to find I18N message string key: " + key);
logger.warn("Failed to find I18N message string key: " + key);
result = "$$" + key + "$$";
} }
result = "$$" + key + "$$";
} }
return result; return result;
@@ -240,15 +141,123 @@ public final class ResourceBundleWrapper extends ResourceBundle implements Seria
/** /**
* Factory method to get a named wrapped resource bundle for a particular locale. * Factory method to get a named wrapped resource bundle for a particular locale.
* *
* @param name Bundle name * @param servletContext ServletContext
* @param locale Locale to retrieve bundle for * @param name Bundle name
* @param locale Locale to retrieve bundle for
* *
* @return Wrapped ResourceBundle instance for specified locale * @return Wrapped ResourceBundle instance for specified locale
*/ */
public static ResourceBundle getResourceBundle(String name, Locale locale) public static ResourceBundle getResourceBundle(ServletContext servletContext, String name, Locale locale)
{ {
// apply our wrapper to catch MissingResourceException List<ResourceBundle> bundles = new ArrayList<ResourceBundle>(ResourceBundleWrapper.addedBundleNames.size() + 2);
return new ResourceBundleWrapper(name, locale);
// Load the default bundle
ResourceBundle bundle = ResourceBundle.getBundle(name, locale);
if (bundle == null)
{
throw new AlfrescoRuntimeException("Unable to load Alfresco messages bundle: " + name);
}
bundles.add(bundle);
// also look up the custom version of the bundle in the extension package
ResourceBundle customBundle = null;
if (servletContext != null)
{
MessageService messageService = (MessageService)WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).getBean(BEAN_RESOURCE_MESSAGE_SERVICE);
// first try in the repo otherwise try the classpath
StoreRef storeRef = null;
String path = null;
try
{
String customName = null;
int idx = name.lastIndexOf(".");
if (idx != -1)
{
customName = name.substring(idx+1, name.length());
}
else
{
customName = name;
}
storeRef = Repository.getStoreRef();
// TODO - make path configurable in one place ...
// Note: path here is XPath for selectNodes query
path = PATH + "/cm:" + customName;
customBundle = messageService.getRepoResourceBundle(Repository.getStoreRef(), path, locale);
}
catch (Throwable t)
{
// for now ... ignore the error, cannot be found or read from repo
logger.debug("Custom Web Client properties not found: " + storeRef + path);
}
}
if (customBundle == null)
{
// also look up the custom version of the bundle in the extension package
String customName = determineCustomBundleName(name);
try
{
customBundle = ResourceBundle.getBundle(customName, locale);
if (logger.isDebugEnabled()== true)
{
logger.debug("Located and loaded custom bundle: " + customName);
}
}
catch (MissingResourceException mre)
{
// ignore the error, just leave custom bundle as null
}
}
// Add the custom bundle to the list
if (customBundle != null)
{
bundles.add(customBundle);
}
// Add any additional bundles
for (String bundleName : ResourceBundleWrapper.addedBundleNames)
{
try
{
// Load the added bundle
ResourceBundle addedBundle = ResourceBundle.getBundle(bundleName, locale);
bundles.add(addedBundle);
if (logger.isDebugEnabled())
{
logger.debug("Located and loaded added bundle: " + bundleName);
}
}
catch (MissingResourceException mre)
{
// ignore the error, just log some debug info
if (logger.isDebugEnabled())
{
logger.debug("Unable to load added bundle: " + bundleName);
}
}
}
// apply our wrapper to catch MissingResourceException
return new ResourceBundleWrapper(bundles);
}
/**
* Adds a resource bundle to the collection of custom bundles available
*
* @param name the name of the resource bundle
*/
public static void addResourceBundle(String name)
{
ResourceBundleWrapper.addedBundleNames.add(name);
} }
/** /**

View File

@@ -0,0 +1,101 @@
/**
*
*/
package org.alfresco.web.app;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import junit.framework.TestCase;
/**
* Unit test for resource bundle wrapper
*
* @author Roy Wetherall
*/
public class ResourceBundleWrapperTest extends TestCase
{
private static final String BUNDLE_NAME = "org.alfresco.web.app.resourceBundleWrapperTest";
private static final String KEY_1 = "test_key_one";
private static final String KEY_2 = "test_key_two";
private static final String MSG_1 = "Test Key One";
private static final String MSG_2 = "Test Key Two";
/**
* Test adding the bundles
*/
public void testAddingBundles()
{
// Check that the string's are not added to the bundle
ResourceBundle before = ResourceBundleWrapper.getResourceBundle(null, "alfresco.messages.webclient", Locale.US);
Enumeration<String> keys = before.getKeys();
assertFalse(containsValue(keys, KEY_1));
assertFalse(containsValue(keys, KEY_2));
try
{
before.getString(KEY_1);
fail("Not expecting the key to be there");
}
catch (Throwable exception){};
try
{
before.getString(KEY_2);
fail("Not expecting the key to be there");
}
catch (Throwable exception){};
// Add an additional resource bundle
ResourceBundleWrapper.addResourceBundle(BUNDLE_NAME);
// Check that the string's are now added to the bundle
ResourceBundle after = ResourceBundleWrapper.getResourceBundle(null, "alfresco.messages.webclient", Locale.US);
Enumeration<String> keys2 = after.getKeys();
assertTrue(containsValue(keys2, KEY_1));
assertEquals(after.getString(KEY_1), MSG_1);
assertEquals(after.getString(KEY_2), MSG_2);
}
/**
* Test the bootstrap bean
*/
public void testBootstrap()
{
// Use the bootstrap bean to add the bundles
List<String> bundles = new ArrayList<String>(1);
bundles.add(BUNDLE_NAME);
ResourceBundleBootstrap bootstrap = new ResourceBundleBootstrap();
bootstrap.setResourceBundles(bundles);
// Check that the string's are now added to the bundle
ResourceBundle after = ResourceBundleWrapper.getResourceBundle(null, "alfresco.messages.webclient", Locale.US);
Enumeration<String> keys2 = after.getKeys();
assertTrue(containsValue(keys2, KEY_1));
assertTrue(containsValue(keys2, KEY_2));
assertEquals(after.getString(KEY_1), MSG_1);
assertEquals(after.getString(KEY_2), MSG_2);
}
/**
* Check whether the list contains the values
*
* @param values list of values to check
* @param value value to look for
* @return boolean true if value contained, false otherwise
*/
private boolean containsValue(Enumeration<String> values, String value)
{
boolean result = false;
while (values.hasMoreElements() == true)
{
if (values.nextElement().equals(value) == true)
{
result = true;
break;
}
}
return result;
}
}

View File

@@ -0,0 +1,3 @@
test_key_one=Test Key One
test_key_two=Test Key Two
test_key_three=Test Key Three