Introdução a JMS e Message-Driven Bean Comunicação Assíncrona Ricardo Cavalcanti...

Preview:

Citation preview

Introdução a JMS e Message-Driven Bean

Comunicação Assíncrona

Ricardo Cavalcantiroc3@cin.ufpe.br

Jobson Ronanjrjs@cin.ufpe.br

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

Aplicação AplicaçãoInvocação de método remoto

Messaging

Aplicação AplicaçãoMessage

Middleware

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.

Produtor 1 Consumidor 1

Canal

Consumidor 2Produtor 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 1Consumidor 1Fila

Produtor 2

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

JNDI

Serviço de nomes

1. Obter o Driver JMS (ConnectionFactory)

4. Obter o destino JMS

2. Criar conexão

3. Criar sessão

5. Criar producer ou consumer

6. Enviar ou receber mensagens

JMS Connection Factory

JSM Connection

JMS Session

JSM Prosucer ou Consumer

Driver JMS do cliente

Servidor JMS

6. Enviar ou receber mensagens

Fila1

Fila2

Tópico1

Exemplo//..importspublic 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); }}

InterfacesINTERFACE PAI POINT-TO-POINT PUB/SUBConnectionFactory QueueConnectionFactory TopicConnectionFactoryConnection 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ão-bloqueaveis” 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 chegada 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

Cliente Destino JMS

Instancias de Message-Driven

Beans

Pool de MDBs

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 MDBspackage 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 {}}

<?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>

Deployment Descriptors

...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...

Warning 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 dentro 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//..importspublic 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); }}

Exercício Construa um MDB simples que

recebe uma mensagem de texto e imprime seu conteúdo se a mensagem possuir no cabeçalho a informação “fonte : cliente”

Construa um cliente que envia uma Mensagem a fila na qual o MDB está escutando

...mas quem pode e deve ser um cliente de um bean: Servlets locais Beans locais Classes java remotas ...

Exercício (++) “... How the pieces fit together?” Construa um Entity Bean CompraBean

com os segiuntes atributos: Código Cliente produtos (pode ser uma string contendo todos

os produtos) valor total status da compra (um booleano que indica se a

compra foi validada ou não)

Exercício (++)

Construa um MDB ValidadorBean que recebe uma mensagem contendo os dados de uma compra e simula uma verificação de perfil de compra. Em seguida ele altera o estado do CompraBean Correspondente para validado você pode usar um "Thread.sleep()"

para simular um processo demorado

Exercício (++) Crie um ValueObject para o Bean Compra

(CompraVO) Construa um SessionBean stateless que

contém o método efetuarCompra(CompraVO compra) que Cria um CompraBean equicvalente ao

CompraVO passado por parametro E em seguida envia uma mensagem ao

ValidadorBean, solicitando a validação da compra

Exercício (++)

Crie um cliente simples que efetua uma compra através o session Bean que você implementou

...E...

Bom (resto) de fim de semana!

Recommended