A Flash in the Pan?

Last night, I awoke at 3 a.m. wondering whether David Geary and I should have given more coverage to the JSF 2 flash in our Core JSF book revision. Here is why I think your time is better spent learning about other, more powerful constructs, together with some thoughts about CDI and REST.

JSF 2 introduces an EL variable flash. Anything you set persists for one post-redirect-get cycle. (In contrast, anything in the request scope is gone after a redirect.) A typical use of the flash is for messages. A managed bean method might put a message in the flash,

ExternalContext.getFlash().put("warning", "Your password is about to expire");

Then the message can be displayed on the next page as

#{flash.warning}

That's handy—the message survives one redirect, and then it is gone.

But it also points to a weakness of the flash. It doesn't really fit into the managed bean model. Normally, I would put a message in a managed bean object, without using the JSF API. Then I'd use it as #{myPage.warning}. In the published uses of the flash, you always see unsightly code in which data are shoveled in or out of the flash.

Of course, I'd want the myPage bean to go away soon, and do so automatically. Maybe a CDI FlashScope is in order, so that I can do

@Named @FlashScoped public class MyPage

There is a discussion about this on the Seam 3 board.

Similar to Rails, the JSF 2 flash allows you to keep an entry for another cycle, by using

#{flash.keep.key}

This way, you can carry data along a page flow. You can have a data entry page with

<h:inputTextArea value="#{flash.description}"/>

followed by a confirmation page with

#{flash.keep.description}

followed by another page that shovels the description into its final destination.

(When I first saw this, I stared at it for a long time, not being able to figure out from the documentation what was going on. I finally looked at the source and found that the getValue method has special handling for flash.keep. There is also special handling for flash.now, which apparently is just a synonym for requestScope, perhaps to make Rails developers feel at home?)

My head started hurting when I traced the behavior. It just doesn't feel like the JSF way. It seems to be so much easier to use CDI and have a

@Named @ConversationScoped Widget

with a description property. Then I can use #{widget.description} and end the conversation when I no longer need the widget.

Not only is is mentally simpler, it also works better. If you use flash, and your user opens two browser windows, the two windows interfere with another in ways that make my head hurt even more.

(NB. This morning, my wife checked our daughter's appointment on the Kaiser web site, and I mentally gasped when she opened another browser tab to check her own appointment at the same time, because, as she told me when I asked, the site is so slow. I wasn't sure if it was going to work, but it did. The site uses Struts, not JSF :-))

Another good option for a page flow is to turn inputs into view parameters of a request-scoped bean.

<f:metadata>
   <f:viewParam name="description" value="#{widget.description}"/>
</f:metadata>
 ...
<h:commandButton action="next?faces-redirect=true&amp;includeViewParams=true"/>

(Don't ask why it is faces-redirect but includeViewParams...)

This is all very politically correct, with REST and PRG, and it is also easy to reason about the behavior of your app. Multiple browser windows work fine.

Which is better? The REST way is easy to understand. You post to the confirmation page, and then post the same data again to the final page. There is no server-side state, and that makes it easy to test each page in isolation. But it is pretty tedious if your page contains lots of inputs. CDI takes the opposite approach and embraces server-side state as something that is your friend, provided of course that it is properly managed.

It is nice to know that JSF 2 supports two good ways of managing data in a page flow, both of which seem better than using the flash and are definitely worth learning. Is it worth figuring out the innermost and undocumented secrets of the flash? Maybe not? JSF has more nooks and crannies than the Winchester Mystery House, and I think the most effective way of using it is to stay away as many of them as I can.