Source: core/PubQueue.js

/**
 * Copyright (C) 2005-2016 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Singleton providing class for handling publications. This allows publications to be queued whilst all the
 * widgets on the page are created. The overall [page widget]{@link module:alfresco/core/Page} will then "release"
 * all the publications once the widgets are ready to process them.
 *  
 * @module alfresco/core/PubQueue
 * @author Dave Draper
 */
define(["dojo/_base/declare",
        "dojo/_base/lang",
        "dojo/_base/array",
        "dojo/topic",
        "alfresco/core/PubSubLog",
        "service/constants/Default"], 
        function(declare, lang, array, pubSub, PubSubLog, AlfConstants) {

   // This is a simple singleton pattern. Technically it is still possible to instantiate a new log,
   // but as the core will always use the singleton and it is expected that all calls will go through the core
   // then this shouldn't be a problem...
   var PubQueue = declare(null, {
      
      /**
       * Indicates whether or not the publications have been released. This is set from false to true
       * when the [release]{@link module:alfresco/core/PubQueue#release} function is called and will result
       * in publications no longer being queue but being published immediated
       *
       * @instance
       * @type {boolean}
       * @default
       */
      _released: false,

      /**
       * To make sure that all publications are made in order after releasing, this flag is used to indicate
       * that all queued publications have been made before publishing resulting publications. An example of this
       * would be where a queued publication triggers another publication - it is imperative that this resulting
       * publication does not "jump the queue". Instead it should itself be queued and wait for its turn.
       * 
       * @instance
       * @type {boolean}
       * @default
       * @since 1.0.65
       */
      _unreleasedEmptied: false,

      /**
       * @instance
       * @type {array}
       * @default []
       */
      _queue: [],

      /**
       * It is possible for multiple Surf Components to exist on a browser page where each Surf Component is creating
       * a new Aikau page. In order for the PubQueue to only allow the release of publications once all pages have 
       * finished being created it is necessary to track the number of pages being rendered. This counter is 
       * incremented with every call to [registerPage]{@link module:alfresco/core/PubQueue#registerPage} and
       * decremented with every call to [release]{@link module:alfresco/core/PubQueue#release}. See AKU-965 for more
       * information.
       * 
       * @instance
       * @type {number}
       * @default
       * @since 1.0.68
       */
      _pageCount: 0,
      
      /**
       * This function should only be called from the [Page]{@link module:alfresco/core/Page} widget before the page
       * is constructed. It increments the [_pageCount]{@link module:alfresco/core/PubQueue#_pageCount} counter to ensure
       * that all pages finish rendering before publications are released.
       * 
       * @instance
       * @since 1.0.68
       */
      registerPage: function alfresco_core_PubQueue__registerPage() {
         this._pageCount++;
         this._released = false;
         this._unreleasedEmptied = false;
      },

      /**
       * @instance
       * @param {string} scopedTopic The topic to publish on
       * @param {string} payload The payload to be delivered
       */
      publish: function alfresco_core_PubQueue__publish(scopedTopic, payload, caller) {
         if (this._released === false || this._unreleasedEmptied === false)
         {
            this._queue.push({
               topic: scopedTopic,
               payload: payload,
               caller: caller
            });
         }
         else
         {
            this.log(scopedTopic, payload, caller);
            pubSub.publish(scopedTopic, payload);
         }
      },

      /**
       * Iterates over the queued publications and publishes them.
       *
       * @instance
       */
      release: function alfresco_core_PubQueue__release() {
         this._pageCount--;
         if (this._pageCount === 0)
         {
            this._released = true;
            var publication = this._queue.shift();
            while (publication)
            {
               this.log(publication.topic, publication.payload, publication.caller);
               pubSub.publish(publication.topic, publication.payload);
               publication = this._queue.shift();
            }
            this._unreleasedEmptied = true;
         }
      },

      /**
       * Logs the publication if the publication to be logged isn't a log request or 
       * a request to log publications or subscriptions.
       * 
       * @param {string} scopedTopic The topic to publish on
       * @param {object} payload The payload to be delivered
       * @param {object} caller The widget or service requesting the publication
       */
      log: function alfresco_core_PubQueue__log(scopedTopic, payload, caller) {
         if (scopedTopic && (scopedTopic !== "ALF_LOG_REQUEST" &&
                             scopedTopic !== "ALF_LOG_PUBLICATION_ACTIVITY" &&
                             scopedTopic !== "ALF_LOG_SUBSCRIPTION_ACTIVITY" &&
                             scopedTopic !== "ALF_LOG_UNSUBSCRIPTION_ACTIVITY"))
         {
            if (AlfConstants.DEBUG === true)
            {
               PubSubLog.getSingleton().pub(scopedTopic, payload, caller);
               pubSub.publish("ALF_LOG_PUBLICATION_ACTIVITY", payload, caller);
            }
         }
      }
   });
   
   var instance; 
   PubQueue.getSingleton = function() {
      if (!instance)
      {
         instance = new PubQueue(); 
      }
      return instance;
   };
   return PubQueue;
});