10

I am writing a web service using Java JDK 1.7 and Jersey Web service Framework. One of the things I need to provide is a way to allow authenticated clients to download certain large data files ( 1-3 GB). Ideally I would like this to be a pause and resume type downloadable option. I tried the jersey multi-part API and was able to get it to work on my client machine upto 400 MB but beyond that it ran into out-of memory issues. I am also worried that the server might fail when faced with simultaneous download requests. Any thoughts on how this can be done? Is Netty an option? Any pointers on how Netty can be integrated into a existing Jersey based web service? Are there other frame works available to help accomplish this? I do have to use java for the web service. Any pointers will be helpful.

Rashkar
  • 101
  • 1
  • 1
  • 3
  • Maybe the accepted answer can help you too: http://stackoverflow.com/questions/10326460/upload-a-large-file-using-jersey-client – Eich Feb 20 '13 at 11:08
  • Is it an option to "outsource" this to sftp or ftps? The serverside could then be managed by a standard ftp-server-application. On Client Side there sure are ready-to-use components. – Fildor Feb 21 '13 at 09:32
  • Since it is only download: let the webservice provide a http: link to some webserver (apache httpd for example) that only serves the file. If you proxy through apache httpd it can also do authentication for you. – John Smith Feb 21 '13 at 11:55
  • How did you solve the issue? – gkiko Jun 29 '15 at 17:52

2 Answers2

6

If you are getting stuck on out-of-memory issues, you should check how you are handling the data you are downloading. If you are using Jersey's ClientResponse, make sure you are using getEntityInputStream() and not getEntity(). This way, you can stream the data, write it to file, and toss it aside, rather than letting it build up in the Java heap space.

I can't really speak about your simultaneous download concerns, but if you are using the web services framework, then it should be handled properly.

For both issues, more info on your specific implementation, especially code, will help you get a better response.

tdn120
  • 181
  • 5
2

The server and the client must both support HTTP chunked encoding which allows one to stream data using HTTP. The code below should work with Jersey 2.11.

For downloading large files, try this on the server:

@GET
@Path("/files/{fileName}")
@Produces(MediaType.APPLICATION_OCTET_STREAM)

public StreamingOutput getFile(@PathParam("fileName") final String fileName)  throws Exception  {
  //create instance of StreamingOutput here
  return streamingOutput;
}

Try this for a client GET request using steams to download a file.

public String getFileReq(File outFile) throws IOException {

  client = ClientBuilder.newClient(new ClientConfig());
  client.property(ClientProperties.REQUEST_ENTITY_PROCESSING, "CHUNKED");
  WebTarget target = client.target(URI)
  OutputStream fileOutputStream = new FileOutputStream(outFile);
  InputStream fileInputStream = target.request().get(InputStream.class);
  writeFile(fileInputStream, fileOutputStream);    

}

public static void writeFile(InputStream fileInputStream, OutputStream outputStream) throws IOException {
try {
  byte[] buffer = new byte[1024];
  int bytesRead;

  while((bytesRead = fileInputStream.read(buffer)) !=-1) {
      outputStream.write(buffer, 0, bytesRead);
  }

  fileInputStream.close();
  outputStream.flush();
 } catch (IOException e) {
   e.printStackTrace();
 } finally {
   outputStream.close();
}
rschmidt13
  • 349
  • 3
  • 3