1

In my application the user is able to push a button to create and download a file. The process takes some time, so I want to block the UI during this process until the download window appears.

The action method were I am handling the response looks basically like this:

public void download() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    // set content disposition etc.    
    XSSFWorkbook wb = getWorkbook();
    wb.write(externalContext.getResponseOutputStream());            
    facesContext.responseComplete();
}

In my JSF view I am triggering a blockUI component to disable the button like this:

<p:commandButton value="Doanload" id="b" 
                 action="#{bean.doanload()}"
                 ajax="false" 
                 onclick="PF('crBui').show();"  />
<p:blockUI block=":trGrid" widgetVar="crBui" trigger="b">
     <p:graphicImage value="/images/loading.gif" alt="loading..."/>
</p:blockUI>

I tried to use the PrimeFaces RequestContext to execute some JavaScript to hide the blockUI component, but that does not work. The JavaScript is not executed:

    public void download() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        // set content disposition etc.    
        XSSFWorkbook wb = getWorkbook();
        wb.write(externalContext.getResponseOutputStream());    
        RequestContext.getCurrentInstance()
                      .execute("PF('crBui').hide();");        
        facesContext.responseComplete();
    }

If I am using a ajax call instead of the non-ajax call, then the file download does not work any longer.

Any suggestions how could I archieve my functionality?

2 Answers 2

4

I finally ended up using PrimeFaces 'PrimeFaces.monitorDownload()'

In my view:

<p:commandButton value="Doanload" id="b" 
             action="#{bean.doanload()}"
             ajax="false" 
             onclick="PrimeFaces.monitorDownload(start, stop);"  />

<script type="text/javascript">
    function start() {
        PF('crBui').show();
    }
    function stop() {
        PF('crBui').hide();
    }
</script>

The main trick to get the DownloadMonitor working is to simply set a Cookie in the response:

externalContext.addResponseCookie(
    org.primefaces.util.Constants.DOWNLOAD_COOKIE,
    "true",
    Collections.<String, Object>emptyMap()
);

That way the UI-elements are blocked until the window for the FileDownload appears, which is exactly what I wanted to achieve in the very end.

Sign up to request clarification or add additional context in comments.

1 Comment

Your code helped me to use a commandbutton with ajax="false", but why I need to use org.primefaces.util.Constants.DOWNLOAD_COOKIE?
1

You should use p:fileDownload instead of trying to create some homebrewn solution. Modified example from the showcase:

xhtml:

<script type="text/javascript">
function start() {
    PF('crBui').show();
}

function stop() {
    PF('crBui').hide();
}
</script>

Bean:

import java.io.InputStream;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;

import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

@ManagedBean
public class FileDownloadView {

    private StreamedContent file;

    public FileDownloadView() {       
        InputStream stream = <create your stream>
        file = new DefaultStreamedContent(stream, "<your mime-type>", "<your filename>");
    }

    public StreamedContent getFile() {
        return file;
    }
}

2 Comments

Thank you for your answer, indeed the 'p:fileDownload' component is a good thing, if I rally just want to download a file from the server.But in my case, the Apache POI library works that way that I directly write into an OutputStream but the StreamedContent only takes an InputStream. I had a look into the PrimeFaces source code and found out that it is doing almost the same that I am doing in my Code. So using the PF component here, I would end up writing my file into an ByteArrayOutputStream und write it into an ByteInputStream afterwards just byte by byte ... just to let the PF component
write it byte by byte into an OutputSteam again. Sounds ugly to me. But now I understood how the DownloadMonitor works and now I am able to use this without using p:fileDownload. So thanks again for pointing out the possibility with p:download which gives me the push into the right direction :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.