Skip to main content

Repost: Bringing Ruby on Rails's Flash to JSF

Posted by edburns on March 1, 2006 at 12:20 PM PST

With the demise of the Sun Engineer's Sandbox, my content posted there has disappeared. Thankfully I saved a copy. Thanks to srcerer on the ##jsf chat room on freenode for reminding me to repost this.

Overview

To celebrate the release of Ruby on Rails (RoR) 1.0, I have taken the
href="http://api.rubyonrails.com/classes/ActionController/Flash.html">flash
concept from Rails's ActionController and brought it to
JSF. For those unfamiliar with RoR or the flash, the flash is basically
a map whose entries have a finite, container enforced lifetime. The
concept is familiar; it's the same old "scope" concept used in the
"request", "session" and "application" classes in the Servlet spec. The
point of the flash is to hold information you discover on this
request, that you want to use on the next request, but want to be
forgotten after the next request is finished

Figure 1 is a cheesy graphical depiction of the request, flash,
dialog, session, and application scopes.

The nice thing about these scopes is that they all have a Map into
which you can stick things. These Maps have the special property that
they will be cleared when the scope ends. In the case of the flash, the
map is cleared after exactly two runs through the JSF request processing
lifecycle.

I included Shale's href="http://struts.apache.org/struts-shale/features-dialog-manager.html">Dialog
concept for good measure since I believe this concept is important to
the future of JSF For example, it's so important that JBoss Seam href="http://docs.jboss.com/seam/reference/en/html/tutorial.html#d0e778">also
provides a similar concept. A Shale dialog or Seam conversation is
a scope whose length is determined by the application developer.

Background

Of course, I needed a release-vehicle for this thing so I created a
new glassfish
sub-project on java.net called href="https://jsf-extensions.dev.java.net">jsf-extensions. My
intent is to use this project for a number of extensions to the core jsf
implementation. The flash is just the first the first that is ready for
public use. Others in the works include:

  • A completion and implementation of Jacob Hookom's href="http://weblogs.java.net/blog/jhook/archive/2005/09/jsf_avatar_vs_m_1.html">JSF
    Avatar proposal

  • A generalization of the Sun JSF implementation's JSP
    tag library generator. This tool is used in the Sun
    implementation to generate the TLD and tag handlers for the
    html_basic taglib from the existing standard JSF component
    metadata in the standard-html-renderkit.xml file.
    The idea is to generalize this tool so it can be used to
    generate the taglib for any JSF component.

  • A generalization of the PhaseListener
    approach used in the href="https://bpcatalog.dev.java.net/nonav/ajax/jsf-ajax/frames.html">Sun
    Blueprints Solutions Catalog AJAX components to serve up
    JavaScript files so that it can serve up any file out of a
    component jar. This problem is solved in MyFaces using the href="http://myfaces.apache.org/tomahawk/extensionsFilter.html">Extensions
    Filter but a PhaseListener is a more self-container
    approach. This problem is also solved by href="https://weblets.dev.java.net/">the Weblets Project
    but personally I don't think the problem of loading resources
    is big enough to warrant an entire top-level project. Also,
    weblets has extra XML configuration steps that simply are not
    necessary if you use the PhaseListener approach.

But enough about the future of jsf-extensions, let's
quickly examine how to use the flash by examining the sample war
included in the jsf-extensions download.

Getting Started

  • Download and unpack the href="https://jsf-extensions.dev.java.net/files/documents/4420/25753/jsf-extensions-0.1alpha1.zip">jsf-extensions
    download.

  • Download a recent build of glassfish, I used href="https://glassfish.dev.java.net/servlets/NewsItemView?newsItemID=3072">Build
    31.

  • Start it up by going to the bin directory and
    running:

    ./asadmin start-domain domain1
  • Then deploy the sample app by executing:

    ./asadmin deploy --user admin --password adminadmin ~/jsf-extensions-1.0alpha1/wars/run-time-test-0.1.war

    Of course, you need to adjust your path to the war accordingly. The
    app will then be accessible at href="http://localhost:8080/run-time-test-0.1/">http://localhost:8080/run-time-test-0.1/.
    This will take you to an index page where you should click on the "Ruby
    on Rails-style Flash" link.

App Traversal

This app illustrates using the Flash from JSP. It is also possible
to use the flash directly from Java Code, or via the EL API. These
latter two methods are described in the href="https://jsf-extensions.dev.java.net/nonav/docs/apidocs/com/sun/faces/el/FlashELResolver.html">JavaDocs.

As you may know from href="http://java.sun.com/products/jsp/reference/techart/unifiedEL.html">Jennifer
and Pierre's article on the Unified EL, JSF expressions can be
accessed in a "get" context, or a "set context", otherwise known as
"rvalue" or "lvalue", respectively. Thefore, the EL Expression
#{flash.foo} will store a value into the hash under the key
"foo" when evaluated as an lvalue, while it will retrieve the value
under key "foo" from the flash when evaluated as an rvalue.

In JSP pages, most expressions act as rvalues, whereas the lvalue
behavior does not occurr until the form is submitted and the values
entered by the user are stored into the expressions. However, to make
it easier to set expression values from JSP, including setting into the
flash, the jsf-extensions library includes the jsfExt:set
tag. A simple usage of this tag found on the first page in the sample
app, flash.jsp, is shown below.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>RoR Flash Test Page 1</title>
    <%@ taglib uri="http://java.sun.com/jsf/core"  prefix="f" %>
    <%@ taglib uri="http://java.sun.com/jsf/html"  prefix="h" %>
    <%@ taglib prefix="jsfExt" uri="http://java.sun.com/jsf/extensions" %>
  </head>

  <body>
<f:view>

  <h:form id="form1">

  <h:panelGrid columns="2" border="1" width="600">

    Store into the flash when rendering this page     

    <jsfExt:set var="#{flash.foo}" value="fooValue" />

    Value of <code>\#{flash.foo}</code>, should be <code>null</code>.

    <h:outputText value="#{flash.foo}" />

    <h:commandButton value="reload" />

    <h:commandButton value="next" action="next" />

   </h:panelGrid>

  </h:form>

</f:view>
  </body>
</html>

We're using the panelGrid tag (in way we not possible before JSF 1.2,
due to the problems pointed out in href="http://www.onjava.com/pub/a/onjava/2004/06/09/jsf.html">Hans
Bergsten challenge
) to lay out the contents in a simple two column
table. The first row shows the use of the jsfExt:set tag
to store a value into the flash. The second row shows how to get things
from the flash. When viewing this page the first time, you won't see
anything in the "Value of #{flash.foo} row" until you press the "reload"
button in the page. This is because the normal use-case of the flash is
to store things in this request that will be accessed on the next
request.

If you want to store something in the flash for use on this request,
click on the "next" button in the sample app for an example. In this
page we use the "flash.now" syntax, shown below in JSP.

<jsfExt:set var="#{flash.now.bar}" value="barValue" />

<h:outputText value="#{flash.now.bar}" />

By inserting the special keyword "now" we tell the flash that this
store operation should be accessible on this request, rather than the
next request. If, during processing, you decide you want to promote the
value from flash.now to the real flash, use "flash.next" as shown on the
next page of the sample app.

<f:verbatim>
<jsfExt:set var="\#{flash.now.buckaroo}" value="banzai" />
</f:verbatim>

Value of <code>\#{flash.now.buckaroo}</code>, should be
<code>banzai</code>.

<h:outputText value="#{flash.now.buckaroo}" />

Promote buckaroo to stick around for the next request.

<jsfExt:set var="#{flash.keep.buckaroo}" value="#{flash.now.buckaroo}" />

When you click on the next button, you will be shown a page that
shows that the value in the flash has indeed survived the postback.

Show that buckaroo is still here.

<h:outputText value="#{flash.buckaroo}" />

This is a brief introduction to using the flash, a more in-depth
article would cover a common real-world use-case, such as doing
master-detail, and also cover the other two entry points to using the
flash, the EL API, and direct programmatic use.

Technorati Tags:

Related Topics >>