2

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();
            }
        }
    }
}
nuno
  • 1,771
  • 1
  • 19
  • 48
  • You want to stream the content into the ajax response? This is IMHO not possible and would defeat what AJAX stands for. You send a request and get XML returned to modify the DOM of the displayed page. You might do the validation the AJAX way and then trigger the download with JavaScript. – cheffe Nov 14 '14 at 16:25
  • Have a read here http://stackoverflow.com/questions/25687625/how-to-stream-a-file-download-and-display-a-jsf-faces-message I have had a similar question. – cheffe Nov 14 '14 at 16:27
  • I was trying to download the file only after all ajax processing, and that is why I started meddling with phase-listeners - to intercept an event, after data has been submited and returned a `someResult` value by managers - but the file generation is dependent on the `someResult` value, so I was trying to add that `someResult` in the request parameters, so that the phase listener can intercept the request, get the parameter, and stream the file. Does this make any sense? – nuno Nov 14 '14 at 16:35
  • That's ok. Which additional libraries do you use? Primefaces, Richfaces, etc. Could you add the xhtml portion that belongs to your code? Otherwise it is hard to reproduce your example. – cheffe Nov 14 '14 at 16:39

0 Answers0