1 include(bbq.ajax.AJAXRequest); 2 include(bbq.gui.error.ServerError); 3 4 bbq.ajax.SoapRequest = Class.create(bbq.ajax.AJAXRequest, /** @lends bbq.ajax.SoapRequest.prototype **/ { 5 /** 6 * Sends an asyncronous SOAP request much the same as an AJAX request. 7 * 8 * @example 9 * <pre><code class="language-javascript"> 10 * var request = new bbq.ajax.SoapRequest({ 11 * url: "/path/to/somewhere", 12 * args: { 13 * foo: "bar" 14 * }, 15 * onSuccess: function(serverResponse, soapResponse) { 16 * 17 * } 18 * }); 19 * </pre></code> 20 * @constructs 21 * @param {Object} options 22 * @extends bbq.ajax.AJAXRequest 23 */ 24 initialize: function($super, options) { 25 options.method = "POST"; 26 options.contentType = "application/soap+xml"; 27 28 $super(options); 29 }, 30 31 _createRequestHeaders: function() { 32 return { 33 "SoapAction": this.options.action, 34 "Content-Type": "application/soap+xml" 35 }; 36 }, 37 38 _getPostBody: function() { 39 var header = ""; 40 41 if(this.options.authentication) { 42 header = "<soapenv:Header xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + 43 "<wsse:Security soapenv:mustUnderstand=\"true\">" + 44 this.options.authentication.getSecurityHeader() + 45 "</wsse:Security>" + 46 "</soapenv:Header>"; 47 } 48 49 return "<?xml version='1.0' encoding='UTF-8'?>" + 50 "<soapenv:Envelope xmlns:soapenv='http://www.w3.org/2003/05/soap-envelope'>" + 51 header + 52 "<soapenv:Body>" + 53 "<" + this.options.action + "Request xmlns=\"" + this.options.namespace +"\">" + 54 this._parseMessageBody(null, this.options.message) + 55 "</" + this.options.action + "Request>" + 56 "</soapenv:Body>" + 57 "</soapenv:Envelope>\r\n"; 58 }, 59 60 _parseMessageBody: function(key, message) { 61 if(message == null) { 62 return ""; 63 } 64 65 if(Object.isNumber(message) || Object.isString(message)) { 66 return message; 67 } 68 69 var output = ""; 70 71 if(Object.isArray(message)) { 72 message.each(function(value) { 73 if(value == null) { 74 return; 75 } 76 77 output += "<" + key + ">" + this._parseMessageBody(key, message[key]) + "</" + key + ">"; 78 }); 79 } else { 80 for(var key in message) { 81 if(message[key] == null) { 82 continue; 83 } 84 85 output += "<" + key + ">" + this._parseMessageBody(key, message[key]) + "</" + key + ">"; 86 } 87 } 88 89 return output; 90 }, 91 92 /** 93 * @param {String} handlerName 94 * @param {Object} args 95 */ 96 _callHandler: function($super, handlerName, args) { 97 var serverResponse = args[0]; 98 var response; 99 100 try { 101 var doc = serverResponse.responseXML.documentElement; 102 var responseElement = doc.getElementsByTagName(this.options.action + "Response")[0]; 103 104 response = this._parse(responseElement); 105 106 } catch(e) { 107 Log.error("Could not call handler " + handlerName, e); 108 109 var errorMessage = new bbq.gui.error.ServerError({ 110 url: this.options.url, 111 args: this.options.args, 112 serverResponse: serverResponse.responseText 113 }); 114 errorMessage.appear(); 115 } 116 117 $super(handlerName, [serverResponse, response]); 118 }, 119 120 _parse: function(node) { 121 //Log.info("parsing " + node.nodeName); 122 123 // are we parsing multiple sibling nodes with the same name? 124 // if so, store them in an array 125 var nodeName; 126 var isArray; 127 128 $A(node.childNodes).each(function(childNode) { 129 if(childNode.nodeName == nodeName) { 130 isArray = true; 131 132 throw $break; 133 } 134 135 nodeName = childNode.nodeName; 136 }); 137 138 // will be returned 139 var response; 140 141 if(isArray) { 142 response = []; 143 144 $A(node.childNodes).each(function(childNode) { 145 if(childNode.nodeName == "#text") { 146 // found text node, abort! 147 response = this._parseText(childNode.nodeValue); 148 149 throw $break; 150 } 151 152 response.push(this._parse(childNode)); 153 }.bind(this)); 154 } else { 155 response = {}; 156 157 $A(node.childNodes).each(function(childNode) { 158 if(childNode.nodeName == "#text") { 159 // found text node, abort! 160 response = this._parseText(childNode.nodeValue); 161 162 throw $break; 163 } 164 165 response[childNode.nodeName] = this._parse(childNode); 166 }.bind(this)); 167 } 168 169 return response; 170 }, 171 172 _parseText: function(value) { 173 // try as an integer 174 var asInt = parseInt(value); 175 176 // if not not-a-number and the string value is the same as the int value 177 if(!isNaN(asInt) && "" + asInt == value) { 178 return asInt; 179 } 180 181 // try as a float 182 var asFloat = parseFloat(value); 183 184 // if not not-a-number and the string value is the same as the float value 185 if(!isNaN(asFloat) && "" + asFloat == value) { 186 return asFloat; 187 } 188 189 // is it a date? 190 if(value.charAt(4) == "-" && value.charAt(7) == "-" && value.charAt(10) == "T" 191 && value.charAt(13) == ":" && value.charAt(16) == ":") { 192 return new Date(value); 193 } 194 195 return value; 196 } 197 }); 198