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();
}
精彩评论