You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by Johan Compagner <jc...@j-com.nl> on 2000/12/20 14:09:46 UTC
(Property)MessageResources proposed changes.
Hi,
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.
Re: (Property)MessageResources proposed changes.
Posted by Johan Compagner <jc...@j-com.nl>.
Hi,
One side note
The java-doc for the MessageResources.localeKey(Locale) isn't updated correctly:
<
* <strong>NOTE</strong> - The locale key for the default Locale in our
* environment is a zero length String.
>
this section can be deleted now i believe.
I also see that you implemented another feature that i proposed to you in my email about
multiple datasources or one datasouce that hangles multiple different connections.
I see youre choice was multiple datasources.
Will there be a warning when a user add's 2 datasources but both don't have the key attribute specified?
And the lookup time is better in my implementation of the PropertyMessageResources class.
Especially the first time a locale is used and multiple messages are asked
Because i don't use that much synchronized locks and all the messages are directly stored under
the localeString that was asked (not one by one)
And why not have one PropertyMessageResources class that can handle both property resources:
.properties or .class?
johan
----- Original Message -----
From: "Craig R. McClanahan" <Cr...@eng.sun.com>
To: <st...@jakarta.apache.org>
Sent: Wednesday, December 27, 2000 3:04 AM
Subject: Re: (Property)MessageResources proposed changes.
> Johan,
>
> Thanks for the patches!
>
> As you will see from the commit messages, I've added the first two patches you
> proposed, so the new
> MessageResources implementation should work correctly for your default Locale
> now.
>
> I did not implement the third suggested change -- it seems to me that a better
> strategy if you want to use
> ResourceBundle to load the message strings from would be to create your own
> ResourceBundleMessageResources and
> ResourceBundleMessageResourcesFactory classes. You could subclass the existing
> ones for PropertyMessageResources
> if most of the logic was the same, or start from the base classes again if you
> wanted to do something different
> about multiple keys per message -- in my experience, I think it's worth the
> extra space cost of multiple keys for
> the lookup time on repetitive accesses to the same messages.
>
> Craig
>
>
> Johan Compagner wrote:
>
> > Hi,
> >
> > 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.
> >
> > --------------------------------------------------------------------------------
> > Name: MyPropertyMessageResources.java
> > MyPropertyMessageResources.java Type: unspecified type (application/octet-stream)
> > Encoding: 7bit
> >
> > Name: PropertyMessageResources.java
> > PropertyMessageResources.java Type: unspecified type (application/octet-stream)
> > Encoding: quoted-printable
> >
> > Name: MessageResources.java
> > MessageResources.java Type: unspecified type (application/octet-stream)
> > Encoding: quoted-printable
>
Re: (Property)MessageResources proposed changes.
Posted by "Craig R. McClanahan" <Cr...@eng.sun.com>.
Johan,
Thanks for the patches!
As you will see from the commit messages, I've added the first two patches you
proposed, so the new
MessageResources implementation should work correctly for your default Locale
now.
I did not implement the third suggested change -- it seems to me that a better
strategy if you want to use
ResourceBundle to load the message strings from would be to create your own
ResourceBundleMessageResources and
ResourceBundleMessageResourcesFactory classes. You could subclass the existing
ones for PropertyMessageResources
if most of the logic was the same, or start from the base classes again if you
wanted to do something different
about multiple keys per message -- in my experience, I think it's worth the
extra space cost of multiple keys for
the lookup time on repetitive accesses to the same messages.
Craig
Johan Compagner wrote:
> Hi,
>
> 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.
>
> --------------------------------------------------------------------------------
> Name: MyPropertyMessageResources.java
> MyPropertyMessageResources.java Type: unspecified type (application/octet-stream)
> Encoding: 7bit
>
> Name: PropertyMessageResources.java
> PropertyMessageResources.java Type: unspecified type (application/octet-stream)
> Encoding: quoted-printable
>
> Name: MessageResources.java
> MessageResources.java Type: unspecified type (application/octet-stream)
> Encoding: quoted-printable