12 de jul. de 2010

Weblogic, um Message Driven Bean Simples

Escrevi em outras oportunidades sobre criação de filas ou tópicos JMS no Weblogic e de como este recurso é importante em um ambiente distribuído e corporativo. Para ilustrar vou postar aqui um exemplo simples de um MDB que consome de um tópico JMS simples. Não vou comentar sobre os elementos do MDB detalhadamente, vou focar na implementação. Para ilustrar vou utilizar para o exemplo uma página JSF que posta uma mensagem em um tópico e um MDB com annotations para consumir a mensagem.

Primeiro, para o exemplo funcionar deve-se criar no weblogic um topico simples com as seguintes configurações:

Nome: Exemplo MDB
Nome JNDI: jms.distributed.Topic

Se quiser ver detalhadamente como criar este tópico, fiz um tópico sobre esse assunto no link: http://mmaiacupofcoffee.blogspot.com/2010/02/weblogic-jms-parte-iii-criacao-de-fila.html. Bastando adaptar e criar um tópico(Topic) ao invés de uma fila(Queue).



Os trechos de código relevantes para o exemplo explico à seguir. A parte JSF do exemplo deve ser "empacotada" em um .war e o ejb em um .jar, conforme definido pela especificação.

O cliente de exemplo que publica no tópico é escrito com JSF, composto por uma página e uma Action.
Abaixo posto detalhes relevantes da página que publica a mensagem e define-se quantas vezes será postada. O ActionBean é registrado com o nome mensagemBean no deployment descriptor. O exemplo usa notação JSF simples e por isso não vou detalhar aqui:


    Texto da Mensagem:
Quantidade:


A segunda parte do cliente que publica a mensagem é o ActionBean que recebe os parâmetros dos campos da página e efetivamente posta a mensagem no tópico utilizando JMS. Perceba que um loop é criado para postar várias mensagens se desejado. Para o exemplo ficar mais claro não estou utilizando anottations para fazer injection de dependência de contexto.
package exemplo.action;

import java.util.logging.Logger;

import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class PublicaTopicoAction {
 
 private Logger log = Logger.getLogger(PublicaTopicoAction.class.getName());

 private String mensagem;
 private int quantidadeMensagens;
 
 protected Context ctx;
 protected TopicPublisher tpublisher;
 protected Topic topic;
 protected TextMessage msg;
 protected TopicConnection tcon;
 protected TopicSession tsession;
 
 public final static String JMS_FACTORY = "weblogic.jms.ConnectionFactory";
 
 public final static String TOPIC = "jms.distributed.Topic";

 protected TopicConnectionFactory tconFactory;
 
 public PublicaTopicoAction()
 {
  log.info("Construtor PublicaTopicoAction");
  try {
   ctx = new InitialContext();
   tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY);
   tcon = tconFactory.createTopicConnection();
   tsession = tcon.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
   topic = (Topic) ctx.lookup(TOPIC);
   tpublisher = tsession.createPublisher(topic);
   tcon.start();
  } catch (NamingException e) {
   log.severe("Erro ao recuperar o contexto para fazer lookup");
   e.printStackTrace();
  } catch (JMSException e) {
   log.severe("Ocorreu um erro ao conectar no topico: " + e.getMessage());
   e.printStackTrace();
  }
 }
 
 public String enviaMensagem()
 {
  log.info("Entrou PublicaTopicoAction.publicaMensagem");
  for (int i = 0; i < quantidadeMensagens; i++) {
   publicaMensagemTopic(mensagem + "_" + i); 
  }
  log.info("Executou PublicaTopicoAction.publicaMensagem");
  return "OK";
 }
 
 private void publicaMensagemTopic(String mensagem) {
  try {
   log.info("Entrou PublicaTopicoAction.publicaMensagemTopic");
   msg = tsession.createTextMessage();
   msg.setText(mensagem);
      tpublisher.publish(msg);
   log.info("Executou PublicaTopicoAction.publicaMensagemTopic");
  } catch (Exception e) {
   log.severe("Ocorreu um erro ao postar mensagem na fila");
   e.printStackTrace();
  }
 }
 
 public String getMensagem() {
  return mensagem;
 }

 public void setMensagem(String mensagem) {
  this.mensagem = mensagem;
 }

 public int getQuantidadeMensagens() {
  return quantidadeMensagens;
 }

 public void setQuantidadeMensagens(int quantidadeMensagens) {
  this.quantidadeMensagens = quantidadeMensagens;
 }
 
}


Finalmente o código do Message Driven Bean que é bem simples e assim que uma mensagem chega no tópico ele consome a mesma executando o método onMessage, conforme definido pela especificação. Perceba que o link com o Tópico é feito através de anottations no MDB e que para exemplos simples como este não é necessário a criação de arquivos xml de configuração, o deployment descriptor para EJBs é opcional na versão de EJB 3.0 ou posteriores.

package exemplo.mdb;

import java.util.logging.Logger;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic") }, mappedName = "jms.distributed.Topic")
public class TopicConsumerMDB implements MessageListener {

 Logger log = Logger.getLogger(TopicConsumerMDB.class.getName());

 public TopicConsumerMDB() {
  log.info("Construtor TopicConsumerMDB");
 }

 /**
  * @see MessageListener#onMessage(Message)
  */
 public void onMessage(Message message) {
  log.info("Entrou onMessage");
  try {
   TextMessage textMessage = (TextMessage) message;
   String messageID = textMessage.getJMSMessageID();
   log.info("ID da mensagem recuperada ==>> " + messageID);
   String mensagem = textMessage.getText();
   log.info("Mensagem recebida ==>> " + mensagem);
  } catch (JMSException e) {
   log.severe("Ocorreu um erro ao recuperar informacoes da mensagem ==>> "
       + e.getMessage());
   e.printStackTrace();
  }
  log.info("Executou onMessage");
 }
}


[]s