Вы находитесь на странице: 1из 44

AOP - Livro de Receitas

Michel de Montalvo Guedes

Abstract Este tutorial visa demonstrar como a AOP (Orientao a Aspectos) pode auxiliar-nos a resolver problemas de complexidade mdio-elevada de forma bastante simples. Palavras-Chaves SOA, AOP, IOC, O.O, Framework, Padres de Projeto, JoinPoint, PointCut, Advice.

Introduo
Imagino que o leitor deste tutorial, como eu, j deva ter testado um ou vrios exemplos de Hello World utilizando AOP. Ou ento, tenha lido alguns artigos conceituais sobre: como AOP ir melhorar drasticamente o seu futuro!, porm sem demonstrar nenhum caso prtico disto. Por isso, minha abordagem ser um pouco mais honesta: tentarei mostrar a AOP limitada como ela pode melhorar os sistemas que voc j desenvolve hoje em dia, deixando os comentrios futuristas para os Engenheiros de HollyWood, isto claro se o leitor tambm apreciar, como eu, um belo filme de fico cientfica. Porm, imagino que vrios leitores tero uma primeira impresso sobre AOP com este tutorial, por que quase todo material mais abrangente sobre a mesma encontra-se em lngua inglesa. Assim, no furtei-me a grata tarefa de acrescentar parte inicial deste material uma breve e compacta introduo sobre os principais conceitos relacionados AOP, e tambm disponibilizar, sempre que possvel, referncia documentao disponvel na internet sobre assuntos muito extensos para serem abordados apenas neste papel. Para aqueles que j tiveram uma experincia inicial e dominam conceitos relacionados AOP como: Aspecto, Pointcut, Advice, etc., podem pular o tpico introdutrio e passar direto ao prximo: Definindo Pointcuts em AspectWerkz e JBossAOP que demonstra alguns exemplos prticos de como definir estes elementos na semntica especfica destes dois Frameworks. A parte central (e mais extensa do tutorial) um estudo de caso onde demonstro a construo de um framework que chamei, por motivos implcitos, de MicronContainer. Voc encontrar reunidos nele vrios exemplos prticos da utilizao das tcnicas da AOP em problemas do mundo real, ou seja, do cotidiano do desenvolvedor quando deparado com a construo da arquitetura de sistemas de mdio e grande porte. Cabe aqui uma ressalva: utilizei a linguagem Java, primeiro: por que tenho mais afinidade com ela (e no sou especialista em linguagens artificiais que produzem exemplos artificiais), segundo: por que as principais implementaes de mecanismos de AOP foram escritas para serem utilizadas na plataforma Java (cite-se: AspectJ, AspectWerkz, JBossAOP, SpringAOP, Dynaop, entre outros). Uso nos exemplos dois dos mais populares Framewoks AOP para Java: AspectWerkz e JBossAOP, ambos so muito semelhantes em sua mtodologia e sintaxe pois: Utilizam diretamente linguagem Java para construir todos os elementos necessrios programao para a AOP. da opinio pessoal do autor deste papel que muito mais fcil utilizar est abordagem, que aprender uma linguagem exclusiva para criar Aspectos (para uma explicao formal do termo veja o prximo tpico Conceitos

A voz Java no Brasil Pg. 1

Bsicos), pois permite ao leitor que tenha conhecimentos bsicos sobre a linguagem Java a possibilidade de trabalhar imediatamente com a AOP. Existem pelo menos duas formas de utilizar AOP em uma aplicao Java, uma mais clssica, que exige um estgio de ps-compilao da aplicao e outra mais simples em que este estgio no necessrio - tambm conhecida como AOP via Proxy. Por questes relativas ao tamanho deste material, preferi concentrar-me em exemplos utilizando primeira abordagem, deixando a outra para um material posterior caso surja oportunidade.

Conceitos Bsicos
Para que tenhamos o entendimento total dos exemplos de cdigo utilizados neste tutorial, faz-se necessrio a explanao de alguns conceitos relacionados Orientao a Aspectos (AOP), e uma rpida explicao entre as diferenas pontuais entre a AOP e a Orientao a Objetos (O.O). Na Anlise Orientada a Objetos conseguimos modelar de forma clara e coerente (segundo os princpios de coeso e acoplamento) os requisitos funcionais (de negcios) de um problema. Assim bastante direta a diviso do problema em partes funcionais (tambm chamada de decomposio funcional), ou seja, em classes e objetos. O problema aparece quando passamos ao Projeto (tambm chamado Design, OOD) e nos deparamos com toda uma complexidade de requisitos no-funcionais (dito daqui por diante como n-funcionais), como: Log, persistncia, atomicidade, etc., a serem cumpridos. Como estes requisitos (n-funcionais) frequentemente esto Acoplados no cdigo fonte aos requisitos do negcio (funcionais) de forma ad-hoc (no previsvel) dizemos que eles esto emaranhados no cdigo (chamado de Tangled Code), aumentado ainda mais: A complexidade de uma tarefa que j era por sua natureza, complexa! (LADDAD [1]). O resultado que perdemos toda a coeso e o acoplamento obtidos na anlise e estamos agora com um modelo que difcil de representar e de manter. A AOP se prope a resolver esta questo criando a idia de diviso ortogonal do problema. Seria algo como modelar os requisitos de negcio (Funcionalmente) e tambm os n-funcionais (Ortogonalmente) de um sistema. Vamos dar um exemplo. Imagine um grfico com dois eixos x e y, cada um representando Requisito x Funcionalidades, introduzir um requisito n-funcional seria como introduzir um novo eixo z (ortogonal), dando uma viso 3D ao modelo. Para cada funcionalidade temos uma ou um conjunto de classes. Da mesma forma para cada novo Eixo Ortogonal introduzido ao modelo, temos uma outra unidade fundamental, o Aspecto. O Aspecto unidade funcional da AOP. Ele escrito em uma linguagem particular, ou modernamente, na mesma linguagem utilizada para O.O (veja exemplo na Figura 1). Ainda no existe uma metodologia (como na O.O) que permita modelar um sistema orientado a aspectos desde a anlise at sua implementao, em seu estgio atual a AOP pode ser considerada como: "Uma evoluo das metodologias de desenvolvimento de software" (KICZALES [2]), at por isso vamos propor um padro para o desenvolvimento dos exemplos (veja mais no tpico: Padro JoinPointToken) que estabelecido sobre uma relao de 1-1 (um para um), onde um aspecto representa um requisito (ou interesse) ortogonal do sistema. Nesta abordagem o aspecto nada mais do que uma funcionalidade de nvel do sistema, ou seja,

A voz Java no Brasil Pg. 2

representa um comportamento esperado para o mesmo (Cross-cut Concern), para isto disponibilizando um conjunto de funes, assemelhando-se (o Aspecto) muito mais a programao procedural do que a programao O.O.

Fig.1 Exemplo de um Aspecto. Como no o objetivo deste ser um tratado sobre AOP, vou-me ater de forma prtica h como feita implementao da decomposio do sistema, em Objetos e Aspectos: Inicialmente decompomos funcionalmente o sistema utilizando O.O, representando as regras de negcio em uma linguagem O.O e identificando e isolando os requisitos n-funcionais compartilhados entre as classes num mdulo (pacote) separado: tambm uma boa prtica utilizar esteretipos da UML (por exemplo, <<Aspect>>, <<Transaction>>, etc.), para demarcar classes que funcionalmente esto ligadas a vrias outras. [Grifos Nossos]. Depois implementamos os requisitos n-funcionais compartilhados entre as classes em um Aspecto (minha preferncia utilizar 1-1, mas no h impedimentos para que sejam utilizados vrios Aspectos, conforme surja necessidade), em uma linguagem especfica de Aspectos, ou na mesma Linguagem utilizada para OO com anotaes em um arquivo XML ou anotaes da prpria linguagem, indicando que a classe apresenta as funcionalidades (ou melhor, os interesses) de um Aspecto. (Veja a Figura 2) Utilizamos um combinador de cdigo, chamado Weaver, para montar as duas implementaes. Algo muito parecido com a herana mltipla de O.O puro. (Veja a Figura 3.).

A voz Java no Brasil Pg. 3

Fig.2 Classes Antes do Combinador Weaver.

Fig.3 Classes Depois do Combinador Weaver. 1 Marcando as Classes Para tanto, devemos oferecer uma forma de o compilador weaver juntar os dois cdigos de forma a fornecer o comportamento desejado, que normalmente obteramos com a utilizao de O.O e do cdigo emaranhado. Vamos analisar como isto feito, descrevendo as partes envolvidas nesta combinao: 1.1 - Joinpoints So pontos bem definidos onde podem incidir uma caracterstica ortogonal no Objeto. Por exemplo, se um mtodo de uma classe precisa de um requisito n-funcional (como atomicidade da transao), ele um provvel candidato a ter um (ou mais) Joinpoints. Vejamos um exemplo simples:

A voz Java no Brasil Pg. 4

public class Banco{ public Dinheiro efetuarSaque(Conta contaCorrente, double valor){ Dinheiro dinheiro = null; //Obtm se o cliente da conta tem limite para saque boolean temLimite = verificarLimite(contaCorrente); if(!temLimite){ dinheiro = new DinheiroNaoLiberado(No H Saldo); return dinheiro; } //Interrese Ortogonal: Desfazer tudo se depois ocorrer erro. debitarConta(valor); //JoinPoint dinheiro = new DinheiroLiberado(valor); return dinheiro; } }

Listagem 1.1 Mostrando um JoinPoint Na listagem 1.1 vemos um exemplo de Joinpoint. Caso a operao dinheiro = new DinheiroLiberado(valor) cause uma exceo, a alterao feita pelo mtodo debitarConta(valor) dever ser desfeita se desejamos manter a Integridade da Transao, isto envolveria misturar aos requisitos de negcios lgica de controle para as seguintes operaes: 1) capturar a exceo, 2) desfazer todas as modificaes na base de dados e 3) relanar a exceo adiante. 1.2 - Pointcuts uma regra que define um Joinpoint. Est regra inclui: Uma Expresso Regular ou Padro que descreve que elementos do objeto: (mtodos, atributos, construtores ou o prprio objeto) capturar como Joinpoints. Assim o Padro permite que um Joinpoint: Seja to genrico quanto se deseje (LADDAD [1]). Sua Definio que recebe a expresso e intercepta a execuo do Joinpoint de uma maneira especfica.

Logicamente, a Definio e o Padro devem concordar segundo o tipo do elemento que capturado (mtodo, atributo, etc..), Abaixo alguns exemplos de Pointcuts escritos em AspectWerkz e JBossAOP (Detalharemos a sintaxe de ambos no prximo tpico). Em AspectWerkz:
- Captura os Mtodos efetuarSaque() e debitarConta(): execution( * Banco.efetuarSaque (..) || * *. debitarConta (double)) |---------| |-------------------------------------------------------------| Definio Padro

Listagem 1.2 Exemplo de Pointcut em AspectWerkz Em JBossAOP:

A voz Java no Brasil Pg. 5

- Captura os Mtodos efetuarSaque() e debitarConta(): execution( * Banco->efetuarSaque (..) || * *->debitarConta (double)) |---------| |------------------------------------------------------------------| Definio Padro

Listagem 1.3 Exemplo de Pointcut em JBossAOP.

1.3 - Advices - onde ser implementado o requisito n-funcional que espera-se ser
anexado a um Joinpoint. Trazendo para O.O, seria o mtodo de nossa classe (demarcada como um Aspecto) que seria executado quando o Joinpoint (lugar no Objeto) definido pelo Pointcut (Regra) fosse interceptado, at mesmo por isso, comum que um Advice venha anexado a um Pointcut. Vejamos os exemplos abaixo. Em AspectWerkz:
Advice Pointcut Tipo !------| |-------------------------------------------| @after( execution(* *. debitarConta (double))) public void persistirNaBaseDados(JoinPoint joinPoint){..} @after Depois de executar o mtodo

Advice mtodo

Listagem 1.4 Exemplo de Advice em AspectWerkz. Em JBossAOP:


Advice Pointcut Tipo !------| |------------------------------------------------------| @Bind(pointcut=execution(* *->debitarConta (double))) public Object persistirNaBaseDados(Invocation invocation){..} @Bind Depois de executar o mtodo

Advice mtodo

Listagem 1.5 Exemplo de Advice em JBossAOP.

Alguns frameworks (como o AspectWerkz) definem uma semntica mais rica para os Advices (herdada em grande parte do AspectJ), com o objetivo de especificar com mais preciso o momento em que o Adivice dever ser aplicado ao Joinpoint. (Antes do JoinPoint, Depois do JoinPoint, Aps uma exceo no Joinpoint, etc..). Veja um exemplo rpido abaixo:

A voz Java no Brasil Pg. 6

@afterReturning Depois de executar o mtodo se: terminou normalmente (no levantou exceo) e retornou o parmetro definido em type. @afterReturning( type=Dinheiro pointcut=execution(* Banco.efetuarSaque (..))) public void commitTransaction(StaticJoinPoint joinPoint){..} @afterThrowing - Depois de executar o mtodo se: ele levantou a exceo definida em type. @afterThrowing( type=Exception pointcut=execution(* Banco.efetuarSaque(..))) public void rollbackTransaction(StaticJoinPoint joinPoint){..}

Listagem 1.6 Semntica mais rica de Tipos de Advices do AspectWerkz. Todos estes exemplos demonstraram uma complexidade inicial: O Joinpoint definido atravs da Regra (Pointcut) que est no Advice, e no, formalmente, no Objeto onde ele ocorre. Visto de uma forma diferente: os Joinpoints no existem fisicamente, eles so trechos demarcados mentalmente (atravs da decomposio dos interresses ortogonais), onde sero Injetados os Advices no momento da compilao dos aspectos pelo compilador Weaver. Posteriormente ser proposto um padro que visa desmistificar boa parte desta e de outras complexidades, controlando de forma clara a demarcao dos Joinpoints pelo Objeto.

Definindo Pointcuts em AspectWerkz e JBossAOP


No exemplo anterior mostramos, mais no em detalhes, alguns pointcuts. Neste tpico iremos explicar a sintaxe de como eles so construdos. 1 - Expresso Regular ou Padro o nome do elemento (atributo, classe, mtodo ou construtor) definido atravs da descrio de sua assinatura, ou seja: sua visibilidade, pacote, tipo, classe ou outros atributos que o caracterizem. 1.1 - WildCards - So curingas que permitem anexar um pequeno desvio ao comportamentos das assinaturas dos elementos dos Pointcuts. Em AspectWerkz: * - Permite aceitar qualquer assinatura para um elemento do pacote. aplicvel a somente um nvel do mesmo.

A voz Java no Brasil Pg. 7

.. - Para declarao de classes, significa que quaisquer elementos depois dos dois pontos so vlidos (Neste caso, s pode ser usado como ultimo elemento da declarao do pacote), para parmetros de mtodos, significa que a quantidade de parmetros passados pode ser varivel. + - Usado para selecionar apenas objetos que so subclasses do valor selecionado ou instncias do mesmo.

Em JBossAOP: * - Para declarao de pacotes, significa que quaisquer elementos depois dos dois pontos so vlidos. aplicvel a qualquer nvel da declarao do elemento. .. - Usado para parmetros de mtodos e construtores, significa que a quantidade de parmetros passados pode ser varivel. $instanceof{nomepacote_nomeclasse} Usado para selecionar apenas objetos que so subclasses do valor selecionado ou que implementam a interface passada.

1.2 Padres para Mtodos Em AspectWerkz:

Assinatura <anotao> <modificador> <tipo_retorno> <pacote.classe.nome_mtodo> (<tipos_parametros>)


Veja alguns exemplos no quadro da listagem abaixo:
- Padro: int app.Pessoa.teste (..) Mtodo teste de app.Pessoa que retorne um inteiro, com qualquer numero de parmetros. - Padro: * app.Pessoa+.*(..) Qualquer mtodo que pertena a uma Subclasse ou seja instncia de app.Pessoa e retorne qualquer (ou nenhum) valor. - Padro: * app.*.teste(java.lang.String) Mtodo teste de qualquer classe de app, que receba uma String. - Padro: * app..teste(..) Mtodo teste de qualquer classe de app (ou app.subpacotes), que receba e retorne qualquer valor. - Padro: @app.Transaction * app.*.*(..) Qualquer mtodo de qualquer classe do pacote app, que esteja marcado com a anotao @Transaction do pacote app.

Listagem 1.7 Pointcuts para Mtodos em AspectWerkz.

A voz Java no Brasil Pg. 8

Em JBossAOP:

Assinatura <modificador> <tipo_retorno> <pacote.classe -> <anotao> <nome_mtodo> (<tipos_parametros>).


- Padro: int app.Pessoa->teste(..) Mtodo teste de app.Pessoa que retorne um inteiro, com qualquer numero de parmetros - Padro: * $instanceof{app.Pessoa} -> *(..) Qualquer mtodo que pertena a uma Sub-Classe de app.Pessoa. - Padro: * app.*->teste(java.lang.String) Mtodo teste de qualquer classe de app(ou app.subpacotes), que receba uma String e retorne qualquer valor. - Padro: * *->@app.Transaction(..) Qualquer mtodo de qualquer classe, que esteja marcado com a anotao @Transaction do pacote app.

Listagem 1.8 - Pointcuts para Mtodos em JBossAOP.

1.3 Padres para Atributos Em AspectWerkz:

Assinatura <anotao> <modificador> <tipo> <pacote.classe.nome_atributo>


- Padro: int app.*.id Atributo id de qualquer classe do pacote app, que seja do tipo inteiro. - Padro: java.util.* app..* Qualquer atributo de qualquer classe que pertena ao pacote app e que seja um tipo de java.util (Collection, por exemplo). - Padro: @app.id * *.Pessoa.* Qualquer atributo de Pessoa que esteja marcado com a anotao @id do pacote app.

Listagem 1.9 - Pointcuts para Atributos em AspectWerkz.

Em JBossAOP:

Assinatura <modificador> <tipo_retorno> <pacote.classe -> <anotao>


<nome_atributo>

A voz Java no Brasil Pg. 9

- Padro: int app.*.Pessoa->id Atributo id do Objeto Pessoa de qualquer subpacote de app que seja do tipo inteiro. - Padro: java.util.* app*->* Qualquer atributo de qualquer classe que pertena ao pacote app e que seja um tipo de java.util (Collection, por exemplo). - Padro: * *.Pessoa->@app.id Qualquer atributo de Pessoa que esteja marcado com a anotao @id do pacote app.

Listagem 1.10 - Pointcuts para Atributos em JBossAOP.

1.4 Padres para Construtores (capturam o objeto no momento de sua criao) Em AspectWerkz:

Assinatura

<anotao> (<tipos_parametros>).

<modificador>

<pacote.nome_classe>.<new>

- Padro: public app.*.Pessoa.new(int) Construtor de Pessoa de qualquer subpacote de app que seja pblico e tenha um parmetro inteiro. - Padro: * app.*.new(..) Construtor de qualquer classe do pacote app com qualquer quantidade de parmetros. - Padro: public *..Pessoa.new() Construtor de Pessoa que seja pblico e no tenha argumentos.

Listagem 1.11 - Pointcuts para Construtores em AspectWerkz.

Em JBossAOP:

Assinatura

<modificador> (<tipos_parametros>).

<pacote.classe

->

<anotao>

new>

A voz Java no Brasil Pg. 10

- Padro: public app.*.Pessoa->new(int) Construtor de Pessoa de qualquer subpacote de app (em qualquer nvel) que seja publico e tenha um parmetro inteiro. - Padro: * app.*->new(..) Construtor de qualquer classe do pacote app (ou app.subpacotes) com qualquer quantidade de parmetros. - Padro: public *Pessoa->new() Construtor de Pessoa que seja pblico e no tenha argumentos.

Listagem 1.12 - Pointcuts para Construtores em JBossAOP.

1.5 Padres para Classes - Em AspectWerkz:

Assinatura <anotao> <modificador> <pacote.nome_classe>


- Padro: * * Qualquer classe do sistema. - Padro: public app..Pessoa Classe Pessoa do pacote app (ou app.subpacotes) que seja pblica. - Padro: @ejb * * Qualquer Classe marcada com a anotao @ejb.

Listagem 1.13 - Pointcuts para Classes em AspectWerkz.

Em JBossAOP:

Assinatura <pacote.classe> ou <anotao>


- Padro: * Qualquer classe do sistema. - Padro: app.*.Pessoa Classe Pessoa do pacote app (ou app.subpacotes). - Padro: @ejb Qualquer Classe marcada com a anotao @ejb.

Listagem 1.14 - Pointcuts para Classes em JBossAOP.

A voz Java no Brasil Pg. 11

2 Operadores Permitem unir um ou mais padres de Pointcuts, criando uma nova regra composta entre os mesmo. 2.1 Tipos Em AspectWerkz: ! - Nega um elemento de um Pointcut, realizando a caracterstica contraria a que foi declarada. || ou OR Une dois ou mais Pointcuts, permitindo que a regra seja aplicada se qualquer uma das alternativas for verdadeira. Geralmente tambm usado para criar Pointcuts Mixados, ou seja, unindo dois Pointcuts de tipos diferentes (Por exemplo, unindo um Pointcut de mtodo e um de atributo). && ou AND - Une dois ou mais Pointcuts, permitindo que a regra seja aplicada somente se todas as alternativas forem verdadeiras.

Em JBossAOP: ! - Nega um elemento de um Pointcut, realizando a caracterstica contraria a que foi declarada. OR Une dois ou mais Pointcuts, permitindo que a regra seja aplicada se qualquer uma das alternativas for verdadeira. Geralmente tambm usado para criar Pointcuts Mixados, ou seja unindo dois Pointcuts de tipos diferentes (Por exemplo unindo um Pointcut de mtodo e um de atributo). AND - Une dois ou mais Pointcuts, permitindo que a regra seja aplicada somente se todas as alternativas forem verdadeiras.

3 Definio do Pointcut Intercepta a execuo de um Joinpoint, segundo a regra definida no padro passado como argumento. (Descrito anteriormente). 3.1 Tipos Abaixo esto os tipos mais utilizados de definies para o AspectWerkz e o JBossAOP (a lista completa pode ser encontrada na documentao dos Frameworks nas referncias [10] e [11]). Em AspectWerkz: execution(padro de mtodo ou construtor) - Intercepta a execuo de um Joinpoint definido para um mtodo ou um construtor.
- Captura um Mtodo execution(* app.Pessoa+.*(..))

Listagem 1.15 Execution() em AspectWerkz. set(padro de atributos) - Intercepta a execuo de um Joinpoint definido para um atributo quando este modificado.

A voz Java no Brasil Pg. 12

get(padro de atributos) - Intercepta a execuo de um Joinpoint definido para um atributo quando este lido.
- Captura um Atributo quando modificado ou lido. set(int app.*.Pessoa.id) && get(int app.*.Pessoa.id)

Listagem 1.16 Pointcut get() e set() e o operador lgico AND. call(padro de mtodo ou construtor) - Intercepta a chamada de um Joinpoint definido para um mtodo ou um construtor. within(tipo de parmetro) - Usado para delimitar o scopo de quais tipos podem ser utilizados em Pointcuts do tipo call() ou execution(). Tambm pode ser utilizado para delimitar as classes que entram em uma operao de mixin.

Diferena sutil entre execution() e call() O leitor mais atendo pode ter notado que estes dois tipos de pointcuts capturam mtodos. bem mais fcil notar a diferena entre ambos se pensarmos em pointcuts para construtores. Vejamos um exemplo utilizando a classe Pessoa, definida abaixo:

package app; public class Pessoa{ public Pessoa(){ this(1); } public Pessoa(int i){ } public static void main(String args[]){ new Pessoa(); } }

Listagem 1.17 Definio da classe Pessoa. Se quisssemos capturar o construtor de Pessoa que recebe um int, no mtodo main() no poderamos utilizar o pointcut:
call(public app.Pessoa.new(int))

Listagem 1.18 Pointcut call() para o Construtor de Pessoa Isto por que para este exemplo o comando new() do construtor public Pessoa(int i) no utilizado diretamente no mtodo main(), ao contrrio, chamado indiretamente atravs

A voz Java no Brasil Pg. 13

do construtor sem argumentos public Pessoa(), o que encaixa-se em um pointcut do tipo execution(). O pointcut do exemplo abaixo funciona e consegue capturar a chamada ao construtor com argumentos, pela criao do objeto Pessoa no mtodo main():
execution(public app.Pessoa.new(int))

Listagem 1.19 Pointcut execution() para o Construtor de Pessoa Em JBossAOP: execution(regra de mtodo ou construtor) - Intercepta a execuo de um Joinpoint definido para um mtodo ou um construtor.
- Captura um Construtor (no publico) execution(!public *.Pessoa->new())

Listagem 1.20 Execution() em JBossAOP e o operador lgico !(negao). set(padro de atributos) - Intercepta a execuo de um Joinpoint definido para um atributo quando este modificado. get(padro de atributos) - Intercepta a execuo de um Joinpoint definido para um atributo quando este lido. field(padro de atributos) - Intercepta a execuo de um Joinpoint definido para um atributo quando este modificado ou lido.
- Captura um Atributo quando modificado ou lido. field(int app.*.Pessoa.id)

Listagem 1.21 Exemplo de Pointcut get() e set() usando somente um field(). call(padro de mtodo ou construtor) - Intercepta a chamada de um Joinpoint definido para um mtodo ou um construtor. within(tipo do parmetro) - Usado para delimitar o scopo de quais tipos podem ser utilizados como parmetros em Pointcuts do tipo call() ou execution()
- Captura a chamada a um Mtodo, limitando o tipo dos argumentos call(* $instanceof{app.Pessoa} -> *(..)) AND within(java.util.*)

Listagem 1.22 Call() limitado por um Within() em JBossAOP.

A voz Java no Brasil Pg. 14

Padro JoinPointToken
Pode parecer muita pretenso querer propor um padro, porm, isto mais devido importncia e evidncia que eles tomaram em O.O (alguns afirmam ser eles a salvao do mundo), do que o modelo de sua proposio em si. Em gnese, padres so uma maneira formal de se catalogar um comportamento j: repetida e comprovadamente utilizado de forma eficaz, porm no-formal. Seguindo este modelo vamos analisar o padro proposto abaixo.

1 - Inteno
Controlar o fluxo e a granularidade da demarcao dos Joinpoints no Objeto

2 - Problema
uma questo rdua controlar a granularidade dos Advices de um aspecto. Os Pointcuts, que so a regra para demarcar-se os Joinpoints no podem ser genricos e nem especficos demais, por exemplo, um Pointcut que chama um mtodo no pode ser escrito destas maneiras. 1) Qualquer Objeto, Assinatura e varivel de retorno AspectWerkz : * *.. nome_mtodo(..) JBossAOP : * * -> nome_mtodo(..) . 2) Mtodo especfico de um objeto.
AspectWerkz: public nome_classe. nome_mtodo(nome_parameto)

JBossAOP: public nome_classe-> nome_mtodo(nome_parameto)

No primeiro caso, a granularidade muito fina no Pointcut, pois no permite um controle mais apurado de quais mtodos so desejados para um Advice, j no segundo caso muito grossa, pois temos um controle alto (porm no portvel) dos elementos do advice. Se desejarmos obter uma funcionalidade disponibilizada como um servio (nos moldes da SOA), deve-se planejar muito bem o tipo de granularidade utilizada em um Pointcut. A soluo atual utiliza arquivos de configurao para guardar o elemento que ir receber o Joinpoint, podendo assim vari-lo de forma mais flexvel, porm, traz uma srie de dificuldades pois tira a visibilidade do desenvolvedor de onde est acontecendo chamada ao aspecto (mais especificamente ao Interesse Ortogonal), tornando difcil diagnosticar erros na sintaxe do Pointcut; Por exemplo, se for alterado apenas um caractere do nome do mtodo, o Advice no funcionar da forma esperada. A chave para resolver estes problemas de forma flexvel e clara poder marcar (com um Token) os elementos (atributos, mtodos, objetos, etc.) do objeto de forma que seja fcil a visualizao do interesse que esta sendo aplicado ao elemento do objeto.

3 - Foras
Deve ser fcil marcar um elemento como um Joinpoint. As regras do Pointcut devem ser desacopladas do objeto, porm no apresentarem uma granularidade muito fina (problemtica). O Objeto e o Aspecto devem poder variar independentemente.

A voz Java no Brasil Pg. 15

4 - Soluo
4.1 Mecanismo A soluo encontrada utiliza anotaes como Tokens para marcar os Joinpoints nos objetos. Anotaes so um mecanismo do Java 5, utilizadas para se demarcar objetos (Atributos, classes, mtodos, etc..). 4.2 Tipos Existem 5 tipos diferentes de Tokens, sendo estes: I. TokenField: Token usado para marcar Joinpoints para atributos de um objeto. II. TokenMethod: Token usado para marcar Joinpoints para mtodos de um objeto. III. TokenConstructor: Token usado para marcar Joinpoints para construtores, que so acessados quando um objeto instanciado, por exemplo, com new() em Java. IV. TokenClass: Token usado para marcar Joinpoints para um objeto. Geralmente so usados em casos de Mixin (mistura) entre duas classes, atravs da introduo dinmica (Introduce) de uma interface. V. TokenMixed: Token que marca diferentes tipos de Joinpoints, como por exemplo, mtodos normais e construtores. 4.3 Dependncias Conceitual Para que um Pointcut possa capturar um Token, ambos precisam combinar quanto ao tipo de elemento do objeto (atributo, mtodo, etc..) a que sero aplicveis, ou seja, eles devem coincidir quanto ao tipo de Joinpoint (de mtodo, de atributo, etc..) que ser utilizado. Fsica Da mesma forma: assinatura do Pointcut (que define a quem o Advice atende) deve fazer referncia ao Token (em nosso caso anotao Java) e no diretamente ao elemento do objeto demarcado, assim, garantimos a indireo entre o Joinpoint e o Pointcut: O objeto no conhece o seu Aspecto, e este tambm no conhece o seu objeto, ambos esto relacionados (demarcados) apenas pelo token que o objeto externaliza.

5 Padres Relacionados Builder Memento Interceptor Filter

A voz Java no Brasil Pg. 16

O Framework McronContainer
Neste tpico, ser apresentado um exemplo prtico da utilizao da AOP e do padro JoinPointToken (citado no tpico anterior), para a soluo de problemas de mdia complexidade. Construiremos um Framework SOA (Orientado a Servio) mnimo, porm que nos proveja transparncia na soluo de alguns requisitos de sistema bem comuns, a saber: Inverso de Controle com um cache dinmico, controle transparente da Transao e uma Fbrica Genrica para o padro Dao (j2ee), que ns abstra-a da complexidade de um mecanismo de persistncia especfico. Parece uma tarefa desafiadora a principio e o seria mesmo, quando comparada complexidade dos frameworks que foram projetadas para solucionar estes problemas. At este ponto a escolha do nome para este pequeno (em hiptese), porm funcional Framework de apoio seria at fantasioso: McronContainer. Mas o nome, justamente, pretende demonstrar o quanto a AOP, verdadeiramente, pode nos ajudar a domar as redias do problema e desmistificar o monstro escondido por detrs das nuances da orientao a objetos e dos padres de projeto. A primeira soluo um exemplo de injeo de dependncia nos moldes do EJB3. A segunda e terceira so simplificaes de padres de projetos. Para os exemplos 2 e 3 apenas mostro as interfaces de um mecanismo de persistncia, suponho que esteja sendo utilizado um mapeamento objeto/relacional (como hibernate), para controle da transao e persistncia. Fao isto para que a soluo seja genrica e possa ser portada a qualquer tipo de framework ou tecnologia (dou referncia de um exemplo prtico do mesmo), sem afetar de maneira nenhuma o objeto que requer o servio. 1 IOC com Cache descomplicado, o pacote: org.javafree.microncontainer.ioc Quando a OO surgiu uma de suas principais promessas era o reaproveitamento de cdigo, neste cenrio, a partir da utilizao de mecanismos como um encapsulamento rgido, herana e polimorfismo, uma classe seria distribuda como um componente de software portvel. Modernamente ouve houve uma expanso deste conceito (na verdade uma adequao ao SOA), onde um componente abriga um conjunto de classes, sendo projetado para disponibilizar um servio que, peculiarmente, pode ser consumido sem que haja a necessidade de nenhuma alterao por qualquer aplicao fora do contexto de sua criao". (FOWLER[2]) Por outro lado, vimos que na maioria dos sistemas os requisitos so naturalmente ortogonais, ou seja, apresentam vrias dimenses: geralmente uma dimenso para cada requisito bsico e uma para cada requisito de nvel do sistema (LADDAD [1]), portanto quando tentamos planificar esta ortogonalidade em apenas uma dimenso (Funcional) aparecem efeitos contrrios como o Tangled Code, amontoando uma poro de cdigo burocrtico em um ponto esparso do sistema onde s deveria haver a implementao de uma funo necessria ao requisito bsico. Como descrito por LADDAD [1], o Tangled Code frustra a premissa da reutilizao de cdigo por que causa os seguintes efeitos indesejados: 1 Difcil de rastrear A dependncia de uma classe a vrios outras, causa um efeito cascata que torna difcil a legibilidade do cdigo. Difcil de evoluir - Muitas vezes a hierarquia de dependncias cclica pois as classes esto fortemente acopladas umas nas outras, causando a impossibilidade de evoluo de todo o sistema pela no evoluo de uma de suas partes, fazendo com este venha em certos casos at a estagnar, . A voz Java no Brasil Pg. 17

Vejamos um exemplo de dependncia cclica: Se para executar uma funo, uma classe A possui dependncia explicita (->) de B (ou seja, A->B), e desejamos executar est funo numa classe C, significa que a mesma ser explicitamente: C->A e C->B, se multiplicarmos por n, significa que C->n, ou seja, a classe C est to amarrada s classes n, que no pode ser alterada sob a penalidade de no ser compatvel com a interface das outras n, em contrapartida nenhuma classe n poder evoluir sem que C tambm seja alterado, sob a penalidade de uma parte do programa no funcionar. Veja que utilizamos para este exemplo apenas uma classe, pensando num sistema com milhares destas fcil entender por que a implementao do sistema afasta-se to abruptamente da sua modelagem inicial: Por certo, que em certas situaes difcil at mesmo haver a reutilizao de parte de um programa dentro dele mesmo. [Grifos Nossos]. A IOC inverso de controle veio tentar solucionar parte deste problema do acmulo de dependncias entre os mdulos de um programa. Em linhas gerais, ao utilizar um framework de IOC para a inicializao de um atributo, o controle do fluxo principal do programa e repassado ao framework que dinamicamente injeta as dependncias no mesmo, de acordo com a configurao previa de um alvo (target), at por isso autores como Fowler[2], preferem chamar este recurso de Injeo de Dependncia (Dependency Injection, no original). Para mais detalhes sobre inverso de controle leia o artigo do referido autor. Dito de outra forma, injeo de dependncia significa trocar as vrias dependncias explicitas pela dependncia configurvel ao Framework IOC. Em nosso miniframework vamos trocar est dependncia ao framework IOC pelo acoplamento a um elemento de marcao de cdigo (o token), delegando a injeo da dependncia a um Aspecto em tempo de execuo. Para isto utilizaremos um TokenField (veja o tpico anterior sobre o padro JoinPointToken) chamado de @Inject, para anotar os atributos que sero instanciados por IOC. Como descrito anteriormente, criaremos uma anotao Java para isto. Nosso Token ficaria ento assim:

package org.javafree.microncontainer.ioc; import import import import java.lang.annotation.ElementType; java.lang.annotation.Retention; java.lang.annotation.RetentionPolicy; java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface Inject { }

Listagem 1.23 Definio do Token Inject.

O ponto principal a ser citado a anotao interna @Target, pois ela define a que tipo de elemento a anotao @Inject ser aplicada. Como estamos definindo um TokenField (marcador de atributos), devemos definir seu valor com a enumerao {ElementType.FIELD} (o colchete significa que poderamos anotar mais de um tipo de

A voz Java no Brasil Pg. 18

elemento caso fosse necessrio). Para mais detalhes sobre o recurso de anotaes em Java, veja ARNOLD et al. [5]. Tambm desejamos que os objetos que forem injetados, fiquem por um tempo armazenados em um cache, evitando suas constantes criaes, pois por padro: Estes objetos iro implementar um servio e sero repetidamente criados e invocados pelos consumidores do mesmo. Logo, se no utilizarmos algum mecanismo que nos permita guardar a instncia do objeto que consumido, obteremos que para cada 1000 requisies de um servio sero criadas 1000 instancias do referido objeto. Segundo BOCH[5]: Como Java torna transparente o mecanismo de criao e desalocao de objetos na memria atravs da Mquina Virtual, este processo (a alocao de objetos na memria) relativamente caro para a mesma (VM). Seguindo os exemplos do referido autor, criamos a implementao de uma Fbrica seguindo o padro de projeto Factory e Singleton do GoF (veja mais sobre padres de projeto GoF nas referncias [4] e [14]), como mostra o exemplo da listagem abaixo.

package org.javafree.microncontainer.ioc; import java.util.Map; import java.util.WeakHashMap; public class CachedFactory { //Instancia do Factory private static CachedFactory instance; //Objeto Map(Genrico) usado como Cache private static final Map<Class, Object> cache; static { //Cria o Cache Anexando-a a classe cache = new WeakHashMap<Class, Object>(); } //Implementada como Singleton(Padro GoF) private CachedFactory() { } //Cria uma Instncia nica public static final CachedFactory getInstance() { if (instance == null) { instance = new CachedFactory(); } return instance; }

A voz Java no Brasil Pg. 19

//Mtodo que busca uma Classe pelo Nome private Class find(String name) throws Throwable { //Busca a Classe Class c = Class.forName(name); //No pode ser uma Interface if (c.isInterface()) { throw new Exception( "MicroContainer no Suporta Interface Injection"); } return c; } //Mtodo que cria a instncia de uma classe public Object create(String classe) throws Throwable { //A classe a chave de busca no Map Class key = find(classe); //Busca se a classe j foi criada Object retorno = cache.get(key); //Testa se o objeto no foi criado if (retorno == null) { //Log da Criao System.out.println("Criou o Objeto " + key.getName()); //Cria o objeto retorno = key.newInstance(); //Adiciona ao cache cache.put(key, retorno); } return retorno; } }

Listagem 1.24 Definio da Fabrica dos Objetos. Os pontos mais importantes so: 1 O cache guardado num Map, que instanciado como um WeakHashMap (que libera o objeto se este no for usado continuamente depois de um tempo). O atributo cache static, logo, pertence classe e no a uma instncia do objeto, pois criado apenas uma vez na inicializao da classe pela JVM (no bloco static{}). O mtodo find(String) busca a classe que passada pela sua assinatura (como uma String). Ela no pode ser uma interface (testado com c.isInterface()), pois implementaremos a injeo de dependncia atravs de Setter Injection e no sobre Interface Injection. Para mais detalhes ver Fowler[3]. O mtodo create() busca se o objeto j est armazenado no cache usando como chave a sua classe (key). Se estiver retorna o objeto, seno, cria o objeto pela sua classe usando reflection (retorno = key.newInstance()) e o armazena no cache (cache.put(key, retorno)). Mais detalhes sobre reflection na referncia [12].

Note que at aqui s usamos O.O. Agora vamos ver os detalhes especficos da implementao da AOP, e como nosso aspecto ir capturar o atributo referenciado

A voz Java no Brasil Pg. 20

pelo token @Inject. Antes porm, vamos pensar num pequeno algoritmo que solucionaria nosso problema, assim teramos que: I. Capturar em tempo de execuo a utilizao do atributo. (geralmente fazendo nosso atributo descender de algum tipo especfico). Desviar o fluxo do programa para uma classe que nos retorne o objeto instanciado. Retornar o objeto (como Object em Java) e preencher o atributo, fazendo o cast e a verificao de erro para a converso.

II.

III.

Um Pointcut nos permite capturar um Joinpoint para um atributo (usando get()), resolvendo assim o passo I de nosso algoritmo Para nosso caso, como queremos capturar qualquer atributo que esteja marcado com a anotao @Inject, ento teramos como Pointcut:

Em AspectWerkz: get(@org.javafree.microncontainer.ioc.Inject * *). Em JBossAOP: get(* *->@org.javafree.microncontainer.ioc.Inject).

O passo II imediato. Ao anexar-mos o Pointcut a um Advice o combinador Weaver marca o ponto em nosso objeto em que o fluxo do programa ser redirecionado para o nosso Aspecto. (O momento da redireo depende da semntica do advice de cada framework). J para o passo III, temos a garantia de que o objeto ser do tipo retornado, pois passaremos via reflection assinatura do atributo (com a sintaxe pacote.Nome_Classe) anexado anotao. Veja os exemplos abaixo, para cada framework:

package org.javafree.microncontainer.ioc; import import import import import import org.codehaus.aspectwerkz.annotation.Around; org.codehaus.aspectwerkz.annotation.Aspect; org.codehaus.aspectwerkz.annotation.Expression; org.codehaus.aspectwerkz.definition.Pointcut; org.codehaus.aspectwerkz.joinpoint.FieldSignature; org.codehaus.aspectwerkz.joinpoint.StaticJoinPoint;

@Aspect("perJVM") public class InjectionAspect { @Around("get(@org.javafree.microncontainer.ioc.Inject * *)") public Object injectionAdvice(StaticJoinPoint joinPoint) throws Throwable { // Retorna o atributo instanciado return CachedFactory.getInstance().create( ((FieldSignature) joinPoint.getSignature()) .getField().getType().getName()); } }

Listagem 1.25 Aspecto que implementa IOC em AspectWerkz.

A voz Java no Brasil Pg. 21

package org.javafree.microncontainer.ioc; import org.jboss.aop.Aspect; import org.jboss.aop.Bind; import org.jboss.aop.joinpoint.FieldReadInvocation; @Aspect public class InjectionAspect { @Bind(pointcut = "get(* *-> @org.javafree.microncontainer.ioc.Inject)") public Object injectionAdvice(FieldReadInvocation invocation) throws Throwable { //Retorna o atributo instanciado return CachedFactory.getInstance().create( invocation.getField().getType().getName()); } }

Listagem 1.26 Aspecto que implementa IOC em JBossAOP.

Vamos entender rapidamente os detalhes comuns a ambos os Frameworks: Os dois definem uma anotao para referenciar mtodos que retornam valores como advices (@Around em AspectWerkz e @Bind em JBossAOP). Os nomes dos advices podem ter qualquer sintaxe permitida para nomes de mtodos em Java. O tipo do tributo de retorno obrigatoriamente Object. Trazem o elemento invocado no Joinpoint (recebem-no como parmetro do advice).

Agora os detalhes de cada Framework: AspectWerkz define dois tipos de Joinpoints que o Advice pode receber: JoinPoint e StaticJoinPoint (ou opcionalmente no utilizar nenhum). Use JoinPoint quando necessitar acessar os valores contidos no atributo que foi passado e StaticJoinPoint quando necessitar somente as assinaturas dos mesmos (pois este tem melhor performance).

JBossAOP define 4 quatro tipos de Joinpoints como parmetro de um advice


FieldReadInvocation (leitura de atributos), FieldWriteInvocation (escrita de atributos), MethodInvocation (invocao de mtodos), ConstructorInvocation (Idem para Construtores) e Invocation o mais

(chamando-o

de

Invocation)

genrico, que pode ser qualquer um dos anteriores. Note que os dois Frameworks tornam acessveis informaes sobre o JoinPoint (para mais detalhes veja a documentao de ambos) nos possibilitando a invocao do atributo que est anexado anotao @Inject (getField()), de seu tipo (getType(), via reflection) e do seu nome (getName(), tambm via reflection). Assim, e s chamar nossa Factory passando o nome da classe (mtodo create()). Note que, passar atributos de tipos primitivos e classes que no tem um construtor default sem argumentos ocasionar um erro de tempo de execuo.

A voz Java no Brasil Pg. 22

2 Controle Transparente da Transao, o pacote: org.javafree.microncontainer .atomic Uma preocupao natural de programas que utilizam algum mecanismo de persistncia o controle da transao (ACID). O termo transao pode ser entendido como o mecanismo que nos d garantia de que uma operao persistente tenha quatro propriedades fundamentais: Atomicidade (operaes commit e rollback), Consistncia (nos dados persistidos), Isolamento (no influenciada por resultados externos) e durabilidade. Vejamos um exemplo de uma classe Util, que nos prov um mecanismos de persistncia como descrito acima:

package org.javafree.microncontainer.util; public class PersistenciaUtil { //Aqui se implementaria o inicio da transao public static void beginTransaction(){ System.out.println("Iniciando a Transacao:"); } //Grava a transao no mecanismo de persistncia public static void commitTransaction(){ System.out.println("Transacao Efetuada com Sucesso!"); } //Desfaz a transao no mecanismo de persistncia public static void rollbackTransaction(){ System.out.println("Desfazendo Todas as Transacoes!"); }

Listagem 1.27 Classe Utilitria que controla a transao. Veja que meu exemplo no faz nada, pois para este caso apenas quero demonstrar que o mtodo est sendo chamado. Voc poderia colocar em cada mtodo a implementao correspondente a de um mecanismos de persistncia especifico como o Hibernate: O hibernate um framework ORM (objeto/relacional) que nos prov mecanismos para controle de transao a partir das Interfaces Session e Transaction. (veja referncia [14]). No artigo citado, encontra-se uma implementao de nossa classe Util (com o nome HibernateHelper) caso voc deseje utilizar um exemplo concreto (note que v.c ter que configurar o hibernate e a base de dados). Neste exemplo, trabalho com idia de que a transao feita num mtodo de um objeto de negcios especfico que atua com controlador da mesma. Por isso, o token ser definido como sendo do tipo MethodToken. Vamos ento criar uma anotao chamada @Transaction, com a qual marcaremos os mtodos de nosso objeto controlador, que efetuem operaes transacionais. Veja a anotao na listagem abaixo:

A voz Java no Brasil Pg. 23

package org.javafree.microncontainer.atomic; import import import import java.lang.annotation.ElementType; java.lang.annotation.Retention; java.lang.annotation.RetentionPolicy; java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Transaction { }

Listagem 1.28 Definio da anotao Transaction. Novamente, o principal ponto a se notar a anotao interna @Target, que define a quais elementos do objeto controlador a anotao @Transaction ser aplicvel. Como em nosso caso desejamos marcar mtodos, definimo-la com a enumerao {ElementType.METHOD}. At aqui, a forma como era construdo o Aspecto era muito semelhantes em ambos os frameworks. Neste exemplo porm, apesar de a definio do Pointcut variar pouco (para mtodos usamos execution()), a semntica para definio do advice pode ser definida de forma mais elaborada quando utilizado o AspectWerkz. Irei primeiro explicar o exemplo utilizando este e depois como simular o mesmo comportamento em JBossAOP. Faremos ento um breve comparativo entre a utilizao de cada sintaxe. Vamos antes, pensar em um algoritmo mnimo que nosso objeto controlador dever implementar para solucionar o problema: I. Iniciar a transao, ou melhor o contexto transacional, ao iniciar o mtodo transacional no objeto controler.

II. Controlar o lanamento de excees por parte dos objetos de negcio, e desfazer todas as operaes realizadas durante a transao caso ocorra algum erro. Isto implicaria geramente em vrios blocos aninhados para tratamento de erros (ou um bloco global compartilhado). III. Executar o commit atualizando os dados no mecanismo de persistncia caso o mtodo termine normalmente. Como devemos garantir a durabilidade da transao, devemos programar o commit como a ltima operao executada no mtodo transacional. (lembre-se que utilizar blocos finally{} no recomendvel neste caso). Definido nosso algoritmo, vamos aprender a utilizar a rica semntica do AspectWerkz para solucionar o problema acima demonstrado:

Para o primeiro passo, utilizaremos anotao @Before anexado ao advice beginTansactionAdivice(), onde iniciado o contexto transacional de nosso Joinpoint. Esta anotao executa um Advice antes que um Joinpoint acontea

A voz Java no Brasil Pg. 24

J para o segundo passo, utilizaremos anotao @AfterThrowing anexada ao advice rollbackTransactionAdivice() responsvel por: desfazer todos as operaes com a camada de persistncia caso ocorra qualquer exceo (no caso java.lang.Exception). Est anotao captura as vrias excees definidas em Type, que venham a ocorrer em um Joinpoint. Finalizando nosso algoritmo, utilizaremos anotao @AfterReturning para definir o advice commitTransactionAdivice(), que grava todas as operaes realizadas com o mecanismo de persistncia. Est anotao executar o advice caso o Joinpoint execute normalmente, ou seja, sem ocorrer nenhum erro e retornando um valor. (Poderamos tambm definir o tipo do valor retornado pelo Joinpoint com o parmetro Type da anotao).

Vejamos o exemplo completo abaixo:

package org.javafree.microncontainer.atomic; import import import import import import import org.codehaus.aspectwerkz.annotation.AfterReturning; org.codehaus.aspectwerkz.annotation.AfterThrowing; org.codehaus.aspectwerkz.annotation.Aspect; org.codehaus.aspectwerkz.annotation.Before; org.codehaus.aspectwerkz.annotation.Expression; org.codehaus.aspectwerkz.definition.Pointcut; org.javafree.microncontainer.util.PersistenciaUtil;

@Aspect("perJVM") public class TrasanctionAspect { @Expression( "execution( @org.javafree.microncontainer.atomic.Transaction * *.*(..))") Pointcut pointcut; @Before("pointcut") public void beginTansactionAdivice() throws Throwable { // Inicializa a Transao PersistenciaUtil.beginTransaction(); } @AfterThrowing( type = "java.lang.Exception", pointcut = "pointcut") public void rollbackTransactionAdivice() throws Throwable { // Aconteceu um erro. Desfaz Transao PersistenciaUtil.rollbackTransaction(); } @AfterReturning("pointcut") public void commitTransactionAdivice() throws Throwable { // Tudo Ok. Comita a transao PersistenciaUtil.commitTransaction(); } }

A voz Java no Brasil Pg. 25

Listagem 1.29 Controle da Transao em AspectWerkz. Note que o AspectWerkz tambm define a anotao @Expression, que pode ser usada como um alas, evitando a redefinio de um mesmo Pointcut em diversos advices. Neste exemplo, simplesmente utilizamos para cada advice os servios de nossa classe utilitria PersistenciaUtil que so correspondentes s operaes transacionais definidas para o nosso aspecto. Usando o JBossAOP: A nica sintaxe definida para anotar advices em JBossAOP @Bind. Assim para obtermos o mesmo comportamento definido no outro framework devemos: chamar, controlar e finalizar a execuo do Joinpoint dentro do nosso Advice. Isto obtido usando o mtodo invokeNext() de Invocation. Veja o exemplo abaixo:

package org.javafree.microncontainer.atomic; import import import import org.jboss.aop.Aspect; org.jboss.aop.Bind; org.jboss.aop.joinpoint.MethodInvocation; org.javafree.microncontainer.util.PersistenciaUtil;

@Aspect public class TransactionAspect { @Bind(pointcut = "execution(* *-> @org.javafree.microncontainer.atomic.Transaction(..))") public Object transactionAdvice(MethodInvocation invocation) throws Throwable { Object retorno; try { //Antes de chamar o mtodo transacional PersistenciaUtil.beginTransaction(); //Chama o mtodo transacional retorno = invocation.invokeNext(); //Depois de executar o mtodo transacional PersistenciaUtil.commitTransaction(); return retorno; } catch (Exception e) { //Aconteceu um erro PersistenciaUtil.rollbackTransaction(); throw e; } }

}
Listagem 1.30 Controle da Transao em JBossAOP. Assim ao executar nosso Joinpoint o fluxo do programa automaticamente desviado para o Advice transactionAdvice() (semelhante anotao @Before do AspectWerkz). Iniciamos com a abertura do contexto transacional e ento chamamos invocation.invokeNext(); que nos redireciona ao Joinpoint. Se a execuo do Joinpoint terminar normalmente, o fluxo novamente desviado para o Advice que controla a transao, quando ento executamos a operao de commit com o mecanismo de persistncia. Note que tambm temos que controlar o lanamento de qualquer

A voz Java no Brasil Pg. 26

exceo que venha ocorrer, definindo um bloco try/catch, onde desfazemos todas as operaes e relanamos a exceo adiante. Qual a melhor sintaxe? Depende. A sintaxe ampliada do AspectWerkz nos da um nvel mas apurado de controle sobre cada advice do aspecto, por exemplo, poderamos: anexar outros comportamentos antes da execuo do Joinpoint (um recurso de Log, por exemplo) apenas acrescentando outro advice com a anotao @Before; ter um controle mais apurado para cada tipo de exceo que fosse lanada (sem alterar o comportamento que j foi definido) compondo tantos advices com a anotao @afterThrowing quantos fossem necessrios, etc.. Porm, a sintaxe simplificada do JBossAOP bem mais intuitiva para quem trabalha com O.O. Basta imaginar que o Advice um Proxy que controla a chamada ao Joinpoint e nossa implementao fica muito parecida com a execuo de um mtodo Java normal. Assim, a escolha pela sintaxe ampliada do AspectWerkz ou simplificada dos dois Frameworks depende do gosto subjetivo do programador. Os iniciantes tendem a gostar mais da sintaxe simplificada por acha - l muito parecida com O.O. J quem est mais acostumado com AOP e requer mais poder e flexibilidade para construir advices de forma encadeada, tende a preferir a sintaxe mais rica do AspectWerkz. Um detalhe, a forma simplificada como foi implementada em nossa soluo com JBossAOP (@Bind), tambm pode ser implementada de maneira semelhante em AspectWerkz com a anotao @AfterFinally ou apenas @After. 3 Uma Fbrica Genrica para Daos, o pacote: org.javafree.microncontainer.dao Talvez a caracterstica mais poderosa da AOP seja: a de permitir que um objeto implemente um interface dinamicamente. Como isto feito? De duas formas: I. Podemos aplicar dinamicamente a um objeto uma interface vazia, como java.io.Serializable, operao chamada de Introduce. II. Podemos aplicar dinamicamente a um objeto uma interface com mtodos, oferecendo outro objeto que ir implement-la, operao chamada de Mixin, muito parecida com a herana mltipla de OO, s que feita de maneira segura. Vamos criar uma Interface Dao, que responsvel pelas operaes CRUD com a mecanismo de persistncia (insero, remoo e atualizao). Vejamos o cdigo abaixo:

package org.javafree.microncontainer.dao; //Representa um Dao Genrico independente de tecnologia public interface Dao { //Salva na Base de Dados public void save(); //Deleta na Base de Daos public void delete(); //Atualiza na Base de Daos public void update(); }

A voz Java no Brasil Pg. 27

Listagem 1.31 Interface que Representa um Dao Genrico. Quem j implementou uma interface com funcionalidades semelhante poderia, neste momento, indagar: Por que os mtodos no recebem parmetros, j que sero persistidos os nossos objetos POJOs? (resumo de Plain Java Object, termo cunhado por Martin Fowler para objetos Java expostos por suas propriedades, i.e, como JavaBeans). A resposta bem simples: por que nossos DAOs sero nossos objetos POJOS! Antes de explicarmos est aparente falha de padronizao, vamos dar uma olhada em nossa classe que expe uma implementao concreta para nossa interface Dao. Como est na moda utilizar uma mecanismo de mapeamento Objeto/Relacional chamemo-no de OrmDao, vejamos o cdigo.

package org.javafree.microncontainer.dao; import java.io.Serializable; //Dao para um mecanismo Objeto/Relacional public class OrmDao { // Salva o objeto na base de dados public void save(Serializable classe) { System.out.println("Salvando " + classe); } // Deleta o objeto na base de dados public void delete(Serializable classe) { System.out.println("Deletando " + classe); } // Atualiza o objeto na base de dados public void update(Serializable classe) { System.out.println("Atualizando " + classe); } }

Listagem 1.32 DAO para um Mecanismo Objeto/Relacional. Veja que aqui j recebemos um objeto e ele serializvel. Est implementao como a anterior para transaes no faz nada, pois quero somente demonstrar que o mtodo est sendo executado (Fica a seu critrio, como exerccio, port-la para seu mecanismo de persistncia especifico). vlido notar tambm que: como as interfaces dos mtodos entre a interface Dao e a classe GenericDao so diferentes, teremos que adapta-ls. Um ponto para quem pensou no padro Adapter do GoF (veja mais sobre padres GoF na referncia [4]), pois nosso aspecto ter que fornecer est funcionalidade. Antes de vermos os detalhes especficos da codificao deste Aspecto, vamos definir o tipo de Token que ele dever interceptar. Pensemos em nosso Joinpoint: Como dito no inicio deste exemplo, mostraremos duas formas de um objeto implementar dinamicamente uma Interface; assim, fica bastante evidente que deveremos marcar um objeto, ou melhor, a classe a que ele pertence, logo, teremos que usar um TokenClass (Marcador de Joinpoints de Objetos).

A voz Java no Brasil Pg. 28

Foi definida ento uma anotao chamada @GenericDao, que ir marcar nossos objetos POJOs, como mostra a listagem abaixo:

package org.javafree.microncontainer.dao; import import import import java.lang.annotation.ElementType; java.lang.annotation.Retention; java.lang.annotation.RetentionPolicy; java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface GenericDao { }

Listagem 1.33 Definio da anotao GenericDao. Como nas anteriores, devemos notar que a anotao interna @Target precisa definir que nossa anotao marca Objetos. Isto obtido definido-a com a enumerao
{ElementType.TYPE}.

Primeiro vamos falar da operao de introduce. Obviamente no queremos obrigar que todos os nossos objetos POJOs sejam serializveis, mas somente aqueles que sero persistentes. Se comearmos a aplicar comportamento especializado e alterar o design plano dos nossos objetos de negcios apenas para acrescentar funcionalidades especficas da aplicao, iremos chegar ao ponto de marcar um objeto com dezenas de interfaces. importante notar que neste caso, para utilizar-mos um interesse ortogonal do sistema (Operaes CRUD com o mecanismo de persistncia sobre objetos POJOs), estamos sendo obrigados amarrar nossas classes de negcios (no uso mais expressivo da palavra interface) a um comportamento que no naturalmente o seu Neste cenrio, uma operao de introduce uma amarrao nica e sob-demanda do objeto, pois feita dinamicamente e para quantas interfaces forem necessrias. Vejamos o exemplo da declarao de um Aspecto que faz uma operao de introduce sob o objeto anotado com o Token @GenericDao, em AspectWerkz (devido s diferenas de sintaxe, o exemplo em JBossAOP ficar para o final deste tpico):

A voz Java no Brasil Pg. 29

package org.javafree.microncontainer.dao; import java.io.Serializable; import org.codehaus.aspectwerkz.annotation.Aspect; import org.codehaus.aspectwerkz.annotation.Introduce; @Aspect("perJVM") public class DaoAspect { @Introduce("within( @org.javafree.microncontainer.dao.GenericDao *..*)") Serializable serializable; }

Listagem 1.34 Uma operao de introduce em AspectWerkz. Aqui cabem algumas observaes:

No exemplo, estamos aplicando a anotao @Introduce ao tipo de nossa anotao (observe que ela requer um within(), que aplicado a um tipo de dado, e no a um elemento de um objeto) com um atributo que uma interface do tipo java.io.Serializable. A anotao @Introduce s pode ser aplicada a um atributo que pertena a uma classe anotada como @Aspect.

Chega de mistrio! Vamos agora definir um aspecto chamado de DaoAspect e mostrar como ele faz a adaptao entre a interface Dao e a classe OrmDao. Isto feito com a anotao @Mixin, que em AspectWerkz une uma definio de um Pointcut a uma interface disponibilizada pelo objeto em que ela est anexada, aderindo dinamicamente sua implementao a um Pointcut, neste caso, qualquer objeto marcado com a anotao @GenericDao. Vejamos o exemplo completo de nosso aspecto:
package org.javafree.microncontainer.dao; import java.io.Serializable; import import import import org.codehaus.aspectwerkz.annotation.Aspect; org.codehaus.aspectwerkz.annotation.Introduce; org.codehaus.aspectwerkz.annotation.Mixin; org.javafree.microncontainer.ioc.Inject;

@Aspect("perJVM") public class DaoAspect { @Introduce("within( @org.javafree.microncontainer.dao.GenericDao *..*)") Serializable serializable;

A voz Java no Brasil Pg. 30

@Mixin(pointcut = "within( @org.javafree.microncontainer.dao.GenericDao *..*)", deploymentModel = "perInstance") public static class MixinDao implements Dao { @Inject OrmDao ormDao; // Objeto que ser salvo Serializable POJO; public MixinDao(Object pojo) { POJO = (Serializable) pojo; } public void save() { // Converte do Dao Genrico para o Dao do Hibernate ormDao.save(POJO); } public void delete() { // Converte do Dao Genrico para o Dao do Hibernate ormDao.delete(POJO); } public void update() { // Converte do Dao Genrico para o Dao do Hibernate ormDao.update(POJO); } } }

Listagem 1.35 Definio completa do Aspecto em AspectWerkz

E importante ressaltar que:

Podemos perceber que est anotao marca especificamente classes e que estas devem implementar a interface que se deseja ser disponibilizada dinamicamente. Estamos aplicando a anotao @Mixin a uma classe interna (que a documentao do framework define como esttica), por termos uma operao de introduce, que como dissemos s pode ser aplicada a uma classe anotada como @Aspect. Obtemos a instncia do nosso objeto POJO no construtor, e depois fazemos sua adaptao implementando os mtodos da interface Dao usando seus correspondentes ao objeto OrmDao. Veja que usamos primeiro uma operao de introduce para converter (cast) o objeto recebido para a interface
java.io.Serializable

Assim, nosso objeto POJO marcado com o Token @GenericDao, dinamicamente, poder ser convertido para a interface Dao com apenas uma operao de converso (cast) para a mesma. Note que nossa classe que faz a adaptao entre as interfaces usa internamente a anotao @Inject para obter uma instncia da classe OrmDao,

A voz Java no Brasil Pg. 31

evitando que este seja criado toda vez que for utilizada pelo objeto POJO numa operao definida para um DAO.

Em JBossAOP: Vejamos as principais diferenas. Em JBossAOP tambm temos a anotao @Introduce, com o mesmo escopo de aplicao da mesma em AspectWerkz, porm neste exemplo, vamos aproveitar a sintaxe mais amigvel do JBossAOP que permite que na anotao @Mixin possamos definir um array de interfaces (no elemento interfaces da anotao) que ser aplicvel sobre uma expresso, como mostrado abaixo:

package org.javafree.microncontainer.dao; import org.jboss.aop.Aspect; import org.jboss.aop.Mixin; @Aspect public class DaoAspect { @Mixin(typeExpression=( class(@org.javafree.microncontainer.dao.GenericDao)"), interfaces={org.javafree.microncontainer.dao.Dao.class, java.io.Serializable.class}) public static OrmExternalizableMixinDao createExternalizableMixinDao(Object pojo) { //Funciona como Adapter entre os Daos return new OrmExternalizableMixinDao(pojo); } }

Listagem 1.36 Definio do Aspecto em JBossAOP.

Neste exemplo valido notar que:

Perceba que, o primeiro argumento da anotao (typeExpression), estamos utilizando uma expresso iniciada por class() que nos devolve a classe que uma anotao referencia, isto porque, o outro atributo que poderia ser utilizado (target) recebe um parmetro do tipo java.lang.Class, que facilmente pode ser retirada de um objeto ou interface Java atravs da operao Objeto.class, porm, no pode ser acessado diretamente atravs de uma anotao, como em nosso caso. Apenas uma das interfaces pode ter mtodos pois s poderemos fornecer um mtodo que retorne o objeto adaptador por anotao @mixin, assim as outras interfaces devem ser todas vazias, ou seja, apenas para marcao de objetos. A classe que implementa a interface Dao, i.e, faz a adaptao da mesma para a classe que representa nosso mecanismo de persistncia, e criada dentro do mtodo anotado como @Mixin para ser usada como retorno do mesmo.

A voz Java no Brasil Pg. 32

Vejamos a implementao de nossa classe adaptadora, em JBossAOP:

package org.javafree.microncontainer.dao; import java.io.Serializable; import org.javafree.microncontainer.ioc.Inject; public class OrmExternalizableMixinDao implements Dao { @Inject OrmDao ormDao; // Objeto que ser salvo Serializable POJO; public OrmExternalizableMixinDao(Object pojo) { //Recebe o objeto que ser salvo POJO = (Serializable)pojo; } public void save() { // Converte do Dao Genrico para o Dao do Hibernate ormDao.save(POJO); } public void delete() { // Converte do Dao Genrico para o Dao do Hibernate ormDao.delete(POJO); } public void update() { // Converte do Dao Genrico para o Dao do Hibernate ormDao.update(POJO); } }

Listagem 1.37 Classe que implementa a interface Dao em JBossAOP. Note que o cdigo desta classe em nada difere da classe interna que foi utilizada no outro framework. 4 - Um pequeno exemplo Como o leitor deve ter notado deixamos o exemplo de utilizao do Microncontaner para o final, visando sobretudo aplicar todas as suas funcionalidades em um s exemplo, demostrando assim a simplicidade que nos oferecida pela utilizao da AOP aliada aos recursos de anotaes. Vejamos o exemplo de nossa classe POJO que ir representar uma pessoa:

A voz Java no Brasil Pg. 33

package test; import org.javafree.microncontainer.dao.GenericDao; @GenericDao public class Pessoa { private String nome; @Override public String toString() { return nome == null ? "Pessoa" : nome; } public void setNome(String nome){ this.nome = nome; }

Listagem 1.38 Definio da classe Pessoa. Note que est classe Pessoa contm apenas uma propriedade chamada nome e, est marcada com a anotao @GenericDao, definido-a como uma possvel candidata a ser persistida como um DAO. Tambm sobrescrevemos o mtodo toString() herdado de Object, para visualizarmos a descrio do objeto em que est sendo aplicado nosso interesse ortogonal. Vamos agora criar uma classe Main, que executar todo o nosso exemplo. A implementao desta classe como na listagem abaixo:

package test; import org.javafree.microncontainer.atomic.Transaction; import org.javafree.microncontainer.dao.Dao; public class TesteMain { @Transaction public static void main(String[] args) { // Cria o POJO Pessoa pojo = new Pessoa (); // Converte para um Dao Dao dao = (Dao) pojo; // Salva no Banco dao.save(); //Atualiza o Objeto no banco pojo.setNome("Alberto"); dao.update(); //Remove o Objeto no banco dao.delete(); } }

Listagem 1.39 Definio do classe Main que executar nosso exemplo..

A voz Java no Brasil Pg. 34

Como se pode notar, nosso mtodo principal main() est marcado com a anotao @Transaction, ou seja, por definio executar em um contexto transacional. Veja que convertemos (com um cast) o objeto da classe Pessoa para a interface Dao, - o que em uma aplicao Java normal ocasionaria uma exceo do tipo ClassCastException (erro de converso entre tipos) por este objeto no implementar explicitamente a interface Dao. Vamos executar nosso exemplo (veja como executar o exemplo no prximo tpico) rodando o script ant. A sada que nos exibida no console e a seguinte:
run: [java] [java] [java] [java] [java] [java]

Iniciando a Transacao: Criou o Objeto org.javafree.microncontainer.dao.OrmDao Salvando Pessoa Atualizando Alberto Deletando Alberto Transacao Efetuada com Sucesso!

BUILD SUCCESSFUL Total time: 3 seconds

Listagem 1.40 Console mostrando a execuo do exemplo.

Todas as operaes acima, foram executadas na ordem correta: primeiro entramos em um contexto transacional. Depois criamos o objeto OrmDao (veja que nosso cache funcionou, pois est foi nica vez que o objeto foi criado); e logo em seguida realizamos as operaes de persistncia (incluso, alterao e remoo). Como tudo ocorreu bem, todas as operaes que foram realizadas durante a execuo do contexto transacional so comitadas e o contexto ento fechado. Finalizando, vou propor ao leitor uma brincadeira interessante. Crie todas as classes de nossos exemplos usando um dos dois frameworks. Compile e s execute usando o script ant. Pois bem, depois do resultado crie todas as classes do framework MicronContainer (menos o pacote test) utilizando o outro framework. Agora copie o pacote test (copie a pasta) criado para o outro exemplo sem nenhuma alterao, para este novo exemplo. Compile e execute atravs do script Ant deste framework, e ento voa l, se voc executou tudo certo ele deve mostrar na tela o mesmo resultado! Acredito que aqui cabe uma ultima pergunta: ser que conseguiramos o mesmo resultado se tivssemos acoplado todas as nossas classes de negcios a implementao de um framework especfico? Sinceramente, acredito que sem nenhuma alterao de cdigo isto seria um pouco difcil. H muito tempo comenta-se que no futuro (sem data somente D.C) a O.O ir produzir componentes que, como na engenharia, sejam intercambiveis entre diferentes sistemas. Como podemos notar, o recurso de anotaes e a AOP do um passo adiante para a realizao deste desejo. Seria interessante que, por exemplo, pudssemos trocar o componente que implementa um servio (como feito aqui) sem alterar as classes que a utilizam: imaginem utilizar os servios de um framework web atravs de uma anotao (@Action, por exemplo) e porta-l conforme haja a necessidade entre diferentes frameworks (de Struts para WebWork). A prxima etapa seria unificar as anotaes que implementam este servio em um padro utilizado por todos: Est, talvez seja a etapa mais difcil, pois cada fabricante de um determinado framework deseja vender a imagem de seu produto como o melhor [Grifos Nossos]. Neste sentido, a especificao do EJB 3 (em partes) d um passo importante, pois

A voz Java no Brasil Pg. 35

padroniza como anotaes: componentes e servios entre os vrios fabricantes, tornando a utilizao de um servidor de aplicaes uma escolha especfica e portvel entre vrios projetos.

Rodando os Exemplos
Vejamos como compilar e executar os exemplos em ambos os frameworks. Para tanto, ser necessria mquina virtual Java na verso 5. Baixe o JDK da Sun no endereo: http://java.sun.com/j2se/1.5.0/download.jsp e veja como configur-lo para seu sistema operacional em: http://www.javafree.org/javabb/viewtopic.jbb?t=849869. Tambm fao uso do ant para automatizar a tarefa de compilao Java e compilao weaving e execuo do aplicativo. Baixe a verso 1.6.5 do ant em http://ant.apache.org/bindownload.cgi. Configure a varivel de ambiente ANT_HOME para seu sistema operacional apontando para o diretrio em que foi descompatado o arquivo e a altere a varivel PATH de seu sistema operacional para que ela aponte para o diretrio %ANT_HOME%\bin (no Windows). Se tudo correr bem inicialize o prompt de comando e digite o comando ant, voc deve receber a seguinte mensagem mostrando que est tudo ok:
Buildfile: build.xml does not exist! Build failed

Listagem 1.41 Execuo que confirma a instalao do Ant. Vamos agora detalhar como configurar especificamente o ambiente para cada framework AOP que foi utilizado em nosso tutorial. Para o AspectWerkz: Crie a estrutura de diretrios mostrada na listagem abaixo:
AspectWerkz src Cdigo-fonte da aplicao META-INF aop.xml lib Todos os arquivos .jar build.properties build.xml

Listagem 1.42 Estrutura de diretrios para o AspectWerkz Coloque todos os fontes do exemplo que criamos para AspectWerkz na pasta src. Baixe o arquivo .zip que contm os arquivos .jars necessrios para o AspectWerkz em: http://aspectwerkz.codehaus.org/releases.html (para os exemplos utilizo a verso 2.0) Descompacte-os e adicione ao diretrio lib da figura anterior, os seguintes fontes da pasta lib do diretrio em que foi descompactado o AspectWerkz:

A voz Java no Brasil Pg. 36

asm-1.5.4-snapshot.jar asm-attrs-1.5.4-snapshot.jar asm-util-1.5.4-snapshot.jar aspectwerkz-2.0.jar aspectwerkz-core-2.0.jar aspectwerkz-extensions-2.0.jar aspectwerkz-jdk5-2.0.jar concurrent-1.3.1.jar dom4j-1.4.jar jarjar-0.3.jar jrexx-1.1.1.jar qdox-1.4.jar trove-1.0.2.jar

Listagem 1.43 Arquivos .jar utilizados pelo AspectWerkz O AspectWerkz diferentemente do JBossAOP requer um arquivo de configuraes chamado aop.xml, que deve ser colocado no diretrio META-INF da aplicao, onde devem estar nomeados todas as classes utilizadas como aspectos, e todas as classes utilizadas em uma operao de mixin. Veja a descrio completa para as classes utilizadas pelo MicronContaner abaixo:

<!DOCTYPE aspectwerkz PUBLIC "-//AspectWerkz//DTD 2.0//EN" "http://aspectwerkz.codehaus.org/dtd/aspectwerkz_2_0.dtd"> <aspectwerkz> <system id="microncontainer"> <aspect class= "org.javafree.microncontainer.ioc.InjectionAspect"/> <aspect class= "org.javafree.microncontainer.atomic.TrasanctionAspect"/> <mixin class= "org.javafree.microncontainer.dao.DaoAspect$MixinDao"> </mixin> <aspect class= "org.javafree.microncontainer.dao.DaoAspect"/> </system> </aspectwerkz>

Listagem 1.44 Arquivo aop.xml Neste exemplo interessante notar que:

A voz Java no Brasil Pg. 37

Os aspectos so definidos pela tag <aspect> e nomeados pelo atributo class da referida tag. As classes de mixin de maneira semelhante so definidas pela tag <mixin> e nomeados pelo atributo class. Note tambm que, classe interna MixinDao referida pelo nome da classe principal seguido do caractere $.

Como descrito, utilizo o ant para automatizar as tarefas de compilao das classes Java, compilao weaving dos Aspectos e para execuo do exemplo. Crie o arquivo build.xml como descrito na listagem 1.38 (abaixo do diretrio raiz /AspectWerkz) como mostra a figura abaixo:
?xml version="1.0" encoding="UTF-8"?> <project name="MicronContainer/AspectWerkz" default="run"> <!-- ======================================= --> <!-- initializes parameters --> <!-- ======================================= --> <target name="init"> <property file="build.properties" /> <property name="basedir" value="."/> <property name="src.dir" value="${basedir}/src"/> <property name="build.dir" value="${basedir}/bin"/> <property name="lib.dir" value="${basedir}/lib"/> <property name="config.dir" value="${basedir}/config"/> <property <property <property <property <property name="javac.debug" value="on"/> name="javac.deprecation" value="on"/> name="javac.optimize" value="off"/> name="javac.depend" value="off"/> name="javac.verbose" value="off"/>

<!-- os specific --> <condition property="pathseparator" value=";"> <os family="dos"/> </condition> <condition property="executableSuffix" value=".bat"> <os family="dos"/> </condition> <!-- os specific --> <condition property="pathseparator" value=":"> <not> <os family="dos"/> </not> </condition> <condition property="executableSuffix" value=""> <not> <os family="dos"/> </not> </condition>

A voz Java no Brasil Pg. 38

<property environment="env"/> <condition property="jdk15" value="yes"> <contains string="${java.version}" substring="1.5"/> </condition> <path id="project.classpath"> <!-- Note: aspectwerkz-jdk5 must be first --> <pathelement location="${lib.dir}/aspectwerkz-jdk5-2.0.jar"/> <fileset dir="${lib.dir}"> <include name="*.jar"/> </fileset> </path> </target> <!--======================================== --> <!-- clean --> <!--======================================== --> <target name="clean" depends="init"> <delete dir="${build.dir}"/> <mkdir dir="${build.dir}"/> </target> <!--======================================== --> <!-- compiles the distribution --> <!--======================================== --> <target name="compile" depends="init"> <javac destdir="${build.dir}" debug="on" source="1.5" target="1.5"> <src path="${src.dir}"/> <classpath refid="project.classpath"/> </javac> </target> <target name="run" depends="clean, compile"> <java classname="${main.class}" fork="yes" failonerror="yes"> <jvmarg value="-javaagent:lib/aspectwerkz-jdk5-2.0.jar"/> <classpath> <pathelement path="${src.dir}"/> <pathelement path="${build.dir}"/> <path refid="project.classpath"/> </classpath> </java> </target> </project>

Listagem 1.45 Script Ant para o AspectWerkz. A linha mais interessante deste arquivo de build : -javaagent:lib/aspectwerkz-jdk52.0.jar que mostra que chamamos um agente (programa que fica rodando em segundo plano capturando um comportamento) disponibilizado pelo AspectWerkz para executar a chamada aos nossos aspectos.

A voz Java no Brasil Pg. 39

Crie tambm o arquivos build.properties que deve conter o caminho em que o arquivo de build do Ant (build.xml) encontrar classe Main (classe principal da aplicao). Veja o exemplo abaixo:
main.class=test.TesteMain

Listagem 1.46 Arquivo build.properties Caso deseje mudar a localizao ou o nome da classe Main, ou seja, da classe que executar a aplicao, apenas troque o que foi mudado no arquivo citado acima. Feito isto execute o comando ant no prompt de seu sistema operacional na pasta raiz /AspectWerkz, e se tudo foi feito da forma correta a aplicao dever ser compilada e executada. Para o JBossAOP: Crie a estrutura de diretrios mostrado na listagem abaixo:
JBossAOP src Cdigo-fonte da aplicao lib Todos os arquivos .jar build.properties build.xml

Listagem 1.47 Estrutura de diretrios para o JBossAOP.

Coloque todos os fontes do exemplo que criamos para JBossAOP na pasta src. Como o JBossAOP faz a decompilao dinmica dos Aspectos, ele no exige nenhum arquivo de configurao complementar. Baixe o arquivo .zip que contm os arquivos .jars necessrios para o JBossAOP em: http://labs.jboss.com/portal/jbossaop/index.html (para os exemplos utilizo a verso 1.3.5) Descompacte-os e adicione ao diretrio lib da figura anterior, os seguintes fontes da pasta lib do diretrio em que foi descompactado o JBossAOP:

A voz Java no Brasil Pg. 40

bsh-1.3.0.jar concurrent.jar javassist.jar jboss-aop-jdk50.jar jboss-aop-jdk50-client.jar jboss-aspect-jdk50-client.jar jboss-aspect-library-jdk50.jar jboss-common.jar jrockit-pluggable-instrumentor.jar pluggable-instrumentor.jar qdox.jar trove.jar

Listagem 1.48 Arquivos .jar utilizados pelo JBossAOP. Crie o arquivo build.xml como descrito na listagem 1.46 (abaixo do diretrio raiz /JBossAOP) como mostra a figura abaixo:
<?xml version="1.0" encoding="UTF-8"?> <project name="MicronContainer/JBossAOP" default="run" > <!-- ======================================= --> <!-- initializes parameters --> <!-- +====================================== --> <target name="init"> <property file="build.properties" /> <property name="basedir" value="."/> <property name="src.dir" value="${basedir}/src"/> <property name="build.dir" value="${basedir}/bin"/> <property name="lib.dir" value="${basedir}/lib"/> <property name="config.dir" value="${basedir}/config"/> <property <property <property <property <property name="javac.debug" value="on"/> name="javac.deprecation" value="on"/> name="javac.optimize" value="off"/> name="javac.depend" value="off"/> name="javac.verbose" value="off"/>

<path id="jboss.aop.classpath50"> <fileset dir="${lib.dir}"> <include name="*.jar"/> </fileset> </path> <path id="classpath"> <path refid="jboss.aop.classpath50"/> <pathelement path="${build.dir}"/> </path>

A voz Java no Brasil Pg. 41

<property name="aop50jar" value="${lib.dir}/jboss-aopjdk50.jar"/> <taskdef name="aopc" classname="org.jboss.aop.ant.AopC" classpathref="jboss.aop.classpath50"/> </target> <!--======================================== --> <!-- clean --> <!--======================================== --> <target name="clean" depends="init">

<delete dir="${build.dir}"/> <mkdir dir="${build.dir}"/> </target> <!--==================================== -->


<!-- compiles the distribution --> <!--======================================== --> <target name="compile" depends="init"> <javac srcdir="${src.dir}" destdir="${build.dir}" debug="on" deprecation="on" optimize="off" includes="**"> <classpath refid="classpath"/> </javac> <aopc compilerclasspathref="classpath" classpathref="classpath" verbose="true"> <classpath path="${build.dir}"/> <src path="${build.dir}"/> <aopclasspath path="${build.dir}"/> </aopc> </target> <!--======================================== --> <!-- run --> <!-- ======================================= --> <target name="run" depends="clean, compile"> <java fork="yes" failOnError="true" className="${main.class}"> <sysproperty key="jboss.aop.class.path" value="."/> <classpath refid="classpath"/> </java> </target> </project>

Listagem 1.49 Script Ant para JBossAOP. Crie tambm o arquivo build.properties que deve conter o caminho em que nosso arquivo de build encontrar nossa classe Main (classe principal da aplicao). Veja o exemplo abaixo:
main.class=test.TesteMain

A voz Java no Brasil Pg. 42

Listagem 1.50 Arquivo build.properties Denovo, caso deseje mudar a localizao ou o nome da classe Main, ou seja, da classe que executar a aplicao, apenas troque o que foi mudado no arquivo citado acima. Feito isto execute o comando ant no prompt de seu sistema operacional na pasta raiz /JBossAOP, e se tudo foi feito da forma correta a aplicao dever ser compilada e executada.

Concluso
Espero ter demonstrado com este escrito um painel dos principais benefcios da AOP, quais sejam: capacidade de criar sistemas de forma mais produtiva, com ganho potencial de qualidade, e que sejam fceis de montar, entender e manter. (LADDAD [1]). importante notar que a AOP de forma alguma torna obsoleta a O.O, ao contrrio, ela a complementa tornando o processo de desenvolvimento mais claro, gil e modularizvel, do que o seria se fosse utilizado somente os princpios da O.O. Por exemplo, para uma plataforma com tantas opes de Frameworks de apoio, como Java, utilizar AOP para desenvolver funcionalidades de nvel do sistema (como Log, Transao, Persistncia, etc..) deve ser to ou mais rpido que ler a documentao do Framework, mais direto que utilizar um XML de Configurao e mais fcil de manter do que utilizar um componente de software fechado, caso contrrio, melhor continuar utilizando o modelo dirigido a componentes e servios. H tambm uma alternativa: utilizar AOP em conjunto com um (ou vrios) Framework(s) para implementar um interesse ortogonal, desacoplando as classes e os objetos que implementam as regras de negcio da dependncia formal e explicita ao mesmo, evitando o Tangled Code. H diversos motivos para utilizar est abordagem, os mais diretos seriam: abstrair complexidade da utilizao de um componente (instanciao, chamada, execuo, etc.), tornar a evoluo das regras de negcio independentes da evoluo da ferramenta e unir diversos Frameworks (principalmente quando suas arquiteturas no sejam facilmente inter-operantes) para fornecer um servio planificado ao sistema. Porm, estes motivos no tornam a AOP essencial por si s, pois todos podem ser obtidos com tcnicas de alto nvel de OO, como Padres de Projeto. Devemos unir estas s qualidades elencadas no pargrafo anterior, quais sejam: clareza, agilidade e fcil modularidade, para que fundamentalmente AOP venha oferecer alguma vantagem sobre a O.O pura.

A voz Java no Brasil Pg. 43

Referncias e Links teis


1 - LADDAD, Ramnivas. I Want my AOP!: Separate software concerns with aspectoriented programming, 2002, Disponvel em: <http://www.javaworld.com/javaworld/jw01-2002/jw-0118-aspect.html> Acesso em: 17 mar. 2006. 2 - KICZALES, Gregor et al. Aspect-Oriented Programming, 1997, Disponvel em: < http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/aop.pdf> Acesso em: 3 mar. 2006. 3 - MARTIN, Fowler. Inversion Of Control: Containers de Inverso de Controle e o padro Dependency Injection, 2004, Disponvel em: <http://www.javafree.org/content/ view.jf?idContent=1> Acesso em: 27 mar: 2006. 4 - GAMMA, Eric et al. Design Patterns: Elements of Reusable Design. AddisonWesley, 1995. 5 - BOCH, Josua. Effective Java: Programming Language Guide. Addison-Wesley, 2001. 6 ARNOLD, K.; GOSLING, J.; HOLMES, D. THE Java Programming Language: Fourth Edition. Addison-Wesley, 2001. 7 - JavaWorld - Tutoriais Bsicos sobre AOP (Ingls) http://www.javaworld.com/javaworld/jw-01-2002/jw-0118-aspect.html 8 - IBM - Srie de artigos sobre AOP (Ingls) http://www-128.ibm.com/developerworks/views/java/libraryview.jsp?search_by =AOP @work: 9 - IBM - Comparao entre os Frameworks AOP para Java(Ingls) http://www-128.ibm.com/developerworks/java/library/j-aopwork1/ 10 - JBossAOP - Artigos e Downloads (Ingls) http://labs.jboss.com/portal/jbossaop/index.html 11 AspectWerkz - Artigos e Downloads (Ingls). http://aspectwerkz.codehaus.org/ 12 - GUJ Introduo a Reflection http://www.guj.com.br/java.tutorial.artigo.10.1.guj 13 - GUJ - Padres de Projeto em Javahttp://www.guj.com.br/java.tutorial.artigo.137.1.guj 14 - GUJ Introduo ao Hibernate http://www.guj.com.br/java.tutorial.artigo.174.1.guj http://www.guj.com.br/java.tutorial.artigo.181.1.guj

A voz Java no Brasil Pg. 44

Вам также может понравиться