1 /** 2 * @fileOverview Exposes a set of API wrappers that will hide the dirty work of 3 * constructing Finesse API requests and consuming Finesse events. 4 * 5 * @name finesse.clientservices.ClientServices 6 * @requires OpenAjax, jQuery 1.5, finesse.utilities.Utilities 7 */ 8 9 var finesse = finesse || {}; 10 finesse.version = '$version$'; 11 finesse.clientservices = finesse.clientservices || {}; 12 /** 13 * @class 14 * Allow clients to make Finesse API requests and consume Finesse events by 15 * calling a set of exposed functions. The Services layer will do the dirty 16 * work of establishing a shared BOSH connection (for designated Master 17 * modules), consuming events for client subscriptions, and constructing API 18 * requests. 19 */ 20 finesse.clientservices.ClientServices = (function () { 21 22 var 23 24 /** 25 * Shortcut reference to the master tunnel 26 * @private 27 */ 28 _tunnel, 29 30 _publisher, 31 32 /** 33 * Shortcut reference to the finesse.utilities.Utilities singleton 34 * This will be set by init() 35 * @private 36 */ 37 _util, 38 39 /** 40 * Shortcut reference to the gadgets.io object. 41 * This will be set by init() 42 * @private 43 */ 44 _io, 45 46 /** 47 * Shortcut reference to the gadget pubsub Hub instance. 48 * This will be set by init() 49 * @private 50 */ 51 _hub, 52 53 /** 54 * Logger object set externally by setLogger, defaults to nothing. 55 * @private 56 */ 57 _logger = {}, 58 59 /** 60 * Shortcut reference to the Topics class. 61 * This will be set by init() 62 * @private 63 */ 64 _topics, 65 66 /** 67 * Config object needed to initialize this library 68 * This must be set by init() 69 * @private 70 */ 71 _config, 72 73 /** 74 * @private 75 * Whether or not this ClientService instance is a Master. 76 */ 77 _isMaster = false, 78 79 /** 80 * @private 81 * Whether the Client Services have been initiated yet. 82 */ 83 _inited = false, 84 85 /** 86 * Stores the list of subscription IDs for all subscriptions so that it 87 * could be retrieve for unsubscriptions. 88 * @private 89 */ 90 _subscriptionID = {}, 91 92 /** 93 * The possible states of the JabberWerx BOSH connection. 94 * @private 95 */ 96 _STATUS = { 97 CONNECTING: "connecting", 98 CONNECTED: "connected", 99 DISCONNECTED: "disconnected", 100 DISCONNECTED_CONFLICT: "conflict", 101 DISCONNECTED_UNAUTHORIZED: "unauthorized", 102 DISCONNECTING: "disconnecting", 103 RECONNECTING: "reconnecting", 104 UNLOADING: "unloading" 105 }, 106 107 /** 108 * Handler function to be invoked when BOSH connection is connecting. 109 * @private 110 */ 111 _onConnectingHandler, 112 113 /** 114 * Handler function to be invoked when BOSH connection is connected 115 * @private 116 */ 117 _onConnectHandler, 118 119 /** 120 * Handler function to be invoked when BOSH connection is disconnecting. 121 * @private 122 */ 123 _onDisconnectingHandler, 124 125 /** 126 * Handler function to be invoked when the BOSH is disconnected. 127 * @private 128 */ 129 _onDisconnectHandler, 130 131 /** 132 * Handler function to be invoked when the BOSH is reconnecting. 133 * @private 134 */ 135 _onReconnectingHandler, 136 137 /** 138 * Handler function to be invoked when the BOSH is unloading. 139 * @private 140 */ 141 _onUnloadingHandler, 142 143 /** 144 * Contains a cache of the latest connection info containing the current 145 * state of the BOSH connection and the resource ID. 146 * @private 147 */ 148 _connInfo, 149 150 /** 151 * Keeps track of all the objects that need to be refreshed when we recover 152 * due to our resilient connection. Only objects that we subscribe to will 153 * be added to this list. 154 */ 155 _refreshList = [], 156 157 /** 158 * @private 159 * Centralized logger.log method for external logger 160 * @param {String} msg 161 * Message to log 162 */ 163 _log = function (msg) { 164 // If the external logger throws up, it stops here. 165 try { 166 if (_logger.log) { 167 _logger.log("[ClientServices] " + msg); 168 } 169 } catch (e) { } 170 }, 171 172 /** 173 * Go through each object in the _refreshList and call its refresh() function 174 */ 175 _refreshObjects = function () { 176 var i; 177 178 // wipe out the explicit subscription list before we refresh objects 179 if (_publisher) { 180 _publisher.wipeout(); 181 } 182 183 // refresh each item in the refresh list 184 for (i = _refreshList.length - 1; i >= 0; i -= 1) { 185 _log("Refreshing " + _refreshList[i].getRestUrl()); 186 _refreshList[i].refresh(); 187 } 188 }, 189 190 /** 191 * Handler to process connection info publishes. 192 * @param {Object} data 193 * The connection info data object. 194 * @param {String} data.status 195 * The BOSH connection status. 196 * @param {String} data.resourceID 197 * The resource ID for the connection. 198 * @private 199 */ 200 _connInfoHandler = function (data) { 201 202 //Invoke registered handler depending on status received. Due to the 203 //request topic where clients can make request for the Master to publish 204 //the connection info, there is a chance that duplicate connection info 205 //events may be sent, so ensure that there has been a state change 206 //before invoking the handlers. 207 if (_connInfo === undefined || _connInfo.status !== data.status) { 208 _connInfo = data; 209 switch (data.status) { 210 case _STATUS.CONNECTING: 211 if (_onConnectingHandler) { 212 _onConnectingHandler(); 213 } 214 break; 215 case _STATUS.CONNECTED: 216 // Whenever we are connected, we need to refresh any objects 217 // that are stored. 218 _refreshObjects(); 219 if (_onConnectHandler) { 220 _onConnectHandler(); 221 } 222 break; 223 case _STATUS.DISCONNECTED: 224 if (_onDisconnectHandler) { 225 _onDisconnectHandler(); 226 } 227 break; 228 case _STATUS.DISCONNECTED_CONFLICT: 229 if (_onDisconnectHandler) { 230 _onDisconnectHandler("conflict"); 231 } 232 break; 233 case _STATUS.DISCONNECTED_UNAUTHORIZED: 234 if (_onDisconnectHandler) { 235 _onDisconnectHandler("unauthorized"); 236 } 237 break; 238 case _STATUS.DISCONNECTING: 239 if (_onDisconnectingHandler) { 240 _onDisconnectingHandler(); 241 } 242 break; 243 case _STATUS.RECONNECTING: 244 if (_onReconnectingHandler) { 245 _onReconnectingHandler(); 246 } 247 break; 248 case _STATUS.UNLOADING: 249 if (_onUnloadingHandler) { 250 _onUnloadingHandler(); 251 } 252 break; 253 } 254 } 255 }, 256 257 /** 258 * Ensure that ClientServices have been inited. 259 * @private 260 */ 261 _isInited = function () { 262 if (!_inited) { 263 throw new Error("ClientServices needs to be inited."); 264 } 265 }, 266 267 /** 268 * Have the client become the Master by initiating a tunnel to a shared 269 * event BOSH connection. The Master is responsible for publishing all 270 * events to the pubsub infrastructure. 271 * @private 272 */ 273 _becomeMaster = function () { 274 _tunnel = new finesse.clientservices.MasterTunnel(_config.host, _config.scheme); 275 _publisher = new finesse.clientservices.MasterPublisher(_tunnel); 276 _tunnel.init(_config.id, _config.password, _config.xmppDomain, _config.pubsubDomain, _config.resource); 277 _isMaster = true; 278 }, 279 280 /** 281 * Make a request to the request channel to have the Master publish the 282 * connection info object. 283 * @private 284 */ 285 _makeConnectionInfoReq = function () { 286 var data = { 287 type: "ConnectionInfoReq", 288 data: {}, 289 invokeID: (new Date()).getTime() 290 }; 291 _hub.publish(_topics.REQUESTS, data); 292 }, 293 294 /** 295 * Utility method to register a handler which is associated with a 296 * particular connection status. 297 * @param {String} status 298 * The connection status string. 299 * @param {Function} handler 300 * The handler to associate with a particular connection status. 301 * @throws {Error} 302 * If the handler provided is not a function. 303 * @private 304 */ 305 _registerHandler = function (status, handler) { 306 if (typeof handler === "function") { 307 if (_connInfo && _connInfo.status === status) { 308 handler(); 309 } 310 switch (status) { 311 case _STATUS.CONNECTING: 312 _onConnectingHandler = handler; 313 break; 314 case _STATUS.CONNECTED: 315 _onConnectHandler = handler; 316 break; 317 case _STATUS.DISCONNECTED: 318 _onDisconnectHandler = handler; 319 break; 320 case _STATUS.DISCONNECTING: 321 _onDisconnectingHandler = handler; 322 break; 323 case _STATUS.RECONNECTING: 324 _onReconnectingHandler = handler; 325 break; 326 case _STATUS.UNLOADING: 327 _onUnloadingHandler = handler; 328 break; 329 } 330 331 } else { 332 throw new Error("Callback is not a function"); 333 } 334 }; 335 336 return { 337 338 /** 339 * Adds an item to the list to be refreshed upon reconnect 340 * @param {RestBase} object - rest object to be refreshed 341 */ 342 addToRefreshList: function (object) { 343 _refreshList.push(object); 344 }, 345 346 /** 347 * Removes the given item from the refresh list 348 * @param {RestBase} object - rest object to be removed 349 */ 350 removeFromRefreshList: function (object) { 351 var i; 352 for (i = _refreshList.length - 1; i >= 0; i -= 1) { 353 if (_refreshList[i] === object) { 354 _refreshList.splice(i, 1); 355 break; 356 } 357 } 358 }, 359 360 /** 361 * The location of the tunnel HTML URL. 362 * @returns {String} 363 * The location of the tunnel HTML URL. 364 */ 365 getTunnelURL: function () { 366 return _tunnel.getTunnelURL(); 367 }, 368 369 /** 370 * @private 371 * Indicates whether the tunnel frame is loaded. 372 * @returns {Boolean} 373 * True if the tunnel frame is loaded, false otherwise. 374 */ 375 isTunnelLoaded: function () { 376 return _tunnel.isTunnelLoaded(); 377 }, 378 379 /** 380 * @private 381 * Indicates whether the ClientServices instance is a Master. 382 * @returns {Boolean} 383 * True if this instance of ClientServices is a Master, false otherwise. 384 */ 385 isMaster: function () { 386 return _isMaster; 387 }, 388 389 /** 390 * @private 391 * Get the resource ID. An ID is only available if the BOSH connection has 392 * been able to connect successfully. 393 * @returns {String} 394 * The resource ID string. Null if the BOSH connection was never 395 * successfully created and/or the resource ID has not been associated. 396 */ 397 getResourceID: function () { 398 if (_connInfo !== undefined) { 399 return _connInfo.resourceID; 400 } 401 return null; 402 }, 403 404 /* 405 getHub: function () { 406 return _hub; 407 }, 408 */ 409 /** 410 * @private 411 * Add a callback to be invoked when the BOSH connection is attempting 412 * to connect. If the connection is already trying to connect, the 413 * callback will be invoked immediately. 414 * @param {Function} handler 415 * An empty param function to be invoked on connecting. Only one 416 * handler can be registered at a time. Handlers already registered 417 * will be overwritten. 418 */ 419 registerOnConnectingHandler: function (handler) { 420 _registerHandler(_STATUS.CONNECTING, handler); 421 }, 422 423 /** 424 * @private 425 * Removes the on connecting callback that was registered. 426 */ 427 unregisterOnConnectingHandler: function () { 428 _onConnectingHandler = undefined; 429 }, 430 431 /** 432 * @private 433 * Add a callback to be invoked when the BOSH connection has been 434 * established. If the connection has already been established, the 435 * callback will be invoked immediately. 436 * @param {Function} handler 437 * An empty param function to be invoked on connect. Only one handler 438 * can be registered at a time. Handlers already registered will be 439 * overwritten. 440 */ 441 registerOnConnectHandler: function (handler) { 442 _registerHandler(_STATUS.CONNECTED, handler); 443 }, 444 445 /** 446 * @private 447 * Removes the on connect callback that was registered. 448 */ 449 unregisterOnConnectHandler: function () { 450 _onConnectHandler = undefined; 451 }, 452 453 /** 454 * @private 455 * Add a callback to be invoked when the BOSH connection goes down. If 456 * the connection is already down, invoke the callback immediately. 457 * @param {Function} handler 458 * An empty param function to be invoked on disconnected. Only one 459 * handler can be registered at a time. Handlers already registered 460 * will be overwritten. 461 */ 462 registerOnDisconnectHandler: function (handler) { 463 _registerHandler(_STATUS.DISCONNECTED, handler); 464 }, 465 466 /** 467 * @private 468 * Removes the on disconnect callback that was registered. 469 */ 470 unregisterOnDisconnectHandler: function () { 471 _onDisconnectHandler = undefined; 472 }, 473 474 /** 475 * @private 476 * Add a callback to be invoked when the BOSH is currently disconnecting. If 477 * the connection is already disconnecting, invoke the callback immediately. 478 * @param {Function} handler 479 * An empty param function to be invoked on disconnected. Only one 480 * handler can be registered at a time. Handlers already registered 481 * will be overwritten. 482 */ 483 registerOnDisconnectingHandler: function (handler) { 484 _registerHandler(_STATUS.DISCONNECTING, handler); 485 }, 486 487 /** 488 * @private 489 * Removes the on disconnecting callback that was registered. 490 */ 491 unregisterOnDisconnectingHandler: function () { 492 _onDisconnectingHandler = undefined; 493 }, 494 495 /** 496 * @private 497 * Add a callback to be invoked when the BOSH connection is attempting 498 * to connect. If the connection is already trying to connect, the 499 * callback will be invoked immediately. 500 * @param {Function} handler 501 * An empty param function to be invoked on connecting. Only one 502 * handler can be registered at a time. Handlers already registered 503 * will be overwritten. 504 */ 505 registerOnReconnectingHandler: function (handler) { 506 _registerHandler(_STATUS.RECONNECTING, handler); 507 }, 508 509 /** 510 * @private 511 * Removes the on reconnecting callback that was registered. 512 */ 513 unregisterOnReconnectingHandler: function () { 514 _onReconnectingHandler = undefined; 515 }, 516 517 /** 518 * @private 519 * Add a callback to be invoked when the BOSH connection is unloading 520 * 521 * @param {Function} handler 522 * An empty param function to be invoked on connecting. Only one 523 * handler can be registered at a time. Handlers already registered 524 * will be overwritten. 525 */ 526 registerOnUnloadingHandler: function (handler) { 527 _registerHandler(_STATUS.UNLOADING, handler); 528 }, 529 530 /** 531 * @private 532 * Removes the on unloading callback that was registered. 533 */ 534 unregisterOnUnloadingHandler: function () { 535 _onUnloadingHandler = undefined; 536 }, 537 538 /** 539 * @private 540 * Proxy method for gadgets.io.makeRequest. The will be identical to gadgets.io.makeRequest 541 * ClientServices will mixin the BASIC Auth string, locale, and host, since the 542 * configuration is encapsulated in here anyways. 543 * This removes the dependency 544 * @param {String} url 545 * The relative url to make the request to (the host from the passed in config will be 546 * appended). It is expected that any encoding to the URL is already done. 547 * @param {Function} handler 548 * Callback handler for makeRequest to invoke when the response returns. 549 * Completely passed through to gadgets.io.makeRequest 550 * @param {Object} params 551 * The params object that gadgets.io.makeRequest expects. Authorization and locale 552 * headers are mixed in. 553 */ 554 makeRequest: function (url, handler, params) { 555 // ClientServices needs to be initialized with a config for restHost, auth, and locale 556 _isInited(); 557 558 // Allow mixin of auth and locale headers 559 params = params || {}; 560 params[gadgets.io.RequestParameters.HEADERS] = params[gadgets.io.RequestParameters.HEADERS] || {}; 561 562 // Add Basic auth to request header 563 params[gadgets.io.RequestParameters.HEADERS].Authorization = "Basic " + _config.authorization; 564 //Locale 565 params[gadgets.io.RequestParameters.HEADERS].locale = _config.locale; 566 567 gadgets.io.makeRequest(encodeURI("http://" + _config.restHost) + url, handler, params); 568 }, 569 570 /** 571 * @private 572 * Utility function to make a subscription to a particular topic. Only one 573 * callback function is registered to a particular topic at any time. 574 * @param {String} topic 575 * The full topic name. The topic name should follow the OpenAjax 576 * convention using dot notation (ex: finesse.api.User.1000). 577 * @param {Function} callback 578 * The function that should be invoked with the data when an event 579 * is delivered to the specific topic. 580 * @returns {Boolean} 581 * True if the subscription was made successfully and the callback was 582 * been registered. False if the subscription already exist, the 583 * callback was not overwritten. 584 */ 585 subscribe: function (topic, callback) { 586 _isInited(); 587 588 //Ensure that the same subscription isn't made twice. 589 if (!_subscriptionID[topic]) { 590 //Store the subscription ID using the topic name as the key. 591 _subscriptionID[topic] = _hub.subscribe(topic, 592 //Invoke the callback just with the data object. 593 function (topic, data) { 594 callback(data); 595 }); 596 return true; 597 } 598 return false; 599 }, 600 601 /** 602 * @private 603 * Unsubscribe from a particular topic. 604 * @param {String} topic 605 * The full topic name. 606 */ 607 unsubscribe: function (topic) { 608 _isInited(); 609 610 //Unsubscribe from the topic using the subscription ID recorded when 611 //the subscription was made, then delete the ID from data structure. 612 if (_subscriptionID[topic]) { 613 _hub.unsubscribe(_subscriptionID[topic]); 614 delete _subscriptionID[topic]; 615 } 616 }, 617 618 /** 619 * @private 620 * Make a request to the request channel to have the Master subscribe 621 * to a node. 622 * @param {String} node 623 * The node to subscribe to. 624 */ 625 subscribeNode: function (node, handler) { 626 if (handler && typeof handler !== "function") { 627 throw new Error("ClientServices.subscribeNode: handler is not a function"); 628 } 629 630 // Construct the request to send to MasterPublisher through the OpenAjax Hub 631 var data = { 632 type: "SubscribeNodeReq", 633 data: {node: node}, 634 invokeID: _util.generateUUID() 635 }, 636 responseTopic = _topics.RESPONSES + "." + data.invokeID, 637 _this = this; 638 639 // We need to first subscribe to the response channel 640 this.subscribe(responseTopic, function (rsp) { 641 // Since this channel is only used for this singular request, 642 // we are not interested anymore. 643 // This is also critical to not leaking memory by having OpenAjax 644 // store a bunch of orphaned callback handlers that enclose on 645 // our entire ClientServices singleton 646 _this.unsubscribe(responseTopic); 647 if (handler) { 648 handler(data.invokeID, rsp); 649 } 650 }); 651 // Then publish the request on the request channel 652 _hub.publish(_topics.REQUESTS, data); 653 }, 654 655 /** 656 * @private 657 * Make a request to the request channel to have the Master unsubscribe 658 * from a node. 659 * @param {String} node 660 * The node to unsubscribe from. 661 */ 662 unsubscribeNode: function (node, subid, handler) { 663 if (handler && typeof handler !== "function") { 664 throw new Error("ClientServices.unsubscribeNode: handler is not a function"); 665 } 666 667 // Construct the request to send to MasterPublisher through the OpenAjax Hub 668 var data = { 669 type: "UnsubscribeNodeReq", 670 data: { 671 node: node, 672 subid: subid 673 }, 674 invokeID: _util.generateUUID() 675 }, 676 responseTopic = _topics.RESPONSES + "." + data.invokeID, 677 _this = this; 678 679 // We need to first subscribe to the response channel 680 this.subscribe(responseTopic, function (rsp) { 681 // Since this channel is only used for this singular request, 682 // we are not interested anymore. 683 // This is also critical to not leaking memory by having OpenAjax 684 // store a bunch of orphaned callback handlers that enclose on 685 // our entire ClientServices singleton 686 _this.unsubscribe(responseTopic); 687 if (handler) { 688 handler(rsp); 689 } 690 }); 691 // Then publish the request on the request channel 692 _hub.publish(_topics.REQUESTS, data); 693 }, 694 695 /** 696 * @private 697 * Make a request to the request channel to have the Master connect to the XMPP server via BOSH 698 */ 699 makeConnectionReq : function () { 700 var data = { 701 type: "ConnectionReq", 702 data: { 703 id: _config.id, 704 password: _config.password, 705 xmppDomain: _config.xmppDomain 706 }, 707 invokeID: (new Date()).getTime() 708 }; 709 _hub.publish(_topics.REQUESTS, data); 710 }, 711 712 /** 713 * Set's the global logger for this Client Services instance. 714 * @param {Object} logger 715 * Logger object with the following attributes defined:<ul> 716 * <li><b>log:</b> function (msg) to simply log a message 717 * </ul> 718 */ 719 setLogger: function (logger) { 720 // We want to check the logger coming in so we don't have to check every time it is called. 721 if (logger && typeof logger === "object" && typeof logger.log === "function") { 722 _logger = logger; 723 } else { 724 // We are resetting it to an empty object so that _logger.log in .log is falsy. 725 _logger = {}; 726 } 727 }, 728 729 /** 730 * @private 731 * Centralized logger.log method for external logger 732 * @param {String} msg 733 * Message to log 734 */ 735 log: _log, 736 737 /** 738 * Initiates the Client Services with the specified config parameters. 739 * Enabling the Client Services as Master will trigger the establishment 740 * of a BOSH event connection. 741 * @param {Object} config 742 * Configuration object containing properties used for making REST requests:<ul> 743 * <li><b>host:</b> The Finesse server IP/host as reachable from the browser 744 * <li><b>restHost:</b> The Finesse API IP/host as reachable from the gadget container 745 * <li><b>id:</b> The ID of the user. This is an optional param as long as the 746 * appropriate authorization string is provided, otherwise it is 747 * required.</li> 748 * <li><b>password:</b> The password belonging to the user. This is an optional param as 749 * long as the appropriate authorization string is provided, 750 * otherwise it is required.</li> 751 * <li><b>authorization:</b> The base64 encoded "id:password" authentication string. This 752 * param is provided to allow the ability to hide the password 753 * param. If provided, the id and the password extracted from this 754 * string will be used over the config.id and config.password.</li> 755 * </ul> 756 * @throws {Error} If required constructor parameter is missing. 757 */ 758 init: function (config) { 759 if (!_inited) { 760 //Validate the properties within the config object if one is provided. 761 if (!(typeof config === "object" && 762 typeof config.host === "string" && config.host.length > 0 && config.restHost && 763 (typeof config.authorization === "string" || 764 (typeof config.id === "string" && 765 typeof config.password === "string")))) { 766 throw new Error("Config object contains invalid properties."); 767 } 768 769 // Initialize configuration 770 _config = config; 771 772 // Set shortcuts 773 _util = finesse.utilities.Utilities; 774 _hub = gadgets.Hub; 775 _io = gadgets.io; 776 _topics = finesse.clientservices.Topics; 777 778 //If the authorization string is provided, then use that to 779 //extract the ID and the password. Otherwise use the ID and 780 //password from the respective ID and password params. 781 if (_config.authorization) { 782 var creds = _util.getCredentials(_config.authorization); 783 _config.id = creds.id; 784 _config.password = creds.password; 785 } 786 else { 787 _config.authorization = _util.b64Encode( 788 _config.id + ":" + _config.password); 789 } 790 791 _inited = true; 792 793 if (_hub) { 794 //Subscribe to receive connection information. Since it is possible that 795 //the client comes up after the Master comes up, the client will need 796 //to make a request to have the Master send the latest connection info. 797 //It would be possible that all clients get connection info again. 798 this.subscribe(_topics.EVENTS_CONNECTION_INFO, _connInfoHandler); 799 _makeConnectionInfoReq(); 800 } 801 } 802 803 //Return the CS object for object chaining. 804 return this; 805 }, 806 807 /** 808 * @private 809 * Initializes the BOSH component of this ClientServices instance. This establishes 810 * the BOSH connection and will trigger the registered handlers as the connection 811 * status changes respectively:<ul> 812 * <li>registerOnConnectingHandler</li> 813 * <li>registerOnConnectHandler</li> 814 * <li>registerOnDisconnectHandler</li> 815 * <li>registerOnDisconnectingHandler</li> 816 * <li>registerOnReconnectingHandler</li> 817 * <li>registerOnUnloadingHandler</li> 818 * <ul> 819 * 820 * @param {Object} config 821 * An object containing the following (optional) handlers for the request:<ul> 822 * <li><b>xmppDomain:</b> {String} The domain of the XMPP server. Available from the SystemInfo object. 823 * This is used to construct the JID: user@domain.com</li> 824 * <li><b>pubsubDomain:</b> {String} The pub sub domain where the pub sub service is running. 825 * Available from the SystemInfo object. 826 * This is used for creating or removing subscriptions.</li> 827 * <li><b>resource:</b> {String} The resource to connect to the notification server with.</li> 828 * </ul> 829 */ 830 initBosh: function (config) { 831 //Validate the properties within the config object if one is provided. 832 if (!(typeof config === "object" && typeof config.xmppDomain === "string" && typeof config.pubsubDomain === "string")) { 833 throw new Error("Config object contains invalid properties."); 834 } 835 836 // Mixin the required information for establishing the BOSH connection 837 _config.xmppDomain = config.xmppDomain; 838 _config.pubsubDomain = config.pubsubDomain; 839 _config.resource = config.resource; 840 841 //Initiate Master launch sequence 842 _becomeMaster(); 843 }, 844 845 //BEGIN TEST CODE// 846 /** 847 * Test code added to expose private functions that are used by unit test 848 * framework. This section of code is removed during the build process 849 * before packaging production code. The [begin|end]TestSection are used 850 * by the build to identify the section to strip. 851 * @ignore 852 */ 853 beginTestSection : 0, 854 855 /** 856 * @ignore 857 */ 858 getTestObject: function () { 859 //Load mock dependencies. 860 var _mock = new MockControl(); 861 _hub = _mock.createMock(gadgets.Hub); 862 _io = _mock.createMock(gadgets.io); 863 864 return { 865 //Expose mock dependencies 866 mock: _mock, 867 hub: _hub, 868 io: _io, 869 870 //Expose internal private functions 871 subscriptionID: _subscriptionID, 872 connInfoHandler: _connInfoHandler, 873 874 reset: function () { 875 _inited = false; 876 _onConnectingHandler = undefined; 877 _onConnectHandler = undefined; 878 _onDisconnectingHandler = undefined; 879 _onDisconnectHandler = undefined; 880 _onReconnectingHandler = undefined; 881 _connInfo = undefined; 882 }, 883 setUtil: function () { 884 _util = finesse.utilities.Utilities; 885 }, 886 setConfig: function (config) { 887 _config = config; 888 } 889 }; 890 }, 891 892 /** 893 * @ignore 894 */ 895 endTestSection: 0 896 //END TEST CODE// 897 }; 898 }()); 899