Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/messaging/multichannel.js
2868 views
1
// Copyright 2010 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Definition of goog.messaging.MultiChannel, which uses a
17
* single underlying MessageChannel to carry several independent virtual message
18
* channels.
19
*
20
*/
21
22
23
goog.provide('goog.messaging.MultiChannel');
24
goog.provide('goog.messaging.MultiChannel.VirtualChannel');
25
26
goog.require('goog.Disposable');
27
goog.require('goog.log');
28
goog.require('goog.messaging.MessageChannel'); // interface
29
goog.require('goog.object');
30
31
32
33
/**
34
* Creates a new MultiChannel wrapping a single MessageChannel. The
35
* underlying channel shouldn't have any other listeners registered, but it
36
* should be connected.
37
*
38
* Note that the other side of the channel should also be connected to a
39
* MultiChannel with the same number of virtual channels.
40
*
41
* @param {goog.messaging.MessageChannel} underlyingChannel The underlying
42
* channel to use as transport for the virtual channels.
43
* @constructor
44
* @extends {goog.Disposable}
45
* @final
46
*/
47
goog.messaging.MultiChannel = function(underlyingChannel) {
48
goog.messaging.MultiChannel.base(this, 'constructor');
49
50
/**
51
* The underlying channel across which all requests are sent.
52
* @type {goog.messaging.MessageChannel}
53
* @private
54
*/
55
this.underlyingChannel_ = underlyingChannel;
56
57
/**
58
* All the virtual channels that are registered for this MultiChannel.
59
* These are null if they've been disposed.
60
* @type {Object<?goog.messaging.MultiChannel.VirtualChannel>}
61
* @private
62
*/
63
this.virtualChannels_ = {};
64
65
this.underlyingChannel_.registerDefaultService(
66
goog.bind(this.handleDefault_, this));
67
};
68
goog.inherits(goog.messaging.MultiChannel, goog.Disposable);
69
70
71
/**
72
* Logger object for goog.messaging.MultiChannel.
73
* @type {goog.log.Logger}
74
* @private
75
*/
76
goog.messaging.MultiChannel.prototype.logger_ =
77
goog.log.getLogger('goog.messaging.MultiChannel');
78
79
80
/**
81
* Creates a new virtual channel that will communicate across the underlying
82
* channel.
83
* @param {string} name The name of the virtual channel. Must be unique for this
84
* MultiChannel. Cannot contain colons.
85
* @return {!goog.messaging.MultiChannel.VirtualChannel} The new virtual
86
* channel.
87
*/
88
goog.messaging.MultiChannel.prototype.createVirtualChannel = function(name) {
89
if (name.indexOf(':') != -1) {
90
throw Error(
91
'Virtual channel name "' + name + '" should not contain colons');
92
}
93
94
if (name in this.virtualChannels_) {
95
throw Error(
96
'Virtual channel "' + name + '" was already created for ' +
97
'this multichannel.');
98
}
99
100
var channel = new goog.messaging.MultiChannel.VirtualChannel(this, name);
101
this.virtualChannels_[name] = channel;
102
return channel;
103
};
104
105
106
/**
107
* Handles the default service for the underlying channel. This dispatches any
108
* unrecognized services to the appropriate virtual channel.
109
*
110
* @param {string} serviceName The name of the service being called.
111
* @param {string|!Object} payload The message payload.
112
* @private
113
*/
114
goog.messaging.MultiChannel.prototype.handleDefault_ = function(
115
serviceName, payload) {
116
var match = serviceName.match(/^([^:]*):(.*)/);
117
if (!match) {
118
goog.log.warning(
119
this.logger_, 'Invalid service name "' + serviceName + '": no ' +
120
'virtual channel specified');
121
return;
122
}
123
124
var channelName = match[1];
125
serviceName = match[2];
126
if (!(channelName in this.virtualChannels_)) {
127
goog.log.warning(
128
this.logger_, 'Virtual channel "' + channelName + ' does not ' +
129
'exist, but a message was received for it: "' + serviceName + '"');
130
return;
131
}
132
133
var virtualChannel = this.virtualChannels_[channelName];
134
if (!virtualChannel) {
135
goog.log.warning(
136
this.logger_, 'Virtual channel "' + channelName + ' has been ' +
137
'disposed, but a message was received for it: "' + serviceName +
138
'"');
139
return;
140
}
141
142
if (!virtualChannel.defaultService_) {
143
goog.log.warning(
144
this.logger_, 'Service "' + serviceName + '" is not registered ' +
145
'on virtual channel "' + channelName + '"');
146
return;
147
}
148
149
virtualChannel.defaultService_(serviceName, payload);
150
};
151
152
153
/** @override */
154
goog.messaging.MultiChannel.prototype.disposeInternal = function() {
155
goog.object.forEach(
156
this.virtualChannels_, function(channel) { goog.dispose(channel); });
157
goog.dispose(this.underlyingChannel_);
158
delete this.virtualChannels_;
159
delete this.underlyingChannel_;
160
};
161
162
163
164
/**
165
* A message channel that proxies its messages over another underlying channel.
166
*
167
* @param {goog.messaging.MultiChannel} parent The MultiChannel
168
* which created this channel, and which contains the underlying
169
* MessageChannel that's used as the transport.
170
* @param {string} name The name of this virtual channel. Unique among the
171
* virtual channels in parent.
172
* @constructor
173
* @implements {goog.messaging.MessageChannel}
174
* @extends {goog.Disposable}
175
* @final
176
*/
177
goog.messaging.MultiChannel.VirtualChannel = function(parent, name) {
178
goog.messaging.MultiChannel.VirtualChannel.base(this, 'constructor');
179
180
/**
181
* The MultiChannel containing the underlying transport channel.
182
* @type {goog.messaging.MultiChannel}
183
* @private
184
*/
185
this.parent_ = parent;
186
187
/**
188
* The name of this virtual channel.
189
* @type {string}
190
* @private
191
*/
192
this.name_ = name;
193
};
194
goog.inherits(goog.messaging.MultiChannel.VirtualChannel, goog.Disposable);
195
196
197
/**
198
* The default service to run if no other services match.
199
* @type {?function(string, (string|!Object))}
200
* @private
201
*/
202
goog.messaging.MultiChannel.VirtualChannel.prototype.defaultService_;
203
204
205
/**
206
* Logger object for goog.messaging.MultiChannel.VirtualChannel.
207
* @type {goog.log.Logger}
208
* @private
209
*/
210
goog.messaging.MultiChannel.VirtualChannel.prototype.logger_ =
211
goog.log.getLogger('goog.messaging.MultiChannel.VirtualChannel');
212
213
214
/**
215
* This is a no-op, since the underlying channel is expected to already be
216
* initialized when it's passed in.
217
*
218
* @override
219
*/
220
goog.messaging.MultiChannel.VirtualChannel.prototype.connect = function(
221
opt_connectCb) {
222
if (opt_connectCb) {
223
opt_connectCb();
224
}
225
};
226
227
228
/**
229
* This always returns true, since the underlying channel is expected to already
230
* be initialized when it's passed in.
231
*
232
* @override
233
*/
234
goog.messaging.MultiChannel.VirtualChannel.prototype.isConnected = function() {
235
return true;
236
};
237
238
239
/**
240
* @override
241
*/
242
goog.messaging.MultiChannel.VirtualChannel.prototype.registerService = function(
243
serviceName, callback, opt_objectPayload) {
244
this.parent_.underlyingChannel_.registerService(
245
this.name_ + ':' + serviceName,
246
goog.bind(this.doCallback_, this, callback), opt_objectPayload);
247
};
248
249
250
/**
251
* @override
252
*/
253
goog.messaging.MultiChannel.VirtualChannel.prototype.registerDefaultService =
254
function(callback) {
255
this.defaultService_ = goog.bind(this.doCallback_, this, callback);
256
};
257
258
259
/**
260
* @override
261
*/
262
goog.messaging.MultiChannel.VirtualChannel.prototype.send = function(
263
serviceName, payload) {
264
if (this.isDisposed()) {
265
throw Error('#send called for disposed VirtualChannel.');
266
}
267
268
this.parent_.underlyingChannel_.send(this.name_ + ':' + serviceName, payload);
269
};
270
271
272
/**
273
* Wraps a callback with a function that will log a warning and abort if it's
274
* called when this channel is disposed.
275
*
276
* @param {function()} callback The callback to wrap.
277
* @param {...*} var_args Other arguments, passed to the callback.
278
* @private
279
*/
280
goog.messaging.MultiChannel.VirtualChannel.prototype.doCallback_ = function(
281
callback, var_args) {
282
if (this.isDisposed()) {
283
goog.log.warning(
284
this.logger_, 'Virtual channel "' + this.name_ + '" received ' +
285
' a message after being disposed.');
286
return;
287
}
288
289
callback.apply({}, Array.prototype.slice.call(arguments, 1));
290
};
291
292
293
/** @override */
294
goog.messaging.MultiChannel.VirtualChannel.prototype.disposeInternal =
295
function() {
296
this.parent_.virtualChannels_[this.name_] = null;
297
this.parent_ = null;
298
};
299
300