Sends the batch request to the server and returns a list of RpcResponse
        objects.  The list will be in the order that the requests were made to
        the batch.  Note that the RpcResponse objects may contain an error or a 
        successful result.  When you iterate through the list, you must test for
        response.error.
        
        send() may not be called more than once.

def send(self):
        """
        Sends the batch request to the server and returns a list of RpcResponse
        objects.  The list will be in the order that the requests were made to
        the batch.  Note that the RpcResponse objects may contain an error or a 
        successful result.  When you iterate through the list, you must test for
        response.error.
        
        send() may not be called more than once.
        """
        if self.sent:
            raise Exception("Batch already sent. Cannot send() again.")
        else:
            self.sent = True
            results = self.client.transport.request(self.req_list)
            
            id_to_method = { }
            by_id = { }
            for res in results:
                reqid = res["id"]
                by_id[reqid] = res

            in_req_order = [ ]
            for req in self.req_list:
                reqid  = req["id"]
                result = None
                error  = None
                resp   = safe_get(by_id, reqid)
                if resp == None:
                    msg = "Batch response missing result for request id: %s" % reqid
                    error = RpcException(ERR_INVALID_RESP, msg)
                else:
                    r_err = safe_get(resp, "error")
                    if r_err == None:
                        result = resp["result"]
                    else:
                        error = RpcException(r_err["code"], r_err["message"], safe_get(r_err, "data"))
                in_req_order.append(RpcResponse(req, result, error))
            return in_req_order