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