Question

I want to create a link that would initiate a file download which would be asynchronous to the page itself, i.e. I want the page not to be locked during the file download. Should I make it be initiated outside wicket? Or is there something inside wicket that would let me set up a resource stream which would bypass the page locks?

Things I tried:

  • DownloadLink - locks the page, as stated in its doc. This was my starting point.

  • ResourceLink - did not state the locking explicitly in the doc, so I tried this, but it also locked the page.

  • At this point I've investigated the code of both links a bit and noticed they both schedule the download via ResourceStreamRequestHandler. Expecting that his kind of behavior could be just handler-specific I've attempted to schedule a custom handler I've written:

    private void sendFile(final File file) throws IOException {
    
        IRequestHandler fileDownloadHandler = new IRequestHandler() {
            @Override
            public void respond(IRequestCycle requestCycle) {
                WebResponse response = (WebResponse) requestCycle.getResponse();
    
                OutputStream outStream = response.getOutputStream();
                response.setContentType("audio/x-wav");
                response.setContentLength((int)file.length());
    
                String fileName = "Somethingsomething.wav";
    
                // sets HTTP header
                response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
    
                byte[] byteBuffer = new byte[1024];
                DataInputStream in = null;
    
                try {
    
                    in = new DataInputStream(new FileInputStream(file));
    
                    int length = 0;
                    // reads the file's bytes and writes them to the response stream
                    while ((in != null) && ((length = in.read(byteBuffer)) != -1))
                    {
                         outStream.write(byteBuffer,0,length);
                    }
    
                    in.close();
                    outStream.close();
    
                } catch (IOException e) {
                     throw new PortalError("IOException trying to write the response", e);
                 }
            } 
    
            @Override
            public void detach(IRequestCycle requestCycle) {
    
            }
        };
    
        getRequestCycle().scheduleRequestHandlerAfterCurrent(fileDownloadHandler);
    
    }
    
  • This did not quite work either, so I've investigated further. I've noticed that unlike I expected, the "scheduled" request handlers would not get executed on a separate request, as I expected, but on the same one. I figured that it must be that the page gets locked for the first handler and then remains locked while the second one is executing as well. So I've attempted to force the download handler into a separate request (via an ajax behaviour):

    public void startDownload(AjaxRequestTarget target) throws DownloadTargetNotFoundException{
    
        target.appendJavaScript("setTimeout(\"window.location.href='" + getCallbackUrl() + "'\", 100);");
    
    }
    
    @Override
    public void onRequest() {
    
        sendFile(getFile());
        logger.debug("Download initiated");
    
    }
    

    I've found this here and hoped it could potentially be what I've been looking for. However, unsurprisingly so, the page gets locked still (I would imagine because the behaviour still has to be retrieved from the page, for which the page lock has to be acquired).

I'm at a loss where I should be looking next, especially after all this time trying to get a simple download link working. I was considering creating another web filter one layer above wicket, which could be signaled from within wicket to create the download after the wicket filter is finished with its work (and hence the page lock is already released), but that seems a bit excessive for a task like this.

Any suggestions are welcome.

Was it helpful?
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top