--- title: Utilizando o @ConversationScoped no VRaptor4 --- # Utilizando o @ConversationScoped no VRaptor4 O VRaptor em sua versão 4 utiliza o CDI 1.1 como base. E uma das considerações a serem feitas quando usamos o CDI é o escopo de vida dos objetos. Sempre é preciso escolher com cuidado o escopo, levando em consideração qual vai ser a aplicação do objeto. Utilizar o `@RequestScoped` onde é necessário um `@ApplicationScoped` pode ser desastroso. Um escopo muito util nesse cenário é o `@ConversationScoped` que nos permite um controle maior conforme a nossa necessidade. A aplicação apresentada nesse tutorial está disponivel no GitHub: [ScoreCDI](https://github.com/angeliski/ScoreCDI). Abaixo nosso Controller: ~~~ #!java package br.com.angeliski.controller; import java.io.Serializable; import java.util.Random; import javax.enterprise.context.Conversation; import javax.enterprise.context.ConversationScoped; import javax.inject.Inject; import br.com.caelum.vraptor.Controller; import br.com.caelum.vraptor.Get; import br.com.caelum.vraptor.Post; import br.com.caelum.vraptor.Result; @Controller @ConversationScoped public class HomeController implements Serializable { private static final long serialVersionUID = 943045823176068998L; private Result result; private Conversation conversation; private Integer resultado; private int total; /** * @deprecated CDI eyes only */ protected HomeController() { this(null, null); } @Inject public HomeController(Result result, Conversation conversation) { this.result = result; this.conversation = conversation; } @Get public void index() { } @Get public void game() { if (conversation.isTransient()) { conversation.begin(); } result.include("cid", conversation.getId()); gerarPergunta(); } private void gerarPergunta() { Random random = new Random(); Integer primeiroValor = random.nextInt(100); Integer segundoValor = random.nextInt(100); resultado = primeiroValor * segundoValor; result.include("primeiro", primeiroValor); result.include("segundo", segundoValor); } @Post public void game(Integer resposta) { if (resultado.equals(resposta)) { total++; } gerarPergunta(); result.include("cid", conversation.getId()); } @Get public void fim() { if (!conversation.isTransient()) { conversation.end(); } result.include("total", total); } } ~~~ A primeira distinção desse Controller é a anotação `@ConversationScoped` na classe. Isso indica para o CDI qual vai ser o escopo, mas cuidado: só isso não é suficiente para que a sua classe tenha um escopo maior que o escopo request. Para que o escopo se torne persistente, não perdendo os dados a cada requisição, é necessário injetar um objeto `Conversation` e chamar seu método `begin`. Isso pode ser observado aqui: ~~~ #!java @Get public void game() { if (conversation.isTransient()) { conversation.begin(); } result.include("cid", conversation.getId()); gerarPergunta(); } ~~~ Nesse método a conversação é iniciada. O `Conversation` tem um estado padrão conhecido como *transient*. Quando o método `begin` é acionado ele passa para o *long-running* mantendo os dados até que seja invocado o método `end` do `Conversation`. Só que um detalhe importante deve ser observado. O CDI não tem como saber a qual objeto você está tratando. O único modo dele saber isso é você informando qual o identificador daquela conversação e isso é feito através do pârametro **cid**. É necessário informar na url esse pârametro para que o CDI consiga recuperar o objeto correto. Observe que o pârametro cid é incluido no result para que seja possível utilizar ele na pagina. O nome utilizado para incluir o *id* do `Conversation` no result não é fundamental. Ele poderia ser qualquer um, desde que fosse recuperado corretamente na pagina. Só é fundamental utilizar o pârametro **cid** quando a requisição for enviada para o servidor. Observe como ficou a nossa pagina que vai utilizar esse parâmetro. ~~~ #!jsp <\%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"\%> <\%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"\%> Score CDI

Sessão atual ${cid}

Quanto é ${primeiro} * ${segundo}?

Finalizar! ~~~ Você pode observar que a action do formulário faz o uso correto do **cid**. Quando essa requisição for enviada ao servidor, vai enviar junto o identificador correto. Enquanto a requisição for feita enviando o **cid** o número exibido em Sessão atual vai continuar o mesmo, pois a conversação vai se manter. Você pode fazer um teste acessando diretamente '/home/game' sem enviar o cid no pârametro. Vai ser iniciada uma nova conversação e o cid irá se modificar. Por fim temos o método que encerra o *long-running* através do método `end`: ~~~ #!java @Get public void fim() { if (!conversation.isTransient()) { conversation.end(); } result.include("total", total); } ~~~ Aqui é valido observar que caso você não encerre uma conversação, ela não vai se manter em memória por muito mais que dois minutos, que é o tempo padrão. Isso garante que diferente do `@SessionScoped` os recursos vão ser liberados antes, caso a aplicação não encerre o estado daquele objeto. O timeout pode ser ajustado através do método `setTimeout` conforme a necessidade, mas normalmente não é preciso.