Author: craigmcc
Date: Wed Dec 20 23:13:45 2006
New Revision: 489271

URL: http://svn.apache.org/viewvc?view=rev&rev=489271
Log:
Implement three strategies for dealing with the back button issues described
in SHALE-61 for saving extra state in the JSF component tree:
* "none" (default) - as before, save nothing
* "top" - save the state name of the topmost stack element, plus the stack
  depth to catch cases where the user crosses subdialog boundaries
* "stack" - save the entire position stack, *including* the user data object
  at each level

Need to document this on the website page, but I believe this is sufficient
support for handling back buttons in dialogs for the "basic" implementation,
for the 1.0.4 upcoming release.

Modified:
    shale/framework/trunk/shale-apps/shale-test-dialog-basic/pom.xml
    
shale/framework/trunk/shale-apps/shale-test-dialog-basic/src/main/webapp/WEB-INF/web.xml
    
shale/framework/trunk/shale-apps/shale-test-dialog-basic/src/main/webapp/wizardpage2.jsp
    
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/BasicDialogContext.java
    
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/Globals.java
    
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/Position.java

Modified: shale/framework/trunk/shale-apps/shale-test-dialog-basic/pom.xml
URL: 
http://svn.apache.org/viewvc/shale/framework/trunk/shale-apps/shale-test-dialog-basic/pom.xml?view=diff&rev=489271&r1=489270&r2=489271
==============================================================================
--- shale/framework/trunk/shale-apps/shale-test-dialog-basic/pom.xml (original)
+++ shale/framework/trunk/shale-apps/shale-test-dialog-basic/pom.xml Wed Dec 20 
23:13:45 2006
@@ -87,6 +87,12 @@
 
         <dependency>
             <groupId>org.apache.shale</groupId>
+            <artifactId>shale-core</artifactId>
+            <version>${version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.shale</groupId>
             <artifactId>shale-dialog</artifactId>
             <version>${version}</version>
         </dependency>

Modified: 
shale/framework/trunk/shale-apps/shale-test-dialog-basic/src/main/webapp/WEB-INF/web.xml
URL: 
http://svn.apache.org/viewvc/shale/framework/trunk/shale-apps/shale-test-dialog-basic/src/main/webapp/WEB-INF/web.xml?view=diff&rev=489271&r1=489270&r2=489271
==============================================================================
--- 
shale/framework/trunk/shale-apps/shale-test-dialog-basic/src/main/webapp/WEB-INF/web.xml
 (original)
+++ 
shale/framework/trunk/shale-apps/shale-test-dialog-basic/src/main/webapp/WEB-INF/web.xml
 Wed Dec 20 23:13:45 2006
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
@@ -18,12 +17,7 @@
 
  $Id$
 -->
-
-<web-app               xmlns="http://java.sun.com/xml/ns/j2ee";
-                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
-          xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
-                              http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd";
-                      version="2.4">
+<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee                             
  http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd";>
 
   <!-- Display name for this application -->
   <display-name>Shale Test App (Dialog Basic Implementation)</display-name>
@@ -47,6 +41,12 @@
     <param-value>/WEB-INF/dialog-config.xml</param-value>
   </context-param>
 -->
+
+  <context-param>
+    <description>Strategy for saving dialog-specific state across 
requests.</description>
+    <param-name>org.apache.shale.dialog.basic.STRATEGY</param-name>
+    <param-value>top</param-value>
+  </context-param>
 
   <!-- JavaServer Faces Servlet Configuration -->
   <servlet>

Modified: 
shale/framework/trunk/shale-apps/shale-test-dialog-basic/src/main/webapp/wizardpage2.jsp
URL: 
http://svn.apache.org/viewvc/shale/framework/trunk/shale-apps/shale-test-dialog-basic/src/main/webapp/wizardpage2.jsp?view=diff&rev=489271&r1=489270&r2=489271
==============================================================================
--- 
shale/framework/trunk/shale-apps/shale-test-dialog-basic/src/main/webapp/wizardpage2.jsp
 (original)
+++ 
shale/framework/trunk/shale-apps/shale-test-dialog-basic/src/main/webapp/wizardpage2.jsp
 Wed Dec 20 23:13:45 2006
@@ -21,6 +21,7 @@
 
 <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core"; %>
 <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html"; %>
+<%@ taglib prefix="s" uri="http://shale.apache.org/core"; %>
 
 <f:view>
 <html>
@@ -84,6 +85,11 @@
                       <%-- FIXME - add parameters to the above URL --%>
         </h:panelGroup>
         <h:message        for="zipCode"/>
+
+        <h:outputText   value=""/>
+        <s:token           id="token"/>
+        <h:message         id="message"
+                          for="token"/>
 
         <h:outputText   value=""/>
         <h:panelGroup>

Modified: 
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/BasicDialogContext.java
URL: 
http://svn.apache.org/viewvc/shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/BasicDialogContext.java?view=diff&rev=489271&r1=489270&r2=489271
==============================================================================
--- 
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/BasicDialogContext.java
 (original)
+++ 
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/BasicDialogContext.java
 Wed Dec 20 23:13:45 2006
@@ -165,6 +165,14 @@
 
 
     /**
+     * <p>The strategy identifier for dealing with saving and restoring
+     * state information across requests.  This value is lazily
+     * instantiated, and can be recalculated on demand as needed.</p>
+     */
+    private transient String strategy = null;
+
+
+    /**
      * <p>An empty parameter list to pass to the action method called by
      * a method binding expression.</p>
      */
@@ -259,7 +267,22 @@
     /** [EMAIL PROTECTED] */
     public Object getOpaqueState() {
 
-        return null; // Do not do anything yet, just fulfill the API contract
+        if ("top".equals(strategy())) {
+            if (log().isInfoEnabled()) {
+                log().info("getOpaqueState<top> returns " + new 
TopState(peek().getState().getName(), positions.size()));
+            }
+            return new TopState(peek().getState().getName(), positions.size());
+        } else if ("stack".equals(strategy())) {
+            if (log().isInfoEnabled()) {
+                log().info("getOpaqueStrategy<stack> returns stack of " + 
positions.size());
+            }
+            return positions;
+        } else {
+            if (log().isInfoEnabled()) {
+                log().info("getOpaqueStrategy<none> returns nothing");
+            }
+            return null;
+        }
 
     }
 
@@ -267,7 +290,29 @@
     /** [EMAIL PROTECTED] */
     public void setOpaqueState(Object opaqueState) {
 
-        ; // Do not do anything yet, just fulfill the API contract
+        if ("top".equals(strategy())) {
+            TopState topState = (TopState) opaqueState;
+            if (log().isInfoEnabled()) {
+                log().info("setOpaqueState<top> restores " + topState);
+            }
+            if (topState.stackDepth != positions.size()) {
+                throw new IllegalStateException("Restored stack depth expects "
+                        + positions.size() + " but is actually "
+                        + topState.stackDepth);
+            }
+            Position top = peek();
+            top.setState(top.getDialog().findState(topState.stateName));
+        } else if ("stack".equals(strategy())) {
+            if (log().isInfoEnabled()) {
+                log().info("setOpaqueState<stack> restores stack of " + 
((List) opaqueState).size());
+            }
+            positions = (List) opaqueState;
+        } else {
+            if (log().isInfoEnabled()) {
+                log().info("setOpaqueState<none> restores nothing");
+            }
+            ; // Do nothing
+        }
 
     }
 
@@ -668,6 +713,25 @@
 
 
     /**
+     * <p>Return the strategy identifier for dealing with saving state
+     * information across requests.</p>
+     */
+    private String strategy() {
+
+        if (this.strategy == null) {
+            this.strategy = 
FacesContext.getCurrentInstance().getExternalContext().getInitParameter(Globals.STRATEGY);
+            if (this.strategy == null) {
+                this.strategy = "none";
+            } else {
+                this.strategy = this.strategy.toLowerCase();
+            }
+        }
+        return this.strategy;
+
+    }
+
+
+    /**
      * <p>Transition the specified [EMAIL PROTECTED] Position}, based on the 
specified
      * logical outcome, to the appropriate next [EMAIL PROTECTED] State}.</p>
      *
@@ -719,6 +783,65 @@
         fireOnEntry(toStateId);
 
     }
+
+
+    // ------------------------------------------------ State Storage 
Subclasses
+
+
+    /**
+     * <p>Class that represents the saved opaque state information when the
+     * <code>top</code> strategy is selected.</p>
+     */
+    public class TopState implements Serializable {
+
+        /**
+         * <p>Construct an uninitialized instance of this state class.</p>
+         */
+        public TopState() {
+            ;
+        }
+
+
+        /**
+         * <p>Construct an initialized instance of this state class.</p>
+         *
+         * @param stateName Name of the current state in the topmost position
+         * @param stackDepth Depth of the position stack
+         */
+        public TopState(String stateName, int stackDepth) {
+            this.stateName = stateName;
+            this.stackDepth = stackDepth;
+        }
+
+
+        /**
+         * <p>The name of the current state within the topmost
+         * <code>Position</code> on the stack.</p>
+         */
+        public String stateName;
+
+
+        /**
+         * <p>The stack depth of the <code>Position</code> stack.  This is
+         * used to detect scenarios where using the back and forward buttons
+         * navigates across a subdialog boundary, which means that the
+         * saved <code>stateName</code> is likely no longer relevant.</p>
+         */
+        public int stackDepth;
+
+
+        /**
+         * <p>Return a string representation of this instance.</p>
+         */
+        public String toString() {
+            return "TopState[stateName=" + this.stateName
+                   + ", stackDepth=" + this.stackDepth + "]";
+        }
+
+
+
+    }
+
 
 
 }

Modified: 
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/Globals.java
URL: 
http://svn.apache.org/viewvc/shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/Globals.java?view=diff&rev=489271&r1=489270&r2=489271
==============================================================================
--- 
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/Globals.java
 (original)
+++ 
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/Globals.java
 Wed Dec 20 23:13:45 2006
@@ -43,4 +43,25 @@
             "org.apache.shale.dialog.basic.DIALOGS";
 
 
+    /**
+     * <p>Context initialization parameter name under which a strategy name
+     * for dealing with saving and restoring dialog context state information
+     * is specified.  Valid values are:</p>
+     * <ul>
+     * <li><code>none</code> - No extra information is stored (default).</li>
+     * <li><code>top</code> - Information from the top-most [EMAIL PROTECTED] 
Position}
+     *     on the stack, plus enough information to detect crossing a subdialog
+     *     boundary.  Such a case will cause an exception to be thrown.</li>
+     * <li><code>stack</code> - The entire stack of [EMAIL PROTECTED] 
Position}s, including
+     *     the corresponding data objects.<li>
+     * </ul>
+     *
+     * <p><strong>IMPLEMENTATION NOTE</strong> - The feature set supported by
+     * this context initialization parameter is experimental, and no guarantees
+     * of backwards compatibility in future versions should be assumed.</p>
+     */
+    public static final String STRATEGY =
+            "org.apache.shale.dialog.basic.STRATEGY";
+
+
 }

Modified: 
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/Position.java
URL: 
http://svn.apache.org/viewvc/shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/Position.java?view=diff&rev=489271&r1=489270&r2=489271
==============================================================================
--- 
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/Position.java
 (original)
+++ 
shale/framework/trunk/shale-dialog-basic/src/main/java/org/apache/shale/dialog/basic/Position.java
 Wed Dec 20 23:13:45 2006
@@ -160,6 +160,13 @@
      * @return The current [EMAIL PROTECTED] State} within the owning [EMAIL 
PROTECTED] Dialog}
      */
     State getState() {
+        if (this.state == null) {
+            Dialog dialog = getDialog();
+            if (dialog == null) {
+                return null;
+            }
+            this.state = dialog.findState(this.stateName);
+        }
         return this.state;
     }
 


Reply via email to