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 _Transports
 20  * @memberOf myfaces._impl.xhrCore
 21  * @description
 22  *
 23  * The xhr core adapter
 24  * which provides the transport mechanisms to the calling
 25  * objects, and controls the queue behavior, the error handling
 26  * and partial page submit functionality among other things
 27  * <p />
 28  * The idea behind this is to make the ajax request object as barebones
 29  * as possible and shift the extra functionality like queuing
 30  * parameter handling etc... to this class so that our transports become more easily
 31  * pluggable. This should keep the path open to iframe submits and other transport layers
 32  * <p />
 33  * the call to the corresponding transport just should be a
 34  * transport.xhrQueuedPost <br />
 35  * or transport.xhrPost,transport.xhrGet  etc... in the future
 36  * <p />
 37  * Note we have taken a pattern lesson or two from the dojo toolkit and its excellent handling
 38  * of transports by our patterns here (which is mainly a centralized transport singleton which routes
 39  * to different transport implementations and the auto passing of parameters into their
 40  * corresponding protected attributes on class level in the transports themselves)
 41  */
 42 myfaces._impl.core._Runtime.extendClass("myfaces._impl.xhrCore._Transports" , Object,
 43      /** @lends myfaces._impl.xhrCore._Transports.prototype */ {
 44 
 45     _PAR_ERRORLEVEL:"errorlevel",
 46     _PAR_QUEUESIZE:"queuesize",
 47     _PAR_PPS:"pps",
 48     _PAR_TIMEOUT:"timeout",
 49     _PAR_DELAY:"delay",
 50 
 51 
 52     /**
 53      * a singleton queue
 54      * note the structure of our inheritance
 55      * is that that _queue is attached to prototype
 56      * and hence the pointer to the request qeue
 57      * is shared over all instances
 58      *
 59      * if you need to have it per instance for complex objects
 60      * you have to initialize in the constructor
 61      *
 62      * (This is the same limitation dojo class inheritance
 63      * where our inheritance pattern is derived from has)
 64      */
 65     _q: new myfaces._impl.xhrCore._AjaxRequestQueue(),
 66 
 67 
 68 
 69     _Lang :  myfaces._impl._util._Lang,
 70     _RT: myfaces._impl.core._Runtime,
 71 
 72 
 73     /**
 74      * a simple not enqueued xhr post
 75      *
 76      * mapped options already have the exec and view properly in place
 77      * myfaces specifics can be found under mappedOptions.myFaces
 78      * @param {Node} source the source of this call
 79      * @param {Node} sourceForm the html form which is the source of this call
 80      * @param {Object} context (Map) the internal pass through context
 81      * @param {Object} passThrgh (Map) values to be passed through
 82      **/
 83     xhrPost : function(source, sourceForm, context, passThrgh) {
 84         var args = this._getArguments(source, sourceForm, context, passThrgh);
 85          delete args.xhrQueue;
 86         (new (this._getAjaxReqClass(context))(args)).send();
 87     },
 88 
 89     /**
 90      * xhr post with enqueuing as defined by the jsf 2.0 specification
 91      *
 92      * mapped options already have the exec and view properly in place
 93      * myfaces specifics can be found under mappedOptions.myFaces
 94      * @param {Node} source the source of this call
 95      * @param {Node} sourceForm the html form which is the source of this call
 96      * @param {Object} context (Map) the internal pass through context
 97      * @param {Object} passThrgh (Map) values to be passed through
 98      **/
 99     xhrQueuedPost : function(source, sourceForm, context, passThrgh) {
100         this._q.enqueue(
101                 new (this._getAjaxReqClass(context))(this._getArguments(source, sourceForm, context, passThrgh)));
102     },
103 
104     /**
105      * xhr get without enqueuing
106      *
107      * mapped options already have the exec and view properly in place
108      * myfaces specifics can be found under mappedOptions.myFaces
109      * @param {Node} source the source of this call
110      * @param {Node} sourceForm the html form which is the source of this call
111      * @param {Object} context (Map) the internal pass through context
112      * @param {Object} passThrgh (Map) values to be passed through
113      **/
114     xhrGet : function(source, sourceForm, context, passThrgh) {
115         var args = this._getArguments(source, sourceForm, context, passThrgh);
116         // note in get the timeout is not working delay however is and queue size as well
117         // since there are no cross browser ways to resolve a timeout on xhr level
118         // we have to live with it
119         args.ajaxType = "GET";
120         delete args.xhrQueue;
121         (new (this._getAjaxReqClass(context))(args)).send();
122     },
123 
124     /**
125      * xhr get which takes the existing queue into consideration to by synchronized
126      * to previous queued post requests
127      *
128      * mapped options already have the exec and view properly in place
129      * myfaces specifics can be found under mappedOptions.myFaces
130      * @param {Node} source the source of this call
131      * @param {Node} sourceForm the html form which is the source of this call
132      * @param {Object} context (Map) the internal pass through context
133      * @param {Object} passThrgh (Map) values to be passed through
134      **/
135     xhrQueuedGet : function(source, sourceForm, context, passThrgh) {
136         var args = this._getArguments(source, sourceForm, context, passThrgh);
137         // note in get the timeout is not working delay however is and queue size as well
138         // since there are no cross browser ways to resolve a timeout on xhr level
139         // we have to live with it
140         args.ajaxType = "GET";
141         this._q.enqueue(
142                 new (this._getAjaxReqClass(context))(args));
143     },
144 
145 
146     /**
147      * iframe post without queueing
148      *
149      * mapped options already have the exec and view properly in place
150      * myfaces specifics can be found under mappedOptions.myFaces
151      * @param {Node} source the source of this call
152      * @param {Node} sourceForm the html form which is the source of this call
153      * @param {Object} context (Map) the internal pass through context
154      * @param {Object} passThrgh (Map) values to be passed through
155      **/
156     multipartPost : function(source, sourceForm, context, passThrgh) {
157         var args = this._getArguments(source, sourceForm, context, passThrgh);
158         // note in get the timeout is not working delay however is and queue size as well
159         // since there are no cross browser ways to resolve a timeout on xhr level
160         // we have to live with it
161         delete args.xhrQueue;
162         (new (this._getMultipartReqClass(context))(args)).send();
163     },
164 
165     /**
166      * iframe queued post
167      *
168      * mapped options already have the exec and view properly in place
169      * myfaces specifics can be found under mappedOptions.myFaces
170      * @param {Node} source the source of this call
171      * @param {Node} sourceForm the html form which is the source of this call
172      * @param {Object} context (Map) the internal pass through context
173      * @param {Object} passThrgh (Map) values to be passed through
174      **/
175     multipartQueuedPost : function(source, sourceForm, context, passThrgh) {
176         var args = this._getArguments(source, sourceForm, context, passThrgh);
177         // note in get the timeout is not working delay however is and queue size as well
178         // since there are no cross browser ways to resolve a timeout on xhr level
179         this._q.enqueue(
180                 new (this._getMultipartReqClass(context))(args));
181     },
182 
183 
184     /**
185      * iframe get without queueing
186      *
187      * mapped options already have the exec and view properly in place
188      * myfaces specifics can be found under mappedOptions.myFaces
189      * @param {Node} source the source of this call
190      * @param {Node} sourceForm the html form which is the source of this call
191      * @param {Object} context (Map) the internal pass through context
192      * @param {Object} passThrgh (Map) values to be passed through
193      **/
194     multipartGet : function(source, sourceForm, context, passThrgh) {
195         var args = this._getArguments(source, sourceForm, context, passThrgh);
196         // note in get the timeout is not working delay however is and queue size as well
197         // since there are no cross browser ways to resolve a timeout on xhr level
198         // we have to live with it
199         args.ajaxType = "GET";
200         delete args.xhrQueue;
201         (new (this._getMultipartReqClass(context))(args)).send();
202     },
203 
204     /**
205      * iframe queued http get
206      *
207      * mapped options already have the exec and view properly in place
208      * myfaces specifics can be found under mappedOptions.myFaces
209      * @param {Node} source the source of this call
210      * @param {Node} sourceForm the html form which is the source of this call
211      * @param {Object} context (Map) the internal pass through context
212      * @param {Object} passThrgh (Map) values to be passed through
213      **/
214     multipartQueuedGet : function(source, sourceForm, context, passThrgh) {
215         var args = this._getArguments(source, sourceForm, context, passThrgh);
216         // note in get the timeout is not working delay however is and queue size as well
217         // since there are no cross browser ways to resolve a timeout on xhr level
218         args.ajaxType = "GET";
219         this._q.enqueue(
220                 new (this._getMultipartReqClass(context))(args));
221     },
222 
223 
224     /**
225      * Spec. 13.3.3
226      * Examining the response markup and updating the DOM tree
227      * @param {XmlHttpRequest} request - the ajax request
228      * @param {XmlHttpRequest} context - the ajax context
229      */
230     response : function(request, context) {
231         var internalContext = context._mfInternal;
232 
233         //the normal usecase is that the request knows about its response
234         //which normally is temporary stored within the _mfRequest object
235         //(aka call from a finished request)
236         //if no _mfRequest object is given which means an external call we
237         //have a call from the outside
238 
239         //TODO check if we cannot eliminate the _mfRequest object in the long run
240         //given we have to pass a request object anyway
241 
242         var ajaxObj = (internalContext && internalContext._mfRequest) ||  new (this._getAjaxReqClass(context))({xhr: request, context: context});
243         //ie gc fix
244         if(internalContext && internalContext._mfRequest){
245             internalContext._mfRequest = null;
246             delete internalContext._mfRequest;
247         }
248 
249         ajaxObj._response.processResponse(request, context);
250     },
251 
252     /**
253      * creates the arguments map and
254      * fetches the config params in a proper way in to
255      * deal with them in a flat way (from the nested context way)
256      *
257      * @param source the source of the request
258      * @param sourceForm the sourceform
259      * @param context   the context holding all values
260      * @param passThrgh the passThrough values to be blended into the response
261      */
262     _getArguments: function(source, sourceForm, context, passThrgh) {
263         var _RT = myfaces._impl.core._Runtime;
264         /** @ignore */
265         var _getConfig = _RT.getLocalOrGlobalConfig;
266         var _Lang = myfaces._impl._util._Lang;
267 
268         var ret = {
269             "source": source,
270             "sourceForm": sourceForm,
271             "context": context,
272             "passThrough": passThrgh,
273             "xhrQueue": this._q
274        };
275 
276         //we now mix in the config settings which might either be set globally
277         //or pushed in under the context myfaces.<contextValue> into the current request 
278         this._applyConfig(ret, context, "alarmThreshold", this._PAR_ERRORLEVEL);
279         this._applyConfig(ret, context, "queueSize", this._PAR_QUEUESIZE);
280         this._applyConfig(ret, context, "timeout", this._PAR_TIMEOUT);
281         this._applyConfig(ret, context, "delay", this._PAR_DELAY);
282 
283         //now partial page submit needs a different treatment
284         //since pps == execute strings
285         if (_getConfig(context, this._PAR_PPS, false)
286                 && _Lang.exists(passThrgh, myfaces._impl.core.Impl.P_EXECUTE)
287                 && passThrgh[myfaces._impl.core.Impl.P_EXECUTE].length > 0) {
288             ret['partialIdsArray'] = passThrgh[myfaces._impl.core.Impl.P_EXECUTE].split(" ");
289         }
290         return ret;
291     },
292 
293     /**
294      * helper method to apply a config setting to our varargs param list
295      *
296      * @param destination the destination map to receive the setting
297      * @param context the current context
298      * @param destParm the destination param of the destination map
299      * @param srcParm the source param which is the key to our config setting
300      */
301     _applyConfig: function(destination, context, destParm, srcParm) {
302         var _RT = myfaces._impl.core._Runtime;
303         /** @ignore */
304         var _getConfig = _RT.getLocalOrGlobalConfig;
305         if (_getConfig(context, srcParm, null) != null) {
306             destination[destParm] = _getConfig(context, srcParm, null);
307         }
308     },
309 
310 
311 
312 
313 
314 
315 
316     _loadImpl: function() {
317         if (!this._Impl) {
318             this._Impl = myfaces._impl.core._Runtime.getGlobalConfig("jsfAjaxImpl", myfaces._impl.core.Impl);
319         }
320         return this._Impl;
321     },
322 
323     /**
324      * centralized transport switching helper
325      * for the multipart submit case
326      *
327      * @param context the context which is passed down
328      */
329     _getMultipartReqClass: function(context) {
330         //if (this._RT.getLocalOrGlobalConfig(context, "transportAutoSelection", false) && this._RT.getXHRLvl() >= 2) {
331         //    return myfaces._impl.xhrCore._AjaxRequestLevel2;
332         //} else {
333             return myfaces._impl.xhrCore._IFrameRequest;
334         //}
335     },
336 
337 
338     _getAjaxReqClass: function(context) {
339         return myfaces._impl.xhrCore._AjaxRequest;
340     }
341 
342 });
343