core
Version:
Core Libs
286 lines (253 loc) • 7.4 kB
JavaScript
/**
* @overview DecoratorChain
* @copyright Dreamlab Onet.pl sp. z. o o 2012
*/
var Event = require("../../event/Event.js").Event;
var ErrorEvent = require("../../event/ErrorEvent.js").ErrorEvent;
var EventDispatcher = require("../../event/EventDispatcher.js").EventDispatcher;
var AbstractDecorator = require("./AbstractDecorator.js").AbstractDecorator;
/**
* Responsible for collecting decorators and request/response process execution.
* @class DecoratorChain
* @extends EventDispatcher
*
* @requires Event
* @requires ErrorEvent
* @requires EventDispatcher
* @requires AbstractDecorator
*
* @returns {DecoratorChain}
*/
var DecoratorChain = function () {
EventDispatcher.call(this);
/**
* Holds currently decorated object
* @private
*/
this._decoratedObject = null;
/**
* Holds decorator's method to invoke
* @private
*/
this._decoratorMethod = null;
/**
* Holds decorators
* @private
* @type Array
*/
this._decorators = [];
/**
* Indicates decorator currently processing
* @private
*/
this._decorationProgress = 0;
/**
* Indicates current processing phase
* @type {String} Posibble values are {@link DecoratorChain.PROCESSING} or {@link DecoratorChain.STOPPED}.
*/
this.currentPhase = DecoratorChain.STOPPED;
};
DecoratorChain.prototype = Object.create(DecoratorChain.prototype);
/**
* Adds decorator to the chain
* @param {AbstractDecorator} decorator
* @method
* @returns {undefined}
*/
DecoratorChain.prototype.addDecorator = function (decorator) {
this._checkDecoratorType(decorator);
this._decorators.push(decorator);
decorator.addEventListener(AbstractDecorator.COMPLETE,
this._handleDecorationComplete, this);
decorator.addEventListener(AbstractDecorator.ERROR,
this._handleDecorationError, this);
};
/**
* Removes decorator from the chain
* @param {AbstractDecorator} decorator
* @returns {AbstractDecorator} removed decorator or null if decorator wasn't found in chain.
* @method
*/
DecoratorChain.prototype.removeDecorator = function (decorator) {
this._checkDecoratorType(decorator);
var i = 0, count = this._decorators.length;
while (i < count && this._decorators[i] != decorator) {
i++;
}
if (i < count) {
decorator.removeEventListener(AbstractDecorator.COMPLETE,
this._handleDecorationComplete, this);
return this._decorators.splice(i);
}
return null;
};
/**
* Indicates if decorator is a part of a chain.
* @param {AbstractDecorator} decorator
* @returns {Boolean}
* @method
*/
DecoratorChain.prototype.hasDecorator = function (decorator) {
this._checkDecoratorType(decorator);
var i = 0, count = this._decorators.length;
while (i < count && this._decorators[i] != decorator) {
i++;
console.log(i < count, this._decorators[i] != decorator);
}
if (i < count) {
return true;
}
return false;
};
/**
* Execute decoration process
* @param {Object} object
* @param {String} methodName
* @throws {DecoratorChain.Exeption.ALREADY_IN_PROGRESS}
* @throws {DecoratorChain.Exeption.WRONG_PARAMS}
* @returns {undefined}
* @method
*/
DecoratorChain.prototype.decorate = function (object, methodName) {
if (this.currentPhase == DecoratorChain.PROCESSING) {
throw DecoratorChain.Exeption.ALREADY_IN_PROGRESS;
}
if (!object || !methodName) {
throw DecoratorChain.Exeption.WRONG_PARAMS;
}
this.currentPhase = DecoratorChain.PROCESSING;
this._decoratedObject = object;
this._decoratorMethod = methodName;
this._decorationProgress = 0;
this._proceedDecoration();
};
/**
* Checks if given decorator is an instance of AbstractDecorator class
* @private
* @param {AbstractDecorato} decorator
* @throws {DecoratorChain.Exeption.WRONG_DECORATOR_TYPE}
* @method
*/
DecoratorChain.prototype._checkDecoratorType = function (decorator) {
if (!(decorator instanceof AbstractDecorator)) {
throw DecoratorChain.Exeption.WRONG_DECORATOR_TYPE;
}
};
/**
* Handles decorator COMPLETE event;
* @private
* @param {Event} e
* @throws {DecoratorChain.Exeption.FATAL_PROCESSING_ERROR}
* @method
*/
DecoratorChain.prototype._handleDecorationComplete = function (e) {
//console.log(" -- DecoratorChain: completed decorator no: " + this._decorationProgress);
if (this.currentPhase != DecoratorChain.PROCESSING) {
throw DecoratorChain.Exeption.FATAL_PROCESSING_ERROR;
}
this._decorationProgress++;
this._proceedDecoration();
};
/**
* Handles decorator ERROR event;
* @private
* @param {Event} e
* @throws {DecoratorChain.Exeption.FATAL_PROCESSING_ERROR}
* @fires DecoratorChain.Event.ERROR_DECORATOR_FAILED
* @method
*/
DecoratorChain.prototype._handleDecorationError = function (e) {
this.currentPhase = DecoratorChain.STOPPED;
this.dispatchEvent(new ErrorEvent(
DecoratorChain.Event.ERROR_DECORATOR_FAILED, e,
-32500, "Decorator processing failed."));
};
/**
* Proceeding decoration of currently decorated object with current decorator.
* @private
* @fires DecoratorChain.Event.COMPLETE
* @method
* @returns {undefined}
*/
DecoratorChain.prototype._proceedDecoration = function () {
//TODO timeout
if (this._decorationProgress < this._decorators.length) {
//console.log(" -- DecoratorChain: starting decorator no: " + this._decorationProgress);
this._decorators[this._decorationProgress][this._decoratorMethod](this._decoratedObject);
} else {
//console.log(" -- DecoratorChain: dispatching COMPLETE...");
this.currentPhase = DecoratorChain.STOPPED;
this.dispatchEvent(new Event(DecoratorChain.Event.COMPLETE, this._decoratedObject));
}
};
/**
* @constant
* @static
* @type {String}
* @default
*/
DecoratorChain.PROCESSING = "decoration_in_progress";
/**
* @constant
* @static
* @type {String}
* @default
*/
DecoratorChain.STOPPED = "stopped";
/**
* Namespace for event messages.
* @static
* @constant
* @namespace
*/
DecoratorChain.Event = {};
/**
* @constant
* @static
* @type {String}
* @default
*/
DecoratorChain.Event.COMPLETE = "complete";
/**
* @constant
* @static
* @type {String}
* @default
*/
DecoratorChain.Event.ERROR_DECORATOR_FAILED = "decorator_failed";
/**
* Namespace for exeptions messages.
* @static
* @constant
* @namespace
*/
DecoratorChain.Exeption = {};
/**
* @constant
* @static
* @type {String}
* @default
*/
DecoratorChain.Exeption.WRONG_DECORATOR_TYPE = "Given decorator must be AbstractDecorator type.";
/**
* @constant
* @static
* @type {String}
* @default
*/
DecoratorChain.Exeption.FATAL_PROCESSING_ERROR = "Fatal error. Processing completion handler was invoket but execution was initialized properly";
/**
* @constant
* @static
* @type {String}
* @default
*/
DecoratorChain.Exeption.ALREADY_IN_PROGRESS = "Decoration chain is already in progress";
/**
* @constant
* @static
* @type {String}
* @default
*/
DecoratorChain.Exeption.WRONG_PARAMS = "DecoratorChain:Incorrect params.";
exports.DecoratorChain = DecoratorChain;