aplicando padrões eai com spring integration...configurando o projeto » no projeto dentro da pasta...

15
5 \ capa_ Aplicando padrões EAI com Spring Integration Saiba como desenhar uma solução completa utilizando padrões EAI com o Spring Integration Giuliano Bem Hur Firmino | giulianofi[email protected] especialista em Engenharia de Software pelo Instituto da Computação da Unicamp e certificado pela Sun (SCJP). Atua na área de desenvolvimento de softwares há 12 anos. Com a plataforma JAVA nos ambientes Web, Mobile e Enterprise. Aplicações raramente vivem isoladas, normalmente são desenvol- vidas para se comunicar com outras aplicações, banco de dados, sistemas de mensagem, sistemas legados e até mesmo com redes sociais. Como lidar com os desafios que essas integrações oferecem? EAI propõe uma forma abstrata e prática de lidar com esses desa- fios, através de padrões. E o Spring Integration se propõe a imple- mentar esses padrões de forma simples, sem a necessidade de gran- des mudanças no processo de desenvolvimento.

Upload: dangdiep

Post on 25-Jan-2019

212 views

Category:

Documents


0 download

TRANSCRIPT

5 \

capa_

Aplicando padrões EAI com Spring Integration

Saiba como desenhar uma solução completa utilizando padrões EAI com o Spring Integration

Giuliano Bem Hur Firmino | [email protected] em Engenharia de Software pelo Instituto da Computação da Unicamp e certificado pela Sun (SCJP). Atua na área de

desenvolvimento de softwares há 12 anos. Com a plataforma JAVA nos ambientes Web, Mobile e Enterprise.

Aplicações raramente vivem isoladas, normalmente são desenvol-vidas para se comunicar com outras aplicações, banco de dados, sistemas de mensagem, sistemas legados e até mesmo com redes sociais. Como lidar com os desafios que essas integrações oferecem? EAI propõe uma forma abstrata e prática de lidar com esses desa-fios, através de padrões. E o Spring Integration se propõe a imple-mentar esses padrões de forma simples, sem a necessidade de gran-des mudanças no processo de desenvolvimento.

/ 6

EAI (Enterprise Application Integration)O termo EAI já existia dede o início de 2000,

mas o problema que ele se propõe a resolver é mui-to antigo, vem desde os primórdios da computação, quando nos deparamos com a necessidade de fazer aplicações se comunicarem.

Podemos resumir a integração entre uma apli-cação e outra como uma conversa. Se ela não for conduzida em uma determinada linguagem e em um determinado padrão, o que chamamos protocolo de comunicação, não há diálogo.

Hoje temos basicamente as seguintes formas de comunicação entre aplicações:

» file transfer: aplicações transferem ou dis-ponibilizam, em local comum, arquivos para que outras aplicações possam ler.

» shared database: aplicações acessando um ou mais banco de dados em comum, com in-tuito de compartilhar informações.

» remote procedure call: aplicações aces-sando outras aplicações através de chamadas remotas. Abrangendo diversas tecnologias, como CORBA, RMI e WebService.

» messaging: aplicações enviando mensagens a outras aplicações.

Em uma arquitetura empresarial, tende a existir diversos sistemas e aplicações, para atender a diver-sos departamentos e serviços que uma empresa pode oferecer e consumir. É muito comum que todos esses recursos estejam distribuídos dentro da organização. No entanto para obter os benefícios desse tipo de distribuição, é necessário se preocupar com a forma com que essas aplicações se integram.

Hoje temos os seguintes tipos de integrações en-tre aplicações.

» point-to-point: neste tipo de integração as conexões são feitas de forma direta. A vanta-gem é que o mesmo atende bem necessidades pontuais, dentro de uma arquitetura pequena. A desvantagem ocorre quando queremos au-mentar o número de aplicações participantes, neste caso, temos um aumento exponencial do número de conexões. Veja um exemplo na figura 1.

Figura 1. Tipo de integração Point-to-Point.

» hub and spoke: todas as aplicações se co-municam através de um mediador e é esse mediador que se comunica com as outras apli-cações. A vantagem é que todas aplicações se convergem em uma só conexão, simplificando a manutenção e o gerenciamento das cone-xões. A desvantagem é justamente pelo fato de centralizar todas as conexões, pois quando o serviço fica indisponível, todas as aplicações sofrem com isso. Veja um exemplo na figura 2.

Figura 2. Tipo de integração Hub and Spoke.

Diferentemente do que parece, EAI não trabalha diretamente com nenhum dos tipos de integrações mencionados acima, tão pouco atende especifica-mente a alguma forma de comunicação existente. EAI possui simplesmente uma notação genérica e baseada em padrões. Cada framework/ferramenta/plataforma implementa a especificação de EAI da forma que lhe convir. Existe um padrão dentro da es-pecificação EAI, por exemplo, chamado Message Bus que visa representar uma boa prática de integração entre aplicações (Hub and Spoke, mencionado ante-riormente), veja como funciona o mesmo na figura 3. Esse padrão foi responsável pelo surgimento de di-versas interpretações, nomeadas de ESB (Enterprise Service Bus).

Figura 3. Exemplo de funcionamento do padrão Message Bus.

applIcatIon

applIcatIon

applIcatIonmEssaGE

bus

7 \

O Framework Spring IntegrationSpring Integration é uma extensão do Spring

(framework de inversão de controle) que possibilita a utilização da notação EAI de forma declarativa e/ou programática.

O mesmo disponibiliza uma interface de inte-gração com os adaptadores do Spring, abstraindo a complexidade de acessar vários tipos de plataformas, sistemas, tecnologias e protocolos como HTTP, TCP/UDP, Banco de Dados, Arquivos, FTP, RMI, JMS, e--mail, até a redes sociais, como Twitter, possibilitan-do ainda reaproveitar e acessar outros tipos de recur-sos externos através de serviços customizados.

No Spring Integration podemos observar os se-guintes elementos para utilização de EAI, acompa-nhando na figura 4.

» data: representa os dados a serem processa-dos.

» message: no Spring Integration, é formada por Header (cabeçalho) e Payload (corpo) confor-me a ilustração da figura 5. No Header pode-mos trafegar informações adicionais que serão usadas para tomada de decisões no fluxo, e no corpo estão os dados propriamente ditos.

mEssaGE

hEadEr

payload

Figura 5. Estrutura da mensagem.

» message channel: é o canal de comunicação de mensagens. Um canal possui duas pontas, por onde as mensagens trafegam:

» Entrada: por onde os produtores enviam as mensagens.

» saída: por onde os receptores conseguem resgatar as mensagens enviadas pelos pro-dutores.

Os canais ainda podem ser categorizados de duas formas:

» handoff: que podem ser síncronos, ou seja, a mensagem é recebida diretamente pelo receptor. Ou assíncronos, ou seja, a men-sagem é armazenada no canal antes de ser enviada ao receptor.

» delivery: que podem ser point-to-point, ou seja, um produtor envia uma mensagem diretamente para um receptor ou publish--subscribe, onde um produtor envia uma mensagem e N receptores podem se inscre-ver para receber a mesma mensagem.

» message Endpoints: são todos os componen-tes que efetivamente sabem receber/manipu-lar/enviar as mensagens. São divididos basica-mente em Gateway, Sevice Activator, Router, Splitter e Aggregator. Os mesmos serão deta-lhados no decorrer da explicação da implemen-tação do projeto de exemplo a seguir.

Diferentemente de muitas das soluções de mer-cado, Spring Integration não é considerado um ESB, pois não é baseado no padrão Message Bus. Mas por se tratar de um framework robusto, provê uma boa base para implementação do mesmo.

Projeto de exemploMeu intuito é mostrar não só os padrões EAI e

como utilizá-los no Spring Integration, mas um exemplo prático e funcional de aplicação dos prin-cipais padrões de integração em um cenário fictício, mas suficientemente complexo que será explorado abaixo.

HistóriaGrandes empresas varejistas e atacadistas ainda

aceitam um grande volume de cheques diariamente de seus clientes. O banco Sua Poupança vendo um ni-cho de mercado ainda pouco explorado, decide criar um novo produto e atrair esses clientes. Sabendo do trabalho que estas empresas têm em depositar esse grande volume de cheques, decide criar um processo que facilite este trabalho.

Figura 4. Elementos básicos da notação EAI.

sEndEr applIcatIon rEcEIvEr applIcatIon

mEssaGE EndpoInt

mEssaGE EndpoInt

mEssaGE data channEl data

/ 8

ProblemaPara atender essa quantidade de cheques, hoje

o banco conta com profi ssionais que avaliam um a um os cheques os separando e os enviando através de malotes para os respectivos bancos. Esse processo é lento e também envolve a burocracia do banco de destino. Ao fi nal o banco de destino envia os dados confi rmando o débito na conta do cliente. O tempo total do depósito do cheque gira em torno de 5 dias.

Solução de negócioEsses cheques são na grande maioria preenchi-

dos por impressoras nos caixas, por isso são passíveis de serem lidos sem a necessidade de intervenção hu-mana.

Para a leitura automática dos cheques, foram en-contradas várias opções de impressoras que conse-guem processar centenas de cheques por minuto, ge-rando imagens de qualidade e capturando dados via OCR. Essas impressoras seriam disponibilizadas para os clientes para que os mesmos possam enviar mais rapidamente as imagens e os dados dos cheques atra-vés de um serviço a ser disponibilizado para o mes-mo. Este serviço por sua vez, agruparia os cheques por banco e os enviaria aos bancos que já possuem uma política de recebimento de cheques digitaliza-dos. A previsão é que o tempo do depósito de cheques desses clientes caia para 2 dias.

Solução técnicaEsse processo é um tanto complexo, pois envol-

ve integração com várias tecnologias, então a equipe

de negócio pede a equipe de Arquitetura que dese-nhe a solução e escolha a melhor forma de resolver o problema. Em uma reunião, a equipe de arquitetura chegou a conclusão que seriam necessárias duas apli-cações, para atender a solução. A fi gura 6 mostra o diagrama de arquitetura levantado.

1. Uma aplicação Desktop que irá capturar as imagens “scaneadas” e dados extraídos dos cheques, através do OCR presente no scanner de cheques. Esses cheques formarão um lote a ser enviado ao serviço Web a ser desenvolvido. Um lote pode possuir N cheques e depende da capacidade do scanner de cheques.

2. Serviço Web que irá separar os cheques e en-viá-los a seus respectivos bancos de destino. Os únicos bancos que possuem serviços que recebem e processam cheques digitalizados é o Banco do Povo e o Banco de Todos. O Banco do Povo disponibiliza um servidor FTP para enviar os dados e as imagens dos cheques e o Ban-co de Todos disponibiliza um servidor de fi las para enviar os dados via remessa, com todas as imagens e informações dos cheques. O serviço precisará acessar um componente EJB que está em outro servidor, para buscar informações do cliente (benefi ciário) uma vez que só será en-viado o código do mesmo.

Para desenvolver o serviço Web, foi optado pelo framework Spring Integration e para chegar nessa decisão, foram considerados os seguintes critérios:

» A integração deve ser feita de forma menos tra-balhosa e mais fl exível possível, uma vez que as tecnologias podem mudar, o número de clien-

Figura 6. Diagrama de arquitetura da solução.

9 \

tes pode aumentar e, no futuro, o número de bancos atendidos também pode aumentar.

» Ser open-source, pois há um risco de investir em ferramenta e treinamento e a solução não ter o retorno esperado.

» Desenvolver uma versão piloto no menor tem-po possível, pelo mesmo motivo do item ante-rior.

» Aproveitamento da equipe de desenvolvimen-to, pelo mesmo motivo do item anterior.

» Aproveitar a infraestrutura já existente, pelo mesmo motivo do item anterior.

Configuração de Ambiente » Maven 3.0.4 » Plugin do eclipse “Maven Integration for Eclip-

se” » Plugin do eclipse “Spring Tool Suite for Eclip-

se”

Criando o projeto » Crie um novo workspace. » Clique com botão direito e selecione “New” >

“Other...”. » Selecione “Maven” > “Maven Project” e clique

em “Next >”. » Em “New Maven Project”, “Select project name

and location”, marque a opção “Create a single project (skip archetype selection)” e clique em “Next >”.

» Em “New Maven Project”, “Enter a group id and the artifact”, preencha os campos “Group Id” e “Artifact Id”, selecione “war” em “Packaging” e clique em “Finish”.

Configurando o projeto » No projeto dentro da pasta “src/main/webapp”,

crie a pasta “WEB-INF” e em seguida o arquivo “web.xml”.

» Como nosso projeto disponibilizará um serviço Web, devemos criar o arquivo “web.xml” que fi-caria conforme a Listagem 1.

» Por se tratar de um projeto Spring não pode-ria faltar o arquivo de configuração do mesmo, veja na Listagem 2 o básico para o projeto fun-cionar. Iremos explicar a configuração do ar-quivo “spring-integration.xml” no decorrer da explicação.

» No arquivo pom.xml adicione a dependência conforme a Listagem 3, para que o projeto fun-cione com o Spring MVC, Spring Integration e como o serviço será um REST, usamos o JAXB que faz os parses de Objeto Java para XML e vice-verça, através da extensão O/X Mappers do Spring.

Listagem 1. Arquivo web.xml.

<?xml version=”1.0” encoding=”UTF-8”?><web-app ...><servlet> <servlet-name>dispatcher-servlet</servlet-name> <servlet-class>org.springframework.web.servlet. DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation </param-name> <param-value> classpath:application-context.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher-servlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping></web-app>

Listagem 2. Arquivo application-context.xml.

<beans xmlns=”http://www.springframework.org/schema/beans” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:context=“http://www.springframework.org/schema/context”xsi:schemaLocation=” http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd”> <context:component-scan base-package= “mundoj.springintegration” /> <import resource=”spring-integration.xml” /> </beans>

Listagem 3. Arquivo pom.xml.

<dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-core</artifactId> <version>${spring.integration.version}</version></dependency>

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version>

/ 10

</dependency><dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet-api.version}</version></dependency>

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${spring.version}</version></dependency>

Explicação do fl uxoPara desenhar o fl uxo, foi optada pela utilização

da forma declarativa, ou seja via XML, pois o plugin Spring Tool Suite consegue exibi-lo facilmente na forma gráfi ca, facilitando a geração de documenta-ção.

Como nosso foco é mostrar o funcionamento dos padrões EAI, para explicar o fl uxo, omitiremos alguns padrões que se repetem ao longo da solução. Para facilitar a explicação os padrões foram enumerados, conforme pode ser visto na fi gura 7.

Ao receber uma notifi cação HTTP, o Spring atra-vés do Servlet org.springframework.web.servlet.DispatcherServlet registrado no web.xml, repassa a requisição para o Spring Integration, no caso, cha-mando o primeiro elemento do fl uxo a ser explicado, o padrão Gateway.

GatewayÉ um padrão de adaptação, disponibilizando co-

nexão a algum recurso de entrada (inbound) ou saída (outbound). Este padrão repassa a mensagem ao re-curso adaptado e então fi ca esperando uma respos-ta, conforme pode ser observado na fi gura 8. Ainda pode atender a diversos formatos, como HTTP, TCP/UDP, FTP, Feed (RSS), JDBC, JMS, JMX, JPA, Arquivos e muitos outros. No nosso exemplo o Gateway é de entrada e representa uma chamada HTTP, veja como fi cou a confi guração do mesmo na forma declarativa na Listagem 4. Como é um serviço web para repre-sentar o endereço a ser disponibilizado, utilizamos a propriedade name. Podemos também estipular o tipo de entrada através da propriedade request-payload, no caso, enviamos um XML no corpo da mensagem e como a Classe mundoj.springintegration.to.Lote está mapeada utilizando anotações da biblioteca Jaxb, o Spring Integration se encarrega de fazer a conversão sem a necessidade de código algum. Além dos canais de entrada e saída, confi gurados através das proprie-dades request-channel e reply-channel, respectiva-mente, e o canal onde os erros que ocorrem no fl uxo serão encaminhados error-channel.

Listagem 4. Exemplo de confi guração do padrão Gateway.

<int-http:inbound-gateway request-channel=“inputChannel” reply-channel=”outputChannel” name=”/lote” supported-methods=”POST”request-payload-type=”mundoj.springintegration.to.Lote”error-channel=”errorChannel” />

Figura 7. Modelagem do fl uxo da solução baseada nos padrões EAI.

Figura 8. Funcionamento do padrão Gateway.

applIcatIon bapplIcatIon a

GatEway

output

output

GatEway

11 \

ChannelO segundo padrão é o Channel. No exemplo de

configuração da Listagem 5, utilizamos o canal de comunicação DirectChannel que é uma implemen-tação síncrona e do tipo point-to-point. Este é o canal mais simples suportado pelo Spring Integra-tion, por isso não exige qualquer configuração espe-cial, simplesmente um id para identificar o mesmo. Por padrão esse tipo de canal implementa um balan-ceamento de carga que é baseado em uma abordagem round-robin, ou seja, se existirem mais de um recep-tor acoplado ao canal as mensagens serão repassadas de forma rotativa. Um recurso também interessante a ser mencionado no balanceamento de carga, é a configuração do atributo failover como true, neste caso se o receptor que está atendendo uma mensa-gem emitir uma exceção, a mensagem é repassada automaticamente ao receptor subsequente. Ainda no “balanceador” é possível estabelecer a ordem de exe-cução dos receptores através da propriedade order, configurada em cada receptor.

Listagem 5. Exemplo de configuração do padrão Channel.

<int:channel id=”inputChannel” />

FilterÉ responsável por decidir se a mensagem deve

continuar no fluxo ou ser descartada, conforme ilus-trado na figura 9. Também é muito simples de ser implementado, exigindo um canal de entrada input--channel e um canal de saída de mensagens output--channel, conforme pode ser observado na Listagem 6. Além disso, é necessário indicar uma implementa-ção através do atributo ref e method, ou mesmo passar uma expressão de decisão do tipo SpEL (Spring Ex-pression Language). A implementação pode ser vista na Listagem 7, no caso, estamos apenas validando os campos obrigatórios para que a mensagem possa ser processada sem erros. Note a presença da anotação @MessageEndpoint responsável por mapear os En-dpoints do Spring Integration como beans do Spring.

Listagem 6. Exemplo de configuração do padrão Filter.

<int:filter input-channel=”loteChannel” output-channel=“loteValidoChannel” ref=”loteFilter” method=”filtrar” />

Listagem 7. Exemplo de implementação do padrão Filter.

@MessageEndpointpublic class LoteFilter { public boolean filtrar(final Lote lote) { checkArgument(lote.getNumeroLote() != null, “Numero do lote não pode ser vazio”); checkArgument(lote.getBeneficiario() != null, “Código do beneficiário não pode ser vazio”); checkArgument(lote.getCheques() != null && !lote.getCheques().isEmpty(), “A lista de cheques não pode ser vazia”); //... return true; } }

Service ActivatorEste padrão é similar ao padrão de programa-

ção orientada a objeto Delegate que simplesmente tem a função de delegar chamadas, conforme pode ser observado na figura 10. Conforme pode ser visto na Listagem 8, além dos canais de entrada e saída, através das propriedades input-channel e output--channel, respectivamente, o Service Activator ne-cessita também do bean a ser chamado através da propriedade ref e o método propriedade method. No lugar do bean, podemos utilizar uma expres-são SpEL, quando queremos executar uma opera-ção mais simples, como uma operação aritmética, por exemplo. Em isolado, seria necessário configu-rar o canal de entrada e saída, com as propriedades input-channel e output-channel, respectivamente.

Figura 9. Funcionamento do padrão Filter.

wIdGEt quotE

wIdGEt quotE

mEssaGE fIltEr

wIdGEt quotE

wIdGEt quotE

GadGEtquotE

/ 12

A implementação do mesmo pode ser analisada na Listagem 9, onde simplesmente chamamos um servi-ço EJB, mapeado como beneficiarioService (veja confi-guração na Listagem 10, no nosso exemplo, estamos utilizando o OpenEJB e o MockEJB), mas o serviço poderia ser outro recurso, como, uma chamada a um programa Mainframe, ou simplesmente a um POJO. Note que estamos trabalhando com uma mensagem que contém um Lote é importante trabalhar desta forma, pois apesar do Spring Integration cuidar de criar uma mensagem de saída. Às vezes, queremos por exemplo, adicionar informações ao Header da mensagem, mas o Spring Integration, não deixa você simplesmente adicionar uma informação no Header, para isso, devemos criar um novo Header, que encap-sula o original, adicionar a nova informação, no caso, o objeto Beneficiario, retornado pelo serviço e utili-zar a classe utilitária MessageBuilder para gerar uma nova mensagem.

Listagem 8. Exemplo de configuração do padrão Service Activator.

<int:service-activator input-channel=”loteValidoChannel” output-channel= “loteBeneficiarioChannel” ref=”beneficiarioServiceActivator” method=”consultar” />

Listagem 9. Exemplo de implementação do padrão Service Activator.

@MessageEndpointpublic class BeneficiarioServiceActivator { @Autowired private BeneficiarioService beneficiarioService; public Message<Lote> consultar(final Message<Lote> message) { Integer codigoBeneficiario = message. getPayload().getBeneficiario(); Beneficiario beneficiario = beneficiarioService. obterPorCodigo(codigoBeneficiario); if (beneficiario == null) { throw new BeneficiarioInvalidoException( String.format(“Beneficiário %d inválido”, codigoBeneficiario)); } Map<String, Object> headers = Maps.newHashMap (message.getHeaders()); headers.put(“beneficiario”, beneficiario); return MessageBuilder.withPayload( message.getPayload()).copyHeaders(headers). build(); } }

Listagem 10. Configuração do EJB BeneficiarioServi-ce.

<jee:remote-slsb id=”beneficiarioService” jndi-name=“java:openejb/ejb/beneficiarioService”business-interface=“mundoj.springintegration.ejb.service.BeneficiarioService” />

Content Enricher Este padrão representa uma ação de enriqueci-

mento do conteúdo da mensagem, conforme pode-mos observar na figura 11. O Spring Integration pos-sui duas variações desse padrão:

» header-enricher: enriquece apenas o Header da mensagem, podemos ver um exemplo na Lis-tagem 10. Para configurá-lo são necessários os canais de entrada e saída e as informações a se-rem adicionadas ao Header. No nosso exemplo, é informado o correlation-id que será utilizado no padrão Aggregator a ser explicado mais a frente. Mas podemos ser mais genéricos utili-zando a tag header, passando o nome a ser uti-lizado, através da propriedade name e o valor, propriedade value.

» enricher: enriquece apenas o Payload. Nele po-Figura 10. Funcionamento do padrão Service Activator.

rEquEst

rEply

sErvIcE actIvator

rEquEstor

sErv

IcE

rEplIEr

13 \

demos atribuir propriedades do objeto contido no Payload, através da tag property e das pro-priedades name, expression ou value, para atri-buir seus valores.

basIc mEssaGE

EnrIchEr

EnrIchEd mEssaGE

Figura 11. Funcionamento do padrão Content Enricher.

Listagem 10. Exemplo de configuração do padrão Content Enricher.

<int:header-enricher input-channel=“loteBeneficiarioChannel” output-channel=“loteBeneficiarioEnriquecidoChannel”> <int:correlation-id expression=”payload.numeroLote” /></int:header-enricher>

SplitterComo o próprio nome diz, ele é responsável por

dividir a mensagem em N mensagens, conforme pode ser observado na figura 12. Sua configuração é sim-ples, bastando fornecer os canais de entrada e saída, através das propriedades input-channel e output--channel, assim como o bean e seu método a ser cha-mado, através das propriedades ref e method, confor-me é mostrado na Listagem 11. A complexidade da sua implementação dependerá da função do mesmo no fluxo, no nosso caso, como pode ser observado na Listagem 12, temos como entrada um lote e quere-mos retornar todos os cheques para serem proces-sados individualmente. Note que criamos a classe QuantidadeCheques que será utilizada como contador de cheques. Essa contagem de cheques é feita por banco e será utilizada pelo agrupador de cheques, a ser explicado mais a frente, necessário para enviar in-

formações ao Banco de todos mais especificamente.

Listagem 11. Exemplo de configuração do padrão Splitter.

<int:splitter input-channel=“loteBeneficiarioEnriquecidoChannel”output-channel=”chequesChannel”ref=”loteSplitter” method=”split” />

Listagem 12. Exemplo de implementação do padrão Splitter.

@MessageEndpointpublic class LoteSplitter { public Collection<Message<Cheque>> split(Message<Lote> message) { Collection<Cheque> cheques = message.getPayload().getCheques(); Map<String, Object> headers = Maps.newHashMap( message.getHeaders()); for (Cheque cheque : cheques) { String chaveChequeBanco = String.format( “CHEQUES_BANCO_%d”, cheque.getBanco()); if (headers.containsKey(chaveChequeBanco)) { QuantidadeCheques quantidade = (QuantidadeCheques) headers.get(chaveChequeBanco); quantidade.incrementar(); } else { headers.put(chaveChequeBanco, new QuantidadeCheques()); } } Collection<Message<Cheque>> messages = Lists.newArrayList(); for (Cheque cheque : cheques) { messages.add( MessageBuilder.withPayload(cheque). copyHeaders(headers).build()); } return messages; }}

Figura 12. Funcionamento do padrão Splitter.

ordEr ItEm 3

ordEr ItEm 2

ordEr ItEm 1

nEw ordEr

splIttEr

/ 14

RouterÉ um padrão de decisão e desvio de fluxo, onde

a mensagem que é recebida pode ser enviada para determinado canal, através da satisfação de determi-nada condição, conforme podemos acompanhar na ilustração da figura 13. Para facilitar, o Spring Inte-gration provê uma série de variações desse padrão.

Todas essas variações seguem a mesma estru-tura, tendo pequenas mudanças entre uma e outra abordagem. Basicamente, precisamos configurar um canal de entrada, propriedade input-channel e um canal para condições não mapeadas, se necessário, neste caso pela propriedade default-output-channel. Os mapeamentos de desvios também devem possuir um canal mapeado, propriedade channel. Seguem as implementações disponíveis:

» payload-type-router: onde é possível, através do tipo do dado contido no Payload da men-sagem, estipular o caminho que a mensagem deve seguir.

» header-value-router: possibilita rotear uma mensagem através das informações contidas no Header da mensagem.

» recipient-list-router: decisão através de ex-pressões que podem ser referentes tanto ao Header como ao Payload da mensagem.

» exception-type-router: permite executar o ro-teamento da mensagem que contenham uma exceção encapsulada.

» router: permite criar uma implementação cus-tomizada de um roteador. Se quiser utilizar o plugin do Spring para gerar o diagrama, não é aconselhável a utilização de um bean para essa variação, pois não permite ao Spring Integra-tion saber de imediato, quais serão os caminhos a serem tomados, quebrando o gráfico. Neste caso, aconselho recuperar as informações em uma etapa anterior, ficando somente uma ex-pressão ou valor para a decisão de roteamento, como no exemplo da Listagem 13.

Listagem 13. Exemplo de configuração do padrão Router.

<int:router input-channel=”chequesChannel” expression=”payload.banco”> <int:mapping value=”341” channel=”chequesBancoDoPovoChannel” /> <int:mapping value=”237” channel=”chequesBancoDeTodosChannel” /></int:router>

Wire TapPadrão responsável por copiar uma mensagem

de um canal e repassá-la a outro canal, conforme podemos acompanhar na figura 14. Isto é muito útil quando queremos monitorar as mensagens de um canal, ou até mesmo fazer outro processamento em paralelo com a mesma mensagem, como é o caso do nosso fluxo. Podemos observar na Listagem 14 que estamos utilizando a tag interceptors dentro da tag channel para interceptar a mensagem e a tab wire-tap para copiar a mesma.

wIrE tap

sourcE dEstInatIon

Figura 14. Funcionamento do padrão Wire Tap.

Figura 13. Funcionamento do padrão Router.

inqueue

mEssaGE routEr

outqueue 1

outqueue 2

15 \

Listagem 14. Exemplo de configuração do padrão Wire Tap.

<int:channel id=”chequesBancoDoPovoChannel”> <int:interceptors> <int:wire-tap channel= “chequesBancoDoPovoWireChannel” /> </int:interceptors></int:channel>

AggregatorSe trata de um agrupador de mensagens, con-

forme mostrado na figura 15. Ao contrário do padrão Splitter que divide as mensagens o Aggregator junta N mensagens. A sua configuração é simples de enten-der, conforme podemos notar na Listagem 15, além das típicas propriedades referentes aos canais de en-trada e saída, o mesmo possui algumas propriedades específicas. Basicamente para que o Aggregator possa transmitir uma mensagem são necessários três pas-sos a serem explicados abaixo:

» Estratégia de correlação: é a estratégia respon-sável por identificar quais mensagens serão consideradas no agrupamento. Por padrão o Aggregator utiliza a informação correlation-id presente no Header da mensagem. No nosso caso, o mesmo é configurado utilizando o pa-drão header-enricher e tomando como base o número do lote, conforme podemos constatar na Listagem 16. A mesma ainda pode ser imple-mentada de forma mais sofisticada, utilizando as propriedades correlation-strategy, passando o bean que contém a estratégia, a propriedade correlation-strategy-method, contendo o mé-todo do bean de estratégia a ser chamado, ou simplesmente correlation-strategy-expression, contendo uma expressão SpEL.

» Estratégia de liberação: é responsável por identificar em que momento a mensagem está pronta para ser transmitida. No caso do fluxo,

tivemos que implementar uma estratégia, a se-tando através das propriedades release-strategy e release-strategy-method. A implementação, pode ser avaliada na Listagem 17, no método verificar, onde simplesmente estamos verifican-do se a quantidade de cheques, até o momento, corresponde a quantidade de cheques do banco informada no Header da mensagem. Outra for-ma de implementar essa estratégia é através da propriedade release-strategy-expression.

» Estratégia de envio: efetivamente transmite a mensagem. A mesma só é acionada se as outras estratégias explicadas anteriormente forem verdadeiras. Para utilizá-la, basta setarmos o bean e o método nas propriedades ref e method. Veja na Listagem 17, no método enviar que esta-mos juntando as mensagens em um novo lote. Esse lote é referente a um banco e um número de lote. Como todas as mensagens contêm as mesmas informações no Header, então estamos o copiando, da primeira mensagem.

Listagem 15. Exemplo de configuração do padrão Aggregator.

<int:aggregator input-channel=“chequesBancoDeTodosChannel”output-channel=”loteBancoDeTodosChannel”ref=”chequeAggregator” method=”enviar”release-strategy=”chequeAggregator” release-strategy-method=”verificar” />

Listagem 16. Exemplo de configuração da Estratégia de correlação do padrão Aggregator.

<int:header-enricher input-channel=“loteBeneficiarioChannel”output-channel=”loteBeneficiarioEnriquecidoChannel”> <int:correlation-id expression=”payload.numeroLote” /></int:header-enricher>

Figura 15. Funcionamento do padrão Aggregator.

InvEntory ItEm 1

InvEntory ItEm 2

InvEntory ItEm 3

aGGrEGator InvEntory ordEr

/ 16

Listagem 17. Exemplo de implementação do padrão Aggregator.

@MessageEndpointpublic class ChequeAggregator { public boolean verificar( Collection<Message<Cheque>> messages) { Message<Cheque> primeiraMensagem = messages.iterator().next(); String chaveChequeBanco = String.format( “CHEQUES_BANCO_%d”, primeiraMensagem.getPayload().getBanco()); QuantidadeCheques quantidadeCheques = ((QuantidadeCheques) primeiraMensagem.getHeaders(). get(chaveChequeBanco)); return messages.size() == quantidadeCheques. getValue(); } public Message<Lote> enviar(final Collection<Message<Cheque>> messages) { Map<String, Object> header = Maps.newHashMap(messages.iterator(). next().getHeaders()); Lote lote = new Lote(); lote.setCheques(Lists.<Cheque>newArrayList()); for (Message<Cheque> message : messages) { lote.getCheques().add(message.getPayload()); } return MessageBuilder.withPayload(lote). copyHeaders(header).build(); }}

Message TranslatorEsse padrão tem uma função bem simples, trans-

formar mensagens. Ou seja, a mensagem produzida é a mensagem que foi utilizada, mas em outro formato, conforme pode ser observado na figura 16. Por exem-

plo, entra um objeto Java e sai um objeto Serializado / JSON / XML ou vice-versa. Normalmente utilizado, para adaptar os tipos internos as chamados de aplica-tivos externos. No nosso fluxo, é utilizado principal-mente para atender aos tipos exigidos pelos bancos, supondo que devemos enviar mensagens para uma fila no Banco De Todos em formato XML, temos que fazer uma transformação do objeto interno Lote, para esse XML, já para o Banco do Povo por se tratar de um FTP, devemos converter o objeto em bytes a serem salvos como arquivos.

Assim como o padrão Router existem algumas implementações prontas com intuito de facilitar a transformação de mensagens. Todas as variações possuem uma configuração similar, necessitando ba-sicamente dos canais de entrada e saída. Abaixo uma listagem desses facilitadores:

» object-to-string-transformer: simplementes transforma o objeto em String, chamam o mé-todo toString().

» payload-serializing-transformer: serializa o objeto JAVA.

» payload-deserializing-transformer: deserializa o objeto JAVA.

» object-to-map-transformer: transforma o ob-jeto em um Map. Esse map será formado por chave (atributo) e valor (valor do atributo).

» map-to-object-transformer: transforma um Map em um objeto, o inverso de object-to--map-transformer.

» object-to-json-transformer: transforma o ob-jeto JAVA em objeto JSON.

» json-to-object-transformer: transforma objeto JSON em objeto JAVA.

» transformer: é um transformador genérico. Se a transformação for simples basta montar uma expressão, utilizando a propriedade expression. Se for mais sofisticada, podemos definir um bean e método que irão executar a transfor-mação, através das propriedades ref e method, respectivamente, conforme a configuração da Listagem 18. No exemplo, é transformado um objeto cheque interno para um cheque no for-mato específico do Banco do Povo, como pode ser constatado na implementação da Listagem 19.

Listagem 18. Exemplo de configuração do padrão Message Translator.

<int:transformer input-channel=“dadosChequeBancoDoPovoChannel”output-channel=”ftpBancoDoPovoChannel”ref=”imagemChequeParaBytesTransformator” method=”transformar” />

Figura 16. Funcionameto do padrão Message Translator.

IncomInG mEssaGE

translator

translatEdmEssaGE

17 \

Listagem 19. Exemplo de implementação do padrão Message Translator.

@MessageEndpointpublic class ChequeParaChequeBancoDoPovoTransformer { public Message<ChequeBancoDoPovo> transformar( final Message<Cheque> message) throws Exception { Cheque cheque = message.getPayload(); Beneficiario beneficiario = (Beneficiario)message.getHeaders(). get(“beneficiario”); ChequeBancoDoPovo chequeBancoDoPovo = new ChequeBancoDoPovo(); chequeBancoDoPovo.setAgenciaBeneficiario( beneficiario.getAgencia()); chequeBancoDoPovo.setContaBeneficiario( beneficiario.getConta()); chequeBancoDoPovo.setValor(cheque.getValor()); return MessageBuilder.withPayload( chequeBancoDoPovo). copyHeaders(message.getHeaders()).build(); } }

ChainO funcionamento do mesmo pode ser observado

na figura 17. Ele não é mencionado dentre os padrões EAI, pois é simplesmente um facilitador, que o Spring Integration oferece, onde podemos ligar os End-points em sequência sem a necessidade de um canal para conectá-los, formando um elemento composto. Na Listagem 20, o utilizamos para agrupar dois Mes-sage Translators. Note que os Endpoints não indicam quais serão os canais de entrada e saída, pois os mes-mo são definidos no Chain.

chain

/chain

Figura 17. Exemplo de funcionamento do padrão Chain.

Listagem 20. Exemplo de configuração do elemento Chain.

<int:chain input-channel=”loteBancoDeTodosChannel” output-channel=”jmsBancoDeTodosChannel”> <int:transformer ref=”loteParaRemessaBancoDeTodosTransformer” method=”transformar” /> <int:transformer ref=”objetoParaXMLTransformer” method=”transformar” /> </int:chain>

Channel AdapterÉ o padrão de adaptação responsável por prover

uma conexão de entrada ou saída há algum recurso. Assim como o Gateway pode atender a diversos re-cursos diferentes. Basicamente a única diferença en-tre esses padrões é que o Channel Adapter não fica esperando a resposta, conforme pode ser visto na figura 18. No nosso fluxo, estamos utilizando adap-tadores do tipo saída. Um, para acessar um servidor FTP e outro, para acessar uma fila de mensagens através de JMS, conforme pode ser acompanhado na Listagem 21. Para configurá-los, necessitamos basi-camente de um canal setando a propriedade channel e então temos as configurações especiais para cada tipo de recurso acessado.

No caso do servidor FTP, temos que estipular o bean SessionFactory (sua configuração pode ser vista na Listagem 22, no exemplo estamos utilizan-do o framework FakeFTP), através da propriedade session-factory, o separador de arquivos, proprieda-de remote-file-separator, se o diretório será criado automaticamente ou não, propriedade auto-create--directory e o diretório remoto onde os arquivos se-rão criados, propriedade remote-directory-expression. A mensagem repassada a este adaptador deve en-capsular três tipos: um array de bytes, uma String ou um tipo java.util.io.File. No caso, estamos crian-do dois tipos de arquivos, um de imagem que é ge-rado se utilizando do atributo imagem do Cheque e o outro é um XML do tipo ChequeBancoDoPovo. No caso da fila de mensagens com JMS, temos que apenas referenciar os beans da fábrica de conexão e da fila propriamente dita, através das propriedades connection-factory e destination, respectivamente. Na Listagem 23, temos as configurações necessárias para apontar para o servidor de mensagens. Para o projeto de exemplo, estamos utilizando o framework Active-MQ da Apache.

/ 18

Listagem 21. Exemplos de configuração do padrão Channel Adapter.

<int-ftp:outbound-channel-adapter id=”ftpBancoDoPovo”channel=”ftpBancoDoPovoChannel” session-factory=”ftpBancoDoPovoSessionFactory”remote-file-separator=”/” auto-create-directory=”true”remote-directory-expression=”’/123/’” />

<int-jms:outbound-channel-adapter id=”jmsBancoDeTodos”channel=”jmsBancoDeTodosChannel”destination=”bancoDeTodosQueue” connection-factory=”bancoDeTodosConnectionFactory” />

Listagem 22. Configuração do Session Factory do servidor FTP do Banco do Povo.

<bean id=”ftpBancoDoPovoSessionFactory”class=”org.springframework.integration.ftp.session.DefaultFtpSessionFactory”> <property name=”host” value=”localhost” /> <property name=”port” value=”9981” /> <property name=”username” value=”mundoj” /> <property name=”password” value=”mundoj” /></bean>

Listagem 23. Configuração da fila de mensagens do Banco De Todos.

<jee:jndi-lookup id=”bancoDeTodosConnectionFactory”jndi-name=”jms/bancoDeTodosConnectionFactory” />

<jee:jndi-lookup id=”bancoDeTodosQueue”jndi-name=”jms/bancoDeTodosQueue” />

BridgeEste padrão estabelece uma ponte entre dois ca-

nais, não alterando a mensagem, ou seja, a mesma mensagem que chega através do canal de entrada é transmitida ao canal de saída, conforme exibido na figura 19. O mesmo pode ser utilizado tanto para fa-cilitar os testes, pulando trechos do fluxo, como para o nosso exemplo, onde temos um canal de tratamen-to de erro que pode se ligar tanto a um canal de log, quanto a um canal de resposta, conforme o adminis-trador optar. Veja na Listagem 24, dois exemplos uti-lizados no fluxo que ilustram bem as configurações deste padrão. Note a presença da propriedade auto--startup, que pode ser usada na maioria dos padrões, indicando se o mesmo será “startado” (true) ao iniciar o fluxo ou ficará “stopado” (false). Se omitido o valor padrão é true.

Listagem 24. Exemplos de utilização do padrão Bridge.

<int:bridge id=”logBridge” input-channel=”errorChannel” output-channel=”logErrorChannel”auto-startup=”true” />

Figura 18. Funcionamento do padrão Channel Adapter.

Figura 19. Funcionamento do padrão Bridge.

applIcatIon bapplIcatIon a Input

channEl adaptEr channEl adaptEr

19 \

<int:bridge id=”errorBridge” input-channel=”errorChannel” output-channel=”outputChannel”auto-startup=”false” />

Control BusO Control Bus é um padrão muito importan-

te dentro de uma solução EAI, pois o mesmo é res-ponsável por prover uma administração de todo o fluxo em tempo de execução, conforme ilustrado na figura 20. No Spring Integration, o mesmo não é acoplado a nenhum EndPoint. Basta apenas dispo-nibilizar acesso externo ao mesmo que esse elemen-to tem controle sobre todo o fluxo. No nosso caso é feito via um Gateway HTTP, através do endereço http://<endereço>:<porta>/spring-integration-servi-ce/control, conforme podemos constatar na Listagem 25. No Spring Integration, o Control Bus funciona a base de comandos, no nosso caso, iremos habilitar ou desabilitar os dois Bridges mencionados anterior-mente. Veja na Listagem 26 um exemplo de utiliza-ção do mesmo, onde, estamos “stopando” o Brigde logBridge e “startando” o Bridge errorBridge, fazendo com que os erros que antes eram “logados”, passem a ser lançados para a aplicação cliente.

Listagem 25. Exemplo de configuração do padrão Control Bus.

<int-http:inbound-gateway request-channel=“controlChannel” name=”/control”supported-methods=”POST” /><int:channel id=”controlChannel” /><int:control-bus input-channel=”controlChannel” />

Listagem 26. Exemplo de utilização do padrão Con-trol Bus.

controlGateway.send(“@logBridge.stop()”);controlGateway.send(“@errorBridge.start()”);

Rodando o projetoPara rodar o projeto que está disponível no site

da revista, basta executar o comando do Maven: mvn integration-test

Isso fará com que o Jetty suba, junto também é “startado” os servidores/containers OpenEJB, Apache ActiveMQ e de FakeFTP, tudo isso para que você não precise subir nada a parte, para ver o exemplo rodan-do.

Ao final da execução, os testes irão verificar se os arquivos foram copiados no servidor FTP e se as men-sagens foram enviadas ao servidor MQ.

Considerações finaisComo podemos observar, EAI não é nenhum bi-

cho de sete cabeças. Muito pelo contrário, o mesmo utiliza uma notação funcional. Por trabalhar com uma estrutura simples, voltada à utilização de pa-drões, facilita em muito o desenho de soluções, a se-paração de tarefas e a reutilização de componentes.

Já o Spring Integration é open source, utiliza a madura plataforma Java e o famoso framework Spring como base, possuindo integração com diver-sas tecnologias, protocolos, plataformas e sistemas. O que faz como que seja uma ótima opção na hora de escolher uma ferramenta EAI.

Se você está pensando em implementar SOA na sua empresa e pretende investir fortemente em uma ferramenta ESB, equipamentos, treinamentos e con-tratações, fica a dica, vale a pena avaliar as opções open source antes.

> Enterprise Application Integration

http://www.eaipatterns.com

> Documentação Spring Integration

http://static.springsource.org/spring-integration/reference/htmlsingle/

> Exemplos de utilização do Spring Integration

https://github.com/SpringSource/spring-integration-

samples

/referências

Figura 20. Funcionamento do padrão Control Bus.

mEssaGE flow

control bus