Derrell Lipman wrote
> Got it. The ExtJs server apparently implements something that claims to be
> JSON-RPC, but doesn't follow the JSON-RPC protocol. (The field "id" is not
> allowed to be called "tid" in a JSON-RPC request or response.)
> 
> So, you have a couple of choices. The easy one for me to suggest (since
> I'm
> not implementing your server) is for your server to copy the tid field in
> the response to a new field called id. That way, the response will work
> for
> both ExtJs clients and qooxdoo ones.
> 
> If that's not a feasible solution, you can try something like this:
> 
>    - extend qx.io.remote.Rpc
>    - override the method createRequest as follows (untested)
> 
>    createRequest : function()
>    {
>      var req = this.base(arguments); // get the request object
> 
>      // Add a listener to munge the response. Since this listener
>      // is added before the one in _callInternal, this one should be
>      // called before the one in _callInternal.
>      req.addListener(
>        "completed",
>        function(evt)
>        {
>          // get a reference to the response object
>          var response = evt.getContent();
> 
>          // If we got a response...
>          if (response !== null)
>          {
>            // Modify the response object in the event content.
>            // You may want a conditional here: only overwrite if id
>            // member does not already exist.
>            response["id"] = response["tid"];
>          }
>        });
> 
>      // return the request object
>      return req;
>    }

You're completely right about the 'id' requirement. Unfortunately, there is
no easy way to fix this in the qooxdoo framework. I tried to follow you're
suggestion, only the response event doesn't contain a response object, but a
response json string that has to be parsed. The parsing happens in the code
below, which is (just a single function), too my opinion far to long and and
impossible to extend (not quite the open closed principle). So, I think I'll
have to start looking at fixing this in on the server side.

This is the function that parses the response object and checks the id prop:

    _callInternal : function(args, callType, refreshSession)
    {
      var self = this;
      var offset = (callType == 0 ? 0 : 1);
      var whichMethod = (refreshSession ? "refreshSession" : args[offset]);
      var handler = args[0];
      var argsArray = [];
      var eventTarget = this;
      var protocol = this.getProtocol();

      for (var i=offset+1; i<args.length; ++i)
      {
        argsArray.push(args[i]);
      }

      var req = this.createRequest();

      // Get any additional out-of-band data to be sent to the server
      var serverData = this.getServerData();

      // Create the request object
      var rpcData = this.createRpcData(req.getSequenceNumber(),
                                       whichMethod,
                                       argsArray,
                                       serverData);

      req.setCrossDomain(this.getCrossDomain());

      if (this.getUsername())
      {
        req.setUseBasicHttpAuth(this.getUseBasicHttpAuth());
        req.setUsername(this.getUsername());
        req.setPassword(this.getPassword());
      }

      req.setTimeout(this.getTimeout());
      var ex = null;
      var id = null;
      var result = null;
      var response = null;

      var handleRequestFinished = function(eventType, eventTarget)
      {
        switch(callType)
        {
          case 0: // sync
            break;

          case 1: // async with handler function
            handler(result, ex, id);
            break;

          case 2: // async with event listeners
            // Dispatch the event to our listeners.
            if (!ex)
            {
              eventTarget.fireDataEvent(eventType, response);
            }
            else
            {
              // Add the id to the exception
              ex.id = id;

              if (args[0])      // coalesce
              {
                // They requested that we coalesce all failure types to
                // &quot;failed&quot;
                eventTarget.fireDataEvent(&quot;failed&quot;, ex);
              }
              else
              {
                // No coalese so use original event type
                eventTarget.fireDataEvent(eventType, ex);
              }
            }
        }
      };

      var addToStringToObject = function(obj)
      {
        if (protocol == &quot;qx1&quot;)
        {
          obj.toString = function()
          {
            switch(obj.origin)
            {
              case qx.io.remote.Rpc.origin.server:
                return &quot;Server error &quot; + obj.code + &quot;: &quot;
+ obj.message;

              case qx.io.remote.Rpc.origin.application:
                return &quot;Application error &quot; + obj.code + &quot;:
&quot; + obj.message;

              case qx.io.remote.Rpc.origin.transport:
                return &quot;Transport error &quot; + obj.code + &quot;:
&quot; + obj.message;

              case qx.io.remote.Rpc.origin.local:
                return &quot;Local error &quot; + obj.code + &quot;: &quot;
+ obj.message;

              default:
                return (&quot;UNEXPECTED origin &quot; + obj.origin +
                        &quot; error &quot; + obj.code + &quot;: &quot; +
obj.message);
            }
          };
        }
        else // protocol == &quot;2.0&quot;
        {
          obj.toString = function()
          {
            var             ret;

            ret =  &quot;Error &quot; + obj.code + &quot;: &quot; +
obj.message;
            if (obj.data)
            {
              ret += &quot; (&quot; + obj.data + &quot;)&quot;;
            }

            return ret;
          };
        }
      };

      var makeException = function(origin, code, message)
      {
        var ex = new Object();

        if (protocol == &quot;qx1&quot;)
        {
          ex.origin = origin;
        }
        ex.code = code;
        ex.message = message;
        addToStringToObject(ex);

        return ex;
      };

      req.addListener(&quot;failed&quot;, function(evt)
      {
        var code = evt.getStatusCode();
        ex = makeException(qx.io.remote.Rpc.origin.transport,
                           code,
                           qx.io.remote.Exchange.statusCodeToString(code));
        id = this.getSequenceNumber();
        handleRequestFinished(&quot;failed&quot;, eventTarget);
      });

      req.addListener(&quot;timeout&quot;, function(evt)
      {
        this.debug(&quot;TIMEOUT OCCURRED&quot;);
        ex = makeException(qx.io.remote.Rpc.origin.local,
                           qx.io.remote.Rpc.localError.timeout,
                           &quot;Local time-out expired for &quot;+
whichMethod);
        id = this.getSequenceNumber();
        handleRequestFinished(&quot;timeout&quot;, eventTarget);
      });

      req.addListener(&quot;aborted&quot;, function(evt)
      {
        ex = makeException(qx.io.remote.Rpc.origin.local,
                           qx.io.remote.Rpc.localError.abort,
                           &quot;Aborted &quot; + whichMethod);
        id = this.getSequenceNumber();
        handleRequestFinished(&quot;aborted&quot;, eventTarget);
      });

      req.addListener(&quot;completed&quot;, function(evt)
      {
        response = evt.getContent();

        // server may have reset, giving us no data on our requests
        if (response === null)
        {
          ex = makeException(qx.io.remote.Rpc.origin.local,
                             qx.io.remote.Rpc.localError.nodata,
                             &quot;No data in response to &quot; +
whichMethod);
          id = this.getSequenceNumber();
          handleRequestFinished(&quot;failed&quot;, eventTarget);
          return;
        }

        // Parse. Skip when response is already an object
        // because the script transport was used.
        if (!qx.lang.Type.isObject(response)) {

          // Handle converted dates
          if (self._isConvertDates()) {

            // Parse as JSON and revive date literals
            if (self._isResponseJson()) {
              response = qx.lang.Json.parse(response, function(key, value) {
                if (value &amp;&amp; typeof value === &quot;string&quot;) {
                  if (value.indexOf(&quot;new Date(Date.UTC(&quot;) >= 0) {
                    var m = value.match(/new
Date\(Date.UTC\((\d+),(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\)\)/);
                    return new
Date(Date.UTC(m[1],m[2],m[3],m[4],m[5],m[6],m[7]));
                  }
                }
                return value;
              });

            // Eval
            } else {
              response = response && response.length > 0 ? eval('(' +
response + ')') : null;
            }

          // No special date handling required, JSON assumed
          } else {
            response = qx.lang.Json.parse(response);
          }
        }

        id = response["id"];

        if (id != this.getSequenceNumber())
        {
          this.warn("Received id (" + id + ") does not match requested id "
+
                    "(" + this.getSequenceNumber() + ")!");
        }

        // Determine if an error was returned. Assume no error, initially.
        var eventType = "completed";
        var exTest = response["error"];

        if (exTest != null)
        {
          // There was an error
          result = null;
          addToStringToObject(exTest);
          ex = exTest;

          // Change the event type
          eventType = "failed";
        }
        else
        {
          result = response["result"];

          if (refreshSession)
          {
            result = eval("(" + result + ")");
            var newSuffix = qx.core.ServerSettings.serverPathSuffix;

            if (self.__currentServerSuffix != newSuffix)
            {
              self.__previousServerSuffix = self.__currentServerSuffix;
              self.__currentServerSuffix = newSuffix;
            }

            self.setUrl(self.fixUrl(self.getUrl()));
          }
        }

        handleRequestFinished(eventType, eventTarget);
      });

      // Provide a replacer when convert dates is enabled
      var replacer = null;
      if (this._isConvertDates()) {
        replacer = function(key, value) {
          // The value passed in is of type string, because the Date's
          // toJson gets applied before. Get value from containing object.
          value = this[key];

          if (qx.lang.Type.isDate(value)) {
            var dateParams =
              value.getUTCFullYear() + "," +
              value.getUTCMonth() + "," +
              value.getUTCDate() + "," +
              value.getUTCHours() + "," +
              value.getUTCMinutes() + "," +
              value.getUTCSeconds() + "," +
              value.getUTCMilliseconds();
            return "new Date(Date.UTC(" + dateParams + "))";
          }
          return value;
        };
      }

      req.setData(qx.lang.Json.stringify(rpcData, replacer));
      req.setAsynchronous(callType > 0);

      if (req.getCrossDomain())
      {
        // Our choice here has no effect anyway.  This is purely
informational.
        req.setRequestHeader("Content-Type",
                             "application/x-www-form-urlencoded");
      }
      else
      {
        // When not cross-domain, set type to text/json
        req.setRequestHeader("Content-Type", "application/json");
      }

      // Do not parse as JSON. Later done conditionally.
      req.setParseJson(false);

      req.send();

      if (callType == 0)
      {
        if (ex != null)
        {
          var error = new Error(ex.toString());
          error.rpcdetails = ex;
          throw error;
        }

        return result;
      }
      else
      {
        return req;
      }
    },





--
View this message in context: 
http://qooxdoo.678.n2.nabble.com/qx-io-remote-Request-51-1-Received-id-undefined-does-not-match-requested-id-tp7586683p7586716.html
Sent from the qooxdoo mailing list archive at Nabble.com.

------------------------------------------------------------------------------
New Year. New Location. New Benefits. New Data Center in Ashburn, VA.
GigeNET is offering a free month of service with a new server in Ashburn.
Choose from 2 high performing configs, both with 100TB of bandwidth.
Higher redundancy.Lower latency.Increased capacity.Completely compliant.
http://p.sf.net/sfu/gigenet
_______________________________________________
qooxdoo-devel mailing list
qooxdoo-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel

Reply via email to