1 /* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to you under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /** 18 * An implementation of an xhr request object 19 * with partial page submit functionality, and jsf 20 * ppr request and timeout handling capabilities 21 * 22 * Author: Werner Punz (latest modification by $Author: ganeshpuri $) 23 * Version: $Revision: 1.4 $ $Date: 2009/05/31 09:16:44 $ 24 */ 25 26 /** 27 * @class 28 * @name _AjaxRequest 29 * @memberOf myfaces._impl.xhrCore 30 * @extends myfaces._impl.core.Object 31 */ 32 _MF_CLS(_PFX_XHR + "_AjaxRequest", _MF_OBJECT, /** @lends myfaces._impl.xhrCore._AjaxRequest.prototype */ { 33 34 _contentType: "application/x-www-form-urlencoded", 35 /** source element issuing the request */ 36 _source: null, 37 /** encoding for the submit */ 38 _encoding:null , 39 /** context passed down from the caller */ 40 _context:null, 41 /** source form issuing the request */ 42 _sourceForm: null, 43 /** passthrough parameters */ 44 _passThrough: null, 45 46 /** queue control */ 47 _timeout: null, 48 /** enqueuing delay */ 49 //_delay:null, 50 /** queue size */ 51 _queueSize:-1, 52 53 /** 54 back reference to the xhr queue, 55 only set if the object really is queued 56 */ 57 _xhrQueue: null, 58 59 /** pps an array of identifiers which should be part of the submit, the form is ignored */ 60 _partialIdsArray : null, 61 62 /** xhr object, internal param */ 63 _xhr: null, 64 65 /** predefined method */ 66 _ajaxType:"POST", 67 68 //CONSTANTS 69 ENCODED_URL:"javax.faces.encodedURL", 70 /* 71 * constants used internally 72 */ 73 _CONTENT_TYPE:"Content-Type", 74 _HEAD_FACES_REQ:"Faces-Request", 75 _VAL_AJAX: "partial/ajax", 76 _XHR_CONST: myfaces._impl.xhrCore.engine.XhrConst, 77 78 // _exception: null, 79 // _requestParameters: null, 80 /** 81 * Constructor 82 * <p /> 83 * note there is a load of common properties 84 * inherited by the base class which define the corner 85 * parameters and the general internal behavior 86 * like _onError etc... 87 * @param {Object} args an arguments map which an override any of the given protected 88 * instance variables, by a simple name value pair combination 89 */ 90 constructor_: function(args) { 91 92 try { 93 this._callSuper("constructor_", args); 94 95 this._onException = this._Lang.hitch(this, this._stdErrorHandler); 96 this._onWarn = this._Lang.hitch(this, this._stdErrorHandler); 97 this._initDefaultFinalizableFields(); 98 delete this._resettableContent["_xhrQueue"]; 99 100 this.applyArgs(args); 101 var mfInternal = this._context._mfInternal; 102 mfInternal._onException = this._onException; 103 mfInternal._onWarning = this._onWarn; 104 105 /*namespace remapping for readability*/ 106 //we fetch in the standard arguments 107 //and apply them to our protected attributes 108 //we do not gc the entry hence it is not defined on top 109 var xhrCore = myfaces._impl.xhrCore; 110 this._AJAXUTIL = xhrCore._AjaxUtils; 111 112 } catch (e) { 113 //_onError 114 this._onException(this._xhr, this._context, "myfaces._impl.xhrCore._AjaxRequest", "constructor", e); 115 } 116 }, 117 118 /** 119 * Sends an Ajax request 120 */ 121 send : function() { 122 123 var _Lang = this._Lang; 124 125 try { 126 127 var scopeThis = _Lang.hitch(this, function(functionName) { 128 return _Lang.hitch(this, this[functionName]); 129 }); 130 this._xhr = _Lang.mixMaps(this._getTransport(), { 131 onprogress: scopeThis("onprogress"), 132 ontimeout: scopeThis("ontimeout"), 133 onloadend: scopeThis("ondone"), 134 onload: scopeThis("onsuccess"), 135 onerror: scopeThis("onerror") 136 137 }, true); 138 var xhr = this._xhr, 139 sourceForm = this._sourceForm, 140 targetURL = (typeof sourceForm.elements[this.ENCODED_URL] == 'undefined') ? 141 sourceForm.action : 142 sourceForm.elements[this.ENCODED_URL].value, 143 formData = this.getFormData(); 144 145 for (var key in this._passThrough) { 146 formData.append(key, this._passThrough[key]); 147 } 148 149 xhr.open(this._ajaxType, targetURL + 150 ((this._ajaxType == "GET") ? "?" + this._formDataToURI(formData) : "") 151 , true); 152 153 xhr.timeout = this._timeout || 0; 154 155 var contentType = this._contentType; 156 if (this._encoding) { 157 contentType = contentType + "; charset:" + this._encoding; 158 } 159 160 xhr.setRequestHeader(this._CONTENT_TYPE, contentType); 161 xhr.setRequestHeader(this._HEAD_FACES_REQ, this._VAL_AJAX); 162 163 this._sendEvent("BEGIN"); 164 //Check if it is a custom form data object 165 //if yes we use makefinal for the final handling 166 if (formData && formData.makeFinal) { 167 formData = formData.makeFinal() 168 } 169 xhr.send((this._ajaxType != "GET") ? formData : null); 170 171 } catch (e) { 172 //_onError//_onError 173 this._onException(this._xhr, this._context, "myfaces._impl.xhrCore._AjaxRequest", "send", e); 174 } 175 }, 176 177 178 ondone: function() { 179 this._requestDone(); 180 }, 181 182 183 onsuccess: function(evt) { 184 185 var context = this._context; 186 var xhr = this._xhr; 187 try { 188 this._sendEvent("COMPLETE"); 189 //now we have to reroute into our official api 190 //because users might want to decorate it, we will split it apart afterwards 191 192 context._mfInternal = context._mfInternal || {}; 193 jsf.ajax.response((xhr.getXHRObject) ? xhr.getXHRObject() : xhr, context); 194 195 //an error in the processing has been raised 196 //TODO move all the error callbacks from response into 197 //a thrown exception best with a message history so 198 //that we have a message trace 199 //target 2.1.5 200 if (!context._mfInternal.internalError) { 201 this._sendEvent("SUCCESS"); 202 } 203 } catch (e) { 204 this._onException(xhr, context, "myfaces._impl.xhrCore._AjaxRequest", "callback", e); 205 } 206 }, 207 208 onerror: function(evt) { 209 210 var context = this._context; 211 var xhr = this._xhr; 212 var _Lang = this._Lang; 213 214 var errorText = ""; 215 this._sendEvent("COMPLETE"); 216 try { 217 var UNKNOWN = _Lang.getMessage("UNKNOWN"); 218 errorText = _Lang.getMessage("ERR_REQU_FAILED", null, 219 (xhr.status || UNKNOWN), 220 (xhr.statusText || UNKNOWN)); 221 222 } catch (e) { 223 errorText = _Lang.getMessage("ERR_REQ_FAILED_UNKNOWN", null); 224 } finally { 225 var _Impl = this.attr("impl"); 226 _Impl.sendError(xhr, context, _Impl.HTTPERROR, 227 _Impl.HTTPERROR, errorText); 228 } 229 //_onError 230 }, 231 232 onprogress: function(evt) { 233 //do nothing for now 234 }, 235 236 ontimeout: function(evt) { 237 try { 238 //we issue an event not an error here before killing the xhr process 239 this._sendEvent("TIMEOUT_EVENT"); 240 //timeout done we process the next in the queue 241 } finally { 242 this._requestDone(); 243 } 244 }, 245 246 _formDataToURI: function(formData) { 247 if (formData && formData.makeFinal) { 248 formData = formData.makeFinal() 249 } 250 return formData; 251 }, 252 253 _getTransport: function() { 254 255 var xhr = this._RT.getXHRObject(); 256 //the current xhr level2 timeout w3c spec is not implemented by the browsers yet 257 //we have to do a fallback to our custom routines 258 259 //Chrome fails in the current builds, on our loadend, we disable the xhr 260 //level2 optimisations for now 261 //if (('undefined' == typeof this._timeout || null == this._timeout) && _Rt.getXHRLvl() >= 2) { 262 //no timeout we can skip the emulation layer 263 // return xhr; 264 //} 265 return new myfaces._impl.xhrCore.engine.Xhr1({xhrObject: xhr}); 266 }, 267 268 269 270 //----------------- backported from the base request -------------------------------- 271 //non abstract ones 272 /** 273 * Spec. 13.3.1 274 * Collect and encode input elements. 275 * Additionally the hidden element javax.faces.ViewState 276 * 277 * 278 * @return an element of formDataWrapper 279 * which keeps the final Send Representation of the 280 */ 281 getFormData : function() { 282 var _AJAXUTIL = this._AJAXUTIL, myfacesOptions = this._context.myfaces; 283 var ret = this._Lang.createFormDataDecorator(jsf.getViewState(this._sourceForm)); 284 285 return ret; 286 }, 287 288 /** 289 * Client error handlers which also in the long run route into our error queue 290 * but also are able to deliver more meaningful messages 291 * note, in case of an error all subsequent xhr requests are dropped 292 * to get a clean state on things 293 * 294 * @param request the xhr request object 295 * @param context the context holding all values for further processing 296 * @param sourceClass (String) the issuing class for a more meaningful message 297 * @param func the issuing function 298 * @param exception the embedded exception 299 */ 300 _stdErrorHandler: function(request, context, sourceClass, func, exception) { 301 context._mfInternal.internalError = true; 302 var xhrQueue = this._xhrQueue; 303 try { 304 this.attr("impl").stdErrorHandler(request, context, sourceClass, func, exception); 305 } finally { 306 if (xhrQueue) { 307 xhrQueue.cleanup(); 308 } 309 } 310 }, 311 312 _sendEvent: function(evtType) { 313 var _Impl = this.attr("impl"); 314 _Impl.sendEvent(this._xhr, this._context, _Impl[evtType]); 315 }, 316 317 _requestDone: function() { 318 var queue = this._xhrQueue; 319 if (queue) { 320 queue.processQueue(); 321 } 322 //ie6 helper cleanup 323 delete this._context.source; 324 this._finalize(); 325 }, 326 327 //cleanup 328 _finalize: function() { 329 330 //final cleanup to terminate everything 331 this._Lang.clearExceptionProcessed(); 332 333 if (this._xhr.readyState == this._XHR_CONST.READY_STATE_DONE) { 334 this._callSuper("_finalize"); 335 } 336 } 337 }); 338 339