airbug/bugcore

View on GitHub
libraries/bugcore/js/src/publisher/Publisher.js

Summary

Maintainability
A
40 mins
Test Coverage
/*
 * Copyright (c) 2016 airbug Inc. http://airbug.com
 *
 * bugcore may be freely distributed under the MIT license.
 */


//-------------------------------------------------------------------------------
// Annotations
//-------------------------------------------------------------------------------

//@Export('Publisher')

//@Require('Class')
//@Require('List')
//@Require('Map')
//@Require('Obj')
//@Require('PublisherMessage')
//@Require('PublisherSubscription')


//-------------------------------------------------------------------------------
// Context
//-------------------------------------------------------------------------------

require('bugpack').context("*", function(bugpack) {

    //-------------------------------------------------------------------------------
    // BugPack
    //-------------------------------------------------------------------------------

    var Class                   = bugpack.require('Class');
    var List                    = bugpack.require('List');
    var Map                     = bugpack.require('Map');
    var Obj                     = bugpack.require('Obj');
    var PublisherMessage        = bugpack.require('PublisherMessage');
    var PublisherSubscription   = bugpack.require('PublisherSubscription');


    //-------------------------------------------------------------------------------
    // Declare Class
    //-------------------------------------------------------------------------------

    // NOTE BRN: The primary difference between an EventDispatcher and Publisher model is that in an EventDispatcher model
    // the listener knows which object it is listening to, so it's very understood where the EventListener is receiving
    // the event from. In a Publisher model, the 'listener' or receiver of a message does not know where the message originated
    // from. So it is much more anonymous. This model is better for cases where any number of objects can send a message
    // and you have fewer number of receivers of that message.

    /**
     * @class
     * @extends {Obj}
     */
    var Publisher = Class.extend(Obj, {

        _name: "Publisher",


        //-------------------------------------------------------------------------------
        // Constructor
        //-------------------------------------------------------------------------------

        /**
         * @constructs
         */
        _constructor: function() {

            this._super();


            //-------------------------------------------------------------------------------
            // Private Properties
            //-------------------------------------------------------------------------------

            /**
             * @private
             * @type {Map.<string, List.<PublisherSubscription>>}
             */
            this.topicToPublisherSubscriptionListMap = new Map();
        },


        //-------------------------------------------------------------------------------
        // Getters and Setters
        //-------------------------------------------------------------------------------

        /**
         * @param {string} topic
         * @return {number}
         */
        getCount: function(topic) {
            if (this.topicToPublisherSubscriptionListMap.containsKey(topic)) {
                var publisherSubscriptionList = this.topicToPublisherSubscriptionListMap.get(topic);
                return publisherSubscriptionList.getCount();
            }
            return 0;
        },


        //-------------------------------------------------------------------------------
        // Public Methods
        //-------------------------------------------------------------------------------

        /**
         * @param {string} topic
         */
        clear: function(topic) {
            this.topicToPublisherSubscriptionListMap.remove(topic);
        },

        /**
         *
         */
        clearAll: function() {
            this.topicToPublisherSubscriptionListMap.clear();
            this.topicToPublisherSubscriptionListMap = new Map();
        },

        /**
         * @param {string} topic
         * @param {*} data
         * @return {boolean}
         */
        publish: function(topic, data) {
            if (this.topicToPublisherSubscriptionListMap.containsKey(topic)) {
                var message = new PublisherMessage(topic, data);
                var oneTimeDeliveryPublisherSubscriptionList = new List();
                var publisherSubscriptionList = this.topicToPublisherSubscriptionListMap.get(topic);
                publisherSubscriptionList.forEach(function(publisherSubscription) {
                    publisherSubscription.deliverMessage(message);
                    if (publisherSubscription.isOneTimeDelivery()) {
                        oneTimeDeliveryPublisherSubscriptionList.add(publisherSubscription);
                    }
                });
                var _this = this;
                oneTimeDeliveryPublisherSubscriptionList.forEach(function(publisherSubscription) {
                    _this.removePublisherSubscription(publisherSubscription);
                });
                return true;
            }
            return false;
        },

        /**
         * Subscribing the same subscriber to the same topic will result in that subscriber being called multiple times.
         * @param {string} topic
         * @param {function(string, PublisherMessage)} subscriberFunction
         * @param {Object} subscriberContext
         * @return {string}
         */
        subscribe: function(topic, subscriberFunction, subscriberContext) {
            var publisherSubscription = new PublisherSubscription(topic, subscriberFunction, subscriberContext, false);
            return this.addPublisherSubscription(publisherSubscription);
        },

        /**
         * @param {string} topic
         * @param {function(string, PublisherMessage)} subscriberFunction
         * @param {Object} subscriberContext
         * @return {string}
         */
        subscribeOnce: function(topic, subscriberFunction, subscriberContext) {
            var publisherSubscription = new PublisherSubscription(topic, subscriberFunction, subscriberContext, true);
            return this.addPublisherSubscription(publisherSubscription);
        },

        /**
         * @param {string} topic
         * @param {function(string, PublisherMessage)} subscriberFunction
         * @param {Object} subscriberContext
         * @return {boolean}
         */
        unsubscribe: function(topic, subscriberFunction, subscriberContext) {
            var publisherSubscription = new PublisherSubscription(topic, subscriberFunction, subscriberContext, false);
            return this.removePublisherSubscription(publisherSubscription);
        },


        //-------------------------------------------------------------------------------
        // Private Methods
        //-------------------------------------------------------------------------------

        /**
         * @private
         * @param {PublisherSubscription} publisherSubscription
         */
        addPublisherSubscription: function(publisherSubscription) {
            var publisherSubscriptionList = this.topicToPublisherSubscriptionListMap.get(publisherSubscription.getTopic());
            if (publisherSubscriptionList === undefined) {
                publisherSubscriptionList = new List();
                this.topicToPublisherSubscriptionListMap.put(publisherSubscription.getTopic(), publisherSubscriptionList);
            }
            publisherSubscriptionList.add(publisherSubscription);
        },

        /**
         * @private
         * @param {PublisherSubscription} publisherSubscription
         */
        removePublisherSubscription: function(publisherSubscription) {
            var publisherSubscriptionList = this.topicToPublisherSubscriptionListMap.get(publisherSubscription.getTopic());
            if (publisherSubscriptionList) {
                return publisherSubscriptionList.remove(publisherSubscription);
            }
            return false;
        }
    });


    //-------------------------------------------------------------------------------
    // Exports
    //-------------------------------------------------------------------------------

    bugpack.export('Publisher', Publisher);
});