Wednesday, June 1, 2011

session based view-scope with codi

codi itself offers an adapter for the view-scope of jsf2+ as well as a view-access scope which sounds similar but is something completely different (there is a 2nd blog entry about the difference). this entry is not about the view-access scope. it's about the view-scope which was introduced by jsf2. the adapter provided by codi allows you to bind cdi beans to the view-scope of jsf2+ directly. that's the reason why it's only available for jsf2+ whereas the other scopes of codi can be used with jsf1.2 as well as jsf2+. however, besides the basic concept of the view-scope, the default implementation has also some disadvantages (like losing the state in case of a browser-refresh, if there is no form with input components). if you haven't faced such issues, you might skip this blog entry. as mentioned before there is no standard way for jsf1.2 users to use the view-scope of jsf2+.

after several questions about it i decided to implement a codi-add-on which can be used with jsf1.2 as well as with jsf2+. due to the powerful spi of codi, the result is a simple implementation which offers additional features like grouped beans (you can manually destroy beans of the same group immediately even though you stay on the  same page), optional bean events,... .

it's e.g. problematic for some use-cases that the jsf2+ implementation of the view-scope stores the beans in the component tree. so several users ask for a session based view-scope. that means the beans for a page will be stored in the session instead of the component tree. if you really need such a scope instead of the view-access-scope provided by codi, you can implement such a scope with the spi of codi + two simple classes.

approach #1

the first one is a marker annotation and the second one an observer for the PreViewConfigNavigateEvent. that's it! if you only use the type-safe navigation of codi, you are done and you annotate your bean with @View and the @ConversationScoped annotation provided by codi. as soon as a navigation to a new page is detected all conversation scoped beans annotated with @View will be destroyed.

if you don't use the type-safe navigation of codi, you can implement e.g. a custom jsf navigation handler which does the same for all navigations.

if you prefer a single annotation instead (let's call it @MyViewScoped), you can write a portable cdi extension which adds the @ConversationScoped dynamically to all beans which are annotated with @MyViewScoped.

it took longer to write this blog entry, than implementing this mechanism :)


approach #2

the result of this approach is the same like approach #1. the advantage is that you don't have to care about the navigation and the disadvantage is that you have to extend a default implementation.

if you are ok with extending the default implementation (with weld you have to #veto the default implementation instead of using @Specializes), you can override the default implementation of #createConversation (a method which is part of the spi of codi). if you just implement the interface, you would override everything and you would deactivate all codi scopes. ok - so let's add a new scope with the same marker annotation and a ConversationFactory instead of the observer:

this implementation is compatible with all jsf concepts which are supported by codi!

approach #2.1

this approach is the same like #2 but instead of implementing it on our own, we can just use the @ViewConversationScoped provided by the enhanced-conversations add-on for codi: