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/npapi/LocalObjectTable.h b/plugins/npapi/LocalObjectTable.h
index 7d95509..1fa69c2 100644
--- a/plugins/npapi/LocalObjectTable.h
+++ b/plugins/npapi/LocalObjectTable.h
@@ -38,8 +38,7 @@
   }
 
 public:
-  LocalObjectTable() {
-    dontFree = false;
+  LocalObjectTable(): nextId(0), dontFree(false) {
   }
 
   virtual ~LocalObjectTable();
@@ -68,11 +67,11 @@
       Debug::log(Debug::Error) << "Freeing freed object slot " << id << Debug::flush;
       return;
     }
-    setFree(id);
     if (!dontFree) {
       NPObject* obj = it->second;
       NPN_ReleaseObject(obj);
     }
+    setFree(id);
   }
 
   void freeAll() {
diff --git a/plugins/npapi/ScriptableInstance.cpp b/plugins/npapi/ScriptableInstance.cpp
index 6149ffc..273fd8a 100644
--- a/plugins/npapi/ScriptableInstance.cpp
+++ b/plugins/npapi/ScriptableInstance.cpp
@@ -63,6 +63,7 @@
     connectedID(NPN_GetStringIdentifier("connected")),

     statsID(NPN_GetStringIdentifier("stats")),

     gwtId(NPN_GetStringIdentifier("__gwt_ObjectId")),

+    jsDisconnectedID(NPN_GetStringIdentifier("__gwt_disconnected")),

     jsInvokeID(NPN_GetStringIdentifier("__gwt_jsInvoke")),

     jsResultID(NPN_GetStringIdentifier("__gwt_makeResult")),

     jsTearOffID(NPN_GetStringIdentifier("__gwt_makeTearOff")),

@@ -542,24 +543,27 @@
   for (unsigned i = 0; i < numArgs; ++i) {

     vargs[i] = NPVariantProxy::getAsValue(args[i], *this);

   }

+  bool isException = false;

+  Value returnValue;

   if (!InvokeMessage::send(*_channel, javaThis, dispId, numArgs, vargs.get())) {

     Debug::log(Debug::Error) << "JavaObject_invoke: failed to send invoke message" << Debug::flush;

-    // TODO(jat): returning false here spams the browser console

-    return true;

-  }

-  Debug::log(Debug::Debugging) << " return from invoke" << Debug::flush;

-  scoped_ptr<ReturnMessage> retMsg(_channel->reactToMessagesWhileWaitingForReturn(this));

-  if (!retMsg.get()) {

-    Debug::log(Debug::Error) << "JavaObject_invoke: failed to get return value" << Debug::flush;

-    return false;

-  }

-  if (isRawToString) {

-    // toString() needs the raw value

-    NPVariantProxy::assignFrom(*this, *result, retMsg->getReturnValue());

-    return !retMsg->isException();

+  } else {

+    Debug::log(Debug::Debugging) << " return from invoke" << Debug::flush;

+    scoped_ptr<ReturnMessage> retMsg(_channel->reactToMessagesWhileWaitingForReturn(this));

+    if (!retMsg.get()) {

+      Debug::log(Debug::Error) << "JavaObject_invoke: failed to get return value" << Debug::flush;

+    } else {

+      if (isRawToString) {

+        // toString() needs the raw value

+        NPVariantProxy::assignFrom(*this, *result, retMsg->getReturnValue());

+        return !retMsg->isException();

+      }

+      isException = retMsg->isException();

+      returnValue = retMsg->getReturnValue();

+    }

   }

   // Wrap the result

-  return makeResult(retMsg->isException(), retMsg->getReturnValue(), result);

+  return makeResult(isException, returnValue, result);

 }

 

 bool ScriptableInstance::JavaObject_getProperty(int objectId, int dispId,

@@ -651,6 +655,11 @@
   javaObjectsToFree.insert(objectId);

 }

 

+void ScriptableInstance::disconnectDetectedImpl() {

+  NPVariantWrapper result(*this);

+  NPN_Invoke(getNPP(), window, jsDisconnectedID, 0, 0, result.addressForReturn());

+}

+

 void ScriptableInstance::sendFreeValues(HostChannel& channel) {

   unsigned n = javaObjectsToFree.size();

   if (n) {

diff --git a/plugins/npapi/ScriptableInstance.h b/plugins/npapi/ScriptableInstance.h
index cdce6f3..2d03a67 100644
--- a/plugins/npapi/ScriptableInstance.h
+++ b/plugins/npapi/ScriptableInstance.h
@@ -72,6 +72,10 @@
   void destroyJavaWrapper(JavaObject*);
 
   static const uint32_t VERSION = 1;
+
+protected:
+  virtual void disconnectDetectedImpl();
+
 private:  
   // Map of object ID to JavaObject
   hash_map<int, JavaObject*> javaObjects;
@@ -94,6 +98,7 @@
   const NPIdentifier statsID;
   const NPIdentifier gwtId;
 
+  const NPIdentifier jsDisconnectedID;
   const NPIdentifier jsInvokeID;
   const NPIdentifier jsResultID;
   const NPIdentifier jsTearOffID;