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/12 00:22:28 UTC

svn commit: r1102114 - in /myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces: application/ renderkit/html/

Author: lu4242
Date: Wed May 11 22:22:27 2011
New Revision: 1102114

URL: http://svn.apache.org/viewvc?rev=1102114&view=rev
Log:
MYFACES-3138 Simplify ResponseStateManager implementation code

Added:
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheFactory.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/java/org/apache/myfaces/application/StateCache.java
    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/HtmlResponseStateManager.java

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=1102114&r1=1102113&r2=1102114&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 Wed May 11 22:22:27 2011
@@ -26,7 +26,7 @@ import javax.faces.context.FacesContext;
  * @author Leonardo Uribe
  *
  */
-public abstract class StateCache
+public abstract class StateCache<K, V>
 {
 
     /**
@@ -35,7 +35,7 @@ public abstract class StateCache
      * @param facesContext
      * @param serializedView
      */
-    public abstract void saveSerializedView(FacesContext facesContext, Object serializedView);
+    public abstract K saveSerializedView(FacesContext facesContext, V serializedView);
     
     /**
      * 
@@ -45,7 +45,7 @@ public abstract class StateCache
      *                  used to identify or restore the state.
      * @return
      */
-    public abstract Object restoreSerializedView(FacesContext facesContext, String viewId, Object viewState);
+    public abstract V restoreSerializedView(FacesContext facesContext, String viewId, K viewState);
 
     /**
      * 
@@ -55,5 +55,5 @@ public abstract class StateCache
      *         ResponseStateManager.writeState or ResponseStateManager.getViewState to be 
      *         output to the client.
      */
-    public abstract Object encodeSerializedState(FacesContext facesContext, Object serializedView);
+    //public abstract K encodeSerializedState(FacesContext facesContext, Object serializedView);
 }

Added: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheFactory.java?rev=1102114&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheFactory.java (added)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheFactory.java Wed May 11 22:22:27 2011
@@ -0,0 +1,33 @@
+/*
+ * 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.application;
+
+import javax.faces.FacesWrapper;
+import javax.faces.context.FacesContext;
+
+public abstract class StateCacheFactory implements FacesWrapper<StateCacheFactory>
+{
+    public abstract StateCache getStateCache(FacesContext facesContext);
+
+    public StateCacheFactory getWrapped()
+    {
+        return null;
+    }
+    
+}

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheImpl.java?rev=1102114&r1=1102113&r2=1102114&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheImpl.java Wed May 11 22:22:27 2011
@@ -634,11 +634,12 @@ public class StateCacheImpl extends Stat
     //------------------------------------- METHOD FROM StateCache ------------------------------------------------
 
     @Override
-    public void saveSerializedView(FacesContext facesContext, Object serializedView)
+    public Object saveSerializedView(FacesContext facesContext, Object serializedView)
     {
         if (facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
         {
             //On client side the state is written completely on the page.
+            return serializedView;
         }
         else
         {
@@ -647,6 +648,8 @@ public class StateCacheImpl extends Stat
             saveSerializedViewInServletSession(facesContext, serializedView);
             
             if (log.isLoggable(Level.FINEST)) log.finest("Exiting saveSerializedView - server-side state saving - saved state");
+            
+            return encodeSerializedState(facesContext, serializedView);
         }
     }
 
@@ -668,8 +671,7 @@ public class StateCacheImpl extends Stat
         }
     }
 
-    @Override
-    public Object encodeSerializedState(FacesContext facesContext, Object serializedView)
+    protected Object encodeSerializedState(FacesContext facesContext, Object serializedView)
     {
         if (facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
         {

Added: 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/html/ClientSideStateCacheImpl.java?rev=1102114&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java (added)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java Wed May 11 22:22:27 2011
@@ -0,0 +1,42 @@
+/*
+ * 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.html;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.application.StateCache;
+
+class ClientSideStateCacheImpl extends StateCache<Object, Object>
+{
+
+    @Override
+    public Object saveSerializedView(FacesContext facesContext,
+            Object serializedView)
+    {
+        return serializedView;
+    }
+
+    @Override
+    public Object restoreSerializedView(FacesContext facesContext,
+            String viewId, Object viewState)
+    {
+        return viewState;
+    }
+
+}

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=1102114&r1=1102113&r2=1102114&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 Wed May 11 22:22:27 2011
@@ -22,9 +22,6 @@ import java.io.IOException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import javax.faces.FacesException;
-import javax.faces.application.StateManager;
-import javax.faces.application.StateManager.SerializedView;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
@@ -32,7 +29,7 @@ import javax.faces.render.RenderKitFacto
 import javax.faces.render.ResponseStateManager;
 
 import org.apache.myfaces.application.StateCache;
-import org.apache.myfaces.application.StateCacheImpl;
+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.shared_impl.config.MyfacesConfig;
@@ -51,9 +48,9 @@ public class HtmlResponseStateManager ex
     //private static final Log log = LogFactory.getLog(HtmlResponseStateManager.class);
     private static final Logger log = Logger.getLogger(HtmlResponseStateManager.class.getName());
 
-    private static final int TREE_PARAM = 0;
-    private static final int STATE_PARAM = 1;
-    private static final int VIEWID_PARAM = 2;
+    //private static final int TREE_PARAM = 2;
+    private static final int STATE_PARAM = 0;
+    private static final int VIEWID_PARAM = 1;
 
     public static final String STANDARD_STATE_SAVING_PARAM = "javax.faces.ViewState";
     
@@ -62,11 +59,11 @@ public class HtmlResponseStateManager ex
     
     private Boolean _handleStateCachingMechanics;
     
-    private StateCache _stateCache;
+    private StateCacheFactory _stateCacheFactory;
     
     public HtmlResponseStateManager()
     {
-        _stateCache = new StateCacheImpl();
+        _stateCacheFactory = new StateCacheFactoryImpl();
     }
     
     protected boolean isHandlingStateCachingMechanics(FacesContext facesContext)
@@ -80,65 +77,36 @@ public class HtmlResponseStateManager ex
     
     public void writeState(FacesContext facesContext, Object state) throws IOException
     {
-        Object[] token = null;
+        ResponseWriter responseWriter = facesContext.getResponseWriter();
+
+        Object token = null;
+        Object[] savedState = new Object[2];
+        
         if (isHandlingStateCachingMechanics(facesContext))
         {
-            getStateCache().saveSerializedView(facesContext, state);
-            
-            token = (Object[]) getStateCache().encodeSerializedState(facesContext, state);
+            token = getStateCache(facesContext).saveSerializedView(facesContext, state);
         }
         else
         {
-            token = (Object[]) state;
+            token = state;
         }
-        ResponseWriter responseWriter = facesContext.getResponseWriter();
-        
-        Object[] savedState = new Object[3];
 
-        if (facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
-        {
-            if (log.isLoggable(Level.FINEST))
-                log.finest("Writing state in client");
-            Object treeStruct = token[0];
-            Object compStates = token[1];
+        if (log.isLoggable(Level.FINEST))
+            log.finest("Writing state in client");
 
-            if (treeStruct != null)
-            {
-                savedState[TREE_PARAM] = treeStruct;
-            }
-            else
-            {
-                if (log.isLoggable(Level.FINEST))
-                    log.finest("No tree structure to be saved in client response!");
-            }
 
-            if (compStates != null)
-            {
-                savedState[STATE_PARAM] = compStates;
-            }
-            else
-            {
-                if (log.isLoggable(Level.FINEST))
-                    log.finest("No component states to be saved in client response!");
-            }
+        if (token != null)
+        {
+            savedState[STATE_PARAM] = token;
         }
         else
         {
             if (log.isLoggable(Level.FINEST))
-                log.finest("Writing state in server");
-            // write viewSequence
-            Object treeStruct = token[0];
-            if (treeStruct != null)
-            {
-                if (treeStruct instanceof String)
-                {
-                    savedState[TREE_PARAM] = treeStruct;
-                }
-            }
+                log.finest("No component states to be saved in client response!");
         }
 
         savedState[VIEWID_PARAM] = facesContext.getViewRoot().getViewId();
-
+        
         if (log.isLoggable(Level.FINEST))
             log.finest("Writing view state and renderKit fields");
 
@@ -200,12 +168,11 @@ public class HtmlResponseStateManager ex
 
         if (isHandlingStateCachingMechanics(facesContext))
         {
-            return getStateCache().restoreSerializedView(facesContext, viewId, 
-                    new Object[] { savedState[TREE_PARAM], savedState[STATE_PARAM] });
+            return getStateCache(facesContext).restoreSerializedView(facesContext, viewId, savedState[STATE_PARAM]);
         }
         else
         {
-            return new Object[] { savedState[TREE_PARAM], savedState[STATE_PARAM] };
+            return savedState[STATE_PARAM];
         }
     }
 
@@ -293,86 +260,34 @@ public class HtmlResponseStateManager ex
     }
 
     @Override
-    public String getViewState(FacesContext facesContext, Object state)
+    public String getViewState(FacesContext facesContext, Object baseState)
     {
-        if (state == null)
+        if (baseState == null)
         {
             return null;
         }
         
+        Object state = null;
         if (isHandlingStateCachingMechanics(facesContext))
         {
-            getStateCache().saveSerializedView(facesContext, state);
-
-            state = getStateCache().encodeSerializedState(facesContext, state);
+            state = getStateCache(facesContext).saveSerializedView(facesContext, baseState);
         }
         
-        Object treeStruct = null;
-        Object compStates = null;
+        Object[] savedState = new Object[2];
         
-        if (state instanceof SerializedView)
-        {
-            SerializedView view = (SerializedView)state; 
-            treeStruct = view.getStructure();
-            compStates = view.getState();
-        }
-        else if (state instanceof Object[])
-        {
-            Object[] structureAndState = (Object[])state;
-
-            if (structureAndState.length == 2)
-            {
-                treeStruct = structureAndState[0];
-                compStates = structureAndState[1];
-            }
-            else
-            {
-                throw new FacesException("The state should be an array of Object[] of lenght 2");
-            }
-        }
-        else
+        if (state != null)
         {
-            throw new FacesException("The state should be an array of Object[] of lenght 2, or a SerializedView instance");
+            savedState[STATE_PARAM] = state;
         }
         
-        Object[] savedState = new Object[3];
-
-        if (facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
-        {
-            if (treeStruct != null)
-            {
-                savedState[TREE_PARAM] = treeStruct;
-            }
-
-            if (compStates != null)
-            {
-                savedState[STATE_PARAM] = compStates;
-            }
-        }
-        else
-        {
-            // write viewSequence
-            if (treeStruct != null)
-            {
-                if (treeStruct instanceof String)
-                {
-                    savedState[TREE_PARAM] = treeStruct;
-                }
-            }
-        }
         savedState[VIEWID_PARAM] = facesContext.getViewRoot().getViewId();
-
+        
         return StateUtils.construct(savedState, facesContext.getExternalContext());
     }
     
-    
-    protected StateCache getStateCache()
+    protected StateCache getStateCache(FacesContext facesContext)
     {
-        return _stateCache;
+        return _stateCacheFactory.getStateCache(facesContext);
     }
 
-    protected void setStateCache(StateCache stateCache)
-    {
-        this._stateCache = stateCache;
-    }
 }

Added: 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/html/ServerSideStateCacheImpl.java?rev=1102114&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java (added)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java Wed May 11 22:22:27 2011
@@ -0,0 +1,667 @@
+/*
+ * 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.html;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+import javax.faces.context.ExternalContext;
+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;
+
+class ServerSideStateCacheImpl extends StateCache<Object, Object>
+{
+    private static final Logger log = Logger.getLogger(StateCacheImpl.class.getName());
+    
+    private static final String SERIALIZED_VIEW_SESSION_ATTR= 
+        StateCacheImpl.class.getName() + ".SERIALIZED_VIEW";
+    
+    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR = 
+        StateCacheImpl.class.getName() + ".RESTORED_SERIALIZED_VIEW";
+
+    /**
+     * Only applicable if state saving method is "server" (= default).
+     * Defines the amount (default = 20) of the latest views are stored in session.
+     */
+    @JSFWebConfigParam(defaultValue="20",since="1.1")
+    private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM = "org.apache.myfaces.NUMBER_OF_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;
+
+    /**
+     * Only applicable if state saving method is "server" (= default).
+     * If <code>true</code> (default) the state will be serialized to a byte stream before it is written to the session.
+     * If <code>false</code> the state will not be serialized to a byte stream.
+     */
+    @JSFWebConfigParam(defaultValue="true",since="1.1")
+    private static final String SERIALIZE_STATE_IN_SESSION_PARAM = "org.apache.myfaces.SERIALIZE_STATE_IN_SESSION";
+
+    /**
+     * Only applicable if state saving method is "server" (= default) and if <code>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</code> is <code>true</code> (= default).
+     * If <code>true</code> (default) the serialized state will be compressed before it is written to the session.
+     * If <code>false</code> the state will not be compressed.
+     */
+    @JSFWebConfigParam(defaultValue="true",since="1.1")
+    private static final String COMPRESS_SERVER_STATE_PARAM = "org.apache.myfaces.COMPRESS_STATE_IN_SESSION";
+
+    /**
+     * Default value for <code>org.apache.myfaces.COMPRESS_STATE_IN_SESSION</code> context parameter.
+     */
+    private static final boolean DEFAULT_COMPRESS_SERVER_STATE_PARAM = true;
+
+    /**
+     * Default value for <code>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</code> context parameter.
+     */
+    private static final boolean DEFAULT_SERIALIZE_STATE_IN_SESSION = true;
+
+    /**
+     * Define the way of handle old view references(views removed from session), making possible to
+     * store it in a cache, so the state manager first try to get the view from the session. If is it
+     * not found and soft or weak ReferenceMap is used, it try to get from it.
+     * <p>
+     * Only applicable if state saving method is "server" (= default).
+     * </p>
+     * <p>
+     * The gc is responsible for remove the views, according to the rules used for soft, weak or phantom
+     * references. If a key in soft and weak mode is garbage collected, its values are purged.
+     * </p>
+     * <p>
+     * By default no cache is used, so views removed from session became phantom references.
+     * </p>
+     * <ul> 
+     * <li> off, no: default, no cache is used</li> 
+     * <li> hard-soft: use an ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.SOFT)</li>
+     * <li> soft: use an ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.SOFT, true) </li>
+     * <li> soft-weak: use an ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.WEAK, true) </li>
+     * <li> weak: use an ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true) </li>
+     * </ul>
+     * 
+     */
+    @JSFWebConfigParam(defaultValue="off", expectedValues="off, no, hard-soft, soft, soft-weak, weak", since="1.2.5")
+    private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE = "org.apache.myfaces.CACHE_OLD_VIEWS_IN_SESSION_MODE";
+    
+    /**
+     * This option uses an hard-soft ReferenceMap, but it could cause a 
+     * memory leak, because the keys are not removed by any method
+     * (MYFACES-1660). So use with caution.
+     */
+    private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT = "hard-soft";
+    
+    private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT = "soft";
+    
+    private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK = "soft-weak";
+    
+    private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK = "weak";
+    
+    private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF = "off";
+
+    private static final int UNCOMPRESSED_FLAG = 0;
+    private static final int COMPRESSED_FLAG = 1;
+
+    private static final int JSF_SEQUENCE_INDEX = 0;
+
+    //------------------------------------- METHODS COPIED FROM JspStateManagerImpl--------------------------------
+
+    protected Integer getServerStateId(Object[] state)
+    {
+      if (state != null)
+      {
+          Object serverStateId = state[JSF_SEQUENCE_INDEX];
+          if (serverStateId != null)
+          {
+              return Integer.valueOf((String) serverStateId, Character.MAX_RADIX);
+          }
+      }
+      return null;
+    }
+
+    protected void saveSerializedViewInServletSession(FacesContext context,
+                                                      Object serializedView)
+    {
+        Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
+        SerializedViewCollection viewCollection = (SerializedViewCollection) sessionMap
+                .get(SERIALIZED_VIEW_SESSION_ATTR);
+        if (viewCollection == null)
+        {
+            viewCollection = new SerializedViewCollection();
+            sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
+        }
+        viewCollection.add(context, serializeView(context, serializedView));
+        // replace the value to notify the container about the change
+        sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
+    }
+
+    protected Object getSerializedViewFromServletSession(FacesContext context, String viewId, Integer sequence)
+    {
+        ExternalContext externalContext = context.getExternalContext();
+        Map<String, Object> requestMap = externalContext.getRequestMap();
+        Object serializedView = null;
+        if (requestMap.containsKey(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR))
+        {
+            serializedView = requestMap.get(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR);
+        }
+        else
+        {
+            SerializedViewCollection viewCollection = (SerializedViewCollection) externalContext
+                    .getSessionMap().get(SERIALIZED_VIEW_SESSION_ATTR);
+            if (viewCollection != null)
+            {
+                /*
+                String sequenceStr = externalContext.getRequestParameterMap().get(
+                       RendererUtils.SEQUENCE_PARAM);
+                Integer sequence = null;
+                if (sequenceStr == null)
+                {
+                    // use latest sequence
+                    Map map = externalContext.getSessionMap();
+                    sequence = (Integer) map.get(RendererUtils.SEQUENCE_PARAM);
+                }
+                else
+                {
+                    sequence = new Integer(sequenceStr);
+                }
+                */
+                if (sequence != null)
+                {
+                    Object state = viewCollection.get(sequence, viewId);
+                    if (state != null)
+                    {
+                        serializedView = deserializeView(state);
+                    }
+                }
+            }
+            requestMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
+            nextViewSequence(context);
+        }
+        return serializedView;
+    }
+
+    protected int getNextViewSequence(FacesContext context)
+    {
+        ExternalContext externalContext = context.getExternalContext();
+
+        if (!externalContext.getRequestMap().containsKey(RendererUtils.SEQUENCE_PARAM))
+        {
+            nextViewSequence(context);
+        }
+
+        Integer sequence = (Integer) externalContext.getRequestMap().get(RendererUtils.SEQUENCE_PARAM);
+        return sequence.intValue();
+    }
+
+    protected void nextViewSequence(FacesContext facescontext)
+    {
+        ExternalContext externalContext = facescontext.getExternalContext();
+        Object sessionObj = externalContext.getSession(true);
+        synchronized(sessionObj) // synchronized to increase sequence if multiple requests
+                                 // are handled at the same time for the session
+        {
+            Map<String, Object> map = externalContext.getSessionMap();
+            Integer sequence = (Integer) map.get(RendererUtils.SEQUENCE_PARAM);
+            if(sequence == null || sequence.intValue() == Integer.MAX_VALUE)
+            {
+                sequence = Integer.valueOf(1);
+            }
+            else
+            {
+                sequence = Integer.valueOf(sequence.intValue() + 1);
+            }
+            map.put(RendererUtils.SEQUENCE_PARAM, sequence);
+            externalContext.getRequestMap().put(RendererUtils.SEQUENCE_PARAM, sequence);
+        }
+    }
+
+    protected Object serializeView(FacesContext context, Object serializedView)
+    {
+        if (log.isLoggable(Level.FINEST)) log.finest("Entering serializeView");
+
+        if(isSerializeStateInSession(context))
+        {
+            if (log.isLoggable(Level.FINEST)) log.finest("Processing serializeView - serialize state in session");
+
+            ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+            try
+            {
+                OutputStream os = baos;
+                if(isCompressStateInSession(context))
+                {
+                    if (log.isLoggable(Level.FINEST)) log.finest("Processing serializeView - serialize compressed");
+
+                    os.write(COMPRESSED_FLAG);
+                    os = new GZIPOutputStream(os, 1024);
+                }
+                else
+                {
+                    if (log.isLoggable(Level.FINEST)) log.finest("Processing serializeView - serialize uncompressed");
+
+                    os.write(UNCOMPRESSED_FLAG);
+                }
+
+                Object[] stateArray = (Object[]) serializedView;
+
+                ObjectOutputStream out = new ObjectOutputStream(os);
+                out.writeObject(stateArray[0]);
+                out.writeObject(stateArray[1]);
+                out.close();
+                baos.close();
+
+                if (log.isLoggable(Level.FINEST)) log.finest("Exiting serializeView - serialized. Bytes : "+baos.size());
+                return baos.toByteArray();
+            }
+            catch (IOException e)
+            {
+                log.log(Level.SEVERE, "Exiting serializeView - Could not serialize state: " + e.getMessage(), e);
+                return null;
+            }
+        }
+
+
+        if (log.isLoggable(Level.FINEST))
+            log.finest("Exiting serializeView - do not serialize state in session.");
+
+        return serializedView;
+
+    }
+
+    /**
+     * Reads the value of the <code>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</code> context parameter.
+     * @see SERIALIZE_STATE_IN_SESSION_PARAM
+     * @param context <code>FacesContext</code> for the request we are processing.
+     * @return boolean true, if the server state should be serialized in the session
+     */
+    protected boolean isSerializeStateInSession(FacesContext context)
+    {
+        String value = context.getExternalContext().getInitParameter(
+                SERIALIZE_STATE_IN_SESSION_PARAM);
+        boolean serialize = DEFAULT_SERIALIZE_STATE_IN_SESSION;
+        if (value != null)
+        {
+           serialize = Boolean.valueOf(value);
+        }
+        return serialize;
+    }
+
+    /**
+     * Reads the value of the <code>org.apache.myfaces.COMPRESS_STATE_IN_SESSION</code> context parameter.
+     * @see COMPRESS_SERVER_STATE_PARAM
+     * @param context <code>FacesContext</code> for the request we are processing.
+     * @return boolean true, if the server state steam should be compressed
+     */
+    protected boolean isCompressStateInSession(FacesContext context)
+    {
+        String value = context.getExternalContext().getInitParameter(
+                COMPRESS_SERVER_STATE_PARAM);
+        boolean compress = DEFAULT_COMPRESS_SERVER_STATE_PARAM;
+        if (value != null)
+        {
+           compress = Boolean.valueOf(value);
+        }
+        return compress;
+    }
+
+    protected Object deserializeView(Object state)
+    {
+        if (log.isLoggable(Level.FINEST)) log.finest("Entering deserializeView");
+
+        if(state instanceof byte[])
+        {
+            if (log.isLoggable(Level.FINEST)) log.finest("Processing deserializeView - deserializing serialized state. Bytes : "+((byte[]) state).length);
+
+            try
+            {
+                ByteArrayInputStream bais = new ByteArrayInputStream((byte[]) state);
+                InputStream is = bais;
+                if(is.read() == COMPRESSED_FLAG)
+                {
+                    is = new GZIPInputStream(is);
+                }
+                ObjectInputStream ois = null;
+                try
+                {
+                    final ObjectInputStream in = new MyFacesObjectInputStream(is);
+                    ois = in;
+                    Object object = null;
+                    if (System.getSecurityManager() != null) 
+                    {
+                        object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object []>() 
+                        {
+                            public Object[] run() throws PrivilegedActionException, IOException, ClassNotFoundException
+                            {
+                                return new Object[] {in.readObject(), in.readObject()};                                    
+                            }
+                        });
+                    }
+                    else
+                    {
+                        object = new Object[] {in.readObject(), in.readObject()};
+                    }
+                    return object;
+                }
+                finally
+                {
+                    if (ois != null)
+                    {
+                        ois.close();
+                        ois = null;
+                    }
+                }
+            }
+            catch (PrivilegedActionException e) 
+            {
+                log.log(Level.SEVERE, "Exiting deserializeView - Could not deserialize state: " + e.getMessage(), e);
+                return null;
+            }
+            catch (IOException e)
+            {
+                log.log(Level.SEVERE, "Exiting deserializeView - Could not deserialize state: " + e.getMessage(), e);
+                return null;
+            }
+            catch (ClassNotFoundException e)
+            {
+                log.log(Level.SEVERE, "Exiting deserializeView - Could not deserialize state: " + e.getMessage(), e);
+                return null;
+            }
+        }
+        else if (state instanceof Object[])
+        {
+            if (log.isLoggable(Level.FINEST)) log.finest("Exiting deserializeView - state not serialized.");
+
+            return state;
+        }
+        else if(state == null)
+        {
+            log.severe("Exiting deserializeView - this method should not be called with a null-state.");
+            return null;
+        }
+        else
+        {
+            log.severe("Exiting deserializeView - this method should not be called with a state of type : "+state.getClass());
+            return null;
+        }
+    }
+
+    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>();
+
+        // 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)
+        {
+            Object key = new SerializedViewKey(context);
+            _serializedViews.put(key, state);
+
+            while (_keys.remove(key));
+            _keys.add(key);
+
+            int views = getNumberOfViewsInSession(context);
+            while (_keys.size() > views)
+            {
+                key = _keys.remove(0);
+                Object oldView = _serializedViews.remove(key);
+                if (oldView != null && 
+                    !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context))) 
+                {
+                    getOldSerializedViewsMap().put(key, oldView);
+                }
+            }
+        }
+
+        /**
+         * Reads the amount (default = 20) of views to be stored in session.
+         * @see NUMBER_OF_VIEWS_IN_SESSION_PARAM
+         * @param context FacesContext for the current request, we are processing
+         * @return Number vf views stored in the session
+         */
+        protected int getNumberOfViewsInSession(FacesContext context)
+        {
+            String value = context.getExternalContext().getInitParameter(
+                    NUMBER_OF_VIEWS_IN_SESSION_PARAM);
+            int views = DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
+            if (value != null)
+            {
+                try
+                {
+                    views = Integer.parseInt(value);
+                    if (views <= 0)
+                    {
+                        log.severe("Configured value for " + NUMBER_OF_VIEWS_IN_SESSION_PARAM
+                                  + " is not valid, must be an value > 0, using default value ("
+                                  + DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
+                        views = DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
+                    }
+                }
+                catch (Throwable e)
+                {
+                    log.log(Level.SEVERE, "Error determining the value for " + NUMBER_OF_VIEWS_IN_SESSION_PARAM
+                              + ", expected an integer value > 0, using default value ("
+                              + DEFAULT_NUMBER_OF_VIEWS_IN_SESSION + "): " + e.getMessage(), e);
+                }
+            }
+            return views;
+        }
+
+        /**
+         * @return old serialized views map
+         */
+        @SuppressWarnings("unchecked")
+        protected Map<Object, Object> getOldSerializedViewsMap()
+        {
+            FacesContext context = FacesContext.getCurrentInstance();
+            if (_oldSerializedViews == null && context != null)
+            {
+                String cacheMode = getCacheOldViewsInSessionMode(context); 
+                if (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
+                {
+                    _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true);
+                }
+                else if (CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK.equals(cacheMode))
+                {
+                    _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.WEAK, true);
+                }
+                else if (CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT.equals(cacheMode))
+                {
+                    _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.SOFT, true);
+                }
+                else if (CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT.equals(cacheMode))
+                {
+                    _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.SOFT);
+                }
+            }
+            
+            return _oldSerializedViews;
+        }
+        
+        /**
+         * Reads the value of the <code>org.apache.myfaces.CACHE_OLD_VIEWS_IN_SESSION_MODE</code> context parameter.
+         * 
+         * @since 1.2.5
+         * @param context
+         * @return constant indicating caching mode
+         * @see CACHE_OLD_VIEWS_IN_SESSION_MODE
+         */
+        protected String getCacheOldViewsInSessionMode(FacesContext context)
+        {
+            String value = context.getExternalContext().getInitParameter(
+                    CACHE_OLD_VIEWS_IN_SESSION_MODE);
+            if (value == null)
+            {
+                return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
+            }
+            else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT))
+            {
+                return CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT;
+            }
+            else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK))
+            {
+                return CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK;
+            }            
+            else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK))
+            {
+                return CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK;
+            }
+            else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT))
+            {
+                return CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT;
+            }
+            else
+            {
+                return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
+            }
+        }
+        
+        public Object get(Integer sequence, String viewId)
+        {
+            Object key = new SerializedViewKey(viewId, sequence);
+            Object value = _serializedViews.get(key);
+            if (value == null)
+            {
+                Map<Object,Object> oldSerializedViewMap = getOldSerializedViewsMap();
+                if (oldSerializedViewMap != null)
+                {
+                    value = oldSerializedViewMap.get(key);
+                }
+            }
+            return value;
+        }
+    }
+
+    protected static class SerializedViewKey implements Serializable
+    {
+        private static final long serialVersionUID = -1170697124386063642L;
+
+        private final String _viewId;
+        private final Integer _sequenceId;
+
+        public SerializedViewKey(String viewId, Integer sequence)
+        {
+            _sequenceId = sequence;
+            _viewId = viewId;
+        }
+
+        public SerializedViewKey(FacesContext context)
+        {
+            _sequenceId = RendererUtils.getViewSequence(context);
+            _viewId = context.getViewRoot().getViewId();
+        }
+
+        @Override
+        public int hashCode()
+        {
+            final int PRIME = 31;
+            int result = 1;
+            result = PRIME * result + ((_sequenceId == null) ? 0 : _sequenceId.hashCode());
+            result = PRIME * result + ((_viewId == null) ? 0 : _viewId.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            final SerializedViewKey other = (SerializedViewKey) obj;
+            if (_sequenceId == null)
+            {
+                if (other._sequenceId != null)
+                    return false;
+            }
+            else if (!_sequenceId.equals(other._sequenceId))
+                return false;
+            if (_viewId == null)
+            {
+                if (other._viewId != null)
+                    return false;
+            }
+            else if (!_viewId.equals(other._viewId))
+                return false;
+            return true;
+        }
+
+    }
+    
+    //------------------------------------- METHOD FROM StateCache ------------------------------------------------
+
+    @Override
+    public Object saveSerializedView(FacesContext facesContext, Object serializedView)
+    {
+        if (log.isLoggable(Level.FINEST)) log.finest("Processing saveSerializedView - server-side state saving - save state");
+        //save state in server session
+        saveSerializedViewInServletSession(facesContext, serializedView);
+        
+        if (log.isLoggable(Level.FINEST)) log.finest("Exiting saveSerializedView - server-side state saving - saved state");
+        
+        return encodeSerializedState(facesContext, serializedView);
+    }
+
+    @Override
+    public Object restoreSerializedView(FacesContext facesContext, String viewId, Object viewState)
+    {
+        if (log.isLoggable(Level.FINEST)) log.finest("Restoring view from session");
+
+        Integer serverStateId = getServerStateId((Object[]) viewState);
+
+        return (serverStateId == null) ? null : getSerializedViewFromServletSession(facesContext, viewId, serverStateId);
+    }
+
+    protected Object encodeSerializedState(FacesContext facesContext, Object serializedView)
+    {
+        Object[] identifier = new Object[2];
+        identifier[JSF_SEQUENCE_INDEX] = Integer.toString(getNextViewSequence(facesContext), Character.MAX_RADIX);
+        return identifier;
+    }
+    
+    
+}

Added: 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/html/StateCacheFactoryImpl.java?rev=1102114&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java (added)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java Wed May 11 22:22:27 2011
@@ -0,0 +1,50 @@
+/*
+ * 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.html;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.application.StateCache;
+import org.apache.myfaces.application.StateCacheFactory;
+
+public class StateCacheFactoryImpl extends StateCacheFactory
+{
+
+    private StateCache _clientSideStateCache;
+    private StateCache _serverSideStateCache;
+    
+    public StateCacheFactoryImpl()
+    {
+        _clientSideStateCache = new ClientSideStateCacheImpl();
+        _serverSideStateCache = new ServerSideStateCacheImpl();
+    }
+
+    @Override
+    public StateCache getStateCache(FacesContext facesContext)
+    {
+        if (facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
+        {
+            return _clientSideStateCache;
+        }
+        else
+        {
+            return _serverSideStateCache;
+        }
+    }
+}