Nesse exemplo usaremos os conceitos interceptor, injeção e ejeção. Leia as documentações correspondentes primeiro.
Se você precisar o OutputStream para enviar um arquivo ao usuário na sua lógica de negócios, você deverá usar as idéias anteriores para criar um simples, rápido e poderoso jeito de atingir a tarefa.
Nós vamos criar um wrapper (ClientOutput) que delega as suas requisições para a HttpServletResponse. Assim nós não misturamos a camada de apresentação com a camada de lógicas de negócios.
O objeto ClientOutput será injetado na lógica usando um interceptor. Nada mais.
Primiero vamos usar o padrão delegate para acessar OuputStream e ContentType:
package org.vraptor.util; /** * permite acesso para OutputStream and ContentType */ public class ClientOutput { private HttpServletResponse response; public ClientOutput(HttpServletResponse response) { super(); this.response = response; } public ServletOutputStream getOutputStream() throws IOException { return response.getOutputStream(); } public void setContentType(String type) { response.setContentType(type); } }
Agora vamos criar o DownloadInterceptor que ejetará o ClientOuput.
O objetos da requisição (response e request) são injetados por padrão. Usaremos o getter para ejetar o clientOutput com a chave do nome completo da classe ClientOutput.
package org.vraptor.util; public class DownloadInterceptor implements Interceptor { private HttpServletResponse response; public DownloadInterceptor(HttpServletResponse response) { this.response = response; } private ClientOutput clientOutput; public void intercept(LogicFlow flow) throws LogicException, ViewException { this.clientOutput = new ClientOutput(this.response); flow.execute(); } @Out(key="org.vraptor.util.ClientOutput") public ClientOutput getClientOutput() { return this.clientOutput; } }
Como você pode ver, usando a idéia da injeção de dependência, criamos o interceptor, injetamos o objeto da resposta (response) e o método intercept será chamado. O método cria nosso wrapper clientOutput.
No final, o objeto clientOutput é ejetado pelo getter.
Agora vamos usar o interceptor na lógica e injetar o objeto clientOutput.
@Component("report") @InterceptedBy( DownloadInterceptor.class ) public class RelatorioDeContratosLogic { private ClientOutput clientOutput; public RelatorioDeContratosLogic(ClientOutput clientOutput) { this.clientOutput = clientOutput; } @Viewless public void sample() throws IOException { clientOutput.setContentType("application/pdf"); // gera um pdf usando o output stream new ReportGenerator().outputTo( this.clientOutput.getOutputStream() ); } }
Se você se perguntar porque precisou criar a classe ClientOutput e porque VRaptor não a incluiu por padrão, a razão é bem simples ...
Se o VRaptor criasse a classe, ele deveria ser bem flexível, como alguns programadores necessitariam de diferentes métodos para delegar, outros não.
Finalmente, o VRaptor incluiria uma classe enorme ClientOutput com métodos que a grande maioria dos programadores não precisariam.
Se algumas alterações fossem necessárias, seria quase impossível, porque muitos programadores já implementaram a classe.
Se você entendeu o conceito da injeção de dependência e a delegação, você aprendeu a idéia do exemplo e viu que não foi difícil atingir o resultado.
E além disso você tem o controle sobre as suas classes.