All Downloads are FREE. Search and download functionalities are using the official Maven repository.

joynr.dispatching.subscription.SubscriptionManager.js Maven / Gradle / Ivy

/*jslint es5: true */

/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2016 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

define("joynr/dispatching/subscription/SubscriptionManager", [
    "global/Promise",
    "joynr/messaging/MessagingQos",
    "joynr/messaging/util/MulticastWildcardRegexFactory",
    "joynr/start/settings/defaultMessagingSettings",
    "joynr/proxy/SubscriptionQos",
    "joynr/dispatching/types/SubscriptionStop",
    "joynr/dispatching/types/SubscriptionRequest",
    "joynr/dispatching/types/MulticastSubscriptionRequest",
    "joynr/dispatching/types/BroadcastSubscriptionRequest",
    "joynr/dispatching/subscription/SubscriptionListener",
    "joynr/dispatching/subscription/util/SubscriptionUtil",
    "joynr/util/LongTimer",
    "joynr/system/LoggerFactory",
    "uuid",
    "joynr/util/UtilInternal",
    "joynr/util/Typing",
    "joynr/types/TypeRegistrySingleton",
    "joynr/exceptions/PublicationMissedException",
    "joynr/util/JSONSerializer"
], function(
        Promise,
        MessagingQos,
        MulticastWildcardRegexFactory,
        defaultMessagingSettings,
        SubscriptionQos,
        SubscriptionStop,
        SubscriptionRequest,
        MulticastSubscriptionRequest,
        BroadcastSubscriptionRequest,
        SubscriptionListener,
        SubscriptionUtil,
        LongTimer,
        LoggerFactory,
        uuid,
        Util,
        Typing,
        TypeRegistrySingleton,
        PublicationMissedException,
        JSONSerializer) {
    /**
     * @name SubscriptionManager
     * @constructor
     * @param {Dispatcher}
     *            dispatcher
     */
    function SubscriptionManager(dispatcher) {
        var multicastWildcardRegexFactory = new MulticastWildcardRegexFactory();
        var log = LoggerFactory.getLogger("joynr.dispatching.subscription.SubscriptionManager");
        var typeRegistry = TypeRegistrySingleton.getInstance();
        if (!(this instanceof SubscriptionManager)) {
            // in case someone calls constructor without new keyword (e.g. var c =
            // Constructor({..}))
            return new SubscriptionManager(dispatcher);
        }

        // stores subscriptionId - SubscriptionInfo pairs
        var subscriptionInfos = {};
        // stores subscriptionId - SubscriptionListener
        var subscriptionListeners = {};
        // stores the object which is returned by setTimeout mapped to the subscriptionId
        var publicationCheckTimerIds = {};
        var subscriptionReplyCallers = {};
        var started = true;

        var multicastSubscribers = {};

        function isReady() {
            return started;
        }

        /**
         * @param {String}
         *            subscriptionId Id of the subscription to check
         * @returns {Number} time of last received publication
         */
        function getLastPublicationTime(subscriptionId) {
            return subscriptionInfos[subscriptionId].lastPublicationTime_ms;
        }

        function setLastPublicationTime(subscriptionId, time_ms) {
            subscriptionInfos[subscriptionId].lastPublicationTime_ms = time_ms;
        }

        /**
         * @param {String}
         *            subscriptionId Id of the subscription to check
         * @param {Number}
         *            delay_ms Delay to the next publication check.
         * @returns {Boolean} true if subscription is expired, false if end date is not reached.
         */
        function subscriptionEnds(subscriptionId, delay_ms) {
            if (subscriptionInfos[subscriptionId] === undefined) {
                log.warn("subscriptionEnds has been called with unresolved subscriptionId \""
                    + subscriptionId
                    + "\"");
                return true;
            }
            var expiryDateMs = subscriptionInfos[subscriptionId].qos.expiryDateMs;
            // log.debug("Checking subscription end for subscriptionId: " + subscriptionId + "
            // expiryDateMs: " + expiryDateMs + "
            // current time: " + Date.now());
            var ends = expiryDateMs <= Date.now() + delay_ms;
            // if (ends === true) {
            // log.info("Subscription end date reached for id: " + subscriptionId);
            // }
            return ends;
        }

        /**
         * @param {String}
         *            subscriptionId Id of the subscription to check
         * @param {Number}
         *            alertAfterIntervalMs maximum delay between two incoming publications
         */
        function checkPublication(subscriptionId, alertAfterIntervalMs) {
            var subscriptionListener = subscriptionListeners[subscriptionId];
            var timeSinceLastPublication = Date.now() - getLastPublicationTime(subscriptionId);
            // log.debug("timeSinceLastPublication : " + timeSinceLastPublication + "
            // alertAfterIntervalMs: " + alertAfterIntervalMs);
            if (alertAfterIntervalMs > 0 && timeSinceLastPublication >= alertAfterIntervalMs) {
                // log.warn("publication missed for subscription id: " + subscriptionId);
                if (subscriptionListener.onError) {
                    var publicationMissedException = new PublicationMissedException({
                        detailMessage : "alertAfterIntervalMs period exceeded without receiving publication",
                        subscriptionId : subscriptionId
                    });
                    subscriptionListener.onError(publicationMissedException);
                }
            }

            var delay_ms;
            if (timeSinceLastPublication > alertAfterIntervalMs) {
                delay_ms = alertAfterIntervalMs;
            } else {
                delay_ms = alertAfterIntervalMs - timeSinceLastPublication;
            }
            if (!subscriptionEnds(subscriptionId, delay_ms)) {

                // log.debug("Rescheduling checkPublication with delay: " + delay_ms);
                publicationCheckTimerIds[subscriptionId] =
                        LongTimer.setTimeout(function checkPublicationDelay() {
                            checkPublication(subscriptionId, alertAfterIntervalMs);
                        }, delay_ms);
            }
        }

        function calculateTtl(subscriptionQos) {
            var ttl;
            if (subscriptionQos.expiryDateMs === SubscriptionQos.NO_EXPIRY_DATE) {
                return defaultMessagingSettings.MAX_MESSAGING_TTL_MS;
            }
            ttl = subscriptionQos.expiryDateMs - Date.now();
            if (ttl > defaultMessagingSettings.MAX_MESSAGING_TTL_MS) {
                return defaultMessagingSettings.MAX_MESSAGING_TTL_MS;
            }
            return ttl;
        }

        function storeSubscriptionRequest(settings, subscriptionRequest) {
            var onReceiveWrapper;
            if (settings.attributeType !== undefined) {
                onReceiveWrapper = function(response) {
                    settings.onReceive(Typing.augmentTypes(response[0], typeRegistry, settings.attributeType));
                };
            } else {
                onReceiveWrapper = function(response) {
                    var responseKey;
                    for (responseKey in response) {
                        if (response.hasOwnProperty(responseKey)) {
                            response[responseKey] = Typing.augmentTypes(response[responseKey],
                                                                        typeRegistry,
                                                                        settings.broadcastParameter[responseKey].type);
                        }
                    }
                    settings.onReceive(response);
                };
            }
            subscriptionListeners[subscriptionRequest.subscriptionId] = new SubscriptionListener({
                onReceive : onReceiveWrapper,
                onError : settings.onError,
                onSubscribed : settings.onSubscribed
            });
            var subscriptionInfo = Util.extend({
                proxyId : settings.proxyId,
                providerId : settings.providerId,
                lastPublicationTime_ms : 0
            }, subscriptionRequest);

            subscriptionInfos[subscriptionRequest.subscriptionId] = subscriptionInfo;

            var alertAfterIntervalMs = subscriptionRequest.qos.alertAfterIntervalMs;
            if (alertAfterIntervalMs !== undefined && alertAfterIntervalMs > 0) {
                publicationCheckTimerIds[subscriptionRequest.subscriptionId] =
                        LongTimer.setTimeout(
                                function checkPublicationAlertAfterInterval() {
                                    checkPublication(
                                            subscriptionRequest.subscriptionId,
                                            alertAfterIntervalMs);
                                },
                                alertAfterIntervalMs);
            }

        }

        function removeRequestFromMulticastSubscribers(multicastId, subscriptionId) {
            var i,multicastIdPattern, subscribers;
            for (multicastIdPattern in multicastSubscribers) {
                if (multicastSubscribers.hasOwnProperty(multicastIdPattern)) {
                    subscribers = multicastSubscribers[multicastIdPattern];
                    for(i=0;i 0;
        };

        this.hasOpenSubscriptions = function() {
            var hasSubscriptionInfos = Object.keys(subscriptionInfos).length > 0;
            var hasSubscriptionListeners = Object.keys(subscriptionListeners).length > 0;
            var hasPublicationCheckTimerIds = Object.keys(publicationCheckTimerIds).length > 0;
            var hasSubscriptionReplyCallers = Object.keys(subscriptionReplyCallers).length > 0;
            return hasSubscriptionInfos ||
                   hasSubscriptionListeners ||
                   hasPublicationCheckTimerIds ||
                   hasSubscriptionReplyCallers ||
                   this.hasMulticastSubscriptions();
        };

        /**
         * Shutdown the subscription manager
         *
         * @function
         * @name SubscriptionManager#shutdown
         */
        this.shutdown = function shutdown() {
            var subscriptionId;
            for (subscriptionId in publicationCheckTimerIds) {
                if (publicationCheckTimerIds.hasOwnProperty(subscriptionId)) {
                    var timerId = publicationCheckTimerIds[subscriptionId];
                    if (timerId !== undefined) {
                        LongTimer.clearTimeout(timerId);
                    }
                }
            }
            publicationCheckTimerIds = {};
            for (subscriptionId in subscriptionReplyCallers) {
                if (subscriptionReplyCallers.hasOwnProperty(subscriptionId)) {
                    var subscriptionReplyCaller = subscriptionReplyCallers[subscriptionId];
                    if (subscriptionReplyCaller) {
                        subscriptionReplyCaller.reject(new Error("Subscription Manager is already shut down"));
                    }
                }
            }
            subscriptionReplyCallers = {};
            started = false;
        };
    }

    return SubscriptionManager;
});




© 2015 - 2025 Weber Informatics LLC | Privacy Policy