FacesMessage not displayed in p:messages when user cancels file download

1k views Asked by At

When I add a FacesMessage inside the catch block of a try-catch it is not displayed in the p:messages component. If I add the FacesMessage in another location it is displayed. Why?

Adding of the FacesMessage:

try {
    ...
} catch (ServiceException | IOException e) {
    LOG.error("Failed to load content for download", e);
    MessageUtils.addErrorMessage(msgs, "msg.error.general", (Object[]) null);
}


public static void addErrorMessage(final MessagesProxy msgs, final String key, final Object... params)
{
    final FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msgs.getText(key, params), null);
    final FacesContext fc = FacesContext.getCurrentInstance();
    fc.addMessage(null, msg);
    fc.validationFailed();
}

msgs is the access to the resource bundle.

Here is the p:messages with autoUpdate=true:

<p:messages id="mainMessagesId" autoUpdate="true" />

Background: the ui provides the download of files which is handled in the backing bean. If the user selects a big file and clicks on button cancel in the save as dialog of the browser an exception comes up:

15:29:13,599 ERROR [xxx.web.bl.ContentBL] (http-/127.0.0.1:9090-1) Failed to load content for download: ClientAbortException:  java.net.SocketException: Connection reset by peer: socket write error
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:403) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:450) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:351) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:426) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:415) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:89) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.omnifaces.servlet.GzipHttpServletResponse$GzipThresholdOutputStream.write(GzipHttpServletResponse.java:204) [omnifaces-1.8.1.jar:1.8.1-20140603]
at org.omnifaces.io.ResettableBufferedOutputStream.write(ResettableBufferedOutputStream.java:77) [omnifaces-1.8.1.jar:1.8.1-20140603]
at org.omnifaces.io.ResettableBufferedOutputStream.write(ResettableBufferedOutputStream.java:56) [omnifaces-1.8.1.jar:1.8.1-20140603]
at org.omnifaces.servlet.HttpServletResponseOutputWrapper$1.write(HttpServletResponseOutputWrapper.java:92) [omnifaces-1.8.1.jar:1.8.1-20140603]
at java.io.OutputStream.write(OutputStream.java:116) [rt.jar:1.7.0_75]
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1793) [commons-io-2.4.jar:2.4]
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1769) [commons-io-2.4.jar:2.4]
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1744) [commons-io-2.4.jar:2.4]
at xxx.web.bl.ContentBL.downloadContent(ContentBL.java:309) [classes:]
at xxx.web.bl.ContentBL$Proxy$_$$_WeldClientProxy.downloadContent(ContentBL$Proxy$_$$_WeldClientProxy.java) [classes:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_75]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_75]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_75]
at java.lang.reflect.Method.invoke(Method.java:606) [rt.jar:1.7.0_75]
at javax.el.BeanELResolver.invokeMethod(BeanELResolver.java:735) [jboss-el-api_2.2_spec-1.0.2.Final-redhat-1.jar:1.0.2.Final-redhat-1]
at javax.el.BeanELResolver.invoke(BeanELResolver.java:467) [jboss-el-api_2.2_spec-1.0.2.Final-redhat-1.jar:1.0.2.Final-redhat-1]
at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:246) [jboss-el-api_2.2_spec-1.0.2.Final-redhat-1.jar:1.0.2.Final-redhat-1]
at de.odysseus.el.tree.impl.ast.AstMethod.eval(AstMethod.java:91) [juel-impl-2.2.7.jar:2.2.7]
at de.odysseus.el.tree.impl.ast.AstMethod.invoke(AstMethod.java:104) [juel-impl-2.2.7.jar:2.2.7]
at de.odysseus.el.tree.impl.ast.AstEval.invoke(AstEval.java:71) [juel-impl-2.2.7.jar:2.2.7]
at de.odysseus.el.TreeMethodExpression.invoke(TreeMethodExpression.java:132) [juel-impl-2.2.7.jar:2.2.7]
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40) [weld-core-1.1.16.Final-redhat-1.jar:1.1.16.Final-redhat-1]
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50) [weld-core-1.1.16.Final-redhat-1.jar:1.1.16.Final-redhat-1]
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) [jsf-impl-2.2.11.jar:2.2.11]
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87) [jsf-api-2.2.11.jar:2.2]
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) [jsf-impl-2.2.11.jar:2.2.11]
at org.apache.myfaces.extensions.cdi.jsf.impl.security.SecurityViolationAwareActionListener.processAction(SecurityViolationAwareActionListener.java:56) [myfaces-extcdi-jsf20-module-impl-1.0.5.jar:1.0.5]
at org.apache.myfaces.extensions.cdi.jsf.impl.config.view.ViewControllerActionListener.processAction(ViewControllerActionListener.java:68) [myfaces-extcdi-jsf20-module-impl-1.0.5.jar:1.0.5]
at org.apache.myfaces.extensions.cdi.jsf.impl.listener.action.CodiActionListener.processAction(CodiActionListener.java:58) [myfaces-extcdi-jsf20-module-impl-1.0.5.jar:1.0.5]
at org.omnifaces.eventlistener.ResetInputAjaxActionListener.processAction(ResetInputAjaxActionListener.java:197) [omnifaces-1.8.1.jar:1.8.1-20140603]
at javax.faces.component.UICommand.broadcast(UICommand.java:315) [jsf-api-2.2.11.jar:2.2]

And then the p:messagesdoes not show anything. I am using primefaces 5.2.6 and JSF 2.2.11.

Regards Oliver

1

There are 1 answers

0
BalusC On BEST ANSWER

Most modern browsers will already eagery download the file in the background even when the enduser hasn't yet decided whether to save the file in the specified location, or cancel the file download. A cancel will obviously abort the currently running download request. In case the file is downloaded faster than the enduser decides to cancel, then it goes fully unnoticed by the server and the browser will silently delete it from (temp) disk instead of moving/renaming it.

This kind of exception cannot be handled in the server side in form of displaying a message to the enduser, for the simple reason that there's no means of a request/response anymore. The client has aborted the request/response. There's no response anywhere to write the message to. Your best bet would be a push connection (e.g. websockets via PrimeFaces <p:socket>).

Just let the exception go. The client has it all at its hands. If necessary, suppress logging of specifically ClientAbortException so that you won't be bothered by it in server logs.

See also:


Unrelated to the concrete problem, as per the stack trace you're using OmniFaces. In case you didn't already know it, it has a Messages utility class saving you from that MessageUtils boilerplate.