Tuesday 18 October 2011

Stomp 1.1 Support in HornetQ

HornetQ now supports the Stomp 1.1 protocol and will be available in the next release, for now though it is part of trunk in the SVN repository.
Stomp 1.1 specification is an update to Stomp 1.0 and is backward compatible. New features include protocol negotiation, heartbeat, the NACK frame and virtual hosting.

An example 'stomp 1.1' is also available in the SVN repository which demonstrates a stomp client that uses one of the new features 'protocol negotiation', lets take a look at the example now.

1. Configuring a HornetQ Stomp Server

First of all we need to configure the server to allow stomp connections by adding a stomp acceptor, this is the same as stomp 1.0.
<acceptor name="stomp-acceptor">
<factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>   
<param key="protocol" value="stomp" />
<param key="port" value="61613" />
</acceptor>
2. Connection Negotiation

Once the HornetQ Stomp server is up and running, it is up to the Stomp client to decide which Stomp specification to use to communicate with HornetQ. This is done by connection negotiation. The Stomp1.1 example shows how to do this
// Step 1. Create a TCP socket to connect to the Stomp port
Socket socket = new Socket("localhost", 61613);

// Step 2. Send a CONNECT frame to connect to the server
String connectFrame = "CONNECT\n" +
"accept-version:1.1\n" +
"host:localhost\n" +
"login:guest\n" +
"passcode:guest\n" +
"request-id:1\n" +
"\n" +
END_OF_FRAME;

sendFrame(socket, connectFrame);

In the above code you can see that the client sends a CONNECT stomp frame with the accept-version set to 1.1, this tells the server that the client is using the 1.1 protocol.
Also new to 1.1 is the host header which is used to configure the virtual host to use, although HornetQ supports setting the header it doesn't support virtual hosts. All other headers are standard Stomp 1.0 headers.

If the server accepts the connection request, it will return a 'CONNECTED' stomp with a 'version' header whose value is 1.1. The example prints this to the console:
...
[java] response: CONNECTED
[java] version:1.1
[java] session:1337300467
[java] server:HornetQ/2.2.5 HornetQ Messaging Engine
[java] response-id:1
...
3. Sending and receiving messages.
Once connected, the client can send and receive Stomp messages with the connection. The example illustrates how to send a stomp message:
// Step 3. Send a SEND frame (a Stomp message) to the
// jms.queue.exampleQueue address with a text body
String text = "Hello World from Stomp 1.1 !";
String message = "SEND\n" +
 "destination:jms.queue.exampleQueue\n" +
 "\n" +
 text +
 END_OF_FRAME;
sendFrame(socket, message);
You can see this is very much the same as a Stomp 1.0 client. The message will be sent to the destination 'jms.queue.exampleQueue'. For the mapping of destination headers to HornetQ jms addresses please refer to the HornetQ's User Manual.
Note: Please pay attention to the leading and trailing spaces in the headers. Stomp 1.0 usually trims off the spaces before processing. But in Stomp 1.1, those spaces are preserved. So in Stomp1.1 unnecessary spaces in headers may result in strange errors which is difficult to find.

4. Enabling Heartbeats

One important feature added to Stomp 1.1 is the heartbeats used to monitor the underlying connection. The heart-beating is established at connection time, using a special header 'heart-beat' in CONNECT frame. For example:
CONNECT
accept-version:1.1
host:127.0.0.1
login:guest
passcode:guest
heart-beat:500,1000

Once connected with the above frame, the HornetQ server will make sure that a stomp frame (or a heartbeat byte) is sent to the client every 1 second (1000 milliseconds). Meanwhile the client should send a stomp frame (or a heartbeat byte) for every 500 milliseconds.
HornetQ server will deem a connection to be broken if it hasn't receive a stomp frame from the client via this connection for a time longer than 2 times of the client heart-beat interval (i.e. 2*500). So for the above case, if it hasn't receive any frame within a second, the server will close the connection.

Note: HornetQ specifies a minimum value for both client and server heart-beat intervals. The minimum interval for both client and server heartbeats is 500 milliseconds. That means if a client sends a CONNECT frame with heartbeat values lower than 500, the server will defaults the value to 500 milliseconds regardless the values of the 'heart-beat' header in the frame.

The HornetQ 1.1 implementation also has several performance improvements however we will continue to improve this over the coming months.

For more information read the stomp specification