Stomp is a simple text-orientated messaging protocol. It defines an interoperable wire format so that any of the available Stomp Clients can communicate with any Stomp Message Broker to provide easy and widespread messaging interoperability among languages, platforms and brokers.
Web Sockets are "TCP for the Web".
When Google announced the availability of Web Sockets in Google Chrome, it explained the idea behind Web Sockets:
The Web Sockets API enables web applications to handle bidirectional communications with server-side process in a straightforward way. Developers have been using XMLHttpRequest ("XHR") for such purposes, but XHR makes developing web applications that communicate back and forth to the server unnecessarily complex. XHR is basically asynchronous HTTP, and because you need to use a tricky technique like long-hanging GET for sending data from the server to the browser, simple tasks rapidly become complex. As opposed to XMLHttpRequest, Web Sockets provide a real bidirectional communication channel in your browser. Once you get a Web Socket connection, you can send data from browser to server by calling a send() method, and receive data from server to browser by an onmessage event handler.
In addition to the new Web Sockets API, there is also a new protocol (the "web socket protocol") that the browser uses to communicate with servers. The protocol is not raw TCP because it needs to provide the browser's "same-origin" security model. It's also not HTTP because web socket traffic differers from HTTP's request-response model. Web socket communications using the new web socket protocol should use less bandwidth because, unlike a series of XHRs and hanging GETs, no headers are exchanged once the single connection has been established. To use this new API and protocol and take advantage of the simpler programming model and more efficient network traffic, you do need a new server implementation to communicate with.
The API is part of HTML5 and is currently only supported by Google Chrome and WebKit nightly builds and other modern Web browsers (Firefox, Safari) have ongoing work to support it too.
This library is not a pure Stomp client. It is aimed to run on the Web Sockets protocol which is not TCP. Basically, the Web Sockets protocol requires a handshake between the browser's client and the server to ensure the browser's "same-origin" security model remains in effect.
This means that this library can not connect to regular Stomp brokers since they would not understand the handshake initiated by the Web Socket which is not part of the Stomp protocol and would likely reject the connection.
There are ongoing works to add Web Socket support to Stomp brokers such as HornetQ and ActiveMQ so that they will accept Stomp connections over the Web Sockets protocol.
HornetQ is the Open Source messaging system developed by Red Hat and JBoss. Support for Stomp on Web Sockets is available for HornetQ subversion trunk.
To start HornetQ with support for Stomp on Web Sockets, run the following steps:
$ svn co http://anonsvn.jboss.org/repos/hornetq/trunk/ hornetq ... $ cd hornetq $ ./build.sh distro ... $ cd build/hornetq-2.1.0.BETA3/bin $ ./run.sh ../examples/jms/stomp-websockets/server0 ... Started Netty Acceptor version 3.2.0.BETA1-r2215 localhost:61614 for STOMP_WS protocol HornetQ Server version 2.0.0.GA (Hornet Queen, 113) started
HornetQ is now started and listens to Stomp over Web Sockets on the port 61614.
It accepts Web Sockets connections from the URL ws://localhost:61614/stomp
To configure and run HornetQ broker with Stomp on Web Sockets enabled, follow the instructions.
ActiveMQ is the Open Source messaging system developed by Apache. Starting with 5.4 snapshots, ActiveMQ supports Stomp on Web Sockets.
To configure and run ActiveMQ broker with Stomp on Web Sockets enabled, follow the instructions.
Stomp on Web Socket provides a straightforward mapping from a Stomp frame to a JavaScript object.
| Property | Type | Notes |
|---|---|---|
command | String | name of the frame ("CONNECT", "SEND", etc.)
|
headers | JavaScript object | |
body | String |
The command and headers properties will always be defined
but the headers can be empty if the frame has no headers.
The body can be null if the frame does not have a body.
Stomp JavaScript clients will communicate to a Stomp server using a ws:// URL.
To create a Stomp client JavaScript object, you need to call Stomp.client(url)
with the URL corresponding to the server's Web Socket endpoint:
var url = "ws://localhost:61614/stomp";
var client = Stomp.client(url);
Once a Stomp client is created, it must call its connect() method to effectively
connect and authenticate to the Stomp server. The method takes two mandatory arguments,
login and passcode corresponding to the user credentials.
Behind the scene, the client will open a connection using a Web Socket and send a CONNECT frame.
The connection is done asynchronously: you have no guarantee to be effectively connected when
the call to connect returns. To be notified of the connection, you can pass a
connect_callback function to the connect() method:
client.connect(login, passcode, connect_callback);
connect_callback = function() {
// called back after the client is connected and authenticated to the Stomp server
};
But what happens if the connection fails? the connect() method accepts an
optional error_callback argument which will be called if the client is not able
to connect to the server.
The callback will be called with a single argument, an error object corresponding to Stomp
ERROR frame:
client.connect(login, passcode, connect_callback, error_callback);
error_callback = function(error) {
// display the error's message header:
alert(error.headers.message);
};
To disconnect a client from the server, you can call its disconnect() method.
The disconnection is asynchronous: to be notified when the disconnection is effective,
the disconnect method takes an optional callback argument.
client.disconnect(function() {
alert("See you next time!");
};
When a client is disconnected, it can no longer send or receive messages.
When the client is connected to the server, it can send Stomp messages using
the send() method. The method takes a mandatory destination
argument corresponding to the Stomp destination. It also takes two optional
arguments: headers, a JavaScript object containing additional
message headers and body, a String object.
client.send("/queue/test", {priority: 9}, "Hello, Stomp");
The client will send a Stomp
SEND frame to /queue/test destination
with a header priority set to 9 and a body Hello, Stomp.
If you want to send a message with a body, you must also pass the headers
argument. If you have no headers to pass, use an empty JavaScript literal {}:
client.send(destination, {}, body);
To receive messages in the browser, the Stomp client must first subscribe to a destination.
You can use the subscribe() method to subscribe to a destination. The method takes 2 mandatory
arguments: destination, a String corresponding to the destination and
callback, a function with one message argument.
id = client.subscribe("/queue/test", callback);
The subscribe() methods returns an id that correspond to the client subscription. You can use this
subscription ID later on to unsubscribe the client from this destination.
The client will send a Stomp SUBSCRIBE frame to the server and register the callback. Every time the server send a message to the client, the client will in turn call the callback with a Stomp Frame object corresponding to the message:
callback = function(message) {
// called when the client receives a Stomp message from the server
if (message.body) {
alert("got message with body " + message.body)
} else {
alert("got empty message");
}
});
The subscribe() method takes an optional headers parameters to specify
additional headers when subscribing to a destination:
var headers = {ack: 'client', 'selector': "location = 'Europe'"};
client.subscribe("/queue/test", message_callback, headers);
The client specifies that it will handle the message acknowledgement and is interested to receive
only messages matching the selector location = 'Europe'.
If you want to subscribe the client to multiple destinations, you can use the same callback to receive all the messages:
onmessage = function(message) {
// called every time the client receives a message
}
client.subscribe("queue/test", onmessage);
client.subscribe("queue/another", onmessage);
To stop receiving messages, the client can use its unsubscribe() method.
The method takes a id argument corresponding to the subscription ID to unsubscribe from.
id = client.subscribe(...);
...
client.unsubscribe(id);
The method also takes an optional headers argument if the client needs to pass additional headers.
The body of a Stomp message must be a String. If you want to send and receive
JSON objects, you can use JSON.stringify() and JSON.parse() to transform the JSON
object to a String and vice versa.
var quote = {symbol: 'APPL', value: 195.46};
client.send("/topic/stocks", {}, JSON.stringify(quote));
client.subcribe("/topic/stocks", function(message) {
var quote = JSON.parse(message.body);
alert(quote.symbol + " is at " + quote.value);
};
By default, Stomp messages will be automatically acknowledged by the server before the message is delivered to the client.
The client can chose instead to handle message acknowledgement by subscribing to a destination and
specify a ack header set to 'client'.
In that case, the client must use the ack() method to inform the server that it has
acknowledge the message. The methods takes a mandatory message_id corresponding to the message
to acknowledge.
client.subscribe("/queue/test", {ack: 'client'}, function(message) {
// do something with the message
...
// and acknowledge it
var message_id = message.headers['message-id']
client.ack(message_id);
});
Messages can be sent and acknowledged in a transaction.
A transaction is started by the client using its begin() method
which takes a mandatory transaction, a String which uniquely identifies the
transaction.
The client can then send and acknowledge messages in the transasction by specifying a
transaction set with the transaction name.
A transaction is completed by the client by calling its commit() method.
Alternatively, the client can abort the transaction by calling its abort method.
var txid = "unique_transaction_identifier";
// start the transaction
client.begin(txid);
// send the message in a transaction
client.send("/queue/test", {transaction: txid}, "message in a transaction");
// commit the transaction to effectively send the message
client.commit(txid);
If you forget to add the transaction header when calling send()
the message will not be part of the transaction and will be sent directly without
waiting for the completion of the transaction.
var txid = "unique_transaction_identifier";
// start the transaction
client.begin(txid);
// oops! send the message outside the transaction
client.send("/queue/test", {}, "I thought I was in a transaction!");
client.abort(txid); // Too late! the message has been sent
There are few tests in the code and it is helpful to see what is sent and received from the library to debug application.
The client can set its debug property to a function with takes a String argument
to see all the debug statements of the library:
client.debug = function(str) {
// append the debug log to a #debug div somewhere in the page using JQuery:
$("#debug").append(str + "\n");
};
The source code contains a chat example in examples/chat/index.html
You need to start a Stomp server with support for Web Socket (using for example HornetQ).
Click on the Connect button to connect to the server and subscribe to the /queue/test/ queue.
You can then type messages in the form at the bottom of the page to send Stomp messages to the queue. Messages received by the client will be displayed at the top of the page.
You can also send regular Stomp messages and see them displayed in the browser. For example using directly telnet on Stomp default port:
$ telnet localhost 61613 CONNECT login:guest passcode:guest ^@ CONNECTED session:1092296064
^@ is a null (control-@ in ASCII) byte.
SEND destination:/queue/test Hello from TCP! ^@
You should now have received this message in your browser.
The source code is hosted on GitHub:
git clone git://github.com/jmesnil/stomp-websocket.git