Cannot forward after response has been committed

Sorry,

I've seen some similar topics but I did find any help. I'm developing a jsf application using netbens IDE and tomcat 5.5.17.

I try to download a file during the invoke application phase then go on another page:

public String button2_action() {

.............

ServletContext context = (ServletContext) getExternalContext().getContext();

HttpServletResponse response = (HttpServletResponse)getExternalContext().getResponse();

response.setContentType("application/txt");

response.addHeader("Content-Disposition", "attachment; filename=" + fileName);

byte[] buf = new byte[1024];

try{

File file = new File(path);

long length = file.length();

BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));

ServletOutputStream out = response.getOutputStream();

response.setContentLength((int)length);

while ((in != null) && ((length = in.read(buf)) != -1)) {

out.write(buf, 0, (int)length);

}

in.close();

out.close();

.......

return "goOnPage2";

}

it never goes on page2 and I get an error :

07-Feb-2007 10:37:22 org.apache.catalina.core.ApplicationContext log

SEVERE: Cannot forward after response has been committed

java.lang.IllegalStateException: Cannot forward after response has been committed

at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:313)

at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:301)

at com.sun.faces.context.ExternalContextImpl.dispatch(ExternalContextImpl.java:346)

at com.sun.faces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:152)

at com.sun.rave.web.ui.appbase.faces.ViewHandlerImpl.renderView(ViewHandlerImpl.java:285)

at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:107)

at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:245)

at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:137)

at javax.faces.webapp.FacesServlet.service(FacesServlet.java:214)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)

at com.sun.rave.web.ui.util.UploadFilter.doFilter(UploadFilter.java:198)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)

at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:368)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)

at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)

at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)

at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)

at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)

at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)

at java.lang.Thread.run(Thread.java:619)

07-Feb-2007 10:37:22 org.apache.catalina.core.StandardWrapperValve invoke

SEVERE: Servlet.service() for servlet Faces Servlet threw exception

com.sun.rave.web.ui.appbase.ApplicationException: Cannot forward after response has been committed

at com.sun.rave.web.ui.appbase.faces.ViewHandlerImpl.cleanup(ViewHandlerImpl.java:559)

at com.sun.rave.web.ui.appbase.faces.ViewHandlerImpl.renderView(ViewHandlerImpl.java:290)

at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:107)

at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:245)

at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:137)

at javax.faces.webapp.FacesServlet.service(FacesServlet.java:214)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)

at com.sun.rave.web.ui.util.UploadFilter.doFilter(UploadFilter.java:198)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)

at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:368)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)

at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)

at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)

at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)

at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)

at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)

at java.lang.Thread.run(Thread.java:619)

Caused by: java.lang.IllegalStateException: Cannot forward after response has been committed

at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:313)

at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:301)

at com.sun.faces.context.ExternalContextImpl.dispatch(ExternalContextImpl.java:346)

at com.sun.faces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:152)

at com.sun.rave.web.ui.appbase.faces.ViewHandlerImpl.renderView(ViewHandlerImpl.java:285)

... 24 more

Can please someone help.

Bye

Anna

[7329 byte] By [annacapa] at [2007-11-26 17:36:37]
# 1
This might be useful: http://balusc.xs4all.nl/srv/dev-jep-pdf.htmlJust replace "PDF" by "Any file" in your head and you're there.
BalusCa at 2007-7-9 0:04:45 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 2

Buffer the contents of the file, because BufferedInputStream.read() returns only 1 byte.

input = new BufferedInputStream(new FileInputStream(getFilePath()));

int contentLength = input.available();

...

Now replace

while (contentLength-- > 0) {

response.getOutputStream().write(input.read());

}

with something like

OutputStream os = response.getOutputStream();

int buffersize = 8192; // for example

byte[] buffer = new byte[buffersize];

int count = input.read(buffer);

while (count > 0)

{

os.write(buffer, 0, count);

count = input.read(buffer);

}

If you really want to change the page simultaneously, you have to send 2 requests. Navigate to the new page during first request and include some javascript in the answer that triggers the second request, that means submit the form with target '_blank'. The last step can be done by using the click() method of an unvisible button with an action method in page bean.

Ingmara at 2007-7-9 0:04:45 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 3

Thank you both for your suggestions until now. For the second one I've buffered the file download. For the first one maybe there is something not clear to me anyway it still does not fit.

I have to download a file as an attachment, so a save as window should open, I do not want to see it in a browser.

Can you please add some more details. I use the netbeans palette and for example I did not find command link.

Thank you

Anna

annacaa at 2007-7-9 0:04:45 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 4

Change the headers. Instead of

response.setHeader( "Content-disposition", "inline; filename=\"" + getFileName() + "\"");

write

response.setHeader( "Content-disposition", "attachment; filename=\"" + getFileName() + "\"");

That's sufficient in my application. If it's not in your's try

response.setContentType("application/download");

instead of

response.setContentType("application/pdf");

You can't influence the behaviour of the browser. If the user configures his browser to open all text files and PDF the headers perhaps will not work.

Ingmara at 2007-7-9 0:04:45 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 5
Rather use application/octet-stream instead of application/download.Also see http://www.w3schools.com/media/media_mimeref.asp
BalusCa at 2007-7-9 0:04:45 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 6

@Ingmar:

> Buffer the contents of the file, because

> BufferedInputStream.read() returns only 1 byte.

> > input = new BufferedInputStream(new

> FileInputStream(getFilePath()));

> int contentLength = input.available();

> ...

>

> Now replace

> > while (contentLength-- > 0) {

> response.getOutputStream().write(input.read());

> }

>

> with something like

> > OutputStream os = response.getOutputStream();

> int buffersize = 8192; // for example

> byte[] buffer = new byte[buffersize];

> int count = input.read(buffer);

> while (count > 0)

> {

> os.write(buffer, 0, count);

> count = input.read(buffer);

> }

>

>

> If you really want to change the page simultaneously,

> you have to send 2 requests. Navigate to the new page

> during first request and include some javascript in

> the answer that triggers the second request, that

> means submit the form with target '_blank'. The last

> step can be done by using the click() method of an

> unvisible button with an action method in page bean.

Found this topic again by the referrers of my website and I would like to comment on this:

Creating an external byte buffer on a BufferedInputStream is completely meaningless. Read the API and/or view the javasource of the BufferedInputStream.

Buffering the unbuffered OutputStream of the HttpServletResponse might be worth the effort, but as network speed is always slower than harddisk and memory speed (in ranges from 10 to 1000's times slower) it won't increase the performance dramatically. Maybe 10ms. But anyway, it is indeed "clean" to also buffer the OutputStream. I'll change the article accordingly by adding the BufferedOutputStream which should wrap the response.getOutputStream() ;)

BalusCa at 2007-7-9 0:04:45 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 7

> Creating an external byte buffer on a

> BufferedInputStream is completely meaningless.

> Read the API and/or view the javasource of the

> BufferedInputStream.

Sorry, if I have posted bad suggestions. I'am not an expert in IO and have read about the buffering in a tutorial. Don't remember which.

Doesn't the use of BufferedInputStream.read(byte[] b, int off, int len) instead of BufferedInputStream.read() reduce the number of method calls and save time this way?

API of BufferedInputStream.read(): "See the general contract of the read method of InputStream."

API InputStream.read(): "Reads the next byte of data from the input stream..."

What is the goal of BufferedInputStream.read(byte[] b, int off, int len)?

Is it usefull to use the alternate constructor BufferedInputStream(InputStream in, int size) and an external byte[] with the same size?

Seems, I have to read the source code.

Ingmara at 2007-7-9 0:04:45 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 8
This can be useful if you want to change the buffer size. BufferedInputStream by default uses a 8192 byte buffer.
BalusCa at 2007-7-9 0:04:45 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 9
Tank you all very much.You are been very kind, sorry for my late response but I did not have time until now to come back to this activity.ByeA.
annacapa at 2007-7-9 0:04:45 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...