Fix handling of onModuleLoad errors, handle HelpInfo with null URLs,
reduce log levels of method invocations, minor cleanups.

Patch by: jat
Review by: rdayal


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7094 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java b/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java
index 5e536fd..9d1ff60 100644
--- a/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java
+++ b/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java
@@ -264,7 +264,8 @@
      * @param sessionKey opaque key for this session, null if using an old plugin
      * @param userAgentIcon byte array containing an icon (which fits within
      *     24x24) representing the user agent or null if unavailable
-     * @return a TreeLogger to use for the module's logs
+     * @return a TreeLogger to use for the module's logs, or null if the module
+     *     load failed
      */
     public abstract TreeLogger loadModule(BrowserChannel channel,
         String moduleName, String userAgent, String url, String tabKey,
@@ -1290,6 +1291,13 @@
    * <p>See {@link UserAgentIconMessage}.
    */
   protected static class RequestIconMessage extends Message {
+
+    /**
+     * Receive a RequestIconMessage, assuming the message tag has already been
+     * read.
+     * 
+     * @throws IOException
+     */
     public static RequestIconMessage receive(BrowserChannel channel)
         throws IOException {
       return new RequestIconMessage(channel);
@@ -1603,8 +1611,7 @@
   }
 
   protected BrowserChannel(InputStream inputStream, OutputStream outputStream,
-      ObjectRefFactory objectRefFactory)
-      throws IOException {
+      ObjectRefFactory objectRefFactory) {
     streamFromOtherSide = new DataInputStream(inputStream);
     streamToOtherSide = new DataOutputStream(outputStream);
     socket = null;
@@ -1684,10 +1691,11 @@
    * React to messages from the other side, where a return value is expected.
    * 
    * @param handler
+   * @throws BrowserChannelException 
    * @throws RemoteDeathError
    */
   public ReturnMessage reactToMessagesWhileWaitingForReturn(
-      SessionHandler handler) {
+      SessionHandler handler) throws BrowserChannelException, RemoteDeathError {
     do {
       try {
         getStreamToOtherSide().flush();
diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java b/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java
index b9c062a..682ce65 100644
--- a/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java
+++ b/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java
@@ -105,7 +105,7 @@
   // @VisibleForTesting
   BrowserChannelServer(TreeLogger initialLogger, InputStream inputStream,
       OutputStream outputStream, SessionHandler handler,
-      boolean ignoreRemoteDeath) throws IOException {
+      boolean ignoreRemoteDeath) {
     super(inputStream, outputStream, new ServerObjectRefFactory());
     this.handler = handler;
     this.ignoreRemoteDeath = ignoreRemoteDeath;
@@ -166,30 +166,34 @@
       Value returnValue = msg.getReturnValue();
       convertToJsValue(ccl, remoteObjects, returnValue, returnJsValue);
       if (msg.isException()) {
+        Object exceptionValue;
         if (returnValue.isNull() || returnValue.isUndefined()) {
-          throw ModuleSpace.createJavaScriptException(ccl, null);
-
+          exceptionValue = null;
         } else if (returnValue.isString()) {
-          throw ModuleSpace.createJavaScriptException(ccl,
-              returnValue.getString());
-
+          exceptionValue = returnValue.getString();
         } else if (returnValue.isJsObject()) {
-          Object jso = JsValueGlue.createJavaScriptObject(returnJsValue, ccl);
-          throw ModuleSpace.createJavaScriptException(ccl, jso);
-
+          exceptionValue = JsValueGlue.createJavaScriptObject(returnJsValue,
+              ccl);
         } else if (returnValue.isJavaObject()) {
           Object object = remoteObjects.get(returnValue.getJavaObject().getRefid());
           Object target = ((JsValueOOPHM.DispatchObjectOOPHM) object).getTarget();
           if (target instanceof Throwable) {
             throw (Throwable) (target);
           } else {
-            // JS throwing random Java Objects, which we'll wrap is JSException
-            throw ModuleSpace.createJavaScriptException(ccl, target);
+            // JS throwing random Java Objects, which we'll wrap in JSException
+            exceptionValue = target;
           }
+        } else {
+          // JS throwing random primitives, which we'll wrap as a string in
+          // JSException
+          exceptionValue = returnValue.getValue().toString();
         }
-        // JS throwing random primitives, which we'll wrap is JSException
-        throw ModuleSpace.createJavaScriptException(ccl,
-            returnValue.getValue().toString());
+        RuntimeException exception = ModuleSpace.createJavaScriptException(
+            ccl, exceptionValue);
+        // reset the stack trace to here to minimize GWT infrastructure in
+        // the stack trace
+        exception.fillInStackTrace();
+        throw exception;
       }
     } catch (IOException e) {
       throw new RemoteDeathError(e);
@@ -375,6 +379,18 @@
         + " @ " + sessionKey);
     logger = handler.loadModule(this, moduleName, userAgent, url,
         tabKey, sessionKey, iconBytes);
+    if (logger == null) {
+      // got an error
+      try {
+        Value errMsg = new Value();
+        errMsg.setString("An error occurred loading the GWT module "
+            + moduleName);
+        ReturnMessage.send(this, true, errMsg);
+        return;
+      } catch (IOException e) {
+        throw new RemoteDeathError(e);
+      }
+    }
     try {
       // send LoadModule response
       try {
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
index b069fd1..d9dc1de 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
@@ -60,7 +60,8 @@
     try {
       Class<?> javaScriptExceptionClass = Class.forName(
           "com.google.gwt.core.client.JavaScriptException", true, cl);
-      Constructor<?> ctor = javaScriptExceptionClass.getDeclaredConstructor(Object.class);
+      Constructor<?> ctor = javaScriptExceptionClass.getDeclaredConstructor(
+          Object.class);
       return (RuntimeException) ctor.newInstance(new Object[] {exception});
     } catch (InstantiationException e) {
       caught = e;
@@ -123,17 +124,14 @@
 
   protected final ModuleSpaceHost host;
 
-  private final Object key;
-
   private final TreeLogger logger;
 
   private final String moduleName;
 
   protected ModuleSpace(TreeLogger logger, ModuleSpaceHost host,
-      String moduleName, Object key) {
+      String moduleName) {
     this.host = host;
     this.moduleName = moduleName;
-    this.key = key;
     this.logger = logger;
     threadLocalLogger.set(host.getLogger());
   }
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
index 4f34e52..6e877e4 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
@@ -30,7 +30,7 @@
 
   public ModuleSpaceOOPHM(ModuleSpaceHost msh, String moduleName,
       BrowserChannelServer channel) {
-    super(msh.getLogger(), msh, moduleName, moduleName);
+    super(msh.getLogger(), msh, moduleName);
     this.channel = channel;
     msh.getLogger().log(TreeLogger.DEBUG,
         "Created ModuleSpaceOOPHM for " + moduleName, null);
diff --git a/dev/core/src/com/google/gwt/dev/shell/OophmSessionHandler.java b/dev/core/src/com/google/gwt/dev/shell/OophmSessionHandler.java
index 91482e9..a1f2200 100644
--- a/dev/core/src/com/google/gwt/dev/shell/OophmSessionHandler.java
+++ b/dev/core/src/com/google/gwt/dev/shell/OophmSessionHandler.java
@@ -115,7 +115,7 @@
     serverChannel.convertToJsValue(cl, localObjects, thisVal, jsThis);
 
     TreeLogger branch = TreeLogger.NULL;
-    if (logger.isLoggable(TreeLogger.DEBUG)) {
+    if (logger.isLoggable(TreeLogger.SPAM)) {
       StringBuffer logMsg = new StringBuffer();
       logMsg.append("Client invoke of ");
       logMsg.append(methodDispatchId);
@@ -130,13 +130,13 @@
       }
       logMsg.append(" on ");
       logMsg.append(jsThis.toString());
-      branch = logger.branch(TreeLogger.DEBUG, logMsg.toString(), null);
+      branch = logger.branch(TreeLogger.SPAM, logMsg.toString(), null);
     }
     JsValueOOPHM[] jsArgs = new JsValueOOPHM[args.length];
     for (int i = 0; i < args.length; ++i) {
       jsArgs[i] = new JsValueOOPHM();
       serverChannel.convertToJsValue(cl, localObjects, args[i], jsArgs[i]);
-      branch.log(TreeLogger.DEBUG, " arg " + i + " = " + jsArgs[i].toString(),
+      branch.log(TreeLogger.SPAM, " arg " + i + " = " + jsArgs[i].toString(),
           null);
     }
     JsValueOOPHM jsRetVal = new JsValueOOPHM();
@@ -196,6 +196,7 @@
       moduleHandle.unload();
       moduleMap.remove(serverChannel);
       moduleHandleMap.remove(serverChannel);
+      return null;
     } finally {
       PerfLogger.end();
       PerfLogger.end();
diff --git a/dev/core/src/com/google/gwt/dev/shell/log/SwingTreeLogger.java b/dev/core/src/com/google/gwt/dev/shell/log/SwingTreeLogger.java
index 30aef66..c5faf8e 100644
--- a/dev/core/src/com/google/gwt/dev/shell/log/SwingTreeLogger.java
+++ b/dev/core/src/com/google/gwt/dev/shell/log/SwingTreeLogger.java
@@ -176,7 +176,7 @@
       if (helpInfo != null) {
         URL url = helpInfo.getURL();
         String anchorText = helpInfo.getAnchorText();
-        if (anchorText == null) {
+        if (anchorText == null && url != null) {
           anchorText = url.toExternalForm();
         }
         String prefix = helpInfo.getPrefix();