Usando ActiveMQ através de Ajax e REST

ActiveMQ é um broker de messageria que implementa a especificação java para messageria a JMS 1.1. Apesar de velinha a API é muito simples e extremamente importante, por que ajuda muito a desenvolver alplicações de alta disponibilidade e que podem escalar.

Você pode usar o ActiveMQ sozinho em modo standalone ou até mesmo embarcado na sua aplicação, também é possivel utilizar através do seu container jee como o JBoss por exemplo através do uso de um resource adapter.

Neste post vou mostrar como consumir e produzir mensagem JMS sem ter que usar a API JMS de forma direta, isso é possivel e pode ser feito de diversas maneira no ActiveMQ. Vamos ver neste post como fazer isso usando Javascript e Ajax e depois usando REST.

Por que Acessar o ActiveMQ com Ajax/JS e REST ?

Desta forma aplicações Web de diversas linguagens como por exemplo CGI, Pearl, ASP podem tirar proveito do uso de messageria, esta é uma forma bem fácil de realizar integração de sistemas já que utiliza padrões conhecidos como Javascript, XML e o protocolo HTTP.

Ambientes corporativos podem tirar muito proveito destas funcionalidades, já que é comun ter aplicações web escritas nas mais diversas linguagens. Outro aspecto importante é que esta integração possibilita efetuar um processamento em tempo de runtime realtime e ao mesmo tempo todas as mesagems podem ser persistidas e você pode consumi-las em Java por exemplo, sem perder escalabilidade.



Mas não é perigoso em termos de segurança fazer isso?

Não é por que as configurações de transporte, localização do broker ficam do lado do servidor. Para que seja possível voce utilizar estes recursos é necessária uma aplicação Web(war) no lado do servidor e nesta aplicação(no web.xml) que ficam as configurações.

Logo não há como um cliente descobrir o endereço real do broker, você ainda poderia criar um usuário e senha especial no ActiveMQ com acesso a alguns recursos apenas. O cliente especifica o nome das filas e dos topicos no hora de enviar e receber as mensagems mas tudo isso pode ser controlado do lado do servidor.

Configurando o web.xml para suporte a Ajax e REST

Vamos começar vendo as configurações que devem ser feitas no lado do server. Então confira o arquivo web.xml a baixo.

<br><?xml version="1.0" encoding="UTF-8"?><br><br><web-app id="WebApp_activemq_ajax_rest" version="2.4"<br>    xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br>    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee <br>                        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"<br>><br>    <servlet><br>        <servlet-name>AjaxServlet</servlet-name><br>        <servlet-class>org.apache.activemq.web.AjaxServlet</servlet-class><br>        <load-on-startup>1</load-on-startup><br>    </servlet><br>    <br>    <servlet><br>        <servlet-name>MessageServlet</servlet-name>       <br>        <servlet-class>org.apache.activemq.web.MessageServlet</servlet-class><br>        <load-on-startup>1</load-on-startup><br>        <init-param><br>                <param-name>destinationOptions</param-name><br>                <param-value>consumer.prefetchSize=1</param-value><br>        </init-param><br>    </servlet>    <br>    <br>    <context-param><br>        <param-name>org.apache.activemq.brokerURL</param-name><br>        <param-value>tcp://127.0.0.1:61616</param-value><br>    </context-param><br>    <br>    <servlet-mapping><br>        <servlet-name>AjaxServlet</servlet-name><br>        <url-pattern>/amq/*</url-pattern>        <br>    </servlet-mapping><br>    <servlet-mapping><br>        <servlet-name>MessageServlet</servlet-name><br>        <url-pattern>/message/*</url-pattern><br>    </servlet-mapping><br>    <br>    <br>    <filter><br>      <filter-name>session</filter-name><br>      <filter-class>org.apache.activemq.web.SessionFilter</filter-class><br>    </filter>    <br>    <filter-mapping><br>      <filter-name>session</filter-name><br>      <url-pattern>/*</url-pattern><br>    </filter-mapping><br></web-app><br>

Perceba que existe o context param chamado org.apache.activemq.brokerURL, aqui você indica a configuração default de transporte através de um URL que indica como conectar no broker. Estou usando o ActiveMQ standalone, basta voce baixar da internet e subir o broker, estou usando url, transporte e porta padrão.

Depois existem 2 servlets que estão sendo registrados, são eles: AjaxServlet e MessageServlet. O primeiro serve para você poder acessar o ActiveMQ usando Ajax/Javascript e o segundo é para integração com REST. Os dois tem os seus mapeamentos configurados no XML.

Enviando uma mensagem com Ajax

Para isso precisamos importar os arquivos javascript do ActiveMQ, você vai precisar dos arquivos a baixo:
Confira página jsp a baixo mas especificamente as funções javascript que fiz para enviar e receber mensagens usando a api js do ActiveMQ.

<br><script type="text/javascript" src="javascript/amq.js"></script><br><script type="text/javascript">amq.uri='/activemq-web-ajax-rest-1.0-SNAPSHOT/amq';</script><br><script type="text/javascript"></p><p>    function sendActiveMQQueueMessage(msg){<br>        try{<br>            var xmlMessage = "<message><text>" + msg + "</text></message>";<br>            amq.sendMessage("channel://js_ajax_queue",xmlMessage);<br>            document.getElementById("divResposnse").innerHTML =  "ActiveMQ Ajax Client: message[" + msg + "] sent to *js_ajax_queue* ";    <br>        }catch(e){<br>            document.getElementById("divResposnse").innerHTML = "Error sending message to ActiveMQ. Error: " + e;    <br>        }<br>    }            <br></script><br>

O parametro amq.uri indica o caminho completo para o seu servlet ajax, sendo que o que vem primeiro é o context root da sua aplicação, na maioria das vezes vai ser o proprio nome do seu war. Esta função javascript só recebe a mensagem por que dentro da função estou definindo qual a fila que quero mandar a mensagem isto é feito com isso: channel://js_ajax_queue, sendo que você poderia dizer topic://nome_topico. Usei channel por que quero que a mensagem vá para um fila.

Agora confira a baixo como receber mensagem com ajax. Isso é feito no mesmo *estilo* de um message listener como você faria em java ou dentro de um MDB. Então confira o código javacript a baixo.

<br><script type="text/javascript" src="javascript/amq.js"></script><br><script type="text/javascript">amq.uri='/activemq-web-ajax-rest-1.0-SNAPSHOT/amq';</script><br><script type="text/javascript"><br><br>    var messageHandler =<br>    {<br>      rcvMessage: function(message)<br>      {<br>        document.getElementById("divResposnseHandle").innerHTML = "Message arrived: <b>" + message.textContent + "</b>";<br>      }<br>    };    <br>    amq.addListener("msghID","channel://js_ajax_queue",messageHandler.rcvMessage);    </p><p></script><br>

Este método é um estilo call back, quando a mensagem chegar a função js chamada rcvMessage sera invocada, por padrão tem um timeout de 10s para que isso ocorre, do contrario na próxima vez que o script rodar ele tenta de novo, você pode fazer um poll forçado se quizer usando por exemplo: amq._startPolling()

Enviando mensagem com REST

Basicamente vamos usar o objeto XMLHttpRequest para realizar esta tarefa. Quando acessamos o mesmo URL mas com metodos diferentes(HTTP) estaremos efetuando operações diferentes. Em resumo POST para mandar mensagems e GET para receber.

O URL é montando assim: http://localhost:8070/activemq-web-ajax-rest-1.0-SNAPSHOT/message/FilaX?type=queue&body=MinhaMSG

Primeiro em azul é o endereço do servidor e porta. Depois em verde é o context root da aplicação web que esta expondo o ActiveMQ, vermlho é o mapeamento do servlet REST, FilaX em laranja é o nome da destination que pode ser uma fila ou topico, neste caso é um fila por que em azul esta escrito type = queue. Por fim em roxo/rosa o parametro body recebe a mensagem a ser enviada.

Então agora que você entendeu o padrão de URL vamos ver o código javascript para enviar mensagem usando REST.

<br><script language="Javascript"><br><br>    function sendRESTMessage(queueName,message) {<br>        try{<br>            var xmlHttpReq = false;<br>            var self = this;<br><br>            if (window.XMLHttpRequest) {<br>                self.xmlHttpReq = new XMLHttpRequest();<br>            }<br>            else if (window.ActiveXObject) {<br>                self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");<br>            }<br>    <br>            var xmlMessage = "<xml><message>" + message + "</message></xml>";<br>            var httpURL    = "message/" + queueName + "?type=queue&body=" + xmlMessage;<br>            <br>            self.xmlHttpReq.open('POST', httpURL, true);<br>            self.xmlHttpReq.setRequestHeader("Content-Type", "text/xml")<br>                    <br>            self.xmlHttpReq.onreadystatechange = function() {<br>                if(self.xmlHttpReq.readyState==4){<br>                   alert("Ajax call back " + self.xmlHttpReq.responseText );<br>                }<br>            }<br>            self.xmlHttpReq.send(null);<br>            alert("Message: " + message + " sent to queue: " + queueName);<br>            <br>        }catch(e){<br>            alert("Error: " + e);<br>        }    <br>    }<br>


Na função js que criei chamada sendRESTMessage recebe o nome da fila e a mensagem. Para chamar a função e mandar a mensagem seria algo do tipo: sendRESTMessage('rest_queue',txtMessage.value);

Para receber mensagens é bem parecido, só que usamos GET ao invés de POST, uma função js de call back é usada para receber as mensagens, confira o código a baixo.

<br><script language="Javascript"></p><p>    function receiveRESTMessage(queueName) {<br>        try{<br>            var xmlHttpReq = false;<br>            var self = this;<br><br>            if (window.XMLHttpRequest) {<br>                self.xmlHttpReq = new XMLHttpRequest();<br>            }<br>            else if (window.ActiveXObject) {<br>                self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");<br>            }<br>    <br>            var httpURL    = "message/" + queueName + "?type=queue";<br>            <br>            self.xmlHttpReq.open('GET', httpURL, true);<br>            self.xmlHttpReq.setRequestHeader("Content-Type", "text/xml")<br>                    <br>            self.xmlHttpReq.onreadystatechange = function() {<br>                if(self.xmlHttpReq.readyState==4){<br>                   alert("Message Arrived: " + self.xmlHttpReq.responseText );<br>                }<br>            }<br>            self.xmlHttpReq.send(null);<br>    <br>        }catch(e){<br>            alert("Error: " + e);<br>        }    <br>    }<br>    <br></script><br>

A função receiveRESTMessage recebe o nome da fila que você quer pegar mensagens e quando a mensagem chega um alert com o conteudo aparece na tela, você pode infocar a função se quizer fazer um poll.

No servidor você vai precisar de algumas dependencias para que os servlets de ajax e rest funcione, confira as dependencias do maven a baixo.

<br><dependencies><br>        <dependency><br>            <groupId>org.apache.activemq</groupId><br>            <artifactId>activemq-core</artifactId><br>            <version>5.3.1</version><br>        </dependency><br>        <dependency><br>            <groupId>org.apache.activemq</groupId><br>            <artifactId>activemq-web</artifactId><br>            <version>5.3.1</version><br>        </dependency><br>        <dependency><br>            <groupId>commons-logging</groupId><br>            <artifactId>commons-logging</artifactId><br>            <version>1.1.1</version><br>        </dependency><br>        <dependency><br>            <groupId>log4j</groupId><br>            <artifactId>log4j</artifactId><br>            <version>1.2.15</version><br>        </dependency><br>    </dependencies><br>

Se você quizer o fonte completo pode baixar do meu repositório do subversion neste url aqui.

Abraços e até a próxima.

Popular posts from this blog

Telemetry and Microservices part2

Installing and Running ntop 2 on Amazon Linux OS

Fun with Apache Kafka