Introdução a JMS e
Message-Driven Bean
Comunicação Assíncrona
Ricardo Cavalcanti
[email protected]
Jobson Ronan
[email protected]
Por que usar um MDB?

Tipicamente devido a algumas limitações
de RMI-IIOP


Performance. Um cliente típico RMI-IIOP
precisa esperar enquanto o servidor está
processando. Apenas quando o servidor
completa o trabalho e o cliente recebe o
resultado, este pode continuar seu
processamento
Garantia. Quando um cliente RMI-IIOP invoca
o servidor, este tem que restar rodando. Se o
servidor ou a rede cair o cliente não pode
efetuar a operação desejada
Por que usar um MDB?


Suporte para vários emissores e
receptores. RMI-IIOP se limita a
comunicação de um único cliente a um
único servidor
Integração com outros sistemas
MOM(Middleware Orientado a
Mensagem).
Messaging
Mensagens são uma alternativa a
invocação de métodos remotos.
 A idéia é inserir uma camada entre o
cliente e o servidor

Invocação de método remoto
Aplicação
Aplicação
Messaging
Aplicação
Message
Middleware
Aplicação
Messaging

Vantagens
Processos não bloqueáveis
 Garantia de entrega
 Suporte a múltiplos emissores e
receptores

JMS – Java Message Service
JMS é um padrão para Messaging
 Tem como objetivo eliminar muitas
das desvantagem que MOMs
encontraram com o passar dos anos
 O Desenvolvedor aprende a usar a
API de JMS e reusa seu código com
diferentes implementações plugáveis
de MOM (idéia similar APIs do J2EE,
como JNDI e JDBC)

Domínios de Mensagens

Publish/subscribe(pub/sub)

Análogo a assistir televisão. Pode haver
muitos produtores de mensagens e
muitos consumidores.
Consumidor 1
Produtor 1
Canal
Produtor 2
Consumidor 2
Domínios de Mensagens

Point-to-point(PTP)

Múltiplos produtores podem enviar
mensagens para a fila mas cada
mensagem é entregue a apenas um
consumidor
Produtor 1
Fila
Produtor 2
Consumidor 1
Usando a API JMS

Passos
1. Localizar o provedor JMS, instancia
de ConnectionFactory
 2. Criar um conexão JMS
 3. Criar uma Sessão JMS
 4. Localizar o destino
 5. Criar um JMS Provider ou um JMS
Consumer
 6. Enviar ou Receber suas mensagens

Cliente
1. Obter o
Driver JSM
(Connection
Factory)
4. Obter o
destino JSM
JNDI
Serviço de nomes
2. Criar
conexão
JMS Connection
Factory
3. Criar
sessão
JSM Connection
Fila1
Fila2
5. Criar
producer ou
consumer
JMS Session
6. Enviar ou
receber
mensagens
JSM Prosucer
ou Consumer
Tópico1
Driver JMS do cliente
6. Enviar ou
receber
mensagens
Servidor JMS
Exemplo
//..imports
public class Client {
public static void main (String[] args) throws Exception {
Context ctxt = new InitialContext();
TopicConnectionFactory factory = (TopicConnectionFactory)
ctxt.lookup("jms/TopicConnectionFactory");
TopicConnection connection = factory.createTopicConnection();
TopicSession session = connection.createTopicSession
(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = (Topic) ctxt.lookup("jms/Topic");
TopicPublisher publisher = session.createPublisher(topic);
TextMessage msg = session.createTextMessage();
msg.setText("This is a test message.");
publisher.publish(msg);
}
}
Interfaces
INTERFACE PAI
POINT-TO-POINT
PUB/SUB
ConnectionFactory
QueueConnectionFactory
TopicConnectionFactory
Connection
QueueConnection
TopicConnection
Destination
Queue
Topic
Session
QueueSession
TopicSession
MessageProducer
QueueSender
TopicPublisher
MessageConsumer
QueueReceiver,
QueueBrowser
TopicSubscriber
Integração JMS-EJB

Motivação

Possuir componentes Ejbs com
características como clientes “nãobloqueaveis” e comunicação n-ária
Integração JMS-EJB

Como implementar a integração?


Implementar objetos Java que recebem
mensagens e realizam chamadas a
componentes EJBs?
Reusar um tipo existente de
componente EJB para receber
Mensagens JMS?
Messsage-Driven Beans

O que são?



Introduzido na especificação EJB 2.0
São componentes EJBs especiais capazes de
receber mensagens enviadas a filas e canais
JMS
Invocados pelo Container dada a chagada de
um mensagem ao destino que um MDB escuta
• Não se envia uma mensagem direto a um
MDB(envia-se ao canal que o bean escuta)
• Proporcionando acoplamento fraco entre cliente e
MDB (conhecimento do canal de comunicação)
Messsage-Driven Beans

Para efetuar a comunicação é
necessário o uso de uma API específica,
como JMS
Pool de MDBs
Cliente
Destino JMS
Instancias de
Message-Driven
Beans
Messsage-Driven Beans

Características





Não possuem interface home, local home,
interface remota, nem interface local
Possuem apenas um método que recebe
qualquer tipo de mensagem
Não têm retorno, e também não lançam
exceções ao cliente
São Stateless
Podem ser ouvintes de uma fila, ou assinantes
durável ou não-durável de um canal(Topic)
Implementando MDBs

MDBs devem implementar duas interfaces



javax.jms.MessageListener
javax.ejb.MessageDrivenBean
Métodos de MessageDrivenBean e da especificação



ejbRemove(): método da interface. Chamado pelo container
quando o message-driven bean está sendo removido do pool
ejbCreate(): método definido na especificação (não está na
interface). É chamado quando um novo bean é criado pelo
container
setMessageDrivenContext(MessageDrivenContext ctx):
método da interface. Chamado antes do ejbCreate() quando
o bean está sendo adicionado ao pool
Implementando MDBs

Método de MessageListener

onMessage(Message m): chamado cada vez que uma
mensagem é enviada para o canal do bean (se o bean
estiver ativado).
Implementando MDBs
package org.citi.pec.ejbs;
//..imports
/**
* @ejb.bean name="ExecuterSQLMessage"
*
display-name="Name for Executer"
*
description="Description for Executer"
*
destination-type="javax.jms.Queue"
*
acknowledge-mode="Auto-acknowledge"
* @jboss.destination-jndi-name name = "queue/MyQueueMDB"
*/
public class ExecuterBean implements MessageDrivenBean, MessageListener {
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage text = (TextMessage) message;
System.out.println(text.getText());
}
} catch (JMSException e) {
throw new EJBException(e);
}
}
public void setMessageDrivenContext(MessageDrivenContext ctx)
throws EJBException {}
public void ejbCreate() throws EJBException {}
public void ejbRemove() throws EJBException {}
}
Deployment Descriptors
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC
"-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN“
"http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar >
<description><![CDATA[No Description.]]></description>
<display-name>Generated by XDoclet</display-name>
<enterprise-beans>
<message-driven >
<description><![CDATA[Description for Executer]]></description>
<display-name>Name for Executer</display-name>
<ejb-name>ExecuterSQLMessage</ejb-name>
<ejb-class>org.citi.pec.ejbs.ExecuterBean</ejb-class>
<transaction-type>Container</transaction-type>
<acknowledge-mode>Auto-acknowledge</acknowledge-mode>
<message-driven-destination>
<destination-type>javax.jms.Queue</destination-type>
</message-driven-destination>
</message-driven>
</ejb-jar>
...e se fosse Topic ???
Deployment Descriptors

Outras Tags

<message-selector>
Usado para incluir um filtro SQL para
cabeçalhos de mensagens. Apenas
mensagens que combinarem com o filtro
serão recebidas pelo bean. Exemplo:
<message-selector><![CDATA[
Formato LIKE '%Imagem%‘ AND JMSExpiration > 0
AND Valor IS NOT NULL]]>
</message-selector>
Deployment Descriptors
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss PUBLIC
"-//JBoss//DTD JBOSS 3.2//EN“
"http://www.jboss.org/j2ee/dtd/jboss_3_2.dtd">
<jboss>
<enterprise-beans>
<message-driven>
<ejb-name>ExecuterSQLMessage</ejb-name>
<destination-jndi-name>queue/MyQueueMDB</destination-jndi-name>
</message-driven>
</enterprise-beans>
<resource-managers>
</resource-managers>
</jboss>
JBoss

...empacotar e fazer o deploy...

Waning no deploy: a fila referênciada
(queue/MyQueueMDB)não existe, o JBoss
criará uma nova fila temporária para o
MDB
JBoss


Como a maioria das coisas no JBoss, JMS Topics e
Queues são implementadas como MBeans
Para criar uma fila permanente no JBoss, basta
adicionar uma declaração de um MBean no
arquivo jbossmq-destinations-service.xml
(diretório jms dendo do diretório deploy)
<!-- .... -->
<mbean code="org.jboss.mq.server.jmx.Queue“
name="jboss.mq.destination:service=Queue,name=MyQueueMDB">
<depends optional-attribute-name="DestinationManager">
jboss.mq:service=DestinationManager
</depends>
</mbean>
<!-- .... -->
Implementando cliente

Como um cliente JMS comum
//..imports
public class MDBClient {
public static void main(String[] args) throws Exception {
Properties namingProperties = new Properties();
namingProperties.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
namingProperties.put("java.naming.provider.url",
"jnp://localhost:1099");
namingProperties.put("java.naming.factory.url.pkgs",
"org.jboss.naming.client");
Context ctx = new InitialContext(namingProperties);
QueueConnectionFactory cf = (QueueConnectionFactory)
ctx.lookup("XAConnectionFactory");
QueueConnection conn = cf.createQueueConnection();
QueueSession session = conn.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) ctx.lookup("queue/MyQueueMDB");
QueueSender sender = session.createSender(queue);
TextMessage message = session.createTextMessage();
message.setText("Hello World of Messaging!");
sender.send(message);
}
}
Download

j2ee_pcc_08_JMS_MSB