File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes JSP and the fly likes HELP! Problems with Buffer/Response Committed Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of EJB 3 in Action this week in the EJB and other Java EE Technologies forum!
JavaRanch » Java Forums » Java » JSP
Bookmark "HELP! Problems with Buffer/Response Committed" Watch "HELP! Problems with Buffer/Response Committed" New topic
Author

HELP! Problems with Buffer/Response Committed

Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
I have my page directive as:

but when I try to forward to another page it throws an exception:
java.lang.IllegalStateException: Response has already been committed
at org.apache.tomcat.facade.HttpServletResponseFacade.sendError(HttpServletResponseFacade.java:202)
at org.apache.tomcat.facade.HttpServletResponseFacade.sendRedirect(HttpServletResponseFacade.java:228)

What's going on here? I thought if I set the buffer to a large size and stopped it from auto-flushing that I'd be able to redirect but I can't!!
Please help!
Also, I have another problem if you can help:
I've set the error page as such (in web.xml):

but that error code gets thrown and it never goes to my error page. however, if I set "errorPage=error.html" in the page directive, it goes there on an error. why isn't the web.xml mapping it up?
thanks.
Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 60046
    
  65

I'd suggest rather than trying to find specious work-arounds for the problem, why not sit back and look at the structure of your page to determine why you feel the need to perform the forward AFTER some output has already been generated.
hth,
bear


[Asking smart questions] [Bear's FrontMan] [About Bear] [Books by Bear]
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
Thanks for the completely not helpful comment. I am NOT WRITING anything anywhere. I have no out.println's and no <%= %> anywhere. I never print anything out. But I did discover the problem (and it's stupid in the servlet api if you ask me):
I call:
getServletConfig().getServletContext().getRequestDispatcher( "/FormHandle" ).include( request, response );
Where the servlet "/FormHandle" checks in a database for the info input and returns after setting a session and request attribute. Then, if the attribute's correct, I forward them to another page. I see no problem with the logic in that.
Problem is, after I include the servlet, it says my response is committed even though I NEVER touch the response object ANYWHERE.
Anyone know how i can fix this? What can/should I be doing?
David O'Meara
Rancher

Joined: Mar 06, 2001
Posts: 13459

MVC
Send the initial request to a processing servlet, allow the servlet to make all of the calls to gather the data and make it available on the request, then include or forward to the JSP to provide the view.
There may be a problem with the Server you are using sending the HTTP header prematurely even though you aren't sending any page content, but this is pretty unlikely. I think it is more likely you are letting accidental white space be output which is causing the response buffer to be filled and committed.
The other possibility is that 'include' calls can cause the buffer to be flushed even if you haven't requested that to happen. In effect, the getRequestDispatcher().include call causes the response to be comitted. Once again the MVC approach should fix it.
Hope you find this useful.
I agree with Bear though, concentrate on the error being thrown and not on mapping the 500 code. No idea why it doesn't manage that code correctly though..
Dave
[ February 03, 2003: Message edited by: David O'Meara ]
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
But David - MVC IS what I'm doing. Here's what happens:
1. The page registers some actions (my classes and api that I created)
2. It hands off to the form handler servlet which uses the form and the actions
3. The form handler delegates allactions to whatever servlet does that action (like a data processing servlet)
4. It hands the results back to the JSP
5. The JSP (the only thing that should be aware of what IT wants to do) then sees what the response is and decides where to send the user (i.e. with a forward).
Anyways, even if the form handler tried a forward, it wouldn't work either. Once you do a RequestDispatcher.include() you can no longer forward anywhere. And THAT is stupid. I don't understand that! It's basically forcing me to do everything on one page! So it says, make this page be the initiator, the setup and the processor as well as the view. Nothing else can control it, nor can it get info from other servlets and then send the user anywhere.
This really makes no sense from an MVC standpoint. (And before anyone goes telling me that people have been doing MVC with JSP/Servlets, I'll bet if I looked at it I'd see a ton of places where it's NOT MVC. I've talked to a ton of people who have said they were doing MVC - or "N-Tier" as the buzzword in the MS world is called - and it wasn't)
Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 60046
    
  65

I am NOT WRITING anything anywhere.

Well, that's important info that wasn't included in your original post (search through this forum and you'll find dozens of posts where people try to forward after emitting reams of data...)
Apparently something is causing the response to commit. If you're not exlicitly performing output, it may be difficult to isolate.
One tactic could be to scan the java class created on behalf of your JSP to see if anything in your page is inadvertently turning into a output call prior to your forward.
Of course David's suggestion of separating processing from display is always a good one!
hth,
bear
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
Well, I'm guessing from what I've read that the "include()" function considers whatever you're doing in there to be included in the response, so the moment you call include, it flushes the buffer to get ready for it (is there a way to stop this?). So is there an "execute()" function? I know that in the latest version of ASP (not ASP.net) they finally added a function like this to go along with include and forward/redirect. Execute merely executed some page or class on the ASP page's behalf but never wrote it into the response.
David O'Meara
Rancher

Joined: Mar 06, 2001
Posts: 13459

see the syntax for the JSP include tag:
<jsp: include page="{ relativeURL | <%= expression %>}" flush="true" />
Using this tag you can specify flush="false" and it shouldn't flush the buffer before including the new file, but I haven't heard anything about its behaviour or stability (ie thats how it should behave, no guarantees on how it is actually done)
Submitting to a Servlet that doesn't output anything is still preferred.
That is, the request gets sent to the Servlet. The Servlet does the 'execute' stuff, then includes the JSP for display. The trick is making sure the Servlet is responsible for processing and not display and that the JSP is responsible for display and NOT processing.
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
OK, I created a solution for anyone needing one. To make include more like "execute", do this:
First create a class that implements HttpServletResponse and ServletResponse (I actually pass it the response object so it can implement some of the "get" methods only). Then pass THAT as the response object into include. Here's a class for you to get started:

Then, pass it like this:
getServletConfig().getServletContext().getRequestDispatcher( "/MyServlet" ).include( request, new EmptyResponse() );
That's it! You can of course go further and put an actual buffer in there too! then they can write to THAT response buffer (which normally is NOT allowed) and then you can extract it and add it to the real response in your JSP page. Yay!
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
ok, I take it back. I must have changed something else because now it's not working again. That makes no sense to me since I passed a fake response object, yet it still won't let me forward to another page! What's going on?
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
it allows me to include more than once (which it didn't before) when I use EmptyResponse, but when I try to forward, it says I already retrieved the OutputStream. Anyone know what's doing this and how I can stop it from getting the outputstream or printwriter?
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
please, anyone who can help me solve this - it's driving me nuts!
Why can't I call requestdispatcher.include with a fake response object, and then forward to another page with the real response object? It always says that I obtained the response outputstream or printwriter even though I never did either (although request dispatcher may have but I don't see how since I passed it a different response object!)
Dominic Paquette
Ranch Hand

Joined: Dec 13, 2002
Posts: 64
Hi Robert, I had the same problem, did you try to look in the Servlet class generated by the container (in the /work directory). I bet you there are some out.write() calls.
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
you're probably right. Or maybe it sets headers? The thing is, I looked at tomcat's implementation of requestdispatcher and I'm thinking it can't be that because the only flsuhing/writing it does is on the response object I pass it. This is so frustrating. I really don't get why I can't execute a servlet without writing to the response? Doesn't it make sense from an MVC point to be able to have a servlet simply execute some data handling (or whatever) but have nothing to do with the response (i.e. the VIEW!!!)
David Hibbs
Ranch Hand

Joined: Dec 19, 2002
Posts: 374
IMHO, there's generally little reason to manipulate things such as your buffer size manually. In fact, it's probably what's causing your issues. Setting the buffer size sets the buffer property on the out object, and setting it can only be done once. So by setting the buffer size, you are implicitly committing your response.
For reference:
http://java.sun.com/products/jsp/tags/11/syntaxref118.html
You should be able to do any number of includes, with or without associated controllers, without issue. If you don't write a single thing to your response, don't set any properties, etc etc, you can probably then forward. But if you're doing includes, there's probably little reason to also do a forward.
As an example, in Struts/Tiles you can associate a controller with a view and include the view result by referencing the controller. i.e. do an include of showUserInfo.do which forwards to userInfo.jsp and voila, the result of userInfo is included. You don't need to do the forward.
If you have a set of processes that need followed in order, forward your way through them rather than trying to include them. If you're trying to include the results of servlet1 and servlet2 before forwarding to sevlet3, instead try
servlet1 forward to servlet2 forward to servlet3.
This gives a much more loose coupling and allows each servlet to determine whether to continue the processing or redirect to an error page or handler.


"Write beautiful code; then profile that beautiful code and make little bits of it uglier but faster." --The JavaPerformanceTuning.com team, Newsletter 039.
Scott Duncan
Ranch Hand

Joined: Nov 01, 2002
Posts: 363
Yes, David is absolutely correct.


No more rhymes! I mean it!<br /> <br />Does anybody want a peanut?
 
Consider Paul's rocket mass heater.
 
subject: HELP! Problems with Buffer/Response Committed
 
Similar Threads
<error-page>
<error-code>404</error-code> happens only once.
jsp:include page="header.html" causes IllegalStateException
Problem with deployment-descriptor's error-page mapping
web.xml and error-page