Exemplo de download do arquivo binário

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.

OutputStream e ContentType

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);
        }

}

O interceptor

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.

A lógica de negócios

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()
                                );
        }

}

Mas porque preciso fazer tudo isso?

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.