Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / InspectorBackend.js
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /**
32  * @constructor
33  */
34 function InspectorBackendClass()
35 {
36     this._connection = null;
37     this._agentPrototypes = {};
38     this._dispatcherPrototypes = {};
39     this._initialized = false;
40     this._enums = {};
41     this._initProtocolAgentsConstructor();
42 }
43
44 InspectorBackendClass.prototype = {
45
46     _initProtocolAgentsConstructor: function()
47     {
48         window.Protocol = {};
49
50         /**
51          * @constructor
52          * @param {!Object.<string, !Object>} agentsMap
53          */
54         window.Protocol.Agents = function(agentsMap) {
55             this._agentsMap = agentsMap;
56         };
57     },
58
59     /**
60      * @param {string} domain
61      */
62     _addAgentGetterMethodToProtocolAgentsPrototype: function(domain)
63     {
64         var upperCaseLength = 0;
65         while (upperCaseLength < domain.length && domain[upperCaseLength].toLowerCase() !== domain[upperCaseLength])
66             ++upperCaseLength;
67
68         var methodName = domain.substr(0, upperCaseLength).toLowerCase() + domain.slice(upperCaseLength) + "Agent";
69
70         /**
71          * @this {Protocol.Agents}
72          */
73         function agentGetter()
74         {
75             return this._agentsMap[domain];
76         }
77
78         window.Protocol.Agents.prototype[methodName] = agentGetter;
79
80         /**
81          * @this {Protocol.Agents}
82          */
83         function registerDispatcher(dispatcher)
84         {
85             this.registerDispatcher(domain, dispatcher)
86         }
87
88         window.Protocol.Agents.prototype["register" + domain + "Dispatcher"] = registerDispatcher;
89     },
90
91     /**
92      * @return {!InspectorBackendClass.Connection}
93      */
94     connection: function()
95     {
96         if (!this._connection)
97             throw "Main connection was not initialized";
98         return this._connection;
99     },
100
101     /**
102      * @param {!InspectorBackendClass.MainConnection} connection
103      */
104     setConnection: function(connection)
105     {
106         this._connection = connection;
107
108         this._connection.registerAgentsOn(window);
109         for (var type in this._enums) {
110             var domainAndMethod = type.split(".");
111             window[domainAndMethod[0] + "Agent"][domainAndMethod[1]] = this._enums[type];
112         }
113     },
114
115     /**
116      * @param {string} domain
117      * @return {!InspectorBackendClass.AgentPrototype}
118      */
119     _agentPrototype: function(domain)
120     {
121         if (!this._agentPrototypes[domain]) {
122             this._agentPrototypes[domain] = new InspectorBackendClass.AgentPrototype(domain);
123             this._addAgentGetterMethodToProtocolAgentsPrototype(domain);
124         }
125
126         return this._agentPrototypes[domain];
127     },
128
129     /**
130      * @param {string} domain
131      * @return {!InspectorBackendClass.DispatcherPrototype}
132      */
133     _dispatcherPrototype: function(domain)
134     {
135         if (!this._dispatcherPrototypes[domain])
136             this._dispatcherPrototypes[domain] = new InspectorBackendClass.DispatcherPrototype();
137         return this._dispatcherPrototypes[domain];
138     },
139
140     /**
141      * @param {string} method
142      * @param {!Array.<!Object>} signature
143      * @param {!Array.<string>} replyArgs
144      * @param {boolean} hasErrorData
145      */
146     registerCommand: function(method, signature, replyArgs, hasErrorData)
147     {
148         var domainAndMethod = method.split(".");
149         this._agentPrototype(domainAndMethod[0]).registerCommand(domainAndMethod[1], signature, replyArgs, hasErrorData);
150         this._initialized = true;
151     },
152
153     /**
154      * @param {string} type
155      * @param {!Object} values
156      */
157     registerEnum: function(type, values)
158     {
159         this._enums[type] = values;
160         this._initialized = true;
161     },
162
163     /**
164      * @param {string} eventName
165      * @param {!Object} params
166      */
167     registerEvent: function(eventName, params)
168     {
169         var domain = eventName.split(".")[0];
170         this._dispatcherPrototype(domain).registerEvent(eventName, params);
171         this._initialized = true;
172     },
173
174     /**
175      * @param {string} domain
176      * @param {!Object} dispatcher
177      */
178     registerDomainDispatcher: function(domain, dispatcher)
179     {
180         this._connection.registerDispatcher(domain, dispatcher);
181     },
182
183     /**
184      * @param {string} jsonUrl
185      */
186     loadFromJSONIfNeeded: function(jsonUrl)
187     {
188         if (this._initialized)
189             return;
190
191         var xhr = new XMLHttpRequest();
192         xhr.open("GET", jsonUrl, false);
193         xhr.send(null);
194
195         var schema = JSON.parse(xhr.responseText);
196         var code = InspectorBackendClass._generateCommands(schema);
197         eval(code);
198     },
199
200     /**
201      * @param {function(T)} clientCallback
202      * @param {string} errorPrefix
203      * @param {function(new:T,S)=} constructor
204      * @param {T=} defaultValue
205      * @return {function(?string, S)}
206      * @template T,S
207      */
208     wrapClientCallback: function(clientCallback, errorPrefix, constructor, defaultValue)
209     {
210         /**
211          * @param {?string} error
212          * @param {S} value
213          * @template S
214          */
215         function callbackWrapper(error, value)
216         {
217             if (error) {
218                 console.error(errorPrefix + error);
219                 clientCallback(defaultValue);
220                 return;
221             }
222             if (constructor)
223                 clientCallback(new constructor(value));
224             else
225                 clientCallback(value);
226         }
227         return callbackWrapper;
228     }
229 }
230
231 /**
232  * @param {*} schema
233  * @return {string}
234  */
235 InspectorBackendClass._generateCommands = function(schema) {
236     var jsTypes = { integer: "number", array: "object" };
237     var rawTypes = {};
238     var result = [];
239
240     var domains = schema["domains"] || [];
241     for (var i = 0; i < domains.length; ++i) {
242         var domain = domains[i];
243         for (var j = 0; domain.types && j < domain.types.length; ++j) {
244             var type = domain.types[j];
245             rawTypes[domain.domain + "." + type.id] = jsTypes[type.type] || type.type;
246         }
247     }
248
249     function toUpperCase(groupIndex, group0, group1)
250     {
251         return [group0, group1][groupIndex].toUpperCase();
252     }
253     function generateEnum(enumName, items)
254     {
255         var members = []
256         for (var m = 0; m < items.length; ++m) {
257             var value = items[m];
258             var name = value.replace(/-(\w)/g, toUpperCase.bind(null, 1)).toTitleCase();
259             name = name.replace(/HTML|XML|WML|API/ig, toUpperCase.bind(null, 0));
260             members.push(name + ": \"" + value +"\"");
261         }
262         return "InspectorBackend.registerEnum(\"" + enumName + "\", {" + members.join(", ") + "});";
263     }
264
265     for (var i = 0; i < domains.length; ++i) {
266         var domain = domains[i];
267
268         var types = domain["types"] || [];
269         for (var j = 0; j < types.length; ++j) {
270             var type = types[j];
271             if ((type["type"] === "string") && type["enum"])
272                 result.push(generateEnum(domain.domain + "." + type.id, type["enum"]));
273             else if (type["type"] === "object") {
274                 var properties = type["properties"] || [];
275                 for (var k = 0; k < properties.length; ++k) {
276                     var property = properties[k];
277                     if ((property["type"] === "string") && property["enum"])
278                         result.push(generateEnum(domain.domain + "." + type.id + property["name"].toTitleCase(), property["enum"]));
279                 }
280             }
281         }
282
283         var commands = domain["commands"] || [];
284         for (var j = 0; j < commands.length; ++j) {
285             var command = commands[j];
286             var parameters = command["parameters"];
287             var paramsText = [];
288             for (var k = 0; parameters && k < parameters.length; ++k) {
289                 var parameter = parameters[k];
290
291                 var type;
292                 if (parameter.type)
293                     type = jsTypes[parameter.type] || parameter.type;
294                 else {
295                     var ref = parameter["$ref"];
296                     if (ref.indexOf(".") !== -1)
297                         type = rawTypes[ref];
298                     else
299                         type = rawTypes[domain.domain + "." + ref];
300                 }
301
302                 var text = "{\"name\": \"" + parameter.name + "\", \"type\": \"" + type + "\", \"optional\": " + (parameter.optional ? "true" : "false") + "}";
303                 paramsText.push(text);
304             }
305
306             var returnsText = [];
307             var returns = command["returns"] || [];
308             for (var k = 0; k < returns.length; ++k) {
309                 var parameter = returns[k];
310                 returnsText.push("\"" + parameter.name + "\"");
311             }
312             var hasErrorData = String(Boolean(command.error));
313             result.push("InspectorBackend.registerCommand(\"" + domain.domain + "." + command.name + "\", [" + paramsText.join(", ") + "], [" + returnsText.join(", ") + "], " + hasErrorData + ");");
314         }
315
316         for (var j = 0; domain.events && j < domain.events.length; ++j) {
317             var event = domain.events[j];
318             var paramsText = [];
319             for (var k = 0; event.parameters && k < event.parameters.length; ++k) {
320                 var parameter = event.parameters[k];
321                 paramsText.push("\"" + parameter.name + "\"");
322             }
323             result.push("InspectorBackend.registerEvent(\"" + domain.domain + "." + event.name + "\", [" + paramsText.join(", ") + "]);");
324         }
325
326         result.push("InspectorBackend.register" + domain.domain + "Dispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, \"" + domain.domain + "\");");
327     }
328     return result.join("\n");
329 }
330
331 /**
332  *  @constructor
333  *  @extends {WebInspector.Object}
334  */
335 InspectorBackendClass.Connection = function()
336 {
337     this._lastMessageId = 1;
338     this._pendingResponsesCount = 0;
339     this._agents = {};
340     this._dispatchers = {};
341     this._callbacks = {};
342     this._initialize(InspectorBackend._agentPrototypes, InspectorBackend._dispatcherPrototypes);
343 }
344
345 InspectorBackendClass.Connection.Events = {
346     Disconnected: "Disconnected",
347 }
348
349 InspectorBackendClass.Connection.prototype = {
350
351     /**
352      * @param {!Object.<string, !InspectorBackendClass.AgentPrototype>} agentPrototypes
353      * @param {!Object.<string, !InspectorBackendClass.DispatcherPrototype>} dispatcherPrototypes
354      */
355     _initialize: function(agentPrototypes, dispatcherPrototypes)
356     {
357         for (var domain in agentPrototypes) {
358             this._agents[domain] = Object.create(agentPrototypes[domain]);
359             this._agents[domain].setConnection(this);
360         }
361
362         for (var domain in dispatcherPrototypes)
363             this._dispatchers[domain] = Object.create(dispatcherPrototypes[domain])
364
365     },
366
367     /**
368      * @param {!Object} object
369      */
370     registerAgentsOn: function(object)
371     {
372         for (var domain in this._agents)
373             object[domain + "Agent"]  = this._agents[domain];
374     },
375
376     /**
377      * @return {number}
378      */
379     nextMessageId: function()
380     {
381         return this._lastMessageId++;
382     },
383
384     /**
385      * @param {string} domain
386      * @return {!InspectorBackendClass.AgentPrototype}
387      */
388     agent: function(domain)
389     {
390         return this._agents[domain];
391     },
392
393     /**
394      * @return {!Object.<string, !Object>}
395      */
396     agentsMap: function()
397     {
398         return this._agents;
399     },
400
401     /**
402      * @param {string} domain
403      * @param {string} method
404      * @param {?Object} params
405      * @param {?function(*)} callback
406      * @private
407      */
408     _wrapCallbackAndSendMessageObject: function(domain, method, params, callback)
409     {
410         var messageObject = {};
411         messageObject.method = method;
412         if (params)
413             messageObject.params = params;
414
415         var wrappedCallback = this._wrap(callback, domain, method);
416
417         var messageId = this.nextMessageId();
418         messageObject.id = messageId;
419
420         if (InspectorBackendClass.Options.dumpInspectorProtocolMessages)
421             console.log("frontend: " + JSON.stringify(messageObject));
422
423         this.sendMessage(messageObject);
424         ++this._pendingResponsesCount;
425         this._callbacks[messageId] = wrappedCallback;
426     },
427
428     /**
429      * @param {?function(*)} callback
430      * @param {string} method
431      * @param {string} domain
432      * @return {!function(*)}
433      */
434     _wrap: function(callback, domain, method)
435     {
436         if (!callback)
437             callback = function() {};
438
439         callback.methodName = method;
440         callback.domain = domain;
441         if (InspectorBackendClass.Options.dumpInspectorTimeStats)
442             callback.sendRequestTime = Date.now();
443
444         return callback;
445     },
446
447     /**
448      * @param {!Object} messageObject
449      */
450     sendMessage: function(messageObject)
451     {
452         throw "Not implemented";
453     },
454
455     /**
456      * @param {!Object} messageObject
457      */
458     reportProtocolError: function(messageObject)
459     {
460         console.error("Protocol Error: the message with wrong id. Message =  " + JSON.stringify(messageObject));
461     },
462
463     /**
464      * @param {!Object|string} message
465      */
466     dispatch: function(message)
467     {
468         if (InspectorBackendClass.Options.dumpInspectorProtocolMessages)
469             console.log("backend: " + ((typeof message === "string") ? message : JSON.stringify(message)));
470
471         var messageObject = /** @type {!Object} */ ((typeof message === "string") ? JSON.parse(message) : message);
472
473         if ("id" in messageObject) { // just a response for some request
474
475             var callback = this._callbacks[messageObject.id];
476             if (!callback) {
477                 this.reportProtocolError(messageObject);
478                 return;
479             }
480
481             var processingStartTime;
482             if (InspectorBackendClass.Options.dumpInspectorTimeStats)
483                 processingStartTime = Date.now();
484
485             this.agent(callback.domain).dispatchResponse(messageObject.id, messageObject, callback.methodName, callback);
486             --this._pendingResponsesCount;
487             delete this._callbacks[messageObject.id];
488
489             if (InspectorBackendClass.Options.dumpInspectorTimeStats)
490                 console.log("time-stats: " + callback.methodName + " = " + (processingStartTime - callback.sendRequestTime) + " + " + (Date.now() - processingStartTime));
491
492             if (this._scripts && !this._pendingResponsesCount)
493                 this.runAfterPendingDispatches();
494             return;
495         } else {
496             var method = messageObject.method.split(".");
497             var domainName = method[0];
498             if (!(domainName in this._dispatchers)) {
499                 console.error("Protocol Error: the message " + messageObject.method + " is for non-existing domain '" + domainName + "'");
500                 return;
501             }
502
503             this._dispatchers[domainName].dispatch(method[1], messageObject);
504
505         }
506
507     },
508
509     /**
510      * @param {string} domain
511      * @param {!Object} dispatcher
512      */
513     registerDispatcher: function(domain, dispatcher)
514     {
515         if (!this._dispatchers[domain])
516             return;
517
518         this._dispatchers[domain].setDomainDispatcher(dispatcher);
519     },
520
521     /**
522      * @param {string=} script
523      */
524     runAfterPendingDispatches: function(script)
525     {
526         if (!this._scripts)
527             this._scripts = [];
528
529         if (script)
530             this._scripts.push(script);
531
532         if (!this._pendingResponsesCount) {
533             var scripts = this._scripts;
534             this._scripts = []
535             for (var id = 0; id < scripts.length; ++id)
536                 scripts[id].call(this);
537         }
538     },
539
540     /**
541      * @param {string} reason
542      */
543     fireDisconnected: function(reason)
544     {
545         this.dispatchEventToListeners(InspectorBackendClass.Connection.Events.Disconnected, {reason: reason});
546     },
547
548     __proto__: WebInspector.Object.prototype
549
550 }
551
552 /**
553  * @constructor
554  * @extends {InspectorBackendClass.Connection}
555  * @param {!function(!InspectorBackendClass.Connection)} onConnectionReady
556  */
557 InspectorBackendClass.MainConnection = function(onConnectionReady)
558 {
559     InspectorBackendClass.Connection.call(this);
560     onConnectionReady(this);
561 }
562
563 InspectorBackendClass.MainConnection.prototype = {
564
565     /**
566      * @param {!Object} messageObject
567      */
568     sendMessage: function(messageObject)
569     {
570         var message = JSON.stringify(messageObject);
571         InspectorFrontendHost.sendMessageToBackend(message);
572     },
573
574     __proto__: InspectorBackendClass.Connection.prototype
575 }
576
577 /**
578  * @constructor
579  * @extends {InspectorBackendClass.Connection}
580  * @param {string} url
581  * @param {!function(!InspectorBackendClass.Connection)} onConnectionReady
582  */
583 InspectorBackendClass.WebSocketConnection = function(url, onConnectionReady)
584 {
585     InspectorBackendClass.Connection.call(this);
586     this._socket = new WebSocket(url);
587     this._socket.onmessage = this._onMessage.bind(this);
588     this._socket.onerror = this._onError.bind(this);
589     this._socket.onopen = onConnectionReady.bind(null, this);
590     this._socket.onclose = this.fireDisconnected.bind(this, "websocket_closed");
591 }
592
593 InspectorBackendClass.WebSocketConnection.prototype = {
594
595     /**
596      * @param {!MessageEvent} message
597      */
598     _onMessage: function(message)
599     {
600         var data = /** @type {string} */ (message.data)
601         this.dispatch(data);
602     },
603
604     /**
605      * @param {!Event} error
606      */
607     _onError: function(error)
608     {
609         console.error(error);
610     },
611
612     /**
613      * @param {!Object} messageObject
614      */
615     sendMessage: function(messageObject)
616     {
617         var message = JSON.stringify(messageObject);
618         this._socket.send(message);
619     },
620
621     __proto__: InspectorBackendClass.Connection.prototype
622 }
623
624
625 /**
626  * @constructor
627  * @extends {InspectorBackendClass.Connection}
628  * @param {!function(!InspectorBackendClass.Connection)} onConnectionReady
629  */
630 InspectorBackendClass.StubConnection = function(onConnectionReady)
631 {
632     InspectorBackendClass.Connection.call(this);
633     onConnectionReady(this);
634 }
635
636 InspectorBackendClass.StubConnection.prototype = {
637
638     /**
639      * @param {!Object} messageObject
640      */
641     sendMessage: function(messageObject)
642     {
643         var message = JSON.stringify(messageObject);
644         setTimeout(this._echoResponse.bind(this, messageObject), 0);
645     },
646
647     /**
648      * @param {!Object} messageObject
649      */
650     _echoResponse: function(messageObject)
651     {
652         this.dispatch(messageObject)
653     },
654
655     __proto__: InspectorBackendClass.Connection.prototype
656 }
657
658 /**
659  * @constructor
660  * @param {string} domain
661  */
662 InspectorBackendClass.AgentPrototype = function(domain)
663 {
664     this._replyArgs = {};
665     this._hasErrorData = {};
666     this._domain = domain;
667 }
668
669 InspectorBackendClass.AgentPrototype.prototype = {
670
671     /**
672      * @param {!InspectorBackendClass.Connection} connection
673      */
674     setConnection: function(connection)
675     {
676         this._connection = connection;
677     },
678
679     /**
680      * @param {string} methodName
681      * @param {!Array.<!Object>} signature
682      * @param {!Array.<string>} replyArgs
683      * @param {boolean} hasErrorData
684      */
685     registerCommand: function(methodName, signature, replyArgs, hasErrorData)
686     {
687         var domainAndMethod = this._domain + "." + methodName;
688
689         /**
690          * @this {InspectorBackendClass.AgentPrototype}
691          */
692         function sendMessage(vararg)
693         {
694             var params = [domainAndMethod, signature].concat(Array.prototype.slice.call(arguments));
695             InspectorBackendClass.AgentPrototype.prototype._sendMessageToBackend.apply(this, params);
696         }
697
698         this[methodName] = sendMessage;
699
700         /**
701          * @this {InspectorBackendClass.AgentPrototype}
702          */
703         function invoke(vararg)
704         {
705             var params = [domainAndMethod].concat(Array.prototype.slice.call(arguments));
706             InspectorBackendClass.AgentPrototype.prototype._invoke.apply(this, params);
707         }
708
709         this["invoke_" + methodName] = invoke;
710
711         this._replyArgs[domainAndMethod] = replyArgs;
712         if (hasErrorData)
713             this._hasErrorData[domainAndMethod] = true;
714
715     },
716
717     /**
718      * @param {string} method
719      * @param {!Array.<!Object>} signature
720      * @param {*} vararg
721      * @private
722      */
723     _sendMessageToBackend: function(method, signature, vararg)
724     {
725         var args = Array.prototype.slice.call(arguments, 2);
726         var callback = (args.length && typeof args[args.length - 1] === "function") ? args.pop() : null;
727
728         var params = {};
729         var hasParams = false;
730         for (var i = 0; i < signature.length; ++i) {
731             var param = signature[i];
732             var paramName = param["name"];
733             var typeName = param["type"];
734             var optionalFlag = param["optional"];
735
736             if (!args.length && !optionalFlag) {
737                 console.error("Protocol Error: Invalid number of arguments for method '" + method + "' call. It must have the following arguments '" + JSON.stringify(signature) + "'.");
738                 return;
739             }
740
741             var value = args.shift();
742             if (optionalFlag && typeof value === "undefined") {
743                 continue;
744             }
745
746             if (typeof value !== typeName) {
747                 console.error("Protocol Error: Invalid type of argument '" + paramName + "' for method '" + method + "' call. It must be '" + typeName + "' but it is '" + typeof value + "'.");
748                 return;
749             }
750
751             params[paramName] = value;
752             hasParams = true;
753         }
754
755         if (args.length === 1 && !callback && (typeof args[0] !== "undefined")) {
756             console.error("Protocol Error: Optional callback argument for method '" + method + "' call must be a function but its type is '" + typeof args[0] + "'.");
757             return;
758         }
759
760         this._connection._wrapCallbackAndSendMessageObject(this._domain, method, hasParams ? params : null, callback);
761     },
762
763     /**
764      * @param {string} method
765      * @param {?Object} args
766      * @param {?function(*)} callback
767      */
768     _invoke: function(method, args, callback)
769     {
770         this._connection._wrapCallbackAndSendMessageObject(this._domain, method, args, callback);
771     },
772
773     /**
774      * @param {number} messageId
775      * @param {!Object} messageObject
776      */
777     dispatchResponse: function(messageId, messageObject, methodName, callback)
778     {
779         if (messageObject.error && messageObject.error.code !== -32000)
780             console.error("Request with id = " + messageObject.id + " failed. " + JSON.stringify(messageObject.error));
781
782         var argumentsArray = [];
783         argumentsArray[0] = messageObject.error ? messageObject.error.message: null;
784
785         if (this._hasErrorData[methodName])
786             argumentsArray[1] = messageObject.error ? messageObject.error.data : null;
787
788         if (messageObject.result) {
789             var paramNames = this._replyArgs[methodName] || [];
790             for (var i = 0; i < paramNames.length; ++i)
791                 argumentsArray.push(messageObject.result[paramNames[i]]);
792         }
793
794         callback.apply(null, argumentsArray);
795     }
796 }
797
798 /**
799  * @constructor
800  */
801 InspectorBackendClass.DispatcherPrototype = function()
802 {
803     this._eventArgs = {};
804     this._dispatcher = null;
805 }
806
807 InspectorBackendClass.DispatcherPrototype.prototype = {
808
809     /**
810      * @param {string} eventName
811      * @param {!Object} params
812      */
813     registerEvent: function(eventName, params)
814     {
815         this._eventArgs[eventName] = params
816     },
817
818     /**
819      * @param {!Object} dispatcher
820      */
821     setDomainDispatcher: function(dispatcher)
822     {
823         this._dispatcher = dispatcher;
824     },
825
826     /**
827      * @param {string} functionName
828      * @param {!Object} messageObject
829      */
830     dispatch: function(functionName, messageObject)
831     {
832         if (!this._dispatcher)
833             return;
834
835         if (!(functionName in this._dispatcher)) {
836             console.error("Protocol Error: Attempted to dispatch an unimplemented method '" + messageObject.method + "'");
837             return;
838         }
839
840         if (!this._eventArgs[messageObject.method]) {
841             console.error("Protocol Error: Attempted to dispatch an unspecified method '" + messageObject.method + "'");
842             return;
843         }
844
845         var params = [];
846         if (messageObject.params) {
847             var paramNames = this._eventArgs[messageObject.method];
848             for (var i = 0; i < paramNames.length; ++i)
849                 params.push(messageObject.params[paramNames[i]]);
850         }
851
852         var processingStartTime;
853         if (InspectorBackendClass.Options.dumpInspectorTimeStats)
854             processingStartTime = Date.now();
855
856         this._dispatcher[functionName].apply(this._dispatcher, params);
857
858         if (InspectorBackendClass.Options.dumpInspectorTimeStats)
859             console.log("time-stats: " + messageObject.method + " = " + (Date.now() - processingStartTime));
860     }
861
862 }
863
864 InspectorBackendClass.Options = {
865     dumpInspectorTimeStats: false,
866     dumpInspectorProtocolMessages: false
867 }
868
869 InspectorBackend = new InspectorBackendClass();