1 /* 2 **************************************************************** 3 * Licensed Materials - Property of IBM 4 * 5725-F96 IBM MessageSight 5 * (C) Copyright IBM Corp. 2014. All Rights Reserved. 6 * 7 * US Government Users Restricted Rights - Use, duplication or 8 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 9 **************************************************************** 10 */ 11 MessagingREST = (function (global) { 12 13 var version = "1.0"; 14 15 16 /** 17 * The JavaScript application communicates with IBM MessageSight via http plug-in using 18 * a {@link MessagingREST.Client} object. 19 * 20 * The methods are implemented as asynchronous JavaScript methods (even though the 21 * underlying protocol exchange might be synchronous in nature). This means they signal 22 * their completion by calling back to the application via Success or Failure callback 23 * functions provided by the application on the method in question. These callbacks are 24 * called at most once per method invocation and do not persist beyond the lifetime of 25 * the script that made the invocation. 26 * 27 * @name MessagingREST.Client 28 * 29 * @constructor 30 * 31 * @param {string} host - the address of the IBM MessageSight host, as a DNS name or dotted decimal IP address. 32 * @param {number} port - the port number to connect to 33 * @param {string} path - the alias on the IBM MessageSight host. 34 * @param {string} clientid - the MessagingREST client identifier 35 * @param {string} username - the username to authenticate with 36 * @param {string} password - the password for the username provided 37 * 38 */ 39 var Client = function (host, port, path, protocol, clientid, username, password) { 40 41 var trace = function() {}; 42 43 44 if (typeof host !== "string") 45 throw new Error("invalid server name"); 46 47 if (typeof port !== "number" || port < 0) 48 throw new Error("invalid port number"); 49 50 if (typeof path !== "string") 51 throw new Error("invalid path"); 52 53 if (!clientid) 54 throw new Error("Client ID is required"); 55 56 if (typeof clientid !== "string") 57 throw new Error("invalid Client ID"); 58 59 var ipv6AddSBracket = (host.indexOf(":") != -1 && host.slice(0,1) != "[" && host.slice(-1) != "]"); 60 var url = protocol + "://"+(ipv6AddSBracket?"["+host+"]":host)+":"+port+path; 61 62 trace("Base URL is: " + url); 63 64 65 /** 66 * Set a trace function that the client can use for 67 * logging trace messages. 68 * 69 * @param {function} trace - a trace function that takes one string as an argument 70 */ 71 this.setTrace = function(traceFunction) { 72 73 if (traceFunction) { 74 trace = traceFunction; 75 } 76 77 } 78 79 /** 80 * Set the necessary request headers for the a provided 81 * XMLHttpRequest object. Since the request will more than 82 * likely be a CORS request only headers that IBM MessageSight 83 * allows may be set. 84 * @private 85 * 86 * @name MessagingREST.Client#setRequestHeaders 87 * @function 88 * @param {object} request - The XMLHttpRequest object that headers should be set for. 89 * 90 */ 91 this.setRequestHeaders = function(request) { 92 93 trace("Enter: Client.setRequestHeaders"); 94 95 if (!request) { 96 return; 97 } 98 99 if (username && password) { 100 var userPass = btoa(username + ":" + password); 101 request.setRequestHeader("Authorization", "Basic " + userPass); 102 } 103 104 trace("setting header client-id to " + clientid); 105 request.setRequestHeader("Client-ID", clientid); 106 107 } 108 109 /** 110 * Create a subscription for a given topic filter and a provided name. 111 * 112 * 113 * @name MessagingREST.Client#createTopicSubscription 114 * @function 115 * @param {string} filter - the topic filter that the subscription should be set to 116 * @param {string} subscriptionName - the name of the subscription 117 * @param {boolean} durable - if the subscription is durable or not 118 * @param {function} onSuccess - Called after a response with a status code of 200 is received 119 * from the server. A single response parameter is passed 120 * to the onSuccess callback: 121 * <ol> 122 * <li>a string that contains any response from the request 123 * </ol> 124 * @param {function} onFailure - Called when a status code other than 200 is received from 125 * the server. Two response parameters are passed to the 126 * onFailure callback: 127 * <ol> 128 * <li>a number that indicates the response code from the server 129 * <li>a string that contains any response text from the server 130 * </ol> 131 * 132 */ 133 this.createTopicSubscription = function(filter, subscriptionName, durable, onSuccess, onFailure) { 134 135 trace("Enter: Client.createTopicSubscription"); 136 137 // POST /restmsg/topic/filter?subscribe=name&durable=bool 138 var filterEncoded = encodeURIComponent(filter); 139 var requestURL = url + "/topic/" + filterEncoded + "?subscribe=" + subscriptionName + "&durable=" + durable.toString(); 140 trace("Request URL is " + requestURL); 141 142 var xhrSubscribe = new XMLHttpRequest(); 143 xhrSubscribe.open('POST', requestURL, true); 144 this.setRequestHeaders(xhrSubscribe); 145 146 xhrSubscribe.onreadystatechange = function() { 147 if (this.readyState != 4) { return; } 148 if (this.status === 200) { 149 if (onSuccess) { 150 onSuccess(this.responseText); 151 } 152 } else { 153 if (onFailure) { 154 onFailure(this.status, this.responseText); 155 } 156 } 157 this.onreadystatechange = function() { }; 158 }; 159 160 xhrSubscribe.send(); 161 162 } 163 164 165 /** 166 * Obtain messages for current subscriptions. 167 * 168 * 169 * @name MessagingREST.Client#retrieveMessages 170 * @function 171 * @param {number} timeout - The amount of time to wait for a message. 172 * @param {function} onSuccess - Called after a response with a status code of 200 is received 173 * from the server. A single response parameter is passed 174 * to the onSuccess callback: 175 * <ol> 176 * <li>a string that contains any response from the request 177 * </ol> 178 * @param {function} onFailure - Called when a status code other than 200 is received from 179 * the server. Two response parameters are passed to the 180 * onFailure callback: 181 * <ol> 182 * <li>a number that indicates the response code from the server 183 * <li>a string that contains any response text from the server 184 * </ol> 185 * 186 */ 187 this.retrieveMessages = function(timeout, onSuccess, onFailure) { 188 189 trace("Enter: Client.retrieveMessages"); 190 191 // GET /restmsg?timeout=int 192 var requestUrl = url + "?timeout=" + timeout; 193 trace("Request URL is " + requestUrl); 194 var xhrMsgs = new XMLHttpRequest(); 195 196 xhrMsgs.open('GET', requestUrl, true); 197 this.setRequestHeaders(xhrMsgs); 198 199 xhrMsgs.onreadystatechange = function() { 200 if (this.readyState != 4) { return; } 201 if (this.status === 200) { 202 if (onSuccess) { 203 var topic = this.getResponseHeader("Topic"); 204 var retained = this.getResponseHeader("Retained"); 205 onSuccess(topic, retained, this.responseText); 206 } 207 } else { 208 if (onFailure) { 209 onFailure(this.status, this.statusText); 210 } 211 } 212 this.onreadystatechange = function() { }; 213 }; 214 215 xhrMsgs.send(); 216 217 } 218 219 /** 220 * Invoke action to obtain retained messages from topic. 221 * This API will invoke an asynchronous call on the IBM 222 * MessageSight server that will attempt to obtain a retained 223 * message. After successful callback from this API a check 224 * for the retained message can be done with a call to 225 * MessagingREST.Client#retrieveMessages 226 * 227 * 228 * @name MessagingREST.Client#getRetainedMsg 229 * @function 230 * @param {string} topicName - The topic name to obtain a retained message from. 231 * @param {function} onSuccess - Called after a response with a status code of 200 is received 232 * from the server. A single response parameter is passed 233 * to the onSuccess callback: 234 * <ol> 235 * <li>a string that contains any response from the request 236 * </ol> 237 * @param {function} onFailure - Called when a status code other than 200 is received from 238 * the server. Two response parameters are passed to the 239 * onFailure callback: 240 * <ol> 241 * <li>a number that indicates the response code from the server 242 * <li>a string that contains any response text from the server 243 * </ol> 244 * 245 */ 246 this.getRetainedMsg = function(topicName, onSuccess, onFailure) { 247 248 trace("Enter: Client.getRetainedMsg"); 249 250 // GET /restmsg/topic/topicName 251 var topicNameEncoded = encodeURIComponent(topicName); 252 var requestUrl = url + "/topic/" + topicNameEncoded; 253 trace("Request URL is " + requestUrl); 254 var xhrRetainedMsgs = new XMLHttpRequest(); 255 256 xhrRetainedMsgs.open('GET', requestUrl, true); 257 this.setRequestHeaders(xhrRetainedMsgs); 258 259 xhrRetainedMsgs.onreadystatechange = function() { 260 if (this.readyState != 4) { return; } 261 if (this.status === 200) { 262 if (onSuccess) { 263 onSuccess(this.responseText); 264 } 265 } else { 266 if (onFailure) { 267 onFailure(this.status, this.statusText); 268 } 269 } 270 this.onreadystatechange = function() { }; 271 }; 272 273 xhrRetainedMsgs.send(); 274 275 } 276 277 /** 278 * Invoke action to delete retained message from a 279 * given topic. 280 * 281 * 282 * @name MessagingREST.Client#deleteRetained 283 * @function 284 * @param {string} topicName - The topic that the retained message should be removed from. 285 * @param {function} onSuccess - Called after a response with a status code of 200 is received 286 * from the server. A single response parameter is passed 287 * to the onSuccess callback: 288 * <ol> 289 * <li>a string that contains any response from the request 290 * </ol> 291 * @param {function} onFailure - Called when a status code other than 200 is received from 292 * the server. Two response parameters are passed to the 293 * onFailure callback: 294 * <ol> 295 * <li>a number that indicates the response code from the server 296 * <li>a string that contains any response text from the server 297 * </ol> 298 * 299 */ 300 this.deleteRetained = function(topicName, onSuccess, onFailure) { 301 302 trace("Enter: Client.deleteRetained"); 303 304 // GET /restmsg/topic/topicName 305 var topicNameEncoded = encodeURIComponent(topicName); 306 var requestUrl = url + "/topic/" + topicNameEncoded; 307 trace("Request URL is " + requestUrl); 308 var xhrDeleteRetained = new XMLHttpRequest(); 309 310 xhrDeleteRetained.open('PUT', requestUrl, true); 311 this.setRequestHeaders(xhrDeleteRetained); 312 313 xhrDeleteRetained.onreadystatechange = function() { 314 if (this.readyState != 4) { return; } 315 if (this.status === 200) { 316 if (onSuccess) { 317 onSuccess(this.responseText); 318 } 319 } else { 320 if (onFailure) { 321 onFailure(this.status, this.statusText); 322 } 323 } 324 this.onreadystatechange = function() { }; 325 }; 326 327 xhrDeleteRetained.send(null); 328 329 } 330 331 /** 332 * Publish a message to a specific topic. 333 * 334 * 335 * @name MessagingREST.Client#createTopicSubscription 336 * @function 337 * @param {string} topicName - the topic filter that the subscription should be set to 338 * @param {boolean} persist - if the message should persist 339 * @param {boolean} retain - if the message should be retained 340 * @param {function} onSuccess - Called after a response with a status code of 200 is received 341 * from the server. A single response parameter is passed 342 * to the onSuccess callback: 343 * <ol> 344 * <li>a string that contains any response from the request 345 * </ol> 346 * @param {function} onFailure - Called when a status code other than 200 is received from 347 * the server. Two response parameters are passed to the 348 * onFailure callback: 349 * <ol> 350 * <li>a number that indicates the response code from the server 351 * <li>a string that contains any response text from the server 352 * </ol> 353 * 354 */ 355 this.publishMessageTopic = function(topicName, persist, retain, onSuccess, onFailure) { 356 357 trace("Enter: Client.publishMessageTopic"); 358 359 // POST /restmsg/topic/topicname?persist=bool&retain=bool 360 var topicNameEncoded = encodeURIComponent(topicName); 361 var requestUrl = url + "/topic/" + topicNameEncoded + "?persist=" + persist.toString() + "&retain=" + retain.toString(); 362 trace("Request URL is " + requestUrl); 363 364 var xhrPublish = new XMLHttpRequest(); 365 xhrPublish.open('POST', requestUrl, true); 366 this.setRequestHeaders(xhrPublish); 367 xhrPublish.setRequestHeader("Content-Type", "text/plain"); 368 369 xhrPublish.onreadystatechange = function() { 370 if (this.readyState != 4) { return; } 371 if (this.status === 200) { 372 if (onSuccess) { 373 onSuccess(this.responseText); 374 } 375 } else { 376 if (onFailure) { 377 onFailure(this.status, this.responseText); 378 } 379 } 380 this.onreadystatechange = function() { }; 381 }; 382 383 var msgObj = {message: topicForm.textMessage.value } 384 var msgString = JSON.stringify(msgObj); 385 xhrPublish.send(topicForm.textMessage.value); 386 387 } 388 389 390 /** 391 * Send an explicit disconnect request to IBM MessageSight 392 * 393 * 394 * @name MessagingREST.Client#sendDisconnect 395 * @function 396 * @param {number} timeout - Amount of time that IBM MessageSight should wait for the 397 * request to complete. 398 * @param {function} onSuccess - Called after a response with a status code of 200 is received 399 * from the server. A single response parameter is passed 400 * to the onSuccess callback: 401 * <ol> 402 * <li>a string that contains any response from the request 403 * </ol> 404 * @param {function} onFailure - Called when a status code other than 200 is received from 405 * the server. Two response parameters are passed to the 406 * onFailure callback: 407 * <ol> 408 * <li>a number that indicates the response code from the server 409 * <li>a string that contains any response text from the server 410 * </ol> 411 * 412 */ 413 this.sendDisconnect = function(timeout, onSuccess, onFailure) { 414 415 trace("Enter: Client.sendDisconnect"); 416 417 // POST /restmsg?close=int 418 var requestUrl = url + "?close=" + timeout; 419 trace("Request URL is " + requestUrl); 420 421 var xhrClose = new XMLHttpRequest(); 422 xhrClose.open('POST', requestUrl, true); 423 this.setRequestHeaders(xhrClose); 424 425 xhrClose.onreadystatechange = function() { 426 if (this.readyState != 4) { return; } 427 if (this.status === 200) { 428 if (onSuccess) { 429 onSuccess(this.responseText); 430 } 431 } else { 432 if (onFailure) { 433 onFailure(this.status, this.responseText); 434 } 435 } 436 this.onreadystatechange = function() { }; 437 }; 438 439 xhrClose.send(); 440 441 } 442 443 }; 444 445 446 // Module contents. 447 return { 448 Client: Client 449 }; 450 451 })(window); 452