domingo, 17 de agosto de 2014

Construindo aplicações móveis híbridas com Apache Cordova, Day 1

INtrodução

Pra quem nunca ouviu falar, Apache Cordova é uma plataforma que permite construir aplicações móveis a partir de código html, css e javascript e executá-las como aplicações nativas em diversos sistemas operacionais, como: iOS, Android, Blackberry, Windows Phone, Palm WebOS, Bada, e Symbian. Se quiser saber mais, visite o site do Apache Cordova.

Instalando o node.js

No momento estou utilizando uma máquina Linux, com a distribuição Ubuntu 14.04 codinome Trusty Tahr, o que torna a instalação do node.js um pouco diferente. O primeiro passo é instalar algumas bibliotecas:

sudo apt-get install g++ curl libssl-dev apache2-utils

Segundo passo, no Linux é necessário compilar o node.js:

Apos baixar e descompactar o tar.gz do node em http://nodejs.org/ entre no diretorio e execute o comando abaixo

sudo make

E por fim, instalá-lo:

sudo make install

Se deu tudo certo, você deverá ser capaz de ver a versão do node.js que acabou de instalar:

node --version

Instalando o Git

Se você ainda não tem o Git instalado, é bom tê-lo

sudo apt-get install git

Instalando o Apache Cordova

Finalmente, vamos a instalação do Apache Cordova. O cordova command-line é distribuído como um pacote npm.

sudo npm install -g cordova
couchbase mongodb oracle mysql db2 java php python scala c# perl erlang find large files on linux shell bash como encontrar aquivo grandes no linux ubuntu fedora redhat centOs mandriva mandrake slackware Ubuntu 14.10 make money dinheiro

sábado, 19 de julho de 2014

How to find large files on Linux

To find all files over 10M use following syntax:
find . -type f -size +10M -exec ls -lh {}\;
couchbase mongodb oracle mysql db2 java php python scala c# perl erlang find large files on linux shell bash como encontrar aquivo grandes no linux ubuntu fedora redhat centOs mandriva mandrake slackware Ubuntu 14.10 make money

quarta-feira, 14 de maio de 2014

ORA-22835: Buffer too small for CLOB to CHAR or BLOB to RAW conversion (actual: %s, maximum: %s)

Se você recebeu essa mensagem bem no meio da sua cara:

ORA-22835: Buffer muito pequeno para conversão de CLOB em CHAR 
ou de BLOB em RAW (real: 7946, máximo: 4000)

ou essa
ORA-22835:  Buffer too small for CLOB to CHAR 
or BLOB to RAW conversion (actual: %s, maximum: %s)

é porque tentou converter um CLOB (com mais de 4 mil caracteres) em CHAR ou um BLOB para RAW. E agora o que fazer?

Simples, a solução é usar o DBMS_LOB.SUBSTR. Conforme exemplo abaixo.

SQL> select dbms_lob.substr(nomedacoluna, 4000, 1) from tabela
ORA-12154 TNS:could not resolve the connect identifier specified Cause: A connection to a database or other service was requested using a connect identifier, and the connect identifier specified could not be resolved into a connect descriptor.

sexta-feira, 4 de outubro de 2013

Como definir configurações de proxy para o console do Node.js

Vai aí uma dica para quem está com dificuldades ao baixar dependências no console no node.js por estar atrás de uma rede com proxy.

No console no node.js digite:

npm config set proxy http://proxy.dominio.com:8080
npm config set https-proxy http://proxy.dominio.com:8080

quarta-feira, 26 de junho de 2013

Porque NoSQL?

Três tendências que rompem com o status quo das bases atuais

Tradução livre do NoSQL Whitepaper +Apache CouchDB 


A maneira como interagimos com as aplicações mudaram drasticamente nos últimos 15 anos. No final dos anos 90 grandes empresas.com (ponto com) surgiram com drásticos requisitos de escalabilidade em diferentes dimensões:


  • O número de usuário simultâneos disparou com a aparição das aplicações web (e logo depois, com os dispositivos móveis) 
  • O montante de dados coletados e processados cresceu com desde de que se tornou interessante para as empresas coletar todos os tipos de dados.
  • O total de dados não-estruturas e semi-estruturas explodiu e tornou-se valioso para as novas aplicações "ricas".

Lidar com estas questões tornou-se cadas vez mais difícil usando bases relacionais. O ponto chave é que as bases relacionais são essencialmente projetadas para rodar em uma única máquina e usa a abordagem de esquema rígido na modelagem dos dados.  

Google, Amazon, Facebook, e o LinkedIn foram as primeiras empresas a descobrir as sérias limitações que as bases de dados relacionais têm para suportar os requisitos das novas aplicações. Alternativas comerciais não existiam no momento, isso os levou a criar uma nova forma de gerenciar seus dados. Seu trabalho pioneiro gerou interesse crescente de companhias com problemas similares. Surgiram projetos NoSQL open-source que ganharam rápida adoção de grandes empresas.

Hoje em dia o uso de opções NoSQL é crescente entre as empresas de internet, e cada vez mais é considerada uma alternativa viável ao uso de bases relacionais, especialmente à medida que as organizações reconhecem a eficácia alcançada com a execução em cluster com servidores padrões e onde a abordagem schema-less é frequentemente uma opção melhor para lidar com a variedade e tipo de dados capturados e processados atualmente.


O que está causando a migração para o NoSQL?

Três assuntos relacionados estão levando a adoção de tecnologias NoSQL: Alto volume da dado, Alto volume de usuários e Cloud Computing.

Alto volume da usuários

A pouco tempo atrás 1.000 usuários/dia para um aplicação era considerado muito, e 10.000 era um caso extremo. Hoje em dia as aplicação mais novas são hospedadas em "nuvens" a disponibilizadas através da internet, essas mesmas aplicações precisam estar disponíveis globalmente 24 horas por dia, 365 dias por ano. Mais de 2 bilhões de pessoas estão conectadas na internet, e o tempo que estas pessoas gastam online é cada vez maior, criando uma explosão de usuários simultâneos para as aplicações. Hoje, não é nada incomum que aplicações tenham bilhões de usuários diferentes.



quarta-feira, 4 de julho de 2012

Gerenciamento de transações - EJB 3

Introdução

Este post trata sobre as duas estratégias de demarcação de transações EJB, CMT (Container Managed Transactions) e BMT (Bean Managed Transactions), bem como os tipos de transações suportadas por estas estratégias.

CMT (Transações Gerenciadas pelo Container)

Este tipo de demarcação pode ser usado tanto por Session Beans como por MDB´s. O uso de transações gerenciadas pelo container simplifica o desenvolvimento por não exigir o controle programático das fronteiras da transação.
Caso não seja definido o tipo de demarcação de transação o bean assumirá CMT como padrão.

BMT (Transações Gerenciadas pelo Bean)

Este tipo de demarcação mesmo oneroso para implementação, tem um bom motivo para existir. Há uma limitação quanto aos Beans Gerenciados por Container. Um método quando executado, só pode ser associado a uma única transação ou nenhuma.
Caso essa limitação da CMT seja um problema para sua aplicação, ou você precise de um controle mais fino das transações, esta é a melhor estratégia.
Abaixo, um pseudo-código que ilustra o uso da BMT:
begin transaction
...
    update usuario
...
    if (condicao1) {
         commit transaction
    } else if (condicao2) {
         update perfil
         commit transaction
    } else {
         rollback transaction
         begin transaction
         update funcionalidade
         commit transaction
     }

Anotação @TransactionManagement

Essa anotação define qual dos dois tipos de demarcação acima, seu bean irá usar. Ela pode assumir os seguintes valores:

@TransactionManagement(TransactionManagementType.BEAN)
@TransactionManagement(TransactionManagementType.CONTAINER)

Anotação @TransactionAttribute

Embora o container faça a maior parte do trabalho, no CMT você ainda precisa definir de que forma seus métodos usarão uma transação.
Por exemplo, imagine que você tem um método que consulta determinados valores. Talvez este método não precise criar uma nova transação para ser executado, neste caso você usaria a anotação com o atributo SUPPORTS, que informa ao seu container que nenhuma transação é usada neste método, mas se já existir uma o método irá usá-la.
A anotação @TransactionAttribute pode assumir os seguintes valores:
  • REQUIRED
  • REQUIRES_NEW
  • SUPPORTS
  • MANDATORY
  • NOT_SUPPORTED
  • NEVER

REQUIRED

Se uma transação já estiver sendo executada quando o método em questão for invocado, o método é executado usando a mesma transação. Caso contrário é criada uma nova transação antes da execução do método.
O Atributo REQUIRED é assumido como padrão para os métodos que não definem explicitamente a anotação @TransactionAttribute.

REQUIRES_NEW

Esse atributo é usado quando queremos garantir que determinado método será executado em uma nova transação. Quando um método que possui este atributo de transação é invocado, o container executa os seguintes passos:
  1. A transação atual é suspensa.
  2. É criada uma nova transação
  3. O método é invocado
  4. O método invocado realiza o commit ou rollback desta nova transação
  5. A transação anterior é retomada

SUPPORTS

Caso já exista uma transação ativa no momento que o método for invocado, este método é executa dentro desta mesma transação. Caso contrário o container executa o método sem criar uma nova transação.

MANDATORY

Métodos com este tipo de anotação exigem que já haja uma transação ativa, caso contrário o container lançará uma exceção javax.ejb.EJBTransactionRequiredException.

NOT_SUPPORTED

Ao invocar um método com este tipo de atributo de transação o container realiza os seguintes passos:
  1. Caso haja uma transação ativa ela será suspensa
  2. Executa o método fora de qualquer contexto transacional
  3. Assim que o método retornar a transação suspensa será retomada

NEVER

Métodos que utilizam este atributo não podem ser invocados em um contexto transacional, caso contrário será lançada uma exceção javax.ejb.EJBException.

sexta-feira, 29 de junho de 2012

HornetQ, middleware orientado a mensagens ( JBoss | Filas | JMS )


+JBoss Community release announcements 


Imagine que você precisa de um notebook novo e resolve comprar em algum destes famosos sites de compras online. Com certeza você já deve ter reparado que ao efetuar o pagamento com cartão de crédito a cobrança não é autorizada instantaneamente. Ao invés disso, o site registra sua compra e pede para que você aguarde um e-mail com a confirmação de pagamento. Simplificando, um dos motivos disso ocorrer, é porque o site perderia muitas vendas se o cliente tivesse que aguardar com a tela de cobrança aberta até a confirmação do pagamento. Outro motivo está relacionado ao fato de ser inviável manter uma sessão aberta por um período de tempo que você não tem como mensurar, por exemplo, o pagamento poderia ser confirmado em uma hora em dias de alto tráfego, enquanto em dias normais poderia ser confirmado em apenas dois minutos.
O passo a passo dessa solução é até bem simples. Quando o usuário finaliza a compra de determinado produto, o sistema irá salvar um registro com o status de “aguardando confirmação de pagamento”, por exemplo. Logo após, é enviada uma mensagem ao servidor da operadora de cartões, informando os dados do pagamento. Assim que a operadora de cartões retorna a mensagem confirmando o pagamento, o status da solicitação é modificado e um e-mail com a confirmação é enviado ao cliente.
Como ponto chave desta solução temos o uso da API JMS (Java Message Service) e o HornetQ (middleware orientado a mensagens). A seguir veremos passo a passo os fundamentos e as tecnologias que garantem o bom funcionamento desta solução.

Middleware orientado a Mensagens (MoM)

Para explicar como funciona um middleware orientado a mensagens é interessante lembrar como funciona um outro modelo, o middleware baseado em RPC (Remote Procedure Call). Para isso, considere uma conversa via rádio entre duas pessoas, João e José. Nesta conversa, João escuta pacientemente enquanto José conclui sua ideia, para em seguida responder. Assim funciona o modelo RPC, baseando-se em requisições e respostas.
Na Listagem 1 temos um método simples, que processa a saída de produtos do estoque de uma loja. Imagine que o primeiro passo deste método (verificarEstoque) realize uma chamada a um EJB remoto, que por algum motivo demore bastante tempo para responder. Os passos 2 e 3 só serão executados após o retorno do primeiro método, neste cenário há uma integração com um sistema que controla o estoque feita de forma síncrona (neste caso utilizando RMI, um exemplo de tecnologia que utiliza o modelo RPC).

Listagem 1: Exemplo de um método com camadas síncronas.
public class MovimentacaoBean {
    public void processarSaida(Movimentacao movimentacao) {
     verificarEstoque(movimentacao);         //Passo 1
 verificarPagamento(movimentacao);       //Passo 2
 disponibilizarParaEnvio(movimentacao);   //Passo 3
    }
}
Diferente do modelo RPC, um middleware orientado a mensagens é como um serviço de e-mail. Quando quer se comunicar com alguém você envia um e-mail e continua fazendo as coisas que tem para fazer, sem ter que parar para aguardar por uma resposta. Note que essa comunicação através de e-mail ocorreu de forma assíncrona, isto é, sem interromper as atividades do remetente.

Neste artigo exploraremos o Middleware Orientado a Mensagens chamado HornetQ, projeto 100% open-source, licenciado sob a Apache Software License v2.0. Por curiosidade, este projeto já foi chamado de JBoss Messaging e JBossMQ. O HornetQ pode ser executado de algumas formas distintas, dentre elas: embutido no JBoss Application Server, embutido na sua aplicação ou stand-alone.
Para todos os exemplos daqui em diante, usaremos os termos “Produtor” para nomear o remetente da mensagem e “Consumidor” para o destinatário.

Estilos de Mensagens

Existem dois padrões principais para troca assíncrona de mensagens, são eles: Ponto-a-Ponto (Queue) e Publicação-Assinatura (Publish Subscribe), descritos a seguir.

Ponto-a-Ponto (Queue)

Neste padrão as mensagens são enviadas para uma fila, onde geralmente serão persistidas a fim de garantir sua entrega. Algum tempo depois o middleware envia a mensagem para o consumidor. Essa mensagem será processada e o consumidor enviará uma confirmação de recebimento de volta. Quando a confirmação chegar, a mensagem correspondente é removida da fila e não estará mais disponível para ser entregue novamente. Caso o sistema falhe antes da confirmação de recebimento, essa mensagem continuará disponível na fila até que a entrega seja realizada com sucesso.
No padrão ponto-a-ponto pode haver diversos consumidores em uma fila, porém cada mensagem só pode ser entregue a um único consumidor.
Figura 1. Exemplo do modelo de mensagens Ponto-a-Ponto.




  • Cada mensagem possui um único Consumidor
  • Não há acoplamento entre Produtor e Consumidor
  • O Consumidor envia uma confirmação ao receber a mensagem

Publicação-Assinatura (Publish-Subscribe)

No padrão publicação-assinatura há uma diferença no nome dos papéis. Aqui, quem consome as mensagens é chamado de Assinante, e ao invés de uma Fila temos um Tópico.
Podemos fazer uma comparação deste modelo com um fórum, onde alguém publica uma mensagem em um tópico pré-definido, e esta mensagem é recebida por todas as pessoas vinculadas a este tópico.
No padrão Publicação-Assinatura muitos Produtores podem enviar mensagens a um Tópico, e em cada Tópico pode haver diversos Assinantes. Todos os Assinantes de um Tópico recebem uma cópia de cada mensagem, neste padrão as mensagens podem ser opcionalmente duráveis. Deste modo, estas mensagens serão retidas no Tópico para que cada novo Assinante receba todas as mensagens já publicadas.
Em caso de falha do sistema, as mensagens não duráveis existem somente durante o tempo de vida da conexão que as criou.
Figura 2. Exemplo do modelo de mensagens Publicação-Assinatura.




Consumindo Mensagens

Mensagens são inerentemente assíncronas. Não há nenhuma dependência fundamental entre o Produtor e o Consumidor de uma mensagem. No entanto, a especificação JMS usa esse termo em um sentido mais preciso. As mensagens podem ser consumidas de duas maneiras:
  • De forma síncrona: Um Assinante ou Consumidor busca explicitamente uma mensagem no destino (fila ou tópico). Esta busca é realizada por determinado método criado pelo programador. Este método pode aguardar a chegada de uma mensagem por um período determinado de tempo;
  • De forma assíncrona: Um Assinante ou Consumidor é criado como um “observador” (vide design pattern Observer) de um destino (fila ou tópico). Então, logo que uma mensagem chega ao destino o Listener processa a mensagem. O consumo de mensagens por esta forma pode ser obtido através de JMS Message Listeners ou Message Driven Beans (MDBs).
Listagem 2: Exemplo de um Message Driven Bean com uso de anotações: PagamentoBean.java
@MessageDriven(activationConfig = { 
 @ActivationConfigProperty(
  propertyName = "destinationType", 
  propertyValue = "javax.jms.Topic"
 ) 
})
public class PagamentoBean implements MessageListener {
    
 public void onMessage(Message msg) {
  ...
    }
}
Listagem 3: Exemplo de um Message Driven Bean sem uso de anotações: PagamentoBean.java
public class PagamentoBean implements MessageListener {
    public void onMessage(Message msg) {
     ...
    }
}

Listagem 4: Exemplo do mapeamento do Message Driven Bean através do descritor de implantação: ejb-jar.xml

 
  
    PagamentoBean 
   br.com.exemplo.PagementoBean
   javax.jms.MessageListener
   Container
   javax.jms.Topic
   
    
     destinationType
     javax.jms.Topic
    
   
  
 

Garantia de Entrega

Um dos principais benefícios que se pode ter com o uso de mensagens é a garantia de entrega. Assim temos a certeza de que cada mensagem será entregue uma e somente uma vez para cada Consumidor de uma fila ou o Assinante receberá todas as mensagens duráveis de um Tópico, mesmo que o sistema falhe.

Tipos de Mensagem

A API JMS define cinco tipos de mensagens.
Tipo de Mensagem Conteúdo
TextMessage Um objeto java.lang.String. Este tipo de mensagem é usado para transportar textos planos e XML.
MapMessage Um conjunto de pares chave-valor, onde a chave é um objeto do tipo String e o valor pode ser um objeto serializável ou um tipo primitivo. A ordenação das entradas no mapa não é mantida.
BytesMessage Um stream de bytes. Normalmente usado para enviar objetos ou tipos primitivos.
StreamMessage Um stream de tipos primitivos. Preenchido e lido sequencialmente.
ObjectMessage Objetos serializáveis.

Instalando o HornetQ

Pré-requisitos

  • Java 6
  • JBoss AS 5.x
  • Ant
  • Libaio (para ambientes Linux)

Instalação

Neste artigo instalaremos o HornetQ embutido no JBoss Application Server 5.x.
É importante que você tenha o Ant instalado em sua máquina e que a variável de ambiente JBOSS_HOME tenha sido definida apontando para a instalação do JBoss AS 5.x.
Baixe o HornetQ 2.1.2.Final do site do projeto (jboss.org/hornetq/downloads.html). Decompacte, e no diretório hornetq-2.1.2.Final\config\jboss-as-5 execute o arquivo build.bat. Este script irá criar dois profiles novos no JBoss AS, um chamado default-with-hornetq (baseado no profile default), e outro chamado all-with-hornetq (baseado no profile all).

Exemplo de mensagens Ponto-a-Ponto

Vamos criar o primeiro exemplo e ver como funciona a troca de mensagem Ponto-a-Ponto na prática. No eclipse crie um projeto EJB com a seguinte estrutura.
Figura 3. Estrutura do projeto.





Listagem 5: Produtor de Mensagem (Cliente MDB): PagamentoMDBClient.java
package br.com.exemplo.mdb.client;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;

public class PagamentoMDBClient {

  public static void main(final String[] args) throws Exception {
    Connection connection = null;
    InitialContext initialContext = null;

    try {
      // Passo 1. Cria o contexto inicial para executar o JNDI lookup
      initialContext = new InitialContext();

      // Passo 2. Busca uma fila de mensagens
      Queue queue = (Queue) initialContext.lookup("/queue/testQueue");

      // Passo 3. Busca uma ConnectionFactory
      ConnectionFactory cf = (ConnectionFactory) initialContext
          .lookup("/ConnectionFactory");

      // Passo 4.Cria uma conexão JMS
      connection = cf.createConnection();

      // Passo 5. Cria uma Sessão JMS
      Session session = connection.createSession(false,
          Session.AUTO_ACKNOWLEDGE);

      // Passo 6. Cria um Produtor de mensagens JMS
      MessageProducer producer = session.createProducer(queue);

      // Passo 7. Cria uma mensagem do tipo Objeto
      TextMessage message = session.createTextMessage("testando 123");

      System.out.println("Mensagem enviada: " + message.getText());

      // Passo 8. Envia a mensagem
      producer.send(message);

      // Passos 9, 10, 11 e 12 no PagamentoMDB
    }
    finally {
      //Passo 13. Libera os recursos utilizados
      if (initialContext != null) {
        initialContext.close();
      }
      if (connection != null) {
        connection.close();
      }
    }
  }
}

Listagem 6: Consumidor de mensagem: PagamentoMDB.java
package br.com.exemplo.mdb;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import org.jboss.ejb3.annotation.ResourceAdapter;

@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
    @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue") })
@TransactionManagement(value = TransactionManagementType.CONTAINER)
@TransactionAttribute(value = TransactionAttributeType.REQUIRED)
@ResourceAdapter("hornetq-ra.rar")
public class PagamentoMDB implements MessageListener {

  public void onMessage(final Message message) {
    try {
      // Passo 9. A mensagem genérica é convertida em uma mensagem de texto
      TextMessage textMessage = (TextMessage) message;

      // Passo 10. O teor da mensagem é recuperado
      String texto = textMessage.getText();

      System.out.println("Mensagem recebida: " + texto);
    }
    catch (JMSException e) {
      e.printStackTrace();
    }
  }
}
Listagem 7: Contexto JNDI para execução do Cliente EJB: jndi.properties
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
Após executar o código do cliente ejb, recebemos a seguinte saída no console do eclipse.

Figura 4. Resultado da execução do produtor de mensagem.




No exemplo mostrado, tanto o Produtor como o Consumidor de mensagens poderiam funcionar como um EJB Stateless ou um POJO.
Neste ponto você deve estar pensando: “Mas eu poderia enviar um objeto ao invés de uma simples mensagem de textual?”, pode sim. Vamos fazer algumas alterações em nossas classes e ver como ficaria um código mais perto da realidade do nosso negócio.

Listagem 8: Produtor de mensagem: PagamentoMDBClient.java
// Passo 7. Cria uma mensagem do tipo Objeto     
Pagamento pagamento = new Pagamento();
pagamento.setCpf("99999999999");
pagamento.setValor(new BigDecimal("1899"));
      
ObjectMessage message = session.createObjectMessage(pagamento);
Note que nesta classe alteramos apenas o passo nº 7, instanciando uma entidade de negócio do nosso sistema, logo criamos uma mensagem do tipo ObjectMessage.

Listagem 9: Consumidor de mensagem: PagamentoMDB.java
public void onMessage(final Message message) {

    try {
      ObjectMessage objectMessage = (ObjectMessage) message;
      Pagamento pagamento = (Pagamento) objectMessage.getObject();
      System.out.println(pagamento.getCpf());
    }
    catch (JMSException e) {
      e.printStackTrace();
    }
  }
No código do Consumidor fizemos um cast de Message para ObjectMessage e invocamos o método getObject() para recuperar o objeto enviado pelo Produtor.
Lembre-se que o envio de objetos requer que eles sejam serializáveis, ou seja, implementem a interface java.io.Serializable.

Modos de Confirmação

Até que o middleware receba a confirmação da recepção da mensagem por parte do Consumidor, essa mensagem permanece armazenada na fila, ou no tópico em caso de mensagens duráveis. O consumo ou recepção de uma mensagem só é considerado bem sucedido após os três passos a seguir:
  1. O Consumidor recebe a mensagem;
  2. O Consumidor processa a mensagem;
  3. A mensagem é confirmada.
Em uma sessão onde há um contexto transacional, a mensagem é confirmada automaticamente logo que a transação é finalizada. Do contrário todas as mensagens serão reenviadas caso a transação seja desfeita.
Já em sessões onde não há transação, o modo como a confirmação será enviada depende do parâmetro especificado no método createSession().

A especificação JMS define três modos de confirmação:
AUTO_ACKNOWLEDGE, CLIENT_ACKNOWLEDGE e DUPS_OK_ACKNOWLEDGE. Entretanto a implementação do HornetQ acrescentou mais um modo, chamado PRE_ACKNOWLEDGE.

Listagem 10: Trecho de código onde é especificado o modo de confirmação
// Passo 5. Cria uma Sessão JMS
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
  • Session.AUTO_ACKNOWLEDGE: A sessão confirma automaticamente o recebimento da mensagem assim que o método chamado no receptor retorna. Por exemplo, em um MessageListener a mensagem será confirmada após o retorno do método onMessage();
  • Session.CLIENT_ACKNOWLEDGE: A confirmação é feita em nível de sessão, logo, se em uma sessão o Consumidor receber dez mensagens e confirmar uma delas, todas serão confirmadas no servidor;
  • Session.DUPS_OK_ACKNOWLEDGE: Neste modo a confirmação das mensagens é feita em lotes, configurado por tamanho no arquivo hornetq-jms.xml. Assim que o lote atinge o tamanho configurado, as mensagens são enviadas. Não há garantia de que a mensagem será entregue somente uma vez. Como as confirmações são enviadas em lote, entre um envio e outro o servidor pode falhar, e as mensagens serão reenviadas ao consumidor;
  • HornetQSession.PRE_ACKNOWLEDGE: Em alguns casos não é importante para o negócio do sistema que todas as mensagens sejam entregues, e você não se importa caso alguma mensagem se perca em caso de falha no servidor. Neste modo as mensagens são confirmadas antes que sejam enviadas ao consumidor.

Mensagens Agendadas

As mensagens agendadas diferem das normais pelo fato de que não serão entregues até que o horário determinado para entrega tenha sido atingido.
Para agendar mensagens a propriedade _HQ_SCHED_DELIVERY (ou a constante Message.HDR_SCHEDULED_DELIVERY_TIME) deve ser definida antes do envio da mensagem. Segue o código que exemplifica o agendamento de entrega das mensagens.
Listagem 11: Mensagens Agendadas
TextMessage mensagem =
session.createTextMessage("Esta mensagem será entregue em 5 segundos");

mensagem.setLongProperty(Message.HDR_SCHEDULED_DELIVERY_TIME.toString(), 
System.currentTimeMillis() + 5000);
produtor.send(message);

Paginação

O HornetQ suporta filas com milhões de mensagens mesmo que o servidor esteja funcionando em um hardware com uma quantidade limitada de memória principal. Este comportamento vem desabilitado por padrão, e em alguns casos é possível que suas filas de mensagens atinjam um tamanho significativo em sua memória.
Para evitar este risco e fazer com que nosso middleware opere com baixo uso de memória, configuraremos a paginação definindo o uso máximo de memória. Assim, sempre que este limite for atingido, nosso middleware passará a paginar as mensagens em disco.
As mensagens são armazenadas em uma pasta individual por endereço, contendo vários arquivos com mensagens. Cada arquivo armazena uma quantidade configurável de mensagens, especificada pela propriedade page-size-bytes.

Configuração

Os parâmetros globais para paginação são configurados no arquivo hornetq-configuration.xml.
Listagem 12: Configuração do arquivo hornetq-configuration.xml.

...
${jboss.server.data.dir}/hornetq/paging
...
Ainda no arquivo hornetq-configuration.xml, vamos definir as configurações por endereço.
Listagem 13: Configuração do arquivo hornetq-configuration.xml.
 
  
   104857600
   10485760
   PAGE
  
 

Lista de parâmetros de paginação, por endereço

Nome da propriedade Descrição Valor padrão
max-size-bytes -1 (desabilitado)
page-size-bytes Tamanho de cada arquivo de paginação. 10MB (10 * 1024 * 1024 bytes)
address-full-policy Ativa o modo de paginação caso o valor seja definido como PAGE. Possui ainda dois outros valores: DROP, as mensagens serão descartadas silenciosamente; e BLOCK, o produtor será impedido de enviar novas mensagens. PAGE

HornetQ em modo Bridge

Em alguns casos o Provedor JMS de destino pode estar em um nó diferente do produtor de mensagens, obrigando que sejam criados vínculos com conexões através da WAN, por vezes não confiáveis.
Caso não haja conexão com o destino no momento do envio, o lógica terá que ser interrompida até que a conexão seja reestabelecida. Como o foco do desenvolvedor deve ser no negócio do sistema e não o controle dos recursos, delegamos ao HornetQ este trabalho.

Figura 5. HornetQ em modo Bridge.





Neste caso é ideal que haja uma instância do HornetQ no Nó do Produtor de mensagens, configurado em modo bridge. Assim, as mensagens serão enviadas ao Bridge e armazenadas. Quando a conexão com o Destino for estabelecida as mensagens serão enviadas.

Conclusões

Neste artigo através de um simples exemplo de compra através da internet, foi apresentado um resumo de como funciona o mundo dos middlewares orientados a mensagem e a API JMS, mesclando o uso de funcionalidades e configurações do middleware. Daqui para frente, ainda á dezenas de temas a serem abordados, como segurança, transações, tipos de mensagens. O empacotamento do HornetQ fornece uma série de outros exemplos para os cenários mais distintos, com um pouco de curiosidade é possível ir muito além desta introdução.

Links

Tutorial Java EE 5
HornetQ 2.1.2 QuickStart
HornetQ 2.1.2 Manual do Usuário