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 * @class 19 * @name Impl 20 * @memberOf myfaces._impl.core 21 * @description Implementation singleton which implements all interface method 22 * defined by our jsf.js API 23 * */ 24 _MF_SINGLTN(_PFX_CORE + "Impl", _MF_OBJECT, /** @lends myfaces._impl.core.Impl.prototype */ { 25 26 //third option myfaces._impl.xhrCoreAjax which will be the new core impl for now 27 _transport : myfaces._impl.core._Runtime.getGlobalConfig("transport", myfaces._impl.xhrCore._Transports), 28 29 /** 30 * external event listener queue! 31 */ 32 _evtListeners : new (myfaces._impl.core._Runtime.getGlobalConfig("eventListenerQueue", myfaces._impl._util._ListenerQueue))(), 33 34 /** 35 * external error listener queue! 36 */ 37 _errListeners : new (myfaces._impl.core._Runtime.getGlobalConfig("errorListenerQueue", myfaces._impl._util._ListenerQueue))(), 38 39 /*CONSTANTS*/ 40 41 /*internal identifiers for options*/ 42 IDENT_ALL: "@all", 43 IDENT_NONE: "@none", 44 IDENT_THIS: "@this", 45 IDENT_FORM: "@form", 46 47 /* 48 * [STATIC] constants 49 */ 50 51 P_PARTIAL_SOURCE: "javax.faces.source", 52 P_VIEWSTATE: "javax.faces.ViewState", 53 P_AJAX: "javax.faces.partial.ajax", 54 P_EXECUTE: "javax.faces.partial.execute", 55 P_RENDER: "javax.faces.partial.render", 56 P_EVT: "javax.faces.partial.event", 57 58 /* message types */ 59 ERROR: "error", 60 EVENT: "event", 61 62 /* event emitting stages */ 63 BEGIN: "begin", 64 COMPLETE: "complete", 65 SUCCESS: "success", 66 67 /*ajax errors spec 14.4.2*/ 68 HTTPERROR: "httpError", 69 EMPTY_RESPONSE: "emptyResponse", 70 MALFORMEDXML: "malformedXML", 71 SERVER_ERROR: "serverError", 72 CLIENT_ERROR: "clientError", 73 TIMEOUT_EVENT: "timeout", 74 75 76 /*error reporting threshold*/ 77 _threshold: "ERROR", 78 79 /*blockfilter for the passthrough filtering, the attributes given here 80 * will not be transmitted from the options into the passthrough*/ 81 _BLOCKFILTER: {onerror: 1, onevent: 1, render: 1, execute: 1, myfaces: 1}, 82 83 84 85 /** 86 * collect and encode data for a given form element (must be of type form) 87 * find the javax.faces.ViewState element and encode its value as well! 88 * return a concatenated string of the encoded values! 89 * 90 * @throws Error in case of the given element not being of type form! 91 * https://issues.apache.org/jira/browse/MYFACES-2110 92 */ 93 getViewState : function(form) { 94 /** 95 * typecheck assert!, we opt for strong typing here 96 * because it makes it easier to detect bugs 97 */ 98 if (form) { 99 form = this._Lang.byId(form); 100 } 101 102 if (!form 103 || !form.nodeName 104 || form.nodeName.toLowerCase() != "form") { 105 throw new Error(this._Lang.getMessage("ERR_VIEWSTATE")); 106 } 107 108 var ajaxUtils = myfaces._impl.xhrCore._AjaxUtils; 109 110 var ret = this._Lang.createFormDataDecorator([]); 111 ajaxUtils.encodeSubmittableFields(ret, form, null); 112 113 return ret.makeFinal(); 114 }, 115 116 /** 117 * this function has to send the ajax requests 118 * 119 * following request conditions must be met: 120 * <ul> 121 * <li> the request must be sent asynchronously! </li> 122 * <li> the request must be a POST!!! request </li> 123 * <li> the request url must be the form action attribute </li> 124 * <li> all requests must be queued with a client side request queue to ensure the request ordering!</li> 125 * </ul> 126 * 127 * @param {String|Node} elem any dom element no matter being it html or jsf, from which the event is emitted 128 * @param {|Event|} event any javascript event supported by that object 129 * @param {|Object|} options map of options being pushed into the ajax cycle 130 * 131 * 132 * TODO refactoring, the passthrgh handling is only for dragging in request parameters 133 * we should rewrite this part 134 * 135 * 136 * a) transformArguments out of the function 137 * b) passThrough handling with a map copy with a filter map block map 138 */ 139 request : function(elem, event, options) { 140 if(this._delayTimeout) { 141 clearTimeout(this._delayTimeout); 142 delete this._delayTimeout; 143 } 144 /*namespace remap for our local function context we mix the entire function namespace into 145 *a local function variable so that we do not have to write the entire namespace 146 *all the time 147 **/ 148 var _Lang = this._Lang, 149 _Dom = this._Dom, 150 WINDOW_ID = "javax.faces.windowId"; 151 /*assert if the onerror is set and once if it is set it must be of type function*/ 152 _Lang.assertType(options.onerror, "function"); 153 /*assert if the onevent is set and once if it is set it must be of type function*/ 154 _Lang.assertType(options.onevent, "function"); 155 156 //options not set we define a default one with nothing 157 options = options || {}; 158 159 /*preparations for jsf 2.2 windowid handling*/ 160 //pass the window id into the options if not set already 161 if(!options.windowId) { 162 var windowId = _Dom.getWindowId(); 163 (windowId) ? options[WINDOW_ID] = windowId: null; 164 } else { 165 options[WINDOW_ID] = options.windowId; 166 delete options.windowId; 167 } 168 169 /** 170 * we cross reference statically hence the mapping here 171 * the entire mapping between the functions is stateless 172 */ 173 //null definitely means no event passed down so we skip the ie specific checks 174 if ('undefined' == typeof event) { 175 event = window.event || null; 176 } 177 178 elem = _Dom.byIdOrName(elem); 179 var elementId = _Dom.nodeIdOrName(elem); 180 181 /* 182 * We make a copy of our options because 183 * we should not touch the incoming params! 184 */ 185 var passThrgh = _Lang.mixMaps({}, options, true, this._BLOCKFILTER); 186 187 if (event) { 188 passThrgh[this.P_EVT] = event.type; 189 } 190 191 /** 192 * ajax pass through context with the source 193 * onevent and onerror 194 */ 195 var context = { 196 source: elem, 197 onevent: options.onevent, 198 onerror: options.onerror, 199 200 //TODO move the myfaces part into the _mfInternal part 201 myfaces: options.myfaces 202 }; 203 204 /** 205 * fetch the parent form 206 * 207 * note we also add an override possibility here 208 * so that people can use dummy forms and work 209 * with detached objects 210 */ 211 var form = (options.myfaces && options.myfaces.form)? 212 _Lang.byId(options.myfaces.form): 213 this._getForm(elem, event); 214 215 /** 216 * binding contract the javax.faces.source must be set 217 */ 218 passThrgh[this.P_PARTIAL_SOURCE] = elementId; 219 220 /** 221 * javax.faces.partial.ajax must be set to true 222 */ 223 passThrgh[this.P_AJAX] = true; 224 225 if (options.execute) { 226 /*the options must be a blank delimited list of strings*/ 227 /*compliance with Mojarra which automatically adds @this to an execute 228 * the spec rev 2.0a however states, if none is issued nothing at all should be sent down 229 */ 230 this._transformList(passThrgh, this.P_EXECUTE, options.execute + " @this", form, elementId); 231 } else { 232 passThrgh[this.P_EXECUTE] = elementId; 233 } 234 235 if (options.render) { 236 this._transformList(passThrgh, this.P_RENDER, options.render, form, elementId); 237 } 238 239 /** 240 * multiple transports upcoming jsf 2.1 feature currently allowed 241 * default (no value) xhrQueuedPost 242 * 243 * xhrQueuedPost 244 * xhrPost 245 * xhrGet 246 * xhrQueuedGet 247 * iframePost 248 * iframeQueuedPost 249 * 250 */ 251 var transportType = this._getTransportType(context, passThrgh, form); 252 253 //additional meta information to speed things up, note internal non jsf 254 //pass through options are stored under _mfInternal in the context 255 context._mfInternal = {}; 256 var mfInternal = context._mfInternal; 257 258 mfInternal["_mfSourceFormId"] = form.id; 259 mfInternal["_mfSourceControlId"] = elementId; 260 mfInternal["_mfTransportType"] = transportType; 261 262 //mojarra compatibility, mojarra is sending the form id as well 263 //this is not documented behavior but can be determined by running 264 //mojarra under blackbox conditions 265 //i assume it does the same as our formId_submit=1 so leaving it out 266 //wont hurt but for the sake of compatibility we are going to add it 267 passThrgh[form.id] = form.id; 268 269 //delay handling is an experimental feature which will most likely 270 //make it into jsf 2.2 271 /* jsf2.2 only: options.delay || */ 272 var delayTimeout = this._RT.getLocalOrGlobalConfig(context, "delay", false); 273 if(delayTimeout) { 274 this._delayTimeout = setTimeout(_Lang.hitch(this, function(){ 275 this._transport[transportType](elem, form, context, passThrgh); 276 } ), delayTimeout); 277 } else { 278 this._transport[transportType](elem, form, context, passThrgh); 279 } 280 }, 281 282 /** 283 * fetches the form in an unprecise manner depending 284 * on an element or event target 285 * 286 * @param elem 287 * @param event 288 */ 289 _getForm: function(elem, event) { 290 var _Dom = this._Dom; 291 var _Lang = this._Lang; 292 var form = _Dom.fuzzyFormDetection(elem); 293 294 if (!form && event) { 295 //in case of no form is given we retry over the issuing event 296 form = _Dom.fuzzyFormDetection(_Lang.getEventTarget(event)); 297 if (!form) { 298 throw Error(_Lang.getMessage("ERR_FORM")); 299 } 300 } else if (!form) { 301 throw Error(_Lang.getMessage("ERR_FORM")); 302 } 303 return form; 304 }, 305 306 /** 307 * determines the transport type to be called 308 * for the ajax call 309 * 310 * @param context the context 311 * @param passThrgh pass through values 312 * @param form the form which issues the request 313 */ 314 _getTransportType: function(context, passThrgh, form) { 315 /** 316 * if execute or render exist 317 * we have to pass them down as a blank delimited string representation 318 * of an array of ids! 319 */ 320 //for now we turn off the transport auto selection, to enable 2.0 backwards compatibility 321 //on protocol level, the file upload only can be turned on if the auto selection is set to true 322 var getConfig = this._RT.getLocalOrGlobalConfig, 323 _Lang = this._Lang, 324 _Dom = this._Dom; 325 326 var transportAutoSelection = getConfig(context, "transportAutoSelection", false); 327 var isMultipart = (transportAutoSelection && _Dom.getAttribute(form, "enctype") == "multipart/form-data") ? 328 _Dom.isMultipartCandidate(passThrgh[this.P_EXECUTE]) : 329 false; 330 331 /** 332 * multiple transports upcoming jsf 2.1 feature currently allowed 333 * default (no value) xhrQueuedPost 334 * 335 * xhrQueuedPost 336 * xhrPost 337 * xhrGet 338 * xhrQueuedGet 339 * iframePost 340 * iframeQueuedPost 341 * 342 */ 343 var transportType = (!isMultipart) ? 344 getConfig(context, "transportType", "xhrQueuedPost") : 345 getConfig(context, "transportType", "multipartQueuedPost"); 346 if (!this._transport[transportType]) { 347 //throw new Error("Transport type " + transportType + " does not exist"); 348 throw new Error(_Lang.getMessage("ERR_TRANSPORT",null, transportType)); 349 } 350 return transportType; 351 352 }, 353 354 /** 355 * transforms the list to the expected one 356 * with the proper none all form and this handling 357 * (note we also could use a simple string replace but then 358 * we would have had double entries under some circumstances) 359 * 360 * @param passThrgh 361 * @param target 362 * @param srcStr 363 * @param form 364 * @param elementId 365 */ 366 _transformList: function(passThrgh, target, srcStr, form, elementId) { 367 var _Lang = this._Lang; 368 //this is probably the fastest transformation method 369 //it uses an array and an index to position all elements correctly 370 //the offset variable is there to prevent 0 which results in a javascript 371 //false 372 var offset = 1, 373 vals = (srcStr) ? srcStr.split(/\s+/) : [], 374 idIdx = (vals.length) ? _Lang.arrToMap(vals, offset) : {}, 375 376 //helpers to improve speed and compression 377 none = idIdx[this.IDENT_NONE], 378 all = idIdx[this.IDENT_ALL], 379 theThis = idIdx[this.IDENT_THIS], 380 theForm = idIdx[this.IDENT_FORM]; 381 382 if (none) { 383 //in case of none only one value is returned 384 passThrgh[target] = this.IDENT_NONE; 385 return passThrgh; 386 } 387 if (all) { 388 //in case of all only one value is returned 389 passThrgh[target] = this.IDENT_ALL; 390 return passThrgh; 391 } 392 393 if (theForm) { 394 //the form is replaced with the proper id but the other 395 //values are not touched 396 vals[theForm - offset] = form.id; 397 } 398 if (theThis && !idIdx[elementId]) { 399 //in case of this, the element id is set 400 vals[theThis - offset] = elementId; 401 } 402 403 //the final list must be blank separated 404 passThrgh[target] = vals.join(" "); 405 return passThrgh; 406 }, 407 408 addOnError : function(/*function*/errorListener) { 409 /*error handling already done in the assert of the queue*/ 410 this._errListeners.enqueue(errorListener); 411 }, 412 413 addOnEvent : function(/*function*/eventListener) { 414 /*error handling already done in the assert of the queue*/ 415 this._evtListeners.enqueue(eventListener); 416 }, 417 418 419 420 /** 421 * implementation triggering the error chain 422 * 423 * @param {Object} request the request object which comes from the xhr cycle 424 * @param {Object} context (Map) the context object being pushed over the xhr cycle keeping additional metadata 425 * @param {String} name the error name 426 * @param {String} serverErrorName the server error name in case of a server error 427 * @param {String} serverErrorMessage the server error message in case of a server error 428 * 429 * handles the errors, in case of an onError exists within the context the onError is called as local error handler 430 * the registered error handlers in the queue receiv an error message to be dealt with 431 * and if the projectStage is at development an alert box is displayed 432 * 433 * note: we have additional functionality here, via the global config myfaces.config.defaultErrorOutput a function can be provided 434 * which changes the default output behavior from alert to something else 435 * 436 * 437 */ 438 sendError : function sendError(/*Object*/request, /*Object*/ context, /*String*/ name, /*String*/ serverErrorName, /*String*/ serverErrorMessage) { 439 var _Lang = myfaces._impl._util._Lang; 440 var UNKNOWN = _Lang.getMessage("UNKNOWN"); 441 442 var eventData = {}; 443 //we keep this in a closure because we might reuse it for our serverErrorMessage 444 var malFormedMessage = function() { 445 return (name && name === myfaces._impl.core.Impl.MALFORMEDXML) ? _Lang.getMessage("ERR_MALFORMEDXML") : ""; 446 }; 447 448 449 450 //by setting unknown values to unknown we can handle cases 451 //better where a simulated context is pushed into the system 452 eventData.type = this.ERROR; 453 454 eventData.status = name || UNKNOWN; 455 eventData.serverErrorName = serverErrorName || UNKNOWN; 456 eventData.serverErrorMessage = serverErrorMessage || UNKNOWN; 457 458 try { 459 eventData.source = context.source || UNKNOWN; 460 eventData.responseCode = request.status || UNKNOWN; 461 eventData.responseText = request.responseText || UNKNOWN; 462 eventData.responseXML = request.responseXML || UNKNOWN; 463 } catch (e) { 464 // silently ignore: user can find out by examining the event data 465 } 466 467 /**/ 468 if (context["onerror"]) { 469 context.onerror(eventData); 470 } 471 472 /*now we serve the queue as well*/ 473 this._errListeners.broadcastEvent(eventData); 474 475 if (jsf.getProjectStage() === "Development" && this._errListeners.length() == 0 && !context["onerror"]) { 476 var defaultErrorOutput = myfaces._impl.core._Runtime.getGlobalConfig("defaultErrorOutput", alert), 477 finalMessage = [], 478 //we remap the function to achieve a better compressability 479 finalMessagePush = _Lang.hitch(finalMessage, finalMessage.push); 480 481 finalMessagePush((name) ? name : ""); 482 if (name) 483 { 484 finalMessagePush(": "); 485 } 486 finalMessagePush((serverErrorName) ? serverErrorName : ""); 487 if (serverErrorName) 488 { 489 finalMessagePush(" "); 490 } 491 finalMessagePush((serverErrorMessage) ? serverErrorMessage : ""); 492 finalMessagePush(malFormedMessage()); 493 finalMessagePush("\n\n"); 494 finalMessagePush( _Lang.getMessage("MSG_DEV_MODE")); 495 defaultErrorOutput(finalMessage.join("")); 496 } 497 }, 498 499 /** 500 * sends an event 501 */ 502 sendEvent : function sendEvent(/*Object*/request, /*Object*/ context, /*event name*/ name) { 503 var _Lang = myfaces._impl._util._Lang; 504 var eventData = {}; 505 var UNKNOWN = _Lang.getMessage("UNKNOWN"); 506 507 eventData.type = this.EVENT; 508 509 eventData.status = name; 510 eventData.source = context.source; 511 512 513 if (name !== this.BEGIN) { 514 515 try { 516 //we bypass a problem with ie here, ie throws an exception if no status is given on the xhr object instead of just passing a value 517 var getValue = function(value, key) { 518 try { 519 return value[key] 520 } catch (e) { 521 return UNKNOWN; 522 } 523 }; 524 525 eventData.responseCode = getValue(request, "status"); 526 eventData.responseText = getValue(request, "responseText"); 527 eventData.responseXML = getValue(request, "responseXML"); 528 529 } catch (e) { 530 var impl = myfaces._impl.core._Runtime.getGlobalConfig("jsfAjaxImpl", myfaces._impl.core.Impl); 531 impl.sendError(request, context, this.CLIENT_ERROR, "ErrorRetrievingResponse", 532 _Lang.getMessage("ERR_CONSTRUCT", e.toString())); 533 534 //client errors are not swallowed 535 throw e; 536 } 537 538 } 539 540 /**/ 541 if (context.onevent) { 542 /*calling null to preserve the original scope*/ 543 context.onevent.call(null, eventData); 544 } 545 546 /*now we serve the queue as well*/ 547 this._evtListeners.broadcastEvent(eventData); 548 }, 549 550 551 /** 552 * Spec. 13.3.3 553 * Examining the response markup and updating the DOM tree 554 * @param {XMLHttpRequest} request - the ajax request 555 * @param {Object} context - the ajax context 556 */ 557 response : function(request, context) { 558 this._RT.getLocalOrGlobalConfig(context, "responseHandler", myfaces._impl.xhrCore._AjaxResponse).processResponse(request, context); 559 }, 560 561 /** 562 * @return the project stage also emitted by the server: 563 * it cannot be cached and must be delivered over the server 564 * The value for it comes from the request parameter of the jsf.js script called "stage". 565 */ 566 getProjectStage : function() { 567 //since impl is a singleton we only have to do it once at first access 568 if(!this._projectStage) { 569 var PRJ_STAGE = "projectStage", 570 STG_PROD = "Production", 571 572 scriptTags = document.getElementsByTagName("script"), 573 getConfig = myfaces._impl.core._Runtime.getGlobalConfig, 574 projectStage = null, 575 found = false, 576 allowedProjectStages = {STG_PROD:1,"Development":1, "SystemTest":1,"UnitTest":1}; 577 578 /* run through all script tags and try to find the one that includes jsf.js */ 579 for (var i = 0; i < scriptTags.length && !found; i++) { 580 if (scriptTags[i].src.search(/\/javax\.faces\.resource\/jsf\.js.*ln=javax\.faces/) != -1) { 581 var result = scriptTags[i].src.match(/stage=([^&;]*)/); 582 found = true; 583 if (result) { 584 // we found stage=XXX 585 // return only valid values of ProjectStage 586 projectStage = (allowedProjectStages[result[1]]) ? result[1] : null; 587 } 588 else { 589 //we found the script, but there was no stage parameter -- Production 590 //(we also add an override here for testing purposes, the default, however is Production) 591 projectStage = getConfig(PRJ_STAGE, STG_PROD); 592 } 593 } 594 } 595 /* we could not find anything valid --> return the default value */ 596 this._projectStage = projectStage || getConfig(PRJ_STAGE, STG_PROD); 597 } 598 return this._projectStage; 599 }, 600 601 /** 602 * implementation of the external chain function 603 * moved into the impl 604 * 605 * @param {Object} source the source which also becomes 606 * the scope for the calling function (unspecified side behavior) 607 * the spec states here that the source can be any arbitrary code block. 608 * Which means it either is a javascript function directly passed or a code block 609 * which has to be evaluated separately. 610 * 611 * After revisiting the code additional testing against components showed that 612 * the this parameter is only targeted at the component triggering the eval 613 * (event) if a string code block is passed. This is behavior we have to resemble 614 * in our function here as well, I guess. 615 * 616 * @param {Event} event the event object being passed down into the the chain as event origin 617 * the spec is contradicting here, it on one hand defines event, and on the other 618 * it says it is optional, after asking, it meant that event must be passed down 619 * but can be undefined 620 */ 621 chain : function(source, event) { 622 var len = arguments.length; 623 var _Lang = this._Lang; 624 var throwErr = function(msgKey) { 625 throw Error(_Lang.getMessage(msgKey)); 626 }; 627 //the spec is contradicting here, it on one hand defines event, and on the other 628 //it says it is optional, I have cleared this up now 629 //the spec meant the param must be passed down, but can be 'undefined' 630 if (len < 2) { 631 throwErr("ERR_EV_OR_UNKNOWN"); 632 } else if (len < 3) { 633 if ('function' == typeof event || this._Lang.isString(event)) { 634 throwErr("ERR_EVT_PASS"); 635 } 636 //nothing to be done here, move along 637 return true; 638 } 639 //now we fetch from what is given from the parameter list 640 //we cannot work with splice here in any performant way so we do it the hard way 641 //arguments only are give if not set to undefined even null values! 642 643 //assertions source either null or set as dom element: 644 645 646 if ('undefined' == typeof source) { 647 throwErr("ERR_SOURCE_DEF_NULL"); 648 //allowed chain datatypes 649 } else if ('function' == typeof source) { 650 throwErr("ERR_SOURCE_FUNC"); 651 } 652 if (this._Lang.isString(source)) { 653 throwErr("ERR_SOURCE_NOSTR"); 654 } 655 656 //assertion if event is a function or a string we already are in our function elements 657 //since event either is undefined, null or a valid event object 658 659 if ('function' == typeof event || this._Lang.isString(event)) { 660 throwErr("ERR_EV_OR_UNKNOWN"); 661 } 662 663 for (var cnt = 2; cnt < len; cnt++) { 664 //we do not change the scope of the incoming functions 665 //but we reuse the argument array capabilities of apply 666 var ret; 667 668 if ('function' == typeof arguments[cnt]) { 669 ret = arguments[cnt].call(source, event); 670 } else { 671 //either a function or a string can be passed in case of a string we have to wrap it into another function 672 ret = new Function("event", arguments[cnt]).call(source, event); 673 } 674 //now if one function returns false in between we stop the execution of the cycle 675 //here, note we do a strong comparison here to avoid constructs like 'false' or null triggering 676 if (ret === false /*undefined check implicitly done here by using a strong compare*/) { 677 return false; 678 } 679 } 680 return true; 681 682 }, 683 684 /** 685 * error handler behavior called internally 686 * and only into the impl it takes care of the 687 * internal message transformation to a myfaces internal error 688 * and then uses the standard send error mechanisms 689 * also a double error logging prevention is done as well 690 * 691 * @param request the request currently being processed 692 * @param context the context affected by this error 693 * @param sourceClass the sourceclass throwing the error 694 * @param func the function throwing the error 695 * @param exception the exception being thrown 696 */ 697 stdErrorHandler: function(request, context, sourceClass, func, exception) { 698 699 var _Lang = myfaces._impl._util._Lang; 700 var exProcessed = _Lang.isExceptionProcessed(exception); 701 try { 702 //newer browsers do not allow to hold additional values on native objects like exceptions 703 //we hence capsule it into the request, which is gced automatically 704 //on ie as well, since the stdErrorHandler usually is called between requests 705 //this is a valid approach 706 707 if (this._threshold == "ERROR" && !exProcessed) { 708 this.sendError(request, context, this.CLIENT_ERROR, exception.name, 709 "MyFaces ERROR:" + this._Lang.createErrorMsg(sourceClass, func, exception)); 710 } 711 } finally { 712 713 //we forward the exception, just in case so that the client 714 //will receive it in any way 715 try { 716 if (!exProcessed) { 717 _Lang.setExceptionProcessed(exception); 718 } 719 } catch(e) { 720 721 } 722 throw exception; 723 } 724 } 725 }); 726 727 728