artigo Aprendendo Padrões Java EE com uma História Interativa AprendendoPadroesJava... ·...

20
artigo Eduardo Guerra ([email protected]) é pesquisador em desenvolvimento de frameworks, participando de projetos open-source como SwingBean, Esfinge Framework, ClassMock e JColtrane. Atualmente está cursando doutorado no ITA, onde também concluiu graduação em Engenharia da Computação e mestrado. Possui as certificações SCJA, SCJP, SCWCD, SCBCD (1.3 e 5.0), SCJWSD, SCMAD e SCEA e experiência como arquiteto de software nas plataformas Java SE, Java EE e Java ME. Atua também como professor na graduação do ITA e nos cursos de pós-graduação ITA/Stefanini. Roberto Perillo ([email protected]) é bacharel em Ciência da Computação e está atualmente concluindo o curso de especialização em Engenharia de Software do ITA. Trabalha com Java há quase 5 anos, possui as certificações SCJP, SCWCD e SCJD, e participa ativamente dos fóruns do JavaRanch. Já trabalhou com JEE em grandes empresas, como Avaya e IBM, onde nesta última foi co-fundador do time de inovação de ibm.com GWPS Brasil. Uma história de padrões é uma narrativa que apresenta um problema fictício e como padrões foram aplicados de forma sequencial para sua solução. Uma história interativa de padrões é uma narrativa na qual o leitor vai tomando as decisões de design e conhecendo as consequências de suas ações. Este artigo traz uma história interativa de padrões para camada de negócios em aplicações Java EE. Será que você consegue tomar as decisões corretas? Aprenda sobre padrões Java EE através das consequências de suas próprias escolhas em uma história de padrões interativa, na qual o final é você quem decide. E ste ano tive o prazer de participar de uma das mais importan- tes conferências sobre padrões do mundo, o PLoP 09 (16th Conference on Pattern Languages of Programs). O evento contou com grandes nomes na área de padrões e modelagem de software como Ralph Johnson, Rebecca Wirfs-Brock, Joseph Yoder, Brian Foote, Lin- da Rising, entre outros. Neste ambiente, me deparei com um artigo sobre padrões bem diferente do tipo de artigo que estava acostumado a ver. Até então eu já conhecia as histórias de padrões (pattern stories) que apresentam uma narrativa que mostra um caso fictício e como os padrões são aplicados de forma incremental. Essas histórias são interessantes, pois ensinam sobre a aplicabilidade dos padrões e as consequências positivas e negativas de sua aplicação. O artigo “An Interactive Pattern Story about Remote Object Invocation” publicado este ano (pode ser baixado do site da Aprendendo Padrões Java EE com uma História Interativa 18 18 www.mundoj.com.br

Transcript of artigo Aprendendo Padrões Java EE com uma História Interativa AprendendoPadroesJava... ·...

a r t i g o

Eduardo Guerra

([email protected]) é pesquisador em

desenvolvimento de frameworks, participando de

projetos open-source como SwingBean, Esfinge

Framework, ClassMock e JColtrane. Atualmente

está cursando doutorado no ITA, onde também

já concluiu graduação em Engenharia da

Computação e mestrado. Possui as certificações

SCJA, SCJP, SCWCD, SCBCD (1.3 e 5.0), SCJWSD,

SCMAD e SCEA e experiência como arquiteto de

software nas plataformas Java SE, Java EE e Java ME.

Atua também como professor na graduação do ITA

e nos cursos de pós-graduação ITA/Stefanini.

Roberto Perillo

([email protected]) é bacharel em Ciência

da Computação e está atualmente concluindo o

curso de especialização em Engenharia de Software

do ITA. Trabalha com Java há quase 5 anos, possui

as certificações SCJP, SCWCD e SCJD, e participa

ativamente dos fóruns do JavaRanch. Já trabalhou

com JEE em grandes empresas, como Avaya e

IBM, onde nesta última foi co-fundador do time de

inovação de ibm.com GWPS Brasil.

Uma história de padrões é uma narrativa

que apresenta um problema fictício e como

padrões foram aplicados de forma sequencial

para sua solução. Uma história interativa de

padrões é uma narrativa na qual o leitor vai

tomando as decisões de design e conhecendo

as consequências de suas ações. Este artigo traz

uma história interativa de padrões para camada

de negócios em aplicações Java EE. Será que você

consegue tomar as decisões corretas?

Aprenda sobre padrões Java

EE através das consequências

de suas próprias escolhas

em uma história de padrões

interativa, na qual o final é

você quem decide.

E ste ano tive o prazer de participar de uma das mais importan-tes conferências sobre padrões do mundo, o PLoP 09 (16th Conference on Pattern Languages of Programs). O evento

contou com grandes nomes na área de padrões e modelagem de software como Ralph Johnson, Rebecca Wirfs-Brock, Joseph Yoder, Brian Foote, Lin-da Rising, entre outros. Neste ambiente, me deparei com um artigo sobre padrões bem diferente do tipo de artigo que estava acostumado a ver.

Até então eu já conhecia as histórias de padrões (pattern stories) que apresentam uma narrativa que mostra um caso fictício e como os padrões são aplicados de forma incremental. Essas histórias são interessantes, pois ensinam sobre a aplicabilidade dos padrões e as consequências positivas e negativas de sua aplicação. O artigo “An Interactive Pattern Story about Remote Object Invocation” publicado este ano (pode ser baixado do site da

Aprendendo Padrões Java EE com

uma História Interativa

1818 www.mundoj.com.br

1919

conferência) trouxe um conceito inovador no qual o leitor pode interagir com a história tomando decisões de design e encarando as consequências de suas escolhas.

Seguindo o mesmo conceito da série de livros “Escolha sua Aventura”, as histórias interativas de padrões fornecem ao leitor escolhas de design que influenciam o final da história. Diferentemente das histórias normais que documentam apenas escolhas corretas, as histórias interativas permitem que os leitores explorem as soluções não-ótimas e identifiquem as conse-quências negativas da aplicação de um padrão em um contexto em que sua utilização não é apropriada.

Este artigo apresenta uma história interativa que foca em padrões de pro-jeto para a camada de negócios de aplicações Java EE. A próxima seção explica como será a dinâmica da leitura do artigo e em seguida o leitor já pode iniciar a leitura da história e tomar suas próprias decisões. No final do artigo, existem quadros explicativos que focam em algumas das escolhas e tecnologias relacionadas com o andamento da história, porém que podem ser lidos de forma independente.

Como ler o artigoEra uma vez...

A história deste artigo não segue um formato linear, mas possui um

formato de grafo, no qual existem pontos de decisão que podem levar a

diferentes finais. Ao ler cada seção, o leitor deve decidir para que ponto

da história ele deve seguir e então pular para seção numerada de acordo

com a decisão tomada. Existe um final “feliz” no qual o leitor tomou todas

as decisões corretas, porém também existe o final desastroso em que

todas as decisões tiveram consequências ruins. Alguns finais também

retratam situações intermediárias nas quais diferentes decisões tiveram

consequências boas e ruins em diferentes pontos.

O objetivo é que o leitor interprete os requisitos que estão sendo

apresentados e procure tomar a melhor decisão para a modelagem da

Seu nome é Edward De Sign e você acabou de ser contratado para o cargo

de arquiteto Java EE da empresa AvajOdnum. Essa empresa multinacional

indiana possui uma grande aplicação que roda na internet e provê serviços

para diversas empresas que pagam pela sua utilização. Não foram dados

muitos detalhes no momento de sua contratação, mas parece que sua

primeira tarefa será o projeto de um módulo para a inserção de notifica-

ções de chamadas em métodos já existentes na aplicação. A vaga foi bem

disputada, então você, de alguma forma, sente o peso da responsabilidade

para a geração de um resultado positivo o mais rápido possível.

Pronto para o primeiro dia de trabalho? Então vá para (1).

arquitetura da aplicação. Cada decisão terá consequências em termos de requisitos não-funcionais. Incentiva-se que o leitor, depois da primeira leitura, explore os diferentes caminhos que a história proporciona, para entender qual seria o resultado caso outras decisões fossem realizadas.

Em cada ponto da história será apresentada uma figura que irá mostrar como a arquitetura se encontra naquele momento. Essa figura serve como base para que o leitor possa ter uma visão de como se encontra o projeto que está sendo realizado.

No final do artigo, existem alguns quadros explicativos para os quais o leitor será direcionado em alguns pontos de sua leitura. Esses quadros possuem informações comuns a diversos ramos da história e que podem ser lidos independentemente do seu andamento. Nesses quadros estão detalhes a respeito das tecnologias utilizadas e dos padrões emprega-dos. Caso o leitor já conheça o padrão ou a tecnologia que estiver sendo abordada no quadro, ele pode pular essa leitura sem prejuízo ao anda-mento da história.

Ciente das regras? A história começa na próxima seção...

Você chega na empresa no seu primeiro dia e é recebido com muito entusiasmo e expectativa por seus novos colegas. Na parte da manhã, você é apresentado à sua equipe de trabalho e se acomoda na sala onde irá trabalhar, realizando tarefas de um recém-chegado como criação de credenciais de segurança e configuração de ambiente. Na parte da tarde, você é cha-mado a uma reunião na qual será explicada a arquitetura do sistema com o qual irá trabalhar e qual será sua primeira tarefa.

Quando já estava esperando que a arquitetura do sistema com o qual irá trabalhar fosse “arcaica” e amarrada a antigos padrões de mercado, você se depara com uma boa surpresa: o sistema está implementado utilizando EJB 3 e JPA. O sistema possui um módulo web implementado em JSF e um módulo desktop im-plementado em Swing que utilizam as interfaces remotas dos EJBs de sessão para o acesso as funcionalidades do sistema. No servidor de aplicações, existe uma camada de EJBs destinada a realizar o acesso a base de dados utilizando JPA, funcionando como uma camada de DAOs. Acima dessa camada, existem EJBs que executam regras de negócio das funcionalidades e acessam a camada de EJBs de acesso a dados quando neces-

sário. As camadas de EJBs para acesso a dados disponibilizam apenas interfaces locais, enquanto a outra camada apenas interfaces remotas.

Devido ao fato da aplicação ser disponibilizada para outras empresas,

diversas necessidades específicas surgem em cada um dos clientes,

muitas vezes relacionadas com a integração com sistemas existentes.

Esse tipo de requisição motivou a gerência a dar importância para a

implementação de um mecanismo na arquitetura que permitisse que

funcionalidades fossem invocadas antes ou depois da chamada de

funcionalidades na camada de negócios, ou seja, nos EJBs remotos da

aplicação.

Não é necessário que essas chamadas influam na execução da funciona-

lidade. A princípio elas apenas devem notificar a execução da funciona-

Aplicação Swing

Aplicação JSF

chamada remota

Session Beans

(negócio)

Session Beans (DAO)

2020 www.mundoj.com.br

lidade. Exemplos de uso desse novo recurso citados na reunião foram:

gravação de trilha de auditoria em bancos de dados ou em arquivos,

acionamento de gatilhos de processos em servidores de workflow, cha-

madas a sistemas externos e envios de e-mail de notificação.

O projeto de como isso será implementado na aplicação será seu pri-

meiro desafio nesse cargo de arquiteto. O projeto se dividirá em três

fases, nas quais haverá a implementação e em seguida a implantação

no servidor em produção. Segue o que será abordado em cada fase:

– Integração do mecanismo de notificação nas funcionali-

dades existente;

– Definição da forma de tratamento das notificações;

– Flexibilização do mecanismo para inserção de novas no-

tificações.

A primeira questão que deverá ser tratada é como a notificação deverá

ser integrada na aplicação já existente de forma a gerar o menor im-

pacto possível no que já está implementado. Neste cenário, surgem

algumas alternativas a serem seguidas:

deseja se reunir com a equipe para explorar melhor os requisitos não-funcionais, vá para (4);

utilizando a injeção de dependência do EJB container para injetar um Session Bean que deve ser chamado dentro dos métodos para que a notificação seja feita, vá para (2);

para executarem em torno da execução dos métodos do EJBs, vá para (7).

2 Você decide que o mecanismo de notificação será imple-mentado em um Session Bean, chamado de Notificador, o qual deve ser injetado pelo container dentro dos EJBs já existentes na aplicação (para mais informações, ler quadro “O Padrão Injeção de Dependência”). Dentro dos métodos dos EJBs, deve ser feita uma chamada a métodos do Noti-ficador passando as informações do contexto da chamada do método, como o seu nome, o EJB ao qual pertence, os parâmetros recebidos e o usuário que o executou.

Para a implantação desse primeiro passo foi escolhida uma fun-

cionalidade simples, porém importante, para ser implantada: o

registro de auditoria em arquivo (ou seja, a gravação do log da

execução das funcionalidades do sistema). Ela servirá para tes-

tar se o mecanismo de notificação está corretamente inserido

na aplicação para que outras questões possam ser tratadas.

O Session Bean Notificador foi implementado facilmente para

realizar as tarefas de auditoria. Para que o mesmo possa ser

utilizado por outros beans, bastou utilizar a injeção de depen-

dência do container. Um atributo do tipo da interface do No-

tificador com a anotação @EJB foi inserido nos session beans

que precisavam utilizar a auditoria. A chamada ao Notificador

precisou ser inserida em cada um dos métodos de cada um dos EJBs. Esta

estratégia se mostrou flexível devido a facilidade de adicionar a chamada

em qualquer ponto da execução do método. Um ponto negativo foi que,

apesar da lógica de processamento estar no bean Notificador, ele ainda

precisa ser invocado dentro de cada método, o que gerou um maior aco-

plamento e um enorme trabalho braçal por parte dos desenvolvedores.

Foi um pouco mais de uma semana de trabalho intenso de toda equipe

para inserir o mecanismo em toda a aplicação. Mesmo com tanto esforço,

alguns métodos acabaram sendo esquecidos e outros implementados

de forma errada. Depois da implementação estar pronta, ainda foi mais

uma semana com diversos testes cobrindo toda a aplicação, nos quais

diversas pequenas falhas foram detectadas. Mesmo depois dos testes,

você ainda se sente um pouco inseguro se está tudo realmente correto.

A equipe ficou insatisfeita em precisar executar um trabalho braçal em

toda a aplicação. A gerência esperava que a implantação desse mecanis-

mo inicial fosse mais rápida e ficou decepcionada com o número de erros

que foram encontrados na fase de testes. Talvez a solução escolhida não

tenha sido a ideal, porém depois de tanto trabalho não dava mais para

voltar atrás. Você sente que suas decisões em relação a outras questões

do mecanismo de notificação serão críticas para seu futuro na empresa.

O bean notificador agora está implementando diretamente a funcionali-

dade de auditoria, mas a intenção é que ele seja apenas um gerenciador

que recebe essas chamadas e redireciona para quem deve fazer o trata-

mento. Outro aspecto que deve ser considerado é a transacionalidade,

pois a notificação só deve ser feita caso a funcionalidade seja executada

com sucesso. Neste momento, existem duas opções a respeito de como

as notificações serão redirecionadas:

-síncrona para um Message-Driven Bean tratar, vá para (5);

para funcionalidade de notificação e delegar a execução da lógica para classes auxiliares, vá para (8).

Aplicação Swing

Aplicação JSF

chamada remota

Session Beans

(negócio)

Session Beans (DAO)

Session Beans

(Notificador)

como

-r, vá para (5);

e delegar a execução da lógica (8).

2121

3

4

A decisão tomada acaba dando um peso maior para sua preocupação com desempenho e você decide realizar uma chamada assíncrona para tratar a notificação, o que é um padrão conhecido como Service Activator (ver quadro “Padrão Service Activator”). Dessa forma, o interceptor irá enviar uma mensagem para um servidor de mensagens, que será recebida por um Message-driven Bean, o qual será responsável pelo processamento da notificação.

Antes de tomar uma decisão a respeito de como deve ser a implemen-tação, você decide reunir a equipe e realizar um brainstorm a respeito de quais os requisitos não-funcionais mais importantes. Além de obter informações importantes sobre os requisitos, você também ganhou o respeito da equipe por tê-la incluído no processo de modelagem da arquitetura.

No final da reunião foram sumarizados os seguintes requisitos não-funcionais:

a aplicação executa atualmente no limite máximo do desempenho que é permitido pelos requisitos e alguns clien-tes chegam a reclamar de lentidão em horários de pico. Não é de-sejável que o mecanismo de notificação cause uma degradação perceptível no desempenho das funcionalidades já existentes.

o sistema atual é muito grande e uma imple-mentação que criasse a necessidade de alteração em diversas classes do sistema seria muito cara e trabalhosa. O mecanismo de notificação deve ser o mais desacoplado possível das classes já existentes no sistema.

diversos clientes que utilizam o sistema já comen-

taram a respeito da necessidade do envio de notificações para sistemas proprietários. Quando o mecanismo estiver pronto, será necessário a implementação de diferentes tipos de notificações para os diferentes clientes. Sendo assim, o processo de criação de tipos de notificação deve ser simples, flexível e configurável.

uma notificação só pode ser efetuada caso a funcionalidade seja executada sem que tenha sido dado um roll-back na transação.

Depois da conversa com a equipe, você se sente mais confiante e com mais informações para tomar decisões a respeito da arquitetura do sistema. Qual será sua decisão a respeito de como o mecanismo de notificação deve ser integrado ao sistema?

utilizando a injeção de dependência do EJB container para injetar um Session Bean que deve ser chamado dentro dos métodos para que a notificação seja feita, vá para (2).

para executarem em torno da execução dos métodos do EJBs, vá para (7).

Como forma de testar esse novo passo do desenvolvimento

será implantada a primeira integração com o sistema de um

dos maiores clientes da AvajOdnum. O cliente disponibilizou

um web service em um dos seus sistemas para ser invocado na

chamada de algumas funcionalidades. Não se sabe exatamente

qual funcionalidade será executada pela aplicação dele. A

princípio serão utilizadas condicionais simples para definir quais

chamadas deverão invocar o serviço do cliente, porém isso deve

ser mudado na última fase da implantação do mecanismo de

notificações.

A funcionalidade de auditoria foi transferida para um Message-

driven Bean que trata mensagens recebidas de uma fila do

servidor de mensagens. O envio da mensagem é feito pelo

interceptor Notificador que antes implementava a funcionali-

dade diretamente. A chamada ao web service do cliente é feita,

a princípio, diretamente do Message-driven Bean e o filtro por

funcionalidade é feito utilizando condicionais no próprio código.

A criação da funcionalidade foi rapidamente feita por você mesmo e nos testes realizados não houve degradação do desempenho da aplicação. Em alguns períodos do dia o serviço do cliente acaba ficando um pouco lento e demorando a responder, porém como isso é tratado assincrona-mente, esse fato não interfere no tempo de execução percebido pelos usuários. O envio da mensagem é incluído na transação distribuída do container e só é efetivado caso não seja dado rollback na mesma. Isso é especialmente útil para notificações realizadas antes da execução da funcionalidade, quando no momento da notificação ainda não se sabe se haverá algum problema que poderá anular a transação.

Havia certo receio na equipe e na gerência que as chamadas a funcionalidades de outras aplicações fossem degradar o desempenho, porém com a solução da chamada assíncrona você mostrou que é possível fazer isso mantendo o tem-po de resposta da aplicação. Você ganha o respeito de todos, que depositam em você a confiança para concluir a funcionalidade de notificação.

A próxima decisão a ser tomada irá influenciar a facilidade de adição de novas ações a serem acionadas pela notificação. No momento, estão implementadas as funcionalidades de auditoria e a chamada a aplicação de um dos clientes, porém você sabe que várias outras ações serão inseridas no futuro. Atualmente condicionais no próprio código verificam as condições de execução de cada tipo de notificação, porém você deve criar um mecanismo que facilite a adição desse tipo de funcionalidade. É preciso levar em consideração que mais de uma ação pode ser realizada a partir de uma notificação e que pode haver lógicas comuns em funcionalidades de notificação diferentes. Qual será a estratégia que você irá escolher para fazer isso?

no método onMessage() que chama métodos abstratos para serem im-plementados por várias subclasses usando o padrão Template Method, vá para (13).

objetos encadeados para o tratamento das mensagens usando o padrão Chain of Responsibility, vá para (17).

Aplicação Swing

Aplicação JSF

chamada remota

Servidor de Mensagens

Processador de Notificações

(Message-driven Bean)

Not

ifica

dor

(inte

rcep

tor)

Session Beans

(negócio)

Session Beans (DAO)

2222 www.mundoj.com.br

5

6

A decisão tomada acaba dando um peso maior para sua preocupação com desempenho e você decide realizar uma chamada assíncrona para tratar a notificação, o que é um pa-drão conhecido como Service Activator (ver quadro “Padrão Service Activator”). Dessa forma, o Session Bean Notificador irá enviar uma mensagem para um servidor de mensagens, que será recebida por um Message-driven Bean, o qual será responsável pelo processamento da notificação.

Quando você entra na sala do gerente, ele está trabalhando em

seu computador. Ele a princípio parece ignorar sua presença, mas

em seguida volta-se para você encarando-o com uma expressão

bem séria. Para sua felicidade, ele alivia a pressão do momento

com um sorriso e pede para você se sentar. Após fazer algumas

perguntas sem muita importância para quebrar o gelo, ele diz que

o motivo de ter te chamado era para falar do seu desempenho até

o momento e falar sobre o seu futuro na empresa:

ficou dentro de nossas expectativas iniciais. Apesar de você

ter tomado decisões inteligentes e que realmente ajudaram

na implementação do mecanismo de notificação de um de

nossos sistemas, você mesmo sabe que essas decisões não

foram sempre corretas que houveram algumas consequên-

cias negativas.

Você balança a cabeça admitindo que nem todas suas decisões

foram as melhores e ele continua:

outra empresa e precisaremos integrar os nossos sistemas

com os sistemas deles. Para isso, estamos criando a posição

de arquiteto corporativo em nossa empresa. Queremos que

você continue atuando como arquiteto nessa aplicação e que

interaja com o novo arquiteto corporativo nessa integração.

Como forma de testar esse novo passo do desenvolvimento

será implantada a primeira integração com o sistema de um

dos maiores clientes da AvajOdnum. O cliente disponibilizou

um web service em um dos seus sistemas para ser invocado

na chamada de algumas funcionalidades. Não se sabe exa-

tamente qual funcionalidade será executada pela aplicação

dele. A princípio serão utilizadas condicionais simples para

definir quais chamadas deverão invocar o serviço do cliente,

porém isso deve ser mudado na última fase da implantação

do mecanismo de notificações.

A funcionalidade de auditoria foi transferida para um Mes-

sage-driven Bean que trata mensagens recebidas de uma

fila do servidor de mensagens. O envio da mensagem é feito

pelo Session Bean Notificador que antes implementava a

funcionalidade diretamente. A chamada ao web service do

cliente é feita, a princípio, diretamente do Message-driven

Bean e o filtro por funcionalidade é feito utilizando condicionais no

próprio código.

A criação da funcionalidade foi rapidamente feita por você mesmo e nos

testes realizados não houve degradação do desempenho da aplicação.

Em alguns períodos do dia o serviço do cliente acaba ficando um pouco

lento e demorando a responder, porém como isso é tratado assincrona-

mente, esse fato não interfere no tempo de execução percebido pelos

usuários. O envio da mensagem é incluído na transação distribuída do

container e só é efetivado caso não seja dado rollback na mesma. Isso

é especialmente útil para notificações realizadas antes da execução da

funcionalidade, quando no momento da notificação ainda não se sabe

se haverá algum problema que poderá anular a transação.

Havia certo receio na equipe e na gerência que a chamada a funciona-

lidade de outras aplicações fosse degradar o desempenho, porém com

a solução da chamada assíncrona você mostrou que é possível fazer

isso mantendo o tempo de resposta da aplicação. Com essa solução,

você recupera o respeito da equipe e da gerência que havia em parte

sido perdido depois da implantação da primeira parte do mecanismo de

notificação. Você sente que seu sucesso na próxima decisão será crítico

para seu futuro na empresa.

A próxima decisão a ser tomada irá influenciar a facilidade de adição de

novas ações a serem acionadas pela notificação. No momento, estão

implementadas as funcionalidades de auditoria e a chamada a aplicação

de um dos clientes, porém você sabe que várias outras ações serão in-

seridas no futuro. Atualmente condicionais no próprio código verificam

as condições de execução de cada tipo de notificação, porém você deve

criar um mecanismo que facilite a adição desse tipo de funcionalidade. É

preciso levar em consideração que mais de uma ação pode ser realizada

a partir de uma notificação e que pode haver lógicas comuns em funcio-

nalidades de notificação diferentes. Qual será a estratégia que você irá

escolher para fazer isso?

-ritmo no método onMessage() que chama métodos abstratos para serem implementados por várias subclasses usando o padrão Tem-plate Method, vá para 16.

outros objetos encadeados para o tratamento das mensagens usando o padrão Chain of Responsibility, vá para 11.

Aplicação Swing

Aplicação JSF

chamada remota

Servidor de Mensagens

Processador de Notificações

(Message-driven Bean)

Session Beans

(Notificador)

Session Beans

(negócio)

Session Beans (DAO)

2323

fim

7 Você decide criar um interceptor, que é uma classe que pode interceptar chamadas de um EJB, para a criação do mecanismo de notificação (para mais informações, ler quadro “EJB3 Interceptors”). Essa classe deve ser definida no descritor XML da aplicação como um interceptor de-fault para todos os Session Beans.

É muito importante que você sempre discuta com ele as mudanças que você fizer na arquitetura, pois ele terá uma visão mais global de nossas aplicações.

Após a conversa, você volta para sua mesa em parte feliz, porque apesar

do erro que você cometeu, ainda irá manter sua posição como arquiteto.

Por outro lado, você percebe que se não fosse a decisão errada que to-

mou, poderia ser você a assumir o cargo de arquiteto corporativo. Você

segue em frente, esperando que o desafio da integração dos sistemas

e a troca de experiências com o novo arquiteto corporativo possam te

ensinar bastante a respeito da modelagem da arquitetura de sistemas.

Para a implantação desse primeiro passo foi escolhida

uma funcionalidade simples, porém importante, para ser

implantada: o registro de auditoria em arquivo (ou seja, a

gravação do log da execução das funcionalidades do siste-

ma). Ela servirá para testar se o mecanismo de notificação

está corretamente inserido na aplicação para que outras

questões possam ser tratadas.

O interceptor, chamado de Notificador, foi implementado

facilmente para realizar as tarefas de auditoria e através das

configurações ele passou a ser chamado antes e depois da

invocação de todos os métodos. Uma das vantagens dessa

abordagem foi o baixo acoplamento desse novo mecanis-

mo com os Session Beans já existentes na aplicação, que

não precisaram ser alterados. Um problema encontrado foi

a falta de flexibilidade, pois devido a mesma classe inter-

ceptar todos os métodos fica difícil de saber, por exemplo,

se a notificação deve ser feita antes ou depois da execução

do método.

Para a resolução desse problema, seguindo a filosofia da ar-

quitetura do EJB 3, foram criadas anotações @NotifyBefore,

@NotifyAfter e @NoNotification que permitiam configurar

quando uma notificação seria enviada. Para evitar configu-

rações em todos os métodos, a notificação depois da exe-

cução, que era o caso mais comum foi considerado o caso

default. As anotações também poderiam ser utilizadas na

classe, servindo, nesse caso, como uma configuração para

todos os métodos, a não ser que existisse uma anotação

Se você se interessou sobre como um componente consome e pro-cessa os metadados que lê, isso já é outra história! Você pode ver a história resumida no artigo “Padrões de Projeto para Flexibilizar o Uso de Anotações” da edição 34 da revista Mundoj, ou a história completa no artigo “A Pattern Language for Metadata-based Fra-meworks” publicado no PLoP deste ano.

Não se pode dizer que foi rápido para inserir as configurações em toda a aplicação, porém o que deu mais trabalho foi percorrer todas as classes de serviço analisando se a notificação era necessária e em que momento ela deveria ser realizada. Em dois dias de dedicação da equipe de de-senvolvimento, o sistema de notificação já estava implantado em toda a aplicação e em mais dois dias os testes revelaram que a implementação havia sido um sucesso.

Todos da equipe ficaram surpresos e satisfeitos com a solução, pois nenhum deles havia pensado na solução de usar uma combinação dos interceptors com as anotações. O código da notificação ficou bem desacoplado das classes da aplicação e a manutenção do mecanismo e inserção da notificação em novos Session Beans serão tarefas bem tranquilas. A gerência ficou satisfeita com o resultado da sua primeira semana de trabalho, pois eles não esperavam que a inserção desse novo componente na arquitetura já existente fosse ser tão rápida. Você fica feliz com seu primeiro acerto, porém sabe que o mecanismo não está completo e ainda existem várias decisões pela frente.

O interceptor Notificador agora está implementando diretamente a funcionalidade de auditoria, mas a intenção é que ele seja apenas um gerenciador que recebe essas chamadas e redireciona para quem deve fazer o tratamento. Outro aspecto que deve ser considerado é a transa-cionalidade, pois a notificação só deve ser feita caso a funcionalidade seja executada com sucesso. Neste momento, existem duas opções a respeito de como as notificações serão redirecionadas:

-síncrona para um Message-Driven Bean tratar, vá para (3).

Session Bean que serve como fachada para funcionalidade de noti-ficação, vá para (10).

específica nele. Esse tipo de estratégica no uso de anotações é utilizada no EJB 3 para gerenciamento de transações, segurança entre outros.

Aplicação Swing

Aplicação JSF

chamada remota

Not

ifica

dor

(inte

rcep

tor)

Session Beans

(negócio)

Session Beans (DAO)

2424 www.mundoj.com.br

8

9

A decisão tomada acaba dando um peso maior para sua preo-cupação com a divisão de responsabilidades entre as classes e você decide tornar o Session Bean Notificador em um serviço de notificação conforme o padrão Application Service (ver quadro “Padrão Application Service”). Essa classe coordena e encapsula a invocação de serviços e classes de negócio que implementam a funcionalidade de cada notificação.

Quando você entra na sala do gerente, ele está trabalhando em seu

computador. Ele a princípio parece ignorar sua presença, mas em

seguida volta-se para você encarando-o com uma expressão bem

séria. Ele pede para você se sentar e sem fazer muitos rodeios diz

que o motivo de ter te chamado era para falar do seu desempenho

até o momento e falar sobre o seu futuro na empresa:

aqui na AvajOdnum achamos que o seu desempenho ficou muito abaixo de nossas expectativas. Todas as suas decisões para a implementação do mecanismo de notificação tive-ram consequências negativas para o nosso negócio. Muito trabalho braçal e demora no desenvolvimento, degradação

no desempenho, duplicação de código, problemas com ma-

nutenção. Infelizmente não consigo enxergar nenhum moti-

vo para manter você em nossa equipe. Gostaria de pedir que

você passasse no RH para acertar a sua situação.

Você fica bastante chateado por ter sido demitido, mas por outro

lado reconhece que nenhuma de suas decisões foi boa para a apli-

cação. Talvez você ainda não esteja preparado para assumir uma

função de arquiteto e ainda precise estudar bastante para chegar a

esse ponto. O mercado está cheio de oportunidades e resta a você

agora começar novamente em outra empresa procurando apren-

der com os erros que cometeu.

Como forma de testar esse novo passo do desenvolvimento

será implantada a primeira integração com o sistema de um dos

maiores clientes da AvajOdnum. O cliente disponibilizou um web

service em um dos seus sistemas para ser invocado na chamada

de algumas funcionalidades. Não se sabe exatamente qual fun-

cionalidade será executada pela aplicação dele. A princípio serão

utilizadas condicionais simples para definir quais chamadas de-

verão invocar o serviço do cliente, porém isso deve ser mudado

na última fase da implantação do mecanismo de notificações.

A funcionalidade de auditoria foi transferida para uma classe

auxiliar responsável por receber as informações do método

invocado e adicionar as informações em um arquivo. Uma classe

equivalente foi criada para encapsular a chamada do web service

do cliente. O Session Bean Notificador com o serviço de notifi-

cação seleciona a classe auxiliar que será chamada utilizando

condicionais no próprio código.

A criação da funcionalidade foi rapidamente feita por você

mesmo e em alguns testes realizados houve, como já era esperado, um pequeno aumento no tempo de resposta da aplicação considerado aceitável. Depois que a modificação foi para o servidor de produção, em alguns períodos do dia o serviço do cliente acaba ficando um pouco lento e demorando a responder, o que impactou diretamente no desempenho da aplicação percebido pelos usuários.

Outro ponto problemático na solução foi o gerenciamento de transações. Em casos que a notificação acontecia antes da execução da funcionalidade e o serviço era invocado, não havia como avisar o sistema do cliente do erro caso houvesse um rollback na transação, pois ele não é transacional. Houve um dia em que um processo foi disparado na aplicação do cliente a partir da chamada no web service e houve um rollback da transação depois. Nem precisa dizer que foi a maior confusão para consertar o problema.

Essa implementação concretizou um dos maiores receios da gerência que a inserção das notificações traria problemas para o desempenho da aplicação. Diversas reclamações dos clientes, tanto por causa da demora na execução das funcionalidades quanto pelo problema com a transação, aju-daram a aumentar a pressão na empresa. Esse já é a sua segunda decisão que traz consequências negativas para a aplicação e você começa a sentir que “sua batata está assando”. Com isso, você sabe que seu próximo passo será decisivo para sua carreira na empresa.

A próxima decisão a ser tomada irá influenciar a facilidade de adição de novas ações a serem acionadas pela notificação. No momento, estão implementadas as funcionalidades de auditoria e a chamada a aplicação de um dos clientes, porém você sabe que várias outras ações serão inseridas no futuro. Atualmente condicionais no próprio código verificam as condições de execução de cada tipo de notificação, porém você deve criar um mecanismo que facilite a adição desse tipo de funcionalidade. É preciso levar em consideração que mais de uma ação pode ser realizada a partir de uma notificação e que pode haver lógicas comuns em funcionalidades de notificação diferentes. Qual será a estratégia que você irá escolher para fazer isso?

que chama métodos abstratos para serem implementados por várias subclasses usando o padrão Template Method, vá para 14.

pelo tratamento das mensagens usando o padrão Chain of Responsibili-ty, vá para 20.

fim

Aplicação Swing

Aplicação JSF

chamada remota

Session Bean (Serviço de Notificação)

Classe Auxiliar

Classe Auxiliar

Session Beans

(negócio)

Session Beans (DAO)

2525

10A decisão tomada acaba dando um peso maior para sua preocupação com a divisão de responsabilidades entre as classes e você decide fazer o interceptor No-tificador invocar um EJB, que será utilizado como um serviço de notificação conforme o padrão Application Service (ver quadro “Padrão Application Service”). Essa classe coordena e encapsula a invocação de serviços e classes de negócio que implementam a funcionalidade de cada notificação.

Como forma de testar esse novo passo do desen-volvimento será implantada a primeira integração com o sistema de um dos maiores clientes da AvajOdnum. O cliente disponibilizou um web service em um dos seus sistemas para ser invo-cado na chamada de algumas funcionalidades. Não se sabe exatamente qual funcionalidade será executada pela aplicação dele. A princípio serão utilizadas condicionais simples para definir quais chamadas deverão invocar o serviço do cliente, porém isso deve ser mudado na última fase da implantação do mecanismo de notificações.

O interceptor recebe agora injeção de dependên-cia (ver quadro “Padrão Injeção de Dependência”) do EJB com o serviço de notificação e delega todas as chamadas para ele. A funcionalidade de auditoria foi transferida para uma classe auxiliar responsável por receber as informações do mé-todo invocado e adicionar as informações em um arquivo. Uma classe equivalente foi criada para encapsular a chamada do web service do cliente. O Session Bean com o serviço de notificação sele-ciona a classe auxiliar que será chamada utilizan-do condicionais no próprio código.

A criação da funcionalidade foi rapidamente feita por você mesmo

e em alguns testes realizados houve, como já era esperado, um

pequeno aumento no tempo de resposta da aplicação considerado

aceitável. Depois que a modificação foi para o servidor de produção,

em alguns períodos do dia o serviço do cliente acaba ficando um

pouco lento e demorando a responder, o que impactou diretamente

no desempenho da aplicação percebido pelos usuários.

Outro ponto problemático na solução foi o gerenciamento de tran-

sações. Em um caso que a notificação acontecia antes da execução

da funcionalidade e o serviço era invocado, não havia como avisar o

sistema do cliente do erro caso houvesse um rollback na transação,

pois ele não é transacional. Houve um dia em que um processo foi

disparado na aplicação do cliente a partir da chamada no web servi-

ce e houve um rollback da transação depois. Nem precisa dizer que

foi a maior confusão para consertar o problema.

Essa implementação concretizou um dos maiores receios da ge-

rência que a inserção das notificações traria problemas para o

desempenho da aplicação. Diversas reclamações dos clientes, tanto

por causa da demora na execução das funcionalidades quanto pelo

problema com a transação, ajudaram a aumentar a pressão na em-

presa. Apesar de você ter acertado na sua primeira decisão, essa

segunda causou certo desconforto no ambiente de trabalho. Você

percebe nesse momento que seu próximo passo pode ser decisivo

para sua carreira na empresa.

A próxima decisão a ser tomada irá influenciar a facilidade de adição de

novas ações a serem acionadas pela notificação. No momento, estão

implementadas as funcionalidades de auditoria e a chamada a aplicação

de um dos clientes, porém você sabe que várias outras ações serão in-

seridas no futuro. Atualmente condicionais no próprio código verificam

as condições de execução de cada tipo de notificação, porém você deve

criar um mecanismo que facilite a adição desse tipo de funcionalidade. É

preciso levar em consideração que mais de uma ação pode ser realizada

a partir de uma notificação e que pode haver lógicas comuns em funcio-

nalidades de notificação diferentes. Qual será a estratégia que você irá

escolher para fazer isso?

notificações que chama métodos abstratos para serem imple-

mentados por várias subclasses usando o padrão Template

Method, vá para 19.

-

ponsáveis pelo tratamento das mensagens usando o padrão

Chain of Responsibility, vá para 15.

Aplicação Swing

Aplicação JSF

chamada remota

Serviço de Notificação

(Session Bean)

Not

ifica

dor

(inte

rcep

tor)

Classe Auxiliar

Classe Auxiliar

Session Beans

(negócio)

Session Beans (DAO)

zan-

Meth

ponsávei

Chain of Res

2626 www.mundoj.com.br

11A sua decisão opta por utilizar a delegação como mecanismo para permitir a criação de novos proces-sadores de notificação. Apenas um Message-driven Bean é responsável por realizar o processamento das notificações. Com base nas informações das mensa-gens, o processador de notificações utiliza regras para definir quais processadores irão compor a cadeia de processamento. Ele é responsável por montar a cadeia de responsabilidades (ver quadro "Padrão Chain of Responsibility") que irá realizar de fato o processamen-to. Cada classe processadora é uma classe que realiza o seu processamento e em seguida delega a execução ao próximo processador da corrente.

A validação da solução agora será com a implemen-

tação das outras funcionalidades de notificação,

algumas de necessidade interna da empresa, como

a contabilização de acessos para fins de cobrança,

e outras por solicitações dos clientes, normalmente

para invocação de algum sistema deles. Existe um

grande número de solicitações e os desenvolvedo-

res irão começar a trabalhar na criação de cada uma

delas. Espera-se que a estrutura adotada consiga

fornecer flexibilidade para a inserção de diversos

processadores diferentes da forma mais simples

possível.

O primeiro passo foi refatorar a funcionalidade já

existente adaptando-a para a nova estrutura. A fun-

cionalidade de auditoria foi isolada em uma classe processadora as-sim como a invocação do web service do cliente. O Message-driven Bean também foi modificado para montar as cadeias de processa-mento com as classes processadoras. Por exemplo, o processamen-to de notificação de algumas funcionalidades era composto pelo registro de auditoria e a chamada do web service.

Quando os desenvolvedores começaram a desenvolver as outras funcionalidades, percebeu-se que entre diversos tipos de notifica-ção havia grande parte da lógica em comum. Exemplos envolviam a obtenção de credenciais para o acesso aos sistemas dos clientes, criptografia de dados, validação de formato, transformação de mensagens, registro de erros ocorridos, entre outros. Com a cadeia de responsabilidades, foi possível reaproveitar componentes já existentes facilmente para compor a cadeia de processamento.

Um problema dessa abordagem foi que a montagem das cadeias começou a gerar uma grande quantidade de código condicional no Message-driven Bean. A solução encontrada foi a criação de um descritor XML com a definição das cadeias de processamento e as regras de inclusão ou não de determinadas classes processadoras. Esse XML é lido pelo Message-driven Bean em sua inicialização, que já monta todas as cadeias de processamento. A inclusão do XML além de desacoplar as classes processadoras do Message-driven bean, tornou simples adicionar ou remover um passo do processa-mento, aumentando a flexibilidade do mecanismo implantado.

Como resultado final foram criadas diversas classes processadoras, algumas específicas de alguns clientes e outras mais gerais, que eram utilizadas para compor as cadeias de execução. Isso evitou a repetição de código dentre diferentes processamentos de noti-ficação e permitiu um rápido desenvolvimento de muitas funcio-nalidades. O XML criado para a definição das cadeias ajudou no seu gerenciamento, tornando simples a manutenção e adição de funcionalidades.

Apesar de ter cometido um engano na sua primeira decisão, você conseguiu recuperar a confiança dos desenvolvedores e da gerência com suas escolhas seguintes. Os desenvolvedores ficam satisfeitos em não precisarem realizar tarefas braçais e repetitivas para imple-mentação dos processadores de notificação como foi na primeira parte do projeto. A gerência parece estar satisfeita com o resultado e ter esquecido um pouco a decepção inicial, visto que consegue facilmente agregar novos mecanismos de notificação, satisfazendo os clientes (e podendo cobrar mais deles) de forma ágil.

Um dia, o gerente de TI da AvajOdnum te chama na sala dele para uma conversa... Vá para (6).

Aplicação Swing

Aplicação JSF

chamada remota

Cadeia de Processamento

Cria e invoca

Classe Processadora

Classe Processadora ...

Session Bean

(Notificador)

Session Beans

(negócio)

Session Beans (DAO)

Servidor de Mensagens

Processador de Notificações

(Message-driven Bean)

segue sfazendo

gil.

ama na sala dele para

2727

12

13

Quando você entra na sala do gerente, ele é todo sorriso e pede

rapidamente para você se sentar. Ele te trata como se fossem gran-

des amigos! Após fazer algumas perguntas sem muita importância

para quebrar o gelo, ele diz que o motivo de ter te chamado era

para falar do seu desempenho até o momento e falar sobre o seu

futuro na empresa:

ficou muito acima de nossas expectativas iniciais. Todas suas decisões na arquitetura foram acertadas e a funcionalidade ficou pronta muito antes do que nós esperávamos. Os de-senvolvedores todos comentam pelos cantos da empresa a respeito de como você é inteligente e saca muito de Java e de arquitetura.

Você balança a cabeça com ucerto orgulho, mas tentando de-

monstrar um pouco de humildade, e ele continua:

-

quirimos outra empresa e precisaremos integrar os nossos

sistemas com os sistemas deles. Para isso, estamos crian-

do a posição de arquiteto corporativo em nossa empresa

a qual queremos que você assuma. Outros arquitetos irão

ser responsáveis pelas aplicações individualmente, mas será

você quem terá uma visão geral das aplicações da empre-

sa e todas as decisões importantes devem passar por você.

Obviamente haverá uma compensação financeira por esse

aumento de responsabilidade.

A conversa segue por aproximadamente uma hora e ele comenta

mais detalhes sobre a expansão da empresa, indicações de pessoas

para assumirem as posições de arquiteto e o quanto o seu salário

irá aumentar. Você sai da conversa satisfeito e motivado para con-

tinuar o trabalho na área de arquitetura, porém reconhece que é

importante nunca parar de aprender!

A sua decisão opta por utilizar a herança como mecanis-mo para permitir a criação de novos processadores de notificação. Para a solução, criou-se uma classe abstrata que possui no método onMessage() um algoritmo ge-nérico para processamento das mensagens, que chama métodos abstratos que devem ser implementados pelas subclasses conforme o padrão Template Method (ver o quadro “Padrão Template Method”). Para o container, cada subclasse que implementa o processador abstrato é considerado um Message-driven Bean diferente e precisa ser considerado individualmente. O interceptor Notificador irá setar nas mensagens algumas proprieda-des, como a funcionalidade e o cliente responsável por aquela invocação, que irão permitir que cada Message-driven Bean filtre apenas as mensagens que são do seu interesse.

fim

A validação da solução agora será com a implementação

das outras funcionalidades de notificação, algumas de

necessidade interna da empresa, como a contabilização

de acessos para fins de cobrança, e outras por solicitações dos clientes,

normalmente para invocação de algum sistema deles. Existe um grande

número de solicitações e os desenvolvedores irão começar a trabalhar na

criação de cada uma delas. Espera-se que a estrutura adotada consiga

fornecer flexibilidade para a inserção de diversos processadores diferen-

tes da forma mais simples possível.

O primeiro passo foi refatorar a funcionalidade já existente adaptando-

a para a nova estrutura. O interceptor foi modificado para configurar

propriedades nas mensagens para permitir que cada Message-driven

Bean possa filtrar apenas as que deve tratar. O processador abstrato im-

plementou o método onMessage() com algum processamento comum e

chamando alguns métodos abstratos. A parte de auditoria foi colocada

em um bean sem filtro e a chamada ao web service do cliente em um

bean que filtrava somente as mensagens relativas àquele cliente. Para

essas duas funcionalidades, a solução funcionou bem.

Quando os desenvolvedores começaram a desenvolver as outras fun-

cionalidades, percebeu-se que entre diversos tipos de notificação havia

grande parte da lógica em comum. Exemplos envolviam a obtenção

de credenciais para o acesso aos sistemas dos clientes, criptografia de

dados, validação de formato, transformação de mensagens, registro de

erros ocorridos, entre outros. A princípio tentou-se repetir a estratégia

do padrão Template Method, criando superclasses que implementavam

essas funcionalidades e chamavam métodos abstratos que seriam imple-

mentados nas subclasses. Foi criado, por exemplo, uma classe abstrata

que incorporava o registro de erros e outra que incorporava a busca das

credenciais de acesso. Houve um momento em que um desenvolvedor

disse que o processador de notificação que estava criando precisava das

duas funcionalidades e perguntou qual das duas superclasses ele deveria

estender. Neste momento, você se lembrou de uma frase que leu no livro

Implementation Patterns de Kent Beck: a herança é uma carta que você

só pode jogar uma vez.

Aplicação Swing

Aplicação JSF

chamada remota

Servidor de Mensagens

Processadores Concretos (Message-driven Bean)

Processador Abstrato

implementarem métodos abstratos

Not

ifica

dor

(inte

rcep

tor)

Session Beans

(negócio)

Session Beans (DAO)

2828 www.mundoj.com.br

O resultado final foi que a profundidade de herança dos processadores

ficou muito grande, com a presença de bastante código duplicado e

hierarquias de classe paralelas. Existiam também muitos Message-driven

Beans consumindo mensagens na mesma fila. Apesar disso ainda não ter

se tornado um problema, um arquiteto de outro projeto afirmou que isso

não é bom para escalabilidade, visto que fica difícil ajustar a quantidade

de beans que irá processar notificações em paralelo no container. Com

essa estrutura, por exemplo, é difícil saber quais os notificadores que

tratam uma determinada mensagem.

Devido ao seu resultado inicial promissor, existia uma grande expectativa

que você conseguiria finalizar a solução provento uma forma simples e

fácil de adicionar novos processadores. Devido ao grande número de

classes, da duplicação de código e da profundidade da hierarquia, o

código dos processadores é difícil de ser criado, mantido e gerenciado. A

gerência se decepciona, pois isso gera uma dificuldade adicional na inte-

gração com os sistemas dos clientes, o que é um ponto muito importante

no plano estratégico da empresa para conquistar novos clientes e manter

os clientes antigos.

Um dia, o gerente de TI da AvajOdnum te chama na sala dele para uma

conversa... Vá para (6).

14A sua decisão opta por utilizar a herança como meca-nismo para permitir a criação de novos processadores de notificação. Para a solução, criou-se uma classe abstrata que possui um método para o processamento das notificações com um algoritmo genérico, que cha-ma métodos abstratos que devem ser implementados pelas subclasses conforme o padrão Template Method (ver o quadro “Padrão Template Method”). O serviço de notificação é o responsável por identificar qual a subclasse que deverá processar cada notificação rece-bida e utiliza as informações do usuário e da invocação (session bean, método, parâmetros) para fazer isso.

A validação da solução agora será com a implementa-

ção das outras funcionalidades de notificação, algumas

de necessidade interna da empresa, como a contabi-

lização de acessos para fins de cobrança, e outras por

solicitações dos clientes, normalmente para invocação

de algum sistema deles. Existe um grande número de

solicitações e os desenvolvedores irão começar a tra-

balhar na criação de cada uma delas. Espera-se que a

estrutura adotada consiga fornecer flexibilidade para a

inserção de diversos processadores diferentes da forma

mais simples possível.

O primeiro passo foi refatorar a funcionalidade já exis-

tente adaptando-a para a nova estrutura. O processador

abstrato implementou o método processarNotificacao() com algum pro-cessamento comum e chamando alguns métodos abstratos. A parte de auditoria foi colocada em uma subclasse do processador abstrato. Como todas as funcionalidades que precisavam da chamada do web service também precisavam do registro de auditoria, esse processador estendeu a classe que fazia auditoria. Para essas duas funcionalidades, a solução funcionou bem.

Quando os desenvolvedores começaram a desenvolver as outras fun-cionalidades, percebeu-se que entre diversos tipos de notificação havia grande parte da lógica em comum. Exemplos envolviam a obtenção de credenciais para o acesso aos sistemas dos clientes, criptografia de dados, validação de formato, transformação de mensagens, registro de erros ocorridos, entre outros. A princípio tentou-se repetir a estratégia do pa-drão Template Method, criando superclasses que implementavam essas funcionalidades e chamavam métodos abstratos que seriam implemen-tados nas subclasses. Foram criadas, por exemplo, uma classe abstrata que incorporava o registro de erros e outra que incorporava a busca das credenciais de acesso. Houve um momento em que um desenvolvedor disse que o processador de notificação que estava criando precisava das duas funcionalidades e perguntou qual das duas superclasses ele deveria estender. Neste momento, você se lembrou de uma frase que leu no livro Implementation Patterns de Kent Beck: a herança é uma carta que você só pode jogar uma vez.

Devido a lógica de identificação da classe de processamento no session bean ter ficado muito complicada, foi criado um arquivo XML para o ma-peamento das chamadas para o processador. A profundidade de herança dos processadores ficou muito grande, com a presença de muito código duplicado e hierarquias de classe paralelas. Existiam tantas particularida-des que era raro uma classe de processamento ser utilizada para mais de um tipo de notificação.

Suas escolhas foram um desastre desde o começo. Muito trabalho braçal, degradação do desempenho, dificuldade de manutenção. Todos esses indesejáveis fatores fizeram com que os desenvolvedores ficassem muito desmotivados em trabalhar nesse projeto. A gerência fica descontente ao notar que existe uma dificuldade generalizada na integração do mecanis-mo com os sistemas dos clientes.

Um dia, o gerente de TI da AvajOdnum te chama na sala dele para uma conversa... Vá para (9).

Aplicação Swing

Aplicação JSF

chamada remota

Session Bean (Serviço de Notificação)

implementarem métodos abstratos

Session Beans

(negócio)

Session Beans (DAO)

Processador Abstrato

Processador Concreto (POJO)

2929

15A sua decisão opta por utilizar a delegação como mecanismo para permitir a criação de novos proces-sadores de notificação. Com base nas informações das mensagens, o serviço de notificação utiliza regras para definir quais processadores irão compor a cadeia de processamento. Ele é responsável por montar a cadeia de responsabilidades (ver quadro "Padrão Chain of Responsibility") que irá realizar de fato o processamen-to. Cada classe processadora é uma classe que realiza o seu processamento e em seguida delega a execução ao próximo processador da corrente.

A validação da solução agora será com a implemen-tação das outras funcionalidades de notificação, algumas de necessidade interna da empresa, como a contabilização de acessos para fins de cobrança, e ou-tras por solicitações dos clientes, normalmente para invocação de algum sistema deles. Existe um grande número de solicitações e os desenvolvedores irão começar a trabalhar na criação de cada uma delas. Espera-se que a estrutura adotada consiga fornecer flexibilidade para a inserção de diversos processado-res diferentes da forma mais simples possível.

O primeiro passo foi refatorar a funcionalidade já existente adaptando-a para a nova estrutura. A fun-cionalidade de auditoria foi isolada em uma classe processadora assim como a invocação do web service do cliente. O Session Bean com o serviço de notifica-ção também foi modificado para montar as cadeias de processamento com as classes processadoras. Por

exemplo, o processamento de notificação de algumas funcionalidades

era composto pelo registro de auditoria e a chamada do web service.

Quando os desenvolvedores começaram a desenvolver as outras fun-

cionalidades, percebeu-se que entre diversos tipos de notificação havia

grande parte da lógica em comum. Exemplos envolviam a obtenção

de credenciais para o acesso aos sistemas dos clientes, criptografia de

dados, validação de formato, transformação de mensagens, registro de

erros ocorridos, entre outros. Com a cadeia de responsabilidades, foi

possível reaproveitar componentes já existentes facilmente para compor

a cadeia de processamento.

Um problema dessa abordagem foi que a montagem das cadeias come-

çou a gerar uma grande quantidade de código condicional no Session

Bean. A solução encontrada foi a criação de um descritor XML com a de-

finição das cadeias de processamento e as regras de inclusão ou não de

determinadas classes processadoras. Esse XML é lido pelo Session Bean

com o serviço de notificação em sua inicialização, que já monta todas

as cadeias de processamento. A inclusão do XML além de desacoplar as

classes processadoras do serviço de notificação, tornou simples adicionar

ou remover um passo do processamento, aumentando a flexibilidade do

mecanismo implantado.

Como resultado final, foram criadas diversas classes processadoras,

algumas específicas de alguns clientes e outras mais gerais, que eram

utilizadas para compor as cadeias de execução. Isso evitou a repetição de

código dentre diferentes processamentos de notificação e permitiu um

rápido desenvolvimento de muitas funcionalidades. O XML criado para a

definição das cadeias ajudou no seu gerenciamento, tornando simples a

manutenção e adição de funcionalidades.

Apesar do sistema de notificação ter degradado o desempenho da

aplicação, você conseguiu fazer com que ele pudesse ser facilmente

acoplado no sistema existente e que novos processadores pudessem ser

facilmente introduzidos. Os desenvolvedores ficam satisfeitos em não

precisarem realizar tarefas braçais e repetitivas em nenhuma fase do

projeto, tendo consciência que estavam trabalhando em cima de uma

boa estrutura. A gerência parece estar satisfeita com o resultado e ter

esquecido um pouco da demora nas requisições, visto que consegue

facilmente agregar novos mecanismos de notificação, satisfazendo os

clientes (e podendo cobrar mais deles) de forma ágil. Quem sabe com

essa boa estrutura você não consegue refatorar alguma coisa para resol-

ver esse problema do desempenho.

Um dia, o gerente de TI da AvajOdnum te chama na sala dele para uma

conversa... Vá para (6).

Aplicação Swing

Aplicação JSF

chamada remota

Cadeia de Processamento

Cria e invoca

Serviço de Notificação

(Session Bean)

Classe Processadora

Classe Processadora ...

Not

ifica

dor

(inte

rcep

tor)

Session Beans

(negócio)

Session Beans (DAO)

3030 www.mundoj.com.br

16

17

A sua decisão opta por utilizar a herança como meca-nismo para permitir a criação de novos processadores de notificação. Para a solução, criou-se uma classe abs-trata que possui no método onMessage() um algorit-mo genérico para processamento das mensagens, que chama métodos abstratos que devem ser implementa-dos pelas subclasses conforme o padrão Template Me-thod (ver o quadro “Padrão Template Method”). Para o container, cada subclasse que implementa o processa-dor abstrato é considerado um Message-driven Bean diferente e precisa ser considerado individualmente. O interceptor Notificador irá setar nas mensagens algu-mas propriedades, como a funcionalidade e o cliente responsável por aquela invocação, que irão permitir que cada Message-driven Bean filtre apenas as mensa-gens que são do seu interesse.

A sua decisão opta por utilizar a delegação como meca-nismo para permitir a criação de novos processadores de notificação. Apenas um Message-driven Bean é responsável por realizar o processamento das notificações. Com base nas informações das mensagens, o processador de notificações utiliza regras para definir quais processadores irão compor

a cadeia de processamento. Ele é responsável por montar a cadeia de responsabilidades (ver quadro "Padrão Chain of Responsibility") que irá realizar de fato o processamento. Cada classe processadora é uma classe que realiza o seu processamento e em seguida delega a execução ao próximo processador da corrente.

A validação da solução agora será com a implementação das outras funcionalidades de notificação, algumas de necessidade interna da empresa, como a contabilização de acessos para fins de cobrança, e outras por solicita-ções dos clientes, normalmente para invocação de algum sistema deles. Existe um grande número de solicitações e os desenvolvedores irão começar a trabalhar na criação de cada uma delas. Espera-se que a estrutura adotada consiga fornecer flexibilidade para a inserção de diversos processadores diferentes da forma mais simples possível.

O primeiro passo foi refatorar a funcionalidade já exis-tente adaptando-a para a nova estrutura. O interceptor foi modificado para configurar propriedades nas mensa-gens para permitir que cada Message-driven Bean possa filtrar apenas as que deve tratar. O processador abstrato

implementou o método onMessage() com algum processamento comum

e chamando alguns métodos abstratos. A parte de auditoria foi colocada

em um bean sem filtro e a chamada ao web service do cliente em um bean

que filtrava somente as mensagens relativas àquele cliente. Para essas

duas funcionalidades, a solução funcionou bem.

Quando os desenvolvedores começaram a desenvolver as outras funciona-

lidades, percebeu-se que entre diversos tipos de notificação havia grande

parte da lógica em comum. Exemplos envolviam a obtenção de credenciais

para o acesso aos sistemas dos clientes, criptografia de dados, validação de

formato, transformação de mensagens, registro de erros ocorridos, entre

outros. A princípio, tentou-se repetir a estratégia do padrão Template Me-

thod, criando superclasses que implementavam essas funcionalidades e

chamavam métodos abstratos que seriam implementados nas subclasses.

Foi criado, por exemplo, uma classe abstrata que incorporava o registro de

erros e outra que incorporava a busca das credenciais de acesso. Houve um

momento em que um desenvolvedor disse que o processador de notifica-

ção que estava criando precisava das duas funcionalidades e perguntou

qual das duas superclasses ele deveria estender. Neste momento, você se

lembrou de uma frase que leu no livro Implementation Patterns de Kent

Beck: a herança é uma carta que você só pode jogar uma vez.

O resultado final foi que a profundidade de herança dos processadores

ficou muito grande, com a presença de bastante código duplicado e

hierarquias de classe paralelas. Existiam também muitos Message-driven

Beans consumindo mensagens na mesma fila. Apesar disso ainda não ter

se tornado um problema, um arquiteto de outro projeto afirmou que isso

não é bom para escalabilidade, visto que fica difícil ajustar a quantidade de

beans que irá processar notificações em paralelo no container. Com essa

estrutura, por exemplo, é difícil de saber quais os notificadores que tratam

uma determinada mensagem.

Você havia se recuperado de seu primeiro erro com a utilização das

chamadas assíncronas para não permitir a degradação do desempenho

com as notificações, porém essa última decisão foi uma decepção para

todos. Devido ao grande número de classes, da duplicação de código e

da profundidade da hierarquia, o código dos processadores é difícil de ser

criado, mantido e gerenciado. A gerência nota que existe uma dificuldade

adicional na integração com os sistemas dos clientes, o que é um ponto

muito importante no plano estratégico da empresa para conquistar novos

clientes e manter os clientes antigos.

Um dia, o gerente de TI da AvajOdnum te chama na sala dele para uma

conversa... Vá para (18).

Aplicação Swing

Aplicação JSF

chamada remota

Session Bean (Notificador)

Session Beans

(negócio)

Session Beans (DAO)

Servidor de Mensagens

Processador Abstrato

implementam métodos abstratos

Processadores Concretos

(Message-driven Bean)

3131

A validação da solução agora será com a implementação das outras fun-

cionalidades de notificação, algumas de necessidade interna da empresa,

como a contabilização de acessos para fins de cobrança, e outras por

solicitações dos clientes, normalmente para invocação de algum sistema

deles. Existe um grande número de solicitações e os desenvolvedores irão

começar a trabalhar na criação de cada uma delas. Espera-se que a es-

trutura adotada consiga fornecer flexibilidade para a inserção de diversos

processadores diferentes da forma mais simples possível.

O primeiro passo foi refatorar a funcionalidade já existente adaptando-a

para a nova estrutura. A funcionalidade de auditoria foi isolada em uma

classe processadora assim como a invocação do web service do cliente.

O Message-driven Bean também foi modificado para montar as cadeias

de processamento com as classes processadoras. Por exemplo, o proces-

samento de notificação de algumas funcionalidades era composto pelo

registro de auditoria e a chamada do web service.

Quando os desenvolvedores começaram a desenvolver as outras fun-

cionalidades, percebeu-se que entre diversos tipos de notificação havia

grande parte da lógica em comum. Exemplos envolviam a obtenção

de credenciais para o acesso aos sistemas dos clientes, criptografia de

dados, validação de formato, transformação de mensagens, registro de

erros ocorridos, entre outros. Com a cadeia de responsabilidades foi

possível reaproveitar componentes já existentes facilmente para compor

a cadeia de processamento.

Um problema dessa abordagem foi que a montagem das cadeias come-

çou a gerar uma grande quantidade de código condicional no Message-

driven Bean. A solução encontrada foi a criação de um descritor XML

com a definição das cadeias de processamento e as regras de inclusão

ou não de determinadas classes processadoras. Esse XML é lido pelo

Message-driven Bean em sua inicialização, que já monta todas as cadeias

de processamento. A inclusão do XML além de desacoplar as classes

processadoras do Message-driven bean, tornou simples adicionar ou

remover um passo do processamento, aumentando a flexibilidade do

mecanismo implantado.

Como resultado final, foram criadas diversas classes processadoras,

algumas específicas de alguns clientes e outras mais gerais, que eram

utilizadas para compor as cadeias de execução. Isso evitou a repetição de

código dentre diferentes processamentos de notificação e permitiu um

rápido desenvolvimento de muitas funcionalidades. O XML criado para a

definição das cadeias ajudou no seu gerenciamento, tornando simples a

manutenção e adição de funcionalidades.

Ao olhar para o resultado final do mecanismo de notificação você se

orgulha de suas decisões e fica com uma sensação de dever cumprido.

Os desenvolvedores ficam satisfeitos por estarem trabalhando em pro-

jeto em que podem se focar no desenvolvimento de funcionalidades

que agregam valor ao projeto sem precisarem realizar tarefas braçais e

repetitivas. A gerência parece estar satisfeita com o resultado, visto que

consegue facilmente agregar novos mecanismos de notificação, satisfa-

zendo os clientes (e podendo cobrar mais deles) de forma ágil.

Um dia, o gerente de TI da AvajOdnum te chama na sala dele para uma

conversa... Vá para (12).

18Quando você entra na sala do gerente, ele está trabalhando em

seu computador. Ele a princípio parece ignorar sua presença,

mas em seguida volta-se para você encarando-o com uma

expressão bem séria. Ele pede para você se sentar e sem fazer

muitos rodeios diz que o motivo de ter te chamado era para falar

do seu desempenho até o momento e falar sobre o seu futuro

na empresa:

-nho ficou abaixo de nossas expectativas iniciais. Apesar de você ter acertado em algumas escolhas para a im-plementação do mecanismo de notificação de um de nossos sistemas, você mesmo sabe que a maioria delas poderiam ser melhores. Várias de suas decisões tornaram complexa a edição de novas funcionalidades no sistema.

Você balança a cabeça admitindo que errou em vários pontos

e ele continua:

-

mentação você demonstrou conhecimento em diversas

tecnologias e que é eficiente na criação de código. Apesar

de acharmos que você ainda não tem experiência para se

tornar um arquiteto, se você se interessar gostaríamos

que continuasse fazendo parte da equipe como desen-

volvedor. É claro que vai ganhar um pouco menos, porém

acredito que terá várias oportunidades para aprender.

Você fica um pouco chateado por não ter dado conta de cum-

prir de forma satisfatória com a função de arquiteto que havia

lhe sido dada. Por outro lado, você sente certo alívio por ainda

ter um emprego. Em situações como esta é que é preciso ter

humildade, reconhecer suas limitações e estudar bastante para

chegar no ponto em que se almeja. Quem sabe daqui a algum

tempo você não consegue recuperar a posição que perdeu. Você

escuta conversas de corredor que a empresa está se expandindo

e oportunidades não irão faltar.

fim

Aplicação Swing

Aplicação JSF

chamada remota

Cadeia de Processamento

Classe Processadora

Classe Processadora ...

Session Beans

(negócio)

Session Beans (DAO)

Servidor de Mensagens

Processador de Notificações

(Message-driven Bean)

cria e invoca

Not

ifica

dor

(inte

rcep

tor)

3232 www.mundoj.com.br

19

20

A sua decisão opta por utilizar a herança como meca-nismo para permitir a criação de novos processadores de notificação. Para a solução, criou-se uma classe abstrata que possui um método para o processamento das notificações com um algoritmo genérico, que cha-ma métodos abstratos que devem ser implementados pelas subclasses conforme o padrão Template Method (ver o quadro “Padrão Template Method”). O serviço de notificação é o responsável por identificar qual a subclasse que deverá processar cada notificação rece-bida e utiliza as informações do usuário e da invocação (session bean, método, parâmetros) para fazer isso.

A sua decisão opta por utilizar a delegação como meca-

nismo para permitir a criação de novos processadores de

notificação. Com base nas informações das mensagens, o

serviço de notificação utiliza regras para definir quais pro-

cessadores irão compor a cadeia de processamento. Ele é

responsável por montar a cadeia de responsabilidades (ver

quadro "Padrão Chain of Responsibility") que irá realizar

de fato o processamento. Cada classe processadora é uma

classe que realiza o seu processamento e em seguida delega

a execução ao próximo processador da corrente.

A validação da solução agora será com a implementação das outras funcionalidades de notificação, algumas de necessidade interna da empresa, como a contabilização de acessos para fins de cobrança, e outras por solici-tações dos clientes, normalmente para invocação de algum sistema deles. Existe um grande número de soli-citações e os desenvolvedores irão começar a trabalhar na criação de cada uma delas. Espera-se que a estrutura adotada consiga fornecer flexibilidade para a inserção de diversos processadores diferentes da forma mais simples possível.

O primeiro passo foi refatorar a funcionalidade já exis-tente adaptando-a para a nova estrutura. O interceptor não precisou ser modificado, pois já enviava as informa-ções necessárias para o serviço de notificação escolher a classe que irá fazer o processamento. O processador

abstrato implementou o método processarNotificacao() com algum pro-cessamento comum e chamando alguns métodos abstratos. A parte de auditoria foi colocada em uma subclasse do processador abstrato. Como todas as funcionalidades que precisavam da chamada do web service também precisavam do registro de auditoria, esse processador estendeu a classe que fazia auditoria. Para essas duas funcionalidades, a solução funcionou bem.

Quando os desenvolvedores começaram a desenvolver as outras fun-cionalidades, percebeu-se que entre diversos tipos de notificação havia grande parte da lógica em comum. Exemplos envolviam a obtenção de credenciais para o acesso aos sistemas dos clientes, criptografia de dados, validação de formato, transformação de mensagens, registro de erros ocorridos, entre outros. A princípio, tentou-se repetir a estratégia do padrão Template Method, criando superclasses que implementavam essas funcionalidades e chamavam métodos abstratos que seriam imple-mentados nas subclasses. Foi criado, por exemplo, uma classe abstrata que incorporava o registro de erros e outra que incorporava a busca das credenciais de acesso. Houve um momento em que um desenvolvedor disse que o processador de notificação que estava criando precisava das duas funcionalidades e perguntou qual das duas superclasses ele deveria estender. Neste momento, você se lembrou de uma frase que leu no livro Implementation Patterns de Kent Beck: a herança é uma carta que você só pode jogar uma vez.

Devido a lógica de identificação da classe de processamento no session bean ter ficado muito complicada, foi criado um arquivo XML para o mapeamento das chamadas para o processador. A profundidade de herança dos processadores ficou muito grande, com a presença de bastante código duplicado e hierarquias de classe paralelas. Existiam tantas particularidades que era muito raro uma classe de processamento ser utilizada para mais de um tipo de notificação.

Você havia começado bem com a escolha do uso dos interceptors, porém as duas últimas decisões foram uma decepção para todos. Devido ao grande número de classes, da duplicação de código e da profundidade da hierarquia, o código dos processadores é difícil de ser criado, mantido e gerenciado. A gerência nota que existe uma dificuldade adicional na integração com os sistemas dos clientes, o que é um ponto muito impor-tante no plano estratégico da empresa para conquistar novos clientes e manter os clientes antigos.

Um dia, o gerente de TI da AvajOdnum te chama na sala dele para uma conversa... Vá para (18).

Aplicação Swing

Aplicação JSF

chamada remota

Serviço de Notificação

(Session Bean)

Not

ifica

dor

(inte

rcep

tor)

Processador Abstrato

Session Beans (negócio)

Session Beans (DAO)

implementam métodos abstratos

Processador Concreto

(POJO)

A validação da solução agora será com a implementação das outras fun-

cionalidades de notificação, algumas de necessidade interna da empresa,

como a contabilização de acessos para fins de cobrança, e outras por

solicitações dos clientes, normalmente para invocação de algum sistema

deles. Existe um grande número de solicitações e os desenvolvedores irão

começar a trabalhar na criação de cada uma delas. Espera-se que a es-

trutura adotada consiga fornecer flexibilidade para a inserção de diversos

processadores diferentes da forma mais simples possível.

O primeiro passo foi refatorar a funcionalidade já existente adaptando-a

para a nova estrutura. A funcionalidade de auditoria foi isolada em uma

classe processadora assim como a invocação do web service do cliente.

O Session Bean com o serviço de notificação também foi modificado para

montar as cadeias de processamento com as classes processadoras. Por

exemplo, o processamento de notificação de algumas funcionalidades era

composto pelo registro de auditoria e a chamada do web service.

Quando os desenvolvedores começaram a desenvolver as outras fun-

cionalidades, percebeu-se que entre diversos tipos de notificação havia

grande parte da lógica em comum. Exemplos envolviam a obtenção

de credenciais para o acesso aos sistemas dos clientes, criptografia de dados, validação de formato, transformação de mensagens, registro de erros ocorridos, entre outros. Com a cadeia de responsabilidades foi possível reaproveitar componentes já existentes facilmente para compor a cadeia de processamento.

Um problema dessa abordagem foi que a montagem das cadeias come-çou a gerar uma grande quantidade de código condicional no Session Bean. A solução encontrada foi a criação de um descritor XML com a de-finição das cadeias de processamento e as regras de inclusão ou não de determinadas classes processadoras. Esse XML é lido pelo Session Bean com o serviço de notificação em sua inicialização, que já monta todas as cadeias de processamento. A inclusão do XML além de desacoplar as classes processadoras do serviço de notificação, tornou simples adicionar ou remover um passo do processamento, aumentando a flexibilidade do mecanismo implantado.

Como resultado final foram criadas diversas classes processadoras, algumas específicas de alguns clientes e outras mais gerais, que eram utilizadas para compor as cadeias de execução. Isso evitou a repetição de código dentre diferentes processamentos de notificação e permitiu um rápido desenvolvimento de muitas funcionalidades. O XML criado para a definição das cadeias ajudou no seu gerenciamento, tornando simples a manutenção e adição de funcionalidades.

Os problemas provenientes das suas duas primeiras decisões fizeram que sua credibilidade como arquiteto ficasse em baixa, porém essa última escolha levantou sua moral com a equipe e com a gerência. Os desen-volvedores ficam satisfeitos em não precisarem realizar tarefas braçais e repetitivas na inserção dos processadores. A gerência parece estar satis-feita com o resultado dessa fase, visto que consegue facilmente agregar novos mecanismos de notificação, satisfazendo os clientes (e podendo cobrar mais deles) de forma ágil.

Um dia, o gerente de TI da AvajOdnum te chama na sala dele para uma conversa... Vá para (18).

Este padrão foi proposto por Martin Fowler e refere-se ao processo de uma classe permitir que suas dependências possam ser defini-das, ou “injetadas”, externamente ao mesmo. Esse padrão também é conhecido como inversão de controle (IoC), já que o controle do processo de obter a dependência e compor o objeto dependente é deslocado a outro componente (como um container leve, por exemplo).

Um objeto precisa frequentemente da colaboração de outro objeto para realizar uma determinada tarefa. Em tese, o objeto que precisa da dependência precisaria somente de uma referência ao outro objeto, mas normalmente, ele acaba precisando também controlar seu ciclo de vida. A injeção de dependência transfere o processo de criar a dependência (com suas possíveis dependências) e injetá-la

em outro objeto, para que este possa contar com sua colaboração sem precisar controlar como esta é instanciada e inicializada.

Na prática, não é necessário utilizar especificamente um framework para aplicar a injeção de dependência. Somente o fato do processo de composição de um objeto e de suas dependências ser transferido para outro componente, já diminui o acoplamento entre o depen-dente e a dependência. A flexibilidade que é ganha com esse padrão vem do fato que uma classe pode depender de uma interface e qual-quer classe que a implementa pode ser injetada como dependência. Como a criação da instância não está amarrada internamente na classe, é possível facilmente alterar a dependência.

São três os elementos que compõem este padrão: um dependente,

O padrão injeção de dependência

33

Aplicação Swing

Aplicação JSF

chamada remota

Cadeia de Processamento

Classe Processadora

Classe Processadora ...

Session Beans (negócio)

Session Beans (DAO)

cria e invoca

Session Bean (Serviço de Notificação)

as dependências e o injetor. O dependente é o objeto que precisa da colaboração de outro objeto (a dependência) para realizar sua tarefa. O injetor é responsável por fornecer a dependência e compor o objeto dependente, para que este seja capaz de realizar sua tarefa. O injetor também é responsável pelo ciclo de vida tanto da depen-dência quanto do objeto dependente.

Existem três formas de injeção de dependência: por construtor, por setter e por interface. Seguem as descrições:

o objeto dependente possui um construtor que espera o tipo (preferencialmente uma interface) da dependên-cia. O injetor então instancia a dependência e instancia tam-bém o dependente, passando a dependência através do cons-trutor. O injetor pode ser implementado de várias formas, por exemplo, utilizando os padrões Abstract Factory ou Factory Method (padrões GoF). A vantagem de se ter um construtor que espera o tipo da dependência é que o objeto dependente, ao ser construído, está pronto para ser utilizado. Além disso, pelo construtor, pode-se perceber que é impossível utilizar o objeto dependente sem sua dependência.

a dependência chega para o dependente através de um método set que espera o tipo da dependência, sem a ne-cessidade de um construtor. Depois do objeto dependente já criado, o injetor instancia a dependência e a injeta no depen-dente através de um método set.

cria-se uma interface, e nela, define-se um método

que receberá a dependência. As classes que implementam a

interface possuem a implementação concreta do método que

recebe a dependência. A tarefa do injetor pode ser executada

tanto por um framework, que suporte injeção de dependência,

quanto por qualquer outro código que seja responsável pelo

arranjo destes objetos.

A especificação do EJB 3 suporta o padrão de injeção de dependên-

cia. Neste caso, o injetor é o próprio EJB container que é responsável

por, além de controlar o ciclo de vida dos EJBs, setar as dependências

relacionadas, como, por exemplo, fábricas de conexão com bancos

de dados, instâncias do EntityManager (para utilização de JPA) e até

mesmo referências a outros EJBs.

São utilizadas anotações nos atributos dos EJBs para que os mesmos

possam receber a injeção de dependência do container. O sistema

é similar ao uso de métodos setters, porém o injetor acessa dire-

tamente os atributos da classe. Exemplos dessas anotações são @

Resource, @EJB, @WebServiceRef e @PersistentContext.

Alguns frameworks, como o Spring e o Google Guice, oferecem

diversas outras opções para a utilização da injeção de dependência.

O padrão Decorator (GoF) permite que se acrescente funcionalidades de uma forma plugável em uma classe. Neste padrão, é criada uma classe que “decora” a classe original (chamada de decorator), acrescentando a execução de uma funcionalidade e em seguida delegando a execução à classe original. O decorator deve implementar a mesma interface da classe original, para que esse processo seja transparente para seus clientes. Para aplicação desse padrão, deve-se possuir controle sobre o processo de criação da classe decorada, para que o decorator possa ser acrescentado e retornado.

O processo de criação dos EJBs é controlado pelo container e, até a versão 2.1 da especificação, não era possível plugar novas funcionalidades a esse tipo de componente. Com o EJB 3, tornou-se possível criar classes chamadas de Inter-ceptors que podem interceptar a execução de uma método, possibilitando a adição de funcionalidades antes e depois de sua execução.

Os interceptadores do EJB 3 são objetos que são automaticamente chamados quando um método EJB é invocado e tem acesso a todos os seus dados, como parâmetros, retorno, exceções lançadas etc. Os interceptadores podem ser aplicados tanto aos Session Beans quanto aos Message-driven Beans. Eles po-dem ser aplicados em três níveis: default (para todos os beans de um módulo EJB), classe (para todos os métodos de um bean) e método (para somente um método específico). Ao definir interceptadores nos três níveis, os default são invocados primeiro, seguidos pelos de nível de classe e de método.

Um método interceptador pode ser definido tanto no próprio bean quanto

em uma classe separada, porém normalmente é mais recomendado mantê-lo separado dos métodos de negócio por questões de coesão. Para a definição de um interceptador, deve-se definir um (somente um) método com a anotação @AroundInvoke, que será chamado antes do método a ser interceptado. O método de interceptação recebe como parâmetro uma instância da interface InvocationContext e deve chamar o seu método proceed() quando desejar que o fluxo de execução siga para o próximo interceptor ou para classe de negócios se ele for o último.

Para indicar que um método deve ser interceptado, deve-se anotá-lo com @Interceptors, indicando a classe (ou as classes) que contém o método anotado com a anotação @AroundInvoke. Os interceptadores também podem ser definidos no descritor de distribuição, sendo que essa é a única opção para os interceptadores default. Pode-se indicar mais de um interceptador para uma classe ou método, e estes serão executados na ordem em que aparecerem na anotação ou no descritor de distribuição.

É possível também, por exemplo, indicar que um método não deve ser inter-ceptado pelos interceptadores default. Neste caso, anota-se o método com a anotação @ExcludeDefaultInterceptors. Da mesma forma, é possível indicar também que um método não deve ser interceptado pelos interceptadores de nível de classe, anotando-o com @ExcludeClassInterceptors. Em ambos os ca-sos, é possível indicar estas configurações através do descritor de distribuição.

EJB 3 Interceptors

3434 www.mundoj.com.br

Este padrão (que faz parte dos Core J2EE Patterns) propõe como solução

chamar serviços de modo assíncrono. Em aplicações empresariais, é mui-

to comum ter uma grande parte do processamento sendo feita de modo

síncrono. Em alguns casos, o processamento pode ser grande, inclusive

sendo realizado por várias aplicações que talvez nem estejam no mesmo

ambiente. Dessa forma, o processamento pode consumir tempo e recur-

sos consideráveis do servidor. Para esse tipo de processamento, pode-se

utilizar um Service Activator, que é um serviço que recebe solicitações de

forma assíncrona e ativa um ou mais serviços de negócios para realizar o

processamento.

Um Service Activator é implementado normalmente como um Message-

driven Bean que consome via JMS as mensagens recebidas de um servi-

dor. Ao receber uma solicitação, o Service Activator analisa a requisição

e chama os componentes de negócios apropriados para processar a

solicitação. Após concluir o processamento, o Service Activator pode ou

não enviar uma resposta para o cliente, que pode informar se o processa-

mento foi bem-sucedido e fornecer os resultados.

Seguem algumas razões para um serviço ser implementado de forma

assíncrona:

-

gado é quando a chamada a um serviço é na verdade o aciona-

mento de um evento que não necessita que uma resposta seja

enviada ao cliente;

longos, é ruim deixar o cliente aguardando, pois faz parecer que o sistema está lento. Nesses casos, envia-se uma resposta imediata anunciando que a requisição foi recebida com sucesso e está sendo processada. Enquanto isso, envia-se uma mensagem JMS para uma fila para que o processamento seja feito de forma assíncrona;

-mente de aplicações que não se tem controle, o uso do processamen-to assíncrono evita que o desempenho seja degradado devido a uma demora no acesso a esse outro serviço;

grande de requisições de uma só vez e o processamento de todas em paralelo pode consumir os recursos da máquina de forma a com-prometer o desempenho como um todo. O uso de processamento assíncrono nesse caso coloca em uma fila essas requisições, que são processadas por um número fixo de threads. Isso limita a quantidade de recursos que aquele tipo de processamento pode consumir.

O padrão Service Activator também possui a vantagem de desacoplar

quem envia mensagem de quem a recebe. Isso possibilita que, por exem-

plo, a mensagem seja consumida independentemente por dois Message-

driven Beans diferentes, o que torna simples a inserção ou a exclusão de

cada um deles.

Este padrão (que também faz parte dos Core J2EE Patterns) propõe

centralizar a lógica de negócios através dos componentes e serviços

de várias camadas de negócios. É comum encontrar aplicações em-

presariais que possuem alguns componentes comuns, como business

objects e façades de serviço (tanto Session Facades quanto POJO

Facades) que são essencialmente uma camada fina sem lógica de ne-

gócios. Os facades expõem uma interface que controla o acesso dos

clientes aos objetos de negócio, e os business objects colaboram en-

tre si para executar a lógica de negócios que deve ser implementada

pela aplicação. Os business objects representam a implementação de

um modelo de domínio conceitual e concentram a lógica de negócios.

Em algumas situações, casos de uso podem requerer alguma lógica

extra para que executem corretamente suas tarefas. Preferencialmen-

te, os facades de serviço não devem conter lógica de negócios, e os

business objects, idealmente, não devem conter lógica de negócios

específica de um caso de uso, contendo somente a lógica específica

do modelo de domínio. Dessa forma, há mais reuso, e o acoplamento

entre os business objects diminui. Assim, pode-se introduzir uma camada que concentra lógica específica e coordena as ações dos business objects para que esta lógica específica seja executada corre-tamente. A estes serviços dá-se o nome de Application Services, que são serviços que contêm lógica de negócios específica e podem até utilizar DAOs para lidar com dados persistentes.

Uma das estratégias de implementação deste padrão chama-se Application Service Command. Nesta estratégia, um Application Con-troller utiliza um Command que delega o tratamento da requisição a um Application Service. Em uma variante desta estratégia, o próprio Application Service pode implementar um Command e tratar direta-mente uma requisição.

A outra estratégia de implementação deste padrão chama-se Appli-cation Service Layer, que propõe categorizar os Application Services com base em suas funções e capacidade de reutilização. Por exemplo, a primeira camada de serviços contém processamento de negócios específico de tipo de cliente (Channel Service). A próxima camada de

Padrão Service Activator

Padrão Application Service

35

Este é um padrão comportamental GoF, e descreve como construir

uma cadeia de objetos para o tratamento de solicitações, em que

esses objetos possuem lógica específica para o tratamento de cada

tipo de solicitação. Os objetos da cadeia durante o tratamento da

solicitação, podem retornar ou repassá-la para o próximo objeto na

cadeia, até que a mesma chegue ao final. O padrão possui meca-

nismos que permitem facilmente adicionar novos objetos na cadeia

para compor o processamento.

O objetivo deste padrão é evitar o acoplamento do remetente com

a lógica de tratamento e aumentar a flexibilidade permitindo que

um objeto possa ser facilmente inserido ou removido da cadeia. No

padrão original, a solicitação é tratada por somente um objeto, mas

existem documentados vários casos em que os objetos da cadeia

participam como um conjunto do processamento.

O uso desse padrão é indicado para casos em que o processamento

de uma requisição deve ser composto por diversos passos. A es-

trutura do Chain of Responsibility permite que os passos possam

ser utilizados de forma independente e flexível na composição de

diversas cadeias.

Os filtros da API Java Servlet são um exemplo deste padrão. O Mé-

todo doFilter() da classe javax.servlet.FilterChain, cuja instância é

recebida pelo filtro, é o método que liga os objetos na cadeia. Esse

método deve ser chamado para que a solicitação possa seguir para

o próximo elemento da cadeia. Cada filtro pode executar seu pro-

cessamento antes e/ou depois da chamada deste método.

Padrão Chain of Responsibility

Essencialmente, o objetivo deste padrão é definir a estrutura de um algoritmo em uma superclasse, delegando a definição de parte desta estrutura a suas subclasses. Este padrão se aplica quando dois ou mais componentes possuem alguma operação similar, mas não demonstram reuso de uma interface comum. Se uma mudança for necessária na parte comum do algoritmo, todos os componentes sofrerão alteração.

A parte do algoritmo que não varia é definida em um método concreto (o template method, ou método modelo) em uma classe abstrata. A parte que varia é definida em métodos abstratos que são chamados dentro do método concreto, e cada subclasse deve possuir implementações específicas dos métodos abstratos. Dessa forma, o método concreto da classe abstrata pode se comportar de diferentes formas, e o código comum dos diferentes componentes não precisa ser duplicado.

Este padrão é particularmente aplicado em grande escala em

frameworks. Na API da própria linguagem Java pode-se verificar vários exemplos da aplicação desse padrão. Um exemplo é a classe java.io.InputStream, que possui alguns métodos concretos, que invocam o método abstrato read(). Suas subclasses, como java.io.FileInputStream e java.io.ByteArrayInputStream, definem imple-mentações concretas deste método.

Deve-se tomar cuidado com o uso desse padrão, pois ele utiliza herança e uma classe só pode estender outra classe uma vez. Isso faz esse padrão adequado em casos em que pequenas variações do algoritmo principal irão acontecer de uma classe para outra. Em casos em que existem diversas possibilidades que podem ser combinadas nas implementações, é melhor recorrer a padrões que utilizam composição como State ou Strategy.

Para efeito de curiosidade, este padrão também é referenciado como princípio de Hollywood: “não nos telefone, nós telefonaremos para você”.

Padrão Template Method

serviços contém lógica de negócios específica de caso de uso (Use Case Services) e utiliza os Application Services genéricos (Generic Services), que constituem a próxima camada e contém lógica de ne-gócios que não é especifica de caso de uso ou cliente. A utilização de todas as camadas juntas nesta estratégia não é obrigatória.

A aplicação deste padrão traz as seguintes características a aplicação:

-

veis;

36 www.mundoj.com.br36

Co

nsi

der

açõ

es fi

nai

s

Ap

esar

de

hav

er v

ário

s fi

nai

s d

ifer

ente

s p

ara

a h

istó

ria,

acr

edit

o q

ue

nin

gu

ém p

erd

e (m

esm

o q

uem

foi

des

ped

ido)

, poi

s se

mp

re s

e g

anh

a em

con

hec

imen

to. D

epoi

s d

e le

r u

ma

vez,

rec

omen

da-

se q

ue

o le

itor

te

nte

exp

lora

r ou

tras

pos

sib

ilid

ades

e o

utr

os c

amin

hos

par

a ve

r qu

ais

seri

am a

s co

nse

qu

ênci

as p

ara

um

a se

qu

ênci

a d

e es

colh

as d

ifer

ente

s.

Este

tip

o d

e m

ater

ial s

obre

pad

rões

est

imu

la n

ão s

ó os

leit

ores

a c

o-

nh

ecer

em o

s p

adrõ

es, m

as a

exp

erim

enta

rem

su

as e

scol

has

em

um

am

bie

nte

sim

ula

do.

Iss

o ex

erci

ta n

ão s

ó h

abili

dad

es d

e m

odel

agem

d

e so

ftw

are,

mas

tam

bém

a a

nál

ise

crít

ica

dos

req

uis

itos

não

-fu

nci

o-

nai

s. O

s ex

emp

los

de

pad

rões

em

pre

gad

os e

m s

itu

açõe

s em

qu

e el

es

não

são

a s

olu

ção

mai

s ad

equ

ada

mos

tram

com

o as

con

seq

uên

cias

p

odem

ser

ru

ins

e p

reju

dic

ar o

an

dam

ento

de

um

pro

jeto

.

Na

vid

a re

al,

infe

lizm

ente

, m

uit

as v

ezes

não

par

a vo

ltar

atr

ás e

to

mar

um

a d

ecis

ão d

ifer

ente

. D

essa

for

ma,

tod

os d

evem

est

ud

ar e

an

alis

ar b

asta

nte

an

tes

de

um

a es

colh

a. C

omo

na

his

tóri

a, o

fin

al ir

á d

epen

der

de

você

!

Referências

- - -

PLo

P 2

008

con

fere

nce

pro

ceed

ing

s.ce

pro

ceed

ing

s.p

roce

edin

gs.