Details
-
Type: Bug
-
Status: Closed
-
Priority: Major
-
Resolution: Won't Fix
-
Affects Version/s: 3.3
-
Fix Version/s: EE-3.3.0.GA, 4.0.BETA, 4.0
-
Labels:None
-
Environment:JBoss 6, CDI, Weld
-
Assignee Priority:P1
-
Salesforce Case Reference:
-
Workaround Exists:Yes
-
Workaround Description:HideAs noted in the case, it's possible to handle the CDI exception from the client using either the JSF or ICE API for error handling.
It's also possible to make your own ExceptionHandler that can either remove the exception and let the SessionExpiredException propagate to the client so that the redirect behaves normally or handle the error in some other way.ShowAs noted in the case, it's possible to handle the CDI exception from the client using either the JSF or ICE API for error handling. It's also possible to make your own ExceptionHandler that can either remove the exception and let the SessionExpiredException propagate to the client so that the redirect behaves normally or handle the error in some other way.
Description
-
Hide
- 12134.war
- 7.23 MB
- Arran Mccullough
-
- META-INF/MANIFEST.MF 0.1 kB
- login.xhtml 0.7 kB
- nada.xhtml 0.5 kB
- WEB-INF/.faces-config.xml.jsfdia 0.1 kB
- WEB-INF/beans.xml 0.2 kB
- WEB-INF/classes/.../BackingBean.class 0.7 kB
- WEB-INF/classes/fi/.../concept/Filter.class 2 kB
- WEB-INF/classes/.../concept/Listener.class 1 kB
- WEB-INF/faces-config.xml 0.3 kB
- WEB-INF/jboss-web.xml 0.1 kB
- WEB-INF/lib/commons-beanutils-1.8.0.jar 226 kB
- WEB-INF/lib/FastInfoset-1.2.12.jar 287 kB
- WEB-INF/lib/icefaces-3.3.0-RC1.jar 579 kB
- WEB-INF/lib/icefaces-ace-3.3.0-RC1.jar 4.00 MB
- WEB-INF/.../icefaces-compat-3.3.0-RC1.jar 2.59 MB
- WEB-INF/lib/icepush-3.3.0-RC1.jar 194 kB
- WEB-INF/web.xml 2 kB
- META-INF/maven/.../Concept2/pom.xml 3 kB
- META-INF/maven/.../Concept2/pom.properties 0.1 kB
-
Hide
- 12134-mod.war
- 15 kB
- Deryk Sinotte
-
- META-INF/MANIFEST.MF 0.1 kB
- META-INF/maven/.../Concept2/pom.properties 0.1 kB
- META-INF/maven/.../Concept2/pom.xml 3 kB
- WEB-INF/.faces-config.xml.jsfdia 0.1 kB
- WEB-INF/beans.xml 0.2 kB
- WEB-INF/classes/.../BackingBean.class 0.7 kB
- WEB-INF/classes/fi/.../concept/Filter.class 2 kB
- WEB-INF/classes/.../concept/Listener.class 1 kB
- WEB-INF/.../NoConversationExceptionHandler.class 3 kB
- WEB-INF/.../NoConversationExceptionHandlerFactory.class 1.0 kB
- WEB-INF/faces-config.xml 0.5 kB
- WEB-INF/jboss-web.xml 0.1 kB
- WEB-INF/lib/.DS_Store 6 kB
- WEB-INF/web.xml 2 kB
- login.xhtml 3 kB
- nada.xhtml 0.5 kB
- src/.DS_Store 6 kB
- src/.../NoConversationExceptionHandler.java 3 kB
- src/.../NoConversationExceptionHandlerFactory.java 0.6 kB
- web/index.jsp 0.2 kB
- web/WEB-INF/jboss-web.xml 0.2 kB
- web/WEB-INF/web.xml 0.3 kB
Activity
- All
- Comments
- History
- Activity
- Remote Attachments
- Subversion
Got it set up properly and confirmed the behaviour noted in the test case. Normally when the session has expired, the next interaction with the app would return the following (as shown from the Firefox console log):
[10:24:31.272] [window] received error message [code: 200]: <?xml version='1.0' encoding='UTF-8'?> <partial-response><error><error-name>class org.icefaces.application.SessionExpiredException...</partial-response>
However, it appears that the when a conversation is started, the next interaction after the session expired throws a different exception:
[10:26:21.813] [window] received error message [code: 200]: <?xml version='1.0' encoding='UTF-8'?> <partial-response><error><error-name>class org.jboss.weld.context.NonexistentConversationException</error-name><error-message><![CDATA[WELD-000321 No conversation found to restore for id 1]]>...</partial-response>
I suspect that the check and failure to find the conversation id is done before the session is accessed. Since the bridge is configured to redirect on a SessionExpiredException, it's not working.
I'm digging in to why this exception is thrown in the first place to see the best way to possibly get it to work. One thing to try might be to use the container's exception handling:
<error-page> <exception-type>org.jboss.weld.context.NonexistentConversationException</exception-type> <location>/faces/error.xhtml</location> </error-page>
Tried a couple of different variations of this myself but none seemed to work.
<error-page> <exception-type>org.jboss.weld.context.NonexistentConversationException</exception-type> <location>error.html</location> </error-page> <error-page> <exception-type>org.jboss.weld.context.NonexistentConversationException</exception-type> <location>/faces/nada.xhtml?nocid=true</location> </error-page>
The exception is likely be handled in a way that the servlet container never sees.
This doesn't look to be an ICEfaces issue per se. If I remove the ICEfaces libraries and tweak the pages and web.xml so that it's a plain JSF app, the error-page directives noted before will work. However, if I then add Ajax to the buttons:
<h:commandButton value="start" action="#{javax.enterprise.context.conversation.begin()}"> <f:ajax execute="@all" render="@all"/> </h:commandButton> <h:commandButton value="noop" action="#{backingBean.noop()}"> <f:ajax execute="@all" render="@all"/> </h:commandButton>
Then the behaviour is similar to ICEfaces in that a the error-page redirects are not honoured. If in Development mode:
<context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param>
JSF will pop up an alert that a server error occurred but in Production mode it just sits there.
So to summarize, the problems are:
- The ICEfaces bridge is looking for a SessionExpiredException returned as the Ajax response in order to trigger the redirect. Since the NonexistentConversationException occurs first, it's returned as the Ajax response and the redirect never happens.
- It's a JSF behaviour to ignore error-page directs for Ajax responses and is not constrained to ICEfaces.
The best/easiest way to handle this might be to use the jsf API on the client (jsf.ajax.addOnError(callback)) and do the redirect in that code. I'll look next at doing something up as an example.
As noted, this isn't a problem with the conversation id not getting propagated. The real issue is that the org.jboss.weld.context.NonexistentConversationException occurs ahead of the SessionExpiredException and interferes with the ability for ICEfaces to run the logic for redirecting to the sessionExpiredRedirectURI.
There are at least two application-centric ways to work around this:
1. Add a client-side handler to listen for the specific error and redirect from there. The script, using ICEfaces JavaScript API (http://www.icesoft.org/wiki/display/ICE/JavaScript+Client+API) would look something like the following:
var handleNoConversationICE = function handleNoConversationICE(status,responseText,responseXML) { if (responseText) { if (responseText.indexOf("NonexistentConversationException") != -1 ) { //This is the point where we decide how to handle the exception. Assuming //that the conversation id is gone because the session has expired, there are //a few options on how to handle it. console.log("detected NonexistentConversationException"); window.location.href = "./faces/nada.xhtml"; } } }; ice.onServerError(handleNoConversationICE);
There is also use the standard JSF API - jsf.ajax.addOnError(handleNoConversationJSF) - to register a callback and do something similar.
2) The JSF way to deal with exceptions in Ajax is to create an ExceptionHandler. There are 3 things you need to do:
- Create your own class that extends ExceptionHandler
- Create an ExceptionHandlerFactory that returns your ExceptionHandler wrapped around the parent ExceptionHandler (to maintain the chain of ExceptionHandlers).
- Register your factory in the faces-config file.
Attaching a modified version of the test case that shows the ExceptionHandler strategy. Source has been included but the libs have been removed to reduce the size.
Since this is not currently seen as a generic solution, we're going to leave it as something for application developers to use. Another case (ICE-9234) has been opened to potentially add a feature for more generic handling for exceptions from Ajax responses.
(Case owner commenting)
I've used option 2 before but I considered it more of handling a side effect (NonexistingConversationException) than the actual session expiring, I'll give option 1 a spin. What should the web.xml parameters for disabling default popups be for option 1 and 2.
What I find slightly confusion is that Weld activates the non-transient conversation in a PhaseListener but even if I activate the Filter I have in the original WAR, I can detect the stale session and redirect before the exception is thrown but redirect is still ignored.
The following context parameter can be used to disable the default error popups:
<context-param>
<param-name>org.icefaces.disableDefaultErrorPopups</param-name>
<param-value>true</param-value>
</context-param>
http://www.icesoft.org/wiki/display/ICE/disableDefaultErrorPopups
The ICEfaces client-side bridge is looking for a very specific Ajax response to do the redirect. It must be an error containing org.icefaces.application.SessionExpiredException. If anything else arrives as the Ajax response, the redirect does not get triggered. That's why I've created the new case as a potential improvement to allow more flexible error handling on the client.
I'm not a Weld/CDI expert so I'm not sure about all the conditions that cause NonexistingConversationException to occur so it's best at this point to handle it in the application. I still think option 2 is a legitimate solution as well. It's the mechanism that JSF provides for handling errors triggered via Ajax requests.
Attached test case that shows the issue. It is setup to run on Jboss EAP 6.1.0 and is compiled using JDK7.
Steps: