Interceptors 2.0

44 views
Skip to first unread message

Lucas Cavalcanti

unread,
Dec 16, 2010, 6:41:36 PM12/16/10
to caelum-vraptor-dev
Olá pessoal,

Hoje em dia, para garantir a ordem de execução dos interceptors temos que implementar o 
RequestExecution com os interceptors do VRaptor e InterceptorSequence para os da aplicação.

o mais chato é qdo a gente precisa de um interceptor que, por exemplo, rode antes de instanciar os parâmetros.
o único jeito é sobrescrevendo o RequestExecution copiando a implementação do VRaptor e modificando. Bem chato.

proponho, então, uma mudança no jeito em que a gente define as ordens dos interceptors. A anotação mudaria para:

@Intercepts(before={Interceptor1.class, Interceptor2.class}, after={Interceptor3, Interceptor4})

e o VRaptor garantiria que essa ordem é respeitada ([math]com uma ordem topologica dos interceptors.[/math])
Assim a interface InterceptorSequence morreria, e o DefaultRequestExecution do jeito que ele está também

o mais legal é que se eu quiser que o meu interceptor rode antes de popular os parâmetros é só anotar o interceptor com

@Intercepts(before=ParameterInstantiatorInterceptor.class)

sem precisar sobrescrever nada do VRaptor.

E se a gente setar o default do before e after direitinho essa mudança é backwards compatível!

Que acham?
Abraços

Sérgio Lopes

unread,
Dec 16, 2010, 7:53:14 PM12/16/10
to caelum-vr...@googlegroups.com
Fantástico! Principalmente a capacidade de executar antes das coisas do VRaptor. É uma versão 100x mais flexível dos PhaseListeners do JSF que interceptam o ciclo de vida do framework. Acho fundamental!



2010/12/16 Lucas Cavalcanti <lucasm...@gmail.com>
--
You received this message because you are subscribed to the Google Groups "caelum-vraptor-dev" group.
To post to this group, send email to caelum-vr...@googlegroups.com.
To unsubscribe from this group, send email to caelum-vraptor-...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/caelum-vraptor-dev?hl=en.

Otávio Scherer Garcia

unread,
Dec 16, 2010, 8:08:10 PM12/16/10
to caelum-vr...@googlegroups.com
Ótimo, excelente idéia.

Rafael Ponte

unread,
Dec 16, 2010, 8:20:54 PM12/16/10
to caelum-vr...@googlegroups.com
Bem interessante, Lucas.

A abordagem antiga seguia a mesma idéia do Spring com seu AOP, correto?

2010/12/16 Lucas Cavalcanti <lucasm...@gmail.com>
--
You received this message because you are subscribed to the Google Groups "caelum-vraptor-dev" group.
To post to this group, send email to caelum-vr...@googlegroups.com.
To unsubscribe from this group, send email to caelum-vraptor-...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/caelum-vraptor-dev?hl=en.



--
Rafael Ponte
http://www.rponte.com.br

Lucas Cavalcanti

unread,
Dec 16, 2010, 8:28:16 PM12/16/10
to caelum-vr...@googlegroups.com
Rafael, não sei qual é a idéia do spring, mas na abordagem atual os interceptors internos do VRaptor
tem uma ordem fixa


e todos os interceptors do usuário rodam no lugar onde está o InterceptorListPriorToExecutionInterceptor

e o jeito de forçar ordem é bem feio (InterceptorSequence ou sobrescrever o RequestExecution)

2010/12/16 Rafael Ponte <rpo...@gmail.com>

Guilherme Silveira

unread,
Dec 16, 2010, 9:20:43 PM12/16/10
to caelum-vr...@googlegroups.com
Muito boa a idéia, genial! Com certeza um avanço de facilidade na
grande parte dos casos de criação de interceptors.

Caçando os corner cases para suportá-los, consigo só pensar em poucos
corner cases que uma ou outra config extra resolvem:

1 e 2 - se desejo rodar um interceptor no (1) começo ou no (2) final do stack.
Meu interceptor desconhece quem é o primeiro atual e quem é o ultimo
atual, mas ele sabe que ele deseja estar na ponta, ele fica sem saber
dizer o before (1) ou o after (2) dele. Ele não saberia quem está (na
instalacao padrao é o FTDVInterceptor, mas não tenho como ter
certeza).
Nota: Só consigo ver vantagem no caso de querer ficar em ultimo da
fila (trocar o algoritmo de FTDV).
Solução simples: permitir dizer: "i am first/last". Problema
envolvido: se dois interceptors dizerem que é first, como resolver o
conflito.

3 - se desejo substituir um interceptor com a minha própria
implementação. Por exemplo, se desejo trocar o
ParametersInstantiatorInterceptor pelo meu próprio, não desejo falar
que é antes ou depois, mas sim "instead", e posso ou não querer
rodá-lo no mesmo lugar que o PII rodaria (muito provavelmente desejo
no mesmo lugar).
Solução simples: extrair interfaces de todos e usar tais interfaces
para todos os befores e afters.

4 - se algum interceptor trocar de lugar com o padrão, os befores que
referenciavam o padrão serão ignorados pelo algoritmo (ou darão erro,
pior), resultando em uma sequência indevida.
Solução simples: extrair as interfaces resolve se todos referenciarem
ela, e não a implementação. Se referenciarem a implementação, pimpa.
Manter suporte simultaneo ao Execution garante.

========

Em questão de implementação, primeiro suportar o registro programático:

interceptors.add(MeuInterceptor.class).before(Outro.class);
interceptors.add(MinhaView.class).at(Position.TAIL);

E usá-lo para suportar a anotação:

interceptors.add(Xpto.class)
.before(annotation.before())
.after(annotation.after())
.at(annotation.at());

Guilherme Silveira
Caelum | Ensino e Inovação
http://www.caelum.com.br/

2010/12/16 Lucas Cavalcanti <lucasm...@gmail.com>:

Lucas Cavalcanti

unread,
Dec 16, 2010, 9:47:00 PM12/16/10
to caelum-vr...@googlegroups.com
1 e 2 - se desejo rodar um interceptor no (1) começo ou no (2) final do stack.
um noop interceptor antes e um depois talvez resolveriam isso... Mas a gente pode convencionar que
o primeiro é o ResourceLookup e o último é o FTDV
Meu interceptor desconhece quem é o primeiro atual e quem é o ultimo
atual, mas ele sabe que ele deseja estar na ponta, ele fica sem saber
dizer o before (1) ou o after (2) dele. Ele não saberia quem está (na
instalacao padrao é o FTDVInterceptor, mas não tenho como ter
certeza).
Nota: Só consigo ver vantagem no caso de querer ficar em ultimo da
fila (trocar o algoritmo de FTDV). 
 
se eu quero trocar o algoritmo do FTDV eu tenho que rodar antes dele (e depois do ExecuteMethod).

Solução simples: permitir dizer: "i am first/last". Problema
envolvido: se dois interceptors dizerem que é first, como resolver o
conflito.
só não resolver o conflito. Deixa aleatório ;)
 
3 - se desejo substituir um interceptor com a minha própria
implementação. Por exemplo, se desejo trocar o
ParametersInstantiatorInterceptor pelo meu próprio, não desejo falar
que é antes ou depois, mas sim "instead", e posso ou não querer
rodá-lo no mesmo lugar que o PII rodaria (muito provavelmente desejo
no mesmo lugar).
Solução simples: extrair interfaces de todos e usar tais interfaces
para todos os befores e afters.
hoje já funciona isso... só criar um @Component ao invés de um @Intercepts que estende o interceptor. 
mas vai ficar mais complicado de tratar nessa solução  nova

4 - se algum interceptor trocar de lugar com o padrão, os befores que
referenciavam o padrão serão ignorados pelo algoritmo (ou darão erro,
pior), resultando em uma sequência indevida.
Solução simples: extrair as interfaces resolve se todos referenciarem
ela, e não a implementação. Se referenciarem a implementação, pimpa.
Manter suporte simultaneo ao Execution garante.
a ordem vai ser colocada no @Intercepts, mas o @Component que sobrescreve não
vai definir ordem... container.instanceFor(Original.class) vai retornar o Custom sempre.
a configuração vai ser sempre no original
 
========
Em questão de implementação, primeiro suportar o registro programático:

interceptors.add(MeuInterceptor.class).before(Outro.class);
interceptors.add(MinhaView.class).at(Position.TAIL);

E usá-lo para suportar a anotação:

interceptors.add(Xpto.class)
          .before(annotation.before())
          .after(annotation.after())
          .at(annotation.at());
 
O mais chato da implementação vai ser implementar na mão o algoritmo de ordem topologica
(não achei pronto pra java o.o)

[]'s

Paulo Silveira - Caelum

unread,
Dec 16, 2010, 9:56:08 PM12/16/10
to caelum-vr...@googlegroups.com
2010/12/17 Lucas Cavalcanti <lucasm...@gmail.com>:

> O mais chato da implementação vai ser implementar na mão o algoritmo de
> ordem topologica
> (não achei pronto pra java o.o)

o ninja lucas reclamando de uma busca em profundidade?? o.o

:)

boa lucas!

Paulo

Lucas Cavalcanti

unread,
Dec 16, 2010, 9:59:51 PM12/16/10
to caelum-vr...@googlegroups.com
2010/12/17 Paulo Silveira - Caelum <paulo.s...@caelum.com.br>

2010/12/17 Lucas Cavalcanti <lucasm...@gmail.com>:
> O mais chato da implementação vai ser implementar na mão o algoritmo de
> ordem topologica
> (não achei pronto pra java o.o)

o ninja lucas reclamando de uma busca em profundidade?? o.o
:P

busca em profundidade + montar um grafo. Nem lembro mais comofas :P

Guilherme Silveira

unread,
Dec 17, 2010, 4:40:30 AM12/17/10
to caelum-vr...@googlegroups.com

github.com/guilhermesilveira/uva-problems tem.mas precisa procurar.

Am 17.12.2010 01:00 schrieb "Lucas Cavalcanti" <lucasm...@gmail.com>:

2010/12/17 Paulo Silveira - Caelum <paulo.s...@caelum.com.br>


>
> 2010/12/17 Lucas Cavalcanti <lucasm...@gmail.com>:
> > O mais chato da implementação vai ser...

:P

busca em profundidade + montar um grafo. Nem lembro mais comofas :P


 
>
>
> :)
>
> boa lucas!
>
> Paulo
>
> > []'s
> >>
> >> Guilherme Silveira

> >> Caelum | Ensino e ...


--

You received this message because you are subscribed to the Google Groups "caelum-vraptor-dev" group...

Guilherme Silveira

unread,
Dec 17, 2010, 4:46:07 AM12/17/10
to caelum-vr...@googlegroups.com

O problema de rodar por último é que você não sabe quem é o penúltimo e último atual.talvez seja o ftdv, mas talvez não, pois você queria substitui-lo, ou pois outro cara substituiu ele.enquanto manter compatibilidade com o executor ignora esse corner, e implementa se pedirem só...

Sobre o instead, com a configuração programática ele consegue mudar a ordem também, resolve isso, certo?

Am 17.12.2010 01:00 schrieb "Lucas Cavalcanti" <lucasm...@gmail.com>:

2010/12/17 Paulo Silveira - Caelum <paulo.s...@caelum.com.br>


>
> 2010/12/17 Lucas Cavalcanti <lucasm...@gmail.com>:
> > O mais chato da implementação vai ser...

:P

busca em profundidade + montar um grafo. Nem lembro mais comofas :P


 
>
>
> :)
>
> boa lucas!
>
> Paulo
>
> > []'s
> >>
> >> Guilherme Silveira

> >> Caelum | Ensino e ...


--

You received this message because you are subscribed to the Google Groups "caelum-vraptor-dev" group...

Rafael de F. Ferreira

unread,
Dec 17, 2010, 6:40:14 AM12/17/10
to caelum-vr...@googlegroups.com
Topological sort FTW.

Sobre a maneira de substituir um dos interceptors, eu acho que seria
legal aproveitar para pensar numa maneira melhor de substituir
componentes em geral. Atualmente o jeito é implementar a interface do
componente e anotar com @Component e usar o fato que o VRaptor dá
preferência para componentes da aplicação sobre os internos. O
problema é que na maioria das vezes (IME) não queremos substituir o
componente inteiro, apenas customizar um pouco. Hoje, para fazer isso
precisamos de heranca de implementacao (blergh); o ideal é claro seria
fazer um decorator.

Já encontrei isso na prática algumas vezes, a última foi para
customizar o xStream na serialização e deserialização. Tive que fazer
uns overrides feiosos de getXStream() por aí, quando a solução mais
legal seria que tivessemos uma XStreamFactory e os usuarios
customizariam o objeto XStream via decorators.

Não pensei muito sobre os detalhes, mas talvez algo assim:
@Component @Decorator
public class XStreamFactoryCustomization implements XStreamFactory {
public XStreamFactoryCustomization(XStreamFactory original) {....

E poderíamos fazer um esquema parecido com a ordenação de interceptors
para dar suporte a múltiplos decorators:
@Component @Decorator(decorates=DefaultFoo.class)
public void MyFoo1 implements Foo {
public MyFoo1(Foo original) {}
}

@Component @Decorator(decorates=MyFoo1.class)
public void MyFoo2 implements Foo {
public MyFoo1(Foo original) {}
}


Um possível problema é que poderiam argumentar que esse tipo de coisa
ficaria melhor como feature do container de DI do que do VRaptor, mas
como a proposta de ordering constraints para interceptors mostra, essa
linha está ficando menos clara.

Cheers
--
Rafael de F. Ferreira.
http://www.rafaelferreira.net/

2010/12/17 Guilherme Silveira <guilherme...@caelum.com.br>:

Rafael Ponte

unread,
Dec 17, 2010, 7:27:14 AM12/17/10
to caelum-vr...@googlegroups.com
Lucas, o Spring ordena seus advices através da interface Ordered, você pode ver aqui, http://static.springsource.org/spring/docs/3.0.x/reference/aop.html - mais especificamente no tópico "7.2.4.7 Advice ordering".

2010/12/16 Lucas Cavalcanti <lucasm...@gmail.com>

Guilherme Silveira

unread,
Dec 17, 2010, 8:21:47 AM12/17/10
to caelum-vr...@googlegroups.com
Ferreira, não seria mais fácil sem anotação?

> @Component
> public class MyFoo1 implements Foo {
>  public MyFoo1(DefaultFoo original) {}
> }

> @Component
> public class MyFoo2 implements Foo {
>  public MyFoo2(MyFoo1 original) {}
> }

Mais limpo, mais claro que você está atrelado ao comportamento desse
cara, mesmo resultado. Só tem que ver como suportar. E no teste, você
teria que passar um cgilibzado desse cara.


Detalhe: como na conversa que tivemos, *tudo* isso se resolveria se a
ordem de registro dos componentes no container fosse programática ao
invés de discovery no classpath, correto? O que acham? Eu ainda to com
essa pulga em relação a suportar *todo* o wiring programatico usando o
"newie".

Abraço

Guilherme Silveira
Caelum | Ensino e Inovação
http://www.caelum.com.br/

2010/12/17 Rafael de F. Ferreira <raf...@rafaelferreira.net>:


> Topological sort FTW.
>
> Sobre a maneira de substituir um dos interceptors, eu acho que seria
> legal aproveitar para pensar numa maneira melhor de substituir
> componentes em geral. Atualmente o jeito é implementar a interface do
> componente e anotar com @Component e usar o fato que o VRaptor dá
> preferência para componentes da aplicação sobre os internos. O
> problema é que na maioria das vezes (IME) não queremos substituir o
> componente inteiro, apenas customizar um pouco. Hoje, para fazer isso
> precisamos de heranca de implementacao (blergh); o ideal é claro seria
> fazer um decorator.
>
> Já encontrei isso na prática algumas vezes, a última foi para
> customizar o xStream na serialização e deserialização. Tive que fazer
> uns overrides feiosos de getXStream() por aí, quando a solução mais
> legal seria que tivessemos uma XStreamFactory e os usuarios
> customizariam o objeto XStream via decorators.
>
> Não pensei muito sobre os detalhes, mas talvez algo assim:
> @Component @Decorator
> public class XStreamFactoryCustomization implements XStreamFactory {
>  public XStreamFactoryCustomization(XStreamFactory original) {....
>
> E poderíamos fazer um esquema parecido com a ordenação de interceptors
> para dar suporte a múltiplos decorators:
>
>

Lucas Cavalcanti

unread,
Dec 17, 2010, 8:34:22 AM12/17/10
to caelum-vr...@googlegroups.com
Vamos lá:
@Guilherme

O problema de rodar por último é que você não sabe quem é o penúltimo e último atual.talvez seja o ftdv, mas talvez não, pois você queria substitui-lo, ou pois outro cara substituiu ele.enquanto manter compatibilidade com o executor ignora esse corner, e implementa se pedirem só...
não dá pra rodar depois do ftdv pq ele não chama o stack.next ;) então ele é o último

@Ferreira
Hoje, para fazer isso precisamos de heranca de implementacao (blergh); o ideal é claro seria fazer um decorator.
Não sei se decorators cobrem todos os casos. 

Um possível problema é que poderiam argumentar que esse tipo de coisa
ficaria melhor como feature do container de DI do que do VRaptor, mas
como a proposta de ordering constraints para interceptors mostra, essa
linha está ficando menos clara.
o spring (acho q o pico tb) consegue fazer decorators em alguns casos, o guice não pq o binding é estático
mas talvez valha a pena tentar fazer uma estratégia dessa no vraptor mesmo

@Ponte
Lucas, o Spring ordena seus advices através da interface Ordered, você pode ver aqui, http://static.springsource.org/spring/docs/3.0.x/reference/aop.html - mais especificamente no tópico "7.2.4.7 Advice ordering".
Pelo que eu entendi o ordering do spring é por valor (número). O que tem hoje no vraptor é programático (adds em uma lista).

@Guilherme
Detalhe: como na conversa que tivemos, *tudo* isso se resolveria se a
ordem de registro dos componentes no container fosse programática ao
invés de discovery no classpath, correto? O que acham? Eu ainda to com
essa pulga em relação a suportar *todo* o wiring programatico usando o
"newie".
Essa é a proposta do Guice, a gente que subverte ela e faz os wirings "automáticos" manualmente


[]'s

2010/12/17 Guilherme Silveira <guilherme...@caelum.com.br>

Rafael de F. Ferreira

unread,
Dec 17, 2010, 8:51:09 AM12/17/10
to caelum-vr...@googlegroups.com
2010/12/17 Lucas Cavalcanti <lucasm...@gmail.com>:

> Vamos lá:
> @Guilherme
>>
>> O problema de rodar por último é que você não sabe quem é o penúltimo e
>> último atual.talvez seja o ftdv, mas talvez não, pois você queria
>> substitui-lo, ou pois outro cara substituiu ele.enquanto manter
>> compatibilidade com o executor ignora esse corner, e implementa se pedirem
>> só...
>
> não dá pra rodar depois do ftdv pq ele não chama o stack.next ;) então ele é
> o último
>
> @Ferreira
>>
>> Hoje, para fazer isso precisamos de heranca de implementacao (blergh); o
>> ideal é claro seria fazer um decorator.
>
> Não sei se decorators cobrem todos os casos.

O jeito que tá hoje pode continuar funcionando. Mas eu acho que
decorators cobrem todos os casos sim :)

Rafael de F. Ferreira

unread,
Dec 17, 2010, 8:58:42 AM12/17/10
to caelum-vr...@googlegroups.com
2010/12/17 Guilherme Silveira <guilherme...@caelum.com.br>:

> Ferreira, não seria mais fácil sem anotação?
>
>> @Component
>> public class MyFoo1 implements Foo {
>>  public MyFoo1(DefaultFoo original) {}
>> }
>
>> @Component
>> public class MyFoo2 implements Foo {
>>  public MyFoo2(MyFoo1 original) {}
>> }
>
> Mais limpo, mais claro que você está atrelado ao comportamento desse
> cara, mesmo resultado. Só tem que ver como suportar. E no teste, você
> teria que passar um cgilibzado desse cara.

Looks good.

>
>
> Detalhe: como na conversa que tivemos, *tudo* isso se resolveria se a
> ordem de registro dos componentes no container fosse programática ao
> invés de discovery no classpath, correto? O que acham? Eu ainda to com
> essa pulga em relação a suportar *todo* o wiring programatico usando o
> "newie".

Não sei se vale a pena mudar o VRaptor nessa direćão. Os usuários já
estão acostumados com DI+classpath scanning.

Lucas Cavalcanti

unread,
Dec 17, 2010, 4:31:22 PM12/17/10
to caelum-vr...@googlegroups.com
Implementado!

quem quiser dar uma olhada:
teoricamente funciona e está backward compatible! =)

quem puder teste por favor!

[]'s
Lucas
Reply all
Reply to author
Forward
0 new messages