Path: blob/trunk/third_party/closure/goog/messaging/abstractchannel.js
2868 views
// Copyright 2010 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview An abstract superclass for message channels that handles the16* repetitive details of registering and dispatching to services. This is more17* useful for full-fledged channels than for decorators, since decorators18* generally delegate service registering anyway.19*20*/212223goog.provide('goog.messaging.AbstractChannel');2425goog.require('goog.Disposable');26goog.require('goog.json');27goog.require('goog.log');28goog.require('goog.messaging.MessageChannel'); // interface29303132/**33* Creates an abstract message channel.34*35* @constructor36* @extends {goog.Disposable}37* @implements {goog.messaging.MessageChannel}38*/39goog.messaging.AbstractChannel = function() {40goog.messaging.AbstractChannel.base(this, 'constructor');4142/**43* The services registered for this channel.44* @type {Object<string, {callback: function((string|!Object)),45objectPayload: boolean}>}46* @private47*/48this.services_ = {};49};50goog.inherits(goog.messaging.AbstractChannel, goog.Disposable);515253/**54* The default service to be run when no other services match.55*56* @type {?function(string, (string|!Object))}57* @private58*/59goog.messaging.AbstractChannel.prototype.defaultService_;606162/**63* Logger for this class.64* @type {goog.log.Logger}65* @protected66*/67goog.messaging.AbstractChannel.prototype.logger =68goog.log.getLogger('goog.messaging.AbstractChannel');697071/**72* Immediately calls opt_connectCb if given, and is otherwise a no-op. If73* subclasses have configuration that needs to happen before the channel is74* connected, they should override this and {@link #isConnected}.75* @override76*/77goog.messaging.AbstractChannel.prototype.connect = function(opt_connectCb) {78if (opt_connectCb) {79opt_connectCb();80}81};828384/**85* Always returns true. If subclasses have configuration that needs to happen86* before the channel is connected, they should override this and87* {@link #connect}.88* @override89*/90goog.messaging.AbstractChannel.prototype.isConnected = function() {91return true;92};939495/** @override */96goog.messaging.AbstractChannel.prototype.registerService = function(97serviceName, callback, opt_objectPayload) {98this.services_[serviceName] = {99callback: callback,100objectPayload: !!opt_objectPayload101};102};103104105/** @override */106goog.messaging.AbstractChannel.prototype.registerDefaultService = function(107callback) {108this.defaultService_ = callback;109};110111112/** @override */113goog.messaging.AbstractChannel.prototype.send = goog.abstractMethod;114115116/**117* Delivers a message to the appropriate service. This is meant to be called by118* subclasses when they receive messages.119*120* This method takes into account both explicitly-registered and default121* services, as well as making sure that JSON payloads are decoded when122* necessary. If the subclass is capable of passing objects as payloads, those123* objects can be passed in to this method directly. Otherwise, the (potentially124* JSON-encoded) strings should be passed in.125*126* @param {string} serviceName The name of the service receiving the message.127* @param {string|!Object} payload The contents of the message.128* @protected129*/130goog.messaging.AbstractChannel.prototype.deliver = function(131serviceName, payload) {132var service = this.getService(serviceName, payload);133if (!service) {134return;135}136137var decodedPayload =138this.decodePayload(serviceName, payload, service.objectPayload);139if (goog.isDefAndNotNull(decodedPayload)) {140service.callback(decodedPayload);141}142};143144145/**146* Find the service object for a given service name. If there's no service147* explicitly registered, but there is a default service, a service object is148* constructed for it.149*150* @param {string} serviceName The name of the service receiving the message.151* @param {string|!Object} payload The contents of the message.152* @return {?{callback: function((string|!Object)), objectPayload: boolean}} The153* service object for the given service, or null if none was found.154* @protected155*/156goog.messaging.AbstractChannel.prototype.getService = function(157serviceName, payload) {158var service = this.services_[serviceName];159if (service) {160return service;161} else if (this.defaultService_) {162var callback = goog.partial(this.defaultService_, serviceName);163var objectPayload = goog.isObject(payload);164return {callback: callback, objectPayload: objectPayload};165}166167goog.log.warning(this.logger, 'Unknown service name "' + serviceName + '"');168return null;169};170171172/**173* Converts the message payload into the format expected by the registered174* service (either JSON or string).175*176* @param {string} serviceName The name of the service receiving the message.177* @param {string|!Object} payload The contents of the message.178* @param {boolean} objectPayload Whether the service expects an object or a179* plain string.180* @return {string|Object} The payload in the format expected by the service, or181* null if something went wrong.182* @protected183*/184goog.messaging.AbstractChannel.prototype.decodePayload = function(185serviceName, payload, objectPayload) {186if (objectPayload && goog.isString(payload)) {187try {188return goog.json.parse(payload);189} catch (err) {190goog.log.warning(191this.logger, 'Expected JSON payload for ' + serviceName + ', was "' +192payload + '"');193return null;194}195} else if (!objectPayload && !goog.isString(payload)) {196return goog.json.serialize(payload);197}198return payload;199};200201202/** @override */203goog.messaging.AbstractChannel.prototype.disposeInternal = function() {204goog.messaging.AbstractChannel.base(this, 'disposeInternal');205delete this.services_;206delete this.defaultService_;207};208209210