1

The user of my application must click on links to view PDF files. I have this problem. PDF file paths are referenced in a remote database. To get the files the idea I came up with is to make a publisher Web Service application, where the remote database is hosted. So when the client clicks on a link, the WS method is called and the publisher gets the physical file from the corresponding folder over there. As I also have a bandwidth issue, I would like to compress the file on the remote server and download it on my server. Since my superiors asked that the file should be shown directly in the browser, I must unzip the file and show it to the client.

After some research I can see that we can download both the PDF and zipped file. Both don't fit my requirement as the first one would affect bandwidth and the second one will give a zipped output.

I plan to implement my WS in REST. Could I have some guidelines please?

http://www.mkyong.com/webservices/jax-rs/download-text-file-from-jax-rs/ file downloading in restful web services

Community
  • 1
  • 1
yovan786
  • 633
  • 1
  • 8
  • 19
  • Please provide some more context for your architectural setup. It reads as if you have 2 servers and then a browser based client, but is not pretty detailed described. It reads like this: a remote server holding the files, then your own server on which you want to fetch the files from the remote server in order to provide the file as a data stream to the browser client. Your are using Javascript and AJAX in the browser in order to do the download call or do you want to simple have links pointing to our REST service URL with the file IDs as the last bit in the URL path? – Michael Jun 21 '14 at 15:03
  • So the client is a user, who clicks on a link on my local web application. My local web application must contact the remote WS server, which has to get the file path from the remote database. After getting the physical file, the WS zips the file and the response back to my server where it will be unzipped. My application then outputs the response to the client in PDF format. I cannot get the file directly from the remote machine. Hence a web service is required. – yovan786 Jun 21 '14 at 15:08
  • and only the last part (serving the pdf to the client) is not clear to you? how big are these PDF files (you say they would affect the bandwidth). – Michael Jun 21 '14 at 15:10
  • I can get the file names from the database. So they will be links and as u said I will pass the ids of the files as a parameter to the WS. – yovan786 Jun 21 '14 at 15:11
  • Yes. I don't know how to just unzip and output the response to my client's browser. The unzip method is no pb. But how to combine the two. The PDF files are of maximun 50MB. I cannot affect the line between my application and the remote server. Too much traffic already there. – yovan786 Jun 21 '14 at 15:12
  • HTTP supports serving content from a server to a browser in compressed format. The browser would understand that if the content type in the HTTP Response Headers are set right – Michael Jun 21 '14 at 15:14
  • I don't have the details at hand, but search for serving content compressed o browser – Michael Jun 21 '14 at 15:14
  • Yes I think I would download the zipped file only. My pb is to unzip and show the PDF file in the browser using the content-type. – yovan786 Jun 21 '14 at 15:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/56030/discussion-between-yovan786-and-michael). – yovan786 Jun 21 '14 at 15:19

2 Answers2

2

I think you have to

Community
  • 1
  • 1
Michael
  • 131
  • 5
2

If I understand your problem correctly, you want to use compression to return the PDF, but you want it to display directly in the user's browser, rather than requiring the user to unzip it and then open it on his desktop.

If you're planning to return a javax.ws.rs.core.Response object, you'll need to set the Variant so it contains an encoding of "gzip". Ideally, you should let JAX-RS examine the Accept-Encoding header of the request and do the proper negotiation using Request.selectVariant; see this question for details.

You will also of course need to zip or gzip your content. There are many ways to do this, but rather than stuffing the entire compressed document into a new file or byte array, I would favor StreamingOutput:

@Path("document/{id}")
@Produces("application/pdf")
public Response getDocument(@PathParam("id") int id,
                            @Context Request request) {

    final File pdfFile = getPdfContent(id);

    Variant.VariantListBuilder variantBuilder =
        Variant.mediaTypes(new MediaType("application", "pdf"));
    List<Variant> allVariants = 
        variantBuilder.encodings("gzip", "identity").build();

    Variant variant = request.selectVariant(allVariants);

    Response.ResponseBuilder response =
        Response.ok().variants(allVariants).variant(variant);

    if (variant.getEncoding().equals("gzip")) {
        response.entity(new StreamingOutput() {
            @Override
            public void write(OutputStream stream)
            throws IOException {
                GZIPOutputStream gzipped = new GZIPOutputStream(stream);
                Files.copy(pdfFile.toPath(), gzipped);
                gzipped.flush();
            }
        });
    } else {
        response.entity(pdfFile);
    }

    return response.build();
}

Edit: Michael points out that as of Java EE 7, you can register a WriterInterceptor to, among other things, wrap a response OutputStream in a GZIPOutputStream. In this case I assume you would have to set the Content-Encoding header yourself, since WriterInterceptorContext does not use Variant.

Community
  • 1
  • 1
VGR
  • 40,506
  • 4
  • 48
  • 63
  • 2
    looks pretty good to me. Not sure about the JAX-RS Variant parts, but the creating of the GZIPOutputStream looks elegant. I found something different part of Jersey called Interceptors where the whole response stream is gzipped by an interceptor. So that way you could reuse the gzipping for other REST services as well - even JSON data structures which then would reduce the transfered data not only for the binary pdfs: chapter 9.3 to 9.5 https://jersey.java.net/documentation/latest/filters-and-interceptors.html – Michael Jun 21 '14 at 15:56
  • Regarding the Content-Encoding header question/assumption. I am not sure to be honest. Here is the link to the JAX-RS javadoc of the WriterInterceptor: https://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/ext/WriterInterceptor.html – Michael Jun 21 '14 at 18:42
  • I'm not sure either. I spent some time looking at the javadoc and some Oracle documentation, but I couldn't find anything that addressed Content-Encoding, which is the reason for my assumption in my edit. – VGR Jun 21 '14 at 20:26