You are on page 1of 105

INTEGRANDO APLICAES COM ENTERPRISE SERVICE BUS

Produzido por Alberto Barbosa Projeto SPB SP02 Centro de Tecnologia da Informao Renato Archer

Contedo
1 Introduo. ...................................................................................................................................... 2 1.1 Necessidade e Desafios de uma Integrao ............................................................................ 2 1.2 As Solues............................................................................................................................. 3 1.2.1 Soluo Point-to-Point .................................................................................................... 3 1.2.2 Soluo Hub-and-Spoke ................................................................................................. 4 1.2.3 Enterprise Message Bus .................................................................................................. 4 1.2.4 Enterprise Service Bus .................................................................................................... 5 Enterprise Service Bus ESB......................................................................................................... 6 2.1 Caractersticas de um ESB ...................................................................................................... 6 2.1.1 Difuso ............................................................................................................................ 6 2.1.2 Integrao Baseada em Padres ...................................................................................... 6 2.1.3 Integrao Altamente Distribuda e Seletivamente Implantada ...................................... 7 2.1.4 Transformao de Dados ................................................................................................ 7 2.1.5 Segurana e Confiabilidade ............................................................................................ 7 2.1.6 Ambiente Autnomo e Federado .................................................................................... 7 2.1.7 Adoo Incremental ........................................................................................................ 7 2.2 Funcionalidades de um ESB ................................................................................................... 8 2.2.1 Transparncia de Localizao ......................................................................................... 8 2.2.2 Converso de Protocolo de Transporte ........................................................................... 8 2.2.3 Transformao de Mensagem ......................................................................................... 9 2.2.4 Roteamento de Mensagem .............................................................................................. 9 2.2.5 Enriquecimento de Mensagens ..................................................................................... 10 2.2.6 Segurana ...................................................................................................................... 10 2.2.7 Monitoramento e Gerenciamento .................................................................................. 11 ESB Mule ...................................................................................................................................... 11 3.1 Arquitetura do ESB Mule ..................................................................................................... 11 3.1.1 Servios ......................................................................................................................... 11 3.1.2 Transportes .................................................................................................................... 12 3.1.3 Roteadores..................................................................................................................... 15 3.2 Arquivo de Configurao do ESB Mule ............................................................................... 15 Estudo de Caso .............................................................................................................................. 17 4.1 Arquitetura da Soluo.......................................................................................................... 17 Estudo de Caso Fase I ................................................................................................................ 18 5.1 Implementao da Aplicao ................................................................................................ 19 5.1.1 A Aplicao Web .......................................................................................................... 19 5.1.2 O Servio de Cotao de Emprstimo .......................................................................... 19 5.1.3 O Servio de Gerao de Respostas .............................................................................. 20 5.1.4 O Transformer de Solicitaes de Cotao ................................................................... 21 5.1.5 O Transformer de Resposta de Cotao ........................................................................ 24 5.2 Implementao do Fluxo de Mensagens ............................................................................... 24 5.2.1 Declaraes de Namespaces e Esquemas. .................................................................... 25 5.2.2 Configurao dos Transformers .................................................................................... 25 5.2.3 Configurao dos Endpoints ......................................................................................... 25 5.2.4 Configurao dos Servios............................................................................................ 28 5.3 Organizao da Aplicao .................................................................................................... 30

4 5

5.4 Executando a Aplicao ........................................................................................................ 31 Estudo de Caso Fase II ............................................................................................................... 34 6.1 Implementao da Aplicao ................................................................................................ 37 6.1.1 A Aplicao Web .......................................................................................................... 37 6.1.2 Servios da Agncia de Emprstimo............................................................................. 38 6.1.3 Agncia de Crdito........................................................................................................ 40 6.1.4 O Servio de Seleo Bancria ..................................................................................... 43 6.1.5 Bancos ........................................................................................................................... 46 6.1.6 Tratamento de Erros ...................................................................................................... 48 6.1.7 Transformers para a Agncia de Crdito ...................................................................... 49 6.1.8 Transformer para Seleo Bancria .............................................................................. 51 6.2 Implementao do Fluxo de Mensagens ............................................................................... 53 6.2.1 Declaraes de Namespaces e Esquemas ..................................................................... 53 6.2.2 Configurao dos Transformers .................................................................................... 53 6.2.3 Configurao dos Endpoints ......................................................................................... 54 6.2.4 Configurao dos Servios............................................................................................ 56 6.3 Organizao da Aplicao .................................................................................................... 66 6.4 Executando a Aplicao ........................................................................................................ 67 7 Estudo de Caso Fase III ............................................................................................................. 69 7.1 Implementao da Aplicao ................................................................................................ 73 7.1.1 Bancos ........................................................................................................................... 73 7.1.2 Gerador de Relatrio ..................................................................................................... 79 7.1.3 Emisso Automtica de Relatrio ................................................................................. 83 7.1.4 Transformer para os Bancos A e B ............................................................................... 84 7.2 Implementao do Fluxo de Mensagens ............................................................................... 86 7.2.1 Declaraes de Namespaces e Esquemas ..................................................................... 86 7.2.2 Configurao dos Transformers .................................................................................... 87 7.2.3 Configurao dos Endpoints ......................................................................................... 87 7.2.4 Configurao dos Servios............................................................................................ 92 7.3 O Arquivo de Configurao Mule ........................................................................................ 96 7.4 Organizao da Aplicao .................................................................................................. 103 7.5 Executando a Aplicao ...................................................................................................... 104 8 Referncias.................................................................................................................................. 104 6

1 Introduo.
O objetivo deste tutorial apresentar o uso de ESB (Enterprise Service Bus) como infra-estrutura para prover interoperabilidade entre aplicaes. Como o objetivo apresentar uma soluo prtica que auxilie arquitetos e desenvolvedores a construrem solues integradas usando ESB, utilizaremos o ESB Mule como estudo de caso. Antes de entrarmos no estudo de caso propriamente dito, vamos fazer uma breve introduo tecnologia ESB e ao ESB Mule.

1.1 Necessidade e Desafios de uma Integrao


As empresas atualmente no ficam confinadas aos seus limites fsicos. No falamos apenas em integrao entre plataformas ou linguagens, falamos em integrao entre empresas. Partimos de aplicaes em rede para empresas em rede, criando oportunidades enormes para interao entre aplicaes empresariais. O parque de TI das corporaes apresentam um cenrio complexo causado por evoluo de software e fuses entre empresas, apresentando um panorama heterogneo de sistemas de todas as idades e naturezas. As informaes corporativas esto normalmente guardadas nas aplicaes dentro de diferentes departamentos e corporaes. Normalmente custoso e demorado obter esses dados desacoplados; por outro lado, as decises estratgicas de negcios das empresas demandam uma melhoria mensurvel no fluxo de dados e informaes necessrias para tomada de

decises. O processo de integrao entre aplicaes enfrenta uma srie de desafios que esto alm dos problemas tcnicos e de negcios: Aplicaes de negcios geralmente focam em uma rea de negcio especfica, como conseqncia, os grupos de TI geralmente esto alinhados com reas funcionais especficas. Uma integrao bem sucedida no estabelece comunicao apenas entre sistemas computacionais, mas tambm entre unidades de negcios e grupos de TI. Em um ambiente integrado, os grupos no controlam mais uma aplicao especfica porque cada aplicao passa a ser parte integrante de um fluxo geral de aplicaes e servios integrados. Devido a sua larga abrangncia, os esforos de integrao tm implicaes sobre os negcios. Uma vez incorporada uma funcionalidade crtica de negcio soluo integrada, toda a soluo passa a ser crtica para a empresa. Uma falha na soluo integrada pode ter grande impacto nos negcios da empresa. Uma restrio importante ao processo de integrao o baixo controle sobre as aplicaes existentes. Muitas aplicaes so aplicaes legadas sobre as quais no se consegue fazer alteraes para conect-las soluo integrada. A despeito da reconhecida necessidade de integrao de solues, poucos padres estabeleceram-se neste domnio. O advento do XML, XSL e Web Services so os avanos mais significantes nesta rea. Mesmo utilizando XML para padronizar toda a troca de dados, ainda temos um grande desafio no que se refere semntica das informaes. Desenvolver solues integradas um grande desafio, mas a operao e manuteno de tal soluo podem ser ainda mais amedrontadoras. A mistura de tecnologias e a natureza distribuda da soluo fazem com que a distribuio, monitoramento e resoluo de problemas sejam tarefas complexas que requerem uma combinao de competncias que podem estar espalhadas por vrios profissionais dentro da corporao. No existem respostas simples para os problemas de integrao, mas a adoo de tecnologias que utilizam padres de problemas e suas solues pode facilitar enormemente esta tarefa.

1.2 As Solues
Integrar aplicaes uma tarefa difcil e complexa devido grande variedade de arquiteturas e tecnologias utilizadas. Vrias tcnicas, padres e tecnologias foram adotados com o objetivo de integrar aplicaes, vamos destacar algumas arquiteturas utilizadas para integrao: Soluo Point-to-Point. Soluo Hub-and-Spoke Enterprise Message Bus Enterprise Service Bus. As publicaes [1], [2] e [3] constituem um excelente material para se conhecer as tecnologias utilizadas em integrao de aplicaes. A publicao [1] descreve os padres de integrao abordando de maneira extensa os padres relacionados com messaging. O livro [2] aborda especificamente a tecnologia ESB e [3] aborda principalmente JBI, como base para implementao de ESBs.

1.2.1 Soluo Point-to-Point


Nesta arquitetura a integrao entre aplicaes definida para pares de aplicaes. Neste caso temos duas extremidades a serem integradas (end points) e utilizamos protocolos, adaptadores e transformaes em uma ou ambas as extremidades. Utilizamos tecnologias especficas como FTP, IIOP ou interfaces remotas para realizar a integrao. O volume de integrao baixo e entre os dois pontos temos um acoplamento forte, j que ambas as extremidades tm conhecimento a respeito de seu par. Um problema com essa arquitetura a proliferao de ligaes, complicando a manuteno e impossibilitando a governana. A figura a seguir ilustra essa arquitetura.

Aplicao

Aplicao

Aplicao

Aplicao

Figura 1. Arquitetura de integrao Point-to-Point.

1.2.2 Soluo Hub-and-Spoke


Nesta arquitetura, tambm chamada de Message Broker, as aplicaes se conectam a um hub central (broker) atravs de conectores leves. Estes conectores facilitam a integrao com pouca ou nenhuma alterao nas aplicaes existentes. Transformaes e encaminhamento de mensagens acontecem dentro do hub. Esta arquitetura diminui o nmero de conexes requeridas para a integrao, j que as aplicaes no se conectam diretamente. O maior problema com esse tipo de integrao est no fato do hub ser um ponto de falha; se o hub falha, toda a topologia de integrao falha.

Aplicao

Aplicao

HUB

Aplicao

Aplicao

Figura 2 Arquitetura de integrao Hub-and-Spoke.

1.2.3 Enterprise Message Bus


Esta arquitetura prov uma infra-estrutura comum de comunicao que age como um adaptador entre as aplicaes independente de plataforma e linguagem. Esta infra-estrutura pode conter roteadores de mensagens e canais publish-subscriber. As aplicaes interagem entre si de maneira desacoplada, atravs de um barramento de mensagens com ajuda de filas de requisies e respostas. Uma aplicao que precisa usar um servio de um provedor coloca a mensagem adequada na fila de requisies do servio e espera por uma resposta em uma fila de respostas daquele servio.

Aplicao

Barramento de mensagens

Aplicao

Aplicao

Figura 3 Arquitetura de integrao Enterprise Message Bus.

1.2.4 Enterprise Service Bus


Esta abordagem utiliza pilhas de tecnologias para prover um barramento para integrao entre aplicaes. As aplicaes no se comunicam diretamente para integrao; elas se comunicam atravs deste middleware (ESB) que um backbone para Service Oriented Architecture (SOA). ESB uma coleo de servios de middleware que provm capacidade de integrao. Estes servios esto no centro da arquitetura ESB, sobre os quais aplicaes colocam mensagens para serem encaminhadas e transformadas. As aplicaes se conectam ao ESB atravs de conectores inteligentes abstratos. Inteligentes porque eles possuem lgica interna para, junto com o ESB, seletivamente se ligarem a servios em tempo de execuo. So abstratos no sentido de que eles definem apenas protocolos de ligao de transporte e interfaces de servios, no detalhes reais de implementao. A figura seguinte exemplifica esta arquitetura.

Aplicao CI

Aplicao CI

ESB

CI Aplicao

CI Aplicao

CI conector inteligente Figura 4 Arquitetura de integrao Enterprise Service Bus.

2 Enterprise Service Bus ESB


Antes de comear nosso estudo a respeito do ESB Mule, vamos falar um pouco sobre as caractersticas e funcionalidades de um ESB de maneira geral. Um ESB uma plataforma de integrao baseada em padres que combina troca de mensagens, Web Services, transformaes de dados e roteamento inteligente para conectar e coordenar a interao de aplicaes diversas atravs de uma organizao e seus parceiros de negcios. Um ESB prov um framework para implementar SOA, com um ambiente dirigido por eventos (event-driven), de baixo acoplamento e um barramento de mensagens multiprotocolo.

2.1 Caractersticas de um ESB


As sesses a seguir descrevem sucintamente as principais caractersticas de um ESB. O livro Enterprise Service Bus [2] trs uma descrio detalhada das caractersticas de um ESB.

2.1.1 Difuso
Um ESB tem a capacidade de abranger toda a corporao e ir alm, formando um grid de difuso de aplicaes e servios com alcance global entre departamentos da organizao, unidades de negcios e parceiros comerciais. Aplicaes se conectam ao barramento quando necessrio, possibilitando visibilidade e troca de dados entre as aplicaes e servios conectados ao barramento.

2.1.2 Integrao Baseada em Padres


Para conectividade, ESB pode utilizar uma grande variedade de tecnologias padronizadas como Java Message Service (JMS) e J2EE Conecctor Architecture (JCA e J2CA). Pode ser utilizado para integrar aplicaes desenvolvidas em vrias tecnologias e plataformas como .NET, COM, C# e

C/C++. Adicionalmente ESB pode integrar facilmente aplicaes que suportam SOAP e APIs Web Service. Para compartilhamento de dados, ESB pode usar padres XML como: XSLT, XPath e XQuery, provendo transformao de dados e roteamento inteligente. ESB pode tambm utilizar WSDL para descrever interfaces abstratas de servios e Business Process Execution Language (BPEL4WS) para Web Services.

2.1.3 Integrao Altamente Distribuda e Seletivamente Implantada


ESB prov integrao de servios, transformao de dados e adaptadores para aplicaes como servios individuais que podem trabalhar juntos de uma forma altamente distribuda e que pode ser escalada de forma independente. Um conceito central de ESB o conceito de container de servio, que permite implantao seletiva de servios de integrao.

2.1.4 Transformao de Dados


Uma parte fundamental da integrao a transformao de dados entre formatos utilizados pelas aplicaes que fazem parte da soluo integrada. Muitas aplicaes no compartilham o mesmo formato para descrever dados similares. Transformao de dados parte integral do prprio ESB.

2.1.5 Segurana e Confiabilidade


A segurana entre aplicaes e ESB, e mesmo entre mesmo entre ESBs distintos, capaz de estabelecer e manter a mais estrita autenticao, gerenciamento de credenciais e controle de acesso. A confiabilidade alcanada pela adoo de um MOM (Message Oriented Middleware) no ncleo do ESB. O ncleo MOM prov comunicao assncrona, garantia de entrega de dados e integridade transacional.

2.1.6 Ambiente Autnomo e Federado


Um dos maiores problemas encontrados ao estender o alcance da integrao alm dos limites do nvel departamental a questo da autonomia local versus o controle centralizado. Como parte da cultura de grandes corporaes, cada departamento ou unidade de negcios precisa operar de maneira independente. Contudo eles ainda se baseiam em recursos compartilhados e informaes que afunilam em uma funo de negcio comum. Em ambiente desta natureza no razovel impor uma estratgia de integrao que faz com que todas as mensagens passem por um ponto centralizado. Unidades locais de negcios precisam ter controle sobre seus recursos locais como aplicaes que rodam em seu site. ESB permite a instalao de domnios de integrao locais e ainda permite conectar domnios locais em uma grande rede de integrao federada. A figura 5 ilustra, alm da implementao de um grande projeto em fases, o ambiente autnomo e federado. Nesta figura cada ESB define um ambiente autnomo e devido ao fato dos ESBs estarem interconectados, teremos um ambiente federado.

2.1.7 Adoo Incremental


Um grande projeto de integrao pode ser implantado gradualmente utilizando ESB. A figura 5 a seguir ilustra esta caracterstica.

Fase III Fase II Fase I

ESB

ESB

ESB broker

ESB

Domnio I

Domnio II

Domnio III

Domnio IV

Figura 5 Adoo incremental de integrao

2.2 Funcionalidades de um ESB


Nesta sesso apresentamos as principais funcionalidades de um ESB.

2.2.1 Transparncia de Localizao


Quando um consumidor comunica com um provedor de servio via ESB o consumidor no precisa conhecer a localizao real do provedor. O consumidor fica desacoplado do provedor, portanto, mudar o provedor de lugar, no afeta o consumidor. Pode-se implementar transparncia de localizao dentro do ESB atravs de um simples arquivo de configurao XML. A figura seguinte mostra esta funcionalidade.

Aplicao cliente

ESB XML config. localizao

Aplicao provedora de servio

Figura 6 ESB com a funcionalidade de transparncia de localizao configurada por XML

2.2.2 Converso de Protocolo de Transporte


Uma funcionalidade importante do ESB a converso de protocolo de transporte. Essa funcionalidade propicia a comunicao entre um consumidor e um provedor de servio que utilizam diferentes protocolos de comunicao. Por exemplo, se um consumidor usa JMS como transporte e um provedor um sistema legado que pode apenas importar e exportar arquivos batch, o ESB, atravs de componentes denominados adaptadores de protocolos (protocol adapters), poder fazer a converso dos protocolos possibilitando a comunicao. Um ESB possui uma grande variedade de conversores

de protocolos e outros, adquiridos de terceiros, podem ser adicionados ao ESB. A figura a seguir demonstra a funcionalidade de converso de protocolo.

ESB Aplicao cliente Aplicao legada adaptador JMS adaptador arquivo Arquivo

Mensagem JMS Figura 7 - Converso de protocolo de transporte.

2.2.3 Transformao de Mensagem


Normalmente a integrao entre um consumidor e um provedor de servio requer a converso de formato da mensagem. O ESB implementa a lgica de transformao de mensagem. Normalmente a transformao a ser realizada descrita atravs da tecnologia XSLT (Extensible Stylesheet Language Transformation). A figura a seguir exemplifica esta funcionalidade.

ESB Aplicao cliente Aplicao provedora

transformador de mensagem

Mensagem SOAP Figura 8 Funcionalidade transformao de mensagem

Mensagem EDI

2.2.4 Roteamento de Mensagem


Em muitas solues de integrao vrias aplicaes podem ser alvo para mensagens enviadas por uma aplicao cliente. O ESB pode determinar qual aplicao provedora deve receber a mensagem com base em regras e lgicas. O roteamento de uma mensagem pode, entre outras possibilidades, ser baseado no contedo da mensagem ou em filtros. possvel tambm encaminhar a mensagem para uma lista, permitindo que vrios provedores recebam a mensagem. A figura a seguir exemplifica esta funcionalidade.

Aplicao provedora A ESB Aplicao cliente roteador Aplicao provedora B Figura 9 Funcionalidade Roteamento de Mensagem.

2.2.5 Enriquecimento de Mensagens


A funcionalidade de transformao de mensagem diz respeito apenas a mudana de formato da mensagem e no do contedo. Outra funcionalidade provida pelo ESB a adio de novos dados mensagem ou a converso de dados existentes. Podemos, por exemplo, adicionar informaes armazenadas em um banco de dados com base na identificao do cliente enviada na prpria mensagem. O destinatrio receber a mensagem original enriquecida com as informaes obtidas do banco de dados. A figura a seguir ilustra este exemplo.

ESB Aplicao cliente Mensagem original Mensagem enriquecida Banco de dados Figura 10 Enriquecimento de mensagem Aplicao provedora enriquecedor de mensagem

2.2.6 Segurana
Como um ESB lida com lgica de integrao de negcios, ele deve prover mecanismos para autenticao, autorizao e criptografia das mensagens que chegam at ele. Quando o ESB oferece ponto de acesso de integrao para aplicaes fora dos domnios da empresa, essa questo de segurana passa a ser ainda mais importante e crtica. A figura a seguir d uma idia de como podemos configurar segurana em um ESB.

ESB Aplicao cliente Mensagem original Verifica credenciais Autent. Cript.

Aplicao provedora

Mensagem criptografada

LDAP Figura 11- Segurana em ESB

2.2.7 Monitoramento e Gerenciamento


Um ambiente de monitoramento e gerenciamento deve ser provido pelo ESB para configurar o ESB para que ele tenha alta performance e seja confivel. Tambm pode ser necessrio monitorar o fluxo de mensagens que passam pelo ESB em tempo de execuo.

3 ESB Mule
At aqui descrevemos as caractersticas gerais de um ESB, a partir deste ponto vamos apresentar um ESB especfico, o ESB Mule, e descrever suas principais caractersticas e componentes. Iniciaremos apresentando sua arquitetura e componentes, seus conceitos principais e suas funcionalidades. Aps esta parte conceitual iniciaremos um estudo de caso utilizando o ESB Mule. Neste estudo de caso, apresentaremos, em detalhes, as configuraes da soluo integrada, que esperamos seja til para aqueles que esto envolvidos com a difcil tarefa de promover integrao entre aplicaes. As publicaes [4], [5], [6] e [7] abordam o ESB Mule em detalhes. A publicao [4] tambm descreve outro ESB open source, o ServiceMix.

3.1 Arquitetura do ESB Mule


A arquitetura do Mule consiste de uma coleo de componentes que provm as funcionalidades que um ESB deve oferecer. Vamos analisar os principais elementos que compem a arquitetura do Mule: Servios Transportes Roteadores

3.1.1 Servios
Mule um ambiente de execuo que hospeda servios. Servios so conjuntos discretos de funcionalidades que so completamente separados uns dos outros, mas que podem trabalhar juntos sobre os mesmos objetos. Um servio Mule, representado pela figura a seguir, composto por trs elementos: Um inbound router, que especifica quais mensagens o componente de servio processar. Um componente de servio, que implementa a lgica de integrao do servio e pode ser implementado utilizando vrias tecnologias, como: POJO, REST service e BPM, entre outros.

Um outbound router, que determina para onde a mensagem dever ser enviada aps ser processada pelo componente.

Servio Inbound router Componente de servio Outbound router

Figura 12 Elementos que compem um servio. Quando uma mensagem enviada por uma aplicao, Mule pega a mensagem, envia-a para o servio que a processa usando alguma lgica e encaminhe-a para a aplicao correta. Mule possui muitas partes individuais que tratam o processamento e roteamento da mensagem. A principal parte de um servio o componente do servio, que executa lgica de negcio sobre as mensagens. Uma caracterstica importante do componente do servio que ele no tem que ter nenhum cdigo especfico Mule; ele pode ser simplesmente um POJO, um Spring bean, um Java bean ou um web service. Mule gerencia o componente de servio, envolve-o com configuraes e o expe como um servio, assegurando que a informao correta passada para ele e a partir dele conforme sua configurao. Um componente de servio no contm qualquer informao de como receber e enviar mensagens. Para assegurar que um componente de servio receba corretamente mensagens e as encaminhe apropriadamente aps o processamento, precisamos especificar um inbound router e um outbound router. Um inbound router especifica quais mensagens o componente de servio ir processar. Ele pode filtrar, agregar e mudar a seqncia de mensagens antes de encaminh-la ao componente de servio. Aps o componente de servio ter processado a mensagem, o outbound router especifica para onde encaminhar a mensagem. Podem ser definidos mtiplos inbound e outbound routers e mesmo cadeias de routers.

3.1.2 Transportes
Mule pode tratar mensagens que so enviadas em uma variedade de protocolos como, HTTP, JMS, FTP, VM, SMTP, JDBC e outros. O componente de servio no se preocupa com o protocolo usado, na verdade um componente de servio no sabe como ler mensagens e no precisa se preocupar com os formatos das mensagens. Ao invs disso, um transporte se encarrega de transportar as mensagens e os transformers se encarregam de mudar as mensagens de acordo com o formato requerido pelo componente de servio. Todo o transporte, transformao e roteamento de mensagens so completamente transparentes para o componente de servio. A figura a seguir apresenta um caso onde as mensagens chegam via transporte HTTP, so transformadas de XML para objetos Java, processadas e enviadas utilizando transporte JMS.

Servio Componente de servio

Inbound router

outbound router

Transformer XML para objeto Java

Mensagem

Transporte HTTP

Transporte JMS

Mensagem

Figura 13 Roteamento e transformao de mensagens. Um transporte Mule prov todos os elementos ESB requeridos para receber, enviar e transformar mensagens para um protocolo particular. Um transporte se manifesta em uma configurao pelos seguintes elementos: conectores, endpoints e transformers. A figura a seguir apresenta os elementos de um transporte Mule.

Transporte Conector Endpoint Message receiver Transformers

Message dispatcher

Endpoint

Figura 14 Elementos de um transporte Mule.

3.1.2.1 Conectores
Um conector permite a um componente enviar ou receber dados atravs de um protocolo especfico. O conector tem a responsabilidade de controlar o uso de um protocolo particular. Ele configurado com parmetros especficos para um protocolo e mantm qualquer estado que pode ser compartilhado com as entidades abaixo que fazem a comunicao real. Temos ento conector JMS, conector HTTP, etc. Na figura 13 ns utilizamos um conector HTTP e um conector JMS. Um conector uma referncia para uma coleo de classes que so responsveis pela comunicao, como as seguintes: Message Receiver. uma classe que sabe como receber dados usando um protocolo e convert-los em um formato que o Mule possa us-los.

Message Dispatcher. uma classe que sabe como converter dados Mule para transmisso usando um protocolo especfico. Transport-specific transformer. Classes opcionais que permitem transformar os dados quando esto sendo enviados ou recebidos.

3.1.2.2 Endpoints
Um endpoint representa o uso especfico de um protocolo, se ele para listening/polling, para leitura ou escrita. Endpoints controlam quais entidades sero usadas com um conector. Endpoints so elementos-chave de configurao para ligar todos os servios. Inbound e outbound endpoints existem no contexto de um servio e representam respectivamente a entrada esperada e pontos de sada para mensagens. Dentro de Mule, um endpoint pode conectar componentes de servios a recursos locais (como arquivos) ou a recursos de rede (por exemplo, conexes HTTP ou aplicaes de terceiros). Eles servem tambm como locais onde configurar vrias outras caractersticas do ESB Mule, como filtros, transformers e transaes. A figura a seguir mostra o uso de endpoints para ligao entre servios internos e externos ao ESB Mule.

Instancia Mule Aplicao ou servio e p Componente de servio ep e p e p Componente de servio e p Aplicao ou servio e p ep - endpoint Figura 15 Ligao entre servios e aplicaes. Uma aplicao Mule pode ser composta por uma ou mais instancias, possvel conectar componentes de servios em instancias distintas atravs de endpoints. Os endpoints podem ser configurados em vrios elementos de Mule: Na seo inbound de um componente de servio. Neste caso o endpoint um inbound endpoint, dados so lidos dele. Em um router dentro de uma seo outbound de um componente de servio. Neste caso o endpoint um outbound endpoint e dados so escritos nele. Em definies de estratgias de exceo, usadas para gerir excees. Em definies de estratgias catch-all, usadas para gerir possibilidades de roteamento. Os transportes definem endpoints customizados, o que permite a configurao de endereos e valores de propriedades especficas. O endpoint mais simples possui apenas a configurao de um endereo, mas os seguintes atributos so comuns a todos os endpoints: synchronous permite configurar se as mensagens lidas ou escritas em um endpoint deveriam ser lidas ou escritas de maneira sncrona ou assncrona. O valor default falso (assncrono). Componente de servio e p Data source

connector-ref permite especificar que conector usar com um dado transporte. transformer-ref permite especificar uma lista de transformers a serem aplicados sobre as mensagens lidas ou escritas no endpoint.

3.1.2.3 Transformers
Transformers so utilizados para possibilitar a comunicao entre componentes que utilizam formatos de mensagens diferentes. Mule no impe nenhum formato de mensagem, portanto as aplicaes podem utilizar os formatos mais convenientes. Podem-se usar 3 tipos diferentes de transformaes: Transformao de tipo de mensagem. Esta transformao no altera a mensagem propriamente dita, apenas seu tipo. Por exemplo, podemos converter um byte stream para uma string; uma mensagem JMS para um objeto Java. Este o tipo de transformao especfica de transporte. Transformao de mensagem. Esta transformao envolve a converso da mensagem propriamente dita. o tipo de transformao especfica de aplicao. Transformaes envolvendo propriedades de uma mensagem. Mensagens podem conter propriedades, por exemplo, uma mensagem enviada para um servidor SMTP deveria ter as propriedades To, From e CC. Transformers so declarados nas configuraes Mule antes de serem usadas. Eles so referenciados por nome, normalmente dentro de endpoints. Transformers podem ser encadeados, acumulando seus efeitos.

3.1.3 Roteadores
Os roteadores desempenham um papel fundamental no controle da trajetria das mensagens que transitam pelo ESB Mule. Eles ficam na entrada dos endpoint direcionando as mensagens para que alcancem seus destinos corretos. Alguns roteadores so muito simples, outros so mais complexos examinando inclusive algumas caractersticas das mensagens para decidir quais rotas as mensagens devem seguir. Alguns roteadores chegam a um nvel bastante sofisticado podendo quebrar, classificar ou reagrupar mensagens baseando-se em certas condies, normalmente executadas por entidades denominadas de filtros. Os filtros so complementos poderosos dos roteadores, provendo-os com a capacidade de deciso do que fazer com as mensagens que esto em transito. Alguns filtros analisam o contedo das mensagens, baseando-se em determinados valores para fazer o encaminhamento das mensagens. O local do roteador no servio determina sua natureza (inbound, outbound ou async-reply) e os possveis papis nos quais ele poderia atuar (pass-through, aggregator, etc). Os inbound routers so atravessados antes que a mensagem alcance o componente de servio, enquanto os outbound routers so alcanados aps a mensagem ser processada pelo componente. Um roteador async-reply cuida de enviar resposta assncrona para o endpoint que a espera. Quando nenhum roteamento necessrio, o roteador pode ser o mais simples possvel. Neste caso o roteador pode ser um pass-through, dando passagem a qualquer mensagem que decida transitar por ele.

3.2 Arquivo de Configurao do ESB Mule


Uma aplicao Mule configurada atravs de um arquivo de configurao XML que especifica os vrios componentes que compem a arquitetura Mule. No entraremos em detalhes sobre o arquivo de configurao neste momento. Durante a construo do estudo de caso apresentado neste tutorial

explicaremos em detalhes cada parte da configurao utilizada. A seguir apresentamos uma configurao vlida Mule para termos idia de como ela se apresenta. <mule xmlns="http://www.mulesource.org/schema/mule/core/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:http="http://www.mulesource.org/schema/mule/http/2.0" xmlns:vm="http://www.mulesource.org/schema/mule/vm/2.0" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/springbeans-2.0.xsd http://www.mulesource.org/schema/mule/core/2.0 http://www.mulesource.org/schema/mule/core/2.0/mule.xsd http://www.mulesource.org/schema/mule/vm/2.0 http://www.mulesource.org/schema/mule/vm/2.0/mule-vm.xsd http://www.mulesource.org/schema/mule/http/2.0 http://www.mulesource.org/schema/mule/http/2.0/mulehttp.xsd"> <custom-transformer name="StringToNameString" class="org.mule.samples.hello.StringToNameString"/> <custom-transformer name="HttpRequestToNameString" class="org.mule.samples.hello.HttpRequestToNameString"/> <model name="helloSample"> <service name="Greeter"> <inbound> <inbound-endpoint address="http://localhost:8888" transformer-refs="HttpRequestToNameString" synchronous="true"> </inbound-endpoint> <vm:inbound-endpoint path="greeter" transformer-refs="StringToNameString" synchronous="true"/> </inbound> <component class="org.mule.samples.hello.Greeter"/> <outbound> <filtering-router> <vm:outbound-endpoint path="chitchatter"/> <payload-type-filter expectedType="org.mule.samples.hello.NameString"/> </filtering-router> <filtering-router> <vm:outbound-endpoint path="userErrorHandler"/> <payload-type-filter expectedType="java.lang.Exception"/> </filtering-router> </outbound> </service> </model> </mule> Figura 16 Exemplo de um arquivo de configurao Mule

O bloco marcado com o nmero 1 representa declaraes de namespace e esquema, necessrias em um arquivo de configurao. No segundo bloco temos a declarao de dois transformers que sero utilizados nos dois inbound endpoints. No terceiro bloco iniciamos a declarao do modelo e de um servio. O quarto bloco declara dois inbound endpoints. O primeiro utiliza o protocolo HTTP e um transformer e o segundo o protocolo VM e outro transformer. O quinto bloco declara o componente de servio, implementado por uma classe Java. O ltimo bloco, de nmero 6, declara dois outbound endpoints que utilizam o protocolo VM com roteadores equipados com filtros.

4 Estudo de Caso
Neste estudo de caso apresentaremos uma soluo de integrao utilizando o ESB Mule. A soluo ser construda em vrias etapas, iniciando com uma estrutura simples e agregando novos componentes at construir a soluo completa. Toda a soluo ser comentada e seus componentes e configuraes explicadas. Onde necessrio complementaremos com mais teoria e caractersticas do ESB Mule. Nosso estudo de caso baseado no exemplo apresentado no livro Enterprise Integration Patterns [1] e uma variao da implementao loanbroker distribuda como exemplo na instalao do Mule verso comunidade.

4.1 Arquitetura da Soluo


Nosso exemplo uma agncia de emprstimo que oferece um servio de cotao de emprstimos junto a instituies financeiras. A agncia encontra a melhor taxa de emprstimo oferecida por instituies financeiras de acordo com o emprstimo requerido e o perfil do cliente. Ao solicitar o servio o cliente fornece seus dados pessoais (somente nome e CPF por simplicidade), o valor do emprstimo e o prazo, em meses, para o pagamento. O servio retorna ao cliente o nome da instituio financeira que ofereceu a melhor taxa e a taxa oferecida. A figura a seguir apresenta a Agncia de Emprstimo e seu ambiente.

Cliente (browser) Banco-A

Agncia de Emprstimo Web site

Mdulo de Servio

Banco-B

Agncia de Crdito

Banco-C

Figura 17 Agencia de Emprstimo e seu ambiente. O Web site prov o acesso aos servios oferecidos pela agncia. Neste exemplo utilizaremos uma aplicao Web muito simples cujo objetivo colher as informaes sobre o cliente e o emprstimo desejado e solicitar a cotao do emprstimo. Esta aplicao pode rodar em um container como o Apache Tomcat. O mdulo de servio recebe as informaes enviadas pelo cliente, processa a solicitao e envia a resposta, que deve conter o nome da instituio financeira que ofereceu a melhor taxa e a taxa oferecida. Para a realizao do servio solicitado este mdulo utiliza os servios de uma agncia de crdito e de instituies bancrias. Estes servios so oferecidos por aplicaes externas Agncia de Emprstimo. A Agncia de Crdito uma aplicao externa responsvel por analisar o perfil do cliente para assegurar que o emprstimo solicitado seja vivel. Os bancos so aplicaes externas que fornecem cotaes para a solicitao de emprstimo do cliente, eles representam as instituies financeiras. No captulo seguinte apresentaremos a primeira fase deste estudo de caso.

5 Estudo de Caso Fase I


Inicialmente implementaremos apenas um componente definitivo e um auxiliar, provisrio, de nossa aplicao. O componente definitivo ser o componente que representa o servio de cotao de emprstimo. Este componente receber a solicitao do cliente, processar a solicitao e enviar a resposta do servio ao cliente. O componente provisrio ser utilizado para gerar respostas simulando os agentes financeiros (bancos) que no sero implementados nesta verso inicial. A aplicao Agncia de Crdito tambm no ser implementada neste momento. Gradativamente adicionaremos outros componentes e aplicaes nossa aplicao de integrao. Isso nos permitir apresentar a soluo partindo de componentes simples, facilitando a compreenso da tecnologia utilizada. A figura a seguir ilustra o projeto inicial, incluindo os endpoints, transformers e componentes utilizados.

Web site (aplicao Web) HTTP/REST e n d p t r a n Servio de cotao de emprstimo r. assncrono

Cliente (browser)

e n d p

VM

e n d p

Servio de gerao de respostas endpoint transformer

jms

jms

transformer

JMS bus Figura 18 Elementos da soluo inicial.

De acordo com a figura anterior, o cliente envia sua solicitao atravs da aplicao Web, que utiliza o protocolo HTTP/REST para envi-la ao componente responsvel pelo servio de cotao de emprstimo. A solicitao chega a este servio por um endpoint que possui um transformer associado. Este transformer transforma a solicitao recebida em um objeto que representa a solicitao. O componente Servio de Cotao de Emprstimo acionado para processar a solicitao. Nesta implementao inicial este componente simplesmente registra a solicitao (log) e repassa-a para seu endpoint de sada. Este endpoint um endpoint de entrada para o componente Servio de Gerao de Respostas e o protocolo utilizado para a comunicao entre os dois componentes o VM. O componente Servio de Gerao de Respostas provisrio neste tutorial, ele ser substitudo nas prximas etapas medida que o exemplo avanar em direo soluo completa. Este componente recebe a solicitao do cliente e gera uma resposta como se fosse uma agncia bancria. A resposta gerada encaminhada atravs de seu endpoint de sada. Este endpoint tem dois transformers associados e envia a resposta do servio a um roteador assncrono utilizando o protocolo JMS. O primeiro transformer associado ao endpoint transforma a cotao gerada pelo componente, que um objeto, em uma string para ser exibida no browser. O segundo transformer transforma a string gerada pelo primeiro em uma mensagem JMS para que ela possa trafegar pelo JMS Bus. O roteador assncrono envia a resposta para a aplicao Web que a apresentar ao cliente. Na verdade no precisaramos neste momento deste roteador, mas quando este exemplo evoluir teremos respostas enviadas por vrios bancos e o cliente dever receber apenas a cotao mais vantajosa, ou seja, com a menor taxa. Caber a este roteador o papel de selecionar a resposta a ser enviada.

5.1 Implementao da Aplicao


Passamos agora para a implementao desta fase de nossa aplicao. O cdigo foi mantido o mais simples possvel, j que o objetivo deste tutorial mostrar o potencial de um ESB na integrao de aplicaes. Apresentaremos as principais classes para o entendimento da soluo, mas o cdigo produzido nesta fase est disponvel em um pacote zip, contendo a aplicao web e a aplicao integrada.

5.1.1 A Aplicao Web


A aplicao web muito simples e possui apenas alguns arquivos HTML e JSP. O objetivo desta aplicao colher informaes a respeito do cliente e do emprstimo, invocar o servio e apresentar o resultado. As seguintes informaes so obtidas do cliente: nome, CPF, valor do emprstimo e prazo para pagamento (em meses).

5.1.2 O Servio de Cotao de Emprstimo


O servio de cotao de emprstimo oferecido pela agncia representado pela classe ServicoCotacaoEmprestimo, apresentada na figura a seguir. Esta classe recebe a solicitao representada pelo objeto RequisicaoCotacao e registra as informaes relativas a requisio utilizando-se de um Logger. Esta classe apenas o ponto inicial do processamento do servio, nesta fase do projeto a cotao de emprstimo ser gerada pelo servio descrito no item seguinte, mas quando a soluo estiver completa, as cotaes sero geradas pelos bancos. Note que este servio no passa a mensagem (objeto RequisicaoCotacao) explicitamente ao gerador de respostas, estas duas classes so desacopladas e o encaminhamento de mensagens feito por configurao, como veremos no item 4.4.

package spb; import spb.mensagens.RequisicaoCotacao; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Este eo servico que inicia o processo de obtencao de cotacoes. */ public class ServicoCotacaoEmprestimo implements ServicoAgencia { /** * Logger usado por esta classe */ protected final Log logger = LogFactory.getLog(getClass()); public Object getServico(Object requisicao) throws AgenciaEmprestimoException { if (!(requisicao instanceof RequisicaoCotacao)) { throw new AgenciaEmprestimoException("A requisicao recebida nao " + "e do tipo esperado. Esperado: " + RequisicaoCotacao.class.getName() + " Obtido: " + requisicao); } RequisicaoCotacao req = (RequisicaoCotacao)requisicao; String[] params = new String[] { req.getCliente().getNome(), String.valueOf(req.getCliente().getCpf()), String.valueOf(req.getValor()), String.valueOf(req.getPrazo()) }; logger.info("\n***** " + MensagemLocal.requisicaoRecebida(params)); return req; } } Figura 19 Servio de Cotao de Emprstimo

5.1.3 O Servio de Gerao de Respostas


Esta classe, apresentada na figura a seguir, gera uma resposta aleatria contendo um nome de banco e uma taxa de emprstimo. O resultado gerado apresentado como um objeto Cotacao. A solicitao do cliente fluiu do servio de cotao de emprstimo para este servio e passar agora ao roteador assncrono. Durante este fluxo foram aplicadas algumas transformaes que sero apresentadas nos Transformers descritos nos itens seguintes.

package spb; import import import import spb.mensagens.RequisicaoCotacao; spb.mensagens.Cotacao; org.apache.commons.logging.Log; org.apache.commons.logging.LogFactory;

import java.lang.Math; /** * Este eum servico provisorio de geracao de respostas a pedidos * de cotacao de emprestimo. Este servico sera substituido pelos * bancos ateo final da implementacao deste exemplo de integracao. */ public class GeradorRespostas { /** * Logger usado por esta classe */ protected final Log logger = LogFactory.getLog(getClass()); public Object geraResposta(RequisicaoCotacao requisicao) throws AgenciaEmprestimoException { Cotacao cotacao = new Cotacao(); // Os bancos receberao os nomes: Banco-A, Banco-B e Banco-C. cotacao.setNomeBanco("Banco-" + (char)(((new Double(Math.random() * 100).intValue())%3)+65)); // Uma taxa egerada randomicamente para simular uma taxa // oferecida pelo banco. cotacao.setTaxa(Math.random() * 10); logger.info("\n***** " + MensagemLocal.taxaRecebida(cotacao)); return cotacao; } }

Figura 20 Servio de Gerao de Respostas

5.1.4 O Transformer de Solicitaes de Cotao


Quando uma mensagem transita em Mule, na verdade uma instancia de org.mule.api.MuleEvent quem trafega. Este objeto carrega no apenas o contedo da mensagem, mas tambm um contexto do evento. O contexto composto por referncias a vrios objetos, incluindo credencias de segurana, se houver, a sesso na qual a requisio processada e o contexto Mule. O contedo da mensagem, conhecido como payload, por sua vez envolvido por uma instncia de org.mule.api.MuleMessage, que prov diferentes meios para acessar o payload sob diferente formas. Sobre as mensagens que fluem em Mule que aplicamos os transformers, que podem transformar mensagens antes delas serem processadas por um componente ou aps seu processamento, dependendo de onde se encontra o transformer, em um inbound endpoint ou em um outbound endpoint. A maneira mais fcil de construir um transformer estendendo a classe org.mule.transformer.AbstractTransformer, que a base para todos os transformers, e implementando o mtodo doTransform. Usaremos esta prtica no prximo item, onde descreveremos o segundo transformer utilizado neste exemplo.

Todas as vezes que precisamos ler ou alterar propriedades de uma mensagem em um transformer, precisamos ter acesso ao objeto org.mule.api.MuleMessage. A maneira mais adequada de se escrever um transformer para esses casos estendendo o transformer org.mule.transformer.AbstractMessageAwareTransformer, que o transformer que tem a referncia para a mensagem corrente. Usamos esta referencia para termos acesso s propriedades da mensagem corrente, teis para o transformer. Utilizaremos esta classe para construir o transformer de Solicitao de Cotao. Uma solicitao de cotao de emprstimo de um cliente chega aplicao integrada, atravs da aplicao Web, como uma requisio REST. Este transformer retira as informaes enviadas pelo cliente da mensagem REST e cria um objeto RequisicaoCotacao. Este objeto que ser enviad o ao Servio de Cotao de Emprstimo para processamento. O cdigo deste transformer apresentado na figura a seguir. O transformer RequisicaoRestParaRequisicaoCotacao, sobrescreve o mtodo transform da classe AbstractMessageAwareTransformer, l as informaes enviadas pelo cliente (nome, CPF, valor e prazo) e constri um objeto RequisicaoCotacao, que o resultado da transformao. O mtodo getStringProperty de MuleMessage utilizado para obter os valores, dados seus nomes, como esto estabelecidos na mensagem. Este transformer tambm registra a classe de retorno em seu construtor invocando o mtodo setReturnClass de AbstractMessageAwareTransformer, isto permite ao Mule validar a sada antes de passar a mensagem adiante. Neste caso estamos dizendo que o retorno ser um objeto da classe RequisicaoCotacao.

package spb.transformers; import import import import import org.mule.api.MuleMessage; org.mule.api.transformer.TransformerException; spb.mensagens.Cliente; spb.mensagens.RequisicaoCotacao; org.mule.transformer.AbstractMessageAwareTransformer;

/** * Converte parametros da mensagem REST para o objeto * RequisicaoCotacaoCliente. */ public class RequisicaoRestParaRequisicaoCotacao extends AbstractMessageAwareTransformer { public RequisicaoRestParaRequisicaoCotacao() { setReturnClass(RequisicaoCotacao.class); } public Object transform(MuleMessage message, String outputEncoding) throws TransformerException { String nome; String cpf; double valor; int prazo; try { nome = getParam(message, "nomeCliente"); cpf = getParam(message, "cpf"); valor = Double.parseDouble(getParam(message, "valorEmprestimo")); prazo = Integer.parseInt(getParam(message, "prazoEmprestimo")); } catch (Exception e) { throw new TransformerException(this, e); } Cliente c = new Cliente(nome, cpf); RequisicaoCotacao requisicao = new RequisicaoCotacao(c, valor, prazo); return requisicao; } protected String getParam(MuleMessage message, String nomeParam) throws NullPointerException { String valorParam = message.getStringProperty(nomeParam,null); if (valorParam == null) { throw new IllegalArgumentException("Parametro '" + nomeParam + "' nao pode ser omitido."); } return valorParam; } }

Figura 21 Transformer de Solicitaes de Cotao

5.1.5 O Transformer de Resposta de Cotao


O Gerador de Respostas produz objetos Cotacao como resultado de seu servio . Este objeto no pode ser enviado com resposta aplicao Web, a menos que ela tambm conhea a classe Cotacao, o que no conveniente. Precisamos ento de um transformer para converter o objeto Cotacao em uma string que possa ser apresentada ao cliente como resposta sua solicitao. O transformer CotacaoParaString, veja a listagem na figura a seguir, realiza esta tarefa. Este transformer estende a classe AbstractTransformer e implementa o mtodo doTransform. Tudo que este mtodo faz construir uma string com os dados mantidos pelo objeto Cotacao. No construtor do transformer foram registradas, atravs dos mtodos registerSourceType e setReturnClass, as classes fonte e retorno, respectivamente Cotacao e String. Com isso no precisamos nos preocupar em validar as entradas e sadas.
package spb.transformers; import org.mule.api.transformer.TransformerException; import spb.mensagens.Cotacao; import org.mule.transformer.AbstractTransformer; public class CotacaoParaString extends AbstractTransformer { public CotacaoParaString() { super(); registerSourceType(Cotacao.class); this.setReturnClass(String.class); } public Object doTransform(Object message, String encoding) throws TransformerException { Cotacao cotacao = (Cotacao)message; String banco = cotacao.getNomeBanco(); String taxa = Double.toString(cotacao.getTaxa()); String strCot = "<ul><li>Instituicao financeira: " + banco + "</li><li>Taxa: " + taxa + "</li></ul>"; return strCot; } }

Figura 22 Transformer de Resposta de Cotao

5.2 Implementao do Fluxo de Mensagens


Para estabelecer o fluxo de mensagens da aplicao e interligar seus elementos utilizamos o arquivo de configurao Mule. As figuras a seguir (figuras 23, 24, 25, e 26) apresentam a configurao da fase I de nossa aplicao. Cada figura representa uma parte do arquivo, que foi dividido apenas para facilitar a explicao. Este arquivo ser modificado durante o desenvolvimento deste tutorial at chegar a sua verso final.

5.2.1 Declaraes de Namespaces e Esquemas.


Neste bloco do arquivo de configurao, figura 23, declaramos os namespaces e esquemas necessrios. Declaramos inicialmente o esquema Mule Core, onde esto definidos os elementos: Models, Transformers, Routers, Filters, Security manager, components, etc. O segundo esquema que aparece no arquivo o XML Schema definido pelo W3C. Depois temos os esquemas para os protocolos Jetty, VM e JMS que usamos no arquivo de configurao. Os elementos xmlns definem os namespaces e os elementos xsi os esquemas.
<?xml version="1.0" encoding="UTF-8"?> <mule xmlns="http://www.mulesource.org/schema/mule/core/2.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jetty="http://www.mulesource.org/schema/mule/jetty/2.2" xmlns:vm="http://www.mulesource.org/schema/mule/vm/2.2" xmlns:jms="http://www.mulesource.org/schema/mule/jms/2.2" xsi:schemaLocation=" http://www.mulesource.org/schema/mule/jetty/2.2 http://www.mulesource.org/schema/mule/jetty/2.2/mule-jetty.xsd http://www.mulesource.org/schema/mule/core/2.2 http://www.mulesource.org/schema/mule/core/2.2/mule.xsd http://www.mulesource.org/schema/mule/vm/2.2 http://www.mulesource.org/schema/mule/vm/2.2/mule-vm.xsd http://www.mulesource.org/schema/mule/jms/2.2 http://www.mulesource.org/schema/mule/jms/2.2/mule-jms.xsd">

Figura 23 Configurao de namespaces e esquemas.

5.2.2 Configurao dos Transformers


No bloco apresentado na figura 24 temos as declaraes dos transformers utilizados na aplicao. Temos dois customer transformers e um predefinido. O primeiro o que faz a transformao da mensagem REST para objeto RequisicaoCotacao. O segundo utilizado para transformar a resposta, que um objeto Cotacao, para uma String. Estes dois transformers possuem uma classe associada que realiza a transformao. O terceiro transformer j um transformer que faz parte do Mule. Este transformer transforma um objeto em uma mensagem JMS, para que possa trafegar pelo JMS Bus. Na configurao do modelo mais adiante ficar mais claro o uso dos transformers.
<custom-transformer name="RequisicaoRestParaRequisicaoCotacao" class="spb.transformers.RequisicaoRestParaRequisicaoCotacao" /> <custom-transformer name="CotacaoParaString" class="spb.transformers.CotacaoParaString" /> <jms:object-to-jmsmessage-transformer name="ObjectToJmsMessage"/>

Figura 24 Configurao dos transformers

5.2.3 Configurao dos Endpoints


A configurao de endpoints envolve a configurao de conectores e transportes a serem usados nos endpoints. Os endpoints podem ser declarados na seo model da configurao, onde so utilizados, ou podem ser declarados globalmente e referenciados por nome no local de sua utilizao. A declarao global tem a vantagem de facilitar o reuso da declarao. Vamos declar-los globalmente para ficar mais fcil a explicao. Normalmente, para cada protocolo utilizado, precisamos declarar

um ou mais conectores. Mas muitos conectores so utilizados em sua configurao default, possibilitando assim que o prprio Mule os crie, evitando assim a necessidade de declar-los no arquivo de configurao. Isso acontece normalmente com os transportes VM e HTTP. Uma configurao de um endpoint faz referncia ao conector a ser utilizado, mas, por facilidade, se temos apenas um conector para um determinado transporte, no precisamos mencion-lo na declarao do endpoint; o Mule associar automaticamente o conector ao endpoint. Vamos iniciar a configurao dos endpoints de nossa aplicao pelo endpoint que recebe requisies REST do cliente. O transporte Jetty prov suporte para expor servios sobre HTTP atravs de um servidor Jetty light-weight. O conector Jetty declarado da seguinte forma: <jetty:connector name="httpConnector" useContinuations="false" /> A propriedade useContinuations utilizada para definir se deve ser usado o mecanismo de continuao, permitindo a liberao de conexes em situaes de muita carga. Normalmente esse conector no precisa ser declarado, Mule o instanciar automaticamente. A configurao do endpoint que recebe requisies REST fica da seguinte forma: <endpoint name="RequisicaoClienteREST" connector-ref="httpConnector" address="jetty:rest://localhost:8888/AgenciaEmprestimo" /> O endpoint de nome RequisicaoClienteREST declara a URL do servio Web e usa o conector Jetty httpConnector. Outro transporte utilizado pela aplicao o transporte VM, usado na comunicao entre os servios Cotao de Emprstimo e Gerao de Respostas. O conector para o transporte VM definido da seguinte forma: <vm:connector name="vmConnector" queueEvents="true"/> O nome escolhido para o conector foi vmConnector e a propriedade queueEvents configurada para true. Esta propriedade define se as mensagens sero transferidas de maneira assncrona (true) ou sncrona. Na forma sncrona as mensagens so transferidas na modalidade ponto-a-ponto, caso contrrio as mensagens so colocadas em uma fila. O transporte VM de grande utilidade na comunicao entre componentes internos, como estamos utilizando em nossa aplicao. Ele tambm til em fase de testes para simular o transporte JMS, por exemplo. Outra caracterstica interessante deste transporte o fato de podermos persistir as mensagens que esto na fila quando o Mule desativado. Para configurarmos a fila para ser persistente utilizamos a propriedade queue -profile no conector: <vm:connector name="vmConnector" queueEvents="true"> <queue-profile persistence=true maxOutstandingMessages=1000/> </vm:connector> A propriedade maxOutstandingMessages define o nmero mximo de itens que sero persistidos. Definimos ento o endpoint da seguinte forma: <endpoint name="Requisicoes" connector-ref="vmConnector" address="vm://spb.emprestimo.requisicoes" /> O nome do endpoint Requisies, estamos utilizando o conector vmConnector e a fila a ser utilizada definida como spb.emprestimo.requisicoes, que criada no file system na estrutura da aplicao.

O ltimo transporte utilizado por nossa aplicao nesta fase o transporte JMS. O transporte JMS uma opo atrativa para integrao de aplicaes. Se voc est trabalhando em um ambiente Java e tem controle sobre a rede entre as aplicaes, usar o JMS faz muito sentido ele assncrono, seguro, confivel e normalmente muito rpido. Ele oferece a possibilidade de se trabalhar com diferentes payloads e em ambiente puramente Java podemos mesmo passar objetos serializados. O transporte JMS pode ser utilizado para enviar e receber mensagens sobre filas ou tpicos. Mule no implementa um JMS Server, podemos usar o JMS transporte em conjuno com implementaes como ActiveMQ, OpenMQ ou Tibco EMS. A declarao de um conector obrigatria para o transporte JMS, ao contrrio dos transportes VM e HTTP, por exemplo. A seguir temos uma declarao de conector para JMS: <jms:activemq-connector name="jmsConnector" /> Aqui definimos um conector JMS, de nome jmsConnector, e que utiliza a implementao ActiveMQ. Outras propriedades podem ser configuradas no conector, como, por exemplo, nome de usurio e senha para conectar ao JMS Server. Definimos o endpoint para nossa aplicao da seguinte forma: <endpoint name="Cotacoes" connector-ref="jmsConnector" address="jms://spb.emprestimo.cotacoes" /> O endpoint tem como nome spb.emprestimo.cotacoes. Cotacoes, usa o conector jmsConector e a fila

A figura 25 rene todas as configuraes de endpoints que estabelecemos para nossa aplicao em duas verses, uma completa e uma simplificada, aproveitando a caracterstica de configurao automtica que o Mule nos oferece. As duas so equivalentes.
<jetty:connector name="httpConnector" useContinuations="false" /> <vm:connector name="vmConnector" queueEvents="true"/> <jms:activemq-connector name="jmsConnector" /> <endpoint name="RequisicaoClienteREST" connector-ref="httpConnector" address="jetty:rest://localhost:8888/AgenciaEmprestimo" /> <endpoint name="Requisicoes" connector-ref="vmConnector" address="vm://spb.emprestimo.requisicoes" /> <endpoint name="Cotacoes" connector-ref="jmsConnector" address="jms://spb.emprestimo.cotacoes" />

Verso Simplificada
<jms:activemq-connector name="jmsConnector" /> <endpoint name="RequisicaoClienteREST" address="jetty:rest://localhost:8888/AgenciaEmprestimo" /> <endpoint name="Requisicoes" address="vm://spb.emprestimo.requisicoes" /> <endpoint name="Cotacoes" address="jms://spb.emprestimo.cotacoes" />

Figura 25 Configurao dos endpoints

5.2.4 Configurao dos Servios


Agora vamos configurar a nossa aplicao definindo os servios com seus endpoints, componentes, transformers e conexes entre componentes. Aqui definimos o fluxo de mensagens entre os componentes. A figura 26 apresenta a configurao do modelo para nossa aplicao. <model name="AgenciaEmprestimo"> <service name="CotacaoEmprestimo"> <inbound> <inbound-endpoint ref="RequisicaoClienteREST" transformer-refs="RequisicaoRestParaRequisicaoCotacao" /> </inbound> <component class="spb.ServicoCotacaoEmprestimo" /> <outbound> <pass-through-router> <outbound-endpoint ref="Requisicoes" /> </pass-through-router> </outbound> <async-reply> <inbound-endpoint ref="Cotacoes" /> <single-async-reply-router /> </async-reply> </service> <service name="GeradorRespostas"> <inbound> <inbound-endpoint ref="Requisicoes" /> </inbound> <component class="spb.GeradorRespostas" /> <outbound> <pass-through-router> <outbound-endpoint ref="Cotacoes" transformer-refs="CotacaoParaString ObjectToJmsMessage" /> </pass-through-router> </outbound> </service> </model> Figura 26 O modelo da aplicao. O servio declarado com o nome CotacaoEmprestimo representa o servio de cotao de emprstimos oferecido pela aplicao. Este servio possui dois endpoints, (um inbound e um outbound), um componente (classe spb.ServicoCotacaoEmprestimo) e um roteador assncrono. O endpoint inbound tem a seguinte configurao: <inbound> <inbound-endpoint ref="RequisicaoClienteREST" transformer-refs="RequisicaoRestParaRequisicaoCotacao" /> </inbound>

O endpoint declarado, RequisicaoClienteREST, o responsvel por receber requisies REST. Este endpoint est associado ao transformer RequisicaoRestParaRequisicaoCotacao, que transforma a mensagem recebida do cliente em um objeto da classe RequisicaoCotacao. O objeto resultante desta transformao encaminhado ao componente implementado pela classe ServicoCotacaoEmprestimo. Aps o processamento implementado pelo componente, o fluxo continua pelo outbound Requisicoes, que possui um roteador do tipo pass-through-router. Este roteador simplesmente passa adiante a mensagem. <outbound> <pass-through-router> <outbound-endpoint ref="Requisicoes" /> </pass-through-router> </outbound> O ltimo elemento deste servio um roteador assncrono de respostas configurado da seguinte forma: <async-reply> <inbound-endpoint ref="Cotacoes" /> <single-async-reply-router /> </async-reply> Um roteador assncrono de respostas aplicvel em situaes sncronas, j que uma mensagem assncrona no gera respostas. No nosso caso o cliente enviou uma solicitao e espera uma resposta e esse roteador o responsvel por encaminhar a mensagem no final do processamento. Mltiplas respostas podem existir porque a mensagem original pode ter disparado vrios servios que respondero em diferentes momentos. Os roteadores de respostas so utilizados para agregar as respostas em uma nica resposta a ser enviada para o cliente. No estado atual de nosso exemplo temos apenas uma resposta gerada para cada solicitao, o que no justifica o uso deste roteador. Mas quando evoluirmos este exemplo, ns teremos respostas de vrios bancos e haver a necessidade de selecionar a melhor resposta, que ser encaminhada ao cliente. Podemos ter trs tipos de roteadores de respostas, single-async-reply-router, collection-async-replyrouter e custom-async-reply-router. Os trs tipos possuem um endpoint associado, que o ponto de entrada das respostas que ele ter que encaminhar. O single-async-reply-router envia a primeira resposta que receber no endpoint e descarta as outras. O collection-async-reply-router retorna todas as mensagens recebidas no endpoint e o custom-async-reply-router repassa todas as mensagens recebidas para uma classe Java responsvel pela agregao das mensagens. Na evoluo de nosso exemplo mudaremos este single-async-reply-router para um custom-async-reply-router. O segundo servio configurado o gerador de respostas. Este servio conta com dois endpoints (inbound e outbound), um componente e dois transformers. A mensagem chega a este servio pelo endpoint Requisicoes, processada pelo componente GeradorRespostas e vai para o endpoint Cotacoes. Neste endpoint de sada temos um roteador do tipo pass-through e dois transformers, que so aplicados antes da mensagem deixar o endpoint. O primeiro transformer aplicado o CotacaoParaString, que gera a string a ser apresentada ao cliente a partir dos dados mantidos pelo objeto Cotacao. Para que a string gerada possa continuar trafegando pelo JMS bus e alcanar o roteador assncrono de respostas, ela passa pelo transformer ObjectToJmsMessage. Este transformer, que um transformer do transporte JMS, encapsula a string em uma mensagem JMS. A mensagem ento encaminhada pelo roteador assncrono para o cliente.

5.3 Organizao da Aplicao


A implementao deste tutorial est organizada na seguinte estrutura de diretrios:

O diretrio tutorial abriga a aplicao mule no diretrio agencia-emprestimo e a aplicao Web no diretrio ClietRest. Vamos visitar primeiro a estrutura definida por agencia-emprestimo. Neste diretrio encontramos o arquivo build.xml, utilizado por ANT para gerar a aplicao, e o diretrio conf que contm o arquivo mule-config.xml, que o arquivo de configurao de nossa aplicao. Os arquivos fonte se encontram abaixo do diretrio src. No diretrio spb encontramos as classes que implementam os servios e dois diretrios, mensagens e transformers:

No diretrio mensagens encontramos as classes Cliente, Cotacao e RequisicaoCotacao:

No diretrio transformers encontramos as duas classes que implementam os transformers utilizados no exemplo:

No diretrio resources/mensagens temos um arquivo para definir strings utilizadas no logging. O diretrio ClientRest contm a aplicao Web utilizada para invocar o servio oferecido pela aplicao que estamos desenvolvido neste tutorial. Esta aplicao roda em um container Web como o Tomcat. O diretrio AgenciaEmprestimo.war contm arquivos que constituem a pgina do site, este tutorial no formato PDF e os diretrios META-INF e WEB-INF:

No diretrio WEB-INF encontramos o arquivo de configurao da aplicao web.xml e um diretrio lib com as bibliotecas necessrias para invocar um servio utilizando REST.

5.4 Executando a Aplicao


Antes de executar a aplicao precisamos fazer o download e a instalao do Mule. A Edio Comunidade do Mule pode ser obtido do site: http://www.mulesource.org/display/MULE/Download. Aps o download descompacte o Mule em um diretrio. Ser necessrio tambm ter instalado o Java Developer Kit (JDK) 1.5 e o Maven ou Ant. Crie as variveis de ambiente para Java (JAVA_HOME), Maven (MAVEN_HOME) ou Ant (ANT_HOME). Crie a varivel de ambiente MULE_HOME, definindo o diretrio de instalao do Mule. Detalhes da instalao do Mule podem ser encontrados em http://www.mulesource.org/display/MULE2INTRO/Home. Aps a instalao de Mule podemos ento gerar a aplicao. Para gerar a aplicao abrimos uma janela console, vamos ao diretrio agencia-emprestimo e executamos o ant (simplesmente digitamos ant), que ir gerar a aplicao com base no arquivo build.xml. Com a aplicao gerada vamos ao diretrio conf e executamos o Mule a partir de uma janela console, simplesmente digitando mule. O Mule far seu startup e colocar a aplicao no ar. Para invocar o servio oferecido pela aplicao utilizamos a aplicao Web. Para colocar esta aplicao no ar basta copiar o diretrio AgenciaEmprestimo.war para o diretrio webapps do Tomcat e iniciar o Tomcat. Com o Tomcat no ar usamos um browser para ter acesso ao servio atravs da URL http://localhost:8080/AgenciaEmprestimo. A seguinte pgina web ser apresentada:

Selecionando a opo Agencia de Emprstimo obteremos a pgina seguinte, que possibilita a invocao do servio implementado pela aplicao Mule em execuo:

Fornea as informaes necessrias e pressione o boto Cotar Emprestimo. O servio ser invocado retornado uma pgina de resposta como:

Na prxima etapa deste tutorial acrescentaremos novos elementos nossa aplicao.

6 Estudo de Caso Fase II


Nesta fase do desenvolvimento de nosso estudo de caso vamos adicionar vrios componentes nossa aplicao. Removeremos o componente temporrio gerador de respostas, que ser substitudo por novos componentes definitivos, como foi dito na fase anterior. Adicionaremos um mdulo externo que representa uma agncia de crdito. Veja a arquitetura da soluo (figura 17). Este mdulo ser um EJB a ser executado no JBoss, o que nos possibilitar utilizar o transporte EJB, um transporte diferente dos que utilizamos na fase I. Adicionaremos tambm componentes internos, inclusive os trs bancos utilizados no nosso estudo de caso. Estes bancos sero substitudos por componentes externos nas prximas fases do estudo de caso, possibilitando o estudo de outros transportes. Novos roteadores, com filtros, um recurso bastante comum, sero utilizados na soluo. A figura 27 apresenta o fluxo de mensagens na aplicao. O cliente envia uma requisio de servio utilizando a aplicao Web. O ponto de entrada das requisies o mdulo de Servios da Agencia, que verifica se as requisies so vlidas. Requisies invlidas geram mensagens de erro que so encaminhadas ao servio de Tratamento de Erros, que posteriormente as encaminha ao roteador assncrono de respostas, responsvel por envi-las ao cliente. O mdulo de Servios da Agencia trata dois tipos de requisies de servios, a de cotao de emprstimo, que j era tratada na fase anterior, e uma nova, que solicita o perfil de crdito do cliente

mantido pela Agncia de Crdito (EJB externo). Como o servio de cotao de emprstimo tambm depende do perfil de crdito do cliente, nos dois tipos de servios a requisio encaminhada Agncia de Crdito. A resposta (perfil de crdito) fornecida pela Agncia de Crdito pode tomar dois caminhos distintos. Se a requisio de servio for uma solicitao de perfil de crdito a resposta ser encaminhada diretamente ao roteador de respostas para ser enviada ao cliente. Se a requisio for de cotao de emprstimo ela ser encaminhada ao Seletor Bancrio. O Seletor Bancrio montar uma lista com os bancos que oferecem emprstimos nas condies solicitadas para clientes com o perfil de crdito obtido. Novamente a mensagem produzida, neste caso pelo Seletor Bancrio, pode tomar dois caminhos distintos. Se nenhum banco oferece emprstimo nas condies solicitadas, a mensagem encaminhada ao servio de Tratamento de Erros para ser encaminhada ao roteador de respostas. No sendo este o caso, a mensagem encaminhada ao Gateway Bancrio. O Gateway Bancrio envia a mensagem a todos os bancos que oferecem emprstimos nas condies solicitadas. Os bancos que recebem a mensagem com a requisio calculam a sua taxa de emprstimo e encaminham a resposta ao roteador de respostas. No item que trata da implementao do fluxo de mensagens veremos como so configurados os endpoints, utilizando roteadores e filtros, para implementar o fluxo que acabamos de descrever. A figura 28 apresenta o projeto para esta fase, apresentando os componentes e seus endpoints. O componente Servios da Agncia substitui o antigo componente Servio de Cotao de Emprstimo, isso porque agora temos dois servios implementados na agncia de emprstimo: Servio perfil de crdito este servio fornece o perfil de crdito do cliente em termos de uma pontuao, que espelha a pontualidade em pagamentos de emprstimos anteriores, e um histrico, que representa o perodo de tempo observado para calcular a pontuao. Servio cotao de emprstimo este o mesmo servio da implementao da fase I, que fornece a menor taxa oferecida por um banco para o emprstimo desejado. O Componente Gateway Agencia de Crdito estabelece a ligao entre a Agncia de Emprstimo e a Agncia de Crdito, que est em execuo em outro ambiente, no caso um servidor JBoss. O componente Agncia de Crdito um componente externo que fornece o perfil de crdito dos clientes mapeado em dois nmeros inteiros, representando uma pontuao e um perodo de avaliao do histrico do cliente. O Seletor Bancrio o componente responsvel por selecionar os bancos que oferecem emprstimos nas condies requeridas pelo cliente. Este componente se baseia no perfil de crdito do cliente, no valor do emprstimo e no prazo de pagamento. A lista de bancos selecionados passada ao componente Gateway Bancrio. O Gateway Bancrio faz a ligao entre a Agncia de Emprstimo e os bancos, que nesta fase ainda so componentes internos. O gateway envia a requisio do cliente para os bancos que fazem parte da lista construda pelo Seletor Bancrio. Os bancos so as instituies financeiras parceiras da Agncia de Emprstimo. Eles fornecem taxas de emprstimo para as solicitaes dos clientes da agncia. Finalmente temos o componente de tratamento de erros. Este componente prepara mensagens de erro para enviar ao cliente em situaes anormais.

Cliente

Requisio de servio

Servios da Agncia sim erro no Agncia de Crdito

Perfil de crdito servio Cotao de emprstimo Seletor Bancrio sim erro no Tratamento de Erros Gateway Bancrio

Banco A

Banco B

Banco C

Roteador de Respostas

Cliente Figura 27 Fluxo de mensagens.

Web site (aplicao Web) HTTP/REST e n d p t r a n Servios da Agncia

Cliente (browser) ejb jms e n d p r o u t e n d p Binding Gateway Agncia de Crdito

Agncia de Crdito (EJB)

R e n d p r o u t vm

r. assncrono R jms R e n d p Tratamento de Erros jms e n d p e n d p e n d p e n d p r o u t jms e n d p r o u t e n d p Seletor Bancrio

e n d p

Banco A

jms

Banco B

Gateway Bancrio

e n d p

Banco C

Figura 28 Elementos da fase II do estudo de caso.

6.1 Implementao da Aplicao


Passamos agora para a implementao desta fase de nosso estudo de caso. Novamente o cdigo foi mantido o mais simples possvel. Apresentaremos as principais classes para o entendimento da soluo, mas o cdigo produzido nesta fase est disponvel em um pacote zip, contendo a aplicao web, o EJB (Agncia de Crdito) e a aplicao integrada.

6.1.1 A Aplicao Web


Esta aplicao sofreu pequenas modificaes, apenas o necessrio para oferecer o segundo servio da agncia, que o fornecimento de perfil de crdito do cliente. Apenas o arquivo agencia.jsp foi alterado.

6.1.2 Servios da Agncia de Emprstimo


A classe ServicosAgencia, cuja listagem apresentada na figura 29, substitui a antiga classe ServicoCotacaoEmprestimo e implementa os pontos de entrada das requisies dos clientes. O mtodo getCotacao recebe requisies de cotaes de emprstimos e o mtodo getPerfil recebe as requisies de obteno de perfil de crdito. Associado ao inbound endpoint do servio implementado por esta classe est o transformer que converte a requisio REST para um objeto da classe RequisicaoServico. Este transformer, que j existia na implementao da fase I, ganhou uma nova funcionalidade, a de validar os argumentos recebidos. Se houver algum argumento invlido o campo status da requisio refletir essa falha. Se as requisies possuem argumentos vlidos os mtodos de ServicosAgencia propagam a requisio, caso contrrio eles propagam uma mensagem de erro que ser encaminhada ao componente de tratamento de erros para envio ao cliente.
package spb; import import import import import import spb.mensagens.RequisicaoServico; spb.mensagens.StatusRequisicao; spb.mensagens.TipoRequisicao; spb.mensagens.MensagemErro; org.apache.commons.logging.Log; org.apache.commons.logging.LogFactory;

/** * Esta classe possui os pontos de entrada para as * requisicoes dos clientes. Dois tipos de servicos * sao oferecidos: Cotacao de Emprestimo e Perfil * de Credito. */ public class ServicosAgencia implements Servicos { /* Logger */ protected final Log logger = LogFactory.getLog(getClass()); /** * Este metodo einvocado quando chega uma * solicitacao de cotacao de emprestimo. */ public Object getCotacao(Object requisicao) throws AgenciaEmprestimoException { // Verifica se o argumento e' uma requisicao RequisicaoServico req = verificaRequisicao(requisicao); // A requisicao uma solicitacao de cotacao de emprestimo req.setTipo(TipoRequisicao.COTACAO); // Verifica se os argumentos da requisicao sao validos. // Os argumentos foram validados pelo transformer colocado // no inbound endpoint deste componente. StatusRequisicao status = req.getStatus();

Figura 29 Servios da Agncia de Emprstimo (continua)

if (status == StatusRequisicao.OK) { // Log da requisicao. String[] params = new String[] { req.getCliente().getNome(), String.valueOf(req.getCliente().getCpf()), String.valueOf(req.getValor()), String.valueOf(req.getPrazo()) }; logger.info("\n[REQUISICAO COTACAO EMPRESTIMO] " + MensagemLocal.requisicaoRecebida(params)); // A mensagem propagada pelo outbound endpoint contera' // a requisicao do servico Cotacao de Emprestimo. return req; } else { // A requisicao possui argumentos invalidos. A mensagem // propagada pelo outbound endpoint nao contera' a // requisicao e sim uma mensagem de erro. MensagemErro msgErro = new MensagemErro(status); return msgErro; } } /** * Este metodo einvocado quando chega uma * solicitacao de perfil de credito. */ public Object getPerfil(Object requisicao) throws AgenciaEmprestimoException { // Verifica se o argumento e' uma requisicao RequisicaoServico req = verificaRequisicao(requisicao); req.setTipo(TipoRequisicao.PERFIL); StatusRequisicao status = req.getStatus(); // // // if Verifica se os argumentos da requisicao sao validos. Os argumentos foram validados pelo transformer colocado no inbound endpoint deste componente. (status == StatusRequisicao.OK) { // Log da requisicao. String[] params = new String[] { req.getCliente().getNome(), String.valueOf(req.getCliente().getCpf())}; logger.info("\n[REQUISICAO PERFIL CREDITO] " + MensagemLocal.requisicaoHistorico(params)); // A mensagem propagada pelo outbound endpoint contera' // a requisicao do servico Perfil de Credito. return req; } else { // A requisicao possui argumentos invalidos. A mensagem // propagada pelo outbound endpoint nao contera' a // requisicao e sim uma mensagem de erro. MensagemErro msgErro = new MensagemErro(status); return msgErro; } }

Figura 29 Servios da Agncia de Emprstimo (continua).

/** * Este verifica se o objeto recebido e' uma * requisicao de servico. */ private RequisicaoServico verificaRequisicao(Object requisicao) throws AgenciaEmprestimoException { if (!(requisicao instanceof RequisicaoServico)) { throw new AgenciaEmprestimoException("A requisicao recebida nao " + "e do tipo esperado. Esperado: " ] + RequisicaoServico.class.getName() + " Obtido: " + requisicao); } return (RequisicaoServico)requisicao; } }

Figura 29 Servios da Agncia de Emprstimo (continuao).

6.1.3 Agncia de Crdito


A Agncia de Crdito um EJB externo que roda em um servidor de aplicaes, como o JBoss. As classes AgenciaCredito (interface), AgenciaCreditoHome (interface home) e AgenciaCreditoBean implementam o EJB. A figura 30 apresenta a classe AgenciaCreditoBean, que gera randomicamente a pontuao e o histrico que compem o perfil de crdito do cliente. A resposta enviada pelo EJB apresenta o perfil de crdito no formato XML: <perfil-credito> <nome-cliente> ... </nome-cliente> <cpf-cliente> ... </cpf-cliente> <pontuacao-credito> ... </pontuacao-credito> <historico-cliente> ... </historico-cliente> </perfil-credito> Do lado da aplicao Mule foi adicionado um componente para fazer a ligao com o bean Agncia de Crdito. Este componente, representado pela classe GatewayAgenciaCredito, utiliza a interface ServicoAgenciaCredito para obter o perfil de crdito co cliente. A figura 31 apresenta estas classes. Este gateway invoca o EJB e obtm o perfil de crdito. Aps obter o perfil de crdito o gateway verifica que tipo de requisio est sendo atendida para decidir que mensagem ser encaminhada a partir dele. Se a requisio do cliente para obteno do perfil de crdito o trabalho est concludo, ento o gateway monta a resposta ao cliente contendo o perfil e esta resposta encaminhada ao roteador de respostas para ser enviada ao cliente. Se a requisio do cliente para cotar um emprstimo, o perfil de crdito adicionado solicitao que encaminhada ao Seletor Bancrio. A interface para o EJB (ServicoAgenciaCredito) define o mtodo getPerfilCredito que recebe um argumento, o cliente, que representado por um objeto da classe Cliente, e retorna um objeto da classe PerfilCredito. Mas o mtodo getPerfilCredito do EJB recebe dois argumentos do tipo String, o nome e o CPF do cliente, e retorna uma String contendo o perfil no formato XML. A converso dos argumentos e da resposta de responsabilidade de dois transformers, que apresentaremos mais adiante. Outro elemento utilizado para invocar o EJB o binding interface, que tambm apresentaremos mais adiante.

package org.credit; import java.text.MessageFormat; import javax.ejb.EJBException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; /** * <code>AgenciaCreditoBean</code> obtem o de perfil de credito do * cliente. */ public class AgenciaCreditoBean implements SessionBean { // Mensagem com o perfil de credito solicitado. private static final String MSG = "<perfil-credito><nome-cliente>{0}</nome-cliente>" + "<cpf-cliente>{1}</cpf-cliente><pontuacao-credito>" + "{2}</pontuacao-credito><historico-cliente>{3}" + "</historico-cliente></perfil-credito>"; public void ejbActivate() throws EJBException { /* nada a fazer */ } public void ejbPassivate() throws EJBException { /* nada a fazer */ } public void ejbRemove() throws EJBException { /* nada a fazer */ } public void ejbCreate() throws EJBException { /* nada a fazer */ } public void setSessionContext(SessionContext sessionContext) throws EJBException { /* SessionContext pode ser ignorado */ } protected int getPontuacaoCredito(String cpf) { // Calcula randomicamente a pontuao do cliente. int pontuacaoCredito = (int)(Math.random() * 600 + 300); return pontuacaoCredito; } protected int getTempoHistoricoCredito(String cpf) { // Calcula randomicamente o tempo de historico. int tempoHistoricoCredito = (int)(Math.random() * 19 + 1); return tempoHistoricoCredito; } /* Usado pela chamada Ejb */ public String getPerfilCredito(String nomeCliente, String cpfCliente) { // Prepara a resposta com o perfil de credito. String msg = MessageFormat.format(MSG, nomeCliente, cpfCliente, getPontuacaoCredito(cpfCliente), getTempoHistoricoCredito(cpfCliente)); return msg; } }

Figura 30 Agencia de Crdito

package spb.credit; import spb.mensagens.PerfilCredito; import spb.mensagens.Cliente; /** * <code>ServicoAgenciaCredito</code> o servico prove o * perfil de credito doo cliente. */ public interface ServicoAgenciaCredito { PerfilCredito getPerfilCredito(Cliente cliente); }

package spb; import import import import import import import import spb.mensagens.RequisicaoServico; spb.mensagens.TipoRequisicao; org.apache.commons.logging.Log; org.apache.commons.logging.LogFactory; spb.credit.ServicoAgenciaCredito; spb.mensagens.PerfilCredito; spb.mensagens.RespostaCliente; spb.mensagens.Cliente;

public class GatewayAgenciaCredito { /** Logger usado por esta classe */ protected final Log logger = LogFactory.getLog(getClass()); // Para acesso ao EJB. Injetado pelo container. private ServicoAgenciaCredito servicoAgenciaCredito; public Object processaRequisicao(RequisicaoServico requisicao) throws AgenciaEmprestimoException, Exception { // Erro se nao foi possivel obter o acesso ao EJB if (null == servicoAgenciaCredito) { logger.info("\n" + MensagemLocal.mensagemDebug( "Nao foi possivel obter a Agencia de Credito.")); } // Invoca o EJB para obter o perfil de credito do cliente. else { PerfilCredito perfil = servicoAgenciaCredito. getPerfilCredito(requisicao.getCliente()); requisicao.setPerfilCredito(perfil); // Log para depuracao. logger.info("\n" + MensagemLocal.mensagemDebug( " Perfil de Credito: [" + perfil.getPontuacaoCredito() + ", " + perfil.getHistoricoCredito() + "]")); }

Figura 31 Gateway para a Agncia de Crdito (continua)

// Se o cliente requisitou seu perfil de credito o servico // termina aqui e a resposta deve ser gerada. if (requisicao.getTipo() == TipoRequisicao.PERFIL) { RespostaCliente resposta = new RespostaCliente(false, null, requisicao.getPerfilCredito()); return resposta; } // Se a requisicao do cliente e de cotacao de emprestimo // a requisicao deve prosseguir, agora contendo o perfil. return requisicao; } public ServicoAgenciaCredito getServicoAgenciaCredito() { return servicoAgenciaCredito; } public void setServicoAgenciaCredito(ServicoAgenciaCredito servicoAgenciaCredito) { this.servicoAgenciaCredito = servicoAgenciaCredito; } }

Figura 31 Gateway para a Agncia de Crdito (continuao).

6.1.4 O Servio de Seleo Bancria


A seleo dos bancos que oferecem emprstimos nas condies requeridas pelo cliente e de acordo com o seu perfil de crdito realizada pelo servio implementado pela classe SeletorBancario, apresentada na figura 32. O seletor utiliza o arquivo XML bancos.xml para obter as configuraes dos bancos. Este arquivo (figura 33) fornece para cada banco as informaes: nome do banco, valores e prazos mnimos e mximos para emprstimo e pontuao e histrico mnimo admitido. O Seletor Bancrio l o arquivo bancos.xml obtendo a configurao dos bancos para, baseado nas configuraes, montar a lista de bancos que podem atender a solicitao do cliente. O mtodo setListaBancaria o ponto de entrada deste servio, que prepara a lista de bancos e a atribui requisio do cliente. Esta lista de bancos na verdade uma lista de inbound endpoints dos bancos selecionados. Um nome de endpoint de banco formado pelo nome do banco mais o sufixo -edp, que o nome que deve aparecer na configurao da aplicao (mule-config.xml). Se a lista no for vazia, ou seja, existe pelo menos um banco que pode atender a solicitao do cliente, ento a lista passa a fazer parte da requisio que ser encaminhada aos bancos. Se nenhum banco foi selecionado ento uma mensagem de erro gerada e encaminhada ao cliente atravs do servio de tratamento de erros.

package spb; import import import import import import import import import import import spb.banco.ConfigBanco; spb.banco.ListaBancosParser; spb.mensagens.PerfilCredito; spb.mensagens.RequisicaoServico; spb.mensagens.StatusRequisicao; spb.MensagemLocal; spb.mensagens.MensagemErro; org.apache.commons.logging.Log; org.apache.commons.logging.LogFactory; java.util.List; java.util.ArrayList;

public class SeletorBancario { /** logger usado por esta classe. */ private static final Log logger = LogFactory.getLog(SeletorBancario.class); /** Configuracoes dos bancos. */ private List<ConfigBanco> confBancos; public SeletorBancario() { try { // Parser para as configuracoes dos bancos. ListaBancosParser handler = new ListaBancosParser("bancos.xml"); // Obtem a configuracao dos bancos a partir // do arquivo bancos.xml. confBancos = handler.getConfigBancos(); // Log para debug. for (ConfigBanco banco: confBancos) { logger.info("\n" + MensagemLocal.mensagemDebug( "Banco: " + banco.getNomeBanco() + " Valor minimo: " + banco.getValorMinimo() + " Valor maximo: " + banco.getValorMaximo() + " Prazo minimo: " + banco.getPrazoMinimo() + " Prazo maximo: " + banco.getPrazoMaximo() + " Pontuacao minima: " + banco.getPontuacaoMinima()+ " Historico minimo: " + banco.getHistoricoMinimo())); } } catch(Exception e) { logger.info("\n" + MensagemLocal.mensagemDebug( "Nao foi possivel obter as configuracoes dos bancos.")); e.printStackTrace(); } }

Figura 32 Seletor Bancrio (continua)

/** * Este metodo e' invocado ao chegar uma requisicao * de cotacao de credito pelo inbound endpoint. */ public Object setListaBancaria(RequisicaoServico requisicao) { // Obtem a lista de inbound endpoints dos bancos // que oferecem emprestimos nas condicoes solicitadas. List<String> endpoints = getEndpoints( requisicao.getPerfilCredito(), requisicao.getValor(), requisicao.getPrazo()); // // // if } // Se nenhum banco aceita fazer emprestimo nas condicoes // requeridas, encaminhe uma mensagem de erro ao cliente. else { MensagemErro msgErro = new MensagemErro( StatusRequisicao.BANCO_NAO_SEL); return msgErro; } } /** * Este metodo usa as configuracoes dos bancos * para determinar quais os bancos fazem emprestimo * nas condicoes solicitadas. Retorna uma lista * com os endpoints dos bancos selecionados. */ private List<String> getEndpoints(PerfilCredito perfilCredito, double valor, int prazo) { List<String> endpoints = new ArrayList<String>(); for (ConfigBanco banco: confBancos) { if ((valor >= banco.getValorMinimo()) && (valor <= banco.getValorMaximo()) && (prazo >= banco.getPrazoMinimo()) && (prazo <= banco.getPrazoMaximo()) && (perfilCredito.getPontuacaoCredito() >= banco.getPontuacaoMinima()) && (perfilCredito.getHistoricoCredito() >= banco.getHistoricoMinimo()) ) { endpoints.add(banco.getNomeBanco() + "-edp"); logger.info("\n" + MensagemLocal.mensagemDebug( "Banco selecionado: " + banco.getNomeBanco())); } } return endpoints; } } Se algum banco aceita fazer emprestimo nas condicoes requeridas, encaminhe a requisicao com os endpoints dos bancos selecionados. (!endpoints.isEmpty()) { requisicao.setEndpointsBancos(endpoints); return requisicao;

Figura 32 Seletor Bancrio (continuao)

<lista-bancos> <banco> <nome-banco>Banco-A</nome-banco> <valor-minimo>10000.00</valor-minimo> <valor-maximo>1000000.00</valor-maximo> <prazo-minimo>6</prazo-minimo> <prazo-maximo>360</prazo-maximo> <pontuacao-minima>400</pontuacao-minima> <historico-minimo>3</historico-minimo> </banco> <banco> <nome-banco>Banco-B</nome-banco> <valor-minimo>2000.00</valor-minimo> <valor-maximo>100000.00</valor-maximo> <prazo-minimo>3</prazo-minimo> <prazo-maximo>144</prazo-maximo> <pontuacao-minima>350</pontuacao-minima> <historico-minimo>1</historico-minimo> </banco> <banco> <nome-banco>Banco-C</nome-banco> <valor-minimo>10000.00</valor-minimo> <valor-maximo>200000.00</valor-maximo> <prazo-minimo>8</prazo-minimo> <prazo-maximo>260</prazo-maximo> <pontuacao-minima>300</pontuacao-minima> <historico-minimo>2</historico-minimo> </banco> </lista-bancos>

Figura 33 Configuraes dos Bancos

6.1.5 Bancos
Nesta fase de nosso estudo de caso os bancos sero representados por servios internos implementados pela classe Banco. Esta classe (figura 34) implementa ServiceAware com o mtodo setService que automaticamente chamado na iniciao do servio pelo Mule (veja [8]). Isso foi feito apenas para obter o nome do banco que est configurado em config-mule.xml, j que temos apenas uma classe genrica para representar os trs bancos. O mtodo getCotacaoEmprestimo invocado ao chegar uma requisio do cliente ao inbound endpoint do banco. Este mtodo gera a resposta a ser enviada ao cliente com a cotao para o emprstimo. A resposta ser encaminhada ao roteador assncrono configurado para a aplicao. A figura 28, que apresenta a composio de nossa aplicao, apresenta outro componente, o Gateway Bancrio. Este componente no tem implementao, ele serve para receber a requisio do cliente e, baseado na lista de bancos produzida pelo Seletor Bancrio, enviar uma cpia da requisio para cada banco que consta da lista. Veremos em detalhes como funciona o Gateway Bancrio quando descrevermos a implementao do fluxo de mensagens mais adiante.

package spb.banco; import org.mule.api.config.ConfigurationException; import org.mule.api.service.Service; import org.mule.api.service.ServiceAware; import import import import spb.MensagemLocal; spb.mensagens.RequisicaoServico; spb.mensagens.Cotacao; spb.mensagens.RespostaCliente;

import java.io.Serializable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * <code>Banco</code> representa uma instituicao bancaria. */ public class Banco implements ServiceAware, Serializable, ServicoBancario { /** logger usado por esta classe. */ protected static final Log logger = LogFactory.getLog(Banco.class); /** Nome do banco */ private String nomeBanco; /* Taxa oferecida pelo banco */ private double taxa; public Banco() { // Calcula a taxa para emprestimo randomicamente. this.taxa = Math.random() * 10; } /** * Este metodo e' invocado automaticamente quando * na iniciacao do servico. Ele usa a configuracao * do servico para obter o nome do banco. */ public void setService(Service servico) throws ConfigurationException { // Obtem o nome do banco da configuracao do servico. this.nomeBanco = servico.getName(); // Log para debug. logger.info("\n" + MensagemLocal.mensagemDebug( "Banco setService: " + nomeBanco)); }

Figura 34 Banco (continua).

/** * Este metodo e' invocado quando uma mensagem * chega ao inbound endpoint do servico. * Constroi a resposta ao cliente contendo a * cotacao do emprestimo. */ public RespostaCliente getCotacaoEmprestimo( RequisicaoServico requisicao) { // O banco cota o emprestimo. Cotacao cotacao = new Cotacao(); cotacao.setNomeBanco(getNomeBanco()); cotacao.setTaxa(taxa); // Log para debug. logger.info(MensagemLocal.taxaRecebida(cotacao)); // Prepara a resposta ao cliente. RespostaCliente resposta = new RespostaCliente(false, null, cotacao); return resposta; } public String getNomeBanco() { return nomeBanco; } public void setNomeBanco(String nomeBanco) { this.nomeBanco = nomeBanco; } public double getTaxa() { return taxa; } public void setTaxa(double taxa) { this.taxa = taxa; } }

Figura 34 Banco (continuao)

6.1.6 Tratamento de Erros


As diversas situaes de erros detectados pela aplicao so tratados por este servio, que implementado pela classe TrataErrosRequisicao (figura 35). Esta classe possui o mtodo trataErrosRequisicao que invocado quando uma mensagem de erro chega ao inbound endpoint deste servio. Este mtodo prepara a resposta a ser enviada ao cliente com a mensagem de erro. Para tratamento de erros podemos utilizar excees, como veremos em outras fases deste tutorial. As respostas geradas por este servio so encaminhadas ao roteador assncrono para serem enviadas ao cliente.

package spb.excecoes; import spb.mensagens.RespostaCliente; import spb.MensagemLocal; import spb.mensagens.MensagemErro; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class TrataErrosRequisicao { /** logger usado por esta classe. */ private static final Log logger = LogFactory.getLog(TrataErrosRequisicao.class); /** * Este metodo e' invocado quando chega uma mensagem de erro * no inbound endpoint deste servico de tratamento de erros. * Ele gera uma resposta ao cliente com a mensagem de erro. */ public RespostaCliente trataErrosRequisicao(MensagemErro erro) { // Obtem a mensagem de erro para a resposta. String mensagem = erro.getMensagem(); // Log para debug. logger.info("\n" + MensagemLocal.mensagemDebug(mensagem)); // Constroi a resposta a ser enviada ao cliente. RespostaCliente resp = new RespostaCliente(true, mensagem, null); return resp; } }

Figura 35 Tratamento de erros.

6.1.7 Transformers para a Agncia de Crdito


O componente GatewayAgenciaCredito utiliza dois transformers para se comunicar com o EJB Agncia de Crdito. O primeiro transformer utilizado para extrair do objeto Cliente os argumentos necessrios para a Agncia de Crdito (nome e CPF do cliente). Este transformer um expressiontransformer definido por Mule. A figura 36 mostra a declarao deste transformer no arquivo de configurao da aplicao mule-config.xml.
<expression-transformer name="ClienteParaArgsAgenciaCredito"> <return-argument evaluator="bean" expression="nome"/> <return-argument evaluator="bean" expression="cpf"/> </expression-transformer>

Figura 36 Transformer de argumentos para a Agncia de Crdito. Um expression-transform utiliza avaliadores (evaluators) para avaliar o payload da mensagem corrente, podendo ser configurado para avaliar uma ou mais expresses. Dependendo da configurao , o payload da mensagem resultante ser um objeto ou um array de objetos. No nosso caso o transformer usa o avaliador bean para construir uma mensagem onde o payload contm duas

strings, o nome e o CPF do cliente. O avaliador bean avalia expresses como objeto.propriedadeA. No transformer que definimos o avaliador bean chama os mtodos getNome() e getCpf() do objeto que o payload da mensagem, no caso o objeto da classe Cliente. Portanto a classe Cliente precisa ter obrigatoriamente os mtodos getNome e getCpf. Atrs da cena, o avaliador bean utiliza o avaliador jpath. Mule oferece um rico framework de avaliao de expresses permitindo a voc incorporar lgica avanada diretamente no arquivo de configurao de uma aplicao Mule, sem a necessidade de escrever cdigo. Consulte [5] e [7] para ter um bom conhecimento a respeito de expression transformers e avaliadores suportados por Mule. O segundo transformer utilizado pelo GatewayAgenciaCredito o que transforma a mensagem contendo o perfil de crdito retornado pelo EJB Agncia de Crdito em um objeto da classe PerfilCredito. Este transformer um custom-transformer, tipo de transformer que j vimos na fase anterior deste tutorial. A figura 37 apresenta a classe PerfilCreditoXmlParaPerfilCredito que implementa este transformer. A Agncia de Crdito retorna uma string XML contendo o perfil de crdito do cliente e este transformer extrai as informaes do XML e constri um objeto PerfilCredito.
package spb.transformers; import org.mule.api.transformer.TransformerException; import org.mule.transformer.AbstractTransformer; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import spb.mensagens.PerfilCredito; import spb.MensagemLocal; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Esta classe transforma a resposta enviada * pela Agencia de Credito em um objeto * da classe PerfilCredito. */ public class PerfilCreditoXmlParaPerfilCredito extends AbstractTransformer { /** Logger usado por esta classe */ private final Log logger = LogFactory.getLog(getClass()); public PerfilCreditoXmlParaPerfilCredito() { // Recebe o perfil de credito como uma String. registerSourceType(String.class); // Retorna o perfil de credito como // um objeto PerfilCredito. setReturnClass(PerfilCredito.class); }

Figura 37 Transformer de retorno da Agncia de Crdito (continua)

/** * Metodo de transformacao. O perfil de credito * enviado pela Agencia de Credito esta' no formato XML: * <perfil-credito> * <nome-cliente> ... </nome-cliente> * <cpf-cliente> ... </cpf-cliente> * <pontuacao-credito> ... </pontuacao-credito> * <historico-cliente> ... </historico-cliente> * </perfil-credito> */ public Object doTransform(Object src, String encoding) throws TransformerException { Document doc = null; // Parsing do perfil de credito recebido. try { doc = DocumentHelper.parseText(src.toString()); } catch (DocumentException e) { throw new TransformerException(this, e); } // Obtem os valores do perfil de credito e // atribui ao objeto PerfilCredito. String historico = doc.valueOf( "/perfil-credito/historico-cliente"); String pontuacao = doc.valueOf( "/perfil-credito/pontuacao-credito"); // Log para debug. logger.info("\n" + MensagemLocal.mensagemDebug( "Historico: " + historico + " Pontuacao: " + pontuacao)); PerfilCredito perfil = new PerfilCredito(); perfil.setHistoricoCredito( Integer.valueOf(historico).intValue()); perfil.setPontuacaoCredito( Integer.valueOf(pontuacao).intValue()); return perfil; } }

Figura 37 Transformer de retorno da Agncia de Crdito (continuao)

6.1.8 Transformer para Seleo Bancria


O servio de Seleo Bancria utiliza um custom-transformer em seu outbound endpoint para adicionar mensagem que contm a requisio do cliente, uma propriedade com a lista dos endpoints dos bancos selecionados. A propriedade utilizada para conter a lista a StaticRecipientList.RECIPIENTS_PROPERTY. A classe StaticRecipientList do Mule usada para despachar um nico evento para mltiplos recipientes sobre o mesmo transporte (veja [8]). No nosso caso, a estamos utilizando para encaminhar a mesma requisio do cliente para vrios bancos. Esta classe possui duas constantes, a RECIPIENTS_PROPERTY, que representa o nome da propriedade (recipients), e a RECIPIENT_DELIMITER, que separa os valores dos recipientes (vrgula). Esta lista esttica de recipientes utilizada em conjunto com o roteador static-recipient-list-router para

encaminhar uma mesma mensagem para os vrios endpoints que compem a lista. Este roteador ser estudado mais adiante, quando apresentarmos a implementao do fluxo de mensagens. A mensagem que sai do Seletor Bancrio passa pelo transformer BancoComoRecipientes (figura 38) antes de ser encaminhada ao GatewayBancrio. O transformer obtm da mensagem a requisio (payload da mensagem), obtm da requisio a lista dos endpoints dos bancos selecionados e monta uma lista de recipientes. A lista produzida ento armazenada na mensagem como valor da propriedade recipients. O Gateway Bancrio utilizar esta lista para encaminhar a requisio para os bancos cujos endpoints esto na lista de recipientes.
package spb.transformers; import org.mule.api.MuleMessage; import org.mule.api.transformer.TransformerException; import org.mule.routing.outbound.StaticRecipientList; import org.mule.transformer.AbstractMessageAwareTransformer; import spb.mensagens.RequisicaoServico; import spb.MensagemLocal; import java.util.List; public class BancosComoRecipientes extends AbstractMessageAwareTransformer { public BancosComoRecipientes() { this.setReturnClass(MuleMessage.class); } public Object transform(MuleMessage message, String outputEncoding) throws TransformerException { // Obtem a requisicao, que e' o payload da mensagem. Object req = message.getPayload(); // Obtem da requisicao a lista dos endpoints // dos bancos selecionados. List<String> endpoints = ((RequisicaoServico) req).getEndpointsBancos(); // Monta uma string com os endpoints // separados por virgulas. String recipientes = null; for (String endpoint: endpoints) { if (null != recipientes) { recipientes += ","; } else { recipientes = ""; } recipientes += endpoint; } // Armazena a lista de endpoints dos bancos selecionados // como valor da propriedade RECIPIENTS_PROPERTY. message.setProperty(StaticRecipientList.RECIPIENTS_PROPERTY, recipientes); return message; } }

Figura 38 Transformer para seleo bancria (continua)

6.2 Implementao do Fluxo de Mensagens


Para estabelecer o fluxo de mensagens da aplicao e interligar seus elementos utilizamos o arquivo de configurao Mule que foi definido na fase I deste estudo de caso. Este arquivo ser bastante alterado nesta fase para interligar os novos elementos da aplicao. As figuras 39, 40, 41, 42, 46, 47, 48 e 49 apresentam a configurao da fase II de nossa aplicao. Cada figura representa uma parte do arquivo, que foi dividido apenas para facilitar a explicao. Este arquivo ainda ser modificado durante o desenvolvimento deste tutorial at chegar a sua verso final.

6.2.1 Declaraes de Namespaces e Esquemas


Neste bloco do arquivo de configurao mule-config.xml adicionamos declaraes correspondentes ao transporte EJB que estamos utilizando para obter servio da Agncia de Crdito, o componente EJB que roda em um servidor de aplicao (JBoss, por exemplo). A figura 39 apresenta as declaraes. xmlns:ejb=http://www.mulesource.org/schema/mule/ejb/2.2 http://www.mulesource.org/schema/mule/ejb/2.2 http://www.mulesource.org/schema/mule/ejb/2.2/mule-ejb.xsd"> Figura 39 Declaraes de namespace e esquema para o transporte EJB.

6.2.2 Configurao dos Transformers


Acrescentamos, modificamos e removemos transformers nesta fase do estudo de caso. A figura 40 apresenta a nova configurao de transformers para esta fase. O transformer RequisicaoRestParaRequisicaoCotacao definido na fase anterior foi renomeado para RequisicaoRestParaRequisicaoServico porque agora ele trata dois tipos de servios, requisio de cotao e requisio de perfil de crdito. A classe que o implementa foi modificada para refletir a sua nova funcionalidade. O transformer CotacaoParaString, que era utilizado para preparar a resposta produzida pelo Gerador de Respostas, foi removido. Sua funcionalidade est sendo implementada pelo Agregador de Respostas associado ao roteador assncrono. Foi acrescentado o transformer ClientParaArgsPerfilCredito, do tipo expresion-transformer, para preparar os argumentos a serem enviados para o EJB Agncia de Crdito. Dois transformers do tipo custom-transformer foram adicionados. O transformer PerfilCreditoXmlParaPerfilCredito transforma a resposta retornada pelo EJB Agncia de Crdi to em um objeto da classe PerfilCredito. O transformer BancosComoRecipientes monta uma lista de endpoints dos bancos aptos a oferecerem o emprstimo ao cliente.

<custom-transformer name="RequisicaoRestParaRequisicaoServico" class="spb.transformers.RequisicaoRestParaRequisicaoServico" /> <jms:object-to-jmsmessage-transformer name="ObjectToJmsMessage" /> <expression-transformer name="ClienteParaArgsAgenciaCredito"> <return-argument evaluator="bean" expression="nome"/> <return-argument evaluator="bean" expression="cpf"/> </expression-transformer> <custom-transformer name="PerfilCreditoXmlParaPerfilCredito" class="spb.transformers.PerfilCreditoXmlParaPerfilCredito" /> <custom-transformer name="BancosComoRecipientes" class="spb.transformers.BancosComoRecipientes" /> Figura 40 Configurao dos transformers.

6.2.3 Configurao dos Endpoints


A configurao de endpoints envolve a configurao de conectores e transportes a serem usados nos endpoints. Nesta fase declaramos um novo conector utilizado para comunicao com a Agncia de Crdito (EJB externo): <ejb:connector name="ejbConnector" securityPolicy="security.policy" jndiInitialFactory="org.jnp.interfaces.NamingContextFactory" jndiProviderUrl="localhost"> </ejb:connector> O transporte EJB permite que um EJB session bean seja invocado como parte de um fluxo de eventos. Componentes podem possuir um outbound endpoint para invocar objetos remotos e opcionalmente retornar um resultado. O conector EJB prov conectividade para beans EJB. Note que somente outbound endpoints podem usar o transporte EJB. Mule define uma classe EJBConnector, que estende a classe RMIConnector e prov configurao de conexo para endpoints EJB. A hierarquia completa desta classe : java.lang.Object |_ org.mule.transport.AbstractConnector |_ org.mule.transport.AbstractJndiConnector |_ org.mule.transport.rmi.RmiConnector |_ org.mule.transport.ejb.EjbConnector As configuraes para um endpoint EJB so as mesmas do endpoint RMI. Vrias propriedades podem ser configuradas no connector, para maiores detalhes veja [7] e [8]. Para nosso estudo de caso configuramos as seguintes propriedades: securityPolice (herdada de RmiConnector) o nome de um arquivo que determina a poltica de segurana a ser usada para habilitar conexes. Usamos o arquivo security.policy que se encontra na pasta src\main\java\resources. jndiInitialFactory (herdada de AbstractJndiConnector) que determina a interface para criao do contexto inicial. O contexto inicial implementa a interface Context e prov o ponto inicial para a resoluo de nomes.

jndiProviderUrl (herdada de AbstractJndiConnector) determina o provedor JNDI, no nosso caso localhost. Estamos rodando JBoss e Mule na mesma mquina. A configurao do endpoint que usa o transporte EJB no nosso estudo de caso : <ejb:endpoint name="AgenciaCreditoEdp" host="localhost" port="1099" object="/AgenciaCredito" method="getPerfilCredito" methodArgumentTypes="java.lang.String,java.lang.String" connector-ref="ejbConnector"/> Definimos neste endpoint o host, a porta, o objeto, o mtodo a ser invocado e o conector para o transporte. Um mtodo pode receber um ou mais argumentos. Definimos os tipos dos argumentos atravs da propriedade methodArgumentTypes como uma lista separada por vrgulas. No nosso caso a declarao dos tipos dos argumentos no seria necessria, j que temos apenas um mtodo, o getPerfilCredito. Os outros endpoints utilizados no apresentam novidades para ns, so endpoints para os transportes jetty, vm e jms. O endpoint que utiliza o transporte jetty o mesmo da fase anterior, mas mudamos seu nome de RequisicaoClienteREST para RequisicaoServicoREST, um nome mais adequado. A tabela a seguir apresenta os endpoints utilizados nesta fase com os respectivos transportes e utilizao. A figura 41 apresenta a configurao dos conectores e endpoints. Nome RequisicaoServicoREST GWAgenciaCredito AgenciaCreditoEdp SeletorBancarioEdp GWBancario RespostasServicos Transporte Jetty Jms Ejb Vm Jms Jms Utilizao Recebe requisies do cliente Comunicao entre ServicosAgencia e GatewayAgenciaCredito Comunicao entre GatewayAgenciaCredito e AgenciaCredito Comunicao entre GatewayAgenciaCredito e SeletorBancario Comunicao entre SeletorBancario e GatewayBancario Comunicao entre Bancos (A, B e C) e roteador assncrono de respostas ao cliente. Comunicao entre TrataErrosRequisicao e roteador assncrono de respostas ao cliente. Comunicao entre GatewayBancario e Banco-A Comunicao entre GatewayBancario e Banco-B Comunicao entre GatewayBancario e Banco-C Comunicao entre ServicosAgencia e TrataErrosRequisicao. Comunicao entre SeletorBancario e TrataErrosRequisicao.

Banco-A-edp Banco-B-edp Banco-C-edp TrataErrosRequisicaoEdp

Jms Jms Jms Jms

Tabela 1 Relao de endpoints

<jetty:connector name="httpConnector" useContinuations="false" /> <vm:connector name="vmConnector" queueEvents="true"/> <jms:activemq-connector name="jmsConnector" /> <ejb:connector name="ejbConnector" securityPolicy="security.policy" jndiInitialFactory="org.jnp.interfaces.NamingContextFactory" jndiProviderUrl="localhost"> </ejb:connector> <endpoint name="RequisicaoServicoREST" connector-ref="httpConnector" address="jetty:rest://localhost:8888/AgenciaEmprestimo" /> <endpoint name="GWAgenciaCredito" connector-ref="jmsConnector" address="jms://spb.gw.agenciacredito" /> <ejb:endpoint name="AgenciaCreditoEdp" host="localhost" port="1099" object="/AgenciaCredito" method="getPerfilCredito" methodArgumentTypes="java.lang.String,java.lang.String" connector-ref="ejbConnector"/> <endpoint name="SeletorBancarioEdp" connector-ref="vmConnector" address="vm://spb.seletorbancario.bancos" /> <endpoint name="GWBancario" connector-ref="jmsConnector" address="jms://spb.gw.bancario" /> <endpoint name="RespostasServicos" connector-ref="jmsConnector" address="jms://spb.emprestimo.respostas" /> <endpoint name="Banco-A-edp" connector-ref="jmsConnector" address="jms://spb.banco.banco-a" /> <endpoint name="Banco-B-edp" connector-ref="jmsConnector" address="jms://spb.banco.banco-b" /> <endpoint name="Banco-C-edp" connector-ref="jmsConnector" address="jms://spb.banco.banco-c" /> <endpoint name="TrataErrosRequisicaoEdp" connector-ref="jmsConnector" address="jms://spb.erro.requisicao" />

Figura 41 Configurao de conectores e endpoints.

6.2.4 Configurao dos Servios


Agora vamos configurar a nossa aplicao definindo os servios com seus endpoints, componentes, transformers e conexes entre componentes para esta fase do estudo de caso. Aqui definimos o fluxo de mensagens entre os componentes. Na fase anterior definimos apenas dois servios, CotacaoEmprestimo e GeradorRespostas. O primeiro servio foi redefinido para ServicosAgencia, implementando os dois servios oferecidos pela agncia. O servio GeradorRespostas era temporrio e foi removido.

6.2.4.1 Configurao do Servio ServicosAgencia


O primeiro servio a configurar o ServicosAgencia, que substitui o servio CotacaoEmprestimo da fase I. Este servio possui dois endpoints, (um inbound e um outbound), um componente (classe spb.ServicosAgencia) e um roteador assncrono. O inbound endpoint tem a seguinte configurao: <inbound> <inbound-endpoint ref="RequisicaoServicoREST" transformer-refs="RequisicaoRestParaRequisicaoServico" /> </inbound> Este endpoint o responsvel por receber requisies REST do cliente e est associado ao transformer RequisicaoRestParaRequisicaoServico, que transforma a mensagem recebida do cliente em um

objeto da classe RequisicaoServico. O objeto resultante desta transformao encaminhado ao componente implementado pela classe ServicosAgencia. Aps o processamento implementado pelo componente, o fluxo continua pelo outbound endpoint que possui dois roteadores com filtros (filtering-router) para definir o destino da mensagem: <outbound> <filtering-router> <outbound-endpoint ref="GWAgenciaCredito" /> <payload-type-filter expectedType="spb.mensagens.RequisicaoServico"/> </filtering-router> <filtering-router> <outbound-endpoint ref="TrataErrosRequisicaoEdp" /> <payload-type-filter expectedType="spb.mensagens.MensagemErro"/> </filtering-router> </outbound> O primeiro roteador encaminha para o endpoint GWAgenciaCredito mensagens cujo payload contm um objeto da classe RequisicaoServico e o segundo encaminha para o endpoint TrataErrosRequisicaoEdp mensagens cujo payload contm um objeto da classe MensagemErro. Com estes filtros podemos separar o fluxo de sada deste servio em um fluxo de mensagens vlidas e um fluxo de mensagens que reportam erros encontrados nas requisies de servios. Os filtros so muito utilizados como elementos de uma aplicao Mule. Filtragem a habilidade de escolher quais mensagens encaminhar ou aceitar e pode ser aplicada tanto em inbound quanto em outbound endpoints. Um filtro deve retornar um valor booleano, que indica se a mensagem deve ser aceita ou no. O roteador no precisa saber de detalhes especficos do filtro, ele opera de acordo com o valor booleano que o filtro retorna. O filtro precisa verificar uma expresso especfica contra a mensagem corrente. Esta expresso pode operar sobre uma mensagem Mule, isto , ela pode olhar para qualquer valor no payload ou propriedades de uma mensagem Mule. Existem vrios filtros padronizados em Mule, mas voc pode construir um filtro que seja adequado sua aplicao. Correntemente Mule possui os seguintes filtros padronizados (consulte [7] para detalhes): Payload Type Filter. Verifica a classe do objeto contido no payload da mensagem. Este o filtro que estamos utilizando no outbound endpoint de ServicosAgencia. Expression Filter. Utiliza avaliadores para avaliar expresses sobre o payload da mensagem. Vrios avaliadores podem ser utilizados, como, por exemplo, xpath, jxpath e bean. Para este filtro definimos o avaliador e a expresso. RegEx Filter. Aplica uma expresso regular sobre o payload da mensagem. O filtro aplica toString() ao payload para aplicar a expresso regular. Wildcard Filter. Aplica um padro Wildcard ao payload da mensagem. Este filtro tambm aplica toString() ao payload. Exception Type Filter. Um filtro que verifica se o payload um tipo de exceo esperada. Message Property Filter. Este filtro permite adicionar lgica ao roteador com base em uma ou mais propriedades da mensagem. Logic Filters. Existem 3 Logic Filters que podem ser utilizados com outros filtros: AND, OR e NOT. O ltimo elemento deste servio um roteador assncrono de respostas configurado da seguinte forma: <async-reply timeout="10000"> <inbound-endpoint ref="RespostasServicos" /> <custom-async-reply-router class="spb.routers.AgregadorRespostas" />

</async-reply> Na fase I utilizamos um roteador assncrono to tipo single-async-reply-router, nesta fase ns mudamos o tipo para custom- async-reply-router e adotamos um timeout para o recebimento das mensagens com respostas a serem enviadas ao cliente. Neste tipo de roteador assncrono as mensagens so encaminhadas a uma classe que implementa a seleo/agregao das respostas para enviar apenas uma resposta ao cliente. Neste caso especfico, a classe implementa a seleo da melhor cotao oferecida pelos bancos, no caso do servio de cotao de emprstimo. Para o servio de perfil de crdito s temos uma resposta, dado que s temos uma agncia de crdito. As figuras de 42 e 43 apresentam a implementao da seleo de respostas. Uma classe que implementa um agregador de respostas deve estender uma das duas classes Mule (veja a referncia [8]): org.mule.routing.response.AbstractResponseRouter ou org.mule.routing.response.AbstractResponseAggregator. A classe AgregadorRespostas (figura 42) estende a classe Mule ResponseCorrelationAgregator (que estende AbstractResponseRouter) e usa a classe LogicaAgregacaoRespostas para realizar a seleo da melhor resposta a ser enviada ao cliente. As mensagens que chegam ao inbound endpoint RespostasServicos so encaminhadas para o AgregadorRespostas. Quando mensagens transitam em Mule, de fato o que circula so eventos. Um evento carrega no somente o contedo de uma mensagem, mas tambm o contexto no qual a mensagem processada. No nosso caso, a classe AgregadorRespostas implementa o mtodo getCorrelatorCallback, que, quando invocado por Mule retorna uma classe para tratamento dos eventos (mensagens) que chegam ao roteador assncrono. Esta classe possui o mtodo aggregateEvents que Mule invoca para processar as respostas. Este mtodo usa a classe LogicaAgregacaoRespostas para processar os eventos (mensagens).
package spb.routers; import import import import import import org.mule.api.MuleMessage; org.mule.routing.AggregationException; org.mule.routing.CollectionCorrelatorCallback; org.mule.routing.EventCorrelatorCallback; org.mule.routing.inbound.EventGroup; org.mule.routing.response.ResponseCorrelationAggregator;

public class AgregadorRespostas extends ResponseCorrelationAggregator { @Override protected EventCorrelatorCallback getCorrelatorCallback() { return new CollectionCorrelatorCallback() { public MuleMessage aggregateEvents(EventGroup events) throws AggregationException { try { return LogicaAgregacaoRespostas.aggregateEvents(events); } catch (Exception e) { throw new AggregationException(events, null, e); } } }; } }

Figura 42 Classe AgregadorRespostas.

A classe LogicaAgregacaoRespostas (figura 43) recebe os eventos (mensagens) atravs do mtodo aggregateEvents e prepara a resposta a ser enviada ao cliente. Se as mensagens correspondem a respostas de cotao enviadas pelos bancos, a resposta contendo a menor taxa selecionada para ser enviada ao cliente. Se for uma resposta a um pedido de perfil de crdito, s existe uma resposta, no h seleo a ser feita, apenas preparar a resposta a ser enviada ao cliente. Se algum erro foi detectado durante o processamento do servio, ento uma resposta contendo uma mensagem de erro preparada.
package spb.routers; import import import import import import import import import org.mule.DefaultMuleMessage; org.mule.api.MuleEvent; org.mule.api.MuleMessage; spb.MensagemLocal; spb.mensagens.Cotacao; spb.mensagens.RespostaCliente; spb.mensagens.TipoRequisicao; spb.mensagens.PerfilCredito; org.mule.routing.inbound.EventGroup;

import java.util.Iterator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Esta classe implementa a logica de selecao de resposta * a ser enviada ao cliente, no caso de respostas do * servico de cotacao de emprestimo. A resposta enviada ao * cliente e' a que contem a menor taxa de emprestimo. */ public class LogicaAgregacaoRespostas { protected static final Log logger = LogFactory.getLog(LogicaAgregacaoRespostas.class); public static MuleMessage aggregateEvents(EventGroup events) throws Exception { RespostaCliente resposta; Cotacao menorTaxa = null; Cotacao cotacao = null; MuleEvent event = null; String strCot = "<ul>"; int pontuacao = -1; int historico = -1;

Figura 43 Classe LogicaAgregacaoRespostas (continua)

// Processa os eventos (mensagens). for (Iterator iterator = events.iterator(); iterator.hasNext();) { event = (MuleEvent)iterator.next(); Object o = event.transformMessage(); if(o instanceof RespostaCliente) { resposta = (RespostaCliente)o; } else { throw new IllegalArgumentException("O objeto recebido " + "nao e do tipo esperado. Esperado: " + Cotacao.class.getName() + " Recebido: " + o); } // Se for uma mensagem de erro, prepara a mensagem ao // cliente if (resposta.isErro()) { strCot += "<li>" + resposta.getMensagemErro() + "</li>"; } // Se for uma cotacao, estabeleca a menor taxa. else if (resposta.getObjResposta() instanceof Cotacao) { cotacao = (Cotacao)resposta.getObjResposta(); logger.info(MensagemLocal.processandoCotacao(cotacao)); if (menorTaxa == null) { menorTaxa = cotacao; } else { if (cotacao.getTaxa() < menorTaxa.getTaxa()) { menorTaxa = cotacao; } } } // Se for resposta do servico Perfil de Credito, prepare // a resposta ao cliente. else if (resposta.getObjResposta() instanceof PerfilCredito){ PerfilCredito perfil = (PerfilCredito)resposta.getObjResposta(); pontuacao = perfil.getPontuacaoCredito(); historico = perfil.getHistoricoCredito(); } } // Prepare a resposta com a menor taxa, se for o caso. if (null != menorTaxa) { logger.info(MensagemLocal.menorCotacao(menorTaxa)); strCot += "A melhor cotacao recebida: <br/><li>" + "Instituicao financeira: " + menorTaxa.getNomeBanco() + "</li><li>Taxa: " + menorTaxa.getTaxa() + "</li></lu>"; } // Prepare a resposta com o perfil de credito, se for o caso. else if (-1 != pontuacao) { strCot += "Perfil do Cliente: <br/><li>Historico: " + historico + "</li><li>Pontuacao: " + pontuacao + "</li></lu>"; }

Figura 43 Classe LogicaAgregacaoResposta (continua)

// Prepare a resposta com a mensagem de erro, se for o caso. else { strCot += "</lu>"; } // Construa uma mensagem Mule e retorna. return new DefaultMuleMessage(strCot, event.getMessage()); } }

Figura 43 Classe LogicaAgregacaoResposta (continuao) A figura 44 a seguir apresenta a configurao completa do servio ServicosAgencia. <service name="ServicosAgencia"> <inbound> <inbound-endpoint ref="RequisicaoServicoREST" transformer-refs="RequisicaoRestParaRequisicaoServico" /> </inbound> <component class="spb.ServicosAgencia" /> <outbound> <filtering-router> <outbound-endpoint ref="GWAgenciaCredito" /> <payload-type-filter expectedType="spb.mensagens.RequisicaoServico"/> </filtering-router> <filtering-router> <outbound-endpoint ref="TrataErrosRequisicaoEdp" /> <payload-type-filter expectedType="spb.mensagens.MensagemErro"/> </filtering-router> </outbound> <async-reply timeout="10000"> <inbound-endpoint ref="RespostasServicos" /> <custom-async-reply-router class="spb.routers.AgregadorRespostas" /> </async-reply> </service> Figura 44 Configurao do servio ServicosAgencia.

6.2.4.2 Configurao do Servio GatewayAgenciaCredito


O Servio GatewayAgenciaCredito faz a comunicao com o EJB Agncia de Crdito. Ele possui um inbound endpoint, um componente, representado pela classe GatewayAgenciaCrdito e um outbound endpoint com dois roteadores com filtro. A configurao deste servio apresentada na figura 45. O inbound endpoint recebe mensagens do servio ServicosAgencia e as repassa ao componente GatewayAgenciaCredito. <inbound> <inbound-endpoint ref="GWAgenciaCredito" /> </inbound>

O componente implementado pela classe GatewayAgenciaCrdito configurado com uma interface para comunicao com a Agncia de Crdito, que um EJB externo. Esta interface declarada com o elemento binding. <component class="spb.GatewayAgenciaCredito"> <binding interface="spb.credit.ServicoAgenciaCredito" method="getPerfilCredito"> <outbound-endpoint synchronous="true" transformer-refs="ClienteParaArgsAgenciaCredito" responseTransformer-refs="PerfilCreditoXmlParaPerfilCredito" ref="AgenciaCreditoEdp" /> </binding> </component> O elemento binding define a classe Java que representa a interface para acesso ao EJB (ServicoAgenciaCredito), o mtodo a ser invocado (getPerfilCredito) e um outbound endpoint sncrono (AgenciaCreditoEdp), para onde a mensagem ser enviada para chegar ao EJB. No outbound endpoint foram utilizados dois transformers, um para transformar os argumentos a serem passados ao mtodo do EJB (ClienteParaArgsAgenciaCredito) e outro para converter a resposta recebida do EJB (PerfilCreditoXmlParaPerfilCredito). Aps o processamento implementado pelo componente, o fluxo continua pelo outbound endpoint que possui dois roteadores com filtros (filtering-router) para definir o destino da mensagem: <outbound> <filtering-router> <outbound-endpoint ref="SeletorBancarioEdp" /> <payload-type-filter expectedType="spb.mensagens.RequisicaoServico"/> </filtering-router> <filtering-router> <outbound-endpoint ref="RespostasServicos" /> <payload-type-filter expectedType="spb.mensagens.RespostaCliente"/> </filtering-router> </outbound> O primeiro roteador encaminha para o endpoint SeletorBancarioEdp mensagens cujo payload contm um objeto da classe RequisicaoServico e o segundo encaminha para o endpoint RespostasServicos mensagens cujo payload contm um objeto da classe RespostaCliente. Com estes filtros podemos separar o fluxo de sada deste servio em um fluxo de mensagens com requisies de cotaes de emprstimos, a serem encaminhadas ao Seletor Bancrio, e um fluxo de mensagens que so respostas a pedidos de perfil de crdito do cliente, cujo processamento termina neste ponto.

<service name="GatewayAgenciaCredito"> <inbound> <inbound-endpoint ref="GWAgenciaCredito" /> </inbound> <component class="spb.GatewayAgenciaCredito"> <binding interface="spb.credit.ServicoAgenciaCredito" method="getPerfilCredito"> <outbound-endpoint synchronous="true" transformer-refs="ClienteParaArgsAgenciaCredito" responseTransformer-refs="PerfilCreditoXmlParaPerfilCredito" ref="AgenciaCreditoEdp" /> </binding> </component> <outbound> <filtering-router> <outbound-endpoint ref="SeletorBancarioEdp" /> <payload-type-filter expectedType="spb.mensagens.RequisicaoServico"/> </filtering-router> <filtering-router> <outbound-endpoint ref="RespostasServicos" /> <payload-type-filter expectedType="spb.mensagens.RespostaCliente"/> </filtering-router> </outbound> </service> Figura 45 Configurao do servio GatewayAgenciaCredito

6.2.4.3 Configurao do Servio SeletorBancario


O servio SeletorBancario responsvel por fazer a seleo dos bancos que oferecem emprstimos nas condies apresentadas pelo cliente e seu perfil. Este servio contm um inbound endpoint, um componente e um outbound endpoint com dois roteadores com filtro. A figura 46 apresenta a configurao deste servio. O inbound utiliza o endpoint SeletorBancarioEdp, que recebe mensagens oriundas do servio GatewayAgenciaCredito. <inbound> <inbound-endpoint ref="SeletorBancarioEdp" /> </inbound> O componente implementado pela classe SeletorBancario. Este componente pode gerar dois tipos de respostas, uma lista de bancos selecionados, embutida na requisio de servio, ou uma mensagem de erro, quando nenhum banco foi selecionado. O outbound utiliza dois roteadores com filtro. O primeiro encaminha ao endpoint GWBancario mensagens cujo payload contm um objeto da classe RequisicaoServico. Esta a situao onde uma lista de bancos foi montada com sucesso. Este roteador utiliza tambm dois transformers, j explicados anteriormente, que so aplicados sobre a mensagem antes dela prosseguir pelo endpoint de sada. So os transformers BancosComoRecipientes e ObjectToJmsMessage. O segundo roteador encaminha ao endpoint TrataErrosRequisicaoEdp mensagens cujo payload contm um objeto da classe MensagemErro. Esta a situao de erro onde nenhum banco foi selecionado.

<outbound> <filtering-router> <outbound-endpoint ref="GWBancario" transformer-refs="BancosComoRecipientes ObjectToJmsMessage" /> <payload-type-filter expectedType="spb.mensagens.RequisicaoServico"/> </filtering-router> <filtering-router> <outbound-endpoint ref="TrataErrosRequisicaoEdp" /> <payload-type-filter expectedType="spb.mensagens.MensagemErro"/> </filtering-router> </outbound>

<service name="SeletorBancario"> <inbound> <inbound-endpoint ref="SeletorBancarioEdp" /> </inbound> <component class="spb.SeletorBancario" /> <outbound> <filtering-router> <outbound-endpoint ref="GWBancario" transformer-refs="BancosComoRecipientes ObjectToJmsMessage" /> <payload-type-filter expectedType="spb.mensagens.RequisicaoServico"/> </filtering-router> <filtering-router> <outbound-endpoint ref="TrataErrosRequisicaoEdp" /> <payload-type-filter expectedType="spb.mensagens.MensagemErro"/> </filtering-router> </outbound> </service> Figura 46 Configurao do servio SeletorBancario

6.2.4.4 Configurao do Servio GatewayBancario


O servio GatewayBancario possui um inbound endpoint e um outbound endpoint, mas no possui um componente como os outros servios. Isso significa que as mensagens passam do inbound para o outbound endpoint sem processamento. Este servio serve para enviar a requisio de cotao de emprstimo para todos os bancos que compem a lista de bancos selecionados gerada pelo servio SeletorBancario. A figura 47 apresenta a configurao deste servio. O outbound define um roteador baseado em uma lista de recipientes esttica. Isso significa que o roteador enviar uma cpia da mensagem corrente para cada um dos recipientes (inbound endpoints) que fazem parte da lista. A lista dos recipientes faz parte da mensagem e est associada propriedade StaticRecipientList.RECIPIENTS_PROPERTY definida por Mule (veja [8]). Esta propriedade foi injetada na mensagem pelo transformer BancosComoRecipientes. Outro elemento do roteador o reply-to-address. Este elemento define que as respostas enviadas pelos destinatrios das mensagens que o roteador encaminha (os bancos, no caso) devem ser enviadas para o endpoint definido por esse elemento (no caso o endpoint RespostasServicos). Isso significa que os bancos no devem declarar

outbound endpoint, a resposta gerada pelos bancos sero encaminhadas diretamente para o endpoint RespostasServicos. <service name="GatewayBancario"> <inbound> <inbound-endpoint ref="GWBancario" /> </inbound> <outbound> <static-recipient-list-router> <reply-to address="RespostasServicos" /> </static-recipient-list-router> </outbound> </service> Figura 47 Configurao do servio GatewayBancario

6.2.4.5 Configuraes dos Servios Banco-A, Banco-B e Banco-C


Nesta fase do estudo de caso todos os bancos so iguais e tm a mesma configurao. Os servios possuem um inbound endpoint e um componente implementado pela classe Banco em todos os trs servios. Eles no possuem outbound porque o servio que encaminha as mensagens para os bancos (GatewayBancario) j especificou, atravs do elemento reply-to-address, para onde deveriam ser encaminhadas as respostas. A figura 48 apresenta a configurao os trs servios, Banco-A, Banco-B e Banco-C. <service name="Banco-A"> <inbound> <inbound-endpoint ref="Banco-A-edp" /> </inbound> <component class="spb.banco.Banco" /> </service> <service name="Banco-B"> <inbound> <inbound-endpoint ref="Banco-B-edp" /> </inbound> <component class="spb.banco.Banco" /> </service> <service name="Banco-C"> <inbound> <inbound-endpoint ref="Banco-C-edp" /> </inbound> <component class="spb.banco.Banco" /> </service> Figura 48 Configuraes dos servios Banco-A, Banco-B e Banco-C

6.2.4.6 Configurao do Servio TrataErrosRequisicao


Este servio centraliza a gerao de respostas com mensagens de erros encontrados durante o processamento das requisies de servios. Ele possui um inbound endpoint, que recebe as mensagens de erros, um componente, representado pela classe TrataErrosRequisicao, e um outbound endpoint com um roteador do tipo pass-through-router para encaminhar as respostas ao roteador assncrono. A figura 49 apresenta a configurao deste servio. <service name="TrataErrosRequisicao"> <inbound> <inbound-endpoint ref="TrataErrosRequisicaoEdp" /> </inbound> <component class="spb.excecoes.TrataErrosRequisicao" /> <outbound> <pass-through-router> <outbound-endpoint ref="RespostasServicos" /> </pass-through-router> </outbound> </service> Figura 49 Configurao do servio TrataErrosRequisicao

6.3 Organizao da Aplicao


Algumas alteraes na estrutura de diretrio do estudo de caso foram realizadas nesta fase. Uma nova pasta foi adicionada para acomodar o EJB Agncia de Crdito e novas pastas foram adicionadas estrutura da Agncia de Emprstimo. A figura 50 apresenta a nova estrutura. A pasta AgenciaCredito mantm a estrutura da aplicao Agncia de Crdito, um EJB externo ao Mule que roda em um container separado. No caso estamos utilizando o JBoss. Na estrutura da Agncia de Emprstimo foram acrescentadas as seguintes pastas para acomodar os novos servios: banco mantm o componente Banco e outras classes utilitrias. credit mantm a interface para acesso ao EJB Agncia de Crdito. excecoes mantm a classe que implementa o servio de tratamento de erros. routers mantm o agregador de respostas para o roteador assncrono de respostas.

Figura 50 Estrutura de diretrios da aplicao.

6.4 Executando a Aplicao


No houve alterao na gerao e execuo da aplicao Agncia de Emprstimo. Agora temos que gerar o EJB que representa a Agncia de Crdito, o que feito executando ant a partir da pasta AgenciaCredito. O arquivo agencia-credito.jar gerado deve ser colocado no diretrio server\default\deploy do JBoss. Para que a aplicao Agncia de Emprstimo possa chamar o EJB em execuo no JBoss precisamos acrescentar as seguintes bibliotecas JBoss ao diretrio lib\user do Mule:

Para invocar os servios oferecidos pela Agncia de Emprstimo continuamos utilizando a aplicao Web. Para colocar esta aplicao no ar basta copiar o diretrio AgenciaEmprestimo.war para o diretrio Server\default\deploy do JBoss. Com o JBoss no ar usamos um browser para ter acesso ao servio atravs da URL http://localhost:8080/AgenciaEmprestimo. A mesma pgina web inicial da fase I ser apresentada. Ao selecionarmos Agencia de Emprestimo obteremos agora uma pgina diferente da apresentada na fase I, j que agora temos dois servios

oferecidos pela agncia, cotao de emprstimo e avaliao de perfil de crdito. A seguinte pgina ser apresentada:

O servio de cotao de emprstimo funciona da mesma forma que funcionava na fase I. O servio de avaliao apresentar como resultado um histrico e uma pontuao, como apresentado na figura seguinte.

Na prxima etapa deste tutorial apresentaremos novos elementos e transportes suportados por Mule.

7 Estudo de Caso Fase III


Nesta fase adicionaremos novos transportes nossa aplicao e tambm uma nova funcionalidade de gerao e emisso de relatrios de solicitaes de cotao de emprstimo. Teremos tambm a oportunidade de experimentar novos roteadores. Com o objetivo de experimentar novos protocolos vamos transformar dois, dos trs bancos implementados internamente na fase anterior, em implementaes externas. O Banco-A passar a ser uma aplicao que aceita requisies via socket, o que nos possibilita experimentar o transporte TCP. O Banco-C ser implementado como um Web Service executando no JBoss. A funcionalidade de gerao de relatrio de requisies ser implementado em dois servios distintos, um que prepara o relatrio armazenando as requisies em um banco de dados e outro que faz emisses automticas do relatrio armazenado no banco. Com estes servios experimentaremos os transportes JDBC, FILE e SMTP. A arquitetura da soluo apresentada na figura 17 sofrer uma pequena alterao com a adio do banco de dados para suportar a funcionalidade de gerao de relatrio. A figura 51 apresenta a nova arquitetura.

Cliente (browser) Banco-A

Agncia de Emprstimo Web site

Mdulo de Servio

Banco-B

Base Dados Relatrio

Agncia de Crdito

Banco-C

Figura 51 Agncia de emprstimo e seu ambiente. A figura 52 apresenta o fluxo de mensagens da aplicao. Com a adio dos novos servios o fluxo de mensagens sofreu pequenas modificaes. Foram includos no fluxo dois novos componentes, o gerador de relatrio e o emissor automtico de relatrios. Mensagens de requisio de cotao de emprstimo que saem da agncia de crdito fluem tanto para o Seletor Bancrio quanto para o Gerador de Relatrio. Um fluxo paralelo estabelecido por eventos disparados por um timer para acionar a emisso automtica de relatrios. O resto do fluxo de mensagens permanece inalterado. A figura 53 mostra o projeto para essa fase do estudo de caso, apresentando os componentes e seus endpoints. Temos dois novos componentes externos, Banco A TCP e Banco B WS. Os componentes internos Banco A e Banco B definidos na fase anterior passam a funcionar como proxy para os correspondentes componentes externos. Roteadores do tipo chaining-router foram adicionados aos bancos A e B, como veremos no item de configurao dos servios. Dois novos componentes foram adicionados aplicao para implementar a funcionalidade de gerao e emisso de relatrios. O Gerador de Relatrio armazena cada requisio de cotao de emprstimo em um banco de dados e o Emissor Automtico de Relatrios acessa o banco para emitir o relatrio. A emisso do relatrio consiste em gravar o relatrio em arquivo e envi-lo por email. O emissor automtico temporizado para emitir relatrios em intervalos regulares de tempo.

Cliente Timer Requisio de servio

Servios da Agncia sim erro no Agncia de Crdito

Emissor automtico de relatrios

Perfil de crdito servio Cotao de emprstimo Gerador de Relatrio sim erro no Tratamento de Erros Gateway Bancrio Seletor Bancrio

Banco A

Banco B

Banco C

Roteador de Respostas

Cliente Figura 52 Fluxo de mensagens.

Web site (aplicao Web) HTTP/REST

Cliente (browser) ejb Binding

Agncia de Crdito (EJB)

R e n d p r o u t vm

e n d p

t r a n

Servios da Agncia

e n d p

r o u t

jms

e n d p

Gateway Agncia de Crdito

r. assncrono R jms R R r o u t tcp R r o u t cfx R e n d p Banco C e n d p ep Banco B ep e n d p r o u t jms e n d p Gateway Bancrio e n d p ep Banco A ep e n d p Tratamento de Erros e n d p e n d p jms r o u t e n d p Seletor Bancrio

r o u t

e n d p

Banco A TCP

jms

Banco B WS

Base de dados Arquivo relatrio r o u t ep ep Emissor automtico de relatrios e n d p

e n d p

Gerador de Relatrio

e n d p

Email relatrio

Figura 53 Elementos da fase III do estudo de caso.

7.1 Implementao da Aplicao


Vamos apresentara agora os novos componentes implementados nesta fase. Apresentaremos as principais classes para o entendimento da soluo, mas o cdigo produzido nesta fase est disponvel em um pacote zip, contendo a aplicao web, o EJB (Agncia de Crdito), o Banco -A-TCP, o Banco-B-WS e a aplicao integrada. Nesta fase acrescentamos componentes novos nossa aplicao Mule para implementar a gerao e emisso de relatrios. Externamente acrescentamos duas novas aplicaes que representam os bancos A e B, so elas: Banco-A-TCP e Banco-B-WS.

7.1.1 Bancos
Duas novas aplicaes foram desenvolvidas para substituir os bancos A e B que na fase anterior eram implementados como componentes internos aplicao Mule. Estas novas aplicaes so integradas aplicao Mule atravs dos transportes TCP e Web Service. Uma das aplicaes o Banco_A_TCP, integrada via transporte TCP. Esta aplicao composta por duas classes Java: BancoServer e Banco. O BancoServer abre um socket para ouvir requisies enviadas pela aplicao Mule. Ao receber uma requisio o BancoServer a repassa ao Banco, atravs do mtodo getCotacaoEmprestimo, que calcula a taxa de emprstimo. O BancoServer ento envia a resposta aplicao Mule via socket. Os cdigos relativos s duas classes so apresentados nas figuras 54 e 55. O cdigo do banco muito parecido com o cdigo da classe Banco utilizada na fase anterior e o cdigo do BancoServer um cdigo simples de um servidor socket que abre uma janela onde as requisies recebidas so apresentadas. A outra aplicao o Banco_B_WS, integrada com a aplicao Mule via transporte CXF. Esta aplicao possui apenas duas classes, Banco (interface) e BancoImpl (implementao). Novamente, a implementao do banco similar apresentada na fase anterior. A figura 56 apresenta estas classes. Este banco, implementado como Web Service, executado no JBoss. O componente Banco-C no foi modificado nesta verso do estudo de caso e continua sendo um componente interno da aplicao Mule.

import java.text.MessageFormat; /** * <code>Banco_A_TCP</code> representa uma instituicao bancaria. */ public class Banco_A_TCP { /** Nome do banco */ private static final String nomeBanco = "Banco-A"; /* Taxa oferecida pelo banco */ private double taxa; /* Formulario para resposta */ private static final String XML_FORM = "<cotacao><nome-banco>{0}</nome-banco>" + "<taxa>{1}</taxa></cotacao>"; public Banco_A_TCP() { // Calcula a taxa para emprestimo randomicamente. this.taxa = Math.random() * 10; } /** * Este metodo e' invocado quando uma mensagem * chega ao inbound endpoint do servico Banco-A. * Constroi a resposta ao cliente contendo a * cotacao do emprestimo. */ public String getCotacaoEmprestimo( String requisicao) { // Para debug. System.out.println("<<<DEBUG>>>: Requisicao ao Banco-A: " + requisicao); String reqXml = MessageFormat.format(XML_FORM, getNomeBanco(), Double.toString(getTaxa())); return reqXml; } public String getNomeBanco() { return nomeBanco; } public double getTaxa() { return taxa; } } Figura 54 Classe Banco_A_TCP.

import java.awt.Color; import java.awt.BorderLayout; import java.awt.event.*; import javax.swing.*; import java.io.*; import java.net.*; class ClientWorker implements Runnable { private Banco_A_TCP banco; private Socket client; private JTextArea textArea; ClientWorker(Socket client, JTextArea textArea) { this.client = client; this.textArea = textArea; } public void run(){ String line; StringBuffer lineBuf = new StringBuffer(); boolean fim = false; InputStream is = null; PrintWriter out = null; try { is = client.getInputStream(); out = new PrintWriter(client.getOutputStream(), true); } catch (IOException e) { System.out.println("ERRO: Input/Output Stream."); System.exit(-1); } while (!fim) { try{ int r = is.read(); if (r != -1) { lineBuf.append((char)r); if (is.available() <= 0) { fim = true; } } else { break; } } Figura 55 Classe BancoServer (continua).

catch (IOException e) { System.out.println("ERRO DE LEITURA."); textArea.append("ERRO DE LEITURA. Cliente desconectou-se.\r\n\r\n"); break; } } if (lineBuf.length() == 0) { System.out.println("***** NENHUMA ENTRADA RECEBIDA *****"); } else { line = lineBuf.toString(); System.out.println("RECEBIDO: " + line); banco = new Banco_A_TCP(); String resp = banco.getCotacaoEmprestimo(line); out.println(resp); textArea.append(line + "\r\n " + resp + "\r\n"); } } } class BancoServer extends JFrame { JLabel label = new JLabel("Requisicoes recebidas:"); JPanel panel; JTextArea textArea = new JTextArea(); ServerSocket server = null; BancoServer() { panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.setBackground(Color.white); getContentPane().add(panel); panel.add("North", label); panel.add("Center", textArea); } public void listenSocket() { try { server = new ServerSocket(4599); } catch (IOException e) { System.out.println("Erro na criacao do socket porta 4599"); System.exit(-1); } Figura 55 Classe BancoServer (continuao).

while(true){ ClientWorker w; try { w = new ClientWorker(server.accept(), textArea); Thread t = new Thread(w); t.start(); } catch (IOException e) { System.out.println("Falha em Accept."); System.exit(-1); } } } protected void finalize(){ try { server.close(); } catch (IOException e) { System.out.println("Could not close socket"); System.exit(-1); } } public static void main(String[] args){ BancoServer frame = new BancoServer(); frame.setTitle("Server Banco-A"); WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; frame.addWindowListener(l); frame.pack(); frame.setVisible(true); frame.listenSocket(); } } Figura 55 Classe BancoServer (continuao).

package org; import javax.jws.WebService; /** * <code>Banco-B</code> representa uma instituicao bancaria. */ @WebService public interface Banco { /** * Este metodo e' invocado quando uma mensagem chega ao inbound endpoint do servico * Banco-B. Constroi a resposta ao cliente contendo a cotacao do emprestimo. */ String getCotacaoEmprestimo(String requisicao); }

package org; import javax.jws.WebService; import java.text.MessageFormat; @WebService(endpointInterface = "org.Banco", serviceName = "Banco") /** * <code>Banco-B</code> representa uma instituicao bancaria. */ public class BancoImpl implements Banco { /** Nome do banco */ private static final String nomeBanco = "Banco-B"; /* Taxa oferecida pelo banco */ private double taxa; private static final String XML_FORM = "<cotacao><nome-banco>{0}</nome-banco>" + "<taxa>{1}</taxa></cotacao>"; public BancoImpl() { // Calcula a taxa para emprestimo randomicamente. this.taxa = Math.random() * 10; }

Figura 56 Classes do Banco-B-WS (continua).

/** * Este metodo e' invocado quando uma mensagem chega ao inbound endpoint do servico * Banco-B. Constroi a resposta ao cliente contendo a cotacao do emprestimo. */ public String getCotacaoEmprestimo(String requisicao) { // Para debug. System.out.println("<<<DEBUG>>>: Requisicao ao Banco-B: " + requisicao); String reqXml = MessageFormat.format(XML_FORM, getNomeBanco(), Double.toString(getTaxa())); return reqXml; } private String getNomeBanco() { return nomeBanco; } private double getTaxa() { return taxa; } } Figura 56 Classes do Banco-B-WS (continuao).

7.1.2 Gerador de Relatrio


Com o objetivo de experimentar o transporte JDBC adicionamos um componente gerador de relatrio no nosso estudo de caso. Este componente recebe as requisies de cotao de emprstimo e as armazena em um banco de dados. Para simplificar utilizamos o banco HSQLDB (Hypersonic Database), mas poderamos substitu-lo por outro banco rodando separadamente. As configuraes dos endpoints seriam as mesmas. Para a gerao do relatrio ser configurado um novo servio (GeradorRelatorio) que receber uma cpia de todas as mensagens contendo uma requisio de cotao de emprstimo. A classe GeradorRelatorio, veja figura 57, prepara um map contendo as informaes relativas requisio para armazenamento no banco. O armazenamento no banco feito pelo outbound endpoint definido para o servio, veja item 7.2.4.6. O componente Gerador de Relatrio tambm responsvel por iniciar o banco de dados. Como nosso objetivo mostrar o transporte JDBC, o banco existe apenas em memria, os dados no so armazenados no file system. O mtodo initialise da classe GeradorRelatorio ser invocado pelo framework quando o componente for criado. A classe MemoryHSQLDB (figura 58) utilizada para fazer a iniciao do banco criando a tabela para conter o relatrio.

package spb; import spb.mensagens.RequisicaoServico; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import spb.mensagens.PerfilCredito; import spb.mensagens.Cliente; import java.util.*; import java.sql.SQLException; public class GeradorRelatorio implements org.mule.api.lifecycle.Initialisable { /** Logger usado por esta classe */ protected final Log logger = LogFactory.getLog(getClass()); /** Indicador de banco iniciado. */ private boolean initialized = false; /** * Inicia o banco de dados. */ public void initialise() { if (!initialized) { try { MemoryHSQLDB.startup(); // Log para debug logger.info("\n" + MensagemLocal.mensagemDebug( "##### BANCO DE DADOS HSQLDB INICIADO #####")); initialized = true; } catch (SQLException e) { // Log para debug logger.info("\n" + MensagemLocal.mensagemDebug( "##### ERRO INICIANDO BANCO DE DADOS HSQLDB #####")); } } }

/** * Este metodo e' invocado quando uma requisicao de cotacao de * emprestimo chega ao inbound endpoint do servico. um Map * contendo os dados correspondentes a requisicao e' construido. * Este map e' utilizado para inserir a requisicao no banco de dados. */ Figura 57 Gerador de Relatrio (continua).

public Map preparaLinhaRelatorio(RequisicaoServico requisicao) { Map linhaRel = new HashMap(); String cliente = requisicao.getCliente().getNome(); String cpf = requisicao.getCliente().getCpf(); String pontuacao = Integer.toString(requisicao.getPerfilCredito().getPontuacaoCredito()); String historico = Integer.toString(requisicao.getPerfilCredito().getHistoricoCredito()); String valor = Double.toString(requisicao.getValor()); String prazo = Integer.toString(requisicao.getPrazo()); // Log para debug logger.info("\n" + MensagemLocal.mensagemDebug("Dados para relatorio: " + cliente + ", " + cpf + ", " + pontuacao + ", " + historico + ", " + valor + ", " + prazo)); linhaRel.put("CLIENTE", cliente); linhaRel.put("CPF", cpf); linhaRel.put("PONTUACAO", pontuacao); linhaRel.put("HISTORICO", historico); linhaRel.put("VALOR", valor); linhaRel.put("PRAZO", prazo); return linhaRel; } } Figura 57 Gerador de Relatrio (continuao).

/* Esta classe utilizada para fazer o setup do banco HSQLDB. */ package spb; import java.sql.Connection; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import org.hsqldb.jdbc.jdbcDataSource; import java.sql.DriverManager; public class MemoryHSQLDB { /** * Metodo para criacao da tabela Relatorio. */ public static void startup() throws SQLException { Connection connRel = getConnectionRelatorio(); System.out.println("*** CRIANDO TABELA RELATORIO ***"); update(connRel, "CREATE TABLE RELATORIO(ID INTEGER GENERATED BY" + " DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY," + "CLIENTE VARCHAR(32),CPF VARCHAR(32),PONTUACAO VARCHAR(32)," + "HISTORICO VARCHAR(32),VALOR VARCHAR(32),PRAZO VARCHAR(32))"); } /** * Conexao com o banco. */ private static Connection getConnectionRelatorio() { try { Class.forName("org.hsqldb.jdbcDriver").newInstance(); return DriverManager.getConnection("jdbc:hsqldb:mem:relatorio", "sa", ""); } catch (SQLException se) { System.out.println("Excecao ao obter conexao com HSQLDB[1]"); se.printStackTrace(); } catch (Exception e) { System.out.println("Excecao ao obter conexao com HSQLDB[2]"); e.printStackTrace(); } return null; }

Figura 58 Setup do Banco (continua).

/** * Comando Update. */ private static synchronized void update(Connection conn, String expression) throws SQLException { Statement st = null; st = conn.createStatement(); int i = st.executeUpdate(expression); if (i == -1) { System.out.println("ERRO DB : " + expression); } st.close(); } } Figura 58 Setup do Banco (continuao).

7.1.3 Emisso Automtica de Relatrio


Para completar a funcionalidade de produo de relatrio e experimentar os transportes File e SMTP ns adicionamos mais um servio nossa soluo, o servio de emisso automtica de relatrios. Este servio emitir um relatrio, em arquivo, a cada intervalo de tempo programado na configurao do servio. O componente deste servio representado pela classe EmissorRelatorio, que recebe atravs de seu inbound endpoint uma linha correspondente ao resultado de um select na tabela relatrio e prepara uma linha a ser gravada no arquivo de relatrio via seu outbound endpoint. Este mesma linha preparada pelo emissor de relatrios enviada por email atravs de outro outbound endpoint deste servio. As configuraes dos endpoints sero apresentadas no item 7.2.4.7. A linha preparada pela classe EmissorRelatorio tem o seguinte formato: <requisicao> <nome> nome do cliente </nome> <cpf> nmero do CPF </cpf> <pontuacao> pontuao do cliente </pontuacao> <historico> histrico do cliente </historico> <valor> valor do emprstimo </valor> <prazo> prazo para pagamento do emprstimo </prazo> </requisicao> O resultado do select na tabela Relatrio trs sempre todas as linhas e o emissor evita a gravao de linhas duplicadas por meio do ID da linha. claro que isso pode ser melhorado, evitando que o select traga todas as linhas. A figura 59 apresenta o cdigo da classe EmissorRelatorio.

package spb; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.*; public class EmissorRelatorio implements org.mule.api.lifecycle.Initialisable { /** Logger usado por esta classe */ protected final Log logger = LogFactory.getLog(getClass()); private int idUltimoRegistro; public void initialise() { idUltimoRegistro = -1; } public String preparaLinha(Map linhaRel) { String linha = null; int id = ((Integer)linhaRel.get("ID")).intValue(); if (id > idUltimoRegistro) { StringBuffer linhaBuf = new StringBuffer(); linhaBuf.append("<requisicao>" + '\n'); linhaBuf.append(" <nome>" + linhaRel.get("CLIENTE") + "</nome>" + '\n'); linhaBuf.append(" <cpf>" + linhaRel.get("CPF") + "</cpf>" + '\n'); linhaBuf.append(" <pontuacao>" + linhaRel.get("PONTUACAO") + "</pontuacao>" + '\n'); linhaBuf.append(" <historico>" + linhaRel.get("HISTORICO") + "</historico>" + '\n'); linhaBuf.append(" <valor>" + linhaRel.get("VALOR") + "</valor>" + '\n'); linhaBuf.append(" <prazo>" + linhaRel.get("PRAZO") + "</prazo>" + '\n'); linhaBuf.append("</requisicao>" + '\n'); logger.info("\n" + MensagemLocal.mensagemDebug(linhaBuf.toString())); linha = linhaBuf.toString(); idUltimoRegistro = id; } return linha; } } Figura 59 O Emissor de Relatrios.

7.1.4 Transformer para os Bancos A e B


Os inbound endpoints dos bancos A e B trazem respostas das aplicaes externas (via TCB e CXF) no seguinte formato XML: <cotacao> <nome-banco> nome do banco </nome-banco>

<taxa> taxa oferecida pelo banco </taxa> </cotacao> Este no o formato esperado pelo roteador assncrono de respostas, que espera um objeto da classe RespostaCliente. Para fazer esta converso foi desenvolvido o custom transform BancoXMLparaRespostaCliente apresentado na figura 60. Este transformer no apresenta novidades em relao aos que j vimos anteriormente. Outros transformers pr-definidos sero utilizaos pelos bancos, como veremos na parte de configuraes. package spb.transformers; import org.mule.api.transformer.TransformerException; import org.mule.transformer.AbstractTransformer; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import spb.mensagens.RespostaCliente; import spb.mensagens.Cotacao; import spb.MensagemLocal; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Esta classe transforma a resposta enviada pelo banco em um * objeto da classe RespostaCliente. */ public class BancoXMLparaRespostaCliente extends AbstractTransformer { /** Logger usado por esta classe */ private final Log logger = LogFactory.getLog(getClass()); public BancoXMLparaRespostaCliente() { // Recebe a cotacao de credito como uma String XML. registerSourceType(String.class); // Retorna resposta ao cliente setReturnClass(RespostaCliente.class); } Figura 60 Transformer para os bancos A e B (continua).

/** * Metodo de transformacao. A cotacao enviada pelo * banco esta' no formato XML: * <cotacao> * <nome-banco> ... </nome-banco> * <taxa> ... </taxa> * </cotacao> */ public Object doTransform(Object src, String encoding) throws TransformerException { Document doc = null; // Parsing da cotacao recebida. try { doc = DocumentHelper.parseText(src.toString()); } catch (DocumentException e) { throw new TransformerException(this, e); } // Obtem os valores da cotacao e atribui ao objeto RespostaCliente. String nomeBanco = doc.valueOf("/cotacao/nome-banco"); String taxa = doc.valueOf("/cotacao/taxa"); // Log para debug. logger.info("\n" + MensagemLocal.mensagemDebug( "Banco: " + nomeBanco + " Taxa: " + taxa)); Cotacao cotacao = new Cotacao(); cotacao.setNomeBanco(nomeBanco); cotacao.setTaxa(Double.parseDouble(taxa)); RespostaCliente resp = new RespostaCliente(false, null, cotacao); return resp; } } Figura 60 Transformer para os bancos A e B (continuao).

7.2 Implementao do Fluxo de Mensagens


Vamos alterar novamente o arquivo de configurao Mule (mule-config.xml) para acomodar os novos elementos de nosso estudo de caso. Adicionaremos novas configuraes de conectores, endpoints, transformers e servios.

7.2.1 Declaraes de Namespaces e Esquemas


Vamos acrescentar a esse bloco do arquivo de configuraes os namespaces e esquemas relativos aos novos transportes utilizados: TCP, CXF, JDBC, FILE e SMTP. Tambm acrescentaremos namespace e esquema do framework Spring para declarar o driver JDBC utilizado para acesso ao banco HSQLDB. A figura 61 apresenta as novas declaraes.

xmlns:spring="http://www.springframework.org/schema/beans" xmlns:tcp="http://www.mulesource.org/schema/mule/tcp/2.2" xmlns:cxf="http://www.mulesource.org/schema/mule/cxf/2.2" xmlns:jdbc="http://www.mulesource.org/schema/mule/jdbc/2.2" xmlns:file="http://www.mulesource.org/schema/mule/file/2.2" xmlns:smtp="http://www.mulesource.org/schema/mule/smtp/2.2" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.mulesource.org/schema/mule/tcp/2.2 http://www.mulesource.org/schema/mule/tcp/2.2/mule-tcp.xsd http://www.mulesource.org/schema/mule/cxf/2.2 http://www.mulesource.org/schema/mule/cxf/2.2/mule-cxf.xsd http://www.mulesource.org/schema/mule/jdbc/2.2 http://www.mulesource.org/schema/mule/jdbc/2.2/mule-jdbc.xsd http://www.mulesource.org/schema/mule/file/2.2 http://www.mulesource.org/schema/mule/file/2.2/mule-file.xsd http://www.mulesource.org/schema/mule/smtp/2.2 http://www.mulesource.org/schema/mule/smtp/2.2/mule-smtp.xsd">

Figura 61 Declaraes de namespaces e esquemas.

7.2.2 Configurao dos Transformers


Configuraremos novos transportes pr-definidos por Mule e o custom transformer utilizado pelos bancos A e B. Os transportes pr-definidos por Mule que utilizaremos nesta fase so: jmsmessage-to-object-transformer utilizado pelo servio de emisso automtica de relatrios. byte-array-to-string-transformer utilizado pelo Banco A. expression-transformer utilizado pelos bancos A e B. O expression transformer utilizado pelos bancos A e B serve para invocar o mtodo getRequisicaoXML da classe RequisicaoServico e obter a requisio do servio em formato XML, que ser enviada aos bancos implementados como aplicaes externas. A figura 62 apresenta a configurao dos novos transformers.
<jms:jmsmessage-to-object-transformer name="JmsMessageToObject" /> <byte-array-to-string-transformer name="ByteArrayToString" /> <expression-transformer name="RequisicaoServicoParaRequisicaoXML"> <return-argument evaluator="bean" expression="requisicaoXML"/> </expression-transformer> <custom-transformer name="BancoXMLparaRespostaCliente" class="spb.transformers.BancoXMLparaRespostaCliente" />

Figura 62 Configurao dos Transformers.

7.2.3 Configurao dos Endpoints


A configurao dos endpoints envolve a configurao de conectores e transportes a serem utilizados pelos endpoints. Nesta fase do estudo de caso estamos experimentando cinco novos transportes: TCP, CXF, JDBC, FILE e SMTP.

7.2.3.1 Endpoint TCP


O transporte TCP possibilita o envio e recebimento de mensagens via socket TCP. Vrios atributos podem ser configurados em um conector TCP, veja [7] para maiores detalhes. Vamos configurar algumas propriedades para o nosso conector TCP: keepSendSocketOpen esta uma propriedade do tipo booleana que determina se o socket deve ser mantido aberto (true) ou no (false) aps o cliente enviar uma mensagem. payloadOnly esta propriedade booleana indica se s o payload da mensagem (true) deve ser enviado e no todo o objeto mensagem Mule incluindo suas propriedades. Protocolos podemos utilizar vrios protocolos na comunicao via socket, como: Direct, Streaming, XML, Safe, Length, etc. Utilizaremos o protocolo Direct. Este protocolo no garante que os dados escritos no socket sejam entregues em um nico pacote. Utilizar este protocolo muito simples pode ser necessrio para comunicar com protocolos externos baseados em TCP. A configurao do conector TCP fica da seguinte forma: <tcp:connector name="tcpConnector" keepSendSocketOpen="false"> <tcp:direct-protocol payloadOnly="true"/> </tcp:connector> A configurao do endpoint que utilize o conector TCP deve especificar os seguintes atributos: host o host do socket TCP port o nmero da porta do socket TCP A configurao para o nosso endpoint fica: <tcp:endpoint name="TcpBancoAEdp" host="localhost" port="4599" connector-ref="tcpConnector"/>

7.2.3.2 Endpoint CXF


O transporte CXF prov suporte para integrao Web Service via CXF Apache, que um framework de servios que nos ajuda a construir e desenvolver servios usando APIs, como JAX-WS. Estes servios podem falar uma variedade de protocolos como SOAP, XML/HTTP, RESTful HTTP ou CORBA e funciona sobre uma variedade de transportes como HTTP, JMS, VM or JBI. A referncia [7] trs vrias informaes de como configurar e utilizar o transporte CXF. No nosso estudo de caso vamos utilizar o conector WSDL, que usado para invocar web services remotos atravs da obteno da WSDL do servio. O conector no precisa ser declarado, ele estabelecido pelo Mule. Um endpoint WSDL prov um meio para invocar web services facilmente, sem a necessidade de gerar um cliente. Na iniciao, o endpoint l o WSDL para determinar como invocar o web service remoto em tempo de execuo. Quando uma mensagem enviada atravs de endpoint WSDL, ele est em condies de construir uma mensagem SOAP usando o payload da mensagem e o seu cohecimento a respeito do formato esperado pelo web service. preciso prover o URL completo para o WSDL do servio a ser invocado e tambm, atravs do parmetro method, a operao a ser invocada no servio. A configurao do endpoint a ser utilizado para comunicao com o banco implementado como Web Service remoto fica da seguinte forma:
<endpoint name="WSDLCxfBancoBEdp" address="wsdl-cxf:http://localhost:8080/BancoBWS/cotacao?WSDL&amp;method=getCotacaoEmprestimo" />

7.2.3.3 Endpoint JDBC


Precisamos definir endpoints JDBC para acesso ao banco de dados HSQLDB, utilizado para armazenar o relatrio de requisies. Vamos definir um endpoint para que o servio de gerao de relatrio possa armazenar os dados no banco de dados e um endpoint para que o servio de emisso automtica de relatrios possa obter dados do banco de dados. Temos ento um endpoint para INSERT e um endpoint para SELECT. O esquema utilizado para esse banco de dados o seguinte: CREATE TABLE RELATORIO(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY, CLIENTE VARCHAR(32), CPF VARCHAR(32), PONTUACAO VARCHAR(32), HISTORICO VARCHAR(32), VALOR VARCHAR(32),PRAZO VARCHAR(32)) O transporte JDBC implementado por Mule tem ainda uma srie de restries, limitaes e diferenas significativas entre as verses Community e Enterprise do Mule. Verifique em [7] se as funcionalidades que voc precisa so suportadas na verso do Mule que pretende usar. A configurao do transporte JDBC requer quer estabeleamos algumas propriedades, entre elas, as mais comuns so: dataSource-ref a referncia JNDI ou bean para o datasource a ser utilizado para o acesso ao banco de dados. Deve ser configurada no conector. pollingFrequency define a freqncia de execuo da query em milissegundos. Pode ser configurada no conector ou no inbound endpoint. queryKey especifica a query a ser utilizada. Pode ser configurada no conector, inbound endpoint ou outbound endpoint. Para configurar o datasource JDBC vamos utilizar um Spring datasource, onde especificamos uma identificao para o datasource (ser referenciada no conector), a classe que representa o driver manager, a classe que representa o driver JDBC, o URL da tabela do banco de dados que vamos acessar e o usurio do banco de dados com sua senha. A configurao do datasource para nosso estudo de caso fica da seguinte forma:
<spring:bean id="dataSourceRel" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <spring:property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <spring:property name="url" value="jdbc:hsqldb:mem:relatorio"/> <spring:property name="username" value="sa"/> <spring:property name="password" value=""/> </spring:bean>

No conector JDBC vamos fazer referncia ao datasource e configurar as propriedades pollingFrequency e queryKey. PoolingFrequency faz sentido apenas para o inbound endpoint. Teremos duas propriedades queryKey definidas, uma para realizar INSERT e outra para SELECT. A configurao do conector fica:
<jdbc:connector name="jdbcConnector" pollingFrequency="60000" dataSource-ref="dataSourceRel"> <jdbc:query key="outboundInsertStatement" value="INSERT INTO RELATORIO (CLIENTE, CPF, PONTUACAO, HISTORICO, VALOR, PRAZO) VALUES (#[map-payload:CLIENTE],#[map-payload:CPF], #[map-payload:PONTUACAO], #[map-payload:HISTORICO], #[map-payload:VALOR], #[map-payload:PRAZO])"/> <jdbc:query key="inboundSelectStatement" value="SELECT ID, CLIENTE, CPF, PONTUACAO, HISTORICO, VALOR, PRAZO FROM RELATORIO ORDER BY ID"/> </jdbc:connector>

Vejamos como os dados so alimentados no comando INSERT e como so recebidos do comando SELECT. Os dados para o comando INSERT so obtidos do payload da mensagem Mule corrente. Esse payload um Map (Java.util.Map) na forma <nome coluna> <valor>. Por exemplo, na configurao do conector temos a expresso: #[map-payload:CLIENTE] significando que o dado a ser inserido na coluna CLIENTE da tabela ser obtido do elemento do Map cuja chave CLIENTE. A classe GeradorRelatorio, descrita no item 7.1.2, mostra a criao do Map para insero no banco de dados. Da mesma forma o resultado obtido atravs de um comando SELECT chega ao endpoint em uma mensagem Mule cujo payload um Map. A classe EmissorRelatorio obtm deste Map o resultado do SELECT para a emisso do relatrio. Falta agora configurar os dois endpoints, um inbound endpoint para realizar o select na base de dados e o outbound endpoint para realizar insert. As configuraes dos endpoints so as seguintes: <jdbc:endpoint name="insertDataBaseEdp" queryKey="outboundInsertStatement" connector-ref="jdbcConnector" /> <jdbc:endpoint name="selectDataBaseEdp" queryKey="inboundSelectStatement" connector-ref="jdbcConnector" />

7.2.3.4 Endpoint FILE


O transporte FILE permite ler e escrever arquivos em diretrios no file system local. Vrias propriedades podem ser especificadas para esse transporte, veja [7]. Configuraremos um conector onde especificaremos que os dados devem ser adicionados ao fim do arquivo nas operaes de escrita e o nome do arquivo gerado: <file:connector name="fileConnector" outputAppend="true outputPattern="solicitacoes.txt" /> Na configurao do endpoint vamos estabelecer o caminho do diretrio onde o arquivo de relatrio deve ser gravado: <file:endpoint name="relatorioEdp" connector-ref="fileConnector" path="c:/tutorial/agencia-emprestimo/relatorio" /> Existem vrios transformers dedicados ao transporte FILE, como, por exemplo, transformers para transformar dados lidos de um java.io.File em um byte array ou Java.lang.String. Veja [7] para conhecer todos os transformers suportados.

7.2.3.5 Endpoint SMTP


O transporte SMTP pode ser usado para enviar mensagens sobre SMTP. O conector SMTP suporta uma srie de atributos como: ccAddresses, fromAddress, replyToAddresses e subject. Veja [7] para mais detalhes. Alguns dos atributos podem ser configurados tambm no endpoint e no precisamos necessariamente declarar um conector SMTP, Mule cria um automaticamente. Configuraremos em nosso conector SMTP apenas a propriedade subject: <smtp:connector name="smtpConnector" subject="Requisicao Recebida" />

A configurao do endpoint requer um pouco mais de atributos, precisamos definir o usurio do mailbox, sua senha, o endereo do SMTP Server, sua porta, o email do remetente e do destinatrio. Configuramos o endpoint da seguinte forma: <smtp:endpoint name="emailEdp" connector-ref="smtpConnector" host="mailhost.agencia.com.br" port="25" user="relatorio" password="relpasswd" from="relatorio@agencia.com.br" to="gerencia@agencia.com.br" /> A figura 63 apresenta os conectores e endpoints adicionados ao arquivo de configurao Mule (muleconfig.xml) para esta fase do estudo de caso.
<!-- Datasource JDBC --> <spring:bean id="dataSourceRel" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <spring:property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <spring:property name="url" value="jdbc:hsqldb:mem:relatorio"/> <spring:property name="username" value="sa"/> <spring:property name="password" value=""/> </spring:bean> <tcp:connector name="tcpConnector" keepSendSocketOpen="false"> <tcp:direct-protocol payloadOnly="true"/> </tcp:connector> <jdbc:connector name="jdbcConnector" pollingFrequency="60000" dataSource-ref="dataSourceRel"> <jdbc:query key="outboundInsertStatement" value="INSERT INTO RELATORIO (CLIENTE, CPF, PONTUACAO, HISTORICO, VALOR, PRAZO) VALUES (#[map-payload:CLIENTE],#[map-payload:CPF], #[map-payload:PONTUACAO], #[map-payload:HISTORICO], #[map-payload:VALOR], #[map-payload:PRAZO])"/> <jdbc:query key="inboundSelectStatement" value="SELECT ID, CLIENTE, CPF, PONTUACAO, HISTORICO, VALOR, PRAZO FROM RELATORIO ORDER BY ID"/> </jdbc:connector> <file:connector name="fileConnector" outputAppend="true" outputPattern="solicitacoes.txt" /> <smtp:connector name="smtpConnector" subject="Requisicao Recebida" /> <tcp:endpoint name="TcpBancoAEdp" host="localhost" port="4599" connector-ref="tcpConnector"/> <endpoint name="WSDLCxfBancoBEdp" address="wsdl-cxf:http://localhost:8080/BancoBWS/cotacao? WSDL&amp;method=getCotacaoEmprestimo" /> <endpoint name="GeradorRelatorioEdp" connector-ref="vmConnector" address="vm://spb.relatorio" /> <jdbc:endpoint name="insertDataBaseEdp" queryKey="outboundInsertStatement" connector-ref="jdbcConnector" /> <jdbc:endpoint name="selectDataBaseEdp" queryKey="inboundSelectStatement" connector-ref="jdbcConnector" />

Figura 63 Configuraes de conectores e endpoints (continua).

<file:endpoint name="relatorioEdp" connector-ref="fileConnector" path="c:/tutorial/agencia-emprestimo/relatorio" /> <smtp:endpoint name="emailEdp" connector-ref="smtpConnector" host="mailhost.agencia.com.br" port="25" user="relatorio" password="relpasswd" from="relatorio@agencia.com.br" to="gerencia@agencia.com.br" />

Figura 63 Configuraes de conectores e endpoints (continuao).

7.2.4 Configurao dos Servios


Nesta fase do estudo de caso acrescentamos dois novos servios, o Gerador de Relatrio e o Emissor de Relatrios, substitumos os servios Banco-A e Banco-B por aplicaes externas e mudamos algumas configuraes de alguns servios. Vamos descrever as alteraes de configurao e definir as configuraes dos novos servios nos itens seguintes.

7.2.4.1 Configurao do Servio SeletorBancario


Neste servio alteramos apenas a configurao do componente inbound. Utilizamos um Wire Tap router para enviar uma cpia da mensagem que chega ao Seletor Bancrio, que uma mensagem de requisio de cotao de emprstimo, para o servio de gerao de relatrio. A figura 64 mostra a nova configurao do servio Seletor Bancrio, com alterao apenas no elemento inbound.
<service name="SeletorBancario"> <inbound> <inbound-endpoint ref="SeletorBancarioEdp" /> <wire-tap-router> <outbound-endpoint ref="GeradorRelatorioEdp" /> </wire-tap-router> </inbound> <component class="spb.SeletorBancario" /> <outbound> <filtering-router> <outbound-endpoint ref="GWBancario" transformer-refs="BancosComoRecipientes ObjectToJmsMessage" /> <payload-type-filter expectedType="spb.mensagens.RequisicaoServico"/> </filtering-router> <filtering-router> <outbound-endpoint ref="TrataErrosRequisicaoEdp" /> <payload-type-filter expectedType="spb.mensagens.MensagemErro"/> </filtering-router> </outbound> </service>

Figura 64 Configurao do servio SeletorBancario. Um inbound wire tap router permite rotear uma mensagem que chega ao inbound endpoint para outros endpoints bem como para o componente onde ele configurado. Para rotear para outros endpoints feita uma cpia da mensagem que chega ao endpoint. No nosso caso, mensagens que chegam ao inbound endpoint do SeletorBancario (SeletorBancarioEdp) so roteadas tanto para o componente SeletorBancario quanto para o endpoint GeradorRelatorioEdp. Um Wire Tap router suporta tambm a

configurao de filtros, permitindo enviar para o outro endpoint apenas mensagens com certas caractersticas.

7.2.4.2 Configurao do Servio GatewayBancario


A modificao neste componente foi bastante simples. Na fase anterior o elemento outbound deste servio estava configurado com o atributo reply-to, que foi removido nesta fase. Com o atributo replyto os servios Banco-A, Banco-B e Banco-C no precisavam configurar o elemento outbound, as mensagens geradas por seus componentes eram roteadas de acordo com o atributo reply-to, que as encaminhava para o roteador assncrono de respostas, cujo endpoint RespostasServicos. Com a remoo do atributo os servios que representam os bancos precisam configurar o elemento outbound, como veremos adiante. A figura 65 apresenta a nova configurao do servio GatewayBancario, alterando apenas o elemento outbound.

<service name="GatewayBancario"> <inbound> <inbound-endpoint ref="GWBancario" /> </inbound> <outbound> <static-recipient-list-router /> </outbound> </service>

Figura 65 Configurao do servio GatewayBancario.

7.2.4.3 Configurao do Servio Banco-A


O Banco A passou a ser implementado por uma aplicao externa e o servio Banco-A passou a ser um proxy para repassar as requisies de cotao de emprstimo usando o transporte TCP. O elemento inbound do servio no foi alterado e o componente foi removido, j que a implementao do banco passou para a aplicao externa. O elemento outbound teve que ser alterado, assumindo o papel de enviar a requisio aplicao externa, receber a resposta e encaminh-la ao roteador de respostas assncrono (endpoint RespostasServicos). O outbound foi configurado com um chaining router. Este tipo de router permite enviar uma mensagem de maneira sncrona por um endpoint e direcionar a resposta para outro endpoint sem processar o resultado. Podemos configurar uma lista de endpoints e a mensagem fluir pelos endpoints sequencialmente, na ordem que so declarados. A figura 66 apresenta a configurao do servio Banco-A, com um chaining router configurado no elemento outbound contendo dois endpoints, um TCP para enviar mensagem aplicao externa que representa o banco e outro para encaminhar a resposta ao roteador assncrono de respostas. Quatro transformers foram utilizados nesta configurao. O primeiro transforma a requisio de servio (objeto RequisicaoServico) para uma requisio no formato XML antes de envi-la a aplicao externa via TCP (veja item 7.1.4). Os outros trs so utilizados para transformar a resposta da aplicao externa antes de envi-la ao roteador assncrono de respostas. O primeiro destes trs transformers transforma o byte array recebido via TCP em uma String, o segundo transforma a resposta XML enviada pela aplicao externa em um objeto RespostaCliente e o terceiro simplesmente encapsula a resposta em uma mensagem JMS antes de envi-la ao roteador assncrono.

<service name="Banco-A"> <inbound> <inbound-endpoint ref="Banco-A-edp" /> </inbound> <outbound> <chaining-router> <outbound-endpoint ref="TcpBancoAEdp" transformer-refs="RequisicaoServicoParaRequisicaoXML"/> <outbound-endpoint ref="RespostasServicos" transformer-refs="ByteArrayToString BancoXMLparaRespostaCliente ObjectToJmsMessage" /> </chaining-router> </outbound> </service>

Figura 66 Configurao do Servio Banco-A

7.2.4.4 Configurao do Servio Banco-B


O Banco B passou a ser implementado por uma aplicao externa e o servio Banco-B passou a ser um proxy para repassar as requisies de cotao de emprstimo usando o transporte CXF. O elemento inbound do servio no foi alterado e o componente foi removido, j que a implementao do banco passou para a aplicao externa. O elemento outbound teve que ser alterado, assumindo o papel de enviar a requisio aplicao externa, receber a resposta e encaminh-la ao roteador de respostas assncrono (endpoint RespostasServicos). Da mesma forma que o servio Banco-A, o outbound deste servio foi equipado com um chaining router. O chaining router foi configurado contendo dois endpoints, um CXF para enviar mensagem aplicao externa que representa o banco e outro para encaminhar a resposta ao roteador assncrono de respostas. O chaining router foi equipado com trs transformers, a nica diferena em relao configurao do Banco-A foi que o transformer de byte array para String no foi necessrio. A figura 67 apresenta a configurao deste servio.
<service name="Banco-B"> <inbound> <inbound-endpoint ref="Banco-B-edp" /> </inbound> <outbound> <chaining-router> <outbound-endpoint ref="WSDLCxfBancoBEdp" transformer-refs="RequisicaoServicoParaRequisicaoXML"/> <outbound-endpoint ref="RespostasServicos" transformer-refs="BancoXMLparaRespostaCliente ObjectToJmsMessage" /> </chaining-router> </outbound> </service>

Figura 67 Configurao do servio Banco-B.

7.2.4.5 Configurao do Servio Banco-C


Neste servio apenas acrescentamos o elemento outbound. Essa alterao foi necessria porque retiramos do outbound do servio GatewayBancario o atributo reply-to. A figura 68 apresenta a nova configurao.
<service name="Banco-C"> <inbound> <inbound-endpoint ref="Banco-C-edp" /> </inbound> <component class="spb.banco.Banco" /> <outbound> <pass-through-router> <outbound-endpoint ref="RespostasServicos" /> </pass-through-router> </outbound> </service>

Figura 68 Configurao do Servio Banco-C

7.2.4.6 Configurao do Servio GeradorRelatorio


O Gerador de Relatrio um novo servio implementado no estudo de caso. Este servio recebe mensagens com requisies de cotao de emprstimo do Wire Tap router definido no inbound endpoint do servio SeletorBancario. O componente deste servio, cuja implementao foi apresentada no item 7.1.2, tem uma configurao um pouco diferente das que vimos at agora. O componente foi configurado como um singleton-object, significando que a factory responsvel pela criao do objeto deve implementar o pattern singleton. Com isso podemos manter o estado do objeto entre processamento de mensagens distintas. Nesto caso do gerador de relatrio a iniciao do banco de dados deve ocorrer apenas uma vez. O outbound endpoint para esse servio foi configurado como um endpoint JDBC que executa um comando INSERT no banco de dados. Os dados para insero so gerados pelo componente como um objeto Java.util.Map. A figura 69 mostra a configurao do servio GeradorRelatorio.
<service name="GeradorRelatorio"> <inbound> <inbound-endpoint ref="GeradorRelatorioEdp" /> </inbound> <component> <singleton-object class="spb.GeradorRelatorio"/> </component> <outbound> <pass-through-router> <outbound-endpoint ref="insertDataBaseEdp"/> </pass-through-router> </outbound> </service>

Figura 69 Configurao do servio GeradorRelatorio.

7.2.4.7 Configurao do Servio EmissorAutomaticoRelatorio


Este servio emite relatrios de recebimento de requisies de cotao de emprstimo em intervalos regulares de tempo. Os dados para a emisso dos relatrios so obtidos do banco de dados, alimentado pelo servio GeradorRelatorio. O inbound endpoint deste servio foi configurado como um endpoint JDBC que executa um comando SELECT em intervalos regulares de tempo (configuramos para 60 segundos). Cada mensagem que chega ao endpoint um objeto Java.util.Map contendo uma linha do banco de dados. O Map repassado ento ao componente do servio. O componente do servio foi configurado como um singleton da mesma forma que componente do servio GeradorRelatorio. Mantendo o estado entre o processamento de mensagens esse componente evita a duplicao de dados no relatrio verificando o ID da linha recebida. No outbound endpoint do servio foi utilizado um multicasting router para emitir o relatrio tanto em arquivo quanto por email. O multicasting router implementa o pattern broadcast, enviando a mesma mensagem para vrios endpoints. Filtros e transformers podem ser utilizados neste tipo de roteador. Na configurao do outbound endpoint deste servio foram definidos dois destinos para as mensagens, um endpoint FILE e um endpoint SMTP. Desta forma a linha do relatrio ser enviada tanto para um arquivo quanto para um endereo de email. Foi colocado um transformer para transformar a mensagem JMS em um objeto antes de envi-la ao endpoint FILE e foi colocado um filtro no roteador para aceitar apenas mensagens com payload contendo um objeto Java.lang.String. Este filtro foi colocado porque o componente pode retornar null para resultados do SELECT que j foram emitidos. A figura 70 apresenta a configurao do servio EmissorAutomaticoRelatorio.
<service name="EmissorAutomaticoRelatorio"> <inbound> <inbound-endpoint ref="selectDataBaseEdp"/> </inbound> <component> <singleton-object class="spb.EmissorRelatorio"/> </component> <outbound> <multicasting-router> <outbound-endpoint ref="relatorioEdp" transformer-refs="JmsMessageToObject" /> <outbound-endpoint ref="emailEdp" /> <payload-type-filter expectedType="java.lang.String"/> </multicasting-router> </outbound> </service>

Figura 70 Configurao do servio EmissorAutomaticoRelatorio.

7.3 O Arquivo de Configurao Mule


Como o arquivo de configurao (mule-config.xml) foi apresentado por partes nos itens anteriores, vamos apresent-lo de maneira completa na figura 71 para que tenhamos uma viso geral da configurao.

<?xml version="1.0" encoding="UTF-8"?> <mule xmlns="http://www.mulesource.org/schema/mule/core/2.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jetty="http://www.mulesource.org/schema/mule/jetty/2.2" xmlns:vm="http://www.mulesource.org/schema/mule/vm/2.2" xmlns:jms="http://www.mulesource.org/schema/mule/jms/2.2" xmlns:ejb="http://www.mulesource.org/schema/mule/ejb/2.2" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:tcp="http://www.mulesource.org/schema/mule/tcp/2.2" xmlns:cxf="http://www.mulesource.org/schema/mule/cxf/2.2" xmlns:jdbc="http://www.mulesource.org/schema/mule/jdbc/2.2" xmlns:file="http://www.mulesource.org/schema/mule/file/2.2" xmlns:smtp="http://www.mulesource.org/schema/mule/smtp/2.2" xsi:schemaLocation=" http://www.mulesource.org/schema/mule/jetty/2.2 http://www.mulesource.org/schema/mule/jetty/2.2/mule-jetty.xsd http://www.mulesource.org/schema/mule/core/2.2 http://www.mulesource.org/schema/mule/core/2.2/mule.xsd http://www.mulesource.org/schema/mule/vm/2.2 http://www.mulesource.org/schema/mule/vm/2.2/mule-vm.xsd http://www.mulesource.org/schema/mule/jms/2.2 http://www.mulesource.org/schema/mule/jms/2.2/mule-jms.xsd http://www.mulesource.org/schema/mule/ejb/2.2 http://www.mulesource.org/schema/mule/ejb/2.2/mule-ejb.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.mulesource.org/schema/mule/tcp/2.2 http://www.mulesource.org/schema/mule/tcp/2.2/mule-tcp.xsd http://www.mulesource.org/schema/mule/cxf/2.2 http://www.mulesource.org/schema/mule/cxf/2.2/mule-cxf.xsd http://www.mulesource.org/schema/mule/jdbc/2.2 http://www.mulesource.org/schema/mule/jdbc/2.2/mule-jdbc.xsd http://www.mulesource.org/schema/mule/file/2.2 http://www.mulesource.org/schema/mule/file/2.2/mule-file.xsd http://www.mulesource.org/schema/mule/smtp/2.2 http://www.mulesource.org/schema/mule/smtp/2.2/mule-smtp.xsd"> <!-- ####### TRANSFORMERS ####### --> <custom-transformer name="RequisicaoRestParaRequisicaoServico" class="spb.transformers.RequisicaoRestParaRequisicaoServico" /> <jms:object-to-jmsmessage-transformer name="ObjectToJmsMessage" /> <jms:jmsmessage-to-object-transformer name="JmsMessageToObject" /> <byte-array-to-string-transformer name="ByteArrayToString" /> <expression-transformer name="ClienteParaArgsAgenciaCredito"> <return-argument evaluator="bean" expression="nome"/> <return-argument evaluator="bean" expression="cpf"/> </expression-transformer> <custom-transformer name="PerfilCreditoXmlParaPerfilCredito" class="spb.transformers.PerfilCreditoXmlParaPerfilCredito" /> <custom-transformer name="BancosComoRecipientes" class="spb.transformers.BancosComoRecipientes" />

Figura 71 Arquivo de configurao Mule (continua)

<expression-transformer name="RequisicaoServicoParaRequisicaoXML"> <return-argument evaluator="bean" expression="requisicaoXML"/> </expression-transformer> <custom-transformer name="BancoXMLparaRespostaCliente" class="spb.transformers.BancoXMLparaRespostaCliente" /> <!-- Datasource JDBC --> <spring:bean id="dataSourceRel" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <spring:property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <spring:property name="url" value="jdbc:hsqldb:mem:relatorio"/> <spring:property name="username" value="sa"/> <spring:property name="password" value=""/> </spring:bean> <!-- ######## CONECTORES ######## --> <jetty:connector name="httpConnector" useContinuations="false" /> <vm:connector name="vmConnector" queueEvents="true"/> <jms:activemq-connector name="jmsConnector" /> <ejb:connector name="ejbConnector" securityPolicy="security.policy" jndiInitialFactory="org.jnp.interfaces.NamingContextFactory" jndiProviderUrl="localhost"> </ejb:connector> <tcp:connector name="tcpConnector" keepSendSocketOpen="false"> <tcp:direct-protocol payloadOnly="true"/> </tcp:connector> <jdbc:connector name="jdbcConnector" pollingFrequency="60000" dataSource-ref="dataSourceRel"> <jdbc:query key="outboundInsertStatement" value="INSERT INTO RELATORIO (CLIENTE, CPF, PONTUACAO, HISTORICO, VALOR, PRAZO) VALUES (#[map-payload:CLIENTE],#[map-payload:CPF], #[map-payload:PONTUACAO], #[map-payload:HISTORICO], #[map-payload:VALOR], #[map-payload:PRAZO])"/> <jdbc:query key="inboundSelectStatement" value="SELECT ID, CLIENTE, CPF, PONTUACAO, HISTORICO, VALOR, PRAZO FROM RELATORIO ORDER BY ID"/> </jdbc:connector> <file:connector name="fileConnector" outputAppend="true" outputPattern="solicitacoes.txt" /> <smtp:connector name="smtpConnector" subject="Requisicao Recebida" /> <!-- ######## ENDPOINTS ######### --> <endpoint name="RequisicaoServicoREST" connector-ref="httpConnector" address="jetty:rest://localhost:8888/AgenciaEmprestimo" /> <endpoint name="GWAgenciaCredito" connector-ref="jmsConnector" address="jms://spb.gw.agenciacredito" />

Figura 71 Arquivo de configurao Mule (continua)

<ejb:endpoint name="AgenciaCreditoEdp" host="localhost" port="1099" object="/AgenciaCredito" method="getPerfilCredito" methodArgumentTypes="java.lang.String,java.lang.String" connector-ref="ejbConnector"/> <endpoint name="SeletorBancarioEdp" connector-ref="vmConnector" address="vm://spb.seletorbancario.bancos" /> <endpoint name="GWBancario" connector-ref="jmsConnector" address="jms://spb.gw.bancario" /> <endpoint name="RespostasServicos" connector-ref="jmsConnector" address="jms://spb.emprestimo.respostas" /> <endpoint name="Banco-A-edp" connector-ref="jmsConnector" address="jms://spb.banco.banco-a" /> <endpoint name="Banco-B-edp" connector-ref="jmsConnector" address="jms://spb.banco.banco-b" /> <endpoint name="Banco-C-edp" connector-ref="jmsConnector" address="jms://spb.banco.banco-c" /> <endpoint name="TrataErrosRequisicaoEdp" connector-ref="jmsConnector" address="jms://spb.erro.requisicao" /> <tcp:endpoint name="TcpBancoAEdp" host="localhost" port="4599" connector-ref="tcpConnector"/> <endpoint name="WSDLCxfBancoBEdp" address="wsdl-cxf:http://localhost:8080/BancoBWS/cotacao? WSDL&amp;method=getCotacaoEmprestimo" /> <endpoint name="GeradorRelatorioEdp" connector-ref="vmConnector" address="vm://spb.relatorio" /> <jdbc:endpoint name="insertDataBaseEdp" queryKey="outboundInsertStatement" connector-ref="jdbcConnector" /> <jdbc:endpoint name="selectDataBaseEdp" queryKey="inboundSelectStatement" connector-ref="jdbcConnector" /> <file:endpoint name="relatorioEdp" connector-ref="fileConnector" path="c:/Alberto/tutorial/agencia-emprestimo/relatorio" /> <smtp:endpoint name="emailEdp" connector-ref="smtpConnector" host="mailhost.agencia.com.br" port="25" user="relatorio" password="relpasswd" from="relatorio@agencia.com.br" to="gerencia@agencia.com.br" /> <!-- ########### MODEL ########### --> <model name="AgenciaEmprestimo"> <service name="ServicosAgencia"> <inbound> <inbound-endpoint ref="RequisicaoServicoREST" transformer-refs="RequisicaoRestParaRequisicaoServico" /> </inbound> <component class="spb.ServicosAgencia" /> <outbound> <filtering-router> <outbound-endpoint ref="GWAgenciaCredito" /> <payload-type-filter expectedType="spb.mensagens.RequisicaoServico"/> </filtering-router>

Figura 71 Arquivo de configurao Mule (continua)

<filtering-router> <outbound-endpoint ref="TrataErrosRequisicaoEdp" /> <payload-type-filter expectedType="spb.mensagens.MensagemErro"/> </filtering-router> </outbound> <async-reply timeout="15000"> <inbound-endpoint ref="RespostasServicos" /> <custom-async-reply-router class="spb.routers.AgregadorRespostas" /> </async-reply> </service> <service name="GatewayAgenciaCredito"> <inbound> <inbound-endpoint ref="GWAgenciaCredito" /> </inbound> <component class="spb.GatewayAgenciaCredito"> <binding interface="spb.credit.ServicoAgenciaCredito" method="getPerfilCredito"> <outbound-endpoint synchronous="true" transformer-refs="ClienteParaArgsAgenciaCredito" responseTransformer refs="PerfilCreditoXmlParaPerfilCredito" ref="AgenciaCreditoEdp" /> </binding> </component> <outbound> <filtering-router> <outbound-endpoint ref="SeletorBancarioEdp" /> <payload-type-filter expectedType="spb.mensagens.RequisicaoServico"/> </filtering-router> <filtering-router> <outbound-endpoint ref="RespostasServicos" /> <payload-type-filter expectedType="spb.mensagens.RespostaCliente"/> </filtering-router> </outbound> </service> <service name="SeletorBancario"> <inbound> <inbound-endpoint ref="SeletorBancarioEdp" /> <wire-tap-router> <outbound-endpoint ref="GeradorRelatorioEdp" /> </wire-tap-router> </inbound> <component class="spb.SeletorBancario" />

Figura 71 Arquivo de configurao Mule (continua)

<outbound> <filtering-router> <outbound-endpoint ref="GWBancario" transformer-refs="BancosComoRecipientes ObjectToJmsMessage" /> <payload-type-filter expectedType="spb.mensagens.RequisicaoServico"/> </filtering-router> <filtering-router> <outbound-endpoint ref="TrataErrosRequisicaoEdp" /> <payload-type-filter expectedType="spb.mensagens.MensagemErro"/> </filtering-router> </outbound> </service> <service name="GatewayBancario"> <inbound> <inbound-endpoint ref="GWBancario" /> </inbound> <outbound> <static-recipient-list-router /> </outbound> </service> <service name="Banco-A"> <inbound> <inbound-endpoint ref="Banco-A-edp" /> </inbound> <outbound> <chaining-router> <outbound-endpoint ref="TcpBancoAEdp" transformer-refs="RequisicaoServicoParaRequisicaoXML"/> <outbound-endpoint ref="RespostasServicos" transformer-refs="ByteArrayToString BancoXMLparaRespostaCliente ObjectToJmsMessage" /> </chaining-router> </outbound> </service> <service name="Banco-B"> <inbound> <inbound-endpoint ref="Banco-B-edp" /> </inbound> <outbound> <chaining-router> <outbound-endpoint ref="WSDLCxfBancoBEdp" transformer-refs="RequisicaoServicoParaRequisicaoXML"/> <outbound-endpoint ref="RespostasServicos" transformer-refs="BancoXMLparaRespostaCliente ObjectToJmsMessage" /> </chaining-router> </outbound> </service>

Figura 71 Arquivo de configurao Mule (continua)

<service name="Banco-C"> <inbound> <inbound-endpoint ref="Banco-C-edp" /> </inbound> <component class="spb.banco.Banco" /> <outbound> <pass-through-router> <outbound-endpoint ref="RespostasServicos" /> </pass-through-router> </outbound> </service> <service name="TrataErrosRequisicao"> <inbound> <inbound-endpoint ref="TrataErrosRequisicaoEdp" /> </inbound> <component class="spb.excecoes.TrataErrosRequisicao" /> <outbound> <pass-through-router> <outbound-endpoint ref="RespostasServicos" /> </pass-through-router> </outbound> </service> <service name="GeradorRelatorio"> <inbound> <inbound-endpoint ref="GeradorRelatorioEdp" /> </inbound> <component> <singleton-object class="spb.GeradorRelatorio"/> </component> <outbound> <pass-through-router> <outbound-endpoint ref="insertDataBaseEdp"/> </pass-through-router> </outbound> </service> <service name="EmissorAutomaticoRelatorio"> <inbound> <inbound-endpoint ref="selectDataBaseEdp"/> </inbound> <component> <singleton-object class="spb.EmissorRelatorio"/> </component>

Figura 71 Arquivo de configurao Mule (continua)

<outbound> <multicasting-router> <outbound-endpoint ref="relatorioEdp" transformer-refs="JmsMessageToObject" /> <outbound-endpoint ref="emailEdp" /> <payload-type-filter expectedType="java.lang.String"/> </multicasting-router> </outbound> </service> </model> </mule>

Figura 71 Arquivo de configurao Mule (continuao)

7.4 Organizao da Aplicao


Algumas alteraes na estrutura de diretrio do estudo de caso foram realizadas nesta fase. Duas novas pastas foram adicionadas para acomodar as aplicaes Banco-A-TCP e Banco-B-WS e uma nova pasta foi adicionada estrutura da Agncia de Emprstimo para receber o arquivo com o relatrio (pasta relatorio). A figura 72 apresenta a nova estrutura.

Figura 72 Estrutura de diretrios da aplicao.

7.5 Executando a Aplicao


No houve alterao na gerao e execuo da aplicao Agncia de Emprstimo e nem na Agncia de Crdito. Nesta fase do estudo de caso temos duas novas aplicaes externas, o Banco-A-TCP e o Banco-B-WS. Para gerar o Banco-A-TCP simplesmente vamos ao diretrio Banco-A-TCP e executamos javac *.java. Para execut-la basta o comando java BancoServer. Ser apresentada a janela apresentada na figura 73, onde sero apresentadas as mensagens contendo as requisies recebidas pelo Banco A e as resposta enviadas pelo Banco. Para gerar o Banco-B-WS vamos ao diretrio e executamos ant. O arquivo BancoBWS.war ser gerado no diretrio Banco-B-WS\build\jars. O arquivo BancoBWS.war gerado deve ser colocado no diretrio server\default\deploy do JBoss. A execuo e utilizao dos servios da Agncia de Emprstimo continuam da mesma forma que estavam na fase anterior e as mesmas pginas so apresentadas.

Figura 73 Janela da aplicao Banco-A

8 Referncias
[1] Enterprise Integration Patterns. Gregor Hohpe and Bob Woolf. Addison Wesley 2003. [2] Enterprise Service Bus. David Chapell. OReilly 2004. [3] Service Oriented Java Business Integration. Binildas C. A. PACKT Publishing 2008. [4] Open Source ESBs in Action. Tijs Rademakers and Jos Dirksen. Manning 2009. [5] Mule in Action.

David Dossot and John D Emic. Manning 2007. [6] Mule 2: A developers Guide. Peter Delia, Antonie Borg and Ricston. Apress. [7] Mule 2.2.1 Users Guide. MuleSource.Org 2008 http://www.mulesource.org/display/MULE2USER/Home [8] Mule ESB 2.2.1 API. http://www.mulesource.org/docs/site/2.2.1/apidocs

You might also like