Author: nbelaevski
Date: 2008-11-25 18:44:58 -0500 (Tue, 25 Nov 2008)
New Revision: 11385
Modified:
trunk/framework/impl/src/main/javascript/ajaxjsf/queue.js
Log:
https://jira.jboss.org/jira/browse/RF-4961
https://jira.jboss.org/jira/browse/RF-4957
Modified: trunk/framework/impl/src/main/javascript/ajaxjsf/queue.js
===================================================================
--- trunk/framework/impl/src/main/javascript/ajaxjsf/queue.js 2008-11-25 22:24:53 UTC (rev
11384)
+++ trunk/framework/impl/src/main/javascript/ajaxjsf/queue.js 2008-11-25 23:44:58 UTC (rev
11385)
@@ -11,263 +11,279 @@
//queue constructor
A4J.AJAX.EventQueue = function() {
- var Pipeline = function(size, gate, queue) {
- this.size = size || -1;
+ var DROP_NEW = 'dropNew';
+ var DROP_NEXT = 'dropNext';
+ var FIRE_NEW = 'fireNew';
+ var FIRE_NEXT = 'fireNext';
+
+ var extendOptions = function(options) {
+ var opts = {};
- this.gate = gate;
- this.queue = queue;
+ for (var name in options) {
+ opts[name] = options[name];
+ }
- this.items = new Array();
+ for (var name in this.requestOptions) {
+ if (typeof opts[name] == 'undefined') {
+ opts[name] = this.requestOptions[name];
+ }
+ }
+
+ return opts;
};
+
+ var QueueEntry = function() {
+ var ctor = function(queue, query, options, event) {
+ this.queue = queue;
+ this.query = query;
+ this.options = options;
+ this.event = event;
+
+ this.similarityGroupingId = this.options.similarityGroupingId;
+ this.eventsCount = 1;
+ };
- extend(Pipeline.prototype, function() {
-
- return {
- submit: function() {
- var data = this.items.shift();
- if (data) {
- this.createRequest(data);
- }
- },
+ extend(ctor.prototype, {
- createRequest: function(data) {
- LOG.debug("Queue '" + this.queue.name + "' will submit request
NOW");
- this.request = data.submit();
- this.similarityGroupingId = data.getSimilarityGroupingId();
- this.request.shouldNotifyQueue = true;
+ isIgnoreDupResponses: function() {
+ return this.options.ignoreDupResponses;
},
- clearRequest: function() {
- this.request = undefined;
- this.similarityGroupingId = undefined;
+ getSimilarityGroupingId: function() {
+ return this.similarityGroupingId;
},
- getSize: function() {
- var size = this.items.length;
+ setSimilarityGroupingId: function(id) {
+ this.similarityGroupingId = id;
+ },
+
+ submit: function() {
+ this.query.appendParameter("AJAX:EVENTS_COUNT", this.eventsCount);
+ this.request = A4J.AJAX.SubmitQuery(this.query, this.options, this.event)
+ var queue = this.queue;
+ this.request.queue = queue;
+
+ return this.request;
+ },
+
+ abort: function() {
if (this.request) {
- size++;
+ this.request.shouldNotifyQueue = false;
+ this.request.abort();
+ this.request = undefined;
}
-
- return size;
},
- dropFirst: function() {
- this.items.shift();
+ onRequestDelayPassed: function() {
+ this.readyToSubmit = true;
+ this.queue.submitFirst();
},
- fireFirst: function() {
- var data = this.items.shift();
- if (data) {
- data.submit()
- }
- },
+ startTimer: function() {
+ var delay = this.options.requestDelay;
+
+ LOG.debug("Queue will wait " + (delay || 0) + "ms before
submit");
- addEvent: function(data) {
- if (!this.isFull()) {
- this.items.push(data);
+ if (delay) {
+ var _this = this;
+ this.timer = setTimeout(function() {
+ try {
+ _this.onRequestDelayPassed();
+ } finally {
+ _this.timer = undefined;
+ _this = undefined;
+ }
+ }, delay);
} else {
- //log error
+ this.onRequestDelayPassed();
}
},
- //TODO new good name!
- submitEvent: function() {
- if (!this.request && !this.isEmpty()) {
- this.submit();
+ stopTimer: function() {
+ if (this.timer) {
+ clearTimeout(this.timer);
+ this.timer = undefined;
}
},
- submitNext: function() {
- this.clearRequest();
- LOG.debug("After request: queue '" + this.queue.name +
"'");
-
- if (this.getSize() > 0) {
- this.submit();
- } else {
- this.gate.transferIfReady();
- }
+ getEventsCount: function() {
+ return this.eventsCount;
},
- isFull: function() {
- return this.getSize() == this.size;
- },
-
- isEmpty: function() {
- return this.getSize() == 0;
- },
-
- hasNext: function() {
- return this.items.length != 0;
- },
-
- abortCurrentRequest: function() {
- if (this.request) {
- LOG.debug("Current request in queue '" + this.queue.name + "'
has been aborted");
-
- this.request.shouldNotifyQueue = false;
- this.request.abort();
- this.clearRequest();
- }
- },
-
- abortDupResponses: function(data) {
- if (!this.hasNext() && data.getSimilarityGroupingId() ==
this.similarityGroupingId) {
- this.abortCurrentRequest();
- }
+ setEventsCount: function(newCount) {
+ this.eventsCount = newCount;
}
- }
- }());
-
- var Gate = function(queue) {
- this.queue = queue;
+ });
- this.eventsCounter = 0;
+ return ctor;
+ }();
+
+ var Queue = function(name, queueOptions, requestOptions) {
+ this.items = new Array();
+
+ this.name = name;
+ this.queueOptions = queueOptions || {};
+ this.requestOptions = requestOptions || {};
};
+
+ extend(Queue.prototype, {
- extend(Gate.prototype, {
-
- stopRequestDelay: function () {
- if (this.timer) {
- clearTimeout(this.timer);
- this.timer = undefined;
- }
- },
-
- resetRequestDelay: function() {
- this.delayPassed = false;
-
- this.stopRequestDelay();
- this.startRequestDelay();
- },
-
- startRequestDelay: function() {
- var delay = this.data.getRequestDelay();
+ submitFirst: function() {
+ var firstItem = this.items[0];
+ if (firstItem) {
+ if (!firstItem.request) {
+ if (firstItem.readyToSubmit) {
+ LOG.debug("Queue '" + this.name + "' will submit request
NOW");
- LOG.debug("Queue will wait " + (delay || 0) + "ms before
submit");
-
- if (delay) {
- var _this = this;
- this.timer = setTimeout(function() {
- try {
- _this.transferIfEmpty();
- _this.timer = undefined;
- } finally {
- _this = undefined;
+ var req = firstItem.submit();
+ req.shouldNotifyQueue = true;
+
+ if (this.requestOptions.queueonsubmit) {
+ this.requestOptions.queueonsubmit.call(this, req);
+ }
+ } else {
+ LOG.debug("First item is not ready to be submitted yet");
}
- }, delay);
+ }
} else {
- this.transferIfEmpty();
+ LOG.debug("Queue is empty now");
}
},
- transferIfEmpty: function() {
- this.delayPassed = true;
-
- if (this.pipeline.isEmpty()) {
- this.pipeline.addEvent(this.pop());
- this.pipeline.submitEvent();
- }
+ getQueueSize: function() {
+ return this.queueOptions.size;
},
- transferIfReady: function() {
- if (this.delayPassed) {
- this.pipeline.addEvent(this.pop());
- this.pipeline.submitEvent();
+ getSizeExceededBehavior: function() {
+ var policy = this.queueOptions.sizeExceededBehavior;
+ if (!policy) {
+ policy = DROP_NEXT;
}
+
+ return policy;
},
- pop: function() {
- var data = this.data;
- this.data = undefined;
+ push: function(query, opts, event) {
+ var options = extendOptions.call(this, opts);
- this.eventsCounter = 0;
- this.similarityGroupingId = undefined;
- this.delayPassed = false;
+ var entry = new QueueEntry(this, query, options, event);
+ var similarityGroupingId = entry.getSimilarityGroupingId();
- return data;
- },
+ var lastIdx = this.items.length - 1;
+ var last = this.items[lastIdx];
+ var handled = false;
+
+ if (last) {
+ if (last.getSimilarityGroupingId() == similarityGroupingId) {
+ LOG.debug("Similar request currently in queue '" + this.name +
"'");
- push: function() {
- var DROP_NEW = 'dropNew';
- var DROP_NEXT = 'dropNext';
- var FIRE_NEW = 'fireNew';
- var FIRE_NEXT = 'fireNext';
+ if (last.request) {
+ LOG.debug("Request has already beeen sent to server");
+ if (entry.isIgnoreDupResponses()) {
+ LOG.debug("Duplicate responses ignore requested, queue will abort current
request");
- return function(data) {
- if (data.isIgnoreDupResponses()) {
- this.pipeline.abortDupResponses(data);
+ last.abort();
+
+ LOG.debug("Current request in queue '" + this.name + "' has
been aborted");
+
+ //remove last (that is actually first) from queue - will be safer to do that in
LinkedList
+ this.items.shift();
+ }
+ } else {
+ LOG.debug("Combine similar requests and reset timer");
+
+ handled = true;
+ last.stopTimer();
+ entry.setEventsCount(last.getEventsCount() + 1);
+
+ this.items[lastIdx] = entry;
+ entry.startTimer();
+ }
+ } else {
+ LOG.debug("Last queue entry is not the last anymore. Stopping requestDelay
timer and marking entry as ready for submission")
+
+ last.stopTimer();
+ last.setSimilarityGroupingId(undefined);
+ last.readyToSubmit = true;
}
-
- var similarityGroupingId = data.getSimilarityGroupingId();
-
- if (this.similarityGroupingId == similarityGroupingId) {
- LOG.debug("Similar request already in queue '" + this.queue.name +
"'");
- this.data = data;
- data.setEventsCounter(++this.eventsCounter);
+ }
- this.resetRequestDelay();
- } else {
- LOG.debug("New event added to queue '" + this.queue.name +
"'. Queue similarityGroupingId changed to " + similarityGroupingId);
- if (this.data) {
- this.stopRequestDelay();
- this.pipeline.addEvent(this.pop());
+ if (!handled) {
+ if (this.queueOptions.size == this.items.length) {
+ LOG.debug("Queue '" + this.name + "' is currently
full")
+
+ var b = this.getSizeExceededBehavior();
+
+ var nextIdx = 0;
+ while (this.items[nextIdx] && this.items[nextIdx].request) {
+ nextIdx++;
}
-
- var newDataHandled = false;
- if (this.pipeline.isFull()) {
- var behavior = data.getSizeExceededBehavior();
+ if (this.queueOptions.onsizeexceeded) {
+ this.queueOptions.onsizeexceeded.call(this, query, opts, event);
+ }
+
+ if (b == DROP_NEW) {
+ LOG.debug("Queue '" + this.name + "' is going to drop new
item");
- var queue = this.queue;
- var queueOptions = queue.queueOptions;
-
- if (queueOptions.onsizeexceeded) {
- var query = data.query;
- var options = data.options;
- var event = data.event;
+ handled = true;
+ } else if (b == DROP_NEXT) {
+ LOG.debug("Queue '" + this.name + "' is going to drop
[" + nextIdx + "] item that is the next one");
- queueOptions.onsizeexceeded.call(this.queue, query, options, event);
+ var nextEntry = this.items.splice(nextIdx, 1)[0];
+ if (nextEntry) {
+ LOG.debug("Item dropped from queue");
+ nextEntry.stopTimer();
+ } else {
+ LOG.debug("There's no such item, will handle new request instead");
+ handled = true;
}
+ } else if (b == FIRE_NEW) {
+ LOG.debug("Queue '" + this.name + "' will submit new
request");
- if (behavior == DROP_NEW ||
- (behavior == DROP_NEXT && !(this.pipeline.hasNext()))) {
-
- newDataHandled = true;
- } else if (behavior == FIRE_NEW ||
- (behavior == FIRE_NEXT && !(this.pipeline.hasNext()))) {
+ entry.submit();
+ handled = true;
+ } else if (b == FIRE_NEXT) {
+ LOG.debug("Queue '" + this.name + "' is going to drop and
fire immediately [" + nextIdx + "] item that is the next one");
- data.submit();
- newDataHandled = true;
- } else if (behavior == DROP_NEXT) {
- this.pipeline.dropFirst();
- } else if (behavior == FIRE_NEXT) {
- this.pipeline.fireFirst();
+ var nextEntry = this.items.splice(nextIdx, 1)[0];
+ if (nextEntry) {
+ LOG.debug("Item dropped from queue");
+ nextEntry.stopTimer();
+ nextEntry.submit();
+ } else {
+ LOG.debug("There's no such item, will handle new request instead");
+ entry.submit();
+ handled = true;
}
-
}
-
- this.pipeline.submitEvent();
-
- if (!newDataHandled) {
- this.data = data;
- this.similarityGroupingId = similarityGroupingId;
- this.startRequestDelay();
- }
}
+
+ this.submitFirst();
}
- }()
- });
- return function(name, queueOptions, requestOptions) {
- this.name = name;
- this.queueOptions = queueOptions || {};
- this.requestOptions = requestOptions || {};
-
- this.gate = new Gate(this);
- this.pipeline = new Pipeline(this.queueOptions.size, this.gate, this);
- this.gate.pipeline = this.pipeline;
- };
+ if (!handled) {
+ this.items.push(entry);
+
+ LOG.debug("New request added to queue '" + this.name + "'.
Queue similarityGroupingId changed to " + similarityGroupingId);
+
+ entry.startTimer();
+ }
+ },
+
+ pop: function() {
+ LOG.debug("After request: queue '" + this.name + "'");
+
+ this.items.shift();
+
+ LOG.debug("There are " + this.items.length + " requests more in this
queue");
+
+ this.submitFirst();
+ }
+ });
+
+ return Queue;
}();
A4J.AJAX.EventQueue.DEFAULT_QUEUE_NAME = "org.richfaces.queue.global";
@@ -317,11 +333,15 @@
var implicitQueueName;
if (queueName) {
+ LOG.debug("Look up queue with name '" + queueName + "'");
+
formQueueName = qualifyName(queueName, formId);
viewQueueName = qualifyNamespace(queueName, namespace);
implicitQueueName = viewQueueName;
} else {
+ LOG.debug("Look up queue with default name");
+
formQueueName = formId;
viewQueueName = qualifyNamespace(A4J.AJAX.EventQueue.DEFAULT_QUEUE_NAME, namespace);
@@ -331,124 +351,26 @@
var queue = A4J.AJAX._eventQueues[formQueueName];
if (!queue) {
queue = A4J.AJAX._eventQueues[viewQueueName];
- if (!queue && implicitQueueName) {
- queue = A4J.AJAX._eventQueues[implicitQueueName];
- if (!queue) {
- LOG.debug("Creating new transient queue '" + implicitQueueName +
"' with default settings");
- queue = new A4J.AJAX.EventQueue(implicitQueueName);
- queue._transient = true;
-
- A4J.AJAX.EventQueue.addQueue(queue);
+ if (!queue) {
+ if (implicitQueueName) {
+ queue = A4J.AJAX._eventQueues[implicitQueueName];
+ if (!queue) {
+ LOG.debug("Creating new transient queue '" + implicitQueueName +
"' with default settings");
+ queue = new A4J.AJAX.EventQueue(implicitQueueName);
+ queue._transient = true;
+
+ A4J.AJAX.EventQueue.addQueue(queue);
+ } else {
+ LOG.debug("Found transient queue '" + implicitQueueName +
"'");
+ }
}
+ } else {
+ LOG.debug("Found view queue '" + viewQueueName + "'");
}
+ } else {
+ LOG.debug("Found form queue '" + formQueueName + "'");
}
return queue;
}
-}();
-
-A4J.AJAX.EventQueue.prototype = function() {
- var EventQueueData = function(queue, query, options, event) {
- this.queue = queue;
- this.query = query;
- this.event = event;
-
- this.options = options || {};
-
- this.eventsCount = 1;
- };
-
- extend(EventQueueData.prototype, {
- submit: function() {
- this.query.appendParameter("AJAX:EVENTS_COUNT", this.eventsCount);
- this.request = A4J.AJAX.SubmitQuery(this.query, this.options, this.event);
-
- var queue = this.queue;
- this.request.queue = queue;
-
- if (this.options.queueonsubmit) {
- this.options.queueonsubmit.call(queue, this.request);
- }
-
- return this.request;
- },
-
- getSimilarityGroupingId: function() {
- return this.options.similarityGroupingId;
- },
-
- getRequestDelay: function() {
- return this.options.requestDelay;
- },
-
- getSizeExceededBehavior: function() {
- return this.queue.getSizeExceededBehavior();
- },
-
- isIgnoreDupResponses: function() {
- return this.options.ignoreDupResponses;
- },
-
- setEventsCounter: function(count) {
- this.eventsCount = count;
- }
- });
-
-
-// LOG.debug("Queue will wait " + (delay || 0) + "ms before
submit");
-// LOG.debug("Similar request already in queue '" + this.name +
"'");
-
-// LOG.debug("After request: queue '" + this.name + "' is empty
now");
-// LOG.debug("Deleting transient queue '" + this.name + "' from
queues registry");
-// LOG.debug("After request: queue not empty, processing next event in queue
'" + this.name + "'");
-
-// LOG.debug("Queue '" + this.name + "' will submit request
NOW");
-// LOG.debug("Delay for request not passed yet, have to wait");
-// LOG.debug("Queue '" + this.name + "' is empty, nothing to
submit");
-// LOG.debug("Request in queue '" + this.name + "' is active now,
wait until its completion");
-// LOG.debug("New event added to queue '" + this.name + "'. Queue
similarityGroupingId changed to " + similarityGroupingId);
-
- var extendOptions = function(options) {
- var opts = {};
-
- for (var name in options) {
- opts[name] = options[name];
- }
-
- for (var name in this.requestOptions) {
- if (typeof opts[name] == 'undefined') {
- opts[name] = this.requestOptions[name];
- }
- }
-
- return opts;
- };
-
- return {
- //TODO separate service functions
-
- getQueueSize: function() {
- return this.queueOptions.size;
- },
-
- getSizeExceededBehavior: function() {
- var policy = this.queueOptions.sizeExceededBehavior;
- if (!policy) {
- policy = 'dropNext';
- }
-
- return policy;
- },
-
- push: function(query, opts, event) {
- var options = extendOptions.call(this, opts);
- var queueData = new EventQueueData(this, query, options, event);
-
- this.gate.push(queueData);
- },
-
- pop: function() {
- this.pipeline.submitNext()
- }
- }
-}();
+}();
\ No newline at end of file