Search code examples
jakarta-eeservletsdownloadjsf-2.2ajax4jsf

Why JSF implementation invoked response.getWriter() during file upload/download?


This is my first question on SO.

I would like to create reporting file immediately after importing other file with some business elements.

After choosing import file with h:inputFile, I trigger Bean action with h:commandButton and nested a4j:ajax:

FacesContext facesContext = FacesContext.getCurrentInstance();

        try {
            HttpServletRequest req = (HttpServletRequest) facesContext.getExternalContext().getRequest();
            HttpServletResponse res = (HttpServletResponse) facesContext.getExternalContext().getResponse();
            byte[] byteSourceExcelFile = IOUtils.toByteArray(sourceExcelFile.getInputStream());
            req.setAttribute("excel", DatatypeConverter.printBase64Binary(byteSourceExcelFile));

            RequestDispatcher dispatcher = req.getRequestDispatcher("importReport.jsf");  
            dispatcher.forward(req, res);
        } catch (IOException e) {
            FacesUtils.createErrorMessage(e.getMessage(), null, msgs);
        } catch (ServletException e) {
            FacesUtils.createErrorMessage(e.getMessage(), null, msgs);
        } finally {
            facesContext.responseComplete();
            fileClear();    
        }

Request is forwarded to servlet, where import works well, but when I try to obtain object needed for output binary data:

ServletOutputStream outputStream = response.getOutputStream(); 

I get error:

 org.apache.myfaces.view.facelets.el.ContextAwareELException: javax.el.ELException: java.lang.IllegalStateException: SRVE0209E: Writer already obtained

I debugged servlet code and noticed that field _gotWriter is true in response object. This indicates that:

PrintWriter outputStream = response.getWriter();

is called. None of my filters did it. Also, other servlets which are used for obtaining data works fine.

Using MyFaces 2.2.3 as shared library on WebSphere 8.5.5.

Mechanism described above works with Websphere 7 JSF implementation (Sun-RI 1.2) and Richfaces (3.3.3) component rich:fileUpload.

  1. What are possible causes of described state of response object?
  2. Is there any way to replace PrintWriter object with ServletOutputStream object?

I hope this is appropriate way of asking question. I will appreciate any suggestions.


Solution

  • It is all about a4j:ajax nested in h:commandButton. It turns out, that this was cause of invoking response.getWriter() in the middle of request processing (I still don't know where and why).

    <h:commandButton action="#{listBean['processImport']}" > 
        <a4j:ajax  oncomplete="js();" execute="fileUploadId" render="fileUploadId"/>
    </h:commandButton>
    

    I removed a4j:ajax and file download works as it is supposed to.

    <h:commandButton action="#{listBean['processImport']}" onclick="js();"> 
    </h:commandButton>
    

    Now I need to figure how to update desirable elements on jsf page. But it's other story...

    Appendix: JSF 1.2

    It is worth to mention, that before migration from WAS-7 (Sun-RI 1.2) to WAS-8.5.5 (MyFaces 2.2.3) above mechanism works with combination:

    <h:commandButton action="#{listBean['processImport']}" > 
        <a4j:support  oncomplete="js();" reRender="fileUploadId"/>
    </h:commandButton>
    

    but did not work with:

    <a4j:commandButton action="#{listBean['processImport']}" oncomplete="js();" reRender="fileUploadId" />
    

    EDIT: After last IE security update 14-037 (KB2962872) file is received by browser, but cannot be opened or saved anymore.