THRIFT-1087 Nonblocking asynchronous JS services
Patch: Henrique Mendonca


git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1089637 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/js/thrift.js b/lib/js/thrift.js
index b8ca2c0..c7a46fd 100644
--- a/lib/js/thrift.js
+++ b/lib/js/thrift.js
@@ -56,7 +56,7 @@
         var length = 0;
         for (var k in obj) {
             if (obj.hasOwnProperty(k)) {
-              length++;
+                length++;
             }
         }
 
@@ -75,8 +75,8 @@
 Thrift.TException = {};
 Thrift.TException.prototype = {
     initialize: function(message, code) {
-            this.message = message;
-            this.code = (code === null) ? 0 : code;
+        this.message = message;
+        this.code = (code === null) ? 0 : code;
     }
 };
 
@@ -186,19 +186,16 @@
 
     //Gets the browser specific XmlHttpRequest Object
     getXmlHttpRequestObject: function() {
-
         try { return new XMLHttpRequest(); } catch (e1) { }
         try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { }
         try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { }
 
         throw "Your browser doesn't support the XmlHttpRequest object.";
-
     },
 
-    flush: function() {
-
+    flush: function(async) {
         //async mode
-        if (this.url === undefined || this.url === '') {
+        if (async || this.url === undefined || this.url === '') {
             return this.send_buf;
         }
 
@@ -225,6 +222,54 @@
         this.rpos = 0;
     },
 
+    jqRequest: function(client, postData, args, recv_method) {
+        if (typeof jQuery === 'undefined' ||
+            typeof jQuery.Deferred === 'undefined') {
+            throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests';
+        }
+
+        // Deferreds
+        var deferred = jQuery.Deferred();
+        var completeDfd = jQuery._Deferred();
+        var dfd = deferred.promise();
+        dfd.success = dfd.done;
+        dfd.error = dfd.fail;
+        dfd.complete = completeDfd.done;
+
+        var jqXHR = jQuery.ajax({
+            url: this.url,
+            data: postData,
+            type: 'POST',
+            cache: false,
+            dataType: 'text',
+            context: this,
+            success: this.jqResponse,
+            error: function(xhr, status, e) {
+                deferred.rejectWith(client, jQuery.merge([e], xhr.tArgs));
+            },
+            complete: function(xhr, status) {
+                completeDfd.resolveWith(client, [xhr, status]);
+            }
+        });
+
+        deferred.done(jQuery.makeArray(args).pop()); //pop callback from args
+        jqXHR.tArgs = args;
+        jqXHR.tClient = client;
+        jqXHR.tRecvFn = recv_method;
+        jqXHR.tDfd = deferred;
+        return dfd;
+    },
+
+    jqResponse: function(responseData, textStatus, jqXHR) {
+      this.setRecvBuffer(responseData);
+      try {
+          var value = jqXHR.tRecvFn.call(jqXHR.tClient);
+          jqXHR.tDfd.resolveWith(jqXHR, jQuery.merge([value], jqXHR.tArgs));
+      } catch (ex) {
+          jqXHR.tDfd.rejectWith(jqXHR, jQuery.merge([ex], jqXHR.tArgs));
+      }
+    },
+
     setRecvBuffer: function(buf) {
         this.recv_buf = buf;
         this.recv_buf_sz = this.recv_buf.length;
@@ -531,7 +576,11 @@
         this.rstack = [];
         this.rpos = [];
 
-        this.robj = eval(this.transport.readAll());
+        if (typeof jQuery !== 'undefined') {
+            this.robj = jQuery.parseJSON(this.transport.readAll());
+        } else {
+            this.robj = eval(this.transport.readAll());
+        }
 
         var r = {};
         var version = this.robj.shift();
@@ -551,7 +600,6 @@
         return r;
     },
 
-
     readMessageEnd: function() {
     },
 
@@ -617,7 +665,6 @@
         r.ftype = ftype;
         r.fid = fid;
 
-
         return r;
     },
 
@@ -632,7 +679,6 @@
     },
 
     readMapBegin: function(keyType, valType, size) {
-
         var map = this.rstack.pop();
 
         var r = {};
@@ -652,14 +698,12 @@
     },
 
     readListBegin: function(elemType, size) {
-
         var list = this.rstack[this.rstack.length - 1];
 
         var r = {};
         r.etype = Thrift.Protocol.RType[list.shift()];
         r.size = list.shift();
 
-
         this.rpos.push(this.rstack.length);
         this.rstack.push(list);
 
@@ -698,7 +742,6 @@
         return this.readI32();
     },
 
-
     readI32: function(f) {
         if (f === undefined) {
             f = this.rstack[this.rstack.length - 1];
@@ -753,5 +796,4 @@
     skip: function(type) {
         throw 'skip not supported yet';
     }
-
 };