dev@javaserverfaces.java.net

Seekin review: 1449 Flash in session scope

From: Ed Burns <Ed.Burns_at_Sun.COM>
Date: Wed, 20 Jan 2010 09:28:05 -0800

https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=1449


Issue: 1449


SECTION: Modified Files
----------------------------
M jsf-ri/src/com/sun/faces/context/flash/ELFlash.java
M jsf-ri/src/com/sun/faces/config/WebConfiguration.java

- Store the flash in session by default.

M jsf-ri/systest-per-webapp/flash/src/java/com/sun/faces/model/Bean.java
M jsf-ri/systest-per-webapp/flash/src/java/com/sun/faces/systest/FlashTestCase.java
M jsf-ri/systest-per-webapp/flash/web/index.xhtml
M jsf-ri/systest-per-webapp/flash/web/WEB-INF/web.xml
M jsf-ri/systest/src/com/sun/faces/systest/FlashMessagesTestCase.java
M jsf-ri/systest/src/com/sun/faces/systest/flash/FlashMessagesBean.java
M jsf-ri/systest/web/flash/flashKeepMessages01.xhtml

- Test both values for the context-param.

Index: jsf-api/src/main/java/javax/faces/context/Flash.java
===================================================================
--- jsf-api/src/main/java/javax/faces/context/Flash.java (revision 8290)
+++ jsf-api/src/main/java/javax/faces/context/Flash.java (working copy)
@@ -53,9 +53,12 @@
  *
  * <p><b>Implementation Requirements</b></p>
  *
- * <p>The flash is an application scoped object that must be thread
- * safe, and provide a programming model that lets each session treat
- * the flash as if it was a session scoped object.</p>
+ * <p>The flash must be thread safe. By default, the flash is stored in
+ * the session, but applications wishing to use the flash without
+ * forcing the creation of a session may set the context param {_at_link
+ * #STORE_FLASH_IN_SESSION_SCOPE_PARAM_NAME} to <code>false</code> to
+ * prohibit the implementation from storing the flash in the session.
+ * </p>
 
  * <p>The implementation requirements will be described in terms of the
  * runtime traversing the JSF lifecycle. The flash exposes a
@@ -175,6 +178,24 @@
 
  */
 public abstract class Flash implements Map<String, Object> {
+
+ /**
+ * <p>If this context param exists and is set to <code>false</code>,
+ * the implementation must not store the <code>Flash</code>
+ * singleton instance in session scope. Otherwise, the
+ * implementation is free to store the <code>Flash</code> singleton
+ * instance in session scope.</p>
+ */
+ public static final String STORE_FLASH_IN_SESSION_SCOPE_PARAM_NAME =
+ "javax.faces.STORE_FLASH_IN_SESSION_SCOPE";
+
+ /**
+ * <p>The default value of the {_at_link #STORE_FLASH_IN_SESSION_SCOPE}
+ * context param.</p>
+ */
+ public static final Boolean STORE_FLASH_IN_SESSION_SCOPE =
+ Boolean.TRUE;
+
     
 
     /**
Index: jsf-ri/src/com/sun/faces/context/flash/ELFlash.java
===================================================================
--- jsf-ri/src/com/sun/faces/context/flash/ELFlash.java (revision 8290)
+++ jsf-ri/src/com/sun/faces/context/flash/ELFlash.java (working copy)
@@ -273,20 +273,43 @@
     
     public static ELFlash getFlash(ExternalContext extContext, boolean create) {
         Map<String, Object> appMap = extContext.getApplicationMap();
+ Map<String, Object> mapForFlash = null;
+ if (storeFlashInSession(appMap)) {
+ mapForFlash = extContext.getSessionMap();
+ } else {
+ mapForFlash = appMap;
+ }
+
         ELFlash flash = (ELFlash)
- appMap.get(FLASH_ATTRIBUTE_NAME);
+ mapForFlash.get(FLASH_ATTRIBUTE_NAME);
         if (null == flash && create) {
             synchronized (extContext.getContext()) {
                 if (null == (flash = (ELFlash)
- appMap.get(FLASH_ATTRIBUTE_NAME))) {
+ mapForFlash.get(FLASH_ATTRIBUTE_NAME))) {
                     flash = new ELFlash();
- appMap.put(FLASH_ATTRIBUTE_NAME, flash);
+ mapForFlash.put(FLASH_ATTRIBUTE_NAME, flash);
                 }
             }
         }
         return flash;
     }
     
+ private static boolean storeFlashInSession(Map<String, Object> appMap) {
+ boolean result = false;
+ String key = WebConfiguration.BooleanWebContextInitParameter.
+ StoreFlashInSessionScope.getQualifiedName();
+ if (appMap.containsKey(key)) {
+ result = (Boolean) appMap.get(key);
+ } else {
+ result = WebConfiguration.getInstance().isOptionEnabled(WebConfiguration.
+ BooleanWebContextInitParameter.StoreFlashInSessionScope);
+
+ appMap.put(key, (Boolean) result);
+ }
+
+ return result;
+ }
+
     // </editor-fold>
 
     // <editor-fold defaultstate="collapsed" desc="Abstract class overrides">
Index: jsf-ri/src/com/sun/faces/config/WebConfiguration.java
===================================================================
--- jsf-ri/src/com/sun/faces/config/WebConfiguration.java (revision 8290)
+++ jsf-ri/src/com/sun/faces/config/WebConfiguration.java (working copy)
@@ -60,6 +60,7 @@
 
 import java.util.HashMap;
 import javax.faces.component.UIInput;
+import javax.faces.context.Flash;
 import javax.faces.validator.BeanValidator;
 import javax.faces.view.facelets.ResourceResolver;
 
@@ -1065,6 +1066,10 @@
         AllowTextChildren(
             "com.sun.faces.allowTextChildren",
             false
+ ),
+ StoreFlashInSessionScope(
+ Flash.STORE_FLASH_IN_SESSION_SCOPE_PARAM_NAME,
+ (boolean) Flash.STORE_FLASH_IN_SESSION_SCOPE
         );
 
         private BooleanWebContextInitParameter alternate;
Index: jsf-ri/systest-per-webapp/flash/src/java/com/sun/faces/model/Bean.java
===================================================================
--- jsf-ri/systest-per-webapp/flash/src/java/com/sun/faces/model/Bean.java (revision 8290)
+++ jsf-ri/systest-per-webapp/flash/src/java/com/sun/faces/model/Bean.java (working copy)
@@ -92,4 +92,9 @@
         return "flash12?faces-redirect=true";
     }
 
+ public boolean isFlashStoredInSessionScope() {
+ FacesContext context = FacesContext.getCurrentInstance();
+ return context.getExternalContext().getSessionMap().containsKey("csfcff");
+ }
+
 }
Index: jsf-ri/systest-per-webapp/flash/src/java/com/sun/faces/systest/FlashTestCase.java
===================================================================
--- jsf-ri/systest-per-webapp/flash/src/java/com/sun/faces/systest/FlashTestCase.java (revision 8290)
+++ jsf-ri/systest-per-webapp/flash/src/java/com/sun/faces/systest/FlashTestCase.java (working copy)
@@ -115,6 +115,8 @@
         // Get the first page
         HtmlPage page = getPage("/faces/index.xhtml");
         String pageText = page.asXml();
+
+ assertTrue(pageText.contains("Flash stored in session scope: false."));
         // (?s) is an "embedded flag expression" for the "DOTALL" operator.
         // It says, "let . match any character including line terminators."
         // Because page.asXml() returns a big string with lots of \r\n chars
Index: jsf-ri/systest-per-webapp/flash/web/index.xhtml
===================================================================
--- jsf-ri/systest-per-webapp/flash/web/index.xhtml (revision 8290)
+++ jsf-ri/systest-per-webapp/flash/web/index.xhtml (working copy)
@@ -57,8 +57,10 @@
     on this one as well, use either
     <code>\#{flash.now.foo}</code> or
     <code>\#{requestScope.foo}</code>. The former is simply
- an alias for the latter.
+ an alias for the latter. <br />
 
+ <p>Flash stored in session scope: #{bean.flashStoredInSessionScope}.</p>
+
     <f:verbatim>
       c:set target="\#{flash}" property="foo" value="fooValue"
     </f:verbatim>
Index: jsf-ri/systest-per-webapp/flash/web/WEB-INF/web.xml
===================================================================
--- jsf-ri/systest-per-webapp/flash/web/WEB-INF/web.xml (revision 8290)
+++ jsf-ri/systest-per-webapp/flash/web/WEB-INF/web.xml (working copy)
@@ -44,6 +44,10 @@
     <param-value>.xhtml</param-value>
   </context-param>
   <context-param>
+ <param-name>javax.faces.STORE_FLASH_IN_SESSION_SCOPE</param-name>
+ <param-value>false</param-value>
+ </context-param>
+ <context-param>
       <param-name>facelets.DEVELOPMENT</param-name>
       <param-value>true</param-value>
   </context-param>
Index: jsf-ri/systest/src/com/sun/faces/systest/FlashMessagesTestCase.java
===================================================================
--- jsf-ri/systest/src/com/sun/faces/systest/FlashMessagesTestCase.java (revision 8290)
+++ jsf-ri/systest/src/com/sun/faces/systest/FlashMessagesTestCase.java (working copy)
@@ -91,6 +91,9 @@
     public void testBooleanCheckboxSubmittedValue() throws Exception {
 
         HtmlPage page = getPage("/faces/flash/flashKeepMessages01.xhtml");
+
+ assertTrue(page.asText().contains("Flash stored in session scope: true."));
+
         HtmlSubmitInput button = (HtmlSubmitInput) page.getElementById("nextButton");
         page = button.click();
         String pageText = page.asText();
Index: jsf-ri/systest/src/com/sun/faces/systest/flash/FlashMessagesBean.java
===================================================================
--- jsf-ri/systest/src/com/sun/faces/systest/flash/FlashMessagesBean.java (revision 8290)
+++ jsf-ri/systest/src/com/sun/faces/systest/flash/FlashMessagesBean.java (working copy)
@@ -76,5 +76,9 @@
 
     }
 
+ public boolean isFlashStoredInSessionScope() {
+ return getFacesContext().getExternalContext().getSessionMap().containsKey("csfcff");
+ }
 
+
 }
Index: jsf-ri/systest/web/flash/flashKeepMessages01.xhtml
===================================================================
--- jsf-ri/systest/web/flash/flashKeepMessages01.xhtml (revision 8290)
+++ jsf-ri/systest/web/flash/flashKeepMessages01.xhtml (working copy)
@@ -43,6 +43,9 @@
         <title>Test that flash shows multiple messages: issue 1476</title>
     </h:head>
     <h:body>
+
+ <p>Flash stored in session scope: #{flashMessagesBean.flashStoredInSessionScope}.</p>
+
         <h:form prependId="false">
 
             <h:inputText value="#{flashMessagesBean.value}" />

-- 
| ed.burns_at_sun.com  | office: 408 884 9519 OR x31640
| homepage:         | http://ridingthecrest.com/