Binary file download example

This example uses the interceptor, injection and outjection concepts. Read those documents first.

Those who need to use the client OutputStream to send a file to the user in your bussiness logic (which might be ugly) should combine the previous ideas to get a simple, fast and powerfull way to accomplish this task.

We are going to create a wrapper (ClientOutput) which delegates to HttpServletResponse its requests, this way we "don't attach the Business Layer with the Presentation Layer".

A ClientOutput object is injected in our business logic using an Interceptor and that's it!

OutputStream and ContentType

First of all, let's use the delegate pattern to access the OuputStream and ContentType:

package org.vraptor.util;

/**
 * Client output: allows access to 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);
        }

}

The interceptor

Now let's create the DownloadInterceptor which outjects the ClientOuput.

The request and response objects are injected by default so we can inject this in our interceptor. We use the getter for outjection and specify the key using the fully qualified name of the ClientOutput class.

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

}

As you can see, only by using the dependency injection idea, the download interceptor will be instantiated, the response injected and the intercept method called... this instantiate the client output.

After that, the clientOutput is outjected through the getter.

The business logic

Now we setup the interceptor in our component and inject the 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");

                // generate some random pdf report using the output stream
                new ReportGenerator().outputTo(
                        this.clientOutput.getOutputStream()                             );

        }

}

Why do I have to do all this?

If you are questioning yourself why you have to create the ClientOutput class and VRaptor did not create it in it's default package the reason is simple...

If VRaptor would create this class it would have to be quite flexibe as some people would need other delegate methods to be available... others wouldn't...

VRaptor would end up with a huge ClientOutput class with methods which wouldn't be used by most people.

If any changes had to occur in this class, for any reason, it would be impossibly as most people would be already attached to it...

If you understand the conpect behind dependency injection and delegation you got the whole idea of this example and you saw that it's quite easy to achieve such result.

And you still have control of your classes...