Apache Camel: Um guia completo –Parte 3

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (1)  (0)

Evoluindo a solução de pagamento bancário através de novas integrações com sistemas externos.

Fique por dentro
Este artigo apresenta recursos importantes do Apache Camel através da implementação dos requisitos da solução de pagamento bancário. Fundamentado na implementação desses requisitos, será possível constatar as facilidades que o framework oferece para encapsular código complexo capaz de integrar sistemas heterogêneos. Portanto, aqueles que desejam aprender na prática os recursos fundamentais para a construção de um sistema integrado com o auxílio do Apache Camel encontrarão neste artigo códigos valiosos para o alcance desse objetivo.

Na parte 2 desta série de artigos foi apresentado o exemplo prático a ser implementado. Este exemplo consiste na construção de uma solução integradora para pagamento bancário com cartão de crédito via aplicativo mobile. Além disso, os requisitos funcionais e não funcionais que devem ser atendidos também foram indicados, juntamente com o fluxo de negócio a ser seguido.

A partir dessas informações, foi definido que a arquitetura da solução será baseada em componentes com comunicação interna utilizando mensageria no formato JSON, permitindo assim baixo acoplamento, processamento assíncrono, performance, flexibilidade, tolerância a falhas, escalabilidade e baixo custo de manutenção. Ademais, foram apresentados conceitos e funcionalidades básicas do Apache Camel através da implementação do primeiro fluxo de negócio.

Nesta terceira parte, novos recursos do framework serão introduzidos, com destaque para a implementação dos EIPs, de componentes para mensageria e a continuação da codificação do roteamento e manipulação de mensagens visando atender as regras de negócio.

Para exercitar e aprender esses recursos do Camel, os requisitos definidos no artigo anterior continuarão a serem implementados, em sua sequência natural, para que as integrações iniciais com os sistemas externos bancários e de segurança do cartão sejam realizadas ao passo que a arquitetura da solução também é evoluída.

Implementando os requisitos RF-02-SISBAN e RNF-02-SISBAN

Com os primeiros requisitos já atendidos, será iniciada a implementação do RF-02-SISBAN, que menciona que, após receber os dados da requisição de pagamento do Aplicativo Mobile, a Solução de Pagamento Bancário deve enviar o número do cartão e o CPF do titular para o Sistema Bancário para validação, e também do RNF-02-SISBAN, que define que a comunicação com o Sistema Bancário deve ser realizada via mensageria com o formato JSON.

Para atender os novos requisitos, será necessário continuar com o desenvolvimento do componente MobileIntegracao, iniciando pelas alterações na classe MobileIntegracaoRouteBuilder, responsável por definir todas as rotas do respectivo componente. Sendo assim, precisamos alterar a classe MobileIntegracaoRouteBuilder conforme a codificação da Listagem 1.

Listagem 1. Alterações no código da classe MobileIntegracaoRouteBuilder.

  01 package br.com.devmedia.mobile.integracao.rota;
  02 
  03 import org.apache.camel.LoggingLevel;
  04 import org.apache.camel.builder.RouteBuilder;
  05 import org.apache.camel.model.rest.RestBindingMode;
  06 import org.springframework.beans.factory.annotation.Autowired;
  07 import org.springframework.stereotype.Component;
  08 
  09 import br.com.devmedia.mobile.integracao.comum.PagamentoRequisicao;
  10 import br.com.devmedia.mobile.integracao.processor.ConverteParaPagamentoBancarioComumProcessor;
  11 
  12 @Component
  13 public class MobileIntegracaoRouteBuilder extends RouteBuilder {
  14  
  15  private ConverteParaPagamentoBancarioComumProcessor converteParaPagamentoBancarioComumProcessor;
  16  
  17  @Override
  18  public void configure() throws Exception {
  19   
  20   rest("/pagamento").id("rotaEntradaWS")
  21    .description("Serviço para efetuar pagamento bancário")
  22    .consumes("application/json")
  23    .produces("application/json")
  24    .post()
  25    .bindingMode(RestBindingMode.json)
  26    .type(PagamentoRequisicao.class)
  27   .to("seda:postPagamento");
  28   
  29   from("seda:postPagamento")
  30    .log(LoggingLevel.INFO, "[MobileIntegracao] Nova requisição de pagamento bancário")
  31    .process(converteParaPagamentoBancarioComumProcessor)
  32    .setHeader("FLUXO", constant("NOVA_REQUISICAO_PAGAMENTO_BANCARIO"))
  33    .log(LoggingLevel.INFO, "[MobileIntegracao] para [PagamentoBancario] Nova requisição de pagamento bancário")
  34    .to("activemq:queue:PagamentoBancario?deliveryPersistent=false")
  35   .end();
  36  }
  37  
  38  @Autowired
  39  public void setConverteParaPagamentoBancarioComumProcessor(ConverteParaPagamentoBancarioComumProcessor converteParaPagamentoBancarioComumProcessor) {
  40   this.converteParaPagamentoBancarioComumProcessor = converteParaPagamentoBancarioComumProcessor;
  41  }
  42 }

Basicamente, as modificações realizadas foram na rota seda:postPagamento, definida nas linhas 29 a 35, que é uma rota interna responsável por consumir as mensagens enviadas pela rota de entrada (id rotaEntradaWS). Esta última, por sua vez, é a fonte de entrada de dados na Solução de Pagamento Bancário.

Portanto, uma variável de nome converteParaPagamentoBancarioComumProcessor, do tipo ConverteParaPagamentoBancarioComumProcessor, foi declarada na linha 15 e utilizada na linha 31 para que o respectivo processor manipule e trate a mensagem recebida. O processor ConverteParaPagamentoBancarioComumProcessor será desenvolvido nos próximos passos.

Na sequência, a linha 32 define no header da mensagem (Exchange) uma constante de nome FLUXO e valor NOVA_REQUISICAO_PAGAMENTO_BANCARIO para que quando o componente seguinte receber a mensagem consiga identificar de qual fluxo a mesma pertence e, então, tratar e dar o destino correto. Essa abordagem é uma implementação do EIP Content-Based Router.

Adiante, verifica-se na linha 33 a inclusão de log com a mensagem “[MobileIntegracao] para [PagamentoBancario] Nova requisição de pagamento bancário”, para registro do componente de origem e destino da mensagem. Essa abordagem é uma boa prática pois em sistemas componentizados e em cenários de integração é muito importante indicar de onde e para onde a mensagem ou fluxo está caminhando, para que seja fácil a análise posterior.

Finalizando esse trecho, a linha 34 faz de fato o envio da mensagem para uma fila, que, no caso, se chama PagamentoBancario. Para isso é utilizado o componente activemq-camel, que foi previamente configurado no arquivo application-context.xml do componente MobileIntegracao. Ainda nessa mesma linha, observa-se o uso do parâmetro deliveryPersistent, para indicar que as mensagens não precisam ser persistidas em disco quando o servidor de mensageria desligar, pois em nosso cenário não há necessidade de manter as mensagens. Além disso, essa configuração deixará o processo de mensageria mais rápido. Uma dica interessante é que não é preciso criar a fila PagamentoBancario previamente no servidor de mensageria, pois no carregamento da aplicação a mesma é criada automaticamente.

Por fim, as linhas 38 a 41 implementam o método setter da variável converteParaPagamentoBancarioComumProcessor, para que, juntamente com a anotação @Autowired, o Spring faça a injeção e gerenciamento do processor.

Realizadas as modificações em MobileIntegracaoRouteBuilder, é preciso criar o processor ConverteParaPagamentoBancarioComumProcessor, que define a última palavra de sua nomenclatura como Processor para que um padrão seja respeitado com o objetivo de facilitar a identificação de classes desse tipo. Na sequência, será necessário criar o pacote br.com.devmedia.mobile.integracao.processor e implementar a classe ConverteParaPagamentoBancarioComumProcessor, conforme a Listagem 2.

Listagem 2. Código da classe ConverteParaPagamentoBancarioComumProcessor.

  01 package br.com.devmedia.mobile.integracao.processor;
  02 
  03 import java.util.Date;
  04 
  05 import org.apache.camel.Exchange;
  06 import org.apache.camel.Processor;
  07 import org.springframework.stereotype.Component;
  08 
  09 import br.com.devmedia.mobile.integracao.comum.PagamentoBancarioComum;
  10 import br.com.devmedia.mobile.integracao.comum.PagamentoRequisicao;
  11 import br.com.devmedia.pagamento.bancario.conversor.ConversorJson;
  12 import br.com.devmedia.pagamento.bancario.processor.ProcessorUtil;
  13 
  14 @Component
  15 public class ConverteParaPagamentoBancarioComumProcessor implements Processor {
  16  
  17  @Override
  18  public void process(Exchange exchange) throws Exception {
  19   PagamentoRequisicao pagamentoRequisicao = exchange.getIn().getBody(PagamentoRequisicao.class);
  20   PagamentoBancarioComum pagamentoBancario = new PagamentoBancarioComum();
  21   populaPagamentoBancarioComum(pagamentoBancario, pagamentoRequisicao);
  22   ProcessorUtil.setObjetoHeader(exchange, pagamentoBancario);
  23   String json = ConversorJson.converteObjetoParaJson(pagamentoBancario);
  24   exchange.getIn().setBody(json);
  25  }
  26 
  27  private void populaPagamentoBancarioComum(PagamentoBancarioComum pagamentoBancario, PagamentoRequisicao pagamentoRequisicao) {
  28   pagamentoBancario.setIdTransacao(pagamentoRequisicao.getIdTransacao());
  29   pagamentoBancario.setCpfTitularCartao(pagamentoRequisicao.getCpfTitularCartao());
  30   pagamentoBancario.setNumeroCartao(pagamentoRequisicao.getNumeroCartao());
  31   pagamentoBancario.setCodigoSegurancaCartao(pagamentoRequisicao.getCodigoSegurancaCartao());
  32   pagamentoBancario.setDataInicialTransacao(new Date());
  33   pagamentoBancario.setValorCompra(pagamentoRequisicao.getValorCompra());
  34  }
  35 }

Observando a implementação anterior, nota-se que na linha 14 é incluída a anotação @Component para que o Spring consiga fazer a injeção de dependência. Na sequência, a linha 15 declara de fato o processor ConverteParaPagamentoBancarioComumProcessor através da implementação da interface Processor do Camel, isto é, com a implementação dessa interface é que a classe em questão é transformada em um processor. Na linha 18 o método void process(Exchange) é sobrescrito para que a lógica de manipulação de mensagens seja realizada.

Na linha 19, o objeto PagamentoRequisicao, que representa os dados da requisição de pagamento bancário — feita através do web service de entrada da solução — é recuperado, e a partir dele um novo objeto, do tipo PagamentoBancarioComum, é instanciado e populado. Nas seções seguintes, a classe PagamentoBancarioComum será implementada e mais detalhes serão apresentados. Neste momento, saiba que o objetivo com a criação dessa classe é servir como um POJO e trafegar os dados entre os componentes da solução.

Continuando, na linha 21 é invocado o método populaPagamentoBancarioComum(PagamentoBancarioComum, PagamentoRequisicao), cujo objetivo é si" [...]

A exibição deste artigo foi interrompida :(
Este post está disponível para assinantes MVP

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?