tags:

views:

552

answers:

3

I google the error message "getOutputStream() has already been called for this response" and many people said it is because of the space or newline after <% or %>, but in my code , there is no a space or a newline. I am using tomcat6 on linux.

<%@
page import="java.servlet.*,
javax.servlet.http.*,
java.io.*,
java.util.*,
com.lowagie.text.pdf.*,
com.lowagie.text.*"
%><%
response.setContentType("application/pdf");
Document document = new Document();
try{
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
PdfWriter.getInstance(document, buffer);
document.open();
PdfPTable table = new PdfPTable(2);
table.addCell("1");
table.addCell("2");
table.addCell("3");
table.addCell("4");
table.addCell("5");
table.addCell("6");
document.add(table);
document.close();
DataOutput dataOutput = new DataOutputStream(response.getOutputStream());
byte[] bytes = buffer.toByteArray();
response.setContentLength(bytes.length);
for(int i = 0; i < bytes.length; i++)
{
dataOutput.writeByte(bytes[i]);
}
}catch(DocumentException e){
e.printStackTrace();
}%>

~

org.apache.jasper.JasperException: java.lang.IllegalStateException: getOutputStream() has already been called for this response
    org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:522)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:410)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

root cause

java.lang.IllegalStateException: getOutputStream() has already been called for this response
    org.apache.catalina.connector.Response.getWriter(Response.java:610)
    org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:198)
    org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:125)
    org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:118)
    org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:188)
    org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:118)
    org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:77)
    org.apache.jsp.Account.Domain.testPDF_jsp._jspService(testPDF_jsp.java:94)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
+8  A: 

The issue here is that your JSP is talking directly to the response OutputStream. This technically isn't forbidden, but it's very much not a good idea.

Specifically, you call response.getOutputStream() and write data to that. Later, when the JSP engine tries to flush the response, it fails because your code has already "claimed" the response. An application can either call getOutputStream or getWriter on any given response, it's not allowed to do both. JSP engines use getWriter, and so you cannot call getOutputStream.

You should be writing this code as a Servlet, not a JSP. JSPs are only really suitable for textual output as contained in the JSP. You can see that there's no actual text output in your JSP, it only contains java.

skaffman
the whole project is jsp based, I just need add functionality for PDF download
Southsouth
Well you can't, not like this. JSPs are for text, not binary.
skaffman
+1. Raw java code belongs in java classes. Use taglibs/EL in JSP only. If not possible with taglibs/EL, use a servlet.
BalusC
northTiger, there is nothing stopping you from adding a Servlet even if the project is otherwise all JSPs. JSPs wind up as servlets anyway once the compiler is done with them. For working with PDFs, you are MUCH better off with a plain servlet.
Kris
yes, I agree with you guys using servlet. but servket needs more configurations.
Southsouth
+1  A: 

JSP is s presentation framework, and is generally not supposed to contain any program logic in it. As skaffman suggested, use pure servlets, or any MVC web framework in order to achieve what you want.

Bozho
+1  A: 

Ok, you should be using a servlet not a JSP but if you really need to ... add this directive at the top of your page :

<%@ page trimDirectiveWhitespaces="true" %>

Or in the jsp-config section your web.xml

<jsp-config>
  <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
    <trim-directive-whitespaces>true</trim-directive-whitespaces>
  </jsp-property-group>
</jsp-config>

Also flush/close the OutputStream and return when done.

dataOutput.flush();
dataOutput.close();
return;
RealHowTo
Have you verified that this works? I doubt it'll make any difference, the container is still going to call `getWriter`, regardless of the page content.
skaffman
No it doesn't if there's absolutely no whitespace outside `<% %>`. This may however be implementation-specific behaviour which I wouldn't rely on after all. As far as I know it would work fine in Tomcat. But again, java code belongs in java classes, not in jsp files. Period.
BalusC
I forgot to mention that the trimDirectiveWhitespaces directive is for JSP 2.1 or better
RealHowTo
@BalusC: There was no whitespace outside `<% %>` in the original example, but that didn't make a difference.
skaffman
I've been looking at this for hours....adding the directive worked!Thanks!
hmak