开发者

In jsf 1.2, defining a locale from bean causes IllegalStateException in getOutputStream

I'm trying to understand how this happens and how to solve it. I have a jsf request bean with a jsp page that looks like this: (Summarized)

<f:view locale="#{drcBean.userLocale}">
</f:view>

the backing bean code:

public Locale getUserLocale() {
    return new Locale("en");
}

And finally, when the session is started this method is called (Which sends a file to the client)

private void sendFile()
{
        byte[] config = ...;
        String clientFileName = "iphone.mobileconfig";

        // Prepare.
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();开发者_运维问答
        HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();

        // File file = new File(getFilePath(), getFileName());

        BufferedInputStream input = null;
        BufferedOutputStream output = null;

        try {
            // Open file.
            ByteArrayInputStream bais = new ByteArrayInputStream(config);
            input = new BufferedInputStream(bais);

            // Init servlet response.
            response.reset();
            response.setContentType("application/x-apple-aspen-config");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + clientFileName
                    + "\"");
            response.setContentLength((int) config.length);

            // if (logger.isTraceEnabled()) {
            // logger.trace("Writing XML Script:" + new String(scriptDataByteArray));
            // }


            output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);

            // Write file contents to response.
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
            int length;
            while ((length = input.read(buffer)) > 0) {
                output.write(buffer, 0, length);
            }

            // Finalize task.
            output.flush();
        } catch

I get an IllegalStateException exception calling response.getOutputStream() The thing I don't get is that this doesn't happen if locale="#{drcBean.userLocale}" is not defined. (Meaning, I omit the locale tag of the view and the problem disappears)

  • One more evidence is that the file I do receive eventually is the JSP page mentioned which in my opinion means that a new page was sent somehow and aborted the file sending. But what does this have to do with locale?

  • Also, if I use <f:view locale="en"> instead of using the backing bean for the value it works fine.


If you are trying to download a file to the user, why are you bothered about the locale?

Anyway, I don't know why you're getting the IllegalArgumentException. This normally happens when you try to use an OutputStream which has already been written to.

If I use the following jsp:

<%@ page import="uk.co.farwell.MyBean" %>

<f:view locale="en">
<%
MyBean bean = (DossierBean) pageContext.findAttribute ("bean");

bean.sendFile(response);
%>
</f:view>

with the following code in the bean:

public void sendFile(HttpServletResponse response) throws Exception {
    byte[] config = "foobar".getBytes();
    String clientFileName = "iphone.mobileconfig";

    BufferedInputStream input = null;
    BufferedOutputStream output = null;

    ByteArrayInputStream bais = new ByteArrayInputStream(config);
    input = new BufferedInputStream(bais);

    response.reset();
    response.setContentType("application/x-apple-aspen-config");
    response.setHeader("Content-Disposition", "attachment; filename=\"" + clientFileName + "\"");
    response.setContentLength((int) config.length);

    output = new BufferedOutputStream(response.getOutputStream(), 1024);

    byte[] buffer = new byte[1024];
    int length;
    while ((length = input.read(buffer)) > 0) {
        output.write(buffer, 0, length);
    }

    output.flush();
}

and I get an IllegalArgumentException. If this is the error you're getting, then try using a Servlet directly.

public final class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        byte[] config = "foobar".getBytes();

        resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

        resp.setContentType("application/rtf");
        resp.setContentLength(config.length());
        resp.getOutputStream().write(config.getBytes());
        resp.getOutputStream().flush();
        resp.getOutputStream().close();
    }
}

or similar. This is more reliable than using a jsp for downloading files.


The real solution to this problem is to send the file before the JSP page is loaded. To do that I registered a phaselistener and sent the file before the JSP page.

public class DrcPhaseListener implements PhaseListener {

    @Override
    public void afterPhase(PhaseEvent pe) { 
              ..... send file here ....
        }

The problem was, as I suspected, that the JSP page had already started sending date to the response and when I tried to send a file from the bean it was too late. The fix above will force the file send at a phase where the page has not started to load and therefore nothing was written to the response.


You need to call FacesContext#responseComplete() in the end of the action method to prevent that JSF navigates to a page (which defaults to the page from where the form is been submitted).

public void download() {
    sendFile();
    FacesContext.getCurrentInstance().responseComplete();
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜