IE, Chrome, Firefox plugins: gracefully disconnect when server connection drops.

1) Plugins fails gracefully in the face of a disconnect, returning undefined instead of making lots of noise.

2) Plugins invokes hosted.html's __gwt_disconnected() method the first time the session is detected as dropped.  This glasspanels the app.

Review by: jat

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7129 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/plugins/xpcom/FFSessionHandler.cpp b/plugins/xpcom/FFSessionHandler.cpp
index a2b5cc4..b7ad7ff 100755
--- a/plugins/xpcom/FFSessionHandler.cpp
+++ b/plugins/xpcom/FFSessionHandler.cpp
@@ -128,6 +128,26 @@
   }
 }
 
+void FFSessionHandler::disconnectDetectedImpl() {
+  JSContext* ctx = getJSContext();
+  if (!ctx) {
+    return;
+  }
+
+  Debug::log(Debug::Debugging) << "Getting function \"__gwt_disconnected\""
+        << Debug::flush;
+
+  jsval funcVal;
+  if (!JS_GetProperty(ctx, global, "__gwt_disconnected", &funcVal)
+      || funcVal == JSVAL_VOID) {
+    Debug::log(Debug::Error) << "Could not get function \"__gwt_disconnected\""
+        << Debug::flush;
+    return;
+  }
+  jsval rval;
+  JS_CallFunctionValue(ctx, global, funcVal, 0, 0, &rval);
+}
+
 void FFSessionHandler::freeValue(HostChannel& channel, int idCount, const int* ids) {
   Debug::DebugStream& dbg = Debug::log(Debug::Spam)
       << "FFSessionHandler::freeValue [ ";
diff --git a/plugins/xpcom/FFSessionHandler.h b/plugins/xpcom/FFSessionHandler.h
index f7fec2b..1da4288 100755
--- a/plugins/xpcom/FFSessionHandler.h
+++ b/plugins/xpcom/FFSessionHandler.h
@@ -41,6 +41,7 @@
   void disconnect();
 
 protected:
+  virtual void disconnectDetectedImpl();
   virtual void freeValue(HostChannel& channel, int idCount, const int* ids);
   virtual void loadJsni(HostChannel& channel, const std::string& js);
   virtual bool invoke(HostChannel& channel, const Value& thisObj, const std::string& methodName,
diff --git a/plugins/xpcom/JavaObject.cpp b/plugins/xpcom/JavaObject.cpp
index 638094f..ca0104b 100644
--- a/plugins/xpcom/JavaObject.cpp
+++ b/plugins/xpcom/JavaObject.cpp
@@ -359,17 +359,21 @@
   for (int i = 0; i < numArgs; ++i) {
     data->makeValueFromJsval(args[i], ctx, jsargs[i]);
   }
+
+  bool isException = false;
+  Value returnValue;
   if (!InvokeMessage::send(*channel, javaThis, dispId, numArgs, args.get())) {
     Debug::log(Debug::Debugging) << "JavaObject::call failed to send invoke message" << Debug::flush;
-    return false;
+  } else {
+    Debug::log(Debug::Spam) << " return from invoke" << Debug::flush;
+    scoped_ptr<ReturnMessage> retMsg(channel->reactToMessagesWhileWaitingForReturn(handler));
+    if (!retMsg.get()) {
+      Debug::log(Debug::Debugging) << "JavaObject::call failed to get return value" << Debug::flush;
+    } else {
+      isException = retMsg->isException();
+      returnValue = retMsg->getReturnValue();
+    }
   }
-  Debug::log(Debug::Spam) << " return from invoke" << Debug::flush;
-  scoped_ptr<ReturnMessage> retMsg(channel->reactToMessagesWhileWaitingForReturn(handler));
-  if (!retMsg.get()) {
-    Debug::log(Debug::Debugging) << "JavaObject::call failed to get return value" << Debug::flush;
-    return false;
-  }
-  Value returnValue = retMsg->getReturnValue();
   // Since we can set exceptions normally, we always return false to the
   // wrapper function and set the exception ourselves if one occurs.
   // TODO: cleanup exception case
@@ -379,7 +383,7 @@
   jsval retJsVal;
   Debug::log(Debug::Spam) << "  result is " << returnValue << Debug::flush;
   data->makeJsvalFromValue(retJsVal, ctx, returnValue);
-  if (retMsg->isException()) {
+  if (isException) {
     JS_SetPendingException(ctx, retJsVal);
     return false;
   }