AOP dinamica mais tipada

Essa é para quem usa frameworks de AOP dinamico, JAC e AspectWerks por exemplo.

Antes de continuar lendo esse post eu recomento ler o blog do
Rickard Öberg http://www.jroller.com/page/rickard.

Ele fala de uma forma parareduzir o número de casts e boa parte da falta de tipo encontrada em aspectos e mixins.

A idéia é estabelecer um contrato entre as classes sendo aspectadas e os aspects/mixins. Esse contrato seriam interfaces que seriam compartilhadas entre todos. Mas como isso ficaria parecendo?

public interface hasPolicy {
   public void setPolicy(SecurityPolicy policy);
   public SecurityPolicy getPolicy();
}

public interface ResourceLocator {
  Resource locateResource(URL url);
}

Nossa implementação de ResourceLocator exige que o objeto modificado possua uma SecurityPolicy:

public abstract class SecureResourceLocator implements ResourceLocator, 
hasPolicy {
  public Resource locateResource(URL url) {
    Resource r = ...
    r.checkPolicy(getPolicy());
  }
}

e nossa classe que vai receber o mixin:

public class SecureObject implements hasPolicy {
   SecurityPolicy policy;
   public void setPolicy(SecurityPolicy policy) { this.policy = policy; }
   public SecurityPolicy getPolicy() { return policy; }
}

Agora mandamos nosso framework de AOP fazer o seguinte mixin:
classe SecureObject

  • interface ResourceLocator implementação SecureResourceLocator

A dependencia de SecureResourceLocator é resolvida já que SecureObject implementa hasPolicy.

Resultado, o código do mixin ficou muito mais claro alem do maior poder que isso permite. Inclusive, seria possivel usar outro mixin com a implementação de hasPolicy, ela não precisa ficar na classe sofrendo as introductions.

O Rickard implementou essa ideia usando dynamic proxies, porêm esse método possui alguns problemas e limitações.

Implementei hoje um protótipo dessa ideia somente para mixins usando javassist. E funcionou muito bem!

Essa idéia pode ser utilizada também com advices, porêm aqui eu discordo do rickard, ele acha que usar 1 interface Advice com 1 método proceed é melhor que usar diretamente a interface da classe sendo advised, acho o contrario, que fica melhor sem essa interface.

Alguem aqui, alem do cv, já deu uma pensada nessa idéia do rickard?

Pra quem nao entendeu lhufas do que o louds escreveu, http://www.bluebox.com.br/carlos/aop.pdf :wink:

Louds, o que vc acha de:

[code]public class CheckSecurityAdvice extends Advice implements ResourceLocator {

private ResourceLocator target;

public CheckSecurityAdvice(ResourceLocator target) {
this.target = target;
}

public Resource locateResource(URL url) {
System.out.println("Checking security");
// …
Resource r = target.locateResource(url);
// …
System.out.println("End of advice");
}
}[/code]

(Sim, isso eh IoC 3 :D)

A idéia de facilitar o acesso as interfaces das classes sendo alteradas é uma forma de IoC, uma vez que você delega ao framework a preocupação de fazer a ‘cola’ entre chamadas e objetos.

Para diminuir a perda de tipagem em aspectos é fundamental termos o aspecto implementando as interfaces alvos por tornar o acesso aos parametros, valor de retorno e exceptions muito mais consistente.

Com o aspecto implementando as interfaces interceptadas tem que existir a opção dele ser abstrato e só implementar os métodos de seu interesse.

Agora o problema todo é como implementar acesso a classe interceptada.

-Usar uma interface de marcação. Ela teria um método proceed(). Essa é a proposta do Rickard. Problemas: impede a alteração dos parametros e do resultado.

-Usar IoC 3, como sugerido pelo Cv. É uma boa solução, quando precisar chamar um método do objeto basta chamar do objeto delegado. Eu tenho minhas dúvidas se esse método é viavel para deployment models diferentes de per-instance, me parece muito dificil tornar os advices reentrantes para os outros modelos.

-Usar Ioc 1. É uma solução boa, porém é a mais estranha. A idéia é simples, roteamos todas chamadas para as interfaces dentro do aspecto para o objeto em questão:

public class CheckSecurityAdvice implements ResourceLocator {
  public Resource locateResource(URL url) {
    System.out.println("Checking security");
    // ...
    Resource r = locateResource(url); //essa chamada é roteada para o objeto interceptado
    // ...
    System.out.println("End of advice");
  }
}

Fica sim esquisito, mas tem suas vantagens, facil de implementar os vários deployment models e pode acessar mais de uma interface sem a necessidade de ficar usando múltiplas variaveis. A única desvantagem é não poder chamar diretamente os métodos do aspecto que estão nas interfaces.

Li inteiro… mas sem vc para falar sobre os tópicos… não dá para pegar o significado completo de cada item :slight_smile:
Então… dê uma explicação rápida e clara(em 1 pequeno paragrafo) do que é a AOP :roll:
Só para dar uma idéia melhor do que ele faz… li sobre… a muito tempo atraz… e depois que dei uma olhada no seu slide… vi que não era bem aquilo :slight_smile:
:arrow:

Eh perfeitamente viavel - basta ter uma instancia do Advice por instancia do objeto alvo. Per-Thread e Per-Class funcionariam do mesmo jeito (uma instancia dentro de um ThreadLocal e uma instancia só, como se fosse um singleton). O problema mesmo seriam as Per-JVM, uma vez que o Advice implementa a interface do objeto-alvo. Mas de qualquer forma, Per-JVM é na prática igual a Per-Class na maioria dos casos :wink:

Por instancia não tem erro.

[quote=“cv”]
Per-Thread e Per-Class funcionariam do mesmo jeito (uma instancia dentro de um ThreadLocal e uma instancia só, como se fosse um singleton). O problema mesmo seriam as Per-JVM, uma vez que o Advice implementa a interface do objeto-alvo. Mas de qualquer forma, Per-JVM é na prática igual a Per-Class na maioria dos casos ;)[/quote]

O problema aqui é diferente do enfretado por um container de Ioc 3.
Vamos pensar no per-thread que é o mais simples (nenhuma preocupação com locking), o advice fica em uma threadlocal.

Quando ele é instanciado nós passamos um proxy da interface. Então sempre antes de chamar o método nós falariamos pro proxy qual instancia ele tem que delegar as chamadas.

Algo +/- assim:

advice = local_advice.get();
proxy = local_proxy.get();
current = proxy.get();
proxy.set(this_instance);
advice.método();
proxy.set(current);

Usando uma pilha de instancias evita o problema da reentrancia. Perfeito.

Existe um porêm nisso, o advice nunca vai poder usar a instancia do proxy como uma referencia pro objeto sendo interceptado a não ser que usemos uma classe base Advice que tenha um método que a providencie.

Vão existir algums problemas de race conditions nos modelos per-class e per-jvm que ou usasse sincronização, podendo gerar deadlocks, ou threadlocals.

Hmm, ok, Ioc 3 é uma solução clara e tem apenas um porêm, tou convencido. Vou ver se hoje crio um protótipo dessa ideia.

cv, gostei do seu pdf porém fiquei com uma dúvida em relação ao que significa:

:arrow: qeoi;
:arrow: qeok;
:arrow: qeol;
:arrow: ekku;
:arrow: qeon;

Entendi que cada framework de AOP mostrato se relaciona com essas siglas, mas fica minha dúvida quanto ao significado das mesmas!

hasta luego!

Não sou o cv, mas te respondo…
Use http://tinyurl.com/ mais um dos códigos que vc mencionou

fallow

Valeu TedLoprao, eu nem imaginava que aquilo seria um alias para o link dos Frameworks. Eu não sabia nada desse http://tinyurl.com/ , que legal isso!

Valeu mesmo!!

NHAM! Louds’ Aspect Framework entrando no forno, entao? :wink:

hahahaha
dificil sair 1 framework disso
mais provavel ficar no proof-of-concept