Path: blob/trunk/third_party/closure/goog/labs/net/webchannel/webchannelbasetransport.js
1865 views
// Copyright 2013 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 Implementation of a WebChannel transport using WebChannelBase.16*17* When WebChannelBase is used as the underlying transport, the capabilities18* of the WebChannel are limited to what's supported by the implementation.19* Particularly, multiplexing is not possible, and only strings are20* supported as message types.21*22*/2324goog.provide('goog.labs.net.webChannel.WebChannelBaseTransport');2526goog.require('goog.asserts');27goog.require('goog.events.EventTarget');28goog.require('goog.json');29goog.require('goog.labs.net.webChannel.ChannelRequest');30goog.require('goog.labs.net.webChannel.WebChannelBase');31goog.require('goog.log');32goog.require('goog.net.WebChannel');33goog.require('goog.net.WebChannelTransport');34goog.require('goog.object');35goog.require('goog.string');36goog.require('goog.string.path');37383940/**41* Implementation of {@link goog.net.WebChannelTransport} with42* {@link goog.labs.net.webChannel.WebChannelBase} as the underlying channel43* implementation.44*45* @constructor46* @struct47* @implements {goog.net.WebChannelTransport}48* @final49*/50goog.labs.net.webChannel.WebChannelBaseTransport = function() {51if (!goog.labs.net.webChannel.ChannelRequest.supportsXhrStreaming()) {52throw new Error('Environmental error: no available transport.');53}54};555657goog.scope(function() {58var WebChannelBaseTransport = goog.labs.net.webChannel.WebChannelBaseTransport;59var WebChannelBase = goog.labs.net.webChannel.WebChannelBase;606162/**63* @override64*/65WebChannelBaseTransport.prototype.createWebChannel = function(66url, opt_options) {67return new WebChannelBaseTransport.Channel(url, opt_options);68};69707172/**73* Implementation of the {@link goog.net.WebChannel} interface.74*75* @param {string} url The URL path for the new WebChannel instance.76* @param {!goog.net.WebChannel.Options=} opt_options Configuration for the77* new WebChannel instance.78*79* @constructor80* @implements {goog.net.WebChannel}81* @extends {goog.events.EventTarget}82* @final83*/84WebChannelBaseTransport.Channel = function(url, opt_options) {85WebChannelBaseTransport.Channel.base(this, 'constructor');8687/**88* @private {!WebChannelBase} The underlying channel object.89*/90this.channel_ = new WebChannelBase(91opt_options, goog.net.WebChannelTransport.CLIENT_VERSION);9293/**94* @private {string} The URL of the target server end-point.95*/96this.url_ = url;9798/**99* The test URL of the target server end-point. This value defaults to100* this.url_ + '/test'.101*102* @private {string}103*/104this.testUrl_ = (opt_options && opt_options.testUrl) ?105opt_options.testUrl :106goog.string.path.join(this.url_, 'test');107108/**109* @private {goog.log.Logger} The logger for this class.110*/111this.logger_ =112goog.log.getLogger('goog.labs.net.webChannel.WebChannelBaseTransport');113114/**115* @private {Object<string, string>} Extra URL parameters116* to be added to each HTTP request.117*/118this.messageUrlParams_ =119(opt_options && opt_options.messageUrlParams) || null;120121var messageHeaders = (opt_options && opt_options.messageHeaders) || null;122123// default is false124if (opt_options && opt_options.clientProtocolHeaderRequired) {125if (messageHeaders) {126goog.object.set(127messageHeaders, goog.net.WebChannel.X_CLIENT_PROTOCOL,128goog.net.WebChannel.X_CLIENT_PROTOCOL_WEB_CHANNEL);129} else {130messageHeaders = goog.object.create(131goog.net.WebChannel.X_CLIENT_PROTOCOL,132goog.net.WebChannel.X_CLIENT_PROTOCOL_WEB_CHANNEL);133}134}135136this.channel_.setExtraHeaders(messageHeaders);137138var initHeaders = (opt_options && opt_options.initMessageHeaders) || null;139this.channel_.setInitHeaders(initHeaders);140141var httpHeadersOverwriteParam =142opt_options && opt_options.httpHeadersOverwriteParam;143if (httpHeadersOverwriteParam &&144!goog.string.isEmptyOrWhitespace(httpHeadersOverwriteParam)) {145this.channel_.setHttpHeadersOverwriteParam(httpHeadersOverwriteParam);146}147148/**149* @private {boolean} Whether to enable CORS.150*/151this.supportsCrossDomainXhr_ =152(opt_options && opt_options.supportsCrossDomainXhr) || false;153154/**155* @private {boolean} Whether to send raw Json and bypass v8 wire format.156*/157this.sendRawJson_ = (opt_options && opt_options.sendRawJson) || false;158159// Note that httpSessionIdParam will be ignored if the same parameter name160// has already been specified with messageUrlParams161var httpSessionIdParam = opt_options && opt_options.httpSessionIdParam;162if (httpSessionIdParam &&163!goog.string.isEmptyOrWhitespace(httpSessionIdParam)) {164this.channel_.setHttpSessionIdParam(httpSessionIdParam);165if (goog.object.containsKey(this.messageUrlParams_, httpSessionIdParam)) {166goog.object.remove(this.messageUrlParams_, httpSessionIdParam);167goog.log.warning(this.logger_,168'Ignore httpSessionIdParam also specified with messageUrlParams: '169+ httpSessionIdParam);170}171}172173/**174* The channel handler.175*176* @private {!WebChannelBaseTransport.Channel.Handler_}177*/178this.channelHandler_ = new WebChannelBaseTransport.Channel.Handler_(this);179};180goog.inherits(WebChannelBaseTransport.Channel, goog.events.EventTarget);181182183/**184* @override185* @suppress {checkTypes}186*/187WebChannelBaseTransport.Channel.prototype.addEventListener = function(188type, handler, /** boolean= */ opt_capture, opt_handlerScope) {189WebChannelBaseTransport.Channel.base(190this, 'addEventListener', type, handler, opt_capture, opt_handlerScope);191};192193194/**195* @override196* @suppress {checkTypes}197*/198WebChannelBaseTransport.Channel.prototype.removeEventListener = function(199type, handler, /** boolean= */ opt_capture, opt_handlerScope) {200WebChannelBaseTransport.Channel.base(201this, 'removeEventListener', type, handler, opt_capture,202opt_handlerScope);203};204205206/**207* Test path is always set to "/url/test".208*209* @override210*/211WebChannelBaseTransport.Channel.prototype.open = function() {212this.channel_.setHandler(this.channelHandler_);213if (this.supportsCrossDomainXhr_) {214this.channel_.setSupportsCrossDomainXhrs(true);215}216this.channel_.connect(217this.testUrl_, this.url_, (this.messageUrlParams_ || undefined));218};219220221/**222* @override223*/224WebChannelBaseTransport.Channel.prototype.close = function() {225this.channel_.disconnect();226};227228229/**230* The WebChannelBase only supports object types.231*232* @param {!goog.net.WebChannel.MessageData} message The message to send.233*234* @override235*/236WebChannelBaseTransport.Channel.prototype.send = function(message) {237goog.asserts.assert(goog.isObject(message), 'only object type expected');238239if (this.sendRawJson_) {240var rawJson = {};241rawJson['__data__'] = goog.json.serialize(message);242this.channel_.sendMap(rawJson);243} else {244this.channel_.sendMap(message);245}246};247248249/**250* @override251*/252WebChannelBaseTransport.Channel.prototype.disposeInternal = function() {253this.channel_.setHandler(null);254delete this.channelHandler_;255this.channel_.disconnect();256delete this.channel_;257258WebChannelBaseTransport.Channel.base(this, 'disposeInternal');259};260261262263/**264* The message event.265*266* @param {!Array<?>} array The data array from the underlying channel.267* @constructor268* @extends {goog.net.WebChannel.MessageEvent}269* @final270*/271WebChannelBaseTransport.Channel.MessageEvent = function(array) {272WebChannelBaseTransport.Channel.MessageEvent.base(this, 'constructor');273274this.data = array;275};276goog.inherits(277WebChannelBaseTransport.Channel.MessageEvent,278goog.net.WebChannel.MessageEvent);279280281282/**283* The error event.284*285* @param {WebChannelBase.Error} error The error code.286* @constructor287* @extends {goog.net.WebChannel.ErrorEvent}288* @final289*/290WebChannelBaseTransport.Channel.ErrorEvent = function(error) {291WebChannelBaseTransport.Channel.ErrorEvent.base(this, 'constructor');292293/**294* High-level status code.295*/296this.status = goog.net.WebChannel.ErrorStatus.NETWORK_ERROR;297298/**299* @const {WebChannelBase.Error} Internal error code, for debugging use only.300*/301this.errorCode = error;302};303goog.inherits(304WebChannelBaseTransport.Channel.ErrorEvent, goog.net.WebChannel.ErrorEvent);305306307308/**309* Implementation of {@link WebChannelBase.Handler} interface.310*311* @param {!WebChannelBaseTransport.Channel} channel The enclosing WebChannel.312*313* @constructor314* @extends {WebChannelBase.Handler}315* @private316*/317WebChannelBaseTransport.Channel.Handler_ = function(channel) {318WebChannelBaseTransport.Channel.Handler_.base(this, 'constructor');319320/**321* @type {!WebChannelBaseTransport.Channel}322* @private323*/324this.channel_ = channel;325};326goog.inherits(WebChannelBaseTransport.Channel.Handler_, WebChannelBase.Handler);327328329/**330* @override331*/332WebChannelBaseTransport.Channel.Handler_.prototype.channelOpened = function(333channel) {334goog.log.info(335this.channel_.logger_, 'WebChannel opened on ' + this.channel_.url_);336this.channel_.dispatchEvent(goog.net.WebChannel.EventType.OPEN);337};338339340/**341* @override342*/343WebChannelBaseTransport.Channel.Handler_.prototype.channelHandleArray =344function(channel, array) {345goog.asserts.assert(array, 'array expected to be defined');346this.channel_.dispatchEvent(347new WebChannelBaseTransport.Channel.MessageEvent(array));348};349350351/**352* @override353*/354WebChannelBaseTransport.Channel.Handler_.prototype.channelError = function(355channel, error) {356goog.log.info(357this.channel_.logger_, 'WebChannel aborted on ' + this.channel_.url_ +358' due to channel error: ' + error);359this.channel_.dispatchEvent(360new WebChannelBaseTransport.Channel.ErrorEvent(error));361};362363364/**365* @override366*/367WebChannelBaseTransport.Channel.Handler_.prototype.channelClosed = function(368channel, opt_pendingMaps, opt_undeliveredMaps) {369goog.log.info(370this.channel_.logger_, 'WebChannel closed on ' + this.channel_.url_);371this.channel_.dispatchEvent(goog.net.WebChannel.EventType.CLOSE);372};373374375/**376* @override377*/378WebChannelBaseTransport.Channel.prototype.getRuntimeProperties = function() {379return new WebChannelBaseTransport.ChannelProperties(this.channel_);380};381382383384/**385* Implementation of the {@link goog.net.WebChannel.RuntimeProperties}.386*387* @param {!WebChannelBase} channel The underlying channel object.388*389* @constructor390* @implements {goog.net.WebChannel.RuntimeProperties}391* @final392*/393WebChannelBaseTransport.ChannelProperties = function(channel) {394/**395* The underlying channel object.396*397* @private {!WebChannelBase}398*/399this.channel_ = channel;400401};402403404/**405* @override406*/407WebChannelBaseTransport.ChannelProperties.prototype.getConcurrentRequestLimit =408function() {409return this.channel_.getForwardChannelRequestPool().getMaxSize();410};411412413/**414* @override415*/416WebChannelBaseTransport.ChannelProperties.prototype.isSpdyEnabled = function() {417return this.getConcurrentRequestLimit() > 1;418};419420421/**422* @override423*/424WebChannelBaseTransport.ChannelProperties.prototype.getHttpSessionId =425function() {426return this.channel_.getHttpSessionId();427};428429430/**431* @override432*/433WebChannelBaseTransport.ChannelProperties.prototype.commit =434goog.abstractMethod;435436437/**438* @override439*/440WebChannelBaseTransport.ChannelProperties.prototype.getNonAckedMessageCount =441goog.abstractMethod;442443444/**445* @override446*/447WebChannelBaseTransport.ChannelProperties.prototype.notifyNonAckedMessageCount =448goog.abstractMethod;449450451/**452* @override453*/454WebChannelBaseTransport.ChannelProperties.prototype.onCommit =455goog.abstractMethod;456457458/**459* @override460*/461WebChannelBaseTransport.ChannelProperties.prototype.ackCommit =462goog.abstractMethod;463464465/** @override */466WebChannelBaseTransport.ChannelProperties.prototype.getLastStatusCode =467function() {468return this.channel_.getLastStatusCode();469};470}); // goog.scope471472473