I have previously discussed with Daniel Florey a change that allows the user to 
qualify the provider (or source or namespace) to be used for a given text 
entry. My main motivation for this is to allow the same entry key in several 
different text sources, but this also provides better performance since the API 
does not have to loop over the different providers in search for the given 
entry.

Thanks to James Mitchell I am now able to create the diff for this change; see 
below. I would be happy if Daniel or anybody else would review and commit this 
patch.

Included in the patch is also a minor change that allows non-string 
ResourceBundle entries to be used (via toString()).

After this there are a few more changes I would like to discuss - conserning 
class and package dependencies among others - so Daniel, please tell me when 
you are available again. I also hope to find the time to create an example 
DatabaseProvider.

Now here is the diff.
(Again, if lines are wrapped in the e-mail, I can provide the diff by personal 
e-mail or in a bugzilla entry).

Index: src/test/org/apache/commons/i18n/MockProviderTestBase.java
===================================================================
--- src/test/org/apache/commons/i18n/MockProviderTestBase.java  (revision 
170884)
+++ src/test/org/apache/commons/i18n/MockProviderTestBase.java  (working copy)
@@ -30,36 +30,41 @@
  * @author Mattias Jiderhamn
  */
 public abstract class MockProviderTestBase extends TestCase {
-    /**
-     * Mock message provider that returns a string made up of the arguments 
passed to it.
-     */
-    final private MessageProvider mockMessageProvider = new MessageProvider() {
-        public String getText(String id, String entry, Locale locale) throws 
MessageNotFoundException {
-            return MockProviderTestBase.getMockString(id, entry, locale);
-        }
 
-        public Map getEntries(String id, Locale locale) throws 
MessageNotFoundException {
-            Map output = new HashMap();
-            output.put("entry1", 
MockProviderTestBase.getMockString(id,"entry1",locale));
-            output.put("entry2", 
MockProviderTestBase.getMockString(id,"entry2",locale));
-            return output;
-        }
-    };
-
     public void tearDown() {
         /* Remove mock provider after each test, to allow for 
MessageNotFoundExceptions */
-        MessageManager.removeMessageProvider("mock");
-        removeThrowingMockProvider();
+        MessageManager.clearMessageProviders();
     }
 
     /**
      * Add mock provider to <code>MessageManager</code>.
      */
     protected void addMockProvider() {
-        MessageManager.addMessageProvider("mock", mockMessageProvider);
+        addMockProvider("mock");
     }
 
     /**
+     * Add mock provider to <code>MessageManager</code>.
+     */
+    protected void addMockProvider(final String providerId) {
+         //  Mock message provider that returns a string made up of the 
arguments passed to it.
+        MessageProvider mockMessageProvider = new MessageProvider() {
+            public String getText(String id, String entry, Locale locale) 
throws MessageNotFoundException {
+                return MockProviderTestBase.getMockString(providerId, id, 
entry, locale);
+            }
+
+            public Map getEntries(String id, Locale locale) throws 
MessageNotFoundException {
+                Map output = new HashMap();
+                output.put("entry1", 
MockProviderTestBase.getMockString(providerId,id,"entry1",locale));
+                output.put("entry2", 
MockProviderTestBase.getMockString(providerId,id,"entry2",locale));
+                return output;
+            }
+        };
+
+        MessageManager.addMessageProvider(providerId, mockMessageProvider);
+    }
+
+    /**
      * Add provider that always throws error to <code>MessageManager</code>.
      */
     protected void addThrowingMockProvider() {
@@ -82,10 +87,19 @@
     // Utility methods
     ////////////////////////////////////////////////////////////////////////
 
+    public static String getMockString(String providerId, String id, String 
entry, Locale locale) throws MessageNotFoundException {
+        return ((providerId != null) ? "Source=" + providerId + " " : "") +
+                "Id=" + id + " Entry=" + entry + " Locale=" + locale + "";
+    }
+
     public static String getMockString(String id, String entry, Locale locale) 
throws MessageNotFoundException {
-        return "Id=" + id + " Entry=" + entry + " Locale=" + locale + "";
+        return getMockString("mock", id, entry, locale);
     }
 
+    public static String getFormattedMockString(String providerId, String id, 
String entry, String[] arguments, Locale locale) {
+        return MessageFormat.format(getMockString(providerId, id, entry, 
locale), arguments);
+    }
+
     public static String getFormattedMockString(String id, String entry, 
String[] arguments, Locale locale) {
         return MessageFormat.format(getMockString(id, entry, locale), 
arguments);
     }
Index: src/test/org/apache/commons/i18n/MessageManagerTest.java
===================================================================
--- src/test/org/apache/commons/i18n/MessageManagerTest.java    (revision 
170884)
+++ src/test/org/apache/commons/i18n/MessageManagerTest.java    (working copy)
@@ -55,26 +55,48 @@
 
         addMockProvider(); // Add mock provider
 
-        assertEquals("Throwing mock not used", "Id=dummyId Entry=dummyEntry 
Locale=en_US",
+        assertEquals("Throwing mock not used", "Source=mock Id=dummyId 
Entry=dummyEntry Locale=en_US",
                 MessageManager.getText("dummyId", "dummyEntry", null, 
Locale.US, "defaultText"));
 
         removeThrowingMockProvider(); // Removing throwing mock and keep only 
normal mock
 
-        assertEquals("Default text not used", "Id=dummyId Entry=dummyEntry 
Locale=en_US",
+        assertEquals("Default text not used", "Source=mock Id=dummyId 
Entry=dummyEntry Locale=en_US",
                 MessageManager.getText("dummyId", "dummyEntry", null, 
Locale.US, "defaultText"));
 
-        assertEquals("Normal lookup", "Id=id Entry=entry Locale=en_US",
+        assertEquals("Normal lookup", "Source=mock Id=id Entry=entry 
Locale=en_US",
                 MessageManager.getText("id", "entry", null, Locale.US));
         assertEquals("Single argument",
-                "Id=id Entry=entry value1 Locale=en_US",
+                "Source=mock Id=id Entry=entry value1 Locale=en_US",
                 MessageManager.getText("id", "entry {0}", new String[] 
{"value1"}, Locale.US));
         assertEquals("Multiple arguments",
-                "Id=id Entry=entry value0: value1 Locale=en_US",
+                "Source=mock Id=id Entry=entry value0: value1 Locale=en_US",
                 MessageManager.getText("id", "entry {0}: {1}", new String[] 
{"value0", "value1"},Locale.US));
 
         assertEquals("Single argument and default",
-                "Id=id Entry=entry value1 Locale=en_US",
+                "Source=mock Id=id Entry=entry value1 Locale=en_US",
                 MessageManager.getText("id", "entry {0}", new String[] 
{"value1"},Locale.US, "defaultText"));
+
+        // Named provider not found
+        try {
+            MessageManager.getText("mockProvider2", "dummyId", "dummyEntry", 
null, Locale.US);
+            fail("Unknown provider should throw Exception");
+        }
+        catch(MessageNotFoundException mnfex) {
+            assertEquals("Error text", "Provider 'mockProvider2' not 
installed", mnfex.getMessage());
+        }
+
+        assertEquals("Default text used", "defaultText",
+                MessageManager.getText("mockProvider2", "dummyId", 
"dummyEntry", null, Locale.US, "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"));
+
+        assertEquals("Normal qualified lookup", "Source=mockProvider2 Id=id 
Entry=entry Locale=en_US",
+                MessageManager.getText("mockProvider2", "id", "entry", null, 
Locale.US));
     }
 
     public void testGetEntries() {
@@ -100,8 +122,8 @@
 
         Map entries = MessageManager.getEntries("dummyId", Locale.US);
         assertEquals("No of entries", 2, entries.size());
-        assertEquals("Entry 1 match", "Id=dummyId Entry=entry1 Locale=en_US", 
entries.get("entry1"));
-        assertEquals("Entry 2 match", "Id=dummyId Entry=entry2 Locale=en_US", 
entries.get("entry2"));
+        assertEquals("Entry 1 match", "Source=mock Id=dummyId Entry=entry1 
Locale=en_US", entries.get("entry1"));
+        assertEquals("Entry 2 match", "Source=mock Id=dummyId Entry=entry2 
Locale=en_US", entries.get("entry2"));
 
         removeThrowingMockProvider(); // Removing throwing mock and keep only 
normal mock
 
@@ -109,7 +131,24 @@
 
         entries = MessageManager.getEntries("dummyId", Locale.US);
         assertEquals("No of entries", 2, entries.size());
-        assertEquals("Entry 1 match", "Id=dummyId Entry=entry1 Locale=en_US", 
entries.get("entry1"));
-        assertEquals("Entry 2 match", "Id=dummyId Entry=entry2 Locale=en_US", 
entries.get("entry2"));
+        assertEquals("Entry 1 match", "Source=mock Id=dummyId Entry=entry1 
Locale=en_US", entries.get("entry1"));
+        assertEquals("Entry 2 match", "Source=mock Id=dummyId Entry=entry2 
Locale=en_US", entries.get("entry2"));
+
+        // Named provider not found
+        try {
+            MessageManager.getEntries("mockProvider2", "dummyId", Locale.US);
+            fail("Unknown provider should throw Exception");
+        }
+        catch(MessageNotFoundException mnfex) {
+            assertEquals("Error text", "Provider 'mockProvider2' not 
installed", mnfex.getMessage());
+        }
+
+        // Named provider found
+        addMockProvider("mockProvider2");
+
+        entries = MessageManager.getEntries("mockProvider2", "dummyId", 
Locale.US);
+        assertEquals("No of entries", 2, entries.size());
+        assertEquals("Entry 1 match", "Source=mockProvider2 Id=dummyId 
Entry=entry1 Locale=en_US", entries.get("entry1"));
+        assertEquals("Entry 2 match", "Source=mockProvider2 Id=dummyId 
Entry=entry2 Locale=en_US", entries.get("entry2"));
     }
 }
\ No newline at end of file
Index: src/test/org/apache/commons/i18n/LocalizedBundleTest.java
===================================================================
--- src/test/org/apache/commons/i18n/LocalizedBundleTest.java   (revision 
170884)
+++ src/test/org/apache/commons/i18n/LocalizedBundleTest.java   (working copy)
@@ -24,21 +24,38 @@
 public class LocalizedBundleTest extends MockProviderTestBase {
     public void testConstructors() {
         LocalizedBundle lb = new LocalizedBundle("dummyId1");
+        assertNull("No provider", lb.getProviderId());
         assertEquals("Id set", "dummyId1", lb.getId());
         assertNotNull("Arguments not null", lb.getArguments());
         assertEquals("No arguments", 0, lb.getArguments().length);
 
+        LocalizedBundle lbProvider = new LocalizedBundle("dummyProvider2", 
"dummyId2");
+        assertEquals("Provider set", "dummyProvider2", 
lbProvider.getProviderId());
+        assertEquals("Id set", "dummyId2", lbProvider.getId());
+        assertNotNull("Arguments not null", lbProvider.getArguments());
+        assertEquals("No arguments", 0, lbProvider.getArguments().length);
+
         String[] arguments = new String[]{"arg1", "arg2"};
-        LocalizedBundle lbArgs = new LocalizedBundle("dummyId2", arguments);
-        assertEquals("Id set", "dummyId2", lbArgs.getId());
+        LocalizedBundle lbArgs = new LocalizedBundle("dummyId3", arguments);
+        assertNull("No provider", lbArgs.getProviderId());
+        assertEquals("Id set", "dummyId3", lbArgs.getId());
         assertNotNull("Arguments not null", lbArgs.getArguments());
         assertEquals("No of arguments", 2, lbArgs.getArguments().length);
         assertEquals("Arguments", arguments, lbArgs.getArguments());
+
+        LocalizedBundle lbProviderArgs = new LocalizedBundle("dummyProvider4", 
"dummyId4", arguments);
+        assertEquals("Provider set", "dummyProvider4", 
lbProviderArgs.getProviderId());
+        assertEquals("Id set", "dummyId4", lbProviderArgs.getId());
+        assertNotNull("Arguments not null", lbProviderArgs.getArguments());
+        assertEquals("No of arguments", 2, 
lbProviderArgs.getArguments().length);
+        assertEquals("Arguments", arguments, lbProviderArgs.getArguments());
     }
 
     public void testGetEntry() {
         LocalizedBundle lb = new LocalizedBundle("dummyId1");
-        LocalizedBundle lbArgs = new LocalizedBundle("dummyId2", new String[] 
{"arg1", "arg2"});
+        LocalizedBundle lbProvider = new LocalizedBundle("dummyProvider2", 
"dummyId2");
+        LocalizedBundle lbArgs = new LocalizedBundle("dummyId3", new String[] 
{"arg1", "arg2"});
+        LocalizedBundle lbProviderArgs = new LocalizedBundle("dummyProvider4", 
"dummyId4", new String[] {"arg1", "arg2"});
 
         // Test errors
         try {
@@ -63,15 +80,53 @@
 
         addMockProvider(); // Add mock provider
 
-        assertEquals("Default text not used", "Id=dummyId1 Entry=dummyEntry 
Locale=en_US",
+        assertEquals("Default text not used", getMockString("dummyId1", 
"dummyEntry", Locale.US),
                 lb.getEntry("dummyEntry", Locale.US, "defaltText"));
 
-        assertEquals("Normal lookup", "Id=dummyId1 Entry=entry Locale=en_US", 
lb.getEntry("entry", Locale.US));
-        assertEquals("Arguments missing", "Id=dummyId1 Entry=entry {0} 
Locale=en_US",
+        assertEquals("Normal lookup", getMockString("dummyId1", "entry", 
Locale.US), lb.getEntry("entry", Locale.US));
+        assertEquals("Arguments missing", "Source=mock Id=dummyId1 Entry=entry 
{0} Locale=en_US",
                 lb.getEntry("entry {0}", Locale.US));
-        assertEquals("Argument", "Id=dummyId2 Entry=entry arg1 arg2 
Locale=en_US",
+        assertEquals("Argument", "Source=mock Id=dummyId3 Entry=entry arg1 
arg2 Locale=en_US",
                 lbArgs.getEntry("entry {0} {1}", Locale.US));
-        assertEquals("Arguments and default", "Id=dummyId2 Entry=entry arg1 
arg2 Locale=en_US",
+        assertEquals("Arguments and default", "Source=mock Id=dummyId3 
Entry=entry arg1 arg2 Locale=en_US",
                 lbArgs.getEntry("entry {0} {1}", Locale.US, "defaultText"));
+
+        // Named provider not found
+        try {
+            lbProvider.getEntry("dummyEntry", Locale.US);
+            fail("Unknown provider should throw Exception");
+        }
+        catch(MessageNotFoundException mnfex) {
+            assertEquals("Error text", "Provider 'dummyProvider2' not 
installed", mnfex.getMessage());
+        }
+
+        try {
+            lbProviderArgs.getEntry("dummyEntry", Locale.US);
+            fail("Unknown provider should throw Exception");
+        }
+        catch(MessageNotFoundException mnfex) {
+            assertEquals("Error text", "Provider 'dummyProvider4' not 
installed", mnfex.getMessage());
+        }
+
+        assertEquals("Default text", "defaultText", 
lbProvider.getEntry("dummyEntry", Locale.US, "defaultText"));
+        assertEquals("Default text", "defaultText", 
lbProviderArgs.getEntry("dummyEntry", Locale.US, "defaultText"));
+
+        // Named provider found
+        addMockProvider("dummyProvider2");
+        addMockProvider("dummyProvider4");
+
+        assertEquals("Named provider: Default text not used",
+                getMockString("dummyProvider2", "dummyId2", "dummyEntry", 
Locale.US),
+                lbProvider.getEntry("dummyEntry", Locale.US, "defaltText"));
+
+        assertEquals("Named provider: Normal lookup", 
getMockString("dummyProvider2", "dummyId2", "entry", Locale.US),
+                lbProvider.getEntry("entry", Locale.US));
+        assertEquals("Named provider: Arguments missing", 
"Source=dummyProvider2 Id=dummyId2 Entry=entry {0} Locale=en_US",
+                lbProvider.getEntry("entry {0}", Locale.US));
+        assertEquals("Named provider: Argument", "Source=dummyProvider4 
Id=dummyId4 Entry=entry arg1 arg2 Locale=en_US",
+                lbProviderArgs.getEntry("entry {0} {1}", Locale.US));
+        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/XMLMessageProviderTest.java
===================================================================
--- src/test/org/apache/commons/i18n/XMLMessageProviderTest.java        
(revision 170884)
+++ src/test/org/apache/commons/i18n/XMLMessageProviderTest.java        
(working copy)
@@ -2,7 +2,7 @@
 *
 * ====================================================================
 *
-* Copyright 2004 The Apache Software Foundation
+* Copyright 2004 The Apache Software Foundation 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -56,12 +56,12 @@
         }
 
         XMLMessageProvider.install("org.apache.commons-i18n.test",
- 
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml"));
+                
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml"));
 
         assertEquals("Hallo Welt", testMessage.getTitle(Locale.GERMAN));
 
         XMLMessageProvider.update("org.apache.commons-i18n.test",
- 
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml"));
+                
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml"));
 
         assertEquals("OK after update", "Hallo Welt", 
testMessage.getTitle(Locale.GERMAN));
 
@@ -77,14 +77,14 @@
 
         // Try to parse non-XML file
         XMLMessageProvider.install("org.apache.commons-i18n.error",
- 
Thread.currentThread().getContextClassLoader().getResourceAsStream("messageBundle.properties"));
+                
Thread.currentThread().getContextClassLoader().getResourceAsStream("messageBundle.properties"));
     }
-
+    
     public void testGetText() {
 //        XMLMessageProvider.install("org.apache.commons-i18n.test",
-// 
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml"));
+//                
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml"));
         XMLMessageProvider xmlmp = new 
XMLMessageProvider("org.apache.commons-i18n.test",
- 
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml"));
+                
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml"));
 
         assertEquals("Default locale", "hello world", 
xmlmp.getText("helloWorld", "title", Locale.US));
         assertEquals("Default locale", "hello world", 
xmlmp.getText("helloWorld", "title", Locale.UK));
@@ -123,9 +123,9 @@
 
     public void testGetTextVariants() {
 //        XMLMessageProvider.install("org.apache.commons-i18n.variants",
-// 
Thread.currentThread().getContextClassLoader().getResourceAsStream("variantTestMessages.xml"));
+//                
Thread.currentThread().getContextClassLoader().getResourceAsStream("variantTestMessages.xml"));
         XMLMessageProvider xmlmp = new 
XMLMessageProvider("org.apache.commons-i18n.variants",
- 
Thread.currentThread().getContextClassLoader().getResourceAsStream("variantTestMessages.xml"));
+                
Thread.currentThread().getContextClassLoader().getResourceAsStream("variantTestMessages.xml"));
 
         assertEquals("hello world", xmlmp.getText("variants", "theKey", 
Locale.ENGLISH));
         assertEquals("Botswana", "Hello Botswana", xmlmp.getText("variants", 
"theKey", new Locale("", "BW")));
@@ -135,9 +135,9 @@
 
     public void testGetEntries() {
 //        XMLMessageProvider.install("org.apache.commons-i18n.test",
-// 
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml"));
+//                
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml"));
         Map usEntries = new XMLMessageProvider("org.apache.commons-i18n.test",
- 
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml")).
+                
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml")).
                     getEntries("helloWorld", Locale.US);
         assertEquals("Default locale, no of entries", 5, usEntries.size());
         assertEquals("Default locale, titel", "hello world", 
usEntries.get("title"));
@@ -151,7 +151,7 @@
         assertEquals("This entry is not translated to any other languages 
(XML)", usEntries.get("notTranslated"));
 
         Map germanEntries = new 
XMLMessageProvider("org.apache.commons-i18n.test",
- 
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml")).
+                
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml")).
                     getEntries("helloWorld", Locale.GERMAN);
         assertEquals("No of entries", 4, germanEntries.size());
         assertEquals("Hallo Welt", germanEntries.get("title"));
@@ -163,7 +163,7 @@
 //        assertEquals("This entry is not translated to any other languages", 
germanEntries.get("notTranslated"));
 
         Map japaneseEntries = new 
XMLMessageProvider("org.apache.commons-i18n.test",
- 
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml")).
+                
Thread.currentThread().getContextClassLoader().getResourceAsStream("testMessages.xml")).
                     getEntries("helloWorld", Locale.JAPANESE);
         assertEquals("Fallback locale, no of entries", 5, 
japaneseEntries.size());
 
Index: src/test/org/apache/commons/i18n/ResourceBundleMessageProviderTest.java
===================================================================
--- src/test/org/apache/commons/i18n/ResourceBundleMessageProviderTest.java     
(revision 170884)
+++ src/test/org/apache/commons/i18n/ResourceBundleMessageProviderTest.java     
(working copy)
@@ -2,7 +2,7 @@
 *
 * ====================================================================
 *
-* Copyright 2004 The Apache Software Foundation
+* Copyright 2004 The Apache Software Foundation 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@
         ResourceBundleMessageProvider.uninstall("messageBundle");
         ResourceBundleMessageProvider.uninstall("messageBundle2");
         ResourceBundleMessageProvider.uninstall("nonExistentBundle");
- 
ResourceBundleMessageProvider.uninstall("org.apache.commons.i18n.MyListResourceBundle");
+        
ResourceBundleMessageProvider.uninstall("org.apache.commons.i18n.MyListResourceBundle");
     }
 
     public void testInstallResourceBundle() {
@@ -89,17 +89,11 @@
 
         // Test with list resource bundle
 //        ResourceBundleMessageProvider.uninstall("messageBundle"); // Remove
-// 
ResourceBundleMessageProvider.install("org.apache.commons.i18n.MyListResourceBundle");
 // Install ListResourceBundle
+//        
ResourceBundleMessageProvider.install("org.apache.commons.i18n.MyListResourceBundle");
 // Install ListResourceBundle
         ResourceBundleMessageProvider listResourceBundleProvider =
                 new 
ResourceBundleMessageProvider("org.apache.commons.i18n.MyListResourceBundle"); 
// Install ListResourceBundle
         assertEquals("Value from ListResourceBundle", "listResourceValue", 
listResourceBundleProvider.getText("helloWorld", "title", Locale.US));
-        try {
-            String s = listResourceBundleProvider.getText("helloWorld", 
"text", Locale.US);
-            fail("Entry should not be found, since it is numeric. Found text: 
" + s);
-        }
-        catch(MessageNotFoundException mnfex) {
-            assertEquals("No message entries found for bundle with key 
helloWorld", mnfex.getMessage());
-        }
+        assertEquals("Value from ListResourceBundle", "1", 
listResourceBundleProvider.getText("helloWorld", "text", Locale.US));
 
         try {
             rbmp.getText("nonExistentId", "nonExistentEntry", Locale.US);
Index: src/test/org/apache/commons/i18n/I18nTestSuite.java
===================================================================
--- src/test/org/apache/commons/i18n/I18nTestSuite.java (revision 170884)
+++ src/test/org/apache/commons/i18n/I18nTestSuite.java (working copy)
@@ -2,7 +2,7 @@
 *
 * ====================================================================
 *
-* Copyright 2004 The Apache Software Foundation
+* Copyright 2004 The Apache Software Foundation 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
Index: src/test/org/apache/commons/i18n/bundles/ErrorBundleTest.java
===================================================================
--- src/test/org/apache/commons/i18n/bundles/ErrorBundleTest.java       
(revision 170884)
+++ src/test/org/apache/commons/i18n/bundles/ErrorBundleTest.java       
(working copy)
@@ -52,6 +52,38 @@
                 eb.getDetails(Locale.US, "defaultText"));
     }
 
+    public void testWithProvider() {
+        addMockProvider(); // Add wrong provider
+        ErrorBundle eb = new ErrorBundle("dummyProvider", "dummyId");
+        try {
+            eb.getText(Locale.US);
+            fail("Entry not found should cause error");
+        }
+        catch(MessageNotFoundException mnfex) {
+            assertEquals("Provider 'dummyProvider' not installed", 
mnfex.getMessage());
+        }
+        assertEquals("Default used", "defaultText", eb.getText(Locale.US, 
"defaultText"));
+
+        addMockProvider("dummyProvider");
+
+        assertEquals("Normal use", getMockString("dummyProvider", "dummyId", 
ErrorBundle.TEXT, Locale.US),
+                eb.getText(Locale.US));
+        assertEquals("Normal use", getMockString("dummyProvider", "dummyId", 
ErrorBundle.TITLE, Locale.US),
+                eb.getTitle(Locale.US));
+        assertEquals("Normal use", getMockString("dummyProvider", "dummyId", 
ErrorBundle.SUMMARY, Locale.US),
+                eb.getSummary(Locale.US));
+        assertEquals("Normal use", getMockString("dummyProvider", "dummyId", 
ErrorBundle.DETAILS, Locale.US),
+                eb.getDetails(Locale.US));
+        assertEquals("Default not used", getMockString("dummyProvider", 
"dummyId", ErrorBundle.TEXT, Locale.US),
+                eb.getText(Locale.US, "defaultText"));
+        assertEquals("Default not used", getMockString("dummyProvider", 
"dummyId", ErrorBundle.TITLE, Locale.US),
+                eb.getTitle(Locale.US, "defaultText"));
+        assertEquals("Default not used", getMockString("dummyProvider", 
"dummyId", ErrorBundle.SUMMARY, Locale.US),
+                eb.getSummary(Locale.US, "defaultText"));
+        assertEquals("Default not used", getMockString("dummyProvider", 
"dummyId", ErrorBundle.DETAILS, Locale.US),
+                eb.getDetails(Locale.US, "defaultText"));
+    }
+
     public void testWithArguments() {
         String[] arguments = new String[]{"arg1", "arg2"};
         ErrorBundle eb = new ErrorBundle("dummyId", arguments);
@@ -83,4 +115,45 @@
         assertEquals("Default not used", getFormattedMockString("dummyId", 
ErrorBundle.DETAILS, arguments, Locale.US),
                 eb.getDetails(Locale.US, "defaultText"));
     }
+
+    public void testWithProviderAndArguments() {
+        addMockProvider(); // Add wrong provider
+        String[] arguments = new String[]{"arg1", "arg2"};
+        ErrorBundle eb = new ErrorBundle("dummyProvider", "dummyId", 
arguments);
+        try {
+            eb.getText(Locale.US);
+            fail("Entry not found should cause error");
+        }
+        catch(MessageNotFoundException mnfex) {
+            assertEquals("Provider 'dummyProvider' not installed", 
mnfex.getMessage());
+        }
+        assertEquals("Default used", "defaultText arg1 arg2", 
eb.getText(Locale.US, "defaultText {0} {1}"));
+
+        addMockProvider("dummyProvider");
+
+        assertEquals("Normal use",
+                getFormattedMockString("dummyProvider", "dummyId", 
ErrorBundle.TEXT, arguments, Locale.US),
+                eb.getText(Locale.US));
+        assertEquals("Normal use",
+                getFormattedMockString("dummyProvider", "dummyId", 
ErrorBundle.TITLE, arguments, Locale.US),
+                eb.getTitle(Locale.US));
+        assertEquals("Normal use",
+                getFormattedMockString("dummyProvider", "dummyId", 
ErrorBundle.SUMMARY, arguments, Locale.US),
+                eb.getSummary(Locale.US));
+        assertEquals("Normal use",
+                getFormattedMockString("dummyProvider", "dummyId", 
ErrorBundle.DETAILS, arguments, Locale.US),
+                eb.getDetails(Locale.US));
+        assertEquals("Default not used",
+                getFormattedMockString("dummyProvider", "dummyId", 
ErrorBundle.TEXT, arguments, Locale.US),
+                eb.getText(Locale.US, "defaultText"));
+        assertEquals("Default not used",
+                getFormattedMockString("dummyProvider", "dummyId", 
ErrorBundle.TITLE, arguments, Locale.US),
+                eb.getTitle(Locale.US, "defaultText"));
+        assertEquals("Default not used",
+                getFormattedMockString("dummyProvider", "dummyId", 
ErrorBundle.SUMMARY, arguments, Locale.US),
+                eb.getSummary(Locale.US, "defaultText"));
+        assertEquals("Default not used",
+                getFormattedMockString("dummyProvider", "dummyId", 
ErrorBundle.DETAILS, arguments, Locale.US),
+                eb.getDetails(Locale.US, "defaultText"));
+    }
 }
\ No newline at end of file
Index: src/test/org/apache/commons/i18n/bundles/MessageBundleTest.java
===================================================================
--- src/test/org/apache/commons/i18n/bundles/MessageBundleTest.java     
(revision 170884)
+++ src/test/org/apache/commons/i18n/bundles/MessageBundleTest.java     
(working copy)
@@ -46,6 +46,30 @@
                 mb.getTitle(Locale.US, "defaultText"));
     }
 
+    public void testWithProvider() {
+        addMockProvider(); // Add wrong provider
+        MessageBundle mb = new MessageBundle("dummyProvider", "dummyId");
+        try {
+            mb.getText(Locale.US);
+            fail("Entry not found should cause error");
+        }
+        catch(MessageNotFoundException mnfex) {
+            assertEquals("Provider 'dummyProvider' not installed", 
mnfex.getMessage());
+        }
+        assertEquals("Default used", "defaultText", mb.getText(Locale.US, 
"defaultText"));
+
+        addMockProvider("dummyProvider");
+
+        assertEquals("Normal use", getMockString("dummyProvider", "dummyId", 
MessageBundle.TEXT, Locale.US),
+                mb.getText(Locale.US));
+        assertEquals("Normal use", getMockString("dummyProvider", "dummyId", 
MessageBundle.TITLE, Locale.US),
+                mb.getTitle(Locale.US));
+        assertEquals("Default not used", getMockString("dummyProvider", 
"dummyId", MessageBundle.TEXT, Locale.US),
+                mb.getText(Locale.US, "defaultText"));
+        assertEquals("Default not used", getMockString("dummyProvider", 
"dummyId", MessageBundle.TITLE, Locale.US),
+                mb.getTitle(Locale.US, "defaultText"));
+    }
+
     public void testWithArguments() {
         String[] arguments = new String[]{"arg1", "arg2"};
         MessageBundle mb = new MessageBundle("dummyId", arguments);
@@ -69,4 +93,33 @@
         assertEquals("Default not used", getFormattedMockString("dummyId", 
MessageBundle.TITLE, arguments, Locale.US),
                 mb.getTitle(Locale.US, "defaultText"));
     }
+
+    public void testWithProviderAndArguments() {
+        addMockProvider(); // Add wrong provider
+        String[] arguments = new String[]{"arg1", "arg2"};
+        MessageBundle mb = new MessageBundle("dummyProvider", "dummyId", 
arguments);
+        try {
+            mb.getText(Locale.US);
+            fail("Entry not found should cause error");
+        }
+        catch(MessageNotFoundException mnfex) {
+            assertEquals("Provider 'dummyProvider' not installed", 
mnfex.getMessage());
+        }
+        assertEquals("Default used", "defaultText arg1 arg2", 
mb.getText(Locale.US, "defaultText {0} {1}"));
+
+        addMockProvider("dummyProvider");
+
+        assertEquals("Normal use",
+                getFormattedMockString("dummyProvider", "dummyId", 
MessageBundle.TEXT, arguments, Locale.US),
+                mb.getText(Locale.US));
+        assertEquals("Normal use",
+                getFormattedMockString("dummyProvider", "dummyId", 
MessageBundle.TITLE, arguments, Locale.US),
+                mb.getTitle(Locale.US));
+        assertEquals("Default not used",
+                getFormattedMockString("dummyProvider", "dummyId", 
MessageBundle.TEXT, arguments, Locale.US),
+                mb.getText(Locale.US, "defaultText"));
+        assertEquals("Default not used",
+                getFormattedMockString("dummyProvider", "dummyId", 
MessageBundle.TITLE, arguments, Locale.US),
+                mb.getTitle(Locale.US, "defaultText"));
+    }
 }
Index: src/test/org/apache/commons/i18n/bundles/TextBundleTest.java
===================================================================
--- src/test/org/apache/commons/i18n/bundles/TextBundleTest.java        
(revision 170884)
+++ src/test/org/apache/commons/i18n/bundles/TextBundleTest.java        
(working copy)
@@ -43,6 +43,26 @@
                 textBundle.getText(Locale.US, "defaultText"));
     }
 
+    public void testWithProvider() {
+        addMockProvider(); // Add wrong provider
+        TextBundle textBundle = new TextBundle("dummyProvider", "dummyId");
+        try {
+            textBundle.getText(Locale.US);
+            fail("Entry not found should cause error");
+        }
+        catch(MessageNotFoundException mnfex) {
+            assertEquals("Provider 'dummyProvider' not installed", 
mnfex.getMessage());
+        }
+        assertEquals("Default used", "defaultText", 
textBundle.getText(Locale.US, "defaultText"));
+
+        addMockProvider("dummyProvider");
+
+        assertEquals("Normal use", getMockString("dummyProvider", "dummyId", 
TextBundle.TEXT, Locale.US),
+                textBundle.getText(Locale.US));
+        assertEquals("Default not used", getMockString("dummyProvider", 
"dummyId", TextBundle.TEXT, Locale.US),
+                textBundle.getText(Locale.US, "defaultText"));
+    }
+
     public void testWithArguments() {
         String[] arguments = new String[]{"arg1", "arg2"};
         TextBundle textBundle = new TextBundle("dummyId", arguments);
@@ -62,4 +82,26 @@
         assertEquals("Default not used", getFormattedMockString("dummyId", 
TextBundle.TEXT, arguments, Locale.US),
                 textBundle.getText(Locale.US, "defaultText"));
     }
-}
+
+    public void testWithProviderAndArguments() {
+        addMockProvider(); // Add wrong provider
+        String[] arguments = new String[]{"arg1", "arg2"};
+        TextBundle textBundle = new TextBundle("dummyProvider", "dummyId", 
arguments);
+        try {
+            textBundle.getText(Locale.US);
+            fail("Entry not found should cause error");
+        }
+        catch(MessageNotFoundException mnfex) {
+            assertEquals("Provider 'dummyProvider' not installed", 
mnfex.getMessage());
+        }
+        assertEquals("Default used", "defaultText arg1 arg2", 
textBundle.getText(Locale.US, "defaultText {0} {1}"));
+
+        addMockProvider("dummyProvider");
+
+        assertEquals("Normal use",
+                getFormattedMockString("dummyProvider", "dummyId", 
TextBundle.TEXT, arguments, Locale.US),
+                textBundle.getText(Locale.US));
+        assertEquals("Default not used",
+                getFormattedMockString("dummyProvider", "dummyId", 
TextBundle.TEXT, arguments, Locale.US),
+                textBundle.getText(Locale.US, "defaultText"));
+    }}
Index: src/java/org/apache/commons/i18n/MessageManager.java
===================================================================
--- src/java/org/apache/commons/i18n/MessageManager.java        (revision 
170884)
+++ src/java/org/apache/commons/i18n/MessageManager.java        (working copy)
@@ -74,6 +74,14 @@
     }
 
     /**
+     * Remove all <code>[EMAIL PROTECTED] MessageProvider}</code>s from the
+     * <code>MessageManager</code>. Used for tearing down unit tests.
+     */
+    static void clearMessageProviders() {
+        messageProviders.clear();
+    }
+
+    /**
      * Remove custom <code>[EMAIL PROTECTED] MessageProvider}</code> from the
      * <code>MessageManager</code>. Used for tearing down unit tests.
      *
@@ -82,6 +90,7 @@
     static void removeMessageProvider(String providerId) {
         messageProviders.remove(providerId);
     }
+
     /**
      * Iterates over all registered message providers in order to find the 
given
      * entry in the requested message bundle.
@@ -149,6 +158,64 @@
     }
 
     /**
+     * Tries to find the desired entry in the named message provider.
+     * @param providerId The name of the message provider (i.e. source) to use 
for the message
+     * @param id
+     *            The identifier that will be used to retrieve the message
+     *            bundle
+     * @param entry
+     *            The desired message entry
+     * @param arguments
+     *            The dynamic parts of the message that will be evaluated using
+     *            the standard java text formatting abilities.
+     * @param locale
+     *            The locale 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
+     *                message entry is missing in the retrieved bundle
+     * @return The localized text
+     */
+    public static String getText(String providerId, String id, String entry, 
Object[] arguments,
+            Locale locale) 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);
+        return MessageFormat.format(text, arguments);
+    }
+
+    /**
+     * Iterates over all registered message providers in order to find the 
given
+     * entry in the requested message bundle.
+     *
+     * @param providerId The name of the message provider (i.e. source) to use 
for the message
+     * @param id
+     *            The identifier that will be used to retrieve the message
+     *            bundle
+     * @param entry
+     *            The desired message entry
+     * @param arguments
+     *            The dynamic parts of the message that will be evaluated using
+     *            the standard java text formatting abilities.
+     * @param locale
+     *            The locale 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.
+     * @return The localized text or the default text if the message could not
+     *         be found
+     */
+    public static String getText(String providerId, String id, String entry, 
Object[] arguments,
+            Locale locale, String defaultText) {
+        try {
+            return getText(providerId, id, entry, arguments, locale);
+        } catch (MessageNotFoundException e) {
+            return MessageFormat.format(defaultText, arguments);
+        }
+    }
+
+    /**
      * Returns a map containing all available message entries for the given
      * locale. The map contains keys of type [EMAIL PROTECTED] 
String}containing the keys
      * of the available message entries and values of type [EMAIL PROTECTED] 
String}
@@ -168,4 +235,18 @@
         }
         throw exception;
     }
+
+  /**
+   * Returns a map containing all available message entries for the given
+   * locale. The map contains keys of type [EMAIL PROTECTED] String}containing 
the keys
+   * of the available message entries and values of type [EMAIL PROTECTED] 
String}
+   * containing the localized message entries.
+   */
+  public static Map getEntries(String providerId, String id, Locale locale)
+          throws MessageNotFoundException {
+      MessageProvider provider = (MessageProvider) 
messageProviders.get(providerId);
+      if(provider == null)
+          throw new MessageNotFoundException("Provider '" + providerId + "' 
not installed");
+      return provider.getEntries(id, locale);
+  }
 }
\ No newline at end of file
Index: src/java/org/apache/commons/i18n/LocalizedBundle.java
===================================================================
--- src/java/org/apache/commons/i18n/LocalizedBundle.java       (revision 
170884)
+++ src/java/org/apache/commons/i18n/LocalizedBundle.java       (working copy)
@@ -42,16 +42,25 @@
 public class LocalizedBundle implements Serializable {
     public final static String ID = "id";
 
+    protected String providerId;
     protected String id;
     protected Object[] arguments;
 
+  /**
+   * @param providerId The name of the message provider (i.e. source) to use 
for the message
+   * @param messageId The messageId refers the corresponding bundle in the 
file containing
+   * the localized messages.
+   */
+  public LocalizedBundle(String providerId, String messageId) {
+      this(providerId, messageId, new Object[0]);
+  }
+
     /**
      * @param messageId The messageId refers the corresponding bundle in the 
file containing
      * the localized messages.
      */
     public LocalizedBundle(String messageId) {
-        this.id = messageId;
-        this.arguments = new Object[0];
+        this(messageId, new Object[0]);
     }
 
     /**
@@ -65,6 +74,19 @@
         this.arguments = arguments;
     }
 
+  /**
+   * @param providerId The name of the message provider (i.e. source) to use 
for the message
+   * @param messageId The messageId refers the corresponding bundle in the 
file containing
+   * the localized messages.
+   * @param arguments An array of objects containing arguments for the 
messages. These arguments
+   * are used to insert dynamic values into the localized messages.
+   */
+  public LocalizedBundle(String providerId, String messageId, Object[] 
arguments) {
+    this.providerId = providerId;
+    this.id = messageId;
+      this.arguments = arguments;
+  }
+
     /**
      * @return returns the id of this bundle
      */
@@ -78,8 +100,15 @@
     public Object[] getArguments() {
        return arguments;
     }
-    
+
     /**
+     * @return The name of the message provider (i.e. source) to use for the 
message  
+     */
+    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
      * @return returns the text of the desired message entry for the given 
locale  
@@ -87,7 +116,9 @@
      * in this bundle
      */
     public String getEntry(String key, Locale locale) throws 
MessageNotFoundException {
-        return MessageManager.getText(id, key, arguments, locale);
+        return providerId != null ?
+            MessageManager.getText(providerId, id, key, arguments, locale) :
+            MessageManager.getText(id, key, arguments, locale);
     }
 
     /**
@@ -97,6 +128,8 @@
      * @return returns the text of the desired message entry for the given 
locale  
      */
     public String getEntry(String key, Locale locale, String defaultText) {
-        return MessageManager.getText(id, key, arguments, locale, defaultText);
+        return providerId != null ?
+            MessageManager.getText(providerId, id, key, arguments, locale, 
defaultText) :
+            MessageManager.getText(id, key, arguments, locale, defaultText);
     }
 }
\ No newline at end of file
Index: src/java/org/apache/commons/i18n/ResourceBundleMessageProvider.java
===================================================================
--- src/java/org/apache/commons/i18n/ResourceBundleMessageProvider.java 
(revision 170884)
+++ src/java/org/apache/commons/i18n/ResourceBundleMessageProvider.java 
(working copy)
@@ -47,12 +47,9 @@
      * @see org.apache.commons.i18n.MessageProvider#getText(java.lang.String, 
java.lang.String, java.util.Locale)
      */
     public String getText(String id, String entry, Locale locale) throws 
MessageNotFoundException {
-        // TODO: Revise try/catch
         try {
             ResourceBundle resourceBundle = ResourceBundle.getBundle(baseName, 
locale);
-             return resourceBundle.getString(id+"."+entry);
-        } catch ( ClassCastException e ) {
-            // ignore all entries that are not of type String
+             return resourceBundle.getObject(id+"."+entry).toString();
         }
         catch ( MissingResourceException e ) {
             logger.log(
Index: src/java/org/apache/commons/i18n/bundles/ErrorBundle.java
===================================================================
--- src/java/org/apache/commons/i18n/bundles/ErrorBundle.java   (revision 
170884)
+++ src/java/org/apache/commons/i18n/bundles/ErrorBundle.java   (working copy)
@@ -45,6 +45,14 @@
     }
 
     /**
+     * @param providerId The name of the message provider (i.e. source) to use 
for the message
+     * @param messageId Unique message id that identifies the message
+     */
+    public ErrorBundle(String providerId, String messageId) {
+        super(providerId, messageId);
+    }
+
+    /**
      * @param messageId Unique message id that identifies the message 
      * @param arguments An array of objects conaining the values that should be
      * inserted into the localized message.  
@@ -54,6 +62,16 @@
     }
 
     /**
+     * @param providerId The name of the message provider (i.e. source) to use 
for the message
+     * @param messageId Unique message id that identifies the message
+     * @param arguments An array of objects conaining the values that should be
+     * inserted into the localized message.
+     */
+    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 
      * @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
Index: src/java/org/apache/commons/i18n/bundles/TextBundle.java
===================================================================
--- src/java/org/apache/commons/i18n/bundles/TextBundle.java    (revision 
170884)
+++ src/java/org/apache/commons/i18n/bundles/TextBundle.java    (working copy)
@@ -44,6 +44,14 @@
     }
 
     /**
+     * @param providerId The name of the message provider (i.e. source) to use 
for the message
+     * @param messageId Unique message id that identifies the message
+     */
+    public TextBundle(String providerId, String messageId) {
+        super(providerId, messageId);
+    }
+
+    /**
      * @param messageId Unique message id that identifies the message 
      * @param arguments An array of objects conaining the values that should be
      * inserted into the localized message.  
@@ -53,6 +61,16 @@
     }
 
     /**
+     * @param providerId The name of the message provider (i.e. source) to use 
for the message
+     * @param messageId Unique message id that identifies the message
+     * @param arguments An array of objects conaining the values that should be
+     * inserted into the localized message.
+     */
+    public TextBundle(String providerId, String messageId, Object[] arguments) 
{
+        super(providerId, messageId, arguments);
+    }
+
+    /**
      * @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
Index: src/java/org/apache/commons/i18n/bundles/MessageBundle.java
===================================================================
--- src/java/org/apache/commons/i18n/bundles/MessageBundle.java (revision 
170884)
+++ src/java/org/apache/commons/i18n/bundles/MessageBundle.java (working copy)
@@ -42,6 +42,14 @@
     }
 
     /**
+     * @param providerId The name of the message provider (i.e. source) to use 
for the message
+     * @param messageId Unique message id that identifies the message
+     */
+    public MessageBundle(String providerId, String messageId) {
+        super(providerId, messageId);
+    }
+
+    /**
      * @param messageId Unique message id that identifies the message 
      * @param arguments An array of objects conaining the values that should be
      * inserted into the localized message.  
@@ -50,6 +58,15 @@
         super(messageId, arguments);
     }
 
+    /**
+     * @param providerId The name of the message provider (i.e. source) to use 
for the message
+     * @param messageId Unique message id that identifies the message
+     * @param arguments An array of objects conaining the values that should be
+     * inserted into the localized message.
+     */
+    public MessageBundle(String providerId, String messageId, Object[] 
arguments) {
+        super(providerId, messageId, arguments);
+    }
 
     /**
      * @param locale The locale that is used to find the appropriate localized 
text 


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to