My Project is using JSF2.0 and CDI. For one page, I want my backing bean to match the lifespan of the page. @ViewScoped seems a perfect fit but it's not part of CDI and then make our solution not consistent. Then my next option would be the CDI @ConversationScoped. Seems to me the only way to mark the boundary of a conversation is the program way via conversation.begin and conversation.end (I have used Seam 2.x, there you can use annotations to mark conversation boundary). My page is sitting in a common layout with global navigation, which means there are "unlimited" ways to leave my page. How can I make sure the conversation is ended whichever way the user might choose (e.g. clicking on a global navi option which is totally outside of my backing bean's control)? And I hope the solution would not spread the code to other modules; and if that's inevitable, I hope it could be implemented in a cross-cutting manner (AOP).
Asked
Active
Viewed 3,798 times
2 Answers
4
This can be achieved with a custom ConfigurableNavigationHandler
.
Implement a JSF NavigationHandler
public class NavigationHandlerTest extends ConfigurableNavigationHandler { private NavigationHandlerTest concreteHandler; public NavigationHandlerTest(NavigationHandler concreteHandler) { this.concreteHandler = concreteHandler; } @Override public void handleNavigation(FacesContext context, String fromAction, String outcome) { //here, check where navigation is coming from and based on that, retrieve the CDI bean and kill the conversation if(fromAction.equals("someAction"){ BeanManager theBeanManager = getBeanManager(context); Bean bean = theBeanManager.getBeans("yourCDIBean").iterator().next() CreationalContext ctx = theBeanManager.createCreationalContext(bean); MyBeanType o = theBeanManager.getReference(bean, bean.getClass(), ctx); //retrieve the bean from the manager by name. You're guaranteed to retrieve only one of the same name; o.getConversation.end(); //end the conversation from the bean reference } //proceed with normal navigation concreteHandler.handleNavigation(context, fromAction, outcome); } //This method provides access to the cdi bean manager. You need it to be able to //gain access to the cdi bean and from that to the injected conversation instance public BeanManager getBeanManager(FacesContext facesContext){ BeanManager cdiBeanManager = (BeanManager)((ServletContext) facesContext.getExternalContext().getContext()).getAttribute("javax.enterprise.inject.spi.BeanManager"); return cdiBeanManager; } }
Register your custom navigation handler in the faces-config.xml
<application> <navigation-handler>com.foo.bar.NavigationHandlerTest</navigation-handler> </application>
This approach is centralized and minimally invasive

kolossus
- 20,559
- 3
- 52
- 104
-
That's an ugly workaround. I would use CODI-Conversations instead. – Dar Whi Nov 18 '13 at 11:04
-
For custom navigation handler in JSF2 and above follow https://stackoverflow.com/questions/12045442/jsf-custom-navigationhandler-outcome-values-invalid – Tirath Aug 03 '19 at 18:52
0
As I know - you can't. It is almost impossible (hard) to determine if link was opened in current or new tab (for new you need to leave conversation active) in JSF.
But good news - conversation will be closed automatically after 10 minutes of inactivity (by default).

Michail Nikolaev
- 3,733
- 22
- 18
-
Well, leaving the design issue aside. Technically, you can make all the navigation requests go through a navigation service object. And every conversation has an id. Once the target page is open, we can save the id in the service object, if any following navigation request is not for the target page, then we know we need to end the conversation. Since CDI is somewhat based on Seam, I was hoping I can have a more elegant solution. – chaoshangfei Mar 13 '13 at 22:45
-
You may try create special commandLink instead of simple (as some composite with "target" parameter). Such link will call "closeConversation" method on some @ConversationScoped bean and redirect you to "target" link... – Michail Nikolaev Mar 13 '13 at 22:50
-
The Client-Side Window-Handler from CODI can detect a new Tab/Window properly. – Dar Whi Nov 18 '13 at 11:06