To see Ajax in action, try running the examples
The AMQ AjaxServlet needs to be installed in your webapplications to support JMS over Ajax:
The servlet both serves the required js files and handles the JMS requests and responses.
The ajax featues of amq are provided on the client side by the amq.js script. Beginning with ActiveMQ 5.4, this script utilizes one of three different adapters to support ajax communication with the server. Current jQuery, Prototype, and Dojo are supported, and recent versions of all three libraries are shipped with ActiveMQ.
Sending a message
To receive messages, the client must define a message handling function and register it with the amq object. For example:
Be aware that, by default, messages published via Stomp which include a
By default, an ajax client will receive all messages on a topic or queue it is subscribed to. In ActiveMQ 5.4.1 amq.js supports JMS selectors since it is frequently useful to receive only a subset of these messages. Selectors are supplied to an
Using AMQ Ajax in Multiple Browser Windows
All windows or tabs in a single browser share the same
In this example, we use the current time (at the time the web page is loaded) as a unique identifier. This is effective as long as two browser windows are not opened within the same millisecond, and is the approach used by the example chat.html included with ActiveMQ. Other schemes to ensure the uniqueness of
Note that this
How it works
AjaxServlet and MessageListenerServlet
The ajax featues of amq are handled on the server side by the AjaxServlet which extends the MessageListenerServlet. This servlet is responsible for tracking the existing clients (using a HttpSesssion) and lazily creating the AMQ and javax.jms objects required by the client to send and receive messages (eg. Destination, MessageConsumer, MessageAVailableListener). This servlet should be mapped to
Client Sending messages
When a message is sent from the client it is encoded as the content of a POST request, using the API of one of the supported connection adapters (jQuery, Prototype, or Dojo) for XmlHttpRequest. The amq object may combine several sendMessage calls into a single POST if it can do so without adding additional delays (see polling below).
When the MessageListenerServlet receives a POST, the messages are decoded as
Listening for messages
When a client registers a listener, a message subscription request is sent from the client to the server in a POST in the same way as a message, but with a type of
Waiting Poll for messages
When a Listener created by the MessageListenerServlet is called to indicate that a message is available, due to the limitations of the HTTP client-server model, it is not possible to send that message directly to the ajax client. Instead the client must perform a special type of Poll for messages. Polling normally means periodically making a request to see if there are messages available and there is a trade off: either the poll frequency is high and excessive load is generated when the system is idle; or the frequency is low and the latency for detecting new messages is high.
To avoid the load vs latency tradeoff, AMQ uses a waiting poll mechanism. As soon as the amq.js script is loaded, the client begins polling the server for available messages. A poll request can be sent as a GET request or as a POST if there are other messages ready to be delivered from the client to the server. When the MessageListenerServlet receives a poll it:
When the amq.js javascipt receives the response to the poll, it processes all the messages by passing them to the registered handler functions. Once it has processed all the messages, it immediately sends another poll to the server.
Thus the idle state of the amq ajax feature is a poll request "parked" in the server, waiting for messages to be sent to the client. Periodically this "parked" request is refreshed by a timeout that prevents any TCP/IP, proxy or browser timeout closing the connection. The server is thus able to asynchronously send a message to the client by waking up the "parked" request and allowing the response to be sent.
The client is able to asynchronously send a message to the server by creating (or using an existing) second connection to the server. However, during the processing of the poll response, normal client message sending is suspended, so that all messages to be sent are queued and sent as a single POST with the poll that will be sent (with no delay) at the end of the processing. This ensures that only two connections are required between client and server (the normal for most browsers).
The waiting poll described above is implemented using the Jetty 6 Continuations mechanism. This allows the thread associated with the request to be released during the wait, so that the container does not need to have a thread per client (which may be a large number). If another servlet container is used, the Continuation mechanism falls back to use a wait and the thread is not released.
Comparison to Pushlets
Firstly we could easily add support for pushlets to ActiveMQ. However we prefer the Ajax approach for various reasons