POA - Programação Orientada a Aspectos

Esta página é a compilação de duas pesquisas realizadas sobre o tema de programação orientada a aspectos
A primeira pesquisa foi realizada por Bruno Artur, Everton Mendonça e José Elias em 2007-2
A segunda pesquisa foi realizada por Antonio Cesar, Neidjane e Osmario em 2007-2


Pesquisa realizada por Bruno Artur, Everton Mendonça e José Elias em 2007-2

topo

O que é?

A Programação Orientada a Aspectos (POA) mostra um paradigma novo para facilitar o desenvolvimento de software. Concebida por Gregor Kickzales em 1996 quando trabalhava para a Xerox no Xerox Palo Alto Research Center.

Objetivo

Especialistas em Engenharia de Software têm apresentado muitos problemas de implementação que os paradigmas de programação Orientado a Objetos e procedurais não possuem técnicas triviais para ser resolvidos. Sendo necessário implementar ao longo do código medidas para solucionar tais problemas, gerando um código confuso e muitas vezes redundante.
No intuito de resolver estes problemas que surge o paradigma de programação orientado a aspectos, ou simplesmente POA que visa separar o código de acordo com a sua importância e aplicação. Permitindo a separação do sistema em requisitos funcionais e não-funcionais.

Aspectos

O interesse é um dos elementos da POA. Estes interesses podem ser divididos em uma série de aspectos representando os requisitos do sistema. Após definirmos as responsabilidades do Sistema como um todo, carregamos estas responsabilidades em um módulo chamado aspectos. Logo, a composição de um conjunto de aspectos dentro do limite estabelecido pelo sistema que compõe os interesses funcionais, forma a lógica de desenvolvimento.

AspectJ

O conceito de POA utiliza ainda técnicas de programação OO. Com isso o AspectJ é uma extensão da linguagem Java que permite implementar os aspectos. O AspectJ possui um pré-processador que ajuda a unificar o código de componentes com o código de aspectos. No final obtém-se um programa completo com o programa propriamente dito e os aspectos.

JoinPoints e Poincut

JoinPoints são pontos chaves do código a exemplo de chamadas de métodos, acessos a membros de uma classe entre outras ações de execução. PointCut são agrupamentos de joinpoints seguindo um certo criterio.

O primeiro Pointcut no exemplo chamado “publicMethods” seleciona as execuções de todos os métodos públicos do pacote “org.apache.cactus “. Execution é uma primitiva de pointcut (assim como int é uma primitiva de Java Types.) Ele seleciona a execução de qualquer método que bate com a assinatura definida entre parênteses. Um segundo pointcut chamado “logObjectCalls” seleciona todas as execuções de métodos da classe Logger. Finalmente temos o terceiro pointcut – “loggableCalls” que combina os dois pointcuts anteriores usando && !, ou seja, selecionando todos os métodos públicos em “org.apache.cactus” exceto os que se encontram também na classe Logger (Aplicar as chamadas de log aos métodos da classe logging resultaria em uma recursão infinita.)1

public aspect AutoLog{

  pointcut publicMethods() : execution(public * org.apache.cactus..*(..));

  pointcut logObjectCalls() :

    execution(* Logger.*(..));

  pointcut loggableCalls() : publicMethods() && ! logObjectCalls();

  before() : loggableCalls(){

    Logger.entry(thisJoinPoint.getSignature().toString());

  }

    after() : loggableCalls(){

    Logger.exit(thisJoinPoint.getSignature().toString());

  }

}

Compilação

Os compiladores destinados a programação orientada a aspectos não geram um código final de imediato, mas um novo código.
Na primeira compilação são incluidos elementos no código para dar suporte as abstrações. O código gerado a partir dessa primeira compilação é então recompilado para então ser gerado o código de máquina propriamente dito.

Conceitos de responsabilidades (concerns).

Software são compostos por um conjunto de áreas de interrese, ou responsabilidades, funcionais e não funcionais. Por funcionais entendemos a lógica ou regra de negocio e por não funcionais tomamos as responsabilidades computacionais como persistência, segurança, desempenho e etc. Também existem preocupações rondando do desenvolvimento em si como clareza do código, facilidade de manutenção e etc.

Separação de responsabilidades.

Uma das melhores estratégias para solucionar problemas de grandes proporções e se ter uma visão do todo é fragmentar em partes que possam ser isoladas e tratadas separadamente. Dessa forma podemos melhorar ou reconstruir cada parte sem afetar tanto as outras e mantendo a simplicidade da programação. A Programação Orientada a Objetos nos deu o recurso das classes. Como o foco da POA é separar as responsabilidades, temos que ter mecanismos que implemente esse objetivo, as classes da OOP resolvem a maioria das responsabilidades funcionais mas falham com as transversais (crosscutting concerns).
Usando o paradigma OO as responsabilidades transversais irão ficar espalhadas pela aplicação, em seus diversos módulos, comprometendo assim o desenvolvimento da aplicação, imagine que terememos o memos bloco de codigo em 5 lugares diferentes e quando for necessário fazer alguma alteração/melhoria nesse bloco teremos que alterar em 5 pontos distintos, nesse momento foi introduzido um serio ponto de falha e que pode ser difícil de perceber resultando em um esforço desnecessario de depuração.

Responsabilidades Transversais (Crosscutting Concerns).

Em todo sistema existem modulos que prestão serviços a outros, garantindo assim a reutilização de codigo. As responsabilidades transversais geralmente tem essa caracteriscas, como o objetivo da POA é separar ao maximo, esse tipo de responsabilidade recebe atenção especial e é de dificil isolamento.

Para apronfundar seu conhecimento sobre POA ou AspectJ click aqui.
Caso surja interesse por um livro existe o Programação Orientada a Aspectos em Java.


Pesquisa realizada por Antonio Cesar, Neidjane e Osmario em 2007-2

Programação orientada a aspecto

Em ciência da computação, programação orientada a aspecto ou POA, é um paradigma de programação de computadores que permite aos desenvolvedores de software separar e organizar o código de acordo com a sua importância para a aplicação (separation of concerns). Todo programa escrito no paradigma orientado a objetos possui código que é alheio a implementação do comportamento do objeto. Este código é todo aquele utilizado para implementar funcionalidades secundárias e que encontra-se espalhado por toda a aplicação (crosscutting concern). A POA permite que esse código seja encapsulado e modularizado.

O conceito foi criado por Gregor Kiczales e a sua equipe na Xerox PARC, a divisão de pesquisa da Xerox. Eles desenvolveram o AspectJ, a primeira e mais popular linguagem POA.

Os paradigmas de programação mais antigos, como a programação procedural e programação orientada a objeto, implementam a separação do código, através de entidades únicas. Por exemplo, a funcionalidade de log de dados, numa linguagem orientada a objetos, é implementada em uma única classe, que é referenciada em todos os pontos onde é necessário fazer log de dados. Como praticamente todo método necessita que alguns dados sejam registrados em log, as chamadas a essa classe são espalhadas por toda a aplicação.

Tipicamente uma implementação da POA busca encapsular essas chamadas através de uma nova construção chamada de "aspecto". Um aspecto pode alterar o comportamento de um código (a parte do programa não orientada a aspecto) pela aplicação de comportamento adicional, advice, sobre um "ponto de execução", ou join point. A descrição lógica de um conjunto de join points é chamada de pointcut.

O compilador, o IDE eclipse e um primeiro aspecto

Programas orientados a aspectos precisam de um compilador específico. No caso da linguagem AspectJ, o compilador ajc transforma um programa escrito em AspectJ em um programa em bytecode Java, que pode ser executado por qualquer máquina virtual Java (JVM).

O IDE Eclipse

O Eclipse é um IDE (Integrated Development Environment, ou ambiente integrado de desenvolvimento) gratuito, produzido pela IBM, totalmente desenvolvido usando tecnologia Java.

O Eclipse é extensível através de plugins. Existem inúmeros plugins disponíveis. Um deles, o AJDT, fornece suporte ao desenvolvimento com o AspectJ. As telas a seguir ilustram o uso do Eclipse com o AspectJ (as telas mostram o Eclipse versão 3.0; o laboratório da PUC tem a versão 2.1, então espere que haja pequenas diferenças).

Visão geral do AspectJ

O que é AspectJ?

AspectJ é uma extensão da linguagem de programação Java que permite a implementação de aspectos, alem disso AspectJ conta com um montador que serve para unir o programa de componente com o programa de aspecto.

Depois de definirmos as responsabilidades pertencentes a todo sistema, inserimos essa responsabilidade em um modulo – chamado aspecto, definimos isso usando uma linguagem de aspecto – AspectJ por exemplo, após unimos isso com o sistema propriamente dito, essa união é feita com um montador (weaver). E então temos como resultado dessa união um programa completo – programa + aspectos do programa.

Elementos do AspectJ

Pontos de junção (join points) - um ponto de junção é qualquer ponto identificável pelo AspectJ durante a execução de um programa. O AspectJ permite diversos tipos de pontos de junção: entradas e saídas de métodos, tratamento de exceções, acessos a variáveis de objetos, construtores, entre outros.

Pontos de corte (pointcuts) - pontos de corte são construções de programa que permitem a seleção de um ou mais pontos de junção. Pode-se usar expressões regulares para se especificar os pontos de corte, permitindo grande flexibilidade.

Advice - advice, ou "conselho", é um trecho de código que deve ser executado em pontos de junção selecionados por um ponto de corte. O advice pode ser executado antes, depois, ou "em volta" (around) do ponto de junção. O around pode ser usado para substituir o ponto de junção pelo advice, ou para executar código antes e depois do ponto de junção.

Introduções (introduction) - uma introdução é uma forma de um aspecto introduzir mudanças em classes, interfaces e aspectos do sistema. Por exemplo, pode-se acrescentar uma variável ou método a uma classe existente.
Aspectos - o aspecto é a unidade modular principal em AspectJ, assim como a classe é a unidade principal em Java. Um aspecto agrupa pontos de corte, advice, e introduções.

Alguns Aspectos

O elemento principal do AspectJ é o aspecto. Cada aspecto assemelha-se a uma classe e pode ter tudo que uma classe tem: definições de variáveis, métodos e restriçoes de acesso. Além desses elementos, no entanto, aspectos podem ter outros elementos. Os dois tipos principais de elementos no AspectJ são pointcuts ("pontos de corte") e advice ("conselhos").

Pontos de corte são definições de instantes durante a execução de um programa. Os pontos de corte não tem nehum comportamento; são definições de correspondência (ver aula 6). Eles denotam onde e quando os aspectos terão efeito no programa como um todo.

Um advice é um comportamento. Ele especifica não só o que será feito, na forma de uma sequência de operações Java, mas também o momento em que serão feitas as operações. Todo advice é relacionado a um ou mais pontos de corte.

Vejamos um exemplo de aspecto simples. O aspecto a seguir define um ponto de corte que equivale a uma chamada ao método print da classe Receita. O asterisco no pointcut denota que o ponto de corte se refere a qualquer tipo de retorno, ou seja, ele se refere ao método Receita.print(), não importa qual o tipo do valor retornado pelo método.

public aspect Cabecalho {
// Ponto de corte
pointcut cabecalho() : call (* Receita.print());

// Advice
before() : cabecalho() {
System.out.println("-RECEITA DA COZINHA INTELIGENTE-");
}
}

Além do ponto de corte, o aspecto define um advice do tipo before (antes). Além disso, ele se refere ao pointcut definido anteriormente. Isso significa que o programa definido dentro do advice será executado antes do instante definido pelo pointcut. Como o ponto de corte define o instante da chamada ao método print() da classe Receita, o advice define que antes de cada chamada desse tipo será impressa uma mensagem.

O compilador AspectJ verifica se existe ou não um ponto de corte que case com o definido dentro do aspecto e gera código para aplicar o advice no local apropriado. A mudança no programa é automática. A classe Receita é executada e, sem que haja nenhuma referência ao aspecto, este é executado no instante definido pelo pointcut.

Outros aspectos podem ser acrescentados ao projeto da mesma forma. O aspecto a seguir define um ponto de corte que engloba todos os métodos toString() de todas as classes. O advice presente nele é do tipo around, que significa que o código do advice será executado ao invés do método chamado, ou seja, o método toString chamado não é executado, e sim o código do advice. Este, por sua vez, chama o método proceed() (prosseguir), que é uma palavra-chave do AspectJ que executa o método que foi substituído. Nesse exemplo, o objetivo é chamar o método toString() correspondente ao aspecto e guardar seu resultado na variável s. Depois disso, o método converte o string recebido em letras minúsculas usando toLowerCase() e retorna o string convertido para o método que chamou toString() originalmente.

public aspect NormalizaCaixa {
pointcut string() : call (* *.toString());

String around() : string() {
String s = proceed();
return s.toLowerCase();
}
}

O último aspecto, chamado Debug, define um ponto de corte que inclui todos os métodos do sistema, exceto os do próprio aspecto Debug. O advice associado é do tipo after, que executa após terminar a execução do método correspondente no ponto de corte. O advice usa a técnica da introspecção (ou reflexão), uma tecnologia que permite que um programa descubra fatos sobre sua própria estrutura. Nesse caso, o aspecto está verificando o nome do método que foi chamado e após o qual o advice está executando. Ele então imprime uma mensagem com o nome do método.

public aspect Debug {
pointcut debug() : call(* *.*(..)) && !within(Debug) && !within(NormalizaCaixa);

after() : debug() {
String nomeMetodo = thisJoinPointStaticPart.getSignature().getName();
System.out.println("DEBUG: Saindo do metodo " + nomeMetodo);
}
}

O compilador AspectJ gera bytecode com os aspectos entremeados entre as classes. Só para ter uma idéia de como seria a saída do compilador se este transformasse os aspectos em Java puro, seria algo assim, no caso do primeiro aspecto, "Cabeçalho":
public class Cabecalho {
void before$print( ) {
System.out.println("-RECEITA DA COZINHA INTELIGENTE-");
}
}

public class Receita {

Cabecalho c;

… // parte da classe removida

public Receita() { // construtor
c = new Cabecalho();
}

public void print() {
c.before$print();
System.out.println(this.toString());
}
}

Pontos de junção
Um ponto de junção é qualquer ponto identificável pelo AspectJ durante a execução de um programa. Aspectos podem ser associados a pontos de junção e executados antes, depois, ou ao invés deles. Existem diversos pontos de junção reconhecidos pelo AspectJ:
Métodos
Existem dois tipos de pontos de junção relacionados a métodos: pontos de chamada de métodos e pontos de execução de métodos
Chamada de métodos - São os pontos indicativos de onde, no código, o método é chamado.
Execução de métodos - É o corpo dos métodos propriamente ditos.
Por quê precisamos de dois pontos de junção diferentes? Não bastaria um desses? Eles não são equivalentes?
Na verdade, há uma diferença: como em linguagens orientadas a objetos existe polimorfismo, é possível chamarmos um método de uma classe e executarmos um método de uma de suas subclasses. Assim, é útil fazer a distinção em se tratando de aspectos. Além disso, como a chamada e execução podem estar em arquivos fisicamente diferentes, pode-se gerar pontos de corte compostos onde a diferença entre chamada e execução torna-se mais importante.

Construtores
Assim como métodos, construtores têm dois pontos de junção: um para chamadas ao construtor e outro para a execução do construtor. Pontos de junção de chamada de construtores são encontrados em locais onde um objeto é instanciado com comandos new. Pontos de junção de execução de construtores são o próprio código do construtor.

Acesso a campos
Existe um ponto de junção em cada acesso aos dados de uma classe. Os pontos são divididos em pontos de leitura, onde o dado é usado mas não modificado, e pontos de escrita, onde o dado é modificado.
É importante notar que só há pontos de junção em dados declarados no escopo da classe. Não há pontos de junção para variáveis locais a métodos.

Tratamento de exceções
Um ponto de junção de tratamento de exceções é o interior de um bloco catch que 'captura' algum tipo de exceção.

Inicialização de classes
São pontos de junção que representam o instante em que uma classe é carregada na memória e seus dados estáticos são inicializados.
Há outros tipos de pontos de junção menos usados: inicialização de objetos, pré-inicialização de objetos, e execução de advice.

Conclusão

A programação orientada a aspecto cada dia que passa deixa de ser uma grande promessa para fazer parte do dia-a-dia dos desenvolvedores, ainda que existam detalhes que precisam ser melhor estudado – como a falta de uma metodologia. Mas ainda assim vemos um grande futuro para a programação orientada a aspecto, por dispor de um flexibilidade não disponível na programação orientada a objetos.

Mas como toda tecnologia pode ser pensada para ser utilizada de uma forma e vir a ser utilizada de outra. Queremos acreditar que a AOP não seja utilizada apenas para cobrir furos de maus programas (ou maus desenvolvedores???). Esperamos que a AOP venha a contribuir para facilitar o entendimento de softwares complexos, e que possibilitem a diminuição do esforço necessário para a construção e manutenção desses sistemas.

Referências:

http://www.inf.pucminas.br
http://www.lisha.ufsc.br
http://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_orientada_a_aspecto

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License