Hi,

( i am trying to subscribe to STRUTS-DEV but i don't get a confirmation message so i 
post it first here)

When the new MessageResources class (and its sub) where introduced my app didn't 
work anymore because of the changed behaviour in loading resouces.

I have 2 fixes that i have attached here:

First is the MessageResources.localeKey(Locale) method that is needed by both
PropertyMessageResources that i send in.

this:
    protected String localeKey(Locale locale) {
        if (locale == null)
            return ("");
        else if (locale.equals(defaultLocale))
            return ("");
        else
            return (locale.toString());
    }
is changed to this:
    protected String localeKey(Locale locale) {
        if (locale == null)
            return ("");
        else
            return (locale.toString());
    }

Because when it is the default locale or not that doesn't matter. First it must try to
load the right resources for the default locale.
For example if the default locale is nl_NL then i want it to try to load:
xxx.nl_NL.properties or xxx.nl.properties before it tries to load xxx.properties.
Because maybe now my webapp is on a system there the default locale is nl_NL
but maybe it's also getting deployed on a system with the default locale en_US.
Then suddenly the struts load the wrong properties file for the locale, 
(What must be the xxx.properties file? English or Dutch?)
ResourceBundle it self does also try to load the nl_NL first it doesn't look
if the given locale is the default one or not.

PropertyMessageResources.getMessage(Locale,String) changes:

this piece of code:

 // As a last resort, try the default Locale
 localeKey = localeKey(defaultLocale);
 messageKey = messageKey(localeKey, key);
 loadLocale(localeKey);
 synchronized (messages)
{
  message = (String) messages.get(messageKey);
  if (message != null)
  {
   if (addIt)
    messages.put(originalKey, message);
   return (message);
  }
 }

is changed to this:

 // try the default Locale if current locale isn't default
 if(locale != defaultLocale)
 {
  localeKey = localeKey(defaultLocale);
  messageKey = messageKey(localeKey, key);
  loadLocale(localeKey);
  synchronized (messages)
  {
   message = (String) messages.get(messageKey);
   if (message != null)
   {
    if (addIt)
     messages.put(originalKey, message);
    return (message);
   }
  }
 }

 // last resort: try loading de base
 localeKey = "";
 messageKey = messageKey(localeKey, key);
 loadLocale(localeKey);
 synchronized (messages)
 {
  message = (String) messages.get(messageKey);
  if (message != null)
  {
   if (addIt)
    messages.put(originalKey, message);
   return (message);
  }
 }

So i my last resort isn't trying to get it with the defaultLocale
I test it first (maybe equals should be used in tead of == ) 
so that the loading and the synchronized lock isn't invane.

After that and still the message isn't returned i go to my last resort
and that is loading the base (xxx.properties)

But i thought why implement the exact same behaviour of the ResouceBundle?
So i made my own class.

Here are the 2 methods:
public String getMessage(java.util.Locale locale, String key) {
 if(locale == null) locale = defaultLocale;
 String localeKey = localeKey(locale);
 String messageKey = messageKey(localeKey, key);
 String message = null;
 // first try to load a previous stored resource.
 synchronized (messages) {
  message = (String) messages.get(messageKey);
 }
 // if there was no previous stored resource.
 if(message == null) { 
  // try loading the resources
  loadMessages(locale);
  // try getting it again.
  synchronized (messages)  {
   message = (String) messages.get(messageKey);
  }
 }
 // If still null.
 if(message == null) {
  // Return an appropriate error indication
  if (returnNull)  return (null);
  else return ("???" + messageKey(locale, key) + "???");
 }
 return message;
}

protected void loadMessages(Locale locale) {
 String localeKey = localeKey(locale);
  // Have we already attempted to load messages for this locale?
 synchronized (locales) {
  if (locales.get(localeKey) != null) return;
  locales.put(localeKey, localeKey);
 }

 ResourceBundle bundle = 
java.util.ResourceBundle.getBundle(config,locale,this.getClass().getClassLoader());

 if(bundle != null) {
  synchronized (messages) {
   Enumeration names = bundle.getKeys();
   while (names.hasMoreElements())  {
    String key = (String) names.nextElement();
    messages.put(messageKey(localeKey, key), bundle.getObject(key));
   }
  }
  }
 }

I use the resoucebundle class to get the properties.
This has the following advantages:

1> Not having to implement and maintain the complete reading in code.
2> support for not only resource property files but also resource class files!!
3> No double keys for all the resouces when given locale = nl_NL and the properties 
file = xx_nl.properties

explain 3:
Locale = nl_NL
propertie file = xxx._nl.properties
first messages aren't found for that locale key. (multiply synchronized locks)
then are found for localeKey = "nl"; (and added under the key nl) (multiply 
synchronized locks)
Then struts add's that message also under the originalKey nl_NL (so double stored)
The next time another message is ask for the same locale nl_NL:
all over again (except the loading):
calling loadLocale , synchronized lock, but locales hashmap.lookup has that locale 
loaded so returns
synchronized lock but it isn't found 
changing the localeKey
calling the loadLocale again , synchronized lock, but locales hashmap.lookup has that 
locale loaded so returns
again a synchronized lock and now it is found.
addIt is true so it also adds that messages under the original key (again double)

My implementation:

Fist time:
Synchronized lock, message isn't there.
try's to load it for that locale, synchronized lock and message are loaded under the 
given original key.
synchronized lock message found.
next time another message;
Synchronized lock: message found.










PropertyMessageResources.java

MessageResources.java

MyPropertyMessageResources.java

Reply via email to