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,"&#60");
+                               break;
+                       case '>':
+                               buf.replace(i,i+1,"&#62");
+                               break;
+                       case '(':
+                               buf.replace(i,i+1,"&#40");
+                               break;
+                       case ')':
+                               buf.replace(i,i+1,"&#41");
+                               break;
+                       case '#':
+                               buf.replace(i,i+1,"&#35");
+                               break;
+                       case '&':
+                               buf.replace(i,i+1,"&#38");
+                               break;
+                       case '\"':
+                               buf.replace(i,i+1,"&#34");
+                               break;
+                       case '\'':
+                               buf.replace(i,i+1,"&#39");
+                               break;
+                       case '%':
+                               buf.replace(i,i+1,"&#37");
+                               break;
+                       case ';':
+                               buf.replace(i,i+1,"&#59");
+                               break;
+                       case '+':
+                               buf.replace(i,i+1,"&#43");
+                               break;
+                       case '-':
+                               buf.replace(i,i+1,"&#45");
+                               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,"&#60");
+                               break;
+                       case '>':
+                               buf.replace(i,i+1,"&#62");
+                               break;
+                       case '(':
+                               buf.replace(i,i+1,"&#40");
+                               break;
+                       case ')':
+                               buf.replace(i,i+1,"&#41");
+                               break;
+                       case '#':
+                               buf.replace(i,i+1,"&#35");
+                               break;
+                       case '&':
+                               buf.replace(i,i+1,"&#38");
+                               break;
+                       case '\"':
+                               buf.replace(i,i+1,"&#34");
+                               break;
+                       case '\'':
+                               buf.replace(i,i+1,"&#39");
+                               break;
+                       case '%':
+                               buf.replace(i,i+1,"&#37");
+                               break;
+                       case ';':
+                               buf.replace(i,i+1,"&#59");
+                               break;
+                       case '+':
+                               buf.replace(i,i+1,"&#43");
+                               break;
+                       case '-':
+                               buf.replace(i,i+1,"&#45");
+                               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","&#60script&#62&#60/script&#62",dummy.doFilter(test2));
+               assertEquals("javascript 
link","javascript:attack&#40&#41",dummy.doFilter(test3));
+               assertEquals("","&#34hello&#34",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","&#60script&#62&#60/script&#62",dummy.doFilter(test2));
+               assertEquals("javascript 
link","javascript:attack&#40&#41",dummy.doFilter(test3));
+               assertEquals("","&#34hello&#34",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]

Reply via email to