Use the Kaazing Enterprise JavaScript JMS Client API
In this procedure, you will learn how to use the Kaazing Gateway JavaScript JMS Client API and the supported APIs. The steps in this procedure show you how to develop a JavaScript JMS messaging client. For the backend, you'll use the publicly available Kaazing WebSocket Gateway and JMS broker via the URL wss://demos.kaazing.com/jms
.
Alternatively, you can use a local copy of the Gateway and your own JMS-compliant message broker (see Setting Up the Gateway and Clients). By default, the Gateway is configured to connect to the server on tcp://localhost:61616
. You can configure the connect URL in the file GATEWAY_HOME/conf/gateway-config.xml. See About Integrating Kaazing Gateway and JMS-Compliant Message Brokers for more information.
- To find out more specific information about the supported APIs or to learn which APIs are not supported, refer to Kaazing Gateway JMS Client Libraries: Supported APIs.
- Learn about supported browsers, operating systems, and platform versions in the Release Notes.
Before You Begin
This procedure is part of Checklist: Build JavaScript JMS Clients Using Kaazing Gateway.
To use the Kaazing Enterprise JavaScript JMS client libraries to create a JMS messaging client:
- Clone or download the JavaScript JMS tutorial from https://github.com/kaazing/javascript.client.tutorials.
- In the tutorial project, navigate to the folder
javascript.client.tutorials/jms
. - Create a new HTML files named jmsClient.html and save it in the
javascript.client.tutorials/jms
folder. Copy and paste the following text and HTML form into the new jmsClient.html file:
<html> <head> </head> <body> <div class="main-container "> <div class="main wrapper clearfix"> <div class="powered-wrapper"> <div class="powered-header"></div> </div> <article> <section> <!-- Kaazing scripts --> <!-- JavaScript JMS Client Code --> <script> </script> <h1>JavaScript JMS Messaging Demo</h1> <br/> <div id="jms-javascript"> <div id="middle"> <div class="leftPanels"> <div id="login_div" class="panel"> <span class="info">User name and password values are optional</span> <label for="url">Location</label><input id="url"/><br/> <label for="username">Username</label><input id="username"><br/> <label for="password">Password</label><input type="password" id="password"><br/> <label></label> <div id="sso_logindiv" style="margin-left: 2px; position: absolute; border: 1px solid black; border-radius:10px; display: none; height: 190px; width: 318px; background-color:#d0e7fd; z-index: 999;"> <div style="margin-left: 20px; height: 35px; margin-top: 20px; font-weight: bold;"> Login </div> <div style="height: 124px; width: 296px; border: 1px solid black; border-radius:10px; background-color:white; margin-left: 10px;"> <div style="margin-left:10px; margin-top: 10px;"> <span style="width: 60px; font-size:11pt;">Username:</span><input id="sso_username" size="12" style="width: 180px" value=""/> </div> <div style="margin-left:10px"> <span style="width: 60px; font-size:11pt;">Password:</span><input id="sso_password" type="password" size="12" style="width: 180px" value=""/> </div> <div style="margin-left:45px"> <button id="sso_login" style="margin-left:25px; width: 60px;">OK</button> <button id="sso_cancel" style="margin-left:25px; width: 60px;">Cancel </button> </div> </div> </div> <button id="connect">Connect</button> <button id="disconnect">Close</button> </div> <div id="subscribe_div" class="panel"> <span class="info">Subscribe, set message selectors, send messages, and add message properties</span><br/> <label for="destination">Destination</label><input id="destination" value="/topic/destination"><br/> <label for="messageSelector">Message Selector</label><input id="messageSelector" value="" placeholder="Example: symbol='KZNG'"><br/> <label></label> <button id="subscribe">Subscribe</button> <br/><br/> <label for="message">Message</label><input id="message" value="Hello, message"><br/> <label>Custom Property</label><input id="propName1" value="" placeholder="Property name" class="halfWidth"/><input id="propValue1" value="" placeholder="Property value" class="halfWidth propValue"/> <label>Custom Property</label><input id="propName2" value="" placeholder="Property name" class="halfWidth"/><input id="propValue2" value="" placeholder="Property value" class="halfWidth propValue"/> <label>Custom Property</label><input id="propName3" value="" placeholder="Property name" class="halfWidth"/><input id="propValue3" value="" placeholder="Property value" class="halfWidth propValue"/> <label for="binary">Binary </label><input type="checkbox" id="binary" class="cb"><br/> <label></label> <button id="send">Send</button> </div> </div> <div class="rightPanels"> <div id="console_div" class="panel"> <div class="info"> <div style="float: left;"> Log messages </div> <div style="float: right; margin-right: 5px;"> Messages received : <span id="receivedMessageCount">0</span> </div> <div class="clearfix"></div> </div> <div id="console"></div> <button id="clear">Clear Log</button> <input type="checkbox" id="toggleJmsHeadersCb" class="cb" checked="checked" style="margin-left: 20px;"><label for="toggleJmsHeadersCb">Show JMS headers</label> </div> </div> <div class="clearfix"></div> <div id="bottomPanelRow"> <div class="leftPanels"> <div id="transaction_div" class="panel"> <span class="info">Send messages as a single transaction</span><br/> <label for="txDestination">Destination</label><input id="txDestination" value="/topic/destination"><br/> <label for="txMessage">Message</label><input id="txMessage" value="Hello, transaction"><br/> <label for="binaryTransaction">Binary </label><input type="checkbox" id="binaryTransaction" class="cb"><br/> <label></label> <button id="txSend">Send</button> <button id="commit">Commit</button> <button id="rollback">Rollback</button> </div> </div> <div class="rightPanels"> <div id="subscriptions_div" class="panel"> <span class="info">Active subscriptions</span> <table id="subscriptions"> <thead> <tr> <th class="destination">Destination</th> <th class="selector">Message Selector</th> <th></th> </tr> </thead> <tbody> </tbody> </table> </div> </div> <div class="clearfix"></div> </div> </div><!-- middle --> </div><!-- jms-javascript --> </section> </article> </div> <!-- #main --> </div> <!-- #main-container --> </body> </html>
Note the
id
in eachform
element. These ids will be used in your JavaScript code to reference user input and events.In the
head
section, add the followinglink
tags for the CSS stylesheets:<link rel="stylesheet" href="css/normalize.css"> <link rel="stylesheet" href="css/dev.css"> <link rel="stylesheet" href="css/demo.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
- Save the HTML page.
- To see how the page looks, drag the echo.html file into a browser.
In your HTML page named jmsClient.html, add a
script
tag in thehead
section that points to the Kaazing JavaScript WebSocket and JMS libraries available on a content delivery network:<script src="http://cdn.kaazing.com/releases/enterprise.javascript.client/4.1.0/WebSocket.js"></script> <script src="http://cdn.kaazing.com/releases/enterprise.javascript.client/4.1.0/JmsClient.js"></script>
For more information about where you can get the Kaazing JavaScript WebSocket and JMS libraries, see kaazing/download.
- In the
script
tag below theJavaScript JMS Client Code
comment, declare variables for the connection, session and UI elements:var connection; var session; /* UI Elements */ var logConsole, url, username, password, connect, disconnect; var destination, message, messageSelector, subscribe, send; var txSend, txDestination, txMessage, commit, rollback, clear, binary, binaryTransaction; var receivedMessageCount, receivedMessageCounter = 0; var subscriptionsTable; var destinationCounter = 1; var toggleJmsHeadersCb;
- Add the code for the Log Message UI console feature:
function clearLog() { while (logConsole.childNodes.length > 0) { logConsole.removeChild(logConsole.lastChild); } } // Log a string message function log(message) { var div = document.createElement("div"); div.className = "logMessage" div.innerHTML = message; logDiv(div); } function logDiv(div) { logConsole.appendChild(div); toggleJmsHeaders(); // Hide the headers if that's what the user specified // Make sure the last line is visible. logConsole.scrollTop = logConsole.scrollHeight; while (logConsole.childNodes.length > 20) { // Delete two rows to preserved the alternate background colors. logConsole.removeChild(logConsole.firstChild); logConsole.removeChild(logConsole.firstChild); } }
- Add a function for updating the Connect and Disconnect buttons in the UI:
function updateConnectionButtons(connected) { connect.disabled = connected; disconnect.disabled = !connected; subscribe.disabled = !connected; send.disabled = !connected; txSend.disabled = commit.disabled = rollback.disabled = !connected; }
- Add a function for creating the destination provided by the user (not the requirement specified in the error message):
function createDestination(name, session) { if (name.indexOf("/topic/") == 0) { return session.createTopic(name); } else if (name.indexOf("/queue/") == 0) { return session.createQueue(name); } else { throw new Error("Destination must start with /topic/ or /queue/"); } }
- Add a function to respond to a Connect event. This function creates the WebSocket connection with the Gateway. Note that it uses a
try...catch
statement. A function for handling connection exceptions is also added.function handleConnect() { log("CONNECT: " + url.value + " " + username.value); var jmsConnectionFactory = new JmsConnectionFactory(url.value); connect.disabled=true; try { var connectionFuture = jmsConnectionFactory.createConnection(username.value, password.value, function () { if (!connectionFuture.exception) { try { connection = connectionFuture.getValue(); connection.setExceptionListener(handleException); log("CONNECTED"); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); transactedSession = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); connection.start(function () { updateConnectionButtons(true); }); } catch (e) { connect.disabled=false; handleException(e); } } else { connect.disabled=false; handleException(connectionFuture.exception); } }); } catch (e) { handleException(e); } }
- Add a function to handle exceptions and log them for the user in the log console.
function handleException(e) { log("<span class='error'>EXCEPTION: " + e + "</span>"); if (e.type == "ConnectionDisconnectedException") { updateConnectionButtons(false); } }
- Add a function for handling when a user disconnects from the Gateway. The function will close the connection, clear subscriptions, and update the UI.
function handleDisconnect() { disconnect.disabled = "disabled"; // Clear any subscriptions. if (document.getElementsByClassName) { var subscriptions = document.getElementsByClassName("unsubscribeButton"); while (subscriptions[0]) { subscriptions[0].click(); } } else { // The IE way. var unsubscribeButtons = subscriptionsTable.getElementsByTagName("button"); while (unsubscribeButtons.length > 0) { var b = unsubscribeButtons[0]; if (b.className == "unsubscribeButton") { b.click(); } } } log("CLOSE"); try { connection.close(function () { log("CONNECTION CLOSED"); updateConnectionButtons(false); }); } catch (e) { handleException(e); } }
- Add a function for when a user subscribes to a destination, creating the destination and a consumer with a message listener using the destination supplied by the user. A lot of this function changes the UI to enable fields for message selector, custom properties, and adds an Unsubscribe button.
function handleSubscribe() { var name = destination.value; var destinationId = destinationCounter++; log("SUBSCRIBE: " + name + " <span class=\"subscriptionTag\">[#" + destinationId + "]</span>"); var dest = createDestination(name, session); var consumer; if (messageSelector.value.length > 0) { consumer = session.createConsumer(dest, messageSelector.value); } else { consumer = session.createConsumer(dest); } consumer.setMessageListener(function (message) { handleMessage(name, destinationId, message); }); // Add a row to the subscriptions table. var tBody = subscriptionsTable.tBodies[0]; var rowCount = tBody.rows.length; var row = tBody.insertRow(rowCount); var destinationCell = row.insertCell(0); destinationCell.className = "destination"; destinationCell.appendChild(document.createTextNode(name + " ")); var destNode = document.createElement("span"); destNode.className = "subscriptionTag"; destNode.innerHTML = "[#" + destinationId + "]"; destinationCell.appendChild(destNode); var messageSelectorCell = row.insertCell(1); messageSelectorCell.className = "selector"; messageSelectorCell.appendChild(document.createTextNode(messageSelector.value)); var unsubscribeCell = row.insertCell(2); var unsubscribeButton = document.createElement("button"); unsubscribeButton.className = "unsubscribeButton"; unsubscribeButton.innerHTML = "Unsubscribe"; unsubscribeButton.addEventListener('click', function (event) { var targ; if (event.target) { targ = event.target; } else { targ = event.srcElement; // The wonders of IE } log("UNSUBSCRIBE: " + name + " <span class=\"subscriptionTag\">[#" + destinationId + "]</span>"); if (consumer) { consumer.close(null); } var rowIndex = targ.parentElement.parentElement.rowIndex subscriptionsTable.deleteRow(rowIndex); }, false); unsubscribeCell.appendChild(unsubscribeButton); }
- Add a function to handle the message the user sends. The function is called by the previous function you created,
handleSubscribe()
. The function will determine if the message is text or binary or a mapmessage and display the message, message headers, and any properties in the log console.function handleMessage(destination, destinationId, message) { var content = ""; if (message instanceof TextMessage) { content = "RECEIVED TextMessage: " + message.getText(); } else if (message instanceof BytesMessage) { var body = []; message.readBytes(body); content = "RECEIVED BytesMessage: " + body; } else if (message instanceof MapMessage) { var keys = message.getMapNames(); content = "RECEIVED MapMessage: <br/>"; for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = message.getObject(key); var type; if (value == null) { type = ""; } else if (value instanceof String) { type = "String"; } else if (value instanceof Number) { type = "Number"; } else if (value instanceof Boolean) { type = "Boolean"; } else if (value instanceof Array) { type = "Array"; } content += key + ": " + value; if (type != "") { content += " (" + type + ")" } content += "<br />"; } } else { content = "RECEIVED UNKNOWN MESSAGE"; } var div = document.createElement("div"); div.className = "logMessage receiveMessage" div.innerHTML = content; div.appendChild(buildDestinationDiv("Subscription", destination)); div.appendChild(buildPropertiesDiv(message)); div.appendChild(buildJMSHeadersDiv(message, true)); logDiv(div); receivedMessageCount.innerHTML = ++receivedMessageCounter; } var logMessageSend = function (classname, prefix, destination, messageStr, message) { var div = document.createElement("div"); div.className = "logMessage " + classname div.innerHTML = prefix + messageStr; div.appendChild(buildPropertiesDiv(message)); div.appendChild(buildJMSHeadersDiv(message, false)); logDiv(div); } var buildDestinationDiv = function (label, destName, destId) { var destinationDiv = document.createElement("div"); destinationDiv.className = "destination"; var destIdStr = ""; if (destId != undefined) { destIdStr = " [#" + destId + "]"; } destinationDiv.innerHTML += label + ": " + destName + destIdStr; return destinationDiv; } var buildPropertiesDiv = function (message) { var propsDiv = document.createElement("div"); propsDiv.className = "properties"; var props = message.getPropertyNames(); while (props.hasMoreElements()) { var propName = props.nextElement(); var propValue = message.getStringProperty(propName); propsDiv.innerHTML += "Property: " + propName + "=" + propValue + "<br>"; } return propsDiv; } var buildJMSHeadersDiv = function (message, receive) { var headersDiv = document.createElement("div"); headersDiv.className = "headers"; var deliveryModeStr; switch (message.getJMSDeliveryMode()) { case DeliveryMode.NON_PERSISTENT: deliveryModeStr = "NON_PERSISTENT"; break; case DeliveryMode.PERSISTENT: deliveryModeStr = "PERSISTENT"; break; default: deliveryModeStr = "UNKNOWN"; } var jmsDestination = message.getJMSDestination(); var destinationName = (jmsDestination instanceof Queue) ? jmsDestination.getQueueName() : jmsDestination.getTopicName(); headersDiv.innerHTML += "JMSDestination: " + destinationName + "<br>"; if (receive) { headersDiv.innerHTML += "JMSRedelivered: " + message.getJMSRedelivered() + "<br>"; } headersDiv.innerHTML += "JMSDeliveryMode: " + message.getJMSDeliveryMode() + " (" + deliveryModeStr + ")<br>"; headersDiv.innerHTML += "JMSPriority: " + message.getJMSPriority() + "<br>"; headersDiv.innerHTML += "JMSMessageID: " + message.getJMSMessageID() + "<br>"; headersDiv.innerHTML += "JMSTimestamp: " + message.getJMSTimestamp() + "<br>"; headersDiv.innerHTML += "JMSCorrelationID: " + message.getJMSCorrelationID() + "<br>"; headersDiv.innerHTML += "JMSType: " + message.getJMSType() + "<br>"; headersDiv.innerHTML += "JMSReplyTo: " + message.getJMSReplyTo() + "<br>"; return headersDiv; } var addProperties = function (message) { var i = 1; var propName; while (propName = document.getElementById("propName" + i)) { if (propName.value.length > 0) { var propValue = document.getElementById("propValue" + i); message.setStringProperty(propName.value, propValue.value); } i++; } }
- Add a function for when a user clicks Send. The function checks to see if the message is text or binary (user checked the binary option), adds any properties, and updates the log console.
function handleSend() { var name = destination.value; var dest = createDestination(name, session); var producer = session.createProducer(dest); if (!binary.checked) { var textMsg = session.createTextMessage(message.value); addProperties(textMsg); try { var future = producer.send(textMsg, function () { if (future.exception) { handleException(future.exception); } }); } catch (e) { handleException(e); } logMessageSend("sendMessage", "SEND TextMessage: ", destination.value, message.value, textMsg); } else { var bytesMsg = session.createBytesMessage(); bytesMsg.writeUTF(message.value); addProperties(bytesMsg); try { var future = producer.send(bytesMsg, function () { if (future.exception) { handleException(future.exception); } }); } catch (e) { handleException(e); } logMessageSend("sendMessage", "SEND BytesMessage: ", destination.value, message.value, bytesMsg); } producer.close(); }
- Next add the functions for messages sent as transactions. The function also handles the commit and rollback methods of the transaction.
function handleTxSend() { var name = txDestination.value; var dest = createDestination(name, transactedSession); var producer = transactedSession.createProducer(dest); if (!binaryTransaction.checked) { var textMsg = transactedSession.createTextMessage(txMessage.value); try { var future = producer.send(textMsg, function () { if (future.exception) { handleException(future.exception); } }); } catch (e) { handleException(e); } logMessageSend("txSendMessage", "SEND TextMessage: ", name, txMessage.value, textMsg); } else { var bytesMsg = transactedSession.createBytesMessage(); bytesMsg.writeUTF(txMessage.value); try { var future = producer.send(bytesMsg, function () { if (future.exception) { handleException(future.exception); } }); } catch (e) { handleException(e); } logMessageSend("txSendMessage", "SEND BytesMessage: ", name, txMessage.value, bytesMsg); } producer.close(); } function handleCommit() { log("COMMIT"); try { var future = transactedSession.commit(function () { if (!future.exception) { log("TRANSACTION COMMITTED"); } else { handleException(future.exception); } }); } catch (e) { handleException(e); } } function handleRollback() { log("ROLLBACK"); transactedSession.rollback(function () { log("TRANSACTION ROLLED BACK"); }); }
- Add a variable containing a function for displaying or hiding message headers in the log console, depending on whether or not the user has click the Show JMS headers option. This variable is used in many other functions.
var toggleJmsHeaders = function (event) { $('div.headers').toggleClass('hidden', !toggleJmsHeadersCb.checked); }
- Lastly, add a jquery function to load when the HTML page is loaded in the browser. The jquert function will initialize variables for the UI elements that will be used by the other program functions.
$(document).ready(function () { // Initialize UI elements url = document.getElementById("url"); username = document.getElementById("username"); password = document.getElementById("password"); connect = document.getElementById("connect"); disconnect = document.getElementById("disconnect"); logConsole = document.getElementById("console") receivedMessageCount = document.getElementById("receivedMessageCount"); toggleJmsHeadersCb = document.getElementById("toggleJmsHeadersCb"); destination = document.getElementById("destination"); messageSelector = document.getElementById("messageSelector"); message = document.getElementById("message"); subscribe = document.getElementById("subscribe"); send = document.getElementById("send"); txSend = document.getElementById("txSend"); txDestination = document.getElementById("txDestination"); txMessage = document.getElementById("txMessage"); commit = document.getElementById("commit"); rollback = document.getElementById("rollback"); clear = document.getElementById("clear"); binary = document.getElementById("binary"); binaryTransaction = document.getElementById("binaryTransaction"); subscriptionsTable = document.getElementById("subscriptions"); // construct the WebSocket location var locationURI = new URI("wss://demos.kaazing.com/jms"); // default the location url.value = locationURI.toString(); updateConnectionButtons(false); connect.onclick = handleConnect; disconnect.onclick = handleDisconnect; subscribe.onclick = handleSubscribe; send.onclick = handleSend; txSend.onclick = handleTxSend; commit.onclick = handleCommit; rollback.onclick = handleRollback; clear.onclick = clearLog; toggleJmsHeadersCb.onclick = toggleJmsHeaders; // initialize the disabled states connect.disabled = null; disconnect.disabled = "disabled"; });
- Save the jmsClient.html file.
- Test the JavaScript JMS client. Drag the jmsClient.html file into a web browser. The URL
wss://demos.kaazing.com/jms
is displayed in the Location field. - Click Connect. The Log displays a successful connection to the Gateway. If there is an exception, review your code for possible errors.
- Subscribe to a destination and then send a message to the destination and receive the message response.
Migrate JavaScript Applications to Kaazing Gateway 4.x
If you wish to migrate your Kaazing Gateway 3.3-3.5 JavaScript clients to Kaazing Enterpise JavaScript SDK 4.x and use its new library, do the following:
- Add the new WebSocket.js library to your client, as described in this procedure.
- Use the new JmsClient.js library in Kaazing Enterpise JavaScript SDK 4.x. This has replaced the StompJms.js library from 3.3-3.5.
- Change any StompJms.js references to JmsClient.js.
- Change any instances of
StompConnectionFactory
toJmsConnectionFactory
. Modify challenge handlers. In Kaazing Enterpise JavaScript SDK 4.x,
ChallengeHandlers
from 3.3-3.5 was replaced with by theChallengeHandler
method ofWebSocketFactory
. TheChallengeHandler
method is used during authentication for connections and subsequent revalidation that occurs at regular intervals.Kaazing Gateway 3.3-3.5:
function setupSSO() { /* Respond to authentication challenges with popup login dialog */ var basicHandler = new BasicChallengeHandler(); basicHandler.loginHandler = function(callback) { popupLoginDialog(callback); } ChallengeHandlers.setDefault(basicHandler); }
Kaazing Enterpise JavaScript SDK 4.x:
function setupSSO(webSocketFactory) { /* Respond to authentication challenges with popup login dialog */ var basicHandler = new BasicChallengeHandler(); basicHandler.loginHandler = function(callback) { popupLoginDialog(callback); } webSocketFactory.setChallengeHandler(basicHandler); }
- Review the JavaScript JMS Client API.
Durable Subscribers
Note: Currently, the Gateway does not support durable subscribers with Apache ActiveMQ. You may use durable subscribers with TIBCO EMS or Informatica UM. For more information, see Durable Subscribers.If your JMS client needs to receive all of the messages published on a topic, including the ones published while the subscriber is inactive because it is not being used or has lost connections (which is common when using mobile devices), create a durable TopicSubscriber using the Session.createDurableSubscriber() method.
To unsubscribe from a durable subscription that has been created by a client and delete the state being maintained on behalf of the subscriber by the broker, use the unsubscribe()
method available in the Session
object.
The JMS provider retains a separate record of each durable subscription and ensures that all messages from the topic's publishers are retained until they are acknowledged by each durable subscriber or they have expired. Whether messages have been acknowledged is tracked separately for each durable subscriber, and each durable subscriber is identified by the combination of its name and the clientID (if any) set on the Connection. Ensure your application confirms that the clientID (if used) is unique to the user or device, or, if it does not use clientID's, ensure that the durable name is unique to the user or device.
Example
In the following example, a web application enables users to connect to a JMS broker via the Gateway and specify both a username and durable name to create a durable subscriber. First, we'll look at the HTML content of the web application, and then look at the JavaScript functions that use the JavaScript JMS API.
In the connection section of the web application, a username field is included.
<div id="login_div" class="panel"> <label for="url">Location</label> <input id="url" /><br/> <label for="username">Username</label> <input id="username"><br/> <label for="password">Password</label> <input type="password" id="password"><br/> <button id="connect" >Connect</button> <button id="disconnect" >Close</button>
The following section of the web app shows a web form that enables users to subscribe, send messages, and unsubscribe to a particular destination and durable name.
<div id="subscribe_div" class="panel"> <span class="info">Subscribe, set message selectors, send messages, and add message properties</span> <label for="destination">Destination</label> <input id="destination" value="/topic/destination"><br/> <label for="messageSelector">Message Selector</label> <input id="messageSelector" placeholder="Example: symbol='KZNG'"><br /> <label for="durableName">Durable Name</label> <input id="durableName" value=""><br /> <button id="subscribe" >Subscribe</button> </div>
Next, variable names are assigned to each form element (note the variable that is a concatenation of the username and the durable name to ensure that the durable subscription is unique):
// Declare variables var url, username, password, connect, close, disconnect, message, messageSelector, subscribe; var destination; var durName; var durableName; var UniqueDurName; // Assign UI elements to variables url = document.getElementById("url"); username = document.getElementById("username"); password = document.getElementById("password"); connect = document.getElementById("connect"); close = document.getElementById("close"); disconnect = document.getElementById("disconnect"); message = document.getElementById("message"); messageSelector = document.getElementById("messageSelector"); subscribe = document.getElementById("subscribe"); send = document.getElementById("send"); destination = document.getElementById("destination"); durableName = document.getElementById("durableName"); // Create a unique durable name using a concatenation of user name and durable name UniqueDurName = username + "@" + durableName;
To create a connection, the user enters the location of the jms service (ws://example.com:8001/jms), a username, and then clicks Connect (password is optional). The following code creates the connection using the location and username:
function handleConnect() { // log the location and username values to the log text area in the UI log("CONNECT: " + url.value + " " + username.value); // Create a new connection to the JMS provider at the location entered by the user var jmsConnectionFactory = new JmsConnectionFactory(url.value); try { /*Create the actual JMS Connection via WebSocket. Username and password are options used to authenticate with the Gateway.*/ var connectionFuture = jmsConnectionFactory.createConnection( username.value, password.value, function () { if (!connectionFuture.exception) { try { connection = connectionFuture.getValue(); connection.setExceptionListener(handleException); log("CONNECTED"); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); transactedSession = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); connection.start(function () { updateConnectionButtons(true); }); } catch (e) { handleException(e); } } else { handleException(connectionFuture.exception); } }); } catch (e) { handleException(e); } }
To create a durable subscriber for a topic when a user clicks the Subscribe button, the web application calls the createDurableSubscriber() method of a Session object. Note the use of UniqueDurName, the variable created using a concatenation of username and durable name in order to create a unique durable subscription.
There are two instances of createDurableSubscriber(): the first instance is used if a message selector is entered by the user (lines 14-15), and the second is used if no message selector is entered (line 19).
function handleSubscribe() { // Assign the destination entered by the user to a variable var name = destination.value; // Create the destination and assign it to a variable var dest = createDestination(name, session); // Create a variable to hold the durable topic var consumer; // If a durable name is entered by the user, do the following if (durableName.value.length > 0) { // If a message selector was entered, use it when creating the durable topic if (messageSelector.value.length > 0) { /*Create the durable topic using the destination, name, and message selector entered by the user*/ consumer = session.createDurableSubscriber( dest, UniqueDurName, messageSelector.value, false); } else { // Or create the durable topic without the message selector consumer = session.createDurableSubscriber(dest, UniqueDurName); } } else if (messageSelector.value.length > 0) { consumer = session.createConsumer(dest, messageSelector.value); } else { consumer = session.createConsumer(dest); } consumer.setMessageListener(function(message) { handleMessage(name, destinationId, message); }); }Notes:
- Clients built using Kaazing Gateway 3.x libraries will work against Kaazing WebSocket Gateway 5.x. If you wish to upgrade your 3.x client to the Kaazing Enterpise JavaScript SDK 4.x libraries, please note that the 3.x clients used a single JMS library and Kaazing Enterpise JavaScript SDK 4.x clients include and use separate WebSocket and JMS libraries. Update your client library file and code references to include both the WebSocket and JMS libraries, as described in the 4.x documentation.
- Sessions with durable subscribers may be created using a unique client ID or with no client ID specified. For more information, see the jms service.
- A client can change an existing durable subscription by creating a durable TopicSubscriber with the same name and a new topic and/or message selector. Changing a durable subscriber is equivalent to unsubscribing (deleting) the old one and creating a new one.
- TemporaryTopic and TemporaryQueue objects are destroyed when the client loses its connection to the Gateway, or when the JMS-compliant message broker loses its connection to the Gateway. To address this, monitor the client's exception listener to handle recovery for your application. Once the connection is re-established, recreate TemporaryTopic and TemporaryQueue. ConnectionDroppedException and ConnectionInterruptedException are delivered to the connection's exception listener via onException, indicating that messages in flight might be lost, depending on message delivery options. ConnectionRestoredException is delivered to indicate that the connection through to the JMS-compliant message broker has been re-established. TemporaryTopic and TemporaryQueue should be recreated at that time to resume operations.