воскресенье, 10 февраля 2013 г.

Ajax and ActiveMQ

Sometimes you need to notify users (browsers) about some events occurred on the server side. For example someone has added the row into the table and you need to be notified about it.
Also the client could be not just the browser but any program component. And this components can be dynamically connected and disconnected.
The solution could be the message queue and publish subscribe pattern.
 After some research I managed to work the solution based of ActiveMQ 5.7.0 and Apache Tomcat 6.0.35. Here is how I did it.



What i used:

  1. Apache ActiveMQ 5.7.0
  2. java version "1.7.0_09"
    OpenJDK Runtime Environment (IcedTea7 2.3.4) (7u9-2.3.4-0ubuntu1.12.04.1)
    OpenJDK Server VM (build 23.2-b09, mixed mode)
  3. Apache Tomcat 6.0.35
  4. jQuery 1.8.3
  5. Eclipse juno.
Start the ActiveMQ  ./activemq start.

Create Dynamic Web application.

In lib folder place the following libraries:
  • activemq-camel-5.7.0.jar
  • activemq-core-5.7.0.jar
  • activemq-web-5.7.0.jar
  • camel-core-2.10.1.jar
  • geronimo-j2ee-management_1.1_spec-1.0.1.jar
  • geronimo-jms_1.1_spec-1.1.1.jar
  • jetty-all-server-7.6.7.v20120910.jar
  • log4j-1.2.17.jar
  • slf4j-api-1.6.6.jar
  • slf4j-log4j12-1.6.6.jar
In src folder create the file log4j.properties and place the following content in it:
# Root logger option
log4j.rootLogger=DEBUG, stdout
#log4j.logger.org.apache.activemq.web.MessageServletSupport=INFO, stdout

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

This will print all the information on the eclipse console.

Now the interesting part:
In web.xml place the following:
    <!-- context config -->
    <context-param>
        <param-name>org.apache.activemq.brokerURL</param-name>
        <param-value>tcp://localhost:61616</param-value>
    </context-param>
  <servlet>
<servlet-name>AjaxServlet</servlet-name>
<servlet-class>org.apache.activemq.web.AjaxServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
  <servlet-mapping>
<servlet-name>AjaxServlet</servlet-name>
<url-pattern>/amq/*</url-pattern>
</servlet-mapping>
   <filter>
        <filter-name>continuation</filter-name>
        <filter-class>org.eclipse.jetty.continuation.ContinuationFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>continuation</filter-name>
        <url-pattern>/amq/*</url-pattern>
    </filter-mapping>

This means that we will connect to the ActiveMQ on localhost.
The connection to ActiveMQ is done with AjaxServlet. Also take a look at the ContinuationFilter. Without this AjaxServlet will not start on Tomcat 6. That's why  we need jetty in lib.

ActiveMQ provides AJAX support for jquery, dojo, prototype.
Create js folder in your project and add the following files:
amq_jquery_adapter.js
amq.js
jquery.js.

The first 2 js you can get from apache-activemq-5.7.0/webapps/demo/js folder.
Create an index.jsp with the following content:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Тестирование activemq ajax</title>
</head>
<body>
<script type="text/javascript" src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="js/amq_jquery_adapter.js"></script>
<script type="text/javascript" src="js/amq.js"></script>
<script type="text/javascript">
  var amq = org.activemq.Amq;
 
  $(document).ready(function(){
      amq.init({
            uri: 'amq',
            logging: true,
            timeout: 20
          }); 
      var myHandler =
      {
        rcvMessage: function(message)
        {
           alert("received "+message);
        },
        myId: 'test1',
        myDestination: 'topic://test1'
      };

     
      amq.addListener(myHandler.myId, myHandler.myDestination, myHandler.rcvMessage);
  });
</script>

</body>
</html>
It is worth to note that we subscribe here to topic 'topic://test1'. Also note that you can work only with text messages.
Run the index.jsp. Open the browser and enter URL: http://0.0.0.0:8161/admin/topics.jsp. Choose the 'test1' topic. Then enter the message and click send. In your index.jsp you will receive your message.

So, it's a good start to make your research further. For example, how to use WebSockets with ActiveMQ?

I should note that because you use AJAX you can't subscribe to many topics. Browser can send limited number of parallel requests to the same host. When you subscribe to the topic, your browser will poll the server for the events. These requests are blocked for the timeout you specify in amq.init. So, the total performance of your experience with site is slowdown, and this also wastes the server connections pool.

That's why you should look into the WebSocket solution.

Among other solutions you can look at IBM WebSphere MQ Bridge for HTTP or use Web messaging service (http://pic.dhe.ibm.com/infocenter/wasinfo/v8r0/topic/com.ibm.websphere.web2mobile.webmsg.help/docs/Overview.html).

Комментариев нет:

Отправить комментарий