Hi
I've implemented two little extensions for the Commons-i18n project (See
the mail below and the attached patch).
I'd like to see your comments on this.
Regards
Armin Häberling
-------- Original Message --------
Subject: Re: Commons - I18N - adding timezones and filtering
Date: Sat, 5 Aug 2006 14:49:56 +0200
From: Oliver Zeigermann <[EMAIL PROTECTED]>
To: Armin Häberling <[EMAIL PROTECTED]>
CC: [EMAIL PROTECTED], "Ralf Hauser" <[EMAIL PROTECTED]>
References: <[EMAIL PROTECTED]>
Hi Armin!
Thanks a lot for your patch. Would you mind resinding your complete
patch to the commons developer mailing list? This way everyone can
have a look at it and see if it fits into commons i18n.
Thanks a lot in advance and cheers
Oliver
2006/8/4, Armin Häberling <[EMAIL PROTECTED]>:
Hi
I've implemented two little extensions for the commons I18N project:
1) Timezone independence:
Currently dates as message arguments are only displayed in the default
time zone returned by the method TimeZone.getDefault().
I extended the MessageManager.getText() so that one can also choose in
which timezone Date arguments can be displayed.
In the current implementation the message template must contain a date
or time format so that the message is formated with the right timezone.
That means the template "it's now {0}" will not work, whereas "it's now
{o,time} will work.
2) filtering of message arguments:
You may want to include String in message arguments that are untrusted
(i.e. user input). But when you display such a message on a html site it
may contain a javascript attack or other nasty things. Otherwise if you
want to store the message in an sql table there are also attacks
possible. Cause of this the arguments should be filtered depending on
later use of the message.
For this I created a new Filter Interface and extended the
LocalizedBundle so that you can attach a specific filter which filters
the message arguments before formating it. I also did two simple
implementations of specific filters.
I've attached a little patch with my changes. Any comments are welcome.
Regards
Armin Häberling
Index: src/java/org/apache/commons/i18n/bundles/ErrorBundle.java
===================================================================
--- src/java/org/apache/commons/i18n/bundles/ErrorBundle.java (revision
428983)
+++ src/java/org/apache/commons/i18n/bundles/ErrorBundle.java (working copy)
@@ -23,6 +23,7 @@
package org.apache.commons.i18n.bundles;
import java.util.Locale;
+import java.util.TimeZone;
import org.apache.commons.i18n.MessageNotFoundException;
@@ -70,8 +71,18 @@
public ErrorBundle(String providerId, String messageId, Object[]
arguments) {
super(providerId, messageId, arguments);
}
-
+
/**
+ * @param locale The locale that is used to find the appropriate localized
text
+ * @param timezone The timezone that is used for displaying dates and
times
+ * @return returns the localized message entry with the key
<code>summary</code>
+ * @throws MessageNotFoundException is thrown if no entry with key
<code>summary</code> could be found in the message bundle identified by the
given message identifier
+ */
+ public String getSummary(Locale locale, TimeZone timezone) throws
MessageNotFoundException {
+ return getEntry(SUMMARY, locale, timezone);
+ }
+
+ /**
* @param locale The locale that is used to find the appropriate localized
text
* @return returns the localized message entry with the key
<code>summary</code>
* @throws MessageNotFoundException is thrown if no entry with key
<code>summary</code> could be found in the message bundle identified by the
given message identifier
@@ -79,8 +90,18 @@
public String getSummary(Locale locale) throws MessageNotFoundException {
return getEntry(SUMMARY, locale);
}
-
+
/**
+ * @param locale The locale that is used to find the appropriate localized
text
+ * @param timezone The timezone that is used for displaying dates and
times
+ * @param defaultSummary The default text will be returned, if no entry
with key <code>summary</code> could be found in the message bundle identified
by the given message identifier
+ * @return returns the localized message entry with the key
<code>summary</code>
+ */
+ public String getSummary(Locale locale, TimeZone timezone, String
defaultSummary) {
+ return getEntry(SUMMARY, locale, timezone, defaultSummary);
+ }
+
+ /**
* @param locale The locale that is used to find the appropriate localized
text
* @param defaultSummary The default text will be returned, if no entry
with key <code>summary</code> could be found in the message bundle identified
by the given message identifier
* @return returns the localized message entry with the key
<code>summary</code>
@@ -91,6 +112,16 @@
/**
+ * @param locale The locale that is used to find the appropriate localized
text
+ * @param timezone The timezone that is used for displaying dates and
times
+ * @return returns the localized message entry with the key
<code>details</code>
+ * @throws MessageNotFoundException is thrown if no entry with key
<code>details</code> could be found in the message bundle identified by the
given message identifier
+ */
+ public String getDetails(Locale locale, TimeZone timezone) throws
MessageNotFoundException {
+ return getEntry(DETAILS, locale, timezone);
+ }
+
+ /**
* @param locale The locale that is used to find the appropriate localized
text
* @return returns the localized message entry with the key
<code>details</code>
* @throws MessageNotFoundException is thrown if no entry with key
<code>details</code> could be found in the message bundle identified by the
given message identifier
@@ -100,6 +131,16 @@
}
/**
+ * @param locale The locale that is used to find the appropriate localized
text
+ * @param timezone The timezone that is used for displaying dates and
times
+ * @param defaultDetails The default text will be returned, if no entry
with key <code>details</code> could be found in the message bundle identified
by the given message identifier
+ * @return returns the localized message entry with the key
<code>details</code>
+ */
+ public String getDetails(Locale locale, TimeZone timezone, String
defaultDetails) {
+ return getEntry(DETAILS, locale, timezone, defaultDetails);
+ }
+
+ /**
* @param locale The locale that is used to find the appropriate localized
text
* @param defaultDetails The default text will be returned, if no entry
with key <code>details</code> could be found in the message bundle identified
by the given message identifier
* @return returns the localized message entry with the key
<code>details</code>
Index: src/java/org/apache/commons/i18n/bundles/MessageBundle.java
===================================================================
--- src/java/org/apache/commons/i18n/bundles/MessageBundle.java (revision
428983)
+++ src/java/org/apache/commons/i18n/bundles/MessageBundle.java (working copy)
@@ -23,6 +23,7 @@
package org.apache.commons.i18n.bundles;
import java.util.Locale;
+import java.util.TimeZone;
import org.apache.commons.i18n.MessageNotFoundException;
@@ -69,6 +70,16 @@
}
/**
+ * @param locale The locale that is used to find the appropriate localized
text
+ * @param timezone The timezone that is used for displaying dates and
times
+ * @return returns the localized message entry with the key
<code>title</code>
+ * @throws MessageNotFoundException is thrown if no entry with key
<code>title</code> could be found in the message bundle identified by the given
message identifier
+ */
+ public String getTitle(Locale locale, TimeZone timezone) throws
MessageNotFoundException {
+ return getEntry(TITLE, locale,timezone);
+ }
+
+ /**
* @param locale The locale that is used to find the appropriate localized
text
* @return returns the localized message entry with the key
<code>title</code>
* @throws MessageNotFoundException is thrown if no entry with key
<code>title</code> could be found in the message bundle identified by the given
message identifier
@@ -77,7 +88,18 @@
return getEntry(TITLE, locale);
}
+
/**
+ * @param locale The locale that is used to find the appropriate localized
text
+ * @param timezone The timezone that is used for displaying dates and times
+ * @param defaultTitle The default text will be returned, if no entry with
key <code>title</code> could be found in the message bundle identified by the
given message identifier
+ * @return returns the localized message entry with the key
<code>title</code>
+ */
+ public String getTitle(Locale locale, TimeZone timezone, String
defaultTitle) {
+ return getEntry(TITLE, locale, timezone, defaultTitle);
+ }
+
+ /**
* @param locale The locale that is used to find the appropriate localized
text
* @param defaultTitle The default text will be returned, if no entry with
key <code>title</code> could be found in the message bundle identified by the
given message identifier
* @return returns the localized message entry with the key
<code>title</code>
Index: src/java/org/apache/commons/i18n/bundles/TextBundle.java
===================================================================
--- src/java/org/apache/commons/i18n/bundles/TextBundle.java (revision
428983)
+++ src/java/org/apache/commons/i18n/bundles/TextBundle.java (working copy)
@@ -23,6 +23,7 @@
package org.apache.commons.i18n.bundles;
import java.util.Locale;
+import java.util.TimeZone;
import org.apache.commons.i18n.LocalizedBundle;
import org.apache.commons.i18n.MessageNotFoundException;
@@ -71,6 +72,16 @@
}
/**
+ * @param locale The locale that is used to find the appropriate localized
text
+ * @param timezone The timezone that is used for displaying dates and
times
+ * @return returns the localized message entry with the key
<code>text</code>
+ * @throws MessageNotFoundException is thrown if no entry with key
<code>text</code> could be found in the message bundle identified by the given
message identifier
+ */
+ public String getText(Locale locale, TimeZone timezone) throws
MessageNotFoundException {
+ return getEntry(TEXT, locale, timezone);
+ }
+
+ /**
* @param locale The locale that is used to find the appropriate localized
text
* @return returns the localized message entry with the key
<code>text</code>
* @throws MessageNotFoundException is thrown if no entry with key
<code>text</code> could be found in the message bundle identified by the given
message identifier
@@ -78,8 +89,18 @@
public String getText(Locale locale) throws MessageNotFoundException {
return getEntry(TEXT, locale);
}
-
+
/**
+ * @param locale The locale that is used to find the appropriate localized
text
+ * @param timezone The timezone that is used for displaying dates and
times
+ * @param defaultText The default text will be returned, if no entry with
key <code>text</code> could be found in the message bundle identified by the
given message identifier
+ * @return returns the localized message entry with the key
<code>text</code>
+ */
+ public String getText(Locale locale, TimeZone timezone, String
defaultText) {
+ return getEntry(TEXT, locale, timezone, defaultText);
+ }
+
+ /**
* @param locale The locale that is used to find the appropriate localized
text
* @param defaultText The default text will be returned, if no entry with
key <code>text</code> could be found in the message bundle identified by the
given message identifier
* @return returns the localized message entry with the key
<code>text</code>
Index: src/java/org/apache/commons/i18n/filter/Filter.java
===================================================================
--- src/java/org/apache/commons/i18n/filter/Filter.java (revision 0)
+++ src/java/org/apache/commons/i18n/filter/Filter.java (revision 0)
@@ -0,0 +1,8 @@
+
+package org.apache.commons.i18n.filter;
+
+public interface Filter {
+
+ public String doFilter(String input);
+
+}
Index: src/java/org/apache/commons/i18n/filter/SQLFilter.java
===================================================================
--- src/java/org/apache/commons/i18n/filter/SQLFilter.java (revision 0)
+++ src/java/org/apache/commons/i18n/filter/SQLFilter.java (revision 0)
@@ -0,0 +1,62 @@
+
+package org.apache.commons.i18n.filter;
+
+/**
+ * Filter for strings to store in a SQL table.
+ */
+public class SQLFilter implements Filter
+{
+
+ /**
+ * escapes ' " = - / \ ; \r \n
+ */
+ public String doFilter(String input) {
+ StringBuffer buf = new StringBuffer(input);
+ for (int i = 0; i < buf.length(); i++) {
+ char ch = buf.charAt(i);
+ switch (ch) {
+ case '\'':
+ buf.replace(i,i+1,"\\\'");
+ i += 1;
+ break;
+ case '\"':
+ buf.replace(i,i+1,"\\\"");
+ i += 1;
+ break;
+ case '=':
+ buf.replace(i,i+1,"\\=");
+ i += 1;
+ break;
+ case '-':
+ buf.replace(i,i+1,"\\-");
+ i += 1;
+ break;
+ case '/':
+ buf.replace(i,i+1,"\\/");
+ i += 1;
+ break;
+ case '\\':
+ buf.replace(i,i+1,"\\\\");
+ i += 1;
+ break;
+ case ';':
+ buf.replace(i,i+1,"\\;");
+ i += 1;
+ break;
+ case '\r':
+ buf.replace(i,i+1,"\\r");
+ i += 1;
+ break;
+ case '\n':
+ buf.replace(i,i+1,"\\n");
+ i += 1;
+ break;
+ default:
+
+ }
+
+ }
+ return buf.toString();
+ }
+
+}
Index: src/java/org/apache/commons/i18n/filter/HTMLFilter.java
===================================================================
--- src/java/org/apache/commons/i18n/filter/HTMLFilter.java (revision 0)
+++ src/java/org/apache/commons/i18n/filter/HTMLFilter.java (revision 0)
@@ -0,0 +1,58 @@
+
+package org.apache.commons.i18n.filter;
+
+/**
+ * HTML Filter
+ */
+public class HTMLFilter implements Filter {
+
+ public String doFilter(String input) {
+ StringBuffer buf = new StringBuffer(input);
+ for (int i = 0; i < buf.length(); i ++) {
+ char ch = buf.charAt(i);
+ switch (ch){
+ case '<':
+ buf.replace(i,i+1,"<");
+ break;
+ case '>':
+ buf.replace(i,i+1,">");
+ break;
+ case '(':
+ buf.replace(i,i+1,"(");
+ break;
+ case ')':
+ buf.replace(i,i+1,")");
+ break;
+ case '#':
+ buf.replace(i,i+1,"#");
+ break;
+ case '&':
+ buf.replace(i,i+1,"&");
+ break;
+ case '\"':
+ buf.replace(i,i+1,""");
+ break;
+ case '\'':
+ buf.replace(i,i+1,"'");
+ break;
+ case '%':
+ buf.replace(i,i+1,"%");
+ break;
+ case ';':
+ buf.replace(i,i+1,";");
+ break;
+ case '+':
+ buf.replace(i,i+1,"+");
+ break;
+ case '-':
+ buf.replace(i,i+1,"-");
+ break;
+ default:
+ i -= 3;
+ }
+ i += 3;
+ }
+ return buf.toString();
+ }
+
+}
Index: src/java/org/apache/commons/i18n/filter/UntrustedInput.java
===================================================================
--- src/java/org/apache/commons/i18n/filter/UntrustedInput.java (revision 0)
+++ src/java/org/apache/commons/i18n/filter/UntrustedInput.java (revision 0)
@@ -0,0 +1,23 @@
+
+package org.apache.commons.i18n.filter;
+
+/**
+ * Wrapper class to mark untrusted Input
+ */
+public class UntrustedInput {
+
+ protected Object input;
+
+ public UntrustedInput(Object input) {
+ this.input = input;
+ }
+
+ public Object getInput() {
+ return input;
+ }
+
+ public String toString() {
+ return input.toString();
+ }
+
+}
Index: src/java/org/apache/commons/i18n/filter/Filter.java
===================================================================
--- src/java/org/apache/commons/i18n/filter/Filter.java (revision 0)
+++ src/java/org/apache/commons/i18n/filter/Filter.java (revision 0)
@@ -0,0 +1,8 @@
+
+package org.apache.commons.i18n.filter;
+
+public interface Filter {
+
+ public String doFilter(String input);
+
+}
Index: src/java/org/apache/commons/i18n/filter/HTMLFilter.java
===================================================================
--- src/java/org/apache/commons/i18n/filter/HTMLFilter.java (revision 0)
+++ src/java/org/apache/commons/i18n/filter/HTMLFilter.java (revision 0)
@@ -0,0 +1,58 @@
+
+package org.apache.commons.i18n.filter;
+
+/**
+ * HTML Filter
+ */
+public class HTMLFilter implements Filter {
+
+ public String doFilter(String input) {
+ StringBuffer buf = new StringBuffer(input);
+ for (int i = 0; i < buf.length(); i ++) {
+ char ch = buf.charAt(i);
+ switch (ch){
+ case '<':
+ buf.replace(i,i+1,"<");
+ break;
+ case '>':
+ buf.replace(i,i+1,">");
+ break;
+ case '(':
+ buf.replace(i,i+1,"(");
+ break;
+ case ')':
+ buf.replace(i,i+1,")");
+ break;
+ case '#':
+ buf.replace(i,i+1,"#");
+ break;
+ case '&':
+ buf.replace(i,i+1,"&");
+ break;
+ case '\"':
+ buf.replace(i,i+1,""");
+ break;
+ case '\'':
+ buf.replace(i,i+1,"'");
+ break;
+ case '%':
+ buf.replace(i,i+1,"%");
+ break;
+ case ';':
+ buf.replace(i,i+1,";");
+ break;
+ case '+':
+ buf.replace(i,i+1,"+");
+ break;
+ case '-':
+ buf.replace(i,i+1,"-");
+ break;
+ default:
+ i -= 3;
+ }
+ i += 3;
+ }
+ return buf.toString();
+ }
+
+}
Index: src/java/org/apache/commons/i18n/filter/SQLFilter.java
===================================================================
--- src/java/org/apache/commons/i18n/filter/SQLFilter.java (revision 0)
+++ src/java/org/apache/commons/i18n/filter/SQLFilter.java (revision 0)
@@ -0,0 +1,62 @@
+
+package org.apache.commons.i18n.filter;
+
+/**
+ * Filter for strings to store in a SQL table.
+ */
+public class SQLFilter implements Filter
+{
+
+ /**
+ * escapes ' " = - / \ ; \r \n
+ */
+ public String doFilter(String input) {
+ StringBuffer buf = new StringBuffer(input);
+ for (int i = 0; i < buf.length(); i++) {
+ char ch = buf.charAt(i);
+ switch (ch) {
+ case '\'':
+ buf.replace(i,i+1,"\\\'");
+ i += 1;
+ break;
+ case '\"':
+ buf.replace(i,i+1,"\\\"");
+ i += 1;
+ break;
+ case '=':
+ buf.replace(i,i+1,"\\=");
+ i += 1;
+ break;
+ case '-':
+ buf.replace(i,i+1,"\\-");
+ i += 1;
+ break;
+ case '/':
+ buf.replace(i,i+1,"\\/");
+ i += 1;
+ break;
+ case '\\':
+ buf.replace(i,i+1,"\\\\");
+ i += 1;
+ break;
+ case ';':
+ buf.replace(i,i+1,"\\;");
+ i += 1;
+ break;
+ case '\r':
+ buf.replace(i,i+1,"\\r");
+ i += 1;
+ break;
+ case '\n':
+ buf.replace(i,i+1,"\\n");
+ i += 1;
+ break;
+ default:
+
+ }
+
+ }
+ return buf.toString();
+ }
+
+}
Index: src/java/org/apache/commons/i18n/filter/UntrustedInput.java
===================================================================
--- src/java/org/apache/commons/i18n/filter/UntrustedInput.java (revision 0)
+++ src/java/org/apache/commons/i18n/filter/UntrustedInput.java (revision 0)
@@ -0,0 +1,23 @@
+
+package org.apache.commons.i18n.filter;
+
+/**
+ * Wrapper class to mark untrusted Input
+ */
+public class UntrustedInput {
+
+ protected Object input;
+
+ public UntrustedInput(Object input) {
+ this.input = input;
+ }
+
+ public Object getInput() {
+ return input;
+ }
+
+ public String toString() {
+ return input.toString();
+ }
+
+}
Index: src/java/org/apache/commons/i18n/LocalizedBundle.java
===================================================================
--- src/java/org/apache/commons/i18n/LocalizedBundle.java (revision
428983)
+++ src/java/org/apache/commons/i18n/LocalizedBundle.java (working copy)
@@ -25,7 +25,11 @@
import java.io.Serializable;
import java.util.Locale;
+import java.util.TimeZone;
+import org.apache.commons.i18n.filter.Filter;
+import org.apache.commons.i18n.filter.UntrustedInput;
+
/**
*
* <p>The <code>LocalizedBundle</code> class represents a bundle of localized
messages that
@@ -45,6 +49,9 @@
protected String providerId;
protected String id;
protected Object[] arguments;
+
+ protected Filter filter;
+ protected Object[] filteredArguments;
/**
* @param providerId The name of the message provider (i.e. source) to use
for the message
@@ -72,6 +79,8 @@
public LocalizedBundle(String messageId, Object[] arguments) {
this.id = messageId;
this.arguments = arguments;
+ filter = null;
+ filteredArguments = arguments;
}
/**
@@ -85,6 +94,8 @@
this.providerId = providerId;
this.id = messageId;
this.arguments = arguments;
+ filter = null;
+ filteredArguments = arguments;
}
/**
@@ -107,6 +118,33 @@
public String getProviderId() {
return providerId;
}
+
+ /**
+ * @param key the key of the specific message entry in the message bundle
+ * @param locale the locale for that this message should be rendered
+ * @param timezone the timezone for that this message should be rendered
+ * @return returns the text of the desired message entry for the given
locale
+ * @throws MessageNotFoundException if an entry with the given key can not
be found
+ * in this bundle
+ */
+ public String getEntry(String key, Locale locale, TimeZone timezone)
throws MessageNotFoundException {
+ return providerId != null ?
+ MessageManager.getText(providerId, id, key, filteredArguments,
locale, timezone) :
+ MessageManager.getText(id, key, filteredArguments, locale,
timezone);
+ }
+
+ /**
+ * @param key the key of the specific message entry in the message bundle
+ * @param locale the locale for that this message should be rendered
+ * @param timezone the timezone for that this message should be rendered
+ * @param defaultText the text to be returned if no entry was found for
the given key
+ * @return returns the text of the desired message entry for the given
locale
+ */
+ public String getEntry(String key, Locale locale, TimeZone timezone,
String defaultText) {
+ return providerId != null ?
+ MessageManager.getText(providerId, id, key, filteredArguments,
locale, timezone, defaultText) :
+ MessageManager.getText(id, key, filteredArguments, locale,
timezone, defaultText);
+ }
/**
* @param key the key of the specific message entry in the message bundle
@@ -117,8 +155,8 @@
*/
public String getEntry(String key, Locale locale) throws
MessageNotFoundException {
return providerId != null ?
- MessageManager.getText(providerId, id, key, arguments, locale) :
- MessageManager.getText(id, key, arguments, locale);
+ MessageManager.getText(providerId, id, key, filteredArguments,
locale, TimeZone.getDefault()) :
+ MessageManager.getText(id, key, filteredArguments, locale,
TimeZone.getDefault());
}
/**
@@ -129,7 +167,27 @@
*/
public String getEntry(String key, Locale locale, String defaultText) {
return providerId != null ?
- MessageManager.getText(providerId, id, key, arguments, locale,
defaultText) :
- MessageManager.getText(id, key, arguments, locale, defaultText);
+ MessageManager.getText(providerId, id, key, filteredArguments,
locale, TimeZone.getDefault(), defaultText) :
+ MessageManager.getText(id, key, filteredArguments, locale,
TimeZone.getDefault(), defaultText);
}
+
+ public Filter getFilter() {
+ return filter;
+ }
+
+ public void setFilter(Filter filter) {
+ if (filter == null) {
+ filteredArguments = arguments;
+ } else if (!filter.equals(this.filter)) {
+ filteredArguments = new Object[arguments.length];
+ for (int i = 0; i < arguments.length; i ++) {
+ if (arguments[i] instanceof UntrustedInput) {
+ filteredArguments[i] =
filter.doFilter(arguments[i].toString());
+ } else {
+ filteredArguments[i] = arguments[i];
+ }
+ }
+ }
+ this.filter = filter;
+ }
}
\ No newline at end of file
Index: src/java/org/apache/commons/i18n/MessageManager.java
===================================================================
--- src/java/org/apache/commons/i18n/MessageManager.java (revision
428983)
+++ src/java/org/apache/commons/i18n/MessageManager.java (working copy)
@@ -19,6 +19,8 @@
*/
package org.apache.commons.i18n;
+import java.text.DateFormat;
+import java.text.Format;
import java.text.MessageFormat;
import java.util.*;
@@ -96,6 +98,8 @@
* the standard java text formatting abilities.
* @param locale
* The locale in which the message will be printed
+ * @param timezone
+ * The timezone in which the message will be printed
* @exception MessageNotFoundException
* Will be thrown if no message bundle can be found for the
* given id or if the desired message entry is missing in
the
@@ -103,15 +107,16 @@
* @return The localized text
*/
public static String getText(String id, String entry, Object[] arguments,
- Locale locale) throws MessageNotFoundException {
+ Locale locale,TimeZone timezone) throws MessageNotFoundException {
if(messageProviders.isEmpty())
throw new MessageNotFoundException("No MessageProvider
registered");
for (Iterator i = messageProviders.values().iterator(); i.hasNext();) {
String text = ((MessageProvider) i.next()).getText(id, entry,
locale);
if(text != null)
- return (arguments != null && arguments.length > 0) ?
- MessageFormat.format(text, arguments) : text;
+ return (arguments != null && arguments.length > 0) ?
+ //MessageFormat.format(text, arguments) : text;
+
formatWithTimeZone(text,arguments,locale,timezone) : text;
}
throw new MessageNotFoundException(MessageFormat.format(
I18nUtils.INTERNAL_MESSAGES.getString(I18nUtils.MESSAGE_ENTRY_NOT_FOUND),
@@ -132,6 +137,8 @@
* the standard java text formatting abilities.
* @param locale
* The locale in which the message will be printed
+ * @param timezone
+ * The timezone in which the message will be printed
* @param defaultText
* If no message bundle or message entry could be found for the
* specified parameters, the default text will be returned.
@@ -139,12 +146,13 @@
* be found
*/
public static String getText(String id, String entry, Object[] arguments,
- Locale locale, String defaultText) {
+ Locale locale,TimeZone timezone, String defaultText) {
try {
- return getText(id, entry, arguments, locale);
+ return getText(id, entry, arguments, locale, timezone);
} catch (MessageNotFoundException e) {
return (arguments != null && arguments.length > 0) ?
- MessageFormat.format(defaultText, arguments) : defaultText;
+ //MessageFormat.format(defaultText, arguments) :
defaultText;
+
formatWithTimeZone(defaultText,arguments,locale,timezone) : defaultText;
}
}
@@ -161,6 +169,8 @@
* the standard java text formatting abilities.
* @param locale
* The locale in which the message will be printed
+ * @param timezone
+ * The timezone in which the message will be printed
* @exception MessageNotFoundException
* Will be thrown if the requested message provider cannot
be found or
* no message bundle can be found for the given id or if
the desired
@@ -168,14 +178,15 @@
* @return The localized text
*/
public static String getText(String providerId, String id, String entry,
Object[] arguments,
- Locale locale) throws MessageNotFoundException {
+ Locale locale, TimeZone timezone) throws MessageNotFoundException {
MessageProvider provider = (MessageProvider)
messageProviders.get(providerId);
if(provider == null)
throw new MessageNotFoundException("Provider '" + providerId + "'
not installed");
String text = provider.getText(id, entry, locale);
if(text != null)
return (arguments != null && arguments.length > 0) ?
- MessageFormat.format(text, arguments) : text;
+ //MessageFormat.format(text, arguments) : text;
+ formatWithTimeZone(text,arguments,locale,timezone) :
text;
else
throw new MessageNotFoundException(MessageFormat.format(
I18nUtils.INTERNAL_MESSAGES.getString(I18nUtils.MESSAGE_ENTRY_NOT_FOUND),
@@ -197,6 +208,8 @@
* the standard java text formatting abilities.
* @param locale
* The locale in which the message will be printed
+ * @param timezone
+ * The timezone in which the message will be printed
* @param defaultText
* If no message bundle or message entry could be found for the
* specified parameters, the default text will be returned.
@@ -204,12 +217,13 @@
* be found
*/
public static String getText(String providerId, String id, String entry,
Object[] arguments,
- Locale locale, String defaultText) {
+ Locale locale, TimeZone timezone, String defaultText) {
try {
- return getText(providerId, id, entry, arguments, locale);
+ return getText(providerId, id, entry, arguments, locale, timezone);
} catch (MessageNotFoundException e) {
return (arguments != null && arguments.length > 0) ?
- MessageFormat.format(defaultText, arguments) : defaultText;
+ //MessageFormat.format(defaultText, arguments) :
defaultText;
+
formatWithTimeZone(defaultText,arguments,locale,timezone) : defaultText;
}
}
@@ -247,4 +261,22 @@
throw new MessageNotFoundException("Provider '" + providerId + "'
not installed");
return provider.getEntries(id, locale);
}
+
+ protected static String formatWithTimeZone(String template,Object[]
arguments, Locale locale, TimeZone timezone) {
+ MessageFormat mf = new MessageFormat(" ");
+ mf.setLocale(locale);
+ mf.applyPattern(template);
+ if (!timezone.equals(TimeZone.getDefault())) {
+ Format[] formats = mf.getFormats();
+ for (int i = 0; i < formats.length; i++) {
+ if (formats[i] instanceof DateFormat) {
+ DateFormat temp = (DateFormat) formats[i];
+ temp.setTimeZone(timezone);
+ mf.setFormat(i,temp);
+ }
+ }
+ }
+ return mf.format(arguments);
+ }
+
}
\ No newline at end of file
Index: src/test/datetimezoneBundle.properties
===================================================================
--- src/test/datetimezoneBundle.properties (revision 0)
+++ src/test/datetimezoneBundle.properties (revision 0)
@@ -0,0 +1 @@
+datetime1.text=It was {0,date} at {0,time}
Index: src/test/datetimezoneBundle_de.properties
===================================================================
--- src/test/datetimezoneBundle_de.properties (revision 0)
+++ src/test/datetimezoneBundle_de.properties (revision 0)
@@ -0,0 +1 @@
+datetime1.text=Es war am {0,date} um {0,time}
Index: src/test/org/apache/commons/i18n/filter/SQLFilterTest.java
===================================================================
--- src/test/org/apache/commons/i18n/filter/SQLFilterTest.java (revision 0)
+++ src/test/org/apache/commons/i18n/filter/SQLFilterTest.java (revision 0)
@@ -0,0 +1,15 @@
+
+package org.apache.commons.i18n.filter;
+
+import junit.framework.TestCase;
+
+public class SQLFilterTest extends TestCase {
+
+ private static final String test1 = "\'\"=-/\\;\r\n";
+
+ public void testDoFilter() {
+ Filter filter = new SQLFilter();
+ assertEquals("encode special
charaters","\\\'\\\"\\=\\-\\/\\\\\\;\\r\\n",filter.doFilter(test1));
+ }
+
+}
Index: src/test/org/apache/commons/i18n/filter/HTMLFilterTest.java
===================================================================
--- src/test/org/apache/commons/i18n/filter/HTMLFilterTest.java (revision 0)
+++ src/test/org/apache/commons/i18n/filter/HTMLFilterTest.java (revision 0)
@@ -0,0 +1,22 @@
+
+package org.apache.commons.i18n.filter;
+
+import junit.framework.TestCase;
+
+public class HTMLFilterTest extends TestCase {
+
+ private static final String test1 = "hello world";
+ private static final String test2 = "<script></script>";
+ private static final String test3 = "javascript:attack()";
+ private static final String test4 = "\"hello\"";
+
+ public void testDoFilter() {
+ Filter dummy = new HTMLFilter();
+
+ assertEquals("No filtering","hello
world",dummy.doFilter(test1));
+ assertEquals("script
tags","<script></script>",dummy.doFilter(test2));
+ assertEquals("javascript
link","javascript:attack()",dummy.doFilter(test3));
+ assertEquals("",""hello"",dummy.doFilter(test4));
+ }
+
+}
Index: src/test/org/apache/commons/i18n/filter/HTMLFilterTest.java
===================================================================
--- src/test/org/apache/commons/i18n/filter/HTMLFilterTest.java (revision 0)
+++ src/test/org/apache/commons/i18n/filter/HTMLFilterTest.java (revision 0)
@@ -0,0 +1,22 @@
+
+package org.apache.commons.i18n.filter;
+
+import junit.framework.TestCase;
+
+public class HTMLFilterTest extends TestCase {
+
+ private static final String test1 = "hello world";
+ private static final String test2 = "<script></script>";
+ private static final String test3 = "javascript:attack()";
+ private static final String test4 = "\"hello\"";
+
+ public void testDoFilter() {
+ Filter dummy = new HTMLFilter();
+
+ assertEquals("No filtering","hello
world",dummy.doFilter(test1));
+ assertEquals("script
tags","<script></script>",dummy.doFilter(test2));
+ assertEquals("javascript
link","javascript:attack()",dummy.doFilter(test3));
+ assertEquals("",""hello"",dummy.doFilter(test4));
+ }
+
+}
Index: src/test/org/apache/commons/i18n/filter/SQLFilterTest.java
===================================================================
--- src/test/org/apache/commons/i18n/filter/SQLFilterTest.java (revision 0)
+++ src/test/org/apache/commons/i18n/filter/SQLFilterTest.java (revision 0)
@@ -0,0 +1,15 @@
+
+package org.apache.commons.i18n.filter;
+
+import junit.framework.TestCase;
+
+public class SQLFilterTest extends TestCase {
+
+ private static final String test1 = "\'\"=-/\\;\r\n";
+
+ public void testDoFilter() {
+ Filter filter = new SQLFilter();
+ assertEquals("encode special
charaters","\\\'\\\"\\=\\-\\/\\\\\\;\\r\\n",filter.doFilter(test1));
+ }
+
+}
Index: src/test/org/apache/commons/i18n/JdbcMessageProviderTest.java
===================================================================
--- src/test/org/apache/commons/i18n/JdbcMessageProviderTest.java
(revision 428983)
+++ src/test/org/apache/commons/i18n/JdbcMessageProviderTest.java
(working copy)
@@ -9,6 +9,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
+import java.util.TimeZone;
import org.apache.commons.dbcp.BasicDataSource;
@@ -89,7 +90,7 @@
// Test install
MessageManager.addMessageProvider("messages", jdbcMessageProvider);
- assertEquals("Hello World", MessageManager.getText("helloWorld",
"title", null, Locale.ENGLISH));
+ assertEquals("Hello World", MessageManager.getText("helloWorld",
"title", null, Locale.ENGLISH, TimeZone.getDefault()));
}
public void testGetText() throws Exception {
Index: src/test/org/apache/commons/i18n/LocalizedBundleTest.java
===================================================================
--- src/test/org/apache/commons/i18n/LocalizedBundleTest.java (revision
428983)
+++ src/test/org/apache/commons/i18n/LocalizedBundleTest.java (working copy)
@@ -16,7 +16,10 @@
*/
package org.apache.commons.i18n;
+import java.util.Date;
+import java.util.Calendar;
import java.util.Locale;
+import java.util.TimeZone;
/**
* @author Mattias Jiderhamn
@@ -57,6 +60,20 @@
LocalizedBundle lbArgs = new LocalizedBundle("dummyId3", new String[]
{"arg1", "arg2"});
LocalizedBundle lbProviderArgs = new LocalizedBundle("dummyProvider4",
"dummyId4", new String[] {"arg1", "arg2"});
+ // TODO Test date formats and timezones
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeZone(TimeZone.getTimeZone("GMT"));
+ cal.set(Calendar.DATE,7);
+ cal.set(Calendar.MONTH,6);
+ cal.set(Calendar.YEAR,1983);
+ cal.set(Calendar.HOUR_OF_DAY,17);
+ cal.set(Calendar.MINUTE,7);
+ cal.set(Calendar.SECOND,0);
+ Date testDate = cal.getTime();
+ LocalizedBundle lbTime = new LocalizedBundle("dummyIDDate",new
Object[] {testDate});
+ assertEquals("Timezone and Default Text","It's the Jul 7, 1983 at
5:07:00 PM",
+ lbTime.getEntry("dummyEntry", Locale.US,
TimeZone.getTimeZone("GMT"), "It''s the {0,date} at {0,time}"));
+
// Test errors
try {
lb.getEntry("dummyEntry", Locale.US);
@@ -128,5 +145,6 @@
assertEquals("Named provider: Arguments and default",
"Source=dummyProvider4 Id=dummyId4 Entry=entry arg1 arg2
Locale=en_US",
lbProviderArgs.getEntry("entry {0} {1}", Locale.US,
"defaultText"));
+
}
}
Index: src/test/org/apache/commons/i18n/MessageManagerTest.java
===================================================================
--- src/test/org/apache/commons/i18n/MessageManagerTest.java (revision
428983)
+++ src/test/org/apache/commons/i18n/MessageManagerTest.java (working copy)
@@ -16,8 +16,12 @@
*/
package org.apache.commons.i18n;
+import java.text.DateFormat;
+import java.util.Calendar;
+import java.util.Date;
import java.util.Locale;
import java.util.Map;
+import java.util.TimeZone;
/**
* @author Mattias Jiderhamn
@@ -31,22 +35,57 @@
public void testGetText() {
assertEquals("Default text used", "defaultText",
- MessageManager.getText("dummyId", "dummyEntry", null,
Locale.US, "defaultText"));
+ MessageManager.getText("dummyId", "dummyEntry", null,
Locale.US, TimeZone.getDefault(), "defaultText"));
assertEquals("Default text with arguments", "defaultText with value",
MessageManager.getText("dummyId", "dummyEntry", new String[]
{"with value"},
- Locale.US, "defaultText {0}"));
+ Locale.US, TimeZone.getDefault(), "defaultText {0}"));
try {
- MessageManager.getText("dummyId", "dummyEntry", null, Locale.US);
+ MessageManager.getText("dummyId", "dummyEntry", null, Locale.US,
TimeZone.getDefault());
fail("Entry not found should cause error");
}
catch(MessageNotFoundException mnfex) {
assertEquals("Error text", "No MessageProvider registered",
mnfex.getMessage());
}
+ // Date and timezone
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeZone(TimeZone.getTimeZone("GMT"));
+ cal.set(Calendar.DATE,7);
+ cal.set(Calendar.MONTH,6);
+ cal.set(Calendar.YEAR,1983);
+ cal.set(Calendar.HOUR_OF_DAY,17);
+ cal.set(Calendar.MINUTE,7);
+ cal.set(Calendar.SECOND,0);
+ Date testDate = cal.getTime();
+ assertEquals("Default text with date arguments",
+ "defaultText on Jul 7, 1983 at 5:07:00 PM",
+ MessageManager.getText("dummyId", "dummyEntry", new Object[]
{testDate},
+ Locale.US, TimeZone.getTimeZone("GMT"), "defaultText
on {0,date} at {0,time}"));
+ assertEquals("Default text with date and different time zone",
+ "defaultText am 07.07.1983 um 19:07:00",
+ MessageManager.getText("dummyId", "dummyEntry", new Object[]
{testDate},
+ Locale.GERMAN, TimeZone.getTimeZone("CET"),
"defaultText am {0,date} um {0,time}"));
+
+ // non default text
+ MessageManager.addMessageProvider("dateTest",new
ResourceBundleMessageProvider("datetimezoneBundle"));
+ assertEquals("Date and Time",
+ "It was Jul 7, 1983 at 5:07:00 PM",
+ MessageManager.getText("datetime1", "text", new
Object[] {testDate},
+ Locale.US,
TimeZone.getTimeZone("GMT")));
+ assertEquals("Date and Time with Locale and other TimeZone",
+ "Es war am 07.07.1983 um 19:07:00",
+ MessageManager.getText("datetime1", "text", new
Object[] {testDate},
+ Locale.GERMAN,
TimeZone.getTimeZone("CET")));
+ assertEquals("Date and Time with providerId",
+ "It was Jul 7, 1983 at 5:07:00 PM",
+ MessageManager.getText("dateTest","datetime1", "text",
new Object[] {testDate},
+ Locale.US,
TimeZone.getTimeZone("GMT")));
+ MessageManager.removeMessageProvider("dateTest");
+
addThrowingMockProvider(); // Add mock provider always throwing
exceptions
try {
- MessageManager.getText("dummyId", "dummyEntry", null, Locale.US);
+ MessageManager.getText("dummyId", "dummyEntry", null, Locale.US,
TimeZone.getDefault());
fail("Mock provider should throw Exception");
}
catch(MessageNotFoundException mnfex) {
@@ -58,29 +97,29 @@
addMockProvider(); // Add mock provider
assertEquals("Throwing mock not used", "Source=mock Id=dummyId
Entry=dummyEntry Locale=en_US",
- MessageManager.getText("dummyId", "dummyEntry", null,
Locale.US, "defaultText"));
+ MessageManager.getText("dummyId", "dummyEntry", null,
Locale.US, TimeZone.getDefault(), "defaultText"));
removeThrowingMockProvider(); // Removing throwing mock and keep only
normal mock
assertEquals("Default text not used", "Source=mock Id=dummyId
Entry=dummyEntry Locale=en_US",
- MessageManager.getText("dummyId", "dummyEntry", null,
Locale.US, "defaultText"));
+ MessageManager.getText("dummyId", "dummyEntry", null,
Locale.US, TimeZone.getDefault(), "defaultText"));
assertEquals("Normal lookup", "Source=mock Id=id Entry=entry
Locale=en_US",
- MessageManager.getText("id", "entry", null, Locale.US));
+ MessageManager.getText("id", "entry", null, Locale.US,
TimeZone.getDefault()));
assertEquals("Single argument",
"Source=mock Id=id Entry=entry value1 Locale=en_US",
- MessageManager.getText("id", "entry {0}", new String[]
{"value1"}, Locale.US));
+ MessageManager.getText("id", "entry {0}", new String[]
{"value1"}, Locale.US, TimeZone.getDefault()));
assertEquals("Multiple arguments",
"Source=mock Id=id Entry=entry value0: value1 Locale=en_US",
- MessageManager.getText("id", "entry {0}: {1}", new String[]
{"value0", "value1"},Locale.US));
+ MessageManager.getText("id", "entry {0}: {1}", new String[]
{"value0", "value1"},Locale.US, TimeZone.getDefault()));
assertEquals("Single argument and default",
"Source=mock Id=id Entry=entry value1 Locale=en_US",
- MessageManager.getText("id", "entry {0}", new String[]
{"value1"},Locale.US, "defaultText"));
+ MessageManager.getText("id", "entry {0}", new String[]
{"value1"},Locale.US, TimeZone.getDefault(), "defaultText"));
// Named provider not found
try {
- MessageManager.getText("mockProvider2", "dummyId", "dummyEntry",
null, Locale.US);
+ MessageManager.getText("mockProvider2", "dummyId", "dummyEntry",
null, Locale.US, TimeZone.getDefault());
fail("Unknown provider should throw Exception");
}
catch(MessageNotFoundException mnfex) {
@@ -88,22 +127,22 @@
}
assertEquals("Default text used", "defaultText",
- MessageManager.getText("mockProvider2", "dummyId",
"dummyEntry", null, Locale.US, "defaultText"));
+ MessageManager.getText("mockProvider2", "dummyId",
"dummyEntry", null, Locale.US, TimeZone.getDefault(), "defaultText"));
// Named provider found
addMockProvider("mockProvider2");
assertEquals("Default text not used, qualified lookup",
"Source=mockProvider2 Id=dummyId Entry=dummyEntry Locale=en_US",
- MessageManager.getText("mockProvider2", "dummyId",
"dummyEntry", null, Locale.US, "defaultText"));
+ MessageManager.getText("mockProvider2", "dummyId",
"dummyEntry", null, Locale.US, TimeZone.getDefault(), "defaultText"));
assertEquals("Normal qualified lookup", "Source=mockProvider2 Id=id
Entry=entry Locale=en_US",
- MessageManager.getText("mockProvider2", "id", "entry", null,
Locale.US));
+ MessageManager.getText("mockProvider2", "id", "entry", null,
Locale.US, TimeZone.getDefault()));
// Named provider found, but fails to find message
addThrowingMockProvider(); // Add mock provider returning null for
unknown entries
try {
- MessageManager.getText("throwingMock", "dummyId", "dummyEntry",
null, Locale.US);
+ MessageManager.getText("throwingMock", "dummyId", "dummyEntry",
null, Locale.US, TimeZone.getDefault());
fail("Unknown provider should throw Exception");
}
catch(MessageNotFoundException mnfex) {
Index: src/test/org/apache/commons/i18n/ResourceBundleMessageProviderTest.java
===================================================================
--- src/test/org/apache/commons/i18n/ResourceBundleMessageProviderTest.java
(revision 428983)
+++ src/test/org/apache/commons/i18n/ResourceBundleMessageProviderTest.java
(working copy)
@@ -112,7 +112,7 @@
Map germanEntries = new
ResourceBundleMessageProvider("messageBundle").getEntries("helloWorld",
Locale.GERMAN);
assertEquals("No of entries", 3, germanEntries.size());
assertEquals("Hallo Welt", germanEntries.get("title"));
- assertEquals("Ich w�nsche Dir alles Gute und ein frohes Fest!",
germanEntries.get("text"));
+ assertEquals("Ich wünsche Dir alles Gute und ein frohes Fest!",
germanEntries.get("text"));
assertEquals("This entry is not translated to any other languages",
germanEntries.get("notTranslated"));
Map frenchEntries = new
ResourceBundleMessageProvider("messageBundle").getEntries("helloWorld",
Locale.FRENCH);
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]