Vous êtes sur la page 1sur 26

Enterprise JavaBeans 3.

0
Parte 4: Message Driven Bean
<

Rafael Por: Rafael Zancan Frantz >

ATENO: Este material contm algumas imagens retirardas da docomentao oficial da SUN e adaptadas para este material. As mesmas podem ser encontradas no site www.sun.com . O objetivo deste material recompilar uma srie de informaes existentes que possam ser utilizadas para o estudo da tecnologia EJB 3.0 pelo leitor. No final se listam as bibliografias utilizadas e sugerimos que as mesmas sejam utilizadas para aprofundar os conhecimentos nesta tecnologia.

O que um Message Driven Bean


Antes da verso 2.0 da especificao EJB a maioria dos consumidores de mensagens JMS (Java Message Service) foram construdos como simples programas Java fora do container J2EE. Um programa Java era ativado e conectado a um destinatrio JMS e ficava esperando as mensagens. Embora a construo de consumidores de mensagens por meio de aplicaes Java era uma das melhores solues para o problema, esta soluo gerava vrios outros problemas, onde o maior a escalabilidade. Quando o nmero de mensagens na fila aumentava consideravelmente, haveria a necessidade de se executar um programa Java multi-threads para promover a escalabilidade da leitura destas mensagens e se este volume variasse muito, ficaria difcil fazer um algoritmo que na medida exata consumiria as mensagens sem perda de performance com muitas threads e sem perda destas mensagens no caso de poucas threads. Baseado nisto alguns vendedores de EJB pensaram nesta funcionalidade na verso 1.1. Porm a especificao no definia este tipo de bean o que fazia com que cada vendedor tivesse um padro. Basicamente, beans orientados a mensagens processam alguma lgica de negcios usando mensagens JMS enviadas para uma destinao particular, ou seja, consomem mensagens JMS atravs da tecnologia EJB. Atualmente a partir da verso 3.0 do EJB JMS pode fazer uso de anotaes assim como os outros tipos de EJBs para facilitar a sua escrita. Mesmo tendo sido incorporado a especificao de EJB nas verses passadas e no demandando a criao de interfaces home nem remotas ( o que os deixava mais simples de serem escritos) ainda era trabalhoso escrever um Message Driven Bean. Anotaes, como j comentado, a partir da verso 3.0 da especificao facilitam mais este processo. Os Message Driven Beans so completamente escondidos do cliente. O nico meio de clientes comunicarem com os beans orientados a mensagens enviando uma mensagem para um destinatrio JMS. Veja a figura abaixo:

Figura 4-1: Funcionamento do Bean orientado a mensagens com os clientes

Como podemos ver na figura acima, um cliente envia uma mensagem JMS para um destino e o container passa esta mensagem JMS para uma instncia do bean orientado a mensagens que tem se registrado como um receptor de mensagens para uma destinao particular. Por usar um pool de instncia de beans, o container capaz de manipular as mensagens que chegam de uma forma muito mais eficiente e aumenta a escalabilidade das operaes JMS. As instncias dos beans podem ser colocadas ou retiradas do pool dependendo das necessidades do container de atender as requisies. Os beans orientados a mensagens no possuem estado conversacional e portanto, so similares neste aspecto aos beans de sesso stateless. Isto no significa que estes beans no podem ter variveis de instncia, somente significa que as variveis de instncia que os beans possurem no podem ser usadas para guardar informaes de estado de um cliente particular porque no garantido que um mesmo bean atenda um mesmo cliente. Isto at certo ponto obvio porque o cliente no acessa diretamente um bean orientado a mensagens. Um exemplo interessante seria quando definimos uma pea de teatro como sendo o bean de sesso, os atores o bean de entidade, e poderamos definir os beans orientados a mensagens como aqueles scripts que ficam invisveis ao pblico, no havendo iterao direta. Apagar e acender as luzes quando o ator principal chega (pela primeira vez), seria anlogo a quando chegar uma mensagem ao destino JMS, o qual processa a mesma. Por assegurar que todas as instncias dos beans orientados a mensagens so idnticas, o container capaz de manipular um pequeno nmero de instncias no pool e ainda manipular uma grande carga de chamadas. Isto porque qualquer instncia livre pode ser usada para manipular qualquer requisio que chegar vindo de uma destinao especfica. A partir da criao do bean orientado a mensagens at a sua destruio, o container gerencia estes beans exclusivamente. Todos os servios oferecidos para os outros dois beans (sesso e entidade), tais como segurana, suporte a transao e concorrncia so, exceto as interfaces home e remote, providos. O container interage com os beans orientados a mensagens atravs de um conjunto de mtodos de callback que so implementados pelo bean orientado a mensagens. Estes mtodos so similares aos usados pelos beans de sesso e os beans de entidade. Estes mtodos avisam ao bean que determinados eventos ocorrem ou ocorreram. Um Message Driven Bean (MDB) , portanto, um EJB que permite que as aplicaes J2EE processem mensagens de modo assncrono. Age como um listener de mensagens Java Message Service (JMS), o qual similar a um ouvinte de eventos, a no ser pelo fato de que, ao invs de receber eventos, ele recebe mensagens. As mensagens podem ser emitidas por qualquer componente de J2EE - um cliente da aplicao, um outro EJB, ou um componente WEB -- ou por uma aplicao/sistema JMS que no usem a tecnologia J2EE. Os MDBs atualmente processam somente mensagens de JMS, mas no futuro podem ser usados para processar outros tipos de mensagens.

Diferena entre MDB, Session e Entity Bean


A diferena mais visvel entre EJBs MDB e outros EJBs que os clientes no acessam os MDBs atravs das interfaces. Ao contrrio de um EJB session ou entity, um MDB tem somente a classe bean. Em diversos aspectos, um MDB assemelha-se a um EJB Session Stateless 1. As instncias de um MDB no retm nenhum dado ou estado de conversao com um cliente especfico. 2. Todas as instncias de um MDB so equivalente, permitindo que o container EJB atribua uma mensagem a toda instncia de um MDB. O recipiente pode realizar um pool destes objetos para permitir que os fluxos das mensagens sejam processados simultaneamente. 3. Um nico MDB pode processar mensagens de mltiplos clientes. As variveis de instncia do MDB podem manter o estado atravs da manipulao de mensagens do cliente por exemplo, uma conexo JMS, uma conexo com a base de dados, ou uma referncia a um objeto EJB. Quando uma mensagem chega, o container chama o mtodo onMessage() do MDB para processar a mensagem. O mtodo onMessage() realiza normalmente um cast da mensagem para um dos cinco tipos de mensagem JMS e manipula a mensagem de acordo com a lgica do negcio da aplicao. O mtodo onMessage() pode chamar mtodos auxiliares (Helpers), ou pode invocar um Session Bean (muito recomendado nesse caso) ou um Entity Bean para processar a informao contida na mensagem ou para armazen-la em uma base de dados. Uma mensagem pode ser entregue a um MDB dentro de um contexto da transao, de modo que todas as operaes dentro do mtodo onMessage() sejam parte de uma nica transao. Se ao processar a mensagem for executado um roolback, a mensagem ir ser novamente enviada.

Escrevendo um MDB
Aqui vamos escrever um Message Driven Bean, porm antes em poucas linhas vamos entender alguns conceitos importantes para este estudo. Aplicaes que utilizam JMS so chamadas de JMS Clients, e o sistema de mensagens Clients que realiza o roteamento e entrega de mensagens chamado de JMS Provider Uma JMS Provider. Application um sistema composto por muitos JMS Clients e, geralmente, um JMS Provider. Um JMS Client que manda mensagens chamado de producer e um JMS Client que recebe producer, uma mensagem chamado de consumer. Um JMS Client pode ser ao mesmo tempo um consumer. producer e um consumer! Vamos agora ver um exemplo de Message Driven Bean:
package com.ejb.mdb; import javax.ejb.MessageDriven; import javax.jms.Message; import javax.jms.MessageListener; @MessageDriven public class ExemploMDB implements MessageListener { public void onMessage(Message message) { ... } } Cdigo 4-1: MDB simples

Observe acima que um MDB definido atravs do uso de anotaes. Nesta caso utilizada a anotao @javax.ejb.MessageDriven para anotar a classe com um MDB. Todo MDB implementa a interface javax.jms.MessageListener o que obrigar o desenvolvedor a implementar o mtodo onMessage() para tratar o recebimento de mensagens de um client producer. O cdigo a ser executado quando o MDB receber uma mensagem posto no mtodo onMessage(). Um EJB pode ser um consumidor de mensagens assncronas como o mostrado no exemplo acima ou pode ser um produtor de mensagens para que clientes JMS as recebam. Mais adiante mostraremos como fazer isto. Todo MDB deve estar escutando uma fila de mensagens (Queue ou estar inscrito Queue) para receber mensagens de um Topic opic.

Topic
Topic um modelo de mensagens JMS baseado na filosofia publish-and-subscribe. Este modelo tambm conhecido com um para muitos. Aqui uma mensagem JMS ser enviada para um Topic do container EJB e este ir imediatamente realizar um envio de uma cpia desta mensagem para todos aqueles clientes que estiverem inscritos para receber mensagens daquele tpico. Funciona semelhante a um broadcast de mensagens. Veja a figura abaixo:

Figura 4-2: Tpico MDB para EJB

Observe na figura acima que todos os MDBs que estiverem inscritos para receber mensagens do tpico iro receber. Abaixo um cdigo que cria um MDB para receber mensagens de um tpico:

Queue
Este modelo JMS baseado em fila (queue) permitir um cliente enviar mensagens para a fila de forma que outros possam consumir as mensagens da fila. Uma diferena importante com relao ao modelo topic que a mensagem de uma fila ser consumida apenas por um cliente e no distribuda para todos os inscritos como acontece com um topic. Abaixo veja como fica o modelo de um queue:

Figura 4-3: Queue MDB para EJB

Observe que somente um MDB ir consumir a mensagem. Todas as mensagens enviadas por clientes ficam na Fila aguardando algum que as consuma. A deciso de qual modelo utilizar na sua aplicao ir depender em cada caso do que precisa ser representado com JMS. O modelo de Queue garante que somente um cliente ir processar a mensagem recebida. muitas vezes conhecido portanto com pier-to-pier (P2P).

JMS Client Producer


Um client epode gerar uma mensagem e enviar esta mensagem para um topic ou queue. Veja abaixo o cdigo onde um cliente standalone produz uma mensagem de texto e a envia para um topic do container EJB. As mensagens pode ser de outro tipo e no somente textuais. Podem ser mensagens contendo objetos java (java.lang.Object).
public class JMSTopicSendClient { public static void main(String[] args) {

try { InitialContext ctx = getInitialContext(); Topic topic = (Topic) ctx.lookup("topic/testTopic"); // Enviar mensagem para um TOPIC TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory"); TopicConnection connection = factory.createTopicConnection(); TopicSession session = connection.createTopicSession( false, QueueSession.AUTO_ACKNOWLEDGE);

MessageProducer producer = session.createProducer(topic); TextMessage textMsg = session.createTextMessage(); textMsg.setText("Ol clientes do topic! "); producer.send(textMsg); connection.start(); connection.close(); System.out.println("Mensagem enviada para topic: "+topic.getTopicName()+ " pelo client!");

} catch (Exception ex) { ex.printStackTrace(); } }

} Cdigo 4-2: Cliente JMS para Topic

Observe que o programa acima envia uma mensagem para um tpico de nome topic/testTopic do container EJB. Para realizar este envio so necessrios alguns objetos os quais so apresentados abaixo:

javax.jms.MessageProducer
Interface utilizada para representar um objeto com o qual possvel enviar mensagens para um determinado tpico. Observe que ao criar o MessageProducer passado o tpico correspondente.

javax.jms.TopicSession
Interface utilizada para representar a sesso do cliente com o tpico no container EJB. Esta sesso semelhante as sesses web que estamos acostumados.

javax.jms.TextMessage
Mensagem textual criada atravs de um objeto session e que pode ser populada com strings para ser enviada pelo MessageProducer para o topic.

javax.jms.Topic
Representa o topico retornado pelo lookup no JNDI ENC.

javax.jms.TopicConnection
Conexo com o topic do container. Esta conexo utilizada para criar a sesso com o tpico.

javax.jms.TopicConnectionFactory
Fbrica de tpicos utilizada para criar TopicConnection. Esta fabrica de tpicos retornado atravs de um lookup no JNDI ENC do container.

@MessageDriven e @ActivationConfigProperty
Ao definir um Message Driven Bean com a anotao @MessageDrivern necessrio fornecer mais algumas informaes sobre este bean. O bean que esta sendo definido precisa saber se ser um listener de um Topic ou Queue. Isto feito atravs da anotao @ActivationConfigProperty. Abaixo um cdigo que mostra como isto pode ser feito.

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

@MessageDriven( activationConfig = {@ActivationConfigProperty(propertyName="acknowledgeMode", propertyValue="Auto-acknowledge"), @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Topic"), @ActivationConfigProperty(propertyName="destination", propertyValue="topic/testTopic"), @ActivationConfigProperty(propertyName= connectionFactoryJndiName", propertyValue="TopicConnectionFactory") } ) public class MDBTopicSample implements MessageListener {

public void onMessage(Message message) { try { System.out.println("Message Driven Bean-Topic-[ onMessage() ] ..."); TextMessage textMsg = (TextMessage)message; System.out.println("Message: "+ textMsg.getText() ); } catch (JMSException ex) { System.out.println("Erro ao pegar a mensagem: "+ex.getMessage() ); } } } Cdigo 4-3: EJB MDB tratando mensagens

Observe acima que o atributo activationConfig() de @MessageDriven recebe um array de anotaes @ActivationConfigProperty. Estas anotaes so um par de nome/valor que descrevem a configurao do MDB. Acknowledge Acknowledge mode utilizado pelos clientes que recebem a mensagem para comunicar o JMS provider de que a mensagem foi recebida e processada. Caso no seja comunicado o provider isto poder fazer com que o mesmo reenvie a mensagem fazendo assim com que o cliente receba duas ou mais vezes a mesma mensagem. Acknowledge mode aceita dois possveis valores: Auto-acknowledge e Dups-ok-acknowledge. AutoAuto-

acknowledge ir fazer com que o cliente mande o aviso de recebimento da mensagem para o provider logo aps o MDB ter recebido a mensagem para processar. Dups-ok-acknowledge Dups-okfar com que o container no precise mandar o aviso de recebimento imediantamente aps receber a mensagem. O aviso poder ser enviado a qualquer momento aps ter dado ao MDB a mensagem. Isto pode faze com que o provider assuma que a mensagem no foi recebida e a envie novamente. O uso de Dups-ok-acknowledge faz com que a rede seja poupada e tenha um menor trafego. Mas na prtica o consumo de rede to pequeno tornando o Dups-ok-acknowledge no muito utilizado. Destination type , como o prprio nome j sugere o tipo de JMS de destino. Neste caso podemos espeficicar se ser topic ou queue com os respectivos valores: javax.jms.Topic ou javax.jms.Queue. Destination representa o nome do topic ou queue registrado no container EJB. No exemplo acima utilizamos um topic j registrado no JBoss, o topic/testTopic. Connection Factory Jndi Name especifica o nome da fbrica que ser utilizada para a criao de topic ou queue. No exemplo acima utilizamos um connection factory para topic chamado TopicConnectionFactory. Outro @ActivationConfigProperty que pode ser utilizado em alguns casos o Subscription Durability Este atributo utilizado com topic e serve para dizer se as Subscription Durability. mensagens enviadas para o tpico sero durveis ou no. Em caso de serem durveis (Durable) se o EJB contatiner sofre alguma falha como por exemplo reiniciar ou desconectar do JMS provider, as mensagens enviadas para o provider no sero perdidas pois sero salvas pelo JMS provider at que o EJB container volte a fncionar. Quando o container voltar e reconectar ao provider ento as mensagens so enviadas para o container e este as envia para os MDBs. A outra possibilidade que temos no armazenar as mensagens como mensagens durveis (NonDurable). Isto deixa levemetne mais rpido o JMS provider, mas diminui a sua confiabilidade. Veja abaixo como definir este atributo.
@MessageDriven( activationConfig = { @ActivationConfigProperty( propertyName="subscriptionDurability", propertyValue="Durable" ) } ) public class MDBTopicSample implements MessageListener { ... } Cdigo 4-4: Configurando um MDB com anotaes

EJB como JMS producer


Um EJB Session tambm pode ser um produtor de mensagens para um topic. Neste caso o EJB ao executar deve criar uma sesso com o topic e enviar a ele uma mensagem. Nos exemplo que havamos mostrdo at ento era um cliente standalone que enviava mensagens para o topic e como inscritos para o topic tnhamos MDBs. Abaixo mostramos o cdigo de um EJB Session que envia uma mensagem para um topic.
@Stateless public class TopicProducerEJB implements TopicProducerRemote { @Resource(mappedName="TopicConnectionFactory") private TopicConnectionFactory connectionFactory; @Resource(mappedName="topic/testTopic") private Topic topic; public void logar(String nome) { try { // Enviar mensagem para um TOPIC TopicConnection connect = connectionFactory.createTopicConnection(); TopicSession session = connect.createTopicSession(true, 0 ); MessageProducer producer = session.createProducer(topic); TextMessage textMsg = session.createTextMessage(); textMsg.setText(nome+" logou no sistema!! "); producer.send(textMsg); connect.start(); connect.close(); System.out.println("Mensagem enviada para topic: "+topic.getTopicName() ); } catch (JMSException ex) { ex.printStackTrace(); } } } Cdigo 4-5: EJB podutor de mensagens

Observe no cdigo acima como um EJB pode receber atravs de anotaes uma referncia para o TopicConnectionFactory e para o Topic. Utilizando a anotao @javax.annotation.Resource, injetamos no EJB as referncias. O cdigo que temos dentro do MDB um mtodo definido nas interfaces deste EJB para que ao ser chamado remotamente possa produzir uma mensagem e enviar a mesma ao topic. Como invertemos os papis e criamos acima um EJB para produzir uma mensagem e enviar ao topic, vamos agora ver como podemos escrever um cliente que standalone que atravs de JMS possa consumir mensagens de um topic. Abaixo o cdigo que realiza esta tarefa:

public class JMSTopicClient implements MessageListener { public JMSTopicClient() { try { InitialContext ctx = getInitialContext(); Topic topic = (Topic)ctx.lookup("topic/testTopic"); TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory"); TopicConnection connect = factory.createTopicConnection(); TopicSession session = connect.createTopicSession( false, Session.AUTO_ACKNOWLEDGE ); MessageConsumer consumer = session.createConsumer( topic ); consumer.setMessageListener(this); connect.start(); } catch (Exception ex) { ex.printStackTrace(); } }

public void onMessage(Message message) { try { TextMessage textMsg = (TextMessage)message; String text = textMsg.getText(); System.out.println("Mensagem recebida: "+ text ); } catch (JMSException ex) { ex.printStackTrace(); } } } Cdigo 4-6: Cliente EJB MDB

A classe acima define um cliente que pode ser executado em outra JVM que no dentro de um EJB Container. Observe que esta classe implementa a interface MessageListener o que far com que na classe tenhamos mtodo onMessage(Message message) e ento quando uma mensagem chegar o mesmo ser executado. Observe que atravs da sesso criamos um MessageConsumer que um objeto para registrar um listener (assim como fazamos no curso de Java Avanado para as interfaces grficas) que tratar com o mtodo onMessage() o recebimento da mensagem. Lembre-se que podemos ter vrios clientes consumidores registrados/inscritos a um topic.

Queue Um client producer para um Queue


Agora veremos como possvel um cliente produzir uma mensagem e enviar para uma fila de um JMS provider. Veja o cdigo abaixo:
public class JMSQueueSendClient { public static void main(String[] args) {

try { InitialContext ctx = getInitialContext(); Queue queue = (Queue) ctx.lookup("queue/MyQueue"); QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory"); QueueConnection connection = factory.createQueueConnection(); QueueSession session = connection.createQueueSession( false, QueueSession.AUTO_ACKNOWLEDGE); TextMessage msg = session.createTextMessage(" Ol fila queue! "); QueueSender sender = session.createSender(queue); sender.send(msg); connection.close(); System.out.println("Mensagem enviada para queue: "+queue.getQueueName()+ " pelo client!"); } catch (Exception ex) { ex.printStackTrace(); } } } Cdigo 4-7: Cliente standalone para queue

Observe que no cdigo acima feito um lookup na queue/MyQueue para ter acesso a fila e poder enviar mensagens.

Ciclo de vida de um MDB


Os beans orientados a mensagens so normalmente criados quando o container inicializa. O descritor de configurao pode dar ao publicador ou o assembler do bean a habilidade para especificar quantos beans orientados a mensagens estaro disponveis na inicializao e tambm qual o mximo de beans que podem ser criados. funo do container garantir que as instncias do bean no pool estaro disponveis antes das mensagens JMS chegarem. O container primeiro chama um construtor com nenhum argumento para o bean, construtor default, logo em seguinda sero injetadas as anotaes. Aps isto o container chama o mtodo anotado com @javax.annotation.PostConstruct na instncia do bean recm criado. Neste ponto pode-se colocar cdigos de inicializao se seu bean necessita de determinados recursos para completar a lgica de negcios. Estes recursos poderiam ser uma sesso Java Mail ou uma conexo JDBC. O nome do mtodo no importante, uma vez que a anotao que dar o sentido do mtodo. A figura abaixo ilustra os estgios do ciclo de vida de um message-driven bean. O EJB container frequentemente cria um pool de instncias de message-driven beans. Para cada instncia, o EJB container instancia o bean e faz as seguintes tarefas: 1234Chama o mtodo construtor Injeta as anotaes se houverem Chama o mtodo anotado com @javax.annotation.PostConstruct Chama o mtodo onMessage()

Figura 4-4: Ciclo de vida para um Message-Driven Bean

Como um stateless session bean, um message-driven bean no nunca colocado no estado de passivo, e possui somente os estados mostradoa acima: no existente e pronto para receber mensagens.

@javax.annotation.PreDestroy.

No final do ciclo de vida, o container chama o mtodo anotado com A instncia do bean est ento pronta para ser coletada pelo garbage collector.

Abaixo mostramos um exemplo completo de um Message Driven Bean inscrito para um topic contendo os mtodos do ciclo de vida.
package com.ejb.mdb; import import import import import import javax.annotation.PostConstruct; javax.annotation.PreDestroy; javax.ejb.ActivationConfigProperty; javax.ejb.MessageDriven; javax.jms.Message; javax.jms.MessageListener;

@MessageDriven(mappedName = "jms/MDBCicloVida", activationConfig = { @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"), @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "topic/testTopic"), @ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue = "TopicConnectionFactory") } ) public class MDBCicloVida implements MessageListener { public MDBCicloVida() { } public void onMessage(Message message) { System.out.println("onMessage() do MDBCicloVida executado!"); } // Mtodos do ciclo de vida @PostConstruct public void initialize() { System.out.println("MDB criado! @PostConstruct executado! "); } @PreDestroy public void exit() { System.out.println("MDB ser destruido! @PreDestroy executado! "); } } Cdigo 4-8: EJB MDB com ciclo de vida

Quando utilizar um MDB?


Os Session Beans e os Entity Beans permitem que voc emita mensagens JMS e as receba de modo sncrono, mas no assncrono. Para evitar desperdiar recursos de servidor, voc pode preferir no usar um bloqueio de execuo sncrono em um componente no servidor. Para receber mensagens assncronas, use um Message-Driven Bean.

Exemplo de um EJB MDB para JMS Queue


Nesta sesso vamos mostrar um exemplo completo de um MDB que interage com uma fila Queue. Apresentamos inicialemnte um MDB consumidor de mensagens JMS para uma Queue, logo em seguida apresentamos um cliente standalone capaz de enviar mensagens para uma Queue que ser, ento, consumida pelo MDB.

MDB como cliente de uma queue


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

@MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/MyQueue"), @ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue = "QueueConnectionFactory") } ) public class MDBQueueSample implements MessageListener { public void onMessage(Message message) { try { System.out.println("MDB - Queue - [ onMessage() ] ..."); TextMessage textMsg = (TextMessage)message; System.out.println("Message: "+ textMsg.getText() ); } catch (JMSException ex) { System.out.println("Erro ao pegar a mensagem: "+ex.getMessage() ); } } } Cdigo 4-9: EJB exemplo

O MDB acima um bean consumidor de mensagens da fila queue/MyQueue. Abaixo o cliente que pode enviar mensagens JMS para esta queue:

Cliente standalone produtor de mensagens JMS para queue

package com.jms.queue; import import import import import import import import import import import java.util.Properties; javax.jms.Queue; javax.jms.QueueConnection; javax.jms.QueueConnectionFactory; javax.jms.QueueSender; javax.jms.QueueSession; javax.jms.TextMessage; javax.naming.Context; javax.naming.InitialContext; javax.naming.NamingException; javax.swing.JOptionPane;

public class JMSQueueSendClient { public static void main(String[] args) {

try { InitialContext ctx = getInitialContext(); Queue queue = (Queue) ctx.lookup("queue/MyQueue"); QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory"); QueueConnection connection = factory.createQueueConnection(); QueueSession session = connection.createQueueSession( false, QueueSession.AUTO_ACKNOWLEDGE); TextMessage msg = session.createTextMessage(" Ol fila queue! "); QueueSender sender = session.createSender(queue); sender.send(msg); connection.close(); System.out.println("Mensagem enviada para queue: "+queue.getQueueName()+ " pelo client!"); } catch (Exception ex) { ex.printStackTrace(); } } public static InitialContext getInitialContext() throws NamingException { Properties env = new Properties(); env.put(Context.SECURITY_PRINCIPAL, "guest" ); env.put(Context.SECURITY_CREDENTIALS, "guest" ); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory"); env.put(Context.PROVIDER_URL, "jnp://10.1.1.3:1099"); return new InitialContext(env); } } Cdigo 4-10: Cliente JMS standalone produtor

Na seqncia apresentamos um cliente standalone que ao invs de produzir mensagens JMS ser um consumidor de mensagens JMS.

Cliente standalone para consumir mensagens JMS queue


package com.jms.queue; import import import import import import import import import import import import import import java.util.Properties; javax.jms.JMSException; javax.jms.Message; javax.jms.MessageConsumer; javax.jms.MessageListener; javax.jms.Queue; javax.jms.QueueConnection; javax.jms.QueueConnectionFactory; javax.jms.QueueSession; javax.jms.Session; javax.jms.TextMessage; javax.naming.Context; javax.naming.InitialContext; javax.naming.NamingException;

public class JMSQueueReceiveClient implements MessageListener { public JMSQueueReceiveClient() { try { InitialContext ctx = getInitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory"); Queue queue = (Queue)ctx.lookup("queue/MyQueue"); QueueConnection connect = factory.createQueueConnection(); QueueSession session = connect.createQueueSession( false, Session.AUTO_ACKNOWLEDGE ); MessageConsumer consumer = session.createConsumer( queue ); consumer.setMessageListener(this); connect.start(); } catch (Exception ex) { ex.printStackTrace(); } }

public static void main(String[] args) throws Exception { JMSQueueReceiveClient client = new JMSQueueReceiveClient(); int i = 0; while(true) { Thread.sleep(10000); i++; System.out.println("["+i+"] Checando queue ..."); } }

<< Continua na pgina seguinte >>

public static InitialContext getInitialContext() throws NamingException { Properties env = new Properties(); env.put(Context.SECURITY_PRINCIPAL, "guest" ); env.put(Context.SECURITY_CREDENTIALS, "guest" ); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory"); env.put(Context.PROVIDER_URL, "jnp://10.1.1.3:1099"); return new InitialContext(env); }

public void onMessage(Message message) { try { TextMessage textMsg = (TextMessage)message; String text = textMsg.getText(); System.out.println("Mensagem recebida: "+ text ); } catch (JMSException ex) { ex.printStackTrace(); } } } Cdigo 4-11: Cliente JMS standalone consumidor

Exemplo de um EJB MDB para JMS Topic


Semelhante ao que apresentamos sobre Queue vamos agora apresentar sobre o uso de topic. Abaixo sero mostrados trs cdigos, um para um MDB inscrito em um topic, outro para um cliente standalone que envia mensagens agindo como produtor para um topic e por fim um cliente standalone que atua como um consumidor inscrito em um topic. Veja abaixo o MDB:

MDB como cliente de um topic


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

@MessageDriven( activationConfig = { @ActivationConfigProperty(propertyName propertyValue @ActivationConfigProperty(propertyName propertyValue @ActivationConfigProperty(propertyName propertyValue @ActivationConfigProperty(propertyName = propertyValue = } = "acknowledgeMode", = "Auto-acknowledge"), = "destinationType", = "javax.jms.Topic"), = "destination", = "topic/testTopic"), "connectionFactoryJndiName", "TopicConnectionFactory")

) public class MDBTopicSample implements MessageListener { public void onMessage(Message message) { try { System.out.println("MDB - Topic - [ onMessage() ] ..."); TextMessage textMsg = (TextMessage)message; System.out.println("Message: "+ textMsg.getText() ); } catch (JMSException ex) { System.out.println("Erro ao pegar a mensagem: "+ex.getMessage() ); } } } Cdigo 4-12: MDB cliente para topic

Cliente standalone para envio de mensagens JMS a um topic


Abaixo o cliente standalone para enviar mesnagens para um topic:
package com.jms.topic; import import import import import import import import import import import java.util.Properties; javax.jms.MessageProducer; javax.jms.QueueSession; javax.jms.TextMessage; javax.jms.Topic; javax.jms.TopicConnection; javax.jms.TopicConnectionFactory; javax.jms.TopicSession; javax.naming.Context; javax.naming.InitialContext; javax.naming.NamingException;

public class JMSTopicSendClient { public static void main(String[] args) { try { InitialContext ctx = getInitialContext(); Topic topic = (Topic) ctx.lookup("topic/testTopic"); // Enviar mensagem para um TOPIC TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory"); TopicConnection connection = factory.createTopicConnection(); TopicSession session = connection.createTopicSession( false, TopicSession.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(topic); TextMessage textMsg = session.createTextMessage(); textMsg.setText("Ol fila topic! "); producer.send(textMsg); connection.start(); connection.close(); System.out.println("Mensagem enviada para topic: "+topic.getTopicName()+ " pelo client!"); } catch (Exception ex) { ex.printStackTrace(); } } public static InitialContext getInitialContext() throws NamingException { Properties env = new Properties(); env.put(Context.SECURITY_PRINCIPAL, "guest" ); env.put(Context.SECURITY_CREDENTIALS, "guest" ); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory"); env.put(Context.PROVIDER_URL, "jnp://10.1.1.3:1099"); return new InitialContext(env); } } Cdigo 4-13: Cliente standalone produtor para topic

Cliente standalone consumidor de mensagens JMS do topic


Por fim mostramos um clietne standalone receptor de mensagens de um topic:
package com.jms.topic; import import import import import import import import import import import import import import java.util.Properties; javax.jms.JMSException; javax.jms.Message; javax.jms.MessageConsumer; javax.jms.MessageListener; javax.jms.Session; javax.jms.TextMessage; javax.jms.Topic; javax.jms.TopicConnection; javax.jms.TopicConnectionFactory; javax.jms.TopicSession; javax.naming.Context; javax.naming.InitialContext; javax.naming.NamingException;

public class JMSTopicReceiveClient implements MessageListener { public JMSTopicReceiveClient() { try { InitialContext ctx = getInitialContext(); Topic topic = (Topic)ctx.lookup("topic/testTopic"); TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory"); TopicConnection connect = factory.createTopicConnection(); TopicSession session = connect.createTopicSession( false, Session.AUTO_ACKNOWLEDGE ); MessageConsumer consumer = session.createConsumer( topic ); consumer.setMessageListener(this); connect.start(); } catch (Exception ex) { ex.printStackTrace(); } }

public static void main(String[] args) throws Exception { JMSTopicReceiveClient client = new JMSTopicReceiveClient(); int i = 0; while(true) { Thread.sleep(10000); i++; System.out.println("["+i+"] Checando topic ..."); } }

<< Continua na pgina seguinte >>

public static InitialContext getInitialContext() throws NamingException { Properties env = new Properties(); env.put(Context.SECURITY_PRINCIPAL, "guest" ); env.put(Context.SECURITY_CREDENTIALS, "guest" ); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory"); env.put(Context.PROVIDER_URL, "jnp://10.1.1.3:1099"); return new InitialContext(env); }

public void onMessage(Message message) { try { TextMessage textMsg = (TextMessage)message; String text = textMsg.getText(); System.out.println("Mensagem recebida: "+ text ); } catch (JMSException ex) { ex.printStackTrace(); } } } Cdigo 4-14: Cliente standalone consumidor para topic

Bibliografia
1 - BURKE, Bill and MONSON-HAEFEL, Richard. "Enterprise JavaBeans 3.0". O'Reilly. 5 ed. 2006. 760 p. 2 - JENDROCK, Eric et al. "The Java EE 5 Tutorial". (http://java.sun.com/javaee/5/docs /tutorial/doc) Consultado em 16/04/2007. 3 - JBoss Web Site: http://labs.jboss.com/portal/jbossejb3. Consultado em 15/04/2007.

Vous aimerez peut-être aussi