Skip to content

Commit

Permalink
Merge pull request #647 from caelum/ot-docseninterceptors-chpk
Browse files Browse the repository at this point in the history
Adding interceptors docs (EN)
  • Loading branch information
garcia-jj committed Jun 30, 2014
2 parents c75d008 + 48c902d commit 3a4e748
Show file tree
Hide file tree
Showing 2 changed files with 207 additions and 13 deletions.
169 changes: 169 additions & 0 deletions vraptor-site/content/en/docs/interceptors.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,172 @@
---
title: Interceptors
---

#When intercept?

Interceptors are used to perform some task before or after a business logic like data validation,
connection control, database transaction, logs and data encryption/compression.

##How to intercept?

VRaptor uses an approach where the interceptor defines who will be intercepted, more closer to the
interception approaches used by <strong>AOP</ strong> (Aspect Oriented Programming).

Therefore, to intercept a request, you need just to annotate the class with the `@Intercepts`. Like any
other component, you can use scoped annotation to define the interceptor life cicle. The default scope
for an interceptor is `RequestScoped`.

##A simple example

The class below shows an example how to intercept all requests in a request scoped and simply show
the console output that is being invoked. Remember that the interceptor is a component like any
other and can receive any dependencies using Dependency Injection.

~~~
#!java
@Intercepts
@RequestScoped
public class Log {

@Inject
private final HttpServletRequest request;

@AroundCall
public void intercept(SimpleInterceptorStack stack) {
System.out.println("Intercepting " + request.getRequestURI());
// code to be executed before the stack

stack.next(); // execute the stack
}
}
~~~

To execute the code just before or after the controller execution, we can use annotations
`@BeforeCall` and `@AfterCall`:

~~~
#!java
@Intercepts
@RequestScoped
public class Log {
@BeforeCall
public void before() {
// code executed before
}

@AfterCall
public void after() {
// code executed after
}
}
~~~

##Defining when intercepting

In the example above, all requests are intercepted. But we can define, as example, only methods
annotated with `@Audit` annotation. You just to implement a method that returns a `boolean` with
the necessary condition and annotate it with `@Accepts`.

~~~
#!java
@Accepts
public boolean accepts(ControllerMethod method) {
return method.containsAnnotation(Audit.class);
}
~~~

Or we can use the more simple way. The example above is a very common case and thus often repeat
this code. For this situation we can use the annotation `@AcceptsWithAnnotations` as described below:

~~~
#!java
@AcceptsWithAnnotations(Audit.class)
public class AuditInterceptor {

@AroundCall
public void around(SimpleInterceptorStack stack) {
stack.next();
}
}
~~~

##Customizing your Accepts

In the example above we used a customized accepts with annotation `AcceptsWithAnnotations`. And if you
need, you can create your custom annotation to define when intercepts. Before you need to create your
annotation like this example below.

~~~
#!java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@AcceptsConstraint(WithAnnotationAcceptor.class)
@Inherited
public @interface AcceptsWithAnnotations {
public Class<? extends Annotation>[] value();
}
~~~

As you can see, we use the Annotation `@AcceptsConstraint` to define the class that have our logic.
Now we need to implement this class.

~~~
#!java
public class WithAnnotationAcceptor implements AcceptsValidator<AcceptsWithAnnotations> {

@Override
public boolean validate(ControllerMethod controllerMethod, ControllerInstance instance) {
//your code here
return true;
}

@Override
public void initialize(AcceptsWithAnnotations annotation) {
//your code here
this.allowedTypes = Arrays.asList(annotation.value());
}
}
~~~

This class needs only to implements `AcceptsValidator<T>` interface, where generic `T` is the type
of your custom annotation.

##How to guarantee the order: after and before

If you need to guarantee the execution order for your interceptors, you can use the `after` and
`before` attributes from the `@Intercepts` annotation. Like the example below, if you have an
interceptor named `FirstInterceptor` that needs to be executed before `SecondInterceptor`, you
can declare like this:

~~~
#!java
@Intercepts(before=SecondInterceptor.class)
public class FirstInterceptor {
...
}
~~~

and:

~~~
#!java
@Intercepts(after=FirstInterceptor.class)
public class SecondInterceptor {
...
}
~~~

You can define one more Interceptor:

~~~
#!java
@Intercepts(after={FirstInterceptor.class, SecondInterceptor.class},
before={FourthInterceptor.class, FifthInterceptor.class})
public class ThirdInterceptor {
...
}
~~~

Note: VRaptor throws an exception if there is a cycle in the interceptors order. So be
careful when you define interceptors order to avoid cicles.

51 changes: 38 additions & 13 deletions vraptor-site/content/pt/docs/interceptadores.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,27 @@

#Quando interceptar?

O uso de interceptadores é feito para executar alguma tarefa antes e/ou depois de uma lógica de negócios, sendo os usos mais comuns a validação de dados, controle de conexão e transação do banco, log e criptografia/compactação de dados.
O uso de interceptadores é feito para executar alguma tarefa antes e/ou depois de uma lógica de
negócios, sendo os usos mais comuns a validação de dados, controle de conexão e transação do
banco, log e criptografia/compactação de dados.

##Como interceptar?

No VRaptor utilizamos uma abordagem onde o interceptador define quem será interceptado, muito mais próxima a abordagens de interceptação que aparecem em sistemas baseados em <strong>AOP</strong> (Programação Orientada a Aspectos).
No VRaptor utilizamos uma abordagem onde o interceptador define quem será interceptado, muito
mais próxima da abordagens de interceptação que aparecem em sistemas baseados
em <strong>AOP</strong> (Programação Orientada a Aspectos). O escopo padrão de um interceptor
é `RequestScoped`.

Portanto, para interceptar uma requisição, basta anotar a classe com a anotação `@Intercepts`. Assim como qualquer outro componente, com o uso das anotações de escopo você pode dizer em que escopo o interceptador será armazenado.
Portanto, para interceptar uma requisição, basta anotar a classe com a anotação `@Intercepts`.
Assim como qualquer outro componente, com o uso das anotações de escopo você pode dizer em que
escopo o interceptador será armazenado.

##Exemplo simples

A classe a seguir mostra um exemplo de como interceptar todas as requisições em um escopo de requisição e simplesmente mostrar na saída do console o que está sendo invocado. Lembre-se de que o interceptador é um componente como qualquer outro e pode receber quaisquer dependências por meio de Injeção de Dependências.
A classe a seguir mostra um exemplo de como interceptar todas as requisições em um escopo de
requisição e simplesmente mostrar na saída do console o que está sendo invocado. Lembre-se
de que o interceptador é um componente como qualquer outro e pode receber quaisquer
dependências por meio de Injeção de Dependências.

~~~
#!java
Expand All @@ -35,7 +45,8 @@
}
~~~

Para executar um código apenas antes ou depois da execução do controller, podemos usar as anotações `@BeforeCall` e `@AfterCall`:
Para executar um código apenas antes ou depois da execução do controller, podemos usar as
anotações `@BeforeCall` e `@AfterCall`:

~~~
#!java
Expand All @@ -53,11 +64,14 @@
}
~~~

Repare que não é mais obrigatório implementar a interface `Interceptor`, basta criar a classe e usar as anotações acima.
Repare que não é mais obrigatório implementar a interface `Interceptor`, basta criar a
classe e usar as anotações acima.

##Definindo quando interceptar

No exemplo acima todas as requisições são interceptadas. Podemos então definir que iremos interceptar apenas os métodos que possuem uma anotação chamada `@Audit`. Para isso basta implementar um método que retorne um `boolean`com a condição necessária e anotá-lo com `@Accepts`.
No exemplo acima todas as requisições são interceptadas. Podemos então definir que iremos
interceptar apenas os métodos que possuem uma anotação chamada `@Audit`. Para isso basta
implementar um método que retorne um `boolean`com a condição necessária e anotá-lo com `@Accepts`.

~~~
#!java
Expand All @@ -67,7 +81,9 @@
}
~~~

No VRaptor4 também temos outra maneira de definir a condição de aceitação. O exemplo acima é um caso bem comum e acabamos tendo de repetir esse código muitas vezes. Para essas situações você pode usar a annotation `@AcceptsWithAnnotations`.
No VRaptor4 também temos outra maneira de definir a condição de aceitação. O exemplo acima é
um caso bem comum e acabamos tendo de repetir esse código muitas vezes. Para essas situações
você pode usar a annotation `@AcceptsWithAnnotations`.

~~~
#!java
Expand All @@ -83,7 +99,9 @@

##Criando o seu Accepts customizado

Logo acima usamos o exemplo do Accepts customizado. Este é um que já vem pronto VRaptor. Mas nada impede de você criar o seu para as suas necessidades. O fluxo é bem parecido com o de criação de uma validação customizada para a BeanValidation. Primeiro você deve criar sua Annotation.
Logo acima usamos o exemplo do Accepts customizado. Este é um que já vem pronto VRaptor. Mas
nada impede de você criar o seu para as suas necessidades. O fluxo é bem parecido com o de
criação de uma validação customizada para a BeanValidation. Primeiro você deve criar sua Annotation.


~~~
Expand All @@ -97,7 +115,8 @@
}
~~~

Perceba que usamos a Annotation `@AcceptsConstraint` para indicar qual a classe responsável por fazer a verificação. Agora precisamos implementar essa classe.
Perceba que usamos a Annotation `@AcceptsConstraint` para indicar qual a classe responsável
por fazer a verificação. Agora precisamos implementar essa classe.

~~~
#!java
Expand All @@ -117,12 +136,17 @@
}
~~~

Esta classe só precisa implemetar a interface `AcceptsValidator<T>` onde T é o tipo da sua Annotation customizada. Dessa maneira você pode criar as suas condições customizadas e disponibilizá-las para todos os projetos que você precisa.
Esta classe só precisa implemetar a interface `AcceptsValidator<T>` onde T é o tipo da sua
Annotation customizada. Dessa maneira você pode criar as suas condições customizadas e
disponibilizá-las para todos os projetos que você precisa.


##Como garantir ordem: after e before

Se é preciso garantir a ordem de execução de um conjunto de interceptors, você pode usar os atributos `after` e `before` da anotação `@Intercepts`. Suponha que o `PrimeiroInterceptor` tenha que rodar antes do `SegundoInterceptor`, então você pode configurar isso tanto com:
Se é preciso garantir a ordem de execução de um conjunto de interceptors, você pode
usar os atributos `after` e `before` da anotação `@Intercepts`. Suponha que o
`PrimeiroInterceptor` tenha que rodar antes do `SegundoInterceptor`, então você pode
configurar isso tanto com:

~~~
#!java
Expand Down Expand Up @@ -153,5 +177,6 @@
}
~~~

O VRaptor lançará uma exception se existir um ciclo na ordem dos interceptors, então tenha cuidado.
O VRaptor lançará uma exception se existir um ciclo na ordem dos interceptors, então
tenha cuidado.

0 comments on commit 3a4e748

Please sign in to comment.