You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by we...@apache.org on 2009/02/09 23:51:44 UTC
svn commit: r742776 - in
/myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util:
./ _xhr/
Author: werpu
Date: Mon Feb 9 22:51:43 2009
New Revision: 742776
URL: http://svn.apache.org/viewvc?rev=742776&view=rev
Log:
https://issues.apache.org/jira/browse/MYFACES-2148
alternative transport implementation
smaller and down to the core of the spec without any overhead!
Added:
myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_ListenerQueue.js
myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/
myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_SimpleXHRFrameworkAdapter.js
myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_SimpleXHRTransport.js
myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_XHRConst.js
Modified:
myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_JSF2Utils.js
myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_TrinidadFrameworkAdapter.js
Modified: myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_JSF2Utils.js
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_JSF2Utils.js?rev=742776&r1=742775&r2=742776&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_JSF2Utils.js (original)
+++ myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_JSF2Utils.js Mon Feb 9 22:51:43 2009
@@ -292,18 +292,18 @@
myfaces._JSF2Utils.arrayToString = function(/*String or array*/ arr, /*string*/ delimiter) {
- if( myfaces._JSF2Utils.isString(arr) ) {
- return arr;
- }
- var resultArr = [];
- for(var cnt = 0; cnt < arr.length; cnt ++) {
- if(myfaces._JSF2Utils.isString(arr[cnt])) {
- resultArr.push(arr[cnt]);
- } else {
- resultArr.push(arr[cnt].toString());
- }
- }
- return resultArr.join(delimiter);
+ if( myfaces._JSF2Utils.isString(arr) ) {
+ return arr;
+ }
+ var resultArr = [];
+ for(var cnt = 0; cnt < arr.length; cnt ++) {
+ if(myfaces._JSF2Utils.isString(arr[cnt])) {
+ resultArr.push(arr[cnt]);
+ } else {
+ resultArr.push(arr[cnt].toString());
+ }
+ }
+ return resultArr.join(delimiter);
};
/**
@@ -459,4 +459,34 @@
.replace(/\"/g, '%22')
.replace(/\'/g, '%27');
}
+
+ /**
+ * fetches the XHR object in a browser neutral way
+ * so that it can be processed further on
+ */
+ myfaces._JSF2Utils.getXHR = function() {
+ /*if('undefined' != typeof(myfaces._JSF2Utils._xhr)) {
+ myfaces._JSF2Utils._xhr.abort();
+ return myfaces._JSF2Utils._xhr;
+ }*/
+ //all newer browsers!
+ if ('undefined' != typeof XMLHttpRequest ) {
+ myfaces._JSF2Utils._xhr = new XMLHttpRequest();
+ }
+ if (!myfaces._JSF2Utils._xhr) {
+ // Interne
+ // t Explorer 6 or older
+ try {
+ myfaces._JSF2Utils._xhr = new ActiveXObject("Msxml2.XMLHTTP");
+ } catch(e) {
+ try {
+ myfaces._JSF2Utils._xhr = new ActiveXObject("Microsoft.XMLHTTP");
+ } catch(e) {
+ myfaces._JSF2Utils._xhr = null;
+ }
+ }
+ }
+ return myfaces._JSF2Utils._xhr;
+ }
+
}
Added: myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_ListenerQueue.js
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_ListenerQueue.js?rev=742776&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_ListenerQueue.js (added)
+++ myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_ListenerQueue.js Mon Feb 9 22:51:43 2009
@@ -0,0 +1,82 @@
+/*
+ * a classical listener queue pattern
+ */
+
+
+_reserveMyfaces();
+
+/**
+ * Simple listener queue with closures which shall be
+ * called
+ *
+ * idea:
+ * var queue = new myfaces._ListenerQueue();
+ */
+if(!myfaces._JSF2Utils.exists(myfaces, "_ListenerQueue")) {
+ myfaces._ListenerQueue = function() {
+ this._queue = [];
+
+ }
+
+ myfaces._ListenerQueue.prototype._assertListener = function(/*function*/listener) {
+ if("function" != typeof (listener)) {
+ throw new Exception("Error: myfaces._ListenerQueue." + arguments.caller.toString() + "Parameter must be of type function");
+ }
+ }
+
+ myfaces._ListenerQueue.prototype.add = function(/*function*/listener) {
+ this._assertListener( listener);
+ this._queue.push(listener);
+ }
+
+ myfaces._ListenerQueue.prototype.remove = function(/*function*/listener) {
+ this._assertListener( listener);
+ /*find element in queue*/
+ var cnt = 0;
+ while(cnt < this._queue.length && this._queue[cnt] != listener) {
+ cnt += 1;
+ }
+ /*found*/
+ if(cnt < this._queue.length) {
+ this._queue[cnt] = null;
+ /*we remove the element now as fast as possible*/
+ this._queue.splice(cnt, 1);
+ }
+
+ }
+ /**
+ * generic broadcast with a number of arguments being passed down
+ * @param scope the execution scope for the event callback
+ * @param argument,...* the arguments list which has to be passed
+ * down the queue function
+ */
+ myfaces._ListenerQueue.prototype.broadcastScopedEvent = function(scope, /*any*/argument) {
+ for(var cnt = 0; cnt < this._queue.length; cnt ++) {
+ /**
+ * we call the original method under its original scope
+ * use hitch to keep the original scope in place
+ * because there is no way that I can keep it from here
+ **/
+ var varArgs = [];
+ for(var argsCnt = 1; argsCnt < arguments.length; argsCnt++) {
+ varArgs.push(arguments[argsCnt]);
+ }
+ this._queue[cnt].apply(scope, varArgs);
+ }
+ }
+
+ /**
+ * generic broadcast with a number of arguments being passed down
+ */
+ myfaces._ListenerQueue.prototype.broadcastEvent = function(/*any*/argument) {
+ for(var cnt = 0; cnt < this._queue.length; cnt ++) {
+ /**
+ * we call the original method under its original scope
+ * use hitch to keep the original scope in place
+ * because there is no way that I can keep it from here
+ **/
+
+ this._queue[cnt].apply(null, arguments);
+ }
+ }
+};
\ No newline at end of file
Modified: myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_TrinidadFrameworkAdapter.js
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_TrinidadFrameworkAdapter.js?rev=742776&r1=742775&r2=742776&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_TrinidadFrameworkAdapter.js (original)
+++ myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_TrinidadFrameworkAdapter.js Mon Feb 9 22:51:43 2009
@@ -47,6 +47,7 @@
break;;
case myfaces._TrXMLRequestEvent.STATUS_SEND_AFTER:
/*still waiting, we can add listeners later if it is allowed*/
+
break;
case myfaces._TrXMLRequestEvent.STATUS_COMPLETE:
/**
Added: myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_SimpleXHRFrameworkAdapter.js
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_SimpleXHRFrameworkAdapter.js?rev=742776&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_SimpleXHRFrameworkAdapter.js (added)
+++ myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_SimpleXHRFrameworkAdapter.js Mon Feb 9 22:51:43 2009
@@ -0,0 +1,100 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * under the License.
+ */
+
+
+_reserveMyfaces();
+
+/**
+ * Adapter functionc call for the SimpleXHR Transport to be
+ * compatible to jsf2!
+ * For now no direct connection should exist between jsf2 and
+ * the transports so that they stay interchangeable!
+ *
+ * Generally a factory pattern should be supported in the long
+ * run to be able to switch adapters on the fly, probably an iframe
+ * transport has to be added as well.
+ *
+ * But to keep the code lean it should be noted
+ * that no transport code should be mixed with the other!
+ */
+if (!myfaces._JSF2Utils.exists(myfaces, "_SimpleXHRFrameworkAdapter")) {
+ myfaces._SimpleXHRFrameworkAdapter = function() {
+ this._delegate = new myfaces._SimpleXHRTransport();
+ /*we fixate the scope of the event callback to the this object trinidad does a remapping
+ *to the scope object we currently do it here later*/
+ this._delegate.addEventListener(this._eventCallback);
+ };
+
+ /**
+ * unmapping via the event callback
+ * which then triggers into
+ * the jsf event and error subsystem
+ */
+ myfaces._SimpleXHRFrameworkAdapter.prototype._eventCallback = function(/**/event) {
+ var xhrConst = myfaces._XHRConst;
+ var xhrContext = event.context;
+ var request = event.transport;
+
+ var complete = false;
+ /*here we have to do the event mapping back into the ri events*/
+
+ //TODO check whether the scope changes on the sendEvent so that we have to bind it to our context!
+ switch(request.readyState) {
+ //TODO add mapping code here
+ case xhrConst.READY_STATE_OPENED:
+ jsf.ajax.sendEvent(null, xhrContext, jsf.ajax._AJAX_STAGE_BEGIN)
+ break;
+ case xhrConst.READY_STATE_DONE:
+ /**
+ *here we can do our needed callbacks so
+ *that the specification is satisfied
+ **/
+ complete = true;
+ var responseStatusCode = event.status;
+
+ if(200 <= responseStatusCode && 300 > responseStatusCode ) {
+ jsf.ajax.sendEvent(request, xhrContext, jsf.ajax._AJAX_STAGE_COMPLETE);
+
+ //TODO do the dom manipulation callback here
+ jsf.ajax.response(request, xhrContext);
+ } else {
+ jsf.ajax.sendEvent(request, xhrContext, jsf.ajax._AJAX_STAGE_COMPLETE);
+ jsf.ajax.sendError(request, xhrContext, jsf.ajax._AJAX_STAGE_HTTPERROR);
+ }
+ break;
+ default:
+ break;
+ }
+ return complete;
+ };
+
+ /**
+ * central request callback
+ */
+ myfaces._SimpleXHRFrameworkAdapter.prototype.sendRequest = function(ajaxContext, action, viewState, passThroughArguments ) {
+ var data = {};
+ data.context = ajaxContext;
+ data.action = action;
+ data.viewstate = viewState;
+ data.passthroughArguments = passThroughArguments;
+ this._delegate.send(data);
+ };
+
+}
+
+
+
+
+
Added: myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_SimpleXHRTransport.js
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_SimpleXHRTransport.js?rev=742776&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_SimpleXHRTransport.js (added)
+++ myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_SimpleXHRTransport.js Mon Feb 9 22:51:43 2009
@@ -0,0 +1,169 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * under the License.
+ */
+
+
+/**
+ Implementation of the JSF 2.0 transport layer as xml http request
+ as for now only XmlHttpRequest is implemented as Transport,
+ but in the long run we probably also can use iframes
+ and web sockets as transport layers.
+
+ The pluggable transport layer system is similar to what dojo has to offer
+ but is no direct port due to the huge dependency chain dojo introduces in this
+ area, we do not want to have a dojo dependency in our subsystem
+
+ This transport layer allows an ajax command queuing as defined by the jsf 2 spec
+ and also adds more flexibility in the ajax callbacks to ease the
+ adding of trinidad compatible hooks in the implementation details
+
+ The public api utilizes this transport class for calling the entire ajax part!
+ */
+_reserveMyfaces();
+
+
+if (!myfaces._JSF2Utils.exists(myfaces, "_SimpleXHRTransport")) {
+ myfaces._SimpleXHRTransport = function() {
+ /*we need an instance of our utils for the hitch function*/
+ this._utils = myfaces._JSF2Utils;
+ /*const namespace remapping*/
+ this.xhrConst = myfaces._XHRConst;
+
+ /*currently only post is supported*/
+ this._sendMethod = "POST";
+ /*currently only async is supported*/
+ this._async = true;
+ /*calls for now must be uncached*/
+ this._cached = false;
+
+ this._eventListeners = new myfaces._ListenerQueue();
+
+ /*
+ * caching data queue forw cached
+ * ajax post requests!
+ */
+ this._transportDataQueue = [];
+ };
+
+
+ myfaces._SimpleXHRTransport.prototype.addEventListener = function(/*function*/ eventListener) {
+ this._eventListeners.add(eventListener);
+ };
+ myfaces._SimpleXHRTransport.prototype.removeEventListener = function(/*function*/ eventListener) {
+ this._eventListeners.remove(eventListener);
+ };
+
+ myfaces._SimpleXHRTransport.prototype._handleXHREvent = function() {
+ /*handle the event callbach*/
+
+ var data = this._transportDataQueue[0];
+ this._eventListeners.broadcastEvent(data);
+
+ if(data.transport.readyState === this.xhrConst.READY_STATE_DONE) {
+ this._transportDataQueue.shift();
+ this._process(true);
+ /*ie cleanup*/
+ delete data.transport;
+ }
+
+ return true;
+ };
+
+ /**
+ * central queue processing callback!
+ * @param inProcess marks whether the process is called from the outside
+ * or after terminating an xhr request from the inside
+ * we have to cover this that way because of a callback error in mozilla
+ */
+ myfaces._SimpleXHRTransport.prototype._process = function( /*boolean*/ inProcess) {
+ try {
+
+ var size = this._transportDataQueue.length;
+ if(size > 1 && !inProcess) return; /*still in queue no send can be issued*/
+ if(size === 0) {
+
+ return; /*empty queue process has to terminate*/
+ }
+
+
+ /*note this only works this way because javascript multitasks only premptively
+ *if a real multithreading is added please put the outer send into a critical region
+ *to prevent concurrency issues*/
+ var data = this._transportDataQueue[0];
+
+ data.transport = this._utils.getXHR();
+
+ var transport = data.transport;
+ var passThrough = data.passthroughArguments;
+
+ if(!this._utils.isString(passThrough)) {
+ passThrough = this._utils.getPostbackContentFromMap(passThrough);
+ }
+ if(!this._cached) { //we bypass any caching if needed!
+ //set the pragmas here as well
+ data.action = data.action + ((data.action.indexOf('?') == -1) ? "?" :"&" )+ "AjaxRequestUniqueId = "+(new Date().getTime());
+ }
+ /**
+ * We set the on ready state change here
+ */
+
+ transport.onreadystatechange = this._utils.hitch(this, this._handleXHREvent);
+ transport.open(this._sendMethod, data.action, this._async);
+ if(this._utils.exists(transport, "setRequestHeader")) {
+ transport.setRequestHeader(this.xhrConst.FACES_REQUEST, this.xhrConst.PARTIAL_AJAX);
+ transport.setRequestHeader(this.xhrConst.CONTENT_TYPE, this.xhrConst.XFORM_ENCODED);
+ }
+
+ //THE RI does a notification here
+ //be we rely on the official W3C codes
+ //which should be sufficient for the callback
+ //on "begin"
+ transport.send(data.viewstate +"&"+ passThrough);
+
+
+ } catch (e) {
+ //Browser error...
+ /*internal error we log it and then we splice the affected event away*/
+ myfaces._Logger.getInstance().error("Error in myfaces._SimpleXHRTransport.prototype._process", e);
+ if(this._transportDataQueue.length > 0) {
+ this._transportDataQueue.shift();
+ }
+ }
+ }
+
+ /**
+ * data = {
+ * context //jsf2 context
+ * action //String
+ * viewstate //String
+ * passthroughArguments //Map|String
+ * //added by this method
+ * transport //XHRObject
+ * }
+ * called indirectly from ajaxContext, sourceForm.action, viewState, passThroughArguments
+ **/
+ myfaces._SimpleXHRTransport.prototype.send = function(/*Object*/data) {
+
+ var queueData = {};
+ queueData.context = data.context;
+ queueData.action = data.action;
+ queueData.viewstate = data.viewstate;
+ queueData.passthroughArguments = data.passthroughArguments;
+
+ this._transportDataQueue.push(queueData);
+ /*we initiate a send if none is in progress currently*/
+
+ this._process(false);
+ };
+}
\ No newline at end of file
Added: myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_XHRConst.js
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_XHRConst.js?rev=742776&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_XHRConst.js (added)
+++ myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/javax/faces/_util/_xhr/_XHRConst.js Mon Feb 9 22:51:43 2009
@@ -0,0 +1,39 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use myfaces._XHRConst file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * under the License.
+ */
+_reserveMyfaces();
+
+/**
+ * Various constants used by the xhr subsystem!
+ */
+if (!myfaces._JSF2Utils.exists(myfaces, "_XHRConst")) {
+ myfaces._XHRConst = {};
+ /*
+ *
+ * ready states according to www.w3.org
+ *
+ */
+
+ myfaces._XHRConst.READY_STATE_UNSENT = 0;
+ myfaces._XHRConst.READY_STATE_OPENED = 1;
+ myfaces._XHRConst.READY_STATE_HEADERS_RECEIVED = 2;
+ myfaces._XHRConst.READY_STATE_LOADING = 3;
+ myfaces._XHRConst.READY_STATE_DONE = 4;
+
+ /*header constants for the ajax request*/
+ myfaces._XHRConst.FACES_REQUEST = 'Faces-Request';
+ myfaces._XHRConst.PARTIAL_AJAX = 'partial/ajax';
+ myfaces._XHRConst.CONTENT_TYPE = "Content-Type";
+ myfaces._XHRConst.XFORM_ENCODED = "application/x-www-form-urlencoded";
+}