7 Replies Latest reply on Jul 29, 2009 2:31 AM by gturek

    How to detect file download has been cancelled?

    gturek

      I have implemented file download as demoed on http://seamframework.org/Documentation/HowToUploadAndDownloadFilesInSeam. Because I am tracking downloads, I need to detect if a download has been cancelled so I don't create an entry in my db for it. How do I do that?
      Thanx
      Gaby

        • 1. Re: How to detect file download has been cancelled?
          kragoth

          I dont think you can actually detect it client side. I could be wrong but I don't think you can.


          I'm not sure if this is a possible solution as I'm just thinking out loud here. But, couldn't you go to the servlet that delivers your files and get it to write to the database only if the entire stream is sent. If the user aborts the connection then your stream wont complete and thus you don't write to the database.


          I don't know how you do this, but it's just something I'm thinking about. Maybe you can see if this will work for you.

          • 2. Re: How to detect file download has been cancelled?
            gturek

            That was my thinking too, and I was hoping that canceling would cause an IOException but it does not seem to be the case. I will have to track the amount of bytes sent... Hum
            Gaby

            • 3. Re: How to detect file download has been cancelled?
              kragoth

              Could you let us know how you go with this please?
              I know I would be interested in seeing a solution, and I'm sure a lot of other people would be interested too.


              Cheers,
              Tim

              • 4. Re: How to detect file download has been cancelled?
                gturek
                You can be sure if I have a breakthru you'll know about it. Well, the approach of tracking bytes sent does not work. the moment the user the hits the download link the whole file is copied from input stream to output stream in one go. Cancelling arrives too late, so to speak. Here is my code, for sanity sake. The next step is to go into debug mode I suppose and see what exactly happens when one hits cancel. Is there another
                way to do a download perhaps?


                public void downloadModule(Module selectedModule) throws ModuleProcessingException {

                    ... Stuff here to get Uri of file ----

                    File outGoing = new File(archiveRoot + "/" + uri);
                    long fileSize = outGoing.length();


                    HttpServletResponse response = (HttpServletResponse) extCtx.getResponse();
                    response.setContentType("text/plain"); // Placeholder
                    response.addHeader("Content-disposition", "module; filename=\"" + fileName + "\"");

                    ServletOutputStream out = null;
                    FileInputStream in = null;
                    try {
                      out = response.getOutputStream();
                      in = new FileInputStream(outGoing);
                      int bytesWritten = FileUtils.copy(in, out);
                      System.out.println("********** bytesWritten " + bytesWritten);
                      out.flush();
                      out.close();
                      in.close();
                      facesContext.responseComplete();

                      //Doesn't work! copying happens as soon as link is clicked...

                      if (bytesWritten == fileSize) {
                        downloadRecord = new DownloadRecord();
                        downloadRecord.setModuleVersion(moduleVersion);
                        downloadRecord.setDownloadDate(new Date(System.currentTimeMillis()));
                        downloadRecord.setDownloadedBy("auser"); // TODO: get user
                        entityManager.persist(downloadRecord);
                      }

                    } catch (Exception e) {
                       log.fatal("Exception while downloading " + module.getModuleId() + ": " + e.getMessage());
                      throw new ModuleProcessingException(e.getMessage());
                    } finally {
                      try {
                        in.close();
                        out.close();
                      } catch (IOException ioe) {
                        // Nothing to do
                      }
                    }

                The FileUtils.copy code

                public static int copy(InputStream is, OutputStream os) throws IOException {
                    byte[] buffer = new byte[1024 * 1024];
                    int total = 0;
                    for (int i = is.read(buffer); i > -1; i = is.read(buffer)) {
                      os.write(buffer, 0, i);
                      total += i;
                    }
                    return total;
                  }



                • 5. Re: How to detect file download has been cancelled?

                  Gabriella Turek wrote on Jul 03, 2009 02:02:


                  You can be sure if I have a breakthru you'll know about it. Well, the approach of tracking bytes sent does not work. the moment the user the hits the download link the whole file is copied from input stream to output stream in one go.



                  That is... not entirely accurate,  you should say: the moment the user the hits the download link I copy the whole file, and after I finish I try to see if it was sent ;-). You make it that way, with the line:


                  
                  int bytesWritten = FileUtils.copy(in, out);
                  
                  



                  That is when your code copies the whole file in one go, inside FileUtils.copy you do that with a loop (guess that is when you could detect if something is failing, perhaps by flushing each time you send a chunk of the file to the response)


                  And then you even say that you only one to flush at the and... and that you have finished responding:


                        out.flush();
                        out.close();
                        in.close();
                        facesContext.responseComplete();
                  



                  Any checking you do after that is pointless. You have already told the system that the response is Complete

                  • 6. Re: How to detect file download has been cancelled?
                    gturek

                    Yep, you're absolutely right, I need to tweak my copy code and see if I can detect an interrupt. I tried it before expecting some kind of IOException but nothing. Perhaps I need to copy smaller chunks and flush more often, I'll give a go when I get back to work (sick now)

                    • 7. Re: How to detect file download has been cancelled?
                      gturek

                      Still working on this. It turns out that without the facesContext.responseComplete(); line the code does not work. I get the error message

                      An Error Occurred:
                      Servlet response already use stream, Writer not possible


                      and never get the download popup.


                      So I am completely stumped.
                      Gaby