IntroductionActiveMQ supports Ajax Ajax allows a regular DHTML client (with JavaScript and a modern version 5 or later web browser) to send and receive messages over the web. Ajax support in ActiveMQ builds on the same basis as the REST connector for ActiveMQ which allows any web capable device to send or receive messages over JMS. To see Ajax in action, try running the examples The ServletThe AMQ AjaxServlet needs to be installed in your webapplications to support JMS over Ajax: ...
<servlet>
<servlet-name>AjaxServlet</servlet-name>
<servlet-class>org.apache.activemq.web.AjaxServlet</servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>AjaxServlet</servlet-name>
<url-pattern>/amq/*</url-pattern>
</servlet-mapping>
The servlet both the serves required js files and handles the JMS requests and responses. Javascript APIThe ajax featues of amq are provided on the client side by the _amq.js <script type="text/javascript" src="amq/amq.js"></script> <script type="text/javascript">amq.uri='/mycontext/amq';</script> Including these scripts results in the creation of a javascript object called amq, which provides the API to send messages and to subscribe to channels and topics. Sending a message.All that is required to send a JMS message from the javascript client, is to call the method: amq.sendMessage(myDestination,myMessage); where myDestination is the URL string address of the destination (e.g. "topic://MY.NAME" or "channel://MY.NAME") and myMessage is any well formed XML or plain text encoded as XML content. Receiving messages.To receive messages, the client must define a message handling function and register it with the amq var myHandler = { rcvMessage: function(message) { alert("received "+message); } }; amq.addListener(myId,myDestination,myHandler.rcvMessage); where myId is a string identifier that can be used for a later call to amq.removeHandler(myId) and myDestination is a URL string address of the destination (e.g. "topic://MY.NAME" or "channel://MY.NAME"). When a message is received, a call back to the myHandler.rcvMessage function passes the message to your handling code. How it worksAjaxServlet and MessageListenerServletThe ajax featues of amq are handled on the server side by the AjaxServlet Client Sending messagesWhen a message is sent from the client it is encoded as the content of a POST request, using the prototype When the MessageListenerServlet receives a POST, the messages are decoded as application/x-www-form-urlencoded parameters with their type (in this case send as opposed to listen or unlisten see below) and destination. If a destination channel or topic do not exist, it is created. The message is sent to the destination as a TextMessage. Listening for messagesWhen 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 listen. When the MessageListenerServlet receives a listen message, it lazily creates a MessageAvailableConsumer and registers a Listener on it. Waiting Poll for messagesWhen 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). Threadless WaitingThe waiting poll described above is implemented using the Jetty 6 Continuations Comparison to PushletsFirstly we could easily add support for pushlets to ActiveMQ. However we prefer the Ajax approach for various reasons
|