JMS
Autoria Autoria Fábio Cecin (1a versão) Versão V3.2, junho de 2013 C. Geyer
Referências Referências: The JMS Tutorial após versão 1.4 do JEE em capítulo do tutorial JEE da Sun v.1.5 (JEE): até v. 1.3: http://java.sun.com/javaee/5/docs/tutorial/doc/ http://java.sun.com/products/jms/tutorial/ Documentação (javadoc) do pacote JMS: http://java.sun.com/javaee/5/docs/api Dica: utilizar estes documentos como referência de programação para os exercícios.
Referências Referências: The JMS Tutorial Após versão 1.4 do JEE Em capítulos do tutorial JEE da Sun v.1.6 (JEE): Caps. 47 e 48 http://docs.oracle.com/javaee/6/tutorial/doc/
Referências Referências: The JMS Tutorial Até v. 1.3: http://docs.oracle.com/javaee/1.3/jms/tutorial/ http://java.sun.com/products/jms/tutorial/ Em 2012 desvia para: http://www.oracle.com/technetwork/java/jms/ index.html
Referências Referências: Especificação http://www.oracle.com/technetwork/java/ docs-136352.html
Súmula Súmula Visão Geral JMS Arquitetura Modelo de Programação Mecanismos de Confiabilidade Integração com EJB Enterprise JavaBeans Message-Driven Beans
Visão geral Visão Geral JMS é uma API padrão da plataforma JEE que dá acesso a serviços de messaging. Messaging pode ser entendido como troca de mensagens, similar ao sistema de correio eletrônico. JMS é uma API mais um serviço para troca de mensagens entre componentes de software distribuídos oferecendo diversas funcionalidades inexistentes em outros pacotes (bibliotecas, mws, protocolos, ) Recepção Assíncrona (também) e Confiável similar à programação orientada a eventos.
Visão geral Visão Geral JMS foi originalmente desenvolvido para a integração com MOMs (Message-Oriented Middleware) Por exemplo, MQSeries da IBM Permitiria comunicação entre componentes Java e não-java Mas pode ser usado atualmente para integração com Sistemas de Informação (EIS: Enterprise Information Systems) existentes A partir da versão 1.3 do padrão JEE, a API JMS tornou-se uma solução completa, independente, para aplicações de messaging. Procura ser ao mesmo tempo: simples e flexível, com diversas opções
Visão Geral Vantagens de JMS Especialmente sobre alternativas mais fortemente acopladas (RMI ): Fácil substituição: componentes não dependem da interface de outros componentes Componentes que trocam mensagens via JMS não precisam se conhecer Comunicação entre dois componentes não requer que ambos estejam operacionais para que a comunicação aconteça É possível enviar uma mensagem e continuar a execução de forma assíncrona
Visão Geral Vantagens de JMS Diversas opções de sincronização no recebimento time-out síncrona e assíncrona 2 grandes modelos ponto a ponto publicador-assinante (publish-subscribe)
Visão Geral JMS versões Segundo artigos da Oracle v1.1: 2002 v2.0: abril 2013 Ou segundo wikipedia JMS 1.0.2b (June 25, 2001) JMS 1.1 (March 18, 2002) JMS 2.0 (May 21 2013)
Visão Geral JMS implementações Em http://en.wikipedia.org/wiki/java_message_service ActiveMQ Apache Apache Qpid, using AMQP http://qpid.apache.org Oracle Weblogic (part of the Oracle Fusion Middleware Fusion Middleware suite) and Oracle AQ from Oracle Corporation EMS from TIBCO FFMQ, GNU LGPL licensed
Visão Geral JMS implementações JBoss Messaging and HornetQ from Jboss JORAM from the OW2 Consortium Open Message Queue from Oracle OpenJMS from The OpenJMS Group Solace JMS from Solace systems RabbitMQ by Rabbit Technologies Ltd., acquired by SpringSource
Visão Geral JMS implementações SAP Process Integration ESB SonicMQ from Progress Software StormMQ, using AMQP SwiftMQ Tervela
JMS implementações Visão Geral Ultra Messaging from 29 West (acquired by Informatica) webmethods from Software AG WebSphere Application Server from IBM which provides an inbuilt default messaging provider known as the Service Integration Bus (SIBus), or which can connect to WebSphere MQ as a JMS provider "Choosing a messaging system: WebSphere MQ vs. the WebSphere Application Server Service Integration Bus http://www.ibm.com/developerworks/websphere/ library/techarticles/1109_wallis/1109_wallis.html work=ibm developerworks WebSphere MQ (formerly MQSeries) from[ibm
Visão Geral JMS - características funcionais em JEE: EJBs, clientes e componentes web podem consumir mensagens JMS de forma síncrona (recepção) Permite interação com um novo ( faz tempo ) tipo de bean, o message-driven bean: um EJB que consome mensagens JMS de forma assíncrona. Envio e recebimento de mensagens JMS podem participar de transações distribuídas.
Arquitetura JMS Arquitetura JMS Administrative Tool; Cliente JMS Provedor JMS
Arquitetura JMS Provedor de Serviço JMS: Implementa as interfaces do JMS Oferece recursos administrativos e de controle JEE deve oferecer um provedor JMS Clientes JMS: Componentes escritos em Java Consomem e produzem mensagens Arquitetura JMS Todo componente de uma aplicação JEE pode ser cliente JM
Arquitetura JMS Arquitetura JMS Ferramenta administrativa cria objetos administrativos em um serviço de nomes JNDI objetos são Connection Factories e Destinations, utilizados pelos clientes JMS.
Arquitetura JMS Um provedor de serviços JMS (JEE 1.3 e mais) suporta obrigatoriamente tanto o domínio de comunicação ponto-a-ponto quanto o de publicador-assinante. Ponto-a-ponto Publicador-assinante
Modelo (domaine) ponto-a-ponto abstrações filas (queues) de mensagens produtores de mensagens consumidores de mensagens cada mensagem é enviada a uma fila Modelo ponto-a-ponto fila mantém mensagens até serem consumidas ou expiradas cada mensagem só tem um consumidor sem dependência de tempo entre produtor e consumidor consumidor pode consumir mensagem mesmo se não estivesse executando quando do envio da mensagem recebedor confirma recepção da mensagem
Modelo publicador-assinante Modelo publicador-assinante abstrações tópicos (topics) publicadores de mensagens assinantes de mensagens clientes publicadores enviam (publicam) mensagens a um tópico (topic) assinantes se inscrevem como interessados em um tópico o sistema se encarrega de distribuir as mensagens de um tópico aos assinantes desse tópico mensagens são mantidas até que todos os assinantes atuais as recebam
Modelo publicador-assinante Modelo publicador-assinante uma mensagem pode ter vários consumidores (assinantes) há dependência de tempo entre publicador e assinante um assinante só pode consumir mensagens publicadas após a inscrição subscrições duráveis permitem contornar a dependência de tempo oferecem mais flexibilidade e confiabilidade (como as filas) mas preservam a relação n (> 1) consumidores para 1 mensagem
Modelos x Usos Quando usar cada modelo? ponto-a-ponto: use quando cada mensagem deve ser lida por 1 cliente publicador-assinante use quando cada mensagem pode ser lida por zero, 1 ou vários clientes
Interfaces comuns Interfaces comuns envio e recepção de mensagens com o mesmo código seja fila (ponto-a-ponto) ou topic (assinante) as destinações indicarão se fila ou topic as destinações podem ser definidas dinamicamente
Consumo de mensagens Consumo de mensagens Síncrono cliente deve executar o método receive o método receive bloqueia até: uma mensagem chegar ou se houver um time-out Assíncrona cliente registra um message-listener a um consumidor semelhante a um event-listener a cada nova mensagem que chega ao destino o sistema chama o método onmessage esse método processa a mensagem
Modelo de Programação JMS Modelo JMS: Entidades Administrativas: - Fábricas de Conexões - Destinos Entidades de Programação: - Conexão - Sessão - Mensagem - Produtor - Consumidor
Modelo de Programação JMS Fábricas de conexões e destinos São criados e modificados em ferramentas administrativas, em contraste com criação via clientes JMS. O objetivo é manter a portabilidade da API, ao encapsular informações específicas de conexão e de endereçamento nestes objetos. Cada fornecedor JEE Implementa suas próprias ferramentas administrativas. Sun JEE: j2eeadmin (/j2ee/bin) (versão 1.3) Clientes JMS acessam esses objetos através de interfaces padronizadas Usualmente via injeção de recursos (anotação)
Modelo de Programação JMS Fábrica de conexões (connection factory): É o objeto utilizado pelo cliente JMS para criar uma conexão com um serviço JMS. Uma instalação de JMS Deve fornecer pelo menos duas fábricas (nomes JNDI): QueueConnectionFactory (ponto-a-ponto) TopicConnectionFactory (publicador-assinante) Há ainda a fábrica geral: ConnectionFactory J2EE (C. Geyer)
Modelo de Programação JMS Exemplo: Obtendo uma Connection Factory em uma classe cliente @Resource(mappedName = "jms/connectionfactory") private static ConnectionFactory connectionfactory; @Resource(lookup = "jms/connectionfactory") private static ConnectionFactory connectionfactory;
Modelo de Programação JMS Destino (Destination): Um objeto que o cliente JMS usa como alvo das mensagens que produz e fonte das mensagens que consome. Em comunicação ponto-a-ponto um destino é chamado fila (queue) Em comunicação publicador-assinante um destino é chamado tópico (topic). Uma aplicação JMS Pode utilizar quantas filas e/ou tópicos forem necessários.
Modelo de Programação JMS Destino (Destination): Objetos filas e tópicos injetados no programa só podem ser usados como filas ou tópicos Objetos Destinations Para desenvolver componentes que manipulem filas e tópicos com o mesmo código se pode usar objetos Destinations O comportamento de um programa é determinado pelo tipo de destino (fila ou tópico) E não do tipo de factory
Modelo de Programação JMS JEE Sun Criando destinos (filas e tópicos): j2eeadmin -addjmsdestination <nome JNDI da fila> queue j2eeadmin -addjmsdestination <nome JNDI do tópico> topic obs.: válido para versão 1.3 (revisar nas seguintes)
Modelo de Programação JMS Visão geral de codificando um cliente JMS : Obter ConnectionFactory e Destinations via @resource na classe cliente Usar factory para criar uma Connection com o provedor JMS Usar Connection para criar uma ou mais Sessions Usar uma Session com os Destinations para criar produtores e consumidores Habilitar a Connection (método start) para iniciar a entrega de Messages no cliente consumidor Criar uma mensagem usando método específico (conforme tipo da mensagem) de Session Enviar mensagem com método send do produtor Receber mensagem com método receive do consumidor
Modelo de Programação JMS JEE Sun Obtendo um destino no cliente, após criação: @Resource(mappedName = "jms/queue") private static Queue queue @Resource(mappedName = "jms/topic" private static Topic topic; @Resource(lookup = "jms/queue") private static Queue queue; @Resource(lookup = "jms/topic") private static Topic topic;
Modelo de Programação JMS Conexões (Connections): Conexão é um canal entre o cliente e o provedor de serviço JMS Após criado e obtido (@resource) um objeto fábrica de conexões, é possível criar conexões a partir do mesmo: QueueConnection myqueuecon = myqueuefact.createqueueconnection(); TopicConnection mytopiccon = mytopicfact.createtopicconnection(); Connection connection = connectionfactory.createconnection() A criação geral (Connection) pode ser usada para queue e topic queue e topic serão indicados na criação de produtores e consumidores
Modelo de Programação JMS Conexões Podem ser (re)iniciadas e suspensas após criação. Não há recebimento de mensagens enquanto a conexão está suspensa: myqueuecon.start(); /* (re)inicia */ myqueuecon.stop(); /* suspende */ connection.start(); connection.stop(); É necessário fechar conexões após o uso: myqueuecon.close(); connection.close();
Modelo de Programação JMS Resumo de codificando um cliente JMS : Obter ConnectionFactory e Destinations via @resource na classe cliente Usar factory para criar uma Connection com o provedor JMS Habilitar a Connection (método start) para iniciar a entrega de Messages no cliente consumidor Usar Connection para criar uma ou mais Sessions Usar uma Session com os Destinations para criar produtores e consumidores Criar uma mensagem usando método específico (conforme tipo da mensagem) de Session Enviar mensagem com método send do produtor Receber mensagem com método receive do consumidor
Modelo de Programação JMS Sessão (Session): Uma sessão representa um contexto para uma thread produzir e consumir mensagens. Também prove um contexto de transação para um conjunto de sends e receives
Modelo de Programação JMS Sessão (Session): A partir de uma conexão é possível criar sessões (sessions): QueueSession myqueuesession = myqueuecon.createqueuesession(false, Session.AUTO_ACKNOWLEDGE); Arg. 1: sessão sem semântica de transação. Arg. 2: confirmação automática de recebimento de mensagens pela sessão. Session session = connection.createsession( false, Session.AUTO_ACKNOWLEDGE);
Modelo de Programação JMS Resumo de codificando um cliente JMS : Obter ConnectionFactory e Destinations via @resource na classe cliente Usar factory para criar uma Connection com o provedor JMS Habilitar a Connection (método start) para iniciar a entrega de Messages no cliente consumidor Usar Connection para criar uma ou mais Sessions Usar uma Session com os Destinations para criar produtores e consumidores Criar uma mensagem usando método específico (conforme tipo da mensagem) de Session Enviar mensagem com método send do produtor Receber mensagem com método receive do consumidor
Modelo de Programação JMS Produtor de mensagens: É um objeto criado por uma sessão Utilizado para enviar mensagens para um destino especificado. Argumento da criação do produtor Há 3 tipos de interfaces conforme o tipo de destino Geral: interface Producer Para filas: interface QueueSender Para tópicos: interface TopicPublisher
Modelo de Programação JMS Exemplo de produtor Destination dest = queue ou topic;... Producer producer = session.createproducer(dest /*destino*/ ); Message mymessage = /* cria mensagem */ producer.send( mymessage );
Modelo de Programação JMS Produtor de mensagens: É possível não especificar o destino (null) Nesse caso o destino será especificado pelo método de envio (send)
Consumidor de mensagens: Modelo de Programação JMS Objeto criado por uma sessão para recebimento de mensagens enviadas a um destino especificado. Um cliente JMS utiliza um consumidor de mensagens para registrar interesse por certos destinos hospedados em um provedor JMS. O provedor de serviço JMS se encarrega de transferir as mensagens de um destino para os consumidores registrados neste destino. Antes do 1o receive, é necessário ativar a recepção via o método start da sessão
Modelo de Programação JMS Consumidor de mensagens: Geral: interface Consumer Para filas: interface QueueReceiver Para tópicos: interface TopicSubscriber Exemplo com consumo síncrono: Consumer consumer = session.createconsumer(dest); Message m = consumer.receive( 1000 ); receive ( ) parâmetro opcional timeout em milisegundos.
Modelo de Programação JMS Resumo de codificando um cliente JMS : Obter ConnectionFactory e Destinations via @resource na classe cliente Usar factory para criar uma Connection com o provedor JMS Usar Connection para criar uma ou mais Sessions Habilitar a Connection (método start) para iniciar a entrega de Messages no cliente consumidor Usar uma Session com os Destinations para criar produtores e consumidores Criar uma mensagem usando método específico (conforme tipo da mensagem) de Session Enviar mensagem com método send do produtor Receber mensagem com método receive do consumidor
Modelo de Programação JMS Mensagem (Message): Objeto que representa uma mensagem Formato permitiria uso de mensagens por aplicações não JMS Deve ser criado por uma sessão através de interface específica
Modelo de Programação JMS Mensagem (Message): Possui três partes: Cabeçalho (header): possui campos pré-definidos que devem ser preenchidos pela aplicação ou pela implementação JMS. tipo, destino, prioridade, time-stamp,... Propriedades (properties): espaço para um header opcional, mantido pela aplicação. Corpo (body): opcional.
Modelo de Programação JMS Tipos de mensagens (corpo): TextMessage: uma String BytesMessage: uma sequência de bytes StreamMessage: um stream de tipos primitivos Java (int, char, byte[], String...) ObjectMessage: objeto Java serializado Message: mensagem sem corpo
Modelo de Programação JMS Criando e enviando uma mensagem de texto: TextMessage message = session.createtextmessage(); message.settext( minha mensagem ); producer.send(message); Consumindo a mensagem: Message m = consumer.receive(); if (m instanceof TextMessage) { TextMessage message = (TextMessage)m; System.out.println( Mensagem chegou: + message.gettext() ); } else { /* erro: não recebe outro tipo de mensagem */ }
Modelo de Programação JMS Message listeners: Uma classe qualquer da aplicação pode atuar como consumidora assíncrona de mensagens ao implementar a interface MessageListener, do padrão JMS. Esta interface especifica o método: void onmessage( Message ) onde Message é a mensagem de interesse que deve ser processada pela classe. Esse método substitui o receive da recepção síncrona
Modelo de Programação JMS Message listeners: A classe listener deve ser registrada junto a um consumidor (Consumer ou QueueReceiver ou TopicSubscriber) através do método setmessagelistener( ) (do consumidor), para receber as mensagens. Exemplo: mytopicsubscriber.setmessagelistener( mytopiclistener ); Onde mytopiclistener é instância de classe que implementa a interface MessageListener. E mytopicsubscriber é um consumidor
Modelo de Programação JMS Message listeners: A entrega de mensagens também deve ser ativada pelo método start da sessão Um listener específico pode receber mensagens de ambos os tipos O tipo é definido pelo consumidor ao qual o listener registrado Vários listener podem estar registrados em uma sessão Os respectivos consumidores foram criados nessa sessão Nesse caso a execução de todos os listener é serializada Em JEE/EJB, um message drive bean é um caso especial de listener
Modelo de Programação JMS Filtro de mensagens: É possível filtrar mensagens em recepção Um seletor usa uma sintaxe baseada em SQL A seleção só pode ser feita sobre atributos das partes cabeçalho e propriedades da mensagem Não sobre atributos da 3a parte (aplicação)
Modelo de Programação JMS Exceções: JMS possui uma hierarquia de exceções, cuja raiz é JMSException. Portanto, é possível utilizar um tratador genérico para qualquer exceção JMS: try {... } catch (JMSException ex) {... }
Modelo de Programação JMS Resumo de codificando um cliente JMS : Obter ConnectionFactory e Destinations via @resource na classe cliente Usar factory para criar uma Connection com o provedor JMS Usar Connection para criar uma ou mais Sessions Usar uma Session com os Destinations para criar produtores e consumidores Habilitar a Connection (método start) para iniciar a entrega de Messages no cliente consumidor Criar uma mensagem usando método específico (conforme tipo da mensagem) de Session Enviar mensagem com método send do produtor Receber mensagem com método receive do consumidor
Confiabilidade JMS Confiabilidade JMS JMS possui vários mecanismos para aumento da robustez da aplicação: Nível de confirmação (acknowledgement) Persistência de mensagens Nível de prioridade da mensagem Mensagens com tempo de vida Criação de destinos temporários Assinaturas duráveis (durable subscriptions) Transações locais (local transactions)
Confiabilidade JMS Nível de confirmação (acknowledgement) é especificado na criação da fila ou tópico: Session.AUTO_ACKNOWLEDGE: mensagens automaticamente confirmadas. Session.CLIENT_ACKNOWLEDGE: cliente deve invocar o método acknowledge( ) da mensagem para confirmá-la. Session.DUPS_OK_ACKNOWLEDGE: idem a AUTO, porém pode resultar em entregas duplicadas de mensagens, com possível ganho em performance.
JMS 2.0 JMS 2.0 Objetivo principal Nova API simplified Permite códigos mais concisos, simples Tem todas funcionalidades da API anterior API 1.1 classic Continua válida sem prazo para deprecated
JMS 2.0 JMS 2.0 API simplified Novas interfaces: JMSContext, JMSProducer, and JMSConsumer JMSContext Substitui Connection e Session
JMS 2.0 JMS 2.0 API simplified JMSProducer Substitui MessageProducer Oferece manipulação da mensagem Opções de entrega Headers Properties Usando encadeamento de método (method chaining)
JMS 2.0 JMS 2.0 API simplified JMSConsumer Substitui MessageConsumer De modo similar à JMSProducer x MessageProducer
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Aplicação Versão classic Envio de mensagem de texto public void sendmessagejms11(connectionfactory connectionfactory, Queue queuestring text) { try { Connection connection = connectionfactory.createconnection(); try { Session session = connection.createsession(false, Session.AUTO_ACKNOWLEDGE);
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Aplicação Envio de mensagem de texto Versão classic } MessageProducer messageproducer = session.createproducer(queue); TextMessage textmessage = session.createtextmessage(text); messageproducer.send(textmessage); } finally { connection.close(); } } catch (JMSException ex) { // handle exception (details omitted) }
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Versão simplified public void sendmessagejms20(connectionfactory connectionfactory, Queue queue, String text) { try (JMSContext context = connectionfactory.createcontext();) { context.createproducer().send(queue, text); } catch (JMSRuntimeException ex) { // handle exception (details omitted) } }
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Diferenças Simplified cria um único objeto Context E não 2: Connection e Session Simplified tem chamada de close implícita Opções de sessão Simplified: há uma opção default false e Session.AUTO_ACKNOWLEDGE sem transação e confirmação automática de mensagens Outras opções: um (1) único parâmetro
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Diferenças Mensagens texto (text): conteúdo passado como argumento do método send processamento de exceções mais simples Exceção JMSRuntimeException
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Aplicação Recepção síncrona de mensagem de texto Diferenças similares às do envio
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Versão classic public String receivemessagejms11(connectionfactory connectionfactory,queue queue) { String body=null; try { Connection connection = connectionfactory.createconnection(); try { Session session = connection.createsession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer messageconsumer = session.createconsumer(queue); connection.start();
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Versão classic (cont.) } TextMessage textmessage = (TextMessage) messageconsumer.receive(); body = textmessage.gettext(); } finally { connection.close(); } } catch (JMSException ex) { // handle exception (details omitted) } return body;
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Versão simplified (cont.) public String receivemessagejms20( ConnectionFactory connectionfactory,queue queue) { String body=null; try (JMSContext context = connectionfactory.createcontext() { JMSConsumer consumer = session.createconsumer(queue); body = consumer.receivebody(string.class); } } catch (JMSRuntimeException ex) { // handle exception (details omitted) } return body;
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Diferenças Simplified cria um único objeto Context E não 2: Connection e Session Simplified tem chamada de close implícita Opções de sessão Simplified: há uma opção default false e Session.AUTO_ACKNOWLEDGE
JMS 2.0 JMS 2.0 Exemplo comparando simplified x classic Diferenças Não é necessário ativar a recepção (método start) Mensagens texto (text): Recupera texto (corpo da mensagem) com receive especial (sem uso de métodos adicionais) receivebody(string.class)
Resumo JMS Resumo JMS é uma especificação de serviços e API para troca de mensagens Arquitetura Clientes Ferramentas Provedor (serviço) Modos Filas Tópicos (publish/subscribe)
Resumo JMS Resumo API Factories Destinos Connections Sessions Producers e Consumers Messages Diversas funcionalidades como Semânticas variadas de sincronização Time-outs Maior confiabilidade
Fim Parcial
Opções de Confiabilidade
Confiabilidade JMS Persistência de mensagens: DeliveryMode.PERSISTENT: instrui o provedor de serviço JMS a tomar cuidado extra com esta mensagem, para que ela não seja perdida em caso de falhas no serviço. DeliveryMode.NON_PERSISTENT Esta opção pode ser especificada a cada envio de mensagem (nos métodos send( ) e publish( ) dos produtores), Ou especificada no produtor: myproducer.setdeliverymode( <modo> );
Confiabilidade JMS Nível de prioridade da mensagem: Entre 0 e 9 (default=4). O provedor JMS tenta entregar mensagens de maior prioridade primeiro. Pode ser especificado por envio de mensagem: mytopicpublisher.publish(message, DeliveryMode.NON_PERSISTENT, 3); // 3 é a prioridade Pode ser especificado no produtor: myproducer.setpriority( 3 );
Confiabilidade JMS Mensagens com tempo de vida Por exemplo, para se criar mensagens com tempo de vida de 16 segundos: mytopicpublisher.publish(message, DeliveryMode.NON_PERSISTENT, 3, 16000); myproducer.settimetolive( 16000 ); Por default, mensagens não expiram.
Confiabilidade JMS Criação de destinos temporários: é possível a criação programática de destinos, subordinados a uma conexão (Connection): TemporaryQueue mytempqueue= queuesession.createtemporaryqueue(); TemporaryTopic mytemptopic = topicsession.createtemporarytopic(); O destino temporário, e todas as mensagens contidas neste, são descartados quando a conexão é fechada.
Destino temporários Confiabilidade JMS Qualquer produtor pode enviar mensagens para um destino temporário, mas apenas consumidores criados sob a mesma conexão podem consumir mensagens deste. Uso comum - sistema requisição-resposta: Cabeçalho: JMSDestination = myqueue JMSReplyTo = tempqueue Cliente JMS tempqueue myqueue Cliente JMS
Confiabilidade JMS Assinaturas duráveis: após criada uma assinatura durável, um ou mais assinantes duráveis (um de cada vez) podem obter a assinatura e recuperar mensagens enviadas antes das suas criações individuais:
Confiabilidade JMS Transações locais (local transactions): uma sessão criada com suporte a transações disponibiliza dois métodos adicionais: mysession.commit( ) - efetiva a transação. mysession.rollback( ) - desfaz operações parciais da transação. Este suporte é simples, porém limitado Não pode ser usado em EJBs, que devem utilizar o mecanismo de transações distribuídas do JEE.
Confiabilidade JMS Em transações cuidado com a ordem das operações: Somente send()s ou receive()s = OK receive()s antes de send()s = OK send() de uma mensagem e após, tentativa de receive() da resposta na mesma transação = deadlock Causa: mensagens enviadas em uma sessão transacional não são de fato enviadas até o commit( )
Confiabilidade JMS Adicionalmente: uma mensagem enviada em uma transação não pode ser consumida na mesma transação. Isto ocorre porque este suporte à transação é local ao contexto de um cliente e um provedor JMS, que intervém entre o send e o receive:
JMS + Enterprise JavaBeans EJB: Qualquer tipo de enterprise bean pode atuar como um cliente JMS: Produzir mensagens. Consumir mensagens de forma síncrona - Consumer.receive( ); Para evitar uso desnecessário de recursos do servidor ( receive nunca satisfeito) utilizar receivenowait( ) ou receive( <timeout-ms> ): while ( ) { /* retorna null se não há mensagem em 10ms */ Message m = myconsumer.receivenowait( 10 );
JMS + Enterprise JavaBeans Por questão de performance recomenda-se realizar o lookup de objetos administrativos (fábricas de conexões e destinos) apenas no método ebjcreate( ) do bean, ao invés de realizar o lookup cada vez em que o objeto for necessário em um método de serviço do bean. É recomendado utilizar o suporte a transações distribuídas do container EJB (container-managed transactions) ou, em caso de requerimentos especiais da aplicação, outro mecanismo, como bean-managed transactions.
É importante JMS + Enterprise JavaBeans liberar os recursos JMS (sessões e conexões) quando não forem mais utilizadas. Se um recurso for utilizado apenas durante um método de negócio do bean, utilizar uma estrutura try-finally dentro do método: // criação de recursos JMS try { // operações que podem jogar exceções } /* opcionalmente: catch { } */ finally { // liberação dos recursos JMS }
JMS + Enterprise JavaBeans Se o recurso for utilizado durante todo o tempo de vida do EJB, é recomendável criar o recurso JMS (sessão ou conexão) no método ejbcreate( ), e destruir o recurso no método ejbremove( ).
Message-Driven Beans Message-Driven Beans - Um MDB é um bean que pode consumir mensagens de forma assíncrona, assim como um message listener: O método onmessage( ) do MDB é invocado quando uma mensagem chega no destino de interesse. O MDB pode registrar interesse em dois destinos: uma fila, ou em uma assinatura durável (tópico). Um MDB não possui interfaces home e remote, sendo constituído apenas de uma classe de bean.
Message-Driven Beans MDB x Session Beans Possui similaridades com Stateless Session Bean Instâncias com tempo de vida curto; Não guarda estado para um cliente específico; Podem ser criadas previamente em uma pool para atendimento de vários clientes; Podem manter alguns recursos em aberto entre requisições: conexões JMS, conexões com BD, referências EJB...
Message-Driven Beans MDB x message listener Um MDB possui algumas diferenças quanto a um message listener: setmessagelistener( ) não é invocado. A associação do MDB com um destino e uma fábrica de conexões é feita em tempo de deploy do bean para o container EJB.
Message-Driven Beans MDB Além de implementar os métodos ejbcreate( ), ejbremove( ) e onmessage( ), o MDB deve implementar o método: void setmessagedrivencontext( MessageDrivenContext ) Este método será invocado uma vez, antes de ejbcreate( ), para fornecer um objeto MessageDrivenContext. Atualmente, MessageDrivenContext = EJBContext.
Message-Driven Beans MDB O MessageDrivenContext fornece um método útil para utilização conjunta com container-managed transactions: void setrollbackonly( ) Este método marca a transação atual como falha, garantindo que ela não receberá commit. Ser invocado pelo MD quando uma exceção for lançada no seu método onmessage( ), garante o rollback da transação distribuída em que este recebimento de mensagem possa estar participando.
Exemplo - message-driven bean: import javax.ejb.*; import javax.naming.*; import javax.jms.*; public class MessageBean implements MessageDrivenBean, MessageListener { Message-Driven Beans private transient MessageDrivenContext mdc = null; private Context context; public MessageBean() { } /* construtor */ public void ejbcreate() { } public void ejbremove() { }
Message-Driven Beans Exemplo - message-driven bean: public void setmessagedrivencontext(messagedrivencontext mdc) { this.mdc = mdc; }
Message-Driven Beans Exemplo - message-driven bean: /* este MDB processa mensagens de texto */ public void onmessage(message inmessage) { TextMessage msg = null; try { if (inmessage instanceof TextMessage) { msg = (TextMessage) inmessage; System.out.println("MESSAGE BEAN: Message + "received: " + msg.gettext()); } else { System.out.println("Message of wrong type: " + inmessage.getclass().getname()); } }
Message-Driven Beans Exemplo - message-driven bean: } catch (JMSException e) { System.err.println("MessageBean.onMessage: " + "JMSException: " + e.tostring()); mdc.setrollbackonly(); /* se transação: falhou */ } catch (Throwable te) { System.err.println("MessageBean.onMessage: " + "Exception: + te.tostring()); }
JMS
Slides antigos
Modelo de Programação JMS Exemplo Obtendo uma Connection Factory: Context ctx = new InitialContext(); QueueConnectionFactory myqueuefact = (QueueConnectionFactory) ctx.lookup("queueconnectionfactory"); Obs.: Invocar InitialContext( ) sem parâmetros resulta na busca pelo arquivo jndi.properties determina o serviço JNDI (LDAP,...) e o espaço de nomes JNDI a ser utilizado para a construção do contexto.
Modelo de Programação JMS JEE Sun Criando destinos (filas e tópicos): j2eeadmin -addjmsdestination <nome JNDI da fila> queue j2eeadmin -addjmsdestination <nome JNDI do tópico> topic obs.: válido para versão 1.3 (revisar nas seguintes) Obtendo um destino no cliente, após criação: Queue myqueue = (Queue) ctx.lookup( Nome JNDI da fila );