One thing that I wrote that I haven’t really gotten around to examining and verifying in closer detail and validating my position on is the production of the conversational entity manager in the Knappsack archetypes. This article looks at this and re-evaluates my thinking on the use of conversational contexts in CDI.
Defaulting to Request Scoped
It’s one of those things that you write and it works, but something feels wrong with it, and I haven’t had time to go back and look at it. The entity manager is scoped to the conversation so that it will work with as both conversational and request scoped. When an object is scoped to the conversation and there is no long running conversation then the conversation itself is limited to the request so your data, although conversation scoped becomes request scoped. This was a handy way to default data that was mostly request scoped to a request scope while giving it the ability to partake in active conversations. In Seam, this was fairly standard practice since it allowed your model to live in a conversational entity manager without having to worry about detachment issues. However, CDI conversations are different from Seam conversations and their use needs to be a little more focused.
The problem is that CDI is supported in a number of environments within Java EE 6 while the conversation scope is not. To name a few, servlets and web services don’t have default support for conversations and Arquillian tests doesn’t handle conversations well. While we may be able to work around non-conversational servlets, web services and arquillian tests, the problem really goes deeper.
Logically we are thinking about using these beans as request scoped beans because there is no long running conversation. However, the conversational context still needs to be initialized and available to hold these beans. CDI doesn’t magically know to put the conversational beans in the request scope context when there’s no long running conversation, it always puts it in the conversational context.
So, the answer you say is to use request scoped beans and relegate a conversational scope to those cases where you really do need a conversational scope, and not use it everywhere you want request scoped but might need a conversation scoped bean. While this is true, our request scoped beans depend on business logic beans that in turn use the data layer beans that uses our entity manager to access the database. The problem is that the entity manager is conversation scoped so all our beans that depend on it are broken.
The end result is that using some of the tools and API’s with CDI has been rather frustrating since nearly every bean depends on the entity manager at the end of the day and without conversation support it typically breaks with an obscure error message.
The solution is to treat our entity manager like our beans, we only use conversations where absolutely necessary. The question you may be asking yourselves is how to deal with code that is both request and conversation scoped. For example, you load an entity at the start of a wizard into a conversation scoped bean using a conversation scoped entity manager because you want to keep this bean attached for the duration of the conversation. At the end of the conversation, you might want to use the standard request scoped entity Dao to save the entity. Will the request scoped Dao will use a different entity manager from the conversation scoped bean or not? The good news is that we can re-use the same entity manager sourced from the same place and offered up as a request scoped entity manager to get around this so they will use the same entity manager.
Additionally, the introduction of some of the new JSF 2.0 scopes helps out since we can use the flash or view scopes to pass objects from one page to the next or to maintain state between requests. The only problem here is that these scopes are in JSF and not compatible with CDI, or implemented in CDI by default. The Seam 3 faces module provides CDI compatible alternatives and I would put good money on those scopes making it into the next version of CDI.
One take away from this is to always make sure everything will play nice together before committing to a particular strategy or design. It would have been a shame to implement our data access layer and find out that we couldn’t use it in our web services or testing.
I’ll be trying to spend a little time working all this out and seeing what the best strategies are, but hopefully this will remove some of the barriers to demonstrating and adding third party integrations into the Knappsack archetypes. This will probably get changed for the next version of the Knappsack archetypes.