You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2011/05/14 03:05:41 UTC

svn commit: r1102936 - in /myfaces/core/branches/2.0.x/impl/src: main/conf/META-INF/ main/java/org/apache/myfaces/application/ main/java/org/apache/myfaces/renderkit/ main/java/org/apache/myfaces/renderkit/html/ main/java/org/apache/myfaces/view/facele...

Author: lu4242
Date: Sat May 14 01:05:41 2011
New Revision: 1102936

URL: http://svn.apache.org/viewvc?rev=1102936&view=rev
Log:
MYFACES-3117 Current server state saving implementation prevents multi-window usage

Added:
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ClientSideStateCacheImpl.java
      - copied, changed from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
      - copied, changed from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheFactoryImpl.java
      - copied, changed from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheUtils.java
    myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ServerSideStateCacheTest.java
Removed:
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheImpl.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java
Modified:
    myfaces/core/branches/2.0.x/impl/src/main/conf/META-INF/standard-faces-config-base.xml
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCache.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ViewHandlerImpl.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/MyfacesResponseStateManager.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/StateWriter.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java

Modified: myfaces/core/branches/2.0.x/impl/src/main/conf/META-INF/standard-faces-config-base.xml
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/conf/META-INF/standard-faces-config-base.xml?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/conf/META-INF/standard-faces-config-base.xml (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/conf/META-INF/standard-faces-config-base.xml Sat May 14 01:05:41 2011
@@ -29,7 +29,7 @@
    <application>
       <action-listener>org.apache.myfaces.application.ActionListenerImpl</action-listener>
       <view-handler>org.apache.myfaces.application.ViewHandlerImpl</view-handler>
-      <state-manager>org.apache.myfaces.application.jsp.JspStateManagerImpl</state-manager>
+      <state-manager>org.apache.myfaces.application.StateManagerImpl</state-manager>
       <navigation-handler>org.apache.myfaces.application.NavigationHandlerImpl</navigation-handler>
       <resource-handler>org.apache.myfaces.application.ResourceHandlerImpl</resource-handler>
       <!-- 

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java Sat May 14 01:05:41 2011
@@ -18,25 +18,24 @@
  */
 package org.apache.myfaces.application;
 
-import org.apache.commons.beanutils.BeanUtils;
-import org.apache.myfaces.application.jsp.JspStateManagerImpl;
-import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
-import org.apache.myfaces.config.RuntimeConfig;
-import org.apache.myfaces.config.element.Property;
-import org.apache.myfaces.config.element.ResourceBundle;
-import org.apache.myfaces.context.RequestViewContext;
-import org.apache.myfaces.el.PropertyResolverImpl;
-import org.apache.myfaces.el.VariableResolverToApplicationELResolverAdapter;
-import org.apache.myfaces.el.convert.MethodExpressionToMethodBinding;
-import org.apache.myfaces.el.convert.ValueBindingToValueExpression;
-import org.apache.myfaces.el.convert.ValueExpressionToValueBinding;
-import org.apache.myfaces.el.unified.ELResolverBuilder;
-import org.apache.myfaces.el.unified.ResolverBuilderForFaces;
-import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver;
-import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver.Scope;
-import org.apache.myfaces.lifecycle.LifecycleImpl;
-import org.apache.myfaces.shared_impl.util.ClassUtils;
-import org.apache.myfaces.view.facelets.el.ELText;
+import java.beans.BeanDescriptor;
+import java.beans.BeanInfo;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import javax.el.CompositeELResolver;
 import javax.el.ELContext;
@@ -86,24 +85,25 @@ import javax.faces.view.ViewDeclarationL
 import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
-import java.beans.BeanDescriptor;
-import java.beans.BeanInfo;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.MissingResourceException;
-import java.util.TimeZone;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+import org.apache.myfaces.config.RuntimeConfig;
+import org.apache.myfaces.config.element.Property;
+import org.apache.myfaces.config.element.ResourceBundle;
+import org.apache.myfaces.context.RequestViewContext;
+import org.apache.myfaces.el.PropertyResolverImpl;
+import org.apache.myfaces.el.VariableResolverToApplicationELResolverAdapter;
+import org.apache.myfaces.el.convert.MethodExpressionToMethodBinding;
+import org.apache.myfaces.el.convert.ValueBindingToValueExpression;
+import org.apache.myfaces.el.convert.ValueExpressionToValueBinding;
+import org.apache.myfaces.el.unified.ELResolverBuilder;
+import org.apache.myfaces.el.unified.ResolverBuilderForFaces;
+import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver;
+import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver.Scope;
+import org.apache.myfaces.lifecycle.LifecycleImpl;
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.view.facelets.el.ELText;
 
 /**
  * DOCUMENT ME!
@@ -235,7 +235,7 @@ public class ApplicationImpl extends App
         _navigationHandler = new NavigationHandlerImpl();
         _actionListener = new ActionListenerImpl();
         _defaultRenderKitId = "HTML_BASIC";
-        _stateManager = new JspStateManagerImpl();
+        _stateManager = new StateManagerImpl();
         _elContextListeners = new ArrayList<ELContextListener>();
         _resourceHandler = new ResourceHandlerImpl();
         _runtimeConfig = runtimeConfig;

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCache.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCache.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCache.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCache.java Sat May 14 01:05:41 2011
@@ -21,7 +21,8 @@ package org.apache.myfaces.application;
 import javax.faces.context.FacesContext;
 
 /**
- *  
+ * This class provides and interface to separate the state caching operations (saving/restoring)
+ * from the renderkit specific stuff that HtmlResponseStateManager should do.
  * 
  * @author Leonardo Uribe
  *
@@ -38,6 +39,8 @@ public abstract class StateCache<K, V>
     public abstract K saveSerializedView(FacesContext facesContext, V serializedView);
     
     /**
+     * Get the state from the cache is server side state saving is used,
+     * or decode it from the passed viewState param if client side is used.
      * 
      * @param facesContext
      * @param viewId The viewId of the view to be restored
@@ -48,6 +51,8 @@ public abstract class StateCache<K, V>
     public abstract V restoreSerializedView(FacesContext facesContext, String viewId, K viewState);
 
     /**
+     * Calculate the token to be used if server side state saving, or encode the view and return the
+     * viewState that can be used by the underlying ResponseStateManager to write the state.
      * 
      * @param facesContext
      * @param state The state that will be used to derive the token returned.
@@ -55,5 +60,16 @@ public abstract class StateCache<K, V>
      *         ResponseStateManager.writeState or ResponseStateManager.getViewState to be 
      *         output to the client.
      */
-    //public abstract K encodeSerializedState(FacesContext facesContext, Object serializedView);
+    public abstract K encodeSerializedState(FacesContext facesContext, Object serializedView);
+    
+    /**
+     * Indicates if the call to ResponseStateManager.writeState should be done after the view is fully rendered.
+     * Usually this is required for client side state saving, but it is not for server side state saving, because
+     * ResponseStateManager.writeState could render a just a marker and then StateManager.saveState could be called,
+     * preventing use an additional buffer. 
+     * 
+     * @param facesContext
+     * @return
+     */
+    public abstract boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext);
 }

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java Sat May 14 01:05:41 2011
@@ -38,6 +38,8 @@ import javax.faces.render.ResponseStateM
 import javax.faces.view.StateManagementStrategy;
 import javax.faces.view.ViewDeclarationLanguage;
 
+import org.apache.myfaces.renderkit.StateCacheUtils;
+
 public class StateManagerImpl extends StateManager
 {
     private static final Logger log = Logger.getLogger(StateManagerImpl.class.getName());
@@ -140,7 +142,9 @@ public class StateManagerImpl extends St
     @Override
     public Object saveView(FacesContext facesContext)
     {
+        Object serializedView = null;
         UIViewRoot uiViewRoot = facesContext.getViewRoot();
+        ResponseStateManager responseStateManager = facesContext.getRenderKit().getResponseStateManager();
         
         String viewId = uiViewRoot.getViewId();
         ViewDeclarationLanguage vdl = facesContext.getApplication().
@@ -153,7 +157,16 @@ public class StateManagerImpl extends St
             {
                 if (log.isLoggable(Level.FINEST)) log.finest("Calling saveView of StateManagementStrategy: "+sms.getClass().getName());
                 
-                return sms.saveView(facesContext);
+                serializedView = sms.saveView(facesContext);
+                
+                // If MyfacesResponseStateManager is used, give the option to do
+                // additional operations for save the state if is necessary.
+                if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+                {
+                    StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).saveState(facesContext, serializedView);
+                }
+                
+                return serializedView; 
             }
         }
 
@@ -175,7 +188,7 @@ public class StateManagerImpl extends St
         ExternalContext externalContext = facesContext.getExternalContext();
 
         // SerializedView already created before within this request?
-        Object serializedView = externalContext.getRequestMap()
+        serializedView = externalContext.getRequestMap()
                                                             .get(SERIALIZED_VIEW_REQUEST_ATTR);
         if (serializedView == null)
         {
@@ -190,6 +203,13 @@ public class StateManagerImpl extends St
 
             if (log.isLoggable(Level.FINEST)) log.finest("Processing saveSerializedView - new serialized view created");
         }
+        
+        // If MyfacesResponseStateManager is used, give the option to do
+        // additional operations for save the state if is necessary.
+        if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+        {
+            StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).saveState(facesContext, serializedView);
+        }
 
         if (log.isLoggable(Level.FINEST)) log.finest("Exiting saveView");
 
@@ -284,32 +304,6 @@ public class StateManagerImpl extends St
 
     }
 
-    /*
-     * NOTE: This is not required anymore, because all logic related to state storing or caching on session has
-     * been moved to ResponseStateManager
-    @Override
-    public String getViewState(FacesContext facesContext)
-    {
-        UIViewRoot uiViewRoot = facesContext.getViewRoot();
-        String viewId = uiViewRoot.getViewId();
-        ViewDeclarationLanguage vdl = facesContext.getApplication().getViewHandler().getViewDeclarationLanguage(facesContext,viewId);
-        if (vdl != null)
-        {
-            StateManagementStrategy sms = vdl.getStateManagementStrategy(facesContext, viewId);
-            
-            if (sms != null)
-            {
-                if (log.isLoggable(Level.FINEST)) log.finest("Calling saveView of StateManagementStrategy from getViewState: "+sms.getClass().getName());
-                
-                return facesContext.getRenderKit().getResponseStateManager().getViewState(facesContext, saveView(facesContext));
-            }
-        }
-        Object[] savedState = (Object[]) saveView(facesContext);
-        
-        return facesContext.getRenderKit().getResponseStateManager().getViewState(facesContext, savedState);
-
-    }*/
-
     //helpers
 
     protected RenderKitFactory getRenderKitFactory()

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ViewHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ViewHandlerImpl.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ViewHandlerImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ViewHandlerImpl.java Sat May 14 01:05:41 2011
@@ -45,7 +45,8 @@ import javax.faces.view.ViewDeclarationL
 import javax.faces.view.ViewMetadata;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.myfaces.application.jsp.JspStateManagerImpl;
+import org.apache.myfaces.renderkit.MyfacesResponseStateManager;
+import org.apache.myfaces.renderkit.StateCacheUtils;
 import org.apache.myfaces.shared_impl.application.DefaultViewHandlerSupport;
 import org.apache.myfaces.shared_impl.application.InvalidViewIdException;
 import org.apache.myfaces.shared_impl.application.ViewHandlerSupport;
@@ -286,10 +287,35 @@ public class ViewHandlerImpl extends Vie
         if(context.getPartialViewContext().isAjaxRequest())
             return;
 
-        setWritingState(context);
+        ResponseStateManager responseStateManager = context.getRenderKit().getResponseStateManager();
+        
+        setWritingState(context, responseStateManager);
 
         StateManager stateManager = context.getApplication().getStateManager();
-        if (stateManager.isSavingStateInClient(context))
+        
+        // By the spec, it is necessary to use a writer to write FORM_STATE_MARKER, 
+        // after the view is rendered, to preserve changes done on the component tree
+        // on rendering time. But if server side state saving is used, this is not 
+        // really necessary, because a token could be used and after the view is
+        // rendered, a simple call to StateManager.saveState() could do the trick.
+        // The code below check if we are using MyFacesResponseStateManager and if
+        // that so, check if the current one support the trick.
+        if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+        {
+            if (StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).isWriteStateAfterRenderViewRequired(context))
+            {
+                // Only write state marker if javascript view state is disabled
+                ExternalContext extContext = context.getExternalContext();
+                if (!(JavascriptUtils.isJavascriptAllowed(extContext) && MyfacesConfig.getCurrentInstance(extContext).isViewStateJavascript())) {
+                    context.getResponseWriter().write(FORM_STATE_MARKER);
+                }
+            }
+            else
+            {
+                stateManager.writeState(context, new Object[2]);
+            }
+        }
+        else
         {
             // Only write state marker if javascript view state is disabled
             ExternalContext extContext = context.getExternalContext();
@@ -297,13 +323,9 @@ public class ViewHandlerImpl extends Vie
                 context.getResponseWriter().write(FORM_STATE_MARKER);
             }
         }
-        else
-        {
-            stateManager.writeState(context, new Object[2]);
-        }
     }
     
-    private void setWritingState(FacesContext context){
+    private void setWritingState(FacesContext context, ResponseStateManager rsm){
         // Facelets specific hack:
         // Tell the StateWriter that we're about to write state
         StateWriter stateWriter = StateWriter.getCurrentInstance();
@@ -313,7 +335,25 @@ public class ViewHandlerImpl extends Vie
             // be wasteful for pure server-side state managers where nothing
             // is actually written into the output, but this cannot
             // programatically be discovered
-            stateWriter.writingState();
+            // -= Leonardo Uribe =- On MyFacesResponseStateManager was added
+            // some methods to discover it programatically.
+            if (StateCacheUtils.isMyFacesResponseStateManager(rsm))
+            {
+                if (StateCacheUtils.getMyFacesResponseStateManager(rsm).isWriteStateAfterRenderViewRequired(context))
+                {
+                    stateWriter.writingState();
+                }
+                else
+                {
+                    stateWriter.writingStateWithoutWrapper();
+                }
+            }
+            else
+            {
+                stateWriter.writingState();
+            }
+            
+            
         }else
         {
             //we're in a JSP, let the JSPStatemanager know that we need to actually write the state

Copied: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ClientSideStateCacheImpl.java (from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ClientSideStateCacheImpl.java?p2=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ClientSideStateCacheImpl.java&p1=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java&r1=1102114&r2=1102936&rev=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ClientSideStateCacheImpl.java Sat May 14 01:05:41 2011
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.myfaces.renderkit.html;
+package org.apache.myfaces.renderkit;
 
 import javax.faces.context.FacesContext;
 
@@ -39,4 +39,17 @@ class ClientSideStateCacheImpl extends S
         return viewState;
     }
 
+    @Override
+    public Object encodeSerializedState(FacesContext facesContext,
+            Object serializedView)
+    {
+        return serializedView;
+    }
+
+    @Override
+    public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
+    {
+        return true;
+    }
+
 }

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/MyfacesResponseStateManager.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/MyfacesResponseStateManager.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/MyfacesResponseStateManager.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/MyfacesResponseStateManager.java Sat May 14 01:05:41 2011
@@ -41,4 +41,26 @@ public abstract class MyfacesResponseSta
     {
         throw new UnsupportedOperationException("long been deprecated...");
     }
+
+    /**
+     * Execute additional operations like save the state on a cache when server
+     * side state saving is used.
+     */
+    public void saveState(FacesContext facesContext, Object state)
+    {
+    }
+    
+    /**
+     * Indicates if the call to ResponseStateManager.writeState should be done after the view is fully rendered.
+     * Usually this is required for client side state saving, but it is not for server side state saving, because
+     * ResponseStateManager.writeState could render a just a marker and then StateManager.saveState could be called,
+     * preventing use an additional buffer. 
+     * 
+     * @param facesContext
+     * @return
+     */
+    public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
+    {
+        return true;
+    }
 }

Copied: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java (from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?p2=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java&p1=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java&r1=1102114&r2=1102936&rev=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java Sat May 14 01:05:41 2011
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.myfaces.renderkit.html;
+package org.apache.myfaces.renderkit;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -44,21 +44,24 @@ import javax.faces.context.FacesContext;
 import org.apache.commons.collections.map.AbstractReferenceMap;
 import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.myfaces.application.StateCache;
-import org.apache.myfaces.application.StateCacheImpl;
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
 import org.apache.myfaces.shared_impl.renderkit.RendererUtils;
 import org.apache.myfaces.shared_impl.util.MyFacesObjectInputStream;
+import org.apache.myfaces.shared_impl.util.WebConfigParamUtils;
 
 class ServerSideStateCacheImpl extends StateCache<Object, Object>
 {
-    private static final Logger log = Logger.getLogger(StateCacheImpl.class.getName());
+    private static final Logger log = Logger.getLogger(ServerSideStateCacheImpl.class.getName());
     
     private static final String SERIALIZED_VIEW_SESSION_ATTR= 
-        StateCacheImpl.class.getName() + ".SERIALIZED_VIEW";
+        ServerSideStateCacheImpl.class.getName() + ".SERIALIZED_VIEW";
     
     private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR = 
-        StateCacheImpl.class.getName() + ".RESTORED_SERIALIZED_VIEW";
+        ServerSideStateCacheImpl.class.getName() + ".RESTORED_SERIALIZED_VIEW";
 
+    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR = 
+        ServerSideStateCacheImpl.class.getName() + ".RESTORED_VIEW_KEY";
+    
     /**
      * Only applicable if state saving method is "server" (= default).
      * Defines the amount (default = 20) of the latest views are stored in session.
@@ -67,6 +70,18 @@ class ServerSideStateCacheImpl extends S
     private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM = "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
 
     /**
+     * Only applicable if state saving method is "server" (= default).
+     * Indicates the amount of views (default is not active) that should be stored in session between sequential
+     * POST or POST-REDIRECT-GET if org.apache.myfaces.USE_FLASH_SCOPE_PURGE_VIEWS_IN_SESSION is true. 
+     * <p>For example, if this param has value = 2 and in your custom webapp there is a form that is clicked 3 times, only 2 views
+     * will be stored and the third one (the one stored the first time) will be removed from session, even if the view can
+     * store more sessions org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION. This feature becomes useful for multi-window applications.
+     * where without this feature a window can swallow all view slots so the other ones will throw ViewExpiredException.</p>
+     */
+    @JSFWebConfigParam(since="2.0.6")
+    private static final String NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM = "org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION";
+    
+    /**
      * Default value for <code>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</code> context parameter.
      */
     private static final int DEFAULT_NUMBER_OF_VIEWS_IN_SESSION = 20;
@@ -138,10 +153,24 @@ class ServerSideStateCacheImpl extends S
     
     private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF = "off";
 
+    /**
+     * Only applicable if state saving method is "server" (= default).
+     * Allow use flash scope to keep track of the views used in session and the previous ones,
+     * so server side state saving can delete old views even if POST-REDIRECT-GET pattern is used. 
+     * The default value is false.
+     */
+    @JSFWebConfigParam(since="2.0.6", defaultValue="false", expectedValues="true, false")
+    private static final String USE_FLASH_SCOPE_PURGE_VIEWS_IN_SESSION = "org.apache.myfaces.USE_FLASH_SCOPE_PURGE_VIEWS_IN_SESSION";
+
     private static final int UNCOMPRESSED_FLAG = 0;
     private static final int COMPRESSED_FLAG = 1;
 
     private static final int JSF_SEQUENCE_INDEX = 0;
+    
+    private Boolean _useFlashScopePurgeViewsInSession = null;
+    
+    private Integer _numberOfSequentialViewsInSession = null;
+    private boolean _numberOfSequentialViewsInSessionSet = false;
 
     //------------------------------------- METHODS COPIED FROM JspStateManagerImpl--------------------------------
 
@@ -169,7 +198,35 @@ class ServerSideStateCacheImpl extends S
             viewCollection = new SerializedViewCollection();
             sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
         }
-        viewCollection.add(context, serializeView(context, serializedView));
+
+        Map<Object,Object> attributeMap = context.getAttributes();
+        
+        SerializedViewKey key = null;
+        if (getNumberOfSequentialViewsInSession(context.getExternalContext()) != null &&
+            getNumberOfSequentialViewsInSession(context.getExternalContext()) > 0)
+        {
+            key = (SerializedViewKey) attributeMap.get(RESTORED_VIEW_KEY_REQUEST_ATTR);
+            
+            if (key == null )
+            {
+                if (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) && 
+                    Boolean.TRUE.equals(context.getExternalContext().getRequestMap().get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
+                {
+                    key = (SerializedViewKey) context.getExternalContext().getFlash().get(RESTORED_VIEW_KEY_REQUEST_ATTR);
+                }
+            }
+        }
+        
+        viewCollection.add(context, serializeView(context, serializedView), getNextViewSequence(context), key);
+
+        /*
+        if (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) && 
+            context.getExternalContext().getFlash().isRedirect())
+        {
+            context.getExternalContext().getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, new SerializedViewKey(context));
+            context.getExternalContext().getFlash().keep(RESTORED_VIEW_KEY_REQUEST_ATTR);
+        }*/
+        
         // replace the value to notify the container about the change
         sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
     }
@@ -177,11 +234,11 @@ class ServerSideStateCacheImpl extends S
     protected Object getSerializedViewFromServletSession(FacesContext context, String viewId, Integer sequence)
     {
         ExternalContext externalContext = context.getExternalContext();
-        Map<String, Object> requestMap = externalContext.getRequestMap();
+        Map<Object, Object> attributeMap = context.getAttributes();
         Object serializedView = null;
-        if (requestMap.containsKey(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR))
+        if (attributeMap.containsKey(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR))
         {
-            serializedView = requestMap.get(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR);
+            serializedView = attributeMap.get(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR);
         }
         else
         {
@@ -213,13 +270,26 @@ class ServerSideStateCacheImpl extends S
                     }
                 }
             }
-            requestMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
+            attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
+            
+            if (getNumberOfSequentialViewsInSession(externalContext) != null && getNumberOfSequentialViewsInSession(externalContext) > 0)
+            {
+                SerializedViewKey key = new SerializedViewKey(viewId, sequence);
+                attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
+                
+                if (isUseFlashScopePurgeViewsInSession(externalContext))
+                {
+                    externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
+                    externalContext.getFlash().keep(RESTORED_VIEW_KEY_REQUEST_ATTR);
+                }
+            }
+
             nextViewSequence(context);
         }
         return serializedView;
     }
 
-    protected int getNextViewSequence(FacesContext context)
+    public int getNextViewSequence(FacesContext context)
     {
         ExternalContext externalContext = context.getExternalContext();
 
@@ -232,7 +302,7 @@ class ServerSideStateCacheImpl extends S
         return sequence.intValue();
     }
 
-    protected void nextViewSequence(FacesContext facescontext)
+    public void nextViewSequence(FacesContext facescontext)
     {
         ExternalContext externalContext = facescontext.getExternalContext();
         Object sessionObj = externalContext.getSession(true);
@@ -280,11 +350,13 @@ class ServerSideStateCacheImpl extends S
                     os.write(UNCOMPRESSED_FLAG);
                 }
 
-                Object[] stateArray = (Object[]) serializedView;
+                //Object[] stateArray = (Object[]) serializedView;
 
                 ObjectOutputStream out = new ObjectOutputStream(os);
-                out.writeObject(stateArray[0]);
-                out.writeObject(stateArray[1]);
+                
+                out.writeObject(serializedView);
+                //out.writeObject(stateArray[0]);
+                //out.writeObject(stateArray[1]);
                 out.close();
                 baos.close();
 
@@ -366,17 +438,19 @@ class ServerSideStateCacheImpl extends S
                     Object object = null;
                     if (System.getSecurityManager() != null) 
                     {
-                        object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object []>() 
+                        object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() 
                         {
-                            public Object[] run() throws PrivilegedActionException, IOException, ClassNotFoundException
+                            public Object run() throws PrivilegedActionException, IOException, ClassNotFoundException
                             {
-                                return new Object[] {in.readObject(), in.readObject()};                                    
+                                //return new Object[] {in.readObject(), in.readObject()};
+                                return in.readObject();
                             }
                         });
                     }
                     else
                     {
-                        object = new Object[] {in.readObject(), in.readObject()};
+                        //object = new Object[] {in.readObject(), in.readObject()};
+                        object = in.readObject();
                     }
                     return object;
                 }
@@ -422,30 +496,105 @@ class ServerSideStateCacheImpl extends S
             return null;
         }
     }
+    
+    /*
+    public static Integer getViewSequence(FacesContext facescontext)
+    {
+        Map map = facescontext.getExternalContext().getRequestMap();
+        Integer sequence = (Integer) map.get(RendererUtils.SEQUENCE_PARAM);
+        if (sequence == null)
+        {
+            sequence = new Integer(1);
+            map.put(RendererUtils.SEQUENCE_PARAM, sequence);
+
+            synchronized (facescontext.getExternalContext().getSession(true))
+            {
+                facescontext.getExternalContext().getSessionMap().put(RendererUtils.SEQUENCE_PARAM, sequence);
+            }
+        }
+        return sequence;
+    }*/    
 
     protected static class SerializedViewCollection implements Serializable
     {
         private static final long serialVersionUID = -3734849062185115847L;
 
-        private final List<Object> _keys = new ArrayList<Object>(DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
-        private final Map<Object, Object> _serializedViews = new HashMap<Object, Object>();
+        private final List<SerializedViewKey> _keys = new ArrayList<SerializedViewKey>(DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
+        private final Map<SerializedViewKey, Object> _serializedViews = new HashMap<SerializedViewKey, Object>();
+        
+        private final Map<SerializedViewKey, SerializedViewKey> _precedence = 
+            new HashMap<SerializedViewKey, SerializedViewKey>();
 
         // old views will be hold as soft references which will be removed by
         // the garbage collector if free memory is low
         private transient Map<Object, Object> _oldSerializedViews = null;
 
-        public synchronized void add(FacesContext context, Object state)
+        public synchronized void add(FacesContext context, Object state, Integer nextSequence, SerializedViewKey previousRestoredKey)
         {
-            Object key = new SerializedViewKey(context);
+            SerializedViewKey key = new SerializedViewKey(context.getViewRoot().getViewId(), nextSequence);
             _serializedViews.put(key, state);
 
+            Integer maxCount = getNumberOfSequentialViewsInSession(context);
+            if (maxCount != null)
+            {
+                if (previousRestoredKey != null)
+                {
+                    _precedence.put((SerializedViewKey) key, previousRestoredKey);
+                }
+            }
+
             while (_keys.remove(key));
             _keys.add(key);
 
+            if (previousRestoredKey != null && maxCount != null && maxCount > 0)
+            {
+                int count = 0;
+                SerializedViewKey previousKey = (SerializedViewKey) key;
+                do
+                {
+                  previousKey = _precedence.get(previousKey);
+                  count++;
+                } while (previousKey != null && count < maxCount);
+                
+                if (previousKey != null)
+                {
+                    SerializedViewKey keyToRemove = (SerializedViewKey) previousKey;
+                    // In theory it should be only one key but just to be sure
+                    // do it in a loop, but in this case if cache old views is on,
+                    // put on that map.
+                    do
+                    {
+                        while (_keys.remove(keyToRemove));
+
+                        Object oldView = _serializedViews.remove(keyToRemove);
+                        if (oldView != null && 
+                                !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context))) 
+                        {
+                            getOldSerializedViewsMap().put(keyToRemove, oldView);
+                        }
+                    
+                        keyToRemove = _precedence.remove(keyToRemove);
+                    }  while(keyToRemove != null);
+                }
+            }
+
             int views = getNumberOfViewsInSession(context);
             while (_keys.size() > views)
             {
                 key = _keys.remove(0);
+                
+                if (maxCount != null && maxCount > 0)
+                {
+                    SerializedViewKey keyToRemove = (SerializedViewKey) key;
+                    // Note in this case the key to delete is the oldest one, 
+                    // so it could be at least one precedence, but to be safe
+                    // do it with a loop.
+                    do
+                    {
+                        keyToRemove = _precedence.remove(keyToRemove);
+                    } while (keyToRemove != null);
+                }
+                
                 Object oldView = _serializedViews.remove(key);
                 if (oldView != null && 
                     !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context))) 
@@ -455,6 +604,12 @@ class ServerSideStateCacheImpl extends S
             }
         }
 
+        protected Integer getNumberOfSequentialViewsInSession(FacesContext context)
+        {
+            return WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(), 
+                    NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
+        }
+        
         /**
          * Reads the amount (default = 20) of views to be stored in session.
          * @see NUMBER_OF_VIEWS_IN_SESSION_PARAM
@@ -587,11 +742,12 @@ class ServerSideStateCacheImpl extends S
             _viewId = viewId;
         }
 
+        /*
         public SerializedViewKey(FacesContext context)
         {
-            _sequenceId = RendererUtils.getViewSequence(context);
+            _sequenceId = getNextViewSequence(context);
             _viewId = context.getViewRoot().getViewId();
-        }
+        }*/
 
         @Override
         public int hashCode()
@@ -656,12 +812,40 @@ class ServerSideStateCacheImpl extends S
         return (serverStateId == null) ? null : getSerializedViewFromServletSession(facesContext, viewId, serverStateId);
     }
 
-    protected Object encodeSerializedState(FacesContext facesContext, Object serializedView)
+    public Object encodeSerializedState(FacesContext facesContext, Object serializedView)
     {
         Object[] identifier = new Object[2];
         identifier[JSF_SEQUENCE_INDEX] = Integer.toString(getNextViewSequence(facesContext), Character.MAX_RADIX);
         return identifier;
     }
     
+    @Override
+    public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
+    {
+        return false;
+    }
+
+    //------------------------------------- Custom methods -----------------------------------------------------
     
+    private boolean isUseFlashScopePurgeViewsInSession(ExternalContext externalContext)
+    {
+        if (_useFlashScopePurgeViewsInSession == null)
+        {
+            _useFlashScopePurgeViewsInSession = WebConfigParamUtils.getBooleanInitParameter(
+                    externalContext, USE_FLASH_SCOPE_PURGE_VIEWS_IN_SESSION, false);
+        }
+        return _useFlashScopePurgeViewsInSession;
+    }
+    
+    private Integer getNumberOfSequentialViewsInSession(ExternalContext externalContext)
+    {
+        if (!_numberOfSequentialViewsInSessionSet)
+        {
+            _numberOfSequentialViewsInSession = WebConfigParamUtils.getIntegerInitParameter(
+                    externalContext, 
+                    NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
+            _numberOfSequentialViewsInSessionSet = true;
+        }
+        return _numberOfSequentialViewsInSession;
+    }
 }

Copied: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheFactoryImpl.java (from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheFactoryImpl.java?p2=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheFactoryImpl.java&p1=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java&r1=1102114&r2=1102936&rev=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheFactoryImpl.java Sat May 14 01:05:41 2011
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.myfaces.renderkit.html;
+package org.apache.myfaces.renderkit;
 
 import javax.faces.context.FacesContext;
 

Added: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheUtils.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheUtils.java?rev=1102936&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheUtils.java (added)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheUtils.java Sat May 14 01:05:41 2011
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.renderkit;
+
+import javax.faces.FacesWrapper;
+import javax.faces.render.ResponseStateManager;
+
+public class StateCacheUtils
+{
+    public static boolean isMyFacesResponseStateManager(ResponseStateManager rsm)
+    {
+        if (rsm instanceof MyfacesResponseStateManager)
+        {
+            return true;
+        }
+        else
+        {
+            ResponseStateManager rsm1 = rsm;
+            while (rsm1 != null)
+            {
+                if (rsm1 instanceof MyfacesResponseStateManager)
+                {
+                    return true;
+                }
+                if (rsm1 instanceof FacesWrapper)
+                {
+                    rsm1 = ((FacesWrapper<? extends ResponseStateManager>) rsm1).getWrapped();
+                }
+                else
+                {
+                    rsm1 = null;
+                }
+            }
+            return false;
+        }
+    }
+    
+    public static MyfacesResponseStateManager getMyFacesResponseStateManager(ResponseStateManager rsm)
+    {
+        if (rsm instanceof MyfacesResponseStateManager)
+        {
+            return (MyfacesResponseStateManager) rsm;
+        }
+        else
+        {
+            ResponseStateManager rsm1 = rsm;
+            while (rsm1 != null)
+            {
+                if (rsm1 instanceof MyfacesResponseStateManager)
+                {
+                    return (MyfacesResponseStateManager) rsm1;
+                }
+                if (rsm1 instanceof FacesWrapper)
+                {
+                    rsm1 = ((FacesWrapper<? extends ResponseStateManager>) rsm1).getWrapped();
+                }
+                else
+                {
+                    rsm1 = null;
+                }
+            }
+            return null;
+        }
+    }
+}

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java Sat May 14 01:05:41 2011
@@ -32,6 +32,7 @@ import org.apache.myfaces.application.St
 import org.apache.myfaces.application.StateCacheFactory;
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
 import org.apache.myfaces.renderkit.MyfacesResponseStateManager;
+import org.apache.myfaces.renderkit.StateCacheFactoryImpl;
 import org.apache.myfaces.shared_impl.config.MyfacesConfig;
 import org.apache.myfaces.shared_impl.renderkit.html.HTML;
 import org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils;
@@ -84,7 +85,8 @@ public class HtmlResponseStateManager ex
         
         if (isHandlingStateCachingMechanics(facesContext))
         {
-            token = getStateCache(facesContext).saveSerializedView(facesContext, state);
+            //token = getStateCache(facesContext).saveSerializedView(facesContext, state);
+            token = getStateCache(facesContext).encodeSerializedState(facesContext, state);
         }
         else
         {
@@ -116,6 +118,19 @@ public class HtmlResponseStateManager ex
         // renderKitId field
         writeRenderKitIdField(facesContext, responseWriter);
     }
+    
+    @Override
+    public void saveState(FacesContext facesContext, Object state)
+    {
+        if (isHandlingStateCachingMechanics(facesContext))
+        {
+            getStateCache(facesContext).saveSerializedView(facesContext, state);
+        }
+        else
+        {
+            //This is done outside
+        }
+    }
 
     private void writeViewStateField(FacesContext facesContext, ResponseWriter responseWriter, Object savedState)
         throws IOException
@@ -285,6 +300,12 @@ public class HtmlResponseStateManager ex
         return StateUtils.construct(savedState, facesContext.getExternalContext());
     }
     
+    @Override
+    public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
+    {
+        return getStateCache(facesContext).isWriteStateAfterRenderViewRequired(facesContext);
+    }
+
     protected StateCache getStateCache(FacesContext facesContext)
     {
         return _stateCacheFactory.getStateCache(facesContext);

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java Sat May 14 01:05:41 2011
@@ -46,8 +46,6 @@ import javax.faces.view.ViewDeclarationL
 import javax.faces.view.ViewDeclarationLanguageFactory;
 import javax.faces.view.ViewMetadata;
 
-import org.apache.myfaces.application.StateCache;
-import org.apache.myfaces.application.StateCacheImpl;
 import org.apache.myfaces.application.StateManagerImpl;
 import org.apache.myfaces.shared_impl.renderkit.RendererUtils;
 import org.apache.myfaces.shared_impl.util.ClassUtils;

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java Sat May 14 01:05:41 2011
@@ -18,39 +18,22 @@
  */
 package org.apache.myfaces.view.facelets;
 
-import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
-import org.apache.myfaces.config.RuntimeConfig;
-import org.apache.myfaces.shared_impl.application.DefaultViewHandlerSupport;
-import org.apache.myfaces.shared_impl.application.ViewHandlerSupport;
-import org.apache.myfaces.shared_impl.config.MyfacesConfig;
-import org.apache.myfaces.shared_impl.util.ClassUtils;
-import org.apache.myfaces.shared_impl.util.StringUtils;
-import org.apache.myfaces.shared_impl.util.WebConfigParamUtils;
-import org.apache.myfaces.shared_impl.view.ViewDeclarationLanguageBase;
-import org.apache.myfaces.view.ViewMetadataBase;
-import org.apache.myfaces.view.facelets.FaceletViewHandler.NullWriter;
-import org.apache.myfaces.view.facelets.compiler.Compiler;
-import org.apache.myfaces.view.facelets.compiler.SAXCompiler;
-import org.apache.myfaces.view.facelets.compiler.TagLibraryConfig;
-import org.apache.myfaces.view.facelets.el.LocationMethodExpression;
-import org.apache.myfaces.view.facelets.el.LocationValueExpression;
-import org.apache.myfaces.view.facelets.el.VariableMapperWrapper;
-import org.apache.myfaces.view.facelets.impl.DefaultFaceletFactory;
-import org.apache.myfaces.view.facelets.impl.DefaultResourceResolver;
-import org.apache.myfaces.view.facelets.tag.TagLibrary;
-import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorAttachedObjectTarget;
-import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorRedirectBehaviorAttachedObjectHandlerWrapper;
-import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorRedirectEventComponentWrapper;
-import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
-import org.apache.myfaces.view.facelets.tag.composite.CompositeResourceLibrary;
-import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
-import org.apache.myfaces.view.facelets.tag.jsf.core.CoreLibrary;
-import org.apache.myfaces.view.facelets.tag.jsf.html.HtmlLibrary;
-import org.apache.myfaces.view.facelets.tag.jstl.core.JstlCoreLibrary;
-import org.apache.myfaces.view.facelets.tag.jstl.fn.JstlFnLibrary;
-import org.apache.myfaces.view.facelets.tag.ui.UIDebug;
-import org.apache.myfaces.view.facelets.tag.ui.UILibrary;
-import org.apache.myfaces.view.facelets.util.ReflectionUtil;
+import java.beans.BeanDescriptor;
+import java.beans.BeanInfo;
+import java.beans.PropertyDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.Array;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import javax.el.ELContext;
 import javax.el.ELException;
@@ -98,22 +81,40 @@ import javax.faces.view.facelets.Facelet
 import javax.faces.view.facelets.ResourceResolver;
 import javax.faces.view.facelets.TagDecorator;
 import javax.servlet.http.HttpServletResponse;
-import java.beans.BeanDescriptor;
-import java.beans.BeanInfo;
-import java.beans.PropertyDescriptor;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.Writer;
-import java.lang.reflect.Array;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+import org.apache.myfaces.config.RuntimeConfig;
+import org.apache.myfaces.shared_impl.application.DefaultViewHandlerSupport;
+import org.apache.myfaces.shared_impl.application.ViewHandlerSupport;
+import org.apache.myfaces.shared_impl.config.MyfacesConfig;
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.shared_impl.util.StringUtils;
+import org.apache.myfaces.shared_impl.util.WebConfigParamUtils;
+import org.apache.myfaces.shared_impl.view.ViewDeclarationLanguageBase;
+import org.apache.myfaces.view.ViewMetadataBase;
+import org.apache.myfaces.view.facelets.FaceletViewHandler.NullWriter;
+import org.apache.myfaces.view.facelets.compiler.Compiler;
+import org.apache.myfaces.view.facelets.compiler.SAXCompiler;
+import org.apache.myfaces.view.facelets.compiler.TagLibraryConfig;
+import org.apache.myfaces.view.facelets.el.LocationMethodExpression;
+import org.apache.myfaces.view.facelets.el.LocationValueExpression;
+import org.apache.myfaces.view.facelets.el.VariableMapperWrapper;
+import org.apache.myfaces.view.facelets.impl.DefaultFaceletFactory;
+import org.apache.myfaces.view.facelets.impl.DefaultResourceResolver;
+import org.apache.myfaces.view.facelets.tag.TagLibrary;
+import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorAttachedObjectTarget;
+import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorRedirectBehaviorAttachedObjectHandlerWrapper;
+import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorRedirectEventComponentWrapper;
+import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
+import org.apache.myfaces.view.facelets.tag.composite.CompositeResourceLibrary;
+import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
+import org.apache.myfaces.view.facelets.tag.jsf.core.CoreLibrary;
+import org.apache.myfaces.view.facelets.tag.jsf.html.HtmlLibrary;
+import org.apache.myfaces.view.facelets.tag.jstl.core.JstlCoreLibrary;
+import org.apache.myfaces.view.facelets.tag.jstl.fn.JstlFnLibrary;
+import org.apache.myfaces.view.facelets.tag.ui.UIDebug;
+import org.apache.myfaces.view.facelets.tag.ui.UILibrary;
+import org.apache.myfaces.view.facelets.util.ReflectionUtil;
 
 /**
  * This class represents the abstraction of Facelets as a ViewDeclarationLanguage.
@@ -1308,12 +1309,19 @@ public class FaceletViewDeclarationLangu
                 {
                     context.setResponseWriter(writer);
 
-                    // force creation of session if saving state there
                     StateManager stateMgr = context.getApplication().getStateManager();
-                    if (!stateMgr.isSavingStateInClient(context))
-                    {
-                        extContext.getSession(true);
-                    }
+                    // force creation of session if saving state there
+                    // -= Leonardo Uribe =- Do this does not have any sense!. The only reference
+                    // about these lines are on http://java.net/projects/facelets/sources/svn/revision/376
+                    // and it says: "fixed lazy session instantiation with eager response commit"
+                    // This code is obviously to prevent this exception:
+                    // java.lang.IllegalStateException: Cannot create a session after the response has been committed
+                    // But in theory if that so, StateManager.saveState must happen before writer.close() is called,
+                    // which can be done very easily.
+                    //if (!stateMgr.isSavingStateInClient(context))
+                    //{
+                    //    extContext.getSession(true);
+                    //}
                     
                     // render the view to the response
                     writer.startDocument();
@@ -1323,12 +1331,23 @@ public class FaceletViewDeclarationLangu
                     writer.endDocument();
 
                     // finish writing
-                    writer.close();
+                    // -= Leonardo Uribe =- This does not has sense too, because that's the reason
+                    // of the try/finally block. In practice, it only forces the close of the tag 
+                    // in HtmlResponseWriter if necessary, but according to the spec, this should
+                    // be done using writer.flush() instead.
+                    // writer.close();
 
-                    boolean writtenState = stateWriter.isStateWritten();
                     // flush to origWriter
-                    if (writtenState)
+                    if (stateWriter.isStateWritten())
                     {
+                        // Call this method to force close the tag if necessary.
+                        // The spec javadoc says this: 
+                        // "... Flush any ouput buffered by the output method to the underlying 
+                        // Writer or OutputStream. This method will not flush the underlying 
+                        // Writer or OutputStream; it simply clears any values buffered by this 
+                        // ResponseWriter. ..."
+                        writer.flush();
+                        
                         // =-= markoc: STATE_KEY is in output ONLY if 
                         // stateManager.isSavingStateInClient(context)is true - see
                         // org.apache.myfaces.application.ViewHandlerImpl.writeState(FacesContext)
@@ -1374,6 +1393,12 @@ public class FaceletViewDeclarationLangu
                             origWriter.write(content);
                         }
                     }
+                    else if (stateWriter.isStateWrittenWithoutWrapper())
+                    {
+                        // The state token has been written but the state has not been
+                        // saved yet.
+                        stateMgr.saveView(context);
+                    }
                 }
                 finally
                 {

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/StateWriter.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/StateWriter.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/StateWriter.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/StateWriter.java Sat May 14 01:05:41 2011
@@ -53,6 +53,7 @@ public final class StateWriter extends W
     private Writer out;
     private FastWriter fast;
     private boolean writtenState;
+    private boolean writtenStateWithoutWrapper;
 
     static public StateWriter getCurrentInstance()
     {
@@ -99,15 +100,29 @@ public final class StateWriter extends W
         if (!this.writtenState)
         {
             this.writtenState = true;
+            this.writtenStateWithoutWrapper = false;
             this.out = this.fast = new FastWriter(this.initialSize);
         }
     }
-
+    
     public boolean isStateWritten()
     {
         return this.writtenState;
     }
 
+    public void writingStateWithoutWrapper()
+    {
+        if (!this.writtenState && !this.writtenStateWithoutWrapper)
+        {
+            this.writtenStateWithoutWrapper = true;
+        }
+    }    
+
+    public boolean isStateWrittenWithoutWrapper()
+    {
+        return this.writtenStateWithoutWrapper;
+    }
+
     public void close() throws IOException
     {
         // do nothing

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java Sat May 14 01:05:41 2011
@@ -27,12 +27,14 @@ import javax.faces.FacesException;
 import javax.faces.component.UIViewRoot;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
+import javax.faces.render.ResponseStateManager;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.jsp.jstl.core.Config;
 
 import org.apache.myfaces.application.jsp.ServletViewResponseWrapper;
+import org.apache.myfaces.renderkit.StateCacheUtils;
 import org.apache.myfaces.shared_impl.view.JspViewDeclarationLanguageBase;
 import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
 import org.apache.myfaces.view.facelets.tag.jsf.core.CoreLibrary;
@@ -185,6 +187,30 @@ public class JspViewDeclarationLanguage 
         }
     }
 
+    /**
+     * 
+     */
+    @Override
+    protected boolean isViewStateAlreadyEncoded(FacesContext context)
+    {
+        ResponseStateManager responseStateManager = context.getRenderKit().getResponseStateManager();
+        if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+        {
+            if (StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).isWriteStateAfterRenderViewRequired(context))
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+        else
+        {
+            return false;
+        }
+    }
+
     @Override
     protected void sendSourceNotFound(FacesContext context, String message)
     {

Added: myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ServerSideStateCacheTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ServerSideStateCacheTest.java?rev=1102936&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ServerSideStateCacheTest.java (added)
+++ myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ServerSideStateCacheTest.java Sat May 14 01:05:41 2011
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.renderkit;
+
+import javax.faces.application.StateManager;
+
+import org.apache.myfaces.application.StateCache;
+import org.apache.myfaces.test.base.junit4.AbstractJsfConfigurableMultipleRequestsTestCase;
+import org.junit.Test;
+import org.testng.Assert;
+
+public class ServerSideStateCacheTest extends AbstractJsfConfigurableMultipleRequestsTestCase
+{
+
+    @Test
+    public void testNumberOfSequentialViewsInSession() throws Exception
+    {
+        
+        servletContext.addInitParameter(StateManager.STATE_SAVING_METHOD_PARAM_NAME, StateManager.STATE_SAVING_METHOD_SERVER);
+        servletContext.addInitParameter("org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION", "5");
+        servletContext.addInitParameter("org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION", "2");
+        
+        StateCache stateCache = new ServerSideStateCacheImpl();
+        
+        Object savedToken;
+        Object firstSavedToken;
+        
+        try
+        {
+            setupRequest();
+            
+            facesContext.getViewRoot().setViewId("view1.xhtml");
+            savedToken = stateCache.saveSerializedView(facesContext, 1);
+            firstSavedToken = savedToken;
+        }
+        finally
+        {
+            tearDownRequest();
+        }
+        
+        try
+        {
+            setupRequest();
+            
+            Object value = stateCache.restoreSerializedView(facesContext, "view1.xhtml", savedToken);
+            
+            Assert.assertEquals(1, value);
+            
+            facesContext.getViewRoot().setViewId("view2.xhtml");
+            savedToken = stateCache.saveSerializedView(facesContext, 2);
+        }
+        finally
+        {
+            tearDownRequest();
+        }
+
+        try
+        {
+            setupRequest();
+            
+            Object value = stateCache.restoreSerializedView(facesContext, "view2.xhtml", savedToken);
+            
+            Assert.assertEquals(2, value);
+            
+            facesContext.getViewRoot().setViewId("view2.xhtml");
+            savedToken = stateCache.saveSerializedView(facesContext, 3);
+        }
+        finally
+        {
+            tearDownRequest();
+        }
+        
+        try
+        {
+            setupRequest();
+            
+            Object value = stateCache.restoreSerializedView(facesContext, "view1.xhtml", firstSavedToken);
+            
+            // Since org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION is 2, the first one was already discarded
+            Assert.assertNull(value);
+        }
+        finally
+        {
+            tearDownRequest();
+        }
+        
+        
+    }
+}