Upload
brad
View
34
Download
0
Embed Size (px)
DESCRIPTION
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 - PowerPoint PPT Presentation
Citation preview
Introdução a JMS e Message-Driven Bean
Comunicação Assíncrona
Ricardo [email protected]
Jobson [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
Aplicação Aplicação
Invocaçã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 1
Consumidor 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); }}
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ã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!