How to stream generated file download after ajax submit on JSF 2?

3.7k Views Asked by At

I would like to generate a dynamic XML file, after performing a button action method, in JSF 2 and Primefaces.

  • If I enable ajax on that button, the output stream is not downloaded to the client
  • If I desable ajax, the output stream is downloaded sucessfully, but validation doesn't perform as expected

The action method looks like this:

public void someAction() {
    FacesContext context = FacesContext.getCurrentInstance();
    ExternalContext ec = context.getExternalContext();
    try {
        Object someResult = manager.doSomeBusinessLogic();

        String contentType = "application/some-type;charset=utf-8";
        ec.responseReset(); 
        ec.setResponseContentType(contentType);
        ec.setResponseHeader("Content-Disposition", "attachment; filename=\"test.x\""); 

        OutputStream outputStream = ec.getResponseOutputStream();
        writeDataToStream(outputStream, someResult);
    } catch (... ex) {
        log.error("error", ex);
    } finally {
        context.responseComplete();
    }
}

Is there any way to do this having Ajax enabled and having the file downloaded at the end of the request?

Note: I have also tried to use a PhaseListener to intercept the execution, but I don't know how to pass parameters to the request so that the afterPhase is able to process parameters accordingly - and I'd rather not do some redirect in order to enter the PhaseListener. Any ideas?

Edit: I'm using Omnifaces 1.6.3 and Primefaces 5.1.

Here is the xhtml:

<o:form>
    <h:inputText id="field" value="#{bean.someField}" />
    <p:commandButton value="Ajax submit button" action="#{bean.someAction}" />
    <f:phaseListener type="com.company.package.SomePhaseListener"/>
</o:form>

Here is my give-it-a-go at the phase listener implementation; the only limitation is adding the someParam parameter to the HttpServletRequest on the action method.

public class SomePhaseListener implements PhaseListener {

    @Override
    public PhaseId getPhaseId() { return PhaseId.RENDER_RESPONSE; }

    @Override
    public void beforePhase(PhaseEvent event) { ... }

    @Override
    public void afterPhase(PhaseEvent event) {
        FacesContext context = event.getFacesContext();
        HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
        HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
        String someResult = request.getParameter("someParam");
        if(someResult != null) {
            try {
                ExternalContext ec = context.getExternalContext();    
                ec.responseReset(); 
                ec.setResponseContentType(contentType);
                ec.setResponseHeader("Content-Disposition", "attachment; filename=\"test.x\""); 

                OutputStream outputStream = response.getOutputStream();
                writeDataToStream(outputStream, someResult);
            } catch (... ex) {
                log.error(null, ex);
            } finally {
                context.responseComplete();
            }
        }
    }
}
0

There are 0 best solutions below