1

Basically, my system generates url's to download files from my server. I make this using Struts with a result of type 'stream'. This work great. Now I want to notice for each file downloaded, if it was FULLY downloaded.

I've been searching for a while but really don't know how to continue. I'm a beginner with this.

**

New Action:

**

  public String download(){
  try {
            String path = Init.getWebInfPath() + UploadManager.getInstance().getProperty("UPLOAD_DIR") + content.getZipFile();
            file = new FileInputStream(new File(path));
        } catch (Exception e) {
            return ERROR;
        }

        Long overallSize = null;
        try {
            overallSize = file.getChannel().size();
        } catch (IOException e) {
            e.printStackTrace();
        }

        response.setContentType("application/zip");
        response.addHeader("Content-Disposition", "attachment; filename=\""+content.getZipFile()+"\"");
        response.setHeader("Content-Length", String.valueOf(overallSize));

        ServletOutputStream sos = null;
        try {
            sos = response.getOutputStream();
            int read;
            read = file.read();
            while (read>0){
                sos.write(read);
                read = file.read();
            }
        } catch(Exception e){
          return ERROR;      
        }

        return NONE;

}

**

New xml:

**

<struts>
     <package name="content" namespace="/content" extends="default">
    <action name="download" class="com.tictapps.adserver.web.content.ContentAction" method="download">
        <result name="none"/>
    </action>
</package>
</struts>
nosferatu
  • 374
  • 4
  • 14

1 Answers1

1

Once you return the stream result, you've no more control on the OutputStream.

The first ways coming to my mind to ensure that the file is completely downloaded are:

  1. Write directly to the OutputStream, and return the result NONE (that is mapped to nothing) instead of SUCCESS (that you've mapped to Stream). You will have full control on the response, but will lose some of the framework automatisms. This works, I've did it in the past.

  2. Create a custom result based on the Stream result's source code, eg. StreamWithConfirm, and add the logic you need in it.

  3. You could probably do it in a custom interceptor (in the post-invocation part, obviously), but I'm not sure and BTW this would be the hardest of the three for a newbie.

The n. 1 (adapting the code from the linked answer) should be what you need.

Community
  • 1
  • 1
Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243
  • Ok, thanks, I tried to make number 1, but don't know how to continue. Please check the new info. – nosferatu Jan 07 '16 at 18:40
  • 1. Close the ServletOutputStream (better in a finally{} block); 2. How to continue ? When you reach `return NONE;`, the file has been fully downloaded! Do what you need to do the line before that return ;) Also remember to upvote and accept the answer when you'll be comfortable with it. – Andrea Ligios Jan 08 '16 at 09:14
  • I'm sory but this way I always download a 5 bytes file (invalid). The download appears in the Chrome bar when sos is closed, but it only starts to download after return line. – nosferatu Jan 08 '16 at 14:27
  • And after that I get this error: org.apache.struts2.dispatcher.Dispatcher error GRAVE: Exception occurred during processing request: No puedo llamar a sendError() tras llevar a cabo la respuesta java.lang.IllegalStateException: No puedo llamar a sendError() tras llevar a cabo la respuesta at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:450) at org.apache.struts2.dispatcher.ServletDispatcherResult.doExecute(ServletDispatcherResult.java:150) at org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:186) at ... – nosferatu Jan 08 '16 at 14:28
  • Then you're doing something wrong. Please update your code with the latest additions – Andrea Ligios Jan 08 '16 at 14:32
  • Well, 1) you are NOT flushing and closing any `sos`, and 2) you are still mapping "none" to something. You don't need to map it to anything, returning Action.NONE means *"don't return any result"*. Use an empty (or self closing) action in struts.xml – Andrea Ligios Jan 08 '16 at 14:53
  • 1
    AWESOME. It worked! Also I was reading from fil while>0 (it had to be !=-1). Final question: if sos.close line is reached, you can assure that the file was delivered correctly? – nosferatu Jan 08 '16 at 15:27
  • You can assure that *everything has been sent and no error has been thrown*, that I guess is enough for what matters to you. Other than that, I'm not sure when an error is thrown, eg. what happens if the file is downloaded in a damaged section of the hard drive, but that's OS-dependent. For example in DOS when you copied files with "copy foo.txt bar.txt", foo were copied into bar without checks, and you'd discovered that the bar file was corrupted only after opening it – Andrea Ligios Jan 08 '16 at 16:11