Home | History | Annotate | Download | only in metadata
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 'use strict';
      6 
      7 /**
      8  * @class FunctionSequence to invoke steps in sequence
      9  *
     10  * @param {string} name                // TODO(JSDOC).
     11  * @param {Array} steps                array of functions to invoke in sequence.
     12  * @param {Object} logger              logger.
     13  * @param {function} callback          callback to invoke on success.
     14  * @param {function} failureCallback   callback to invoke on failure.
     15  * @constructor
     16  */
     17 function FunctionSequence(name, steps, logger, callback, failureCallback) {
     18   // Private variables hidden in closure
     19   this.currentStepIdx_ = -1;
     20   this.failed_ = false;
     21   this.steps_ = steps;
     22   this.callback_ = callback;
     23   this.failureCallback_ = failureCallback;
     24   this.logger = logger;
     25   this.name = name;
     26 
     27   this.onError = this.onError_.bind(this);
     28   this.finish = this.finish_.bind(this);
     29   this.nextStep = this.nextStep_.bind(this);
     30   this.apply = this.apply_.bind(this);
     31 }
     32 
     33 /**
     34  * Sets new callback
     35  *
     36  * @param {function} callback new callback to call on succeed.
     37  */
     38 FunctionSequence.prototype.setCallback = function(callback) {
     39     this.callback_ = callback;
     40 };
     41 
     42 /**
     43  * Sets new error callback
     44  *
     45  * @param {function} failureCallback new callback to call on failure.
     46  */
     47 FunctionSequence.prototype.setFailureCallback = function(failureCallback) {
     48     this.failureCallback_ = failureCallback;
     49 };
     50 
     51 
     52 /**
     53  * Error handling function, which traces current error step, stops sequence
     54  * advancing and fires error callback.
     55  *
     56  * @param {string} err Error message.
     57  * @private
     58  */
     59 FunctionSequence.prototype.onError_ = function(err) {
     60   this.logger.vlog('Failed step: ' + this.steps_[this.currentStepIdx_].name +
     61                    ': ' + err);
     62   if (!this.failed_) {
     63     this.failed_ = true;
     64     this.failureCallback_(err);
     65   }
     66 };
     67 
     68 /**
     69  * Finishes sequence processing and jumps to the last step.
     70  * This method should not be used externally. In external
     71  * cases should be used finish function, which is defined in closure and thus
     72  * has access to internal variables of functionsequence.
     73  * @private
     74  */
     75 FunctionSequence.prototype.finish_ = function() {
     76   if (!this.failed_ && this.currentStepIdx_ < this.steps_.length) {
     77     this.currentStepIdx_ = this.steps_.length;
     78     this.callback_();
     79   }
     80 };
     81 
     82 /**
     83  * Advances to next step.
     84  * This method should not be used externally. In external
     85  * cases should be used nextStep function, which is defined in closure and thus
     86  * has access to internal variables of functionsequence.
     87  * @private
     88  * @param {...} var_args  // TODO(JSDOC).
     89  */
     90 FunctionSequence.prototype.nextStep_ = function(var_args) {
     91   if (this.failed_) {
     92     return;
     93   }
     94 
     95   if (++this.currentStepIdx_ >= this.steps_.length) {
     96     this.logger.vlog('Sequence ended');
     97     this.callback_.apply(this, arguments);
     98   } else {
     99     this.logger.vlog('Attempting to start step [' +
    100                      this.steps_[this.currentStepIdx_].name +
    101                      ']');
    102     try {
    103       this.steps_[this.currentStepIdx_].apply(this, arguments);
    104     } catch (e) {
    105       this.onError(e.toString());
    106     }
    107   }
    108 };
    109 
    110 /**
    111  * This function should be called only once on start, so start sequence pipeline
    112  * @param {...} var_args  // TODO(JSDOC).
    113  */
    114 FunctionSequence.prototype.start = function(var_args) {
    115   if (this.started) {
    116     throw new Error('"Start" method of FunctionSequence was called twice');
    117   }
    118 
    119   this.logger.log('Starting sequence with ' + arguments.length + ' arguments');
    120 
    121   this.started = true;
    122   this.nextStep.apply(this, arguments);
    123 };
    124 
    125 /**
    126  * Add Function object mimics to FunctionSequence
    127  * @private
    128  * @param {*} obj  // TODO(JSDOC).
    129  * @param {Array.*} args  // TODO(JSDOC).
    130  */
    131 FunctionSequence.prototype.apply_ = function(obj, args) {
    132   this.start.apply(this, args);
    133 };
    134