Adding diagnostic information when a MissingResourceException is thrown.

Patch by: amitmanjhi
Review by: jat



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5487 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/i18n/client/Dictionary.java b/user/src/com/google/gwt/i18n/client/Dictionary.java
index dbeb7e5..5810a61 100644
--- a/user/src/com/google/gwt/i18n/client/Dictionary.java
+++ b/user/src/com/google/gwt/i18n/client/Dictionary.java
@@ -102,6 +102,7 @@
         null, name);
   }
 
+  private JavaScriptObject accessedKeys;
   private JavaScriptObject dict;
 
   private String label;
@@ -123,8 +124,13 @@
           "Cannot find JavaScript object with the name '" + name + "'", name,
           null);
     }
+    createAccessedKeysArray();
   }
 
+  private native void createAccessedKeysArray() /*-{
+    this.@com.google.gwt.i18n.client.Dictionary::accessedKeys = new Array();
+  }-*/;
+
   /**
    * Get the value associated with the given Dictionary key.
    * 
@@ -138,6 +144,12 @@
    */
   public native String get(String key) /*-{
    var value = this.@com.google.gwt.i18n.client.Dictionary::dict[key];
+   var keys = this.@com.google.gwt.i18n.client.Dictionary::accessedKeys;
+   keys.unshift(key);
+   // only keep the last 30 elements. Shrink it when array exceeds 60
+   if (keys.length > 60) {
+     keys.splice(30);
+   }
    if (value == null || !Object.prototype.hasOwnProperty.call(
        this.@com.google.gwt.i18n.client.Dictionary::dict, key))
    {
@@ -179,6 +191,7 @@
     if (s.size() < MAX_KEYS_TO_SHOW) {
       error += "\n keys found: " + s;
     }
+    error += "\n accessed keys: " + accessedKeys;
     throw new MissingResourceException(error, this.toString(), key);
   }
 
diff --git a/user/test/com/google/gwt/i18n/client/I18NTest.java b/user/test/com/google/gwt/i18n/client/I18NTest.java
index e24ad99..c75631a 100644
--- a/user/test/com/google/gwt/i18n/client/I18NTest.java
+++ b/user/test/com/google/gwt/i18n/client/I18NTest.java
@@ -421,6 +421,46 @@
     assertTrue(s.contains("a"));
     assertTrue(s.contains("b"));
     assertFalse(s.contains("c"));
+    String nonExistentKey = "nonExistentKey";
+    try {
+      d.get(nonExistentKey);
+      fail("should have thrown a MissingResourceException");
+    } catch (MissingResourceException ex) {
+      assertTrue(ex.getMessage(), ex.getMessage().indexOf(
+          "accessed keys: " + nonExistentKey + ",d,formattedMessage") != -1);
+    }
+
+    /*
+     * verify that accessedKeys maintains at least the last 30 entries in the
+     * correct order. Steps involved: (i) create expectedKeys array, (ii) access
+     * the dictionary, (iii) confirm that accessedKeys is maintained correctly.
+     */
+    // expectedKeys: nonExistentKey, 9 a's, 9 b's, 9 d's, 2 formattedMessage's
+    StringBuffer expectedKeys = new StringBuffer();
+    expectedKeys.append(nonExistentKey);
+    for (String key : new String[] {"a", "b", "d"}) {
+      for (int i = 0; i < 9; i++) {
+        expectedKeys.append(",");
+        expectedKeys.append(key);
+      }
+    }
+    expectedKeys.append(",formattedMessage,formattedMessage");
+    // access 360 keys. last 30 should match expectedKeys
+    for (int i = 0; i < 10; i++) {
+      for (String key : new String[] {"formattedMessage", "d", "b", "a"}) {
+        for (int j = 0; j < 9; j++) {
+          d.get(key);
+        }
+      }
+    }
+    try {
+      d.get(nonExistentKey);
+      fail("should have thrown a MissingResourceException");
+    } catch (MissingResourceException ex) {
+      assertTrue(ex.getMessage(), ex.getMessage().indexOf(
+          "accessed keys: " + expectedKeys.toString()) != -1);
+    }
+
     Collection<String> s2 = d.values();
     assertTrue(s2.contains("A"));
     assertTrue(s2.contains("B"));